diff --git a/store/state/enum.go b/store/state/enum.go index c580dca614aa..18937ce18bf7 100644 --- a/store/state/enum.go +++ b/store/state/enum.go @@ -56,5 +56,8 @@ func (v Enum) Transit(ctx Context, from, to byte) bool { // Query() retrives state value and proof from a queryable reference func (v Enum) Query(q ABCIQuerier) (res byte, proof *Proof, err error) { value, proof, err := v.Value.QueryRaw(q) + if err != nil { + return + } return value[0], proof, err } diff --git a/store/state/integer.go b/store/state/integer.go index 6758d73cc479..938b83fd1f46 100644 --- a/store/state/integer.go +++ b/store/state/integer.go @@ -58,6 +58,10 @@ func (v Integer) Query(q ABCIQuerier) (res uint64, proof *Proof, err error) { if err != nil { return } + if value == nil { + res = 0 + return + } res, err = DecodeInt(value, v.enc) return } diff --git a/store/state/mapping_test.go b/store/state/mapping_test.go index 2f44b9fcccc2..3d4110fdf672 100644 --- a/store/state/mapping_test.go +++ b/store/state/mapping_test.go @@ -88,7 +88,7 @@ func (m indexerT) RandomKey() interface{} { } func TestMapping(t *testing.T) { - ctx := defaultComponents() + ctx, _ := defaultComponents() table := []mapping{newMapping(), newIndexer(Dec), newIndexer(Hex), newIndexer(Bin)} for _, m := range table { diff --git a/store/state/types.go b/store/state/types.go index 9251c808db88..66ffb1f5255f 100644 --- a/store/state/types.go +++ b/store/state/types.go @@ -4,7 +4,9 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/merkle" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" + stypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -14,5 +16,46 @@ type Proof = merkle.Proof type Codec = codec.Codec type ABCIQuerier interface { - QueryABCI(req abci.RequestQuery) (abci.ResponseQuery, error) + Query(storeName string, key []byte) (abci.ResponseQuery, error) +} + +var _ ABCIQuerier = CLIQuerier{} + +type CLIQuerier struct { + ctx context.CLIContext +} + +func NewCLIQuerier(ctx context.CLIContext) CLIQuerier { + return CLIQuerier{ctx} +} + +func (q CLIQuerier) Query(storeName string, key []byte) (abci.ResponseQuery, error) { + req := abci.RequestQuery{ + Path: "/store/" + storeName + "/key", + Data: key, + Prove: true, + } + + return q.ctx.QueryABCI(req) +} + +var _ ABCIQuerier = StoreQuerier{} + +type StoreQuerier struct { + store stypes.Queryable +} + +func NewStoreQuerier(store stypes.Queryable) StoreQuerier { + return StoreQuerier{store} +} + +func (q StoreQuerier) Query(storeName string, key []byte) (abci.ResponseQuery, error) { + req := abci.RequestQuery{ + Path: "/" + storeName + "/key", + Data: key, + Prove: true, + } + + return q.store.Query(req), nil + } diff --git a/store/state/value.go b/store/state/value.go index 60df0c9718d6..1d467b0ab380 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -1,11 +1,7 @@ package state import ( - "errors" - - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" ) // Value is a capability for reading and writing on a specific key-value point @@ -29,7 +25,7 @@ func (v Value) store(ctx Context) KVStore { } // Cdc() returns the codec that the value is using to marshal/unmarshal -func (v Value) Cdc() *codec.Codec { +func (v Value) Cdc() *Codec { return v.m.Cdc() } @@ -108,19 +104,13 @@ func (v Value) KeyBytes() []byte { } func (v Value) QueryRaw(q ABCIQuerier) ([]byte, *Proof, error) { - req := abci.RequestQuery{ - Path: "/store" + v.m.StoreName() + "/key", - Data: v.KeyBytes(), - Prove: true, - } - - resp, err := q.QueryABCI(req) + resp, err := q.Query(v.m.StoreName(), v.KeyBytes()) if err != nil { return nil, nil, err } if !resp.IsOK() { - return nil, nil, errors.New(resp.Log) + return nil, nil, sdk.NewError(sdk.CodespaceRoot, sdk.CodeType(resp.Code), resp.Log) } return resp.Value, resp.Proof, nil diff --git a/store/state/value_test.go b/store/state/value_test.go index 88f75c32bdbb..38888890bbdf 100644 --- a/store/state/value_test.go +++ b/store/state/value_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" @@ -30,6 +31,7 @@ func key() (res []byte) { } type value interface { + KeyBytes() []byte Get(Context, interface{}) GetSafe(Context, interface{}) error GetRaw(Context) []byte @@ -37,6 +39,7 @@ type value interface { SetRaw(Context, []byte) Exists(Context) bool Delete(Context) + Query(ABCIQuerier, interface{}) (*Proof, error) Marshal(interface{}) []byte Unmarshal([]byte, interface{}) } @@ -110,6 +113,15 @@ func (v booleanT) Unmarshal(bz []byte, ptr interface{}) { } } +func (v booleanT) Query(q ABCIQuerier, ptr interface{}) (proof *Proof, err error) { + res, proof, err := v.Boolean.Query(q) + if err != nil { + return + } + reflect.ValueOf(ptr).Elem().SetBool(res) + return +} + type integerT struct { Integer } @@ -153,6 +165,15 @@ func (v integerT) Unmarshal(bz []byte, ptr interface{}) { reflect.ValueOf(ptr).Elem().SetUint(res) } +func (v integerT) Query(q ABCIQuerier, ptr interface{}) (proof *Proof, err error) { + res, proof, err := v.Integer.Query(q) + if err != nil { + return + } + reflect.ValueOf(ptr).Elem().SetUint(res) + return +} + type enumT struct { Enum } @@ -192,6 +213,15 @@ func (v enumT) Unmarshal(bz []byte, ptr interface{}) { reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(bz[0])) } +func (v enumT) Query(q ABCIQuerier, ptr interface{}) (proof *Proof, err error) { + res, proof, err := v.Enum.Query(q) + if err != nil { + return + } + reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(res)) + return +} + type stringT struct { String } @@ -231,13 +261,22 @@ func (v stringT) Unmarshal(bz []byte, ptr interface{}) { reflect.ValueOf(ptr).Elem().SetString(string(bz)) } -func defaultComponents() sdk.Context { +func (v stringT) Query(q ABCIQuerier, ptr interface{}) (proof *Proof, err error) { + res, proof, err := v.String.Query(q) + if err != nil { + return + } + reflect.ValueOf(ptr).Elem().SetString(res) + return +} + +func defaultComponents() (sdk.Context, *rootmulti.Store) { db := dbm.NewMemDB() cms := rootmulti.NewStore(db) cms.MountStoreWithDB(testkey, sdk.StoreTypeIAVL, db) cms.LoadLatestVersion() ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) - return ctx + return ctx, cms } func indirect(ptr interface{}) interface{} { @@ -245,7 +284,7 @@ func indirect(ptr interface{}) interface{} { } func TestTypeValue(t *testing.T) { - ctx := defaultComponents() + ctx, cms := defaultComponents() var table = []struct { ty typeValue @@ -296,5 +335,19 @@ func TestTypeValue(t *testing.T) { require.Error(t, err) require.Equal(t, reflect.Zero(reflect.TypeOf(ptr).Elem()).Interface(), indirect(ptr)) require.Nil(t, v.GetRaw(ctx)) + + // Set again and test abci query + v.Set(ctx, tc.orig) + cid := cms.Commit() + ptr = v.Proto() + q := NewStoreQuerier(cms) + proof, err := v.Query(q, ptr) + require.NoError(t, err) + require.Equal(t, tc.orig, indirect(ptr), "Expected equal on tc %d", i) + prt := rootmulti.DefaultProofRuntime() + kp := merkle.KeyPath{}. + AppendKey([]byte(testkey.Name()), merkle.KeyEncodingHex). + AppendKey(v.KeyBytes(), merkle.KeyEncodingHex) + require.NoError(t, prt.VerifyValue(proof, cid.Hash, kp.String(), v.GetRaw(ctx))) } } diff --git a/x/ibc/02-client/README.md b/x/ibc/02-client/README.md index a9bd6892771b..f8b3fc98d086 100644 --- a/x/ibc/02-client/README.md +++ b/x/ibc/02-client/README.md @@ -46,4 +46,4 @@ each corresponds to `spec: Header.{height, proof, state, root}`. ### manager.go -`spec: interface ClientState` is implemented by `type Object`. // TODO +`spec: interface ClientState` is implemented by `type State`. // TODO diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index db03c1441329..0895bbcc2c38 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -3,23 +3,31 @@ package client import ( "bytes" - "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/store/state" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func (obj Object) prefix() []byte { +func (obj State) prefix() []byte { return bytes.Split(obj.ConsensusState.KeyBytes(), LocalRoot())[0] } -func (obj Object) ConsensusStateCLI(ctx context.CLIContext) (res ConsensusState, proof merkle.Proof, err error) { - tmproof, err := obj.ConsensusState.Query(ctx, &res) +func (obj State) RootCLI(q state.ABCIQuerier, height uint64) (res commitment.Root, proof merkle.Proof, err error) { + root := obj.Roots.Value(height) + tmproof, err := root.Query(q, &res) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), root) + return +} + +func (obj State) ConsensusStateCLI(q state.ABCIQuerier) (res ConsensusState, proof merkle.Proof, err error) { + tmproof, err := obj.ConsensusState.Query(q, &res) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.ConsensusState) return } -func (obj Object) FrozenCLI(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { - res, tmproof, err := obj.Frozen.Query(ctx) +func (obj State) FrozenCLI(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { + res, tmproof, err := obj.Frozen.Query(q) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Frozen) return } diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index c4238dae8cdb..ff0010c82ded 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -14,14 +14,14 @@ import ( "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" + "github.com/cosmos/cosmos-sdk/x/ibc/version" ) -func mapping(cdc *codec.Codec, storeKey string, version int64) state.Mapping { - prefix := []byte(strconv.FormatInt(version, 10) + "/") +func mapping(cdc *codec.Codec, storeKey string, v int64) state.Mapping { + prefix := version.Prefix(v) return state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) } @@ -35,8 +35,10 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ibcQueryCmd.AddCommand(cli.GetCommands( GetCmdQueryConsensusState(storeKey, cdc), + GetCmdQueryPath(storeKey, cdc), GetCmdQueryHeader(cdc), GetCmdQueryClient(storeKey, cdc), + GetCmdQueryRoot(storeKey, cdc), )...) return ibcQueryCmd } @@ -48,11 +50,12 @@ func GetCmdQueryClient(storeKey string, cdc *codec.Codec) *cobra.Command { Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) - mapp := mapping(cdc, storeKey, ibc.Version) + q := state.NewCLIQuerier(ctx) + mapp := mapping(cdc, storeKey, version.Version) man := client.NewManager(mapp) id := args[0] - state, _, err := man.Object(id).ConsensusStateCLI(ctx) + state, _, err := man.State(id).ConsensusStateCLI(q) if err != nil { return err } @@ -64,6 +67,33 @@ func GetCmdQueryClient(storeKey string, cdc *codec.Codec) *cobra.Command { } } +func GetCmdQueryRoot(storeKey string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "root", + Short: "Query stored root", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + q := state.NewCLIQuerier(ctx) + mapp := mapping(cdc, storeKey, version.Version) + man := client.NewManager(mapp) + id := args[0] + height, err := strconv.ParseUint(args[1], 10, 64) + if err != nil { + return err + } + + root, _, err := man.State(id).RootCLI(q, height) + if err != nil { + return err + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, root)) + + return nil + }, + } +} func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "consensus-state", @@ -108,6 +138,19 @@ func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command } } +func GetCmdQueryPath(storeName string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "path", + Short: "Query the commitment path of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + mapp := mapping(cdc, storeName, version.Version) + path := merkle.NewPath([][]byte{[]byte(storeName)}, mapp.PrefixBytes()) + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, path)) + return nil + }, + } +} + func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "header", diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index 1b18dbe34783..d79bbbcf70e2 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -32,8 +32,8 @@ const ( func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ibcTxCmd := &cobra.Command{ - Use: "ibc", - Short: "IBC transaction subcommands", + Use: "client", + Short: "Client transaction subcommands", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, } @@ -48,7 +48,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "create-client", + Use: "create", Short: "create new client with a consensus state", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { @@ -81,7 +81,7 @@ func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command { func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "update-client", + Use: "update", Short: "update existing client with a header", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { diff --git a/x/ibc/02-client/codec.go b/x/ibc/02-client/codec.go index ece7e750dc98..18dd6da686e8 100644 --- a/x/ibc/02-client/codec.go +++ b/x/ibc/02-client/codec.go @@ -4,11 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -var MsgCdc = codec.New() - -func init() { - RegisterCodec(MsgCdc) -} +var MsgCdc *codec.Codec func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*ConsensusState)(nil), nil) @@ -17,3 +13,7 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgCreateClient{}, "ibc/client/MsgCreateClient", nil) cdc.RegisterConcrete(MsgUpdateClient{}, "ibc/client/MsgUpdateClient", nil) } + +func SetMsgCodec(cdc *codec.Codec) { + MsgCdc = cdc +} diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index eb9a83ff7d2e..b5efd7bd94c1 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -40,72 +40,80 @@ func (man Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { return man } */ -func (man Manager) Object(id string) Object { - return Object{ +func (man Manager) State(id string) State { + return State{ id: id, + Roots: man.protocol.Prefix([]byte(id + "/roots/")).Indexer(state.Dec), ConsensusState: man.protocol.Value([]byte(id)), Frozen: man.protocol.Value([]byte(id + "/freeze")).Boolean(), } } -func (man Manager) Create(ctx sdk.Context, id string, cs ConsensusState) (Object, error) { - obj := man.Object(id) +func (man Manager) Create(ctx sdk.Context, id string, cs ConsensusState) (State, error) { + obj := man.State(id) if obj.exists(ctx) { - return Object{}, errors.New("Create client on already existing id") + return State{}, errors.New("Create client on already existing id") } + obj.Roots.Set(ctx, cs.GetHeight(), cs.GetRoot()) obj.ConsensusState.Set(ctx, cs) return obj, nil } -func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { - res := man.Object(id) +func (man Manager) Query(ctx sdk.Context, id string) (State, error) { + res := man.State(id) if !res.exists(ctx) { - return Object{}, errors.New("client not exists") + return State{}, errors.New("client not exists") } return res, nil } -func (man CounterpartyManager) Object(id string) CounterObject { - return CounterObject{ +func (man CounterpartyManager) State(id string) CounterState { + return CounterState{ id: id, ConsensusState: man.protocol.Value([]byte(id)), } } -func (man CounterpartyManager) Query(id string) CounterObject { - return man.Object(id) +func (man CounterpartyManager) Query(id string) CounterState { + return man.State(id) } -// Any actor holding the Object can access on and modify that client information -type Object struct { +// Any actor holding the Stage can access on and modify that client information +type State struct { id string + Roots state.Indexer ConsensusState state.Value // ConsensusState Frozen state.Boolean } -type CounterObject struct { +type CounterState struct { id string ConsensusState commitment.Value } -func (obj Object) ID() string { +func (obj State) ID() string { return obj.id } -func (obj Object) GetConsensusState(ctx sdk.Context) (res ConsensusState) { +func (obj State) GetConsensusState(ctx sdk.Context) (res ConsensusState) { obj.ConsensusState.Get(ctx, &res) return } -func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { +func (obj State) GetRoot(ctx sdk.Context, height uint64) (res commitment.Root, err error) { + err = obj.Roots.GetSafe(ctx, height, &res) + return +} + +func (obj CounterState) Is(ctx sdk.Context, client ConsensusState) bool { return obj.ConsensusState.Is(ctx, client) } -func (obj Object) exists(ctx sdk.Context) bool { +func (obj State) exists(ctx sdk.Context) bool { return obj.ConsensusState.Exists(ctx) } -func (obj Object) Update(ctx sdk.Context, header Header) error { +func (obj State) Update(ctx sdk.Context, header Header) error { if !obj.exists(ctx) { panic("should not update nonexisting client") } @@ -121,11 +129,12 @@ func (obj Object) Update(ctx sdk.Context, header Header) error { } obj.ConsensusState.Set(ctx, updated) + obj.Roots.Set(ctx, updated.GetHeight(), updated.GetRoot()) return nil } -func (obj Object) Freeze(ctx sdk.Context) error { +func (obj State) Freeze(ctx sdk.Context) error { if !obj.exists(ctx) { panic("should not freeze nonexisting client") } @@ -139,7 +148,7 @@ func (obj Object) Freeze(ctx sdk.Context) error { return nil } -func (obj Object) Delete(ctx sdk.Context) error { +func (obj State) Delete(ctx sdk.Context) error { if !obj.exists(ctx) { panic("should not delete nonexisting client") } diff --git a/x/ibc/02-client/tendermint/codec.go b/x/ibc/02-client/tendermint/codec.go index 31a25031f9fc..1c149c0a3fe3 100644 --- a/x/ibc/02-client/tendermint/codec.go +++ b/x/ibc/02-client/tendermint/codec.go @@ -2,13 +2,8 @@ package tendermint import ( "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client" ) -func init() { - RegisterCodec(client.MsgCdc) -} - func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(ConsensusState{}, "ibc/client/tendermint/ConsensusState", nil) cdc.RegisterConcrete(Header{}, "ibc/client/tendermint/Header", nil) diff --git a/x/ibc/02-client/types.go b/x/ibc/02-client/types.go index 134837a43aa8..36ba2b307913 100644 --- a/x/ibc/02-client/types.go +++ b/x/ibc/02-client/types.go @@ -1,7 +1,7 @@ package client import ( - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // TODO: types in this file should be (de/)serialized with proto in the future diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index 2a6c65d7c824..f4222722332f 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -3,67 +3,68 @@ package connection import ( "bytes" - "github.com/cosmos/cosmos-sdk/client/context" - + "github.com/cosmos/cosmos-sdk/store/state" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func (man Manager) CLIObject(connid, clientid string) Object { - obj := man.Object(connid) - obj.Client = man.client.Object(clientid) +func (man Manager) CLIState(connid, clientid string) State { + obj := man.State(connid) + obj.Client = man.client.State(clientid) return obj } -func (obj Object) prefix() []byte { +func (man Manager) CLIQuery(q state.ABCIQuerier, connid string) (State, error) { + obj := man.State(connid) + conn, _, err := obj.ConnectionCLI(q) + if err != nil { + return State{}, err + } + obj.Client = man.client.State(conn.Client) + return obj, nil +} + +func (obj State) prefix() []byte { return bytes.Split(obj.Connection.KeyBytes(), LocalRoot())[0] } -func (obj Object) ConnectionCLI(ctx context.CLIContext) (res Connection, proof merkle.Proof, err error) { - tmproof, err := obj.Connection.Query(ctx, &res) +func (obj State) ConnectionCLI(q state.ABCIQuerier) (res Connection, proof merkle.Proof, err error) { + tmproof, err := obj.Connection.Query(q, &res) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Connection) return } -func (obj Object) AvailableCLI(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { - res, tmproof, err := obj.Available.Query(ctx) +func (obj State) AvailableCLI(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { + res, tmproof, err := obj.Available.Query(q) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Available) return } -func (obj Object) KindCLI(ctx context.CLIContext) (res string, proof merkle.Proof, err error) { - res, tmproof, err := obj.Kind.Query(ctx) +func (obj State) KindCLI(q state.ABCIQuerier) (res string, proof merkle.Proof, err error) { + res, tmproof, err := obj.Kind.Query(q) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Kind) return } -func (man Handshaker) CLIObject(connid, clientid string) HandshakeObject { - return man.Object(man.man.CLIObject(connid, clientid)) +func (man Handshaker) CLIState(connid, clientid string) HandshakeState { + return man.CreateState(man.man.CLIState(connid, clientid)) } -func (man Handshaker) CLIQuery(ctx context.CLIContext, connid string) (HandshakeObject, error) { - obj := man.man.Object(connid) - conn, _, err := obj.ConnectionCLI(ctx) +func (man Handshaker) CLIQuery(q state.ABCIQuerier, connid string) (HandshakeState, error) { + state, err := man.man.CLIQuery(q, connid) if err != nil { - return HandshakeObject{}, err + return HandshakeState{}, err } - obj.Client = man.man.client.Object(conn.Client) - return man.Object(obj), nil + return man.CreateState(state), nil } -func (obj HandshakeObject) StateCLI(ctx context.CLIContext) (res byte, proof merkle.Proof, err error){ - res, tmproof, err := obj.State.Query(ctx) - proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.State) +func (obj HandshakeState) StageCLI(q state.ABCIQuerier) (res byte, proof merkle.Proof, err error) { + res, tmproof, err := obj.Stage.Query(q) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Stage) return } -func (obj HandshakeObject) CounterpartyClientCLI(ctx context.CLIContext) (res string, proof merkle.Proof, err error) { - res, tmproof, err := obj.CounterpartyClient.Query(ctx) +func (obj HandshakeState) CounterpartyClientCLI(q state.ABCIQuerier) (res string, proof merkle.Proof, err error) { + res, tmproof, err := obj.CounterpartyClient.Query(q) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.CounterpartyClient) - return -} - -func (obj HandshakeObject) NextTimeoutCLI(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error){ - res, tmproof, err := obj.NextTimeout.Query(ctx) - proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.NextTimeout) return } diff --git a/x/ibc/03-connection/client/cli/query.go b/x/ibc/03-connection/client/cli/query.go index efc330969faa..74c982e9cb52 100644 --- a/x/ibc/03-connection/client/cli/query.go +++ b/x/ibc/03-connection/client/cli/query.go @@ -12,22 +12,21 @@ import ( "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client" - "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/utils" + "github.com/cosmos/cosmos-sdk/x/ibc/version" ) const ( FlagProve = "prove" ) - -func object(cdc *codec.Codec, storeKey string, prefix []byte, connid, clientid string) connection.Object { +func object(cdc *codec.Codec, storeKey string, prefix []byte, connid, clientid string) connection.State { base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) climan := client.NewManager(base) man := connection.NewManager(base, climan) - return man.CLIObject(connid, clientid) + return man.CLIState(connid, clientid) } func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { @@ -44,29 +43,31 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { return ibcQueryCmd } -func QueryConnection(ctx context.CLIContext, obj connection.Object, prove bool) (res utils.JSONObject, err error) { - conn, connp, err := obj.ConnectionCLI(ctx) +func QueryConnection(ctx context.CLIContext, obj connection.State, prove bool) (res utils.JSONState, err error) { + q := state.NewCLIQuerier(ctx) + + conn, connp, err := obj.ConnectionCLI(q) if err != nil { return } - avail, availp, err := obj.AvailableCLI(ctx) + avail, availp, err := obj.AvailableCLI(q) if err != nil { return } - kind, kindp, err := obj.KindCLI(ctx) + kind, kindp, err := obj.KindCLI(q) if err != nil { return } if prove { - return utils.NewJSONObject( + return utils.NewJSONState( conn, connp, avail, availp, kind, kindp, ), nil } - return utils.NewJSONObject( + return utils.NewJSONState( conn, nil, avail, nil, kind, nil, @@ -80,7 +81,7 @@ func GetCmdQueryConnection(storeKey string, cdc *codec.Codec) *cobra.Command { Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) - obj := object(cdc, storeKey, ibc.VersionPrefix(ibc.Version), args[0], "") + obj := object(cdc, storeKey, version.Prefix(version.Version), args[0], "") jsonobj, err := QueryConnection(ctx, obj, viper.GetBool(FlagProve)) if err != nil { return err diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index 68283021c36e..43ce9ae810e1 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -1,29 +1,31 @@ package cli import ( + "fmt" "io/ioutil" + "time" "github.com/spf13/cobra" "github.com/spf13/viper" + tmtypes "github.com/tendermint/tendermint/types" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/client/utils" - "github.com/cosmos/cosmos-sdk/x/ibc" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client" - "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) -/* -func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/version" +) -} -*/ const ( FlagNode1 = "node1" FlagNode2 = "node2" @@ -31,14 +33,14 @@ const ( FlagFrom2 = "from2" ) -func handshake(ctx context.CLIContext, cdc *codec.Codec, storeKey string, prefix []byte, connid string) (connection.HandshakeObject, error) { +func handshake(q state.ABCIQuerier, cdc *codec.Codec, storeKey string, prefix []byte, connid string) (connection.HandshakeState, error) { base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) - climan := client.NewManager(base) - man := connection.NewHandshaker(connection.NewManager(base, climan)) - return man.CLIQuery(ctx, connid) + clientManager := client.NewManager(base) + man := connection.NewHandshaker(connection.NewManager(base, clientManager)) + return man.CLIQuery(q, connid) } -func lastheight(ctx context.CLIContext) (uint64, error) { +func lastHeight(ctx context.CLIContext) (uint64, error) { node, err := ctx.GetNode() if err != nil { return 0, err @@ -52,165 +54,271 @@ func lastheight(ctx context.CLIContext) (uint64, error) { return uint64(info.Response.LastBlockHeight), nil } -func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { +func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "connection", + Short: "IBC connection transaction subcommands", + } + + cmd.AddCommand( + GetCmdHandshake(storeKey, cdc), + ) + + return cmd +} + +// TODO: move to 02/tendermint +func getHeader(ctx context.CLIContext) (res tendermint.Header, err error) { + node, err := ctx.GetNode() + if err != nil { + return + } + + info, err := node.ABCIInfo() + if err != nil { + return + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return + } + + nextvalidators, err := node.Validators(&height) + if err != nil { + return + } + + res = tendermint.Header{ + SignedHeader: commit.SignedHeader, + ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), + } + + return +} + +func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "handshake", Short: "initiate connection handshake between two chains", - Args: cobra.ExactArgs(4), - // Args: []string{connid1, connfilepath1, connid2, connfilepath2} + Args: cobra.ExactArgs(6), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - ctx1 := context.NewCLIContext(). + ctx1 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). WithCodec(cdc). WithNodeURI(viper.GetString(FlagNode1)). - WithFrom(viper.GetString(FlagFrom1)) + WithBroadcastMode(flags.BroadcastBlock) + q1 := state.NewCLIQuerier(ctx1) - ctx2 := context.NewCLIContext(). + ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). WithCodec(cdc). WithNodeURI(viper.GetString(FlagNode2)). - WithFrom(viper.GetString(FlagFrom2)) + WithBroadcastMode(flags.BroadcastBlock) + q2 := state.NewCLIQuerier(ctx2) + + connId1 := args[0] + clientId1 := args[1] + connId2 := args[3] + clientId2 := args[4] - conn1id := args[0] - conn1bz, err := ioutil.ReadFile(args[1]) + var path1 commitment.Path + path1bz, err := ioutil.ReadFile(args[2]) if err != nil { return err } - var conn1 connection.Connection - if err := cdc.UnmarshalJSON(conn1bz, &conn1); err != nil { + if err = cdc.UnmarshalJSON(path1bz, &path1); err != nil { return err } + conn1 := connection.Connection{ + Client: clientId1, + Counterparty: connId2, + Path: path1, + } - obj1, err := handshake(ctx1, cdc, storeKey, ibc.VersionPrefix(ibc.Version), conn1id) + obj1, err := handshake(q1, cdc, storeKey, version.DefaultPrefix(), connId1) if err != nil { return err } - conn2id := args[2] - conn2bz, err := ioutil.ReadFile(args[3]) + var path2 commitment.Path + path2bz, err := ioutil.ReadFile(args[5]) if err != nil { return err } - var conn2 connection.Connection - if err := cdc.UnmarshalJSON(conn2bz, &conn2); err != nil { + if err = cdc.UnmarshalJSON(path2bz, &path2); err != nil { return err } + conn2 := connection.Connection{ + Client: clientId2, + Counterparty: connId1, + Path: path2, + } - obj2, err := handshake(ctx2, cdc, storeKey, ibc.VersionPrefix(ibc.Version), conn1id) + obj2, err := handshake(q2, cdc, storeKey, version.DefaultPrefix(), connId2) if err != nil { return err } // TODO: check state and if not Idle continue existing process - height, err := lastheight(ctx2) - if err != nil { - return err - } - nextTimeout := height + 1000 // TODO: parameterize - msginit := connection.MsgOpenInit{ - ConnectionID: conn1id, + msgInit := connection.MsgOpenInit{ + ConnectionID: connId1, Connection: conn1, CounterpartyClient: conn2.Client, - NextTimeout: nextTimeout, Signer: ctx1.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msginit}) + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgInit}) if err != nil { return err } - timeout := nextTimeout - height, err = lastheight(ctx1) + // Another block has to be passed after msgInit is committed + // to retrieve the correct proofs + // TODO: Modify this to actually check two blocks being processed, and + // remove hardcoding this to 8 seconds. + time.Sleep(8 * time.Second) + + header, err := getHeader(ctx1) if err != nil { return err } - nextTimeout = height + 1000 - _, pconn, err := obj1.ConnectionCLI(ctx1) + + msgUpdate := client.MsgUpdateClient{ + ClientID: conn2.Client, + Header: header, + Signer: ctx2.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) if err != nil { return err } - _, pstate, err := obj1.StateCLI(ctx1) + + q1 = state.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) + fmt.Printf("querying from %d\n", header.Height-1) + + _, pconn, err := obj1.ConnectionCLI(q1) if err != nil { return err } - _, ptimeout, err := obj1.NextTimeoutCLI(ctx1) + _, pstate, err := obj1.StageCLI(q1) if err != nil { return err } - _, pcounter, err := obj1.CounterpartyClientCLI(ctx1) + _, pcounter, err := obj1.CounterpartyClientCLI(q1) if err != nil { return err } - msgtry := connection.MsgOpenTry{ - ConnectionID: conn2id, + msgTry := connection.MsgOpenTry{ + ConnectionID: connId2, Connection: conn2, CounterpartyClient: conn1.Client, - Timeout: timeout, - NextTimeout: nextTimeout, - Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, + Proofs: []commitment.Proof{pconn, pstate, pcounter}, + Height: uint64(header.Height), Signer: ctx2.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgtry}) + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgTry}) if err != nil { return err } - timeout = nextTimeout - height, err = lastheight(ctx2) + // Another block has to be passed after msgInit is committed + // to retrieve the correct proofs + // TODO: Modify this to actually check two blocks being processed, and + // remove hardcoding this to 8 seconds. + time.Sleep(8 * time.Second) + + header, err = getHeader(ctx2) if err != nil { return err } - nextTimeout = height + 1000 - _, pconn, err = obj2.ConnectionCLI(ctx2) + + msgUpdate = client.MsgUpdateClient{ + ClientID: conn1.Client, + Header: header, + Signer: ctx1.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgUpdate}) if err != nil { return err } - _, pstate, err = obj2.StateCLI(ctx2) + + q2 = state.NewCLIQuerier(ctx2.WithHeight(header.Height - 1)) + + _, pconn, err = obj2.ConnectionCLI(q2) if err != nil { return err } - _, ptimeout, err = obj2.NextTimeoutCLI(ctx2) + _, pstate, err = obj2.StageCLI(q2) if err != nil { return err } - _, pcounter, err = obj2.CounterpartyClientCLI(ctx2) + _, pcounter, err = obj2.CounterpartyClientCLI(q2) if err != nil { return err } - msgack := connection.MsgOpenAck{ - ConnectionID: conn1id, - Timeout: timeout, - NextTimeout: nextTimeout, - Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, + msgAck := connection.MsgOpenAck{ + ConnectionID: connId1, + Proofs: []commitment.Proof{pconn, pstate, pcounter}, + Height: uint64(header.Height), Signer: ctx1.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgack}) + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgAck}) + if err != nil { + return err + } + + // Another block has to be passed after msgInit is committed + // to retrieve the correct proofs + // TODO: Modify this to actually check two blocks being processed, and + // remove hardcoding this to 8 seconds. + time.Sleep(8 * time.Second) + + header, err = getHeader(ctx1) if err != nil { return err } - timeout = nextTimeout - _, pstate, err = obj1.StateCLI(ctx1) + msgUpdate = client.MsgUpdateClient{ + ClientID: conn2.Client, + Header: header, + Signer: ctx2.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) if err != nil { return err } - _, ptimeout, err = obj1.NextTimeoutCLI(ctx1) + + q1 = state.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) + + _, pstate, err = obj1.StageCLI(q1) if err != nil { return err } - msgconfirm := connection.MsgOpenConfirm{ - ConnectionID: conn2id, - Timeout: timeout, - Proofs: []commitment.Proof{pstate, ptimeout}, + msgConfirm := connection.MsgOpenConfirm{ + ConnectionID: connId2, + Proofs: []commitment.Proof{pstate}, + Height: uint64(header.Height), Signer: ctx2.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgconfirm}) + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgConfirm}) if err != nil { return err } @@ -219,5 +327,14 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command }, } + // TODO: Provide flag description + cmd.Flags().String(FlagNode1, "tcp://localhost:26657", "") + cmd.Flags().String(FlagNode2, "tcp://localhost:26657", "") + cmd.Flags().String(FlagFrom1, "", "") + cmd.Flags().String(FlagFrom2, "", "") + + cmd.MarkFlagRequired(FlagFrom1) + cmd.MarkFlagRequired(FlagFrom2) + return cmd } diff --git a/x/ibc/03-connection/client/utils/types.go b/x/ibc/03-connection/client/utils/types.go index 33480a68291f..9e7e2c807b20 100644 --- a/x/ibc/03-connection/client/utils/types.go +++ b/x/ibc/03-connection/client/utils/types.go @@ -1,25 +1,30 @@ package utils import ( - "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -type JSONObject struct { +type JSONState struct { Connection connection.Connection `json:"connection"` ConnectionProof commitment.Proof `json:"connection_proof,omitempty"` Available bool `json:"available"` AvailableProof commitment.Proof `json:"available_proof,omitempty"` Kind string `json:"kind"` KindProof commitment.Proof `json:"kind_proof,omitempty"` + + State byte `json:"state,omitempty"` + StateProof commitment.Proof `json:"state_proof,omitempty"` + CounterpartyClient string `json:"counterparty_client,omitempty"` + CounterpartyClientProof commitment.Proof `json:"counterparty_client_proof,omitempty"` } -func NewJSONObject( +func NewJSONState( conn connection.Connection, connp commitment.Proof, avail bool, availp commitment.Proof, kind string, kindp commitment.Proof, -) JSONObject { - return JSONObject{ +) JSONState { + return JSONState{ Connection: conn, ConnectionProof: connp, Available: avail, @@ -29,31 +34,24 @@ func NewJSONObject( } } -type HandshakeJSONObject struct { - JSONObject `json:"connection"` - State byte `json:"state"` - StateProof commitment.Proof `json:"state_proof,omitempty"` - CounterpartyClient string `json:"counterparty_client"` - CounterpartyClientProof commitment.Proof `json:"counterparty_client_proof,omitempty"` - NextTimeout uint64 `json:"next_timeout"` - NextTimeoutProof commitment.Proof `json:"next_timeout_proof,omitempty"` -} - -func NewHandshakeJSONObject( +func NewHandshakeJSONState( conn connection.Connection, connp commitment.Proof, avail bool, availp commitment.Proof, kind string, kindp commitment.Proof, state byte, statep commitment.Proof, cpclient string, cpclientp commitment.Proof, - timeout uint64, timeoutp commitment.Proof, -) HandshakeJSONObject { - return HandshakeJSONObject{ - JSONObject: NewJSONObject(conn, connp, avail, availp, kind, kindp), +) JSONState { + return JSONState{ + Connection: conn, + ConnectionProof: connp, + Available: avail, + AvailableProof: availp, + Kind: kind, + KindProof: kindp, + State: state, StateProof: statep, CounterpartyClient: cpclient, CounterpartyClientProof: cpclientp, - NextTimeout: timeout, - NextTimeoutProof: timeoutp, } } diff --git a/x/ibc/03-connection/codec.go b/x/ibc/03-connection/codec.go new file mode 100644 index 000000000000..a3e2284b38a8 --- /dev/null +++ b/x/ibc/03-connection/codec.go @@ -0,0 +1,24 @@ +package connection + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +var MsgCdc *codec.Codec + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(MsgOpenInit{}, "ibc/connection/MsgOpenInit", nil) + cdc.RegisterConcrete(MsgOpenTry{}, "ibc/connection/MsgOpenTry", nil) + cdc.RegisterConcrete(MsgOpenAck{}, "ibc/connection/MsgOpenAck", nil) + cdc.RegisterConcrete(MsgOpenConfirm{}, "ibc/connection/MsgOpenConfirm", nil) +} + +func SetMsgCodec(cdc *codec.Codec) { + // TODO + /* + if MsgCdc != nil && MsgCdc != cdc { + panic("MsgCdc set more than once") + } + */ + MsgCdc = cdc +} diff --git a/x/ibc/03-connection/handler.go b/x/ibc/03-connection/handler.go index 738ba38da7e0..f516c0a5d6df 100644 --- a/x/ibc/03-connection/handler.go +++ b/x/ibc/03-connection/handler.go @@ -5,33 +5,37 @@ import ( ) func HandleMsgOpenInit(ctx sdk.Context, msg MsgOpenInit, man Handshaker) sdk.Result { - _, err := man.OpenInit(ctx, msg.ConnectionID, msg.Connection, msg.CounterpartyClient, msg.NextTimeout) + _, err := man.OpenInit(ctx, msg.ConnectionID, msg.Connection, msg.CounterpartyClient) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), 100, "").Result() + // TODO: Define the error code in errors + return sdk.NewError(sdk.CodespaceType("ibc"), 100, err.Error()).Result() } return sdk.Result{} } func HandleMsgOpenTry(ctx sdk.Context, msg MsgOpenTry, man Handshaker) sdk.Result { - _, err := man.OpenTry(ctx, msg.Proofs, msg.ConnectionID, msg.Connection, msg.CounterpartyClient, msg.Timeout, msg.NextTimeout) + _, err := man.OpenTry(ctx, msg.Proofs, msg.Height, msg.ConnectionID, msg.Connection, msg.CounterpartyClient) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), 200, "").Result() + // TODO: Define the error code in errors + return sdk.NewError(sdk.CodespaceType("ibc"), 200, err.Error()).Result() } return sdk.Result{} } func HandleMsgOpenAck(ctx sdk.Context, msg MsgOpenAck, man Handshaker) sdk.Result { - _, err := man.OpenAck(ctx, msg.Proofs, msg.ConnectionID, msg.Timeout, msg.NextTimeout) + _, err := man.OpenAck(ctx, msg.Proofs, msg.Height, msg.ConnectionID) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), 300, "").Result() + // TODO: Define the error code in errors + return sdk.NewError(sdk.CodespaceType("ibc"), 300, err.Error()).Result() } return sdk.Result{} } func HandleMsgOpenConfirm(ctx sdk.Context, msg MsgOpenConfirm, man Handshaker) sdk.Result { - _, err := man.OpenConfirm(ctx, msg.Proofs, msg.ConnectionID, msg.Timeout) + _, err := man.OpenConfirm(ctx, msg.Proofs, msg.Height, msg.ConnectionID) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), 400, "").Result() + // TODO: Define the error code in errors + return sdk.NewError(sdk.CodespaceType("ibc"), 400, err.Error()).Result() } return sdk.Result{} } diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index c5d9debba1a3..e4c59386d2f6 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -6,13 +6,13 @@ import ( "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -type State = byte +type HandshakeStage = byte const ( - Idle State = iota + Idle HandshakeStage = iota Init OpenTry Open @@ -25,17 +25,13 @@ const HandshakeKind = "handshake" type Handshaker struct { man Manager - counterparty CounterpartyHandshaker + counterParty CounterpartyHandshaker } -// TODO: ocapify Manager; an actor who holds Manager -// should not be able to construct creaters from it -// or add Seal() method to Manager? func NewHandshaker(man Manager) Handshaker { return Handshaker{ man: man, - - counterparty: CounterpartyHandshaker{man.counterparty}, + counterParty: CounterpartyHandshaker{man.counterparty}, } } @@ -43,123 +39,102 @@ type CounterpartyHandshaker struct { man CounterpartyManager } -type HandshakeObject struct { - Object +type HandshakeState struct { + State - State state.Enum + Stage state.Enum CounterpartyClient state.String - NextTimeout state.Integer - Counterparty CounterHandshakeObject + Counterparty CounterHandshakeState } -type CounterHandshakeObject struct { - CounterObject +type CounterHandshakeState struct { + CounterState - State commitment.Enum + Stage commitment.Enum CounterpartyClient commitment.String - NextTimeout commitment.Integer } // CONTRACT: client and remote must be filled by the caller -func (man Handshaker) Object(parent Object) HandshakeObject { - return HandshakeObject{ - Object: parent, - - State: man.man.protocol.Value([]byte(parent.id + "/state")).Enum(), +func (man Handshaker) CreateState(parent State) HandshakeState { + return HandshakeState{ + State: parent, + Stage: man.man.protocol.Value([]byte(parent.id + "/state")).Enum(), CounterpartyClient: man.man.protocol.Value([]byte(parent.id + "/counterpartyClient")).String(), - NextTimeout: man.man.protocol.Value([]byte(parent.id + "/timeout")).Integer(state.Dec), - // CONTRACT: counterparty must be filled by the caller + // CONTRACT: counterParty must be filled by the caller } } -func (man CounterpartyHandshaker) Object(id string) CounterHandshakeObject { - return CounterHandshakeObject{ - CounterObject: man.man.Object(id), - - State: man.man.protocol.Value([]byte(id + "/state")).Enum(), +func (man CounterpartyHandshaker) CreateState(id string) CounterHandshakeState { + return CounterHandshakeState{ + CounterState: man.man.CreateState(id), + Stage: man.man.protocol.Value([]byte(id + "/state")).Enum(), CounterpartyClient: man.man.protocol.Value([]byte(id + "/counterpartyClient")).String(), - NextTimeout: man.man.protocol.Value([]byte(id + "/timeout")).Integer(state.Dec), } } -func (man Handshaker) create(ctx sdk.Context, id string, connection Connection, counterpartyClient string) (obj HandshakeObject, err error) { +func (man Handshaker) create(ctx sdk.Context, id string, connection Connection, counterpartyClient string) (obj HandshakeState, err error) { cobj, err := man.man.create(ctx, id, connection, HandshakeKind) if err != nil { return } - obj = man.Object(cobj) + obj = man.CreateState(cobj) obj.CounterpartyClient.Set(ctx, counterpartyClient) - obj.Counterparty = man.counterparty.Object(connection.Counterparty) + obj.Counterparty = man.counterParty.CreateState(connection.Counterparty) return obj, nil } -func (man Handshaker) query(ctx sdk.Context, id string) (obj HandshakeObject, err error) { +func (man Handshaker) query(ctx sdk.Context, id string) (obj HandshakeState, err error) { cobj, err := man.man.query(ctx, id, HandshakeKind) if err != nil { return } - obj = man.Object(cobj) - obj.Counterparty = man.counterparty.Object(obj.GetConnection(ctx).Counterparty) + obj = man.CreateState(cobj) + obj.Counterparty = man.counterParty.CreateState(obj.GetConnection(ctx).Counterparty) return } -func (obj HandshakeObject) remove(ctx sdk.Context) { - obj.Object.remove(ctx) - obj.State.Delete(ctx) +func (obj HandshakeState) remove(ctx sdk.Context) { + obj.State.remove(ctx) + obj.Stage.Delete(ctx) obj.CounterpartyClient.Delete(ctx) - obj.NextTimeout.Delete(ctx) -} - -func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { - if uint64(ctx.BlockHeight()) > timeoutHeight { - return errors.New("timeout") - } - - return nil } // Using proofs: none func (man Handshaker) OpenInit(ctx sdk.Context, - id string, connection Connection, counterpartyClient string, nextTimeoutHeight uint64, -) (HandshakeObject, error) { + id string, connection Connection, counterpartyClient string, +) (HandshakeState, error) { // man.Create() will ensure // assert(get("connections/{identifier}") === null) and // set("connections{identifier}", connection) obj, err := man.create(ctx, id, connection, counterpartyClient) if err != nil { - return HandshakeObject{}, err + return HandshakeState{}, err } - obj.NextTimeout.Set(ctx, nextTimeoutHeight) - obj.State.Set(ctx, Init) + obj.Stage.Set(ctx, Init) return obj, nil } -// Using proofs: counterparty.{connection,state,nextTimeout,counterpartyClient, client} +// Using proofs: counterParty.{connection,state,nextTimeout,counterpartyClient, client} func (man Handshaker) OpenTry(ctx sdk.Context, - proofs []commitment.Proof, - id string, connection Connection, counterpartyClient string, timeoutHeight, nextTimeoutHeight uint64, -) (obj HandshakeObject, err error) { + proofs []commitment.Proof, height uint64, + id string, connection Connection, counterpartyClient string, +) (obj HandshakeState, err error) { obj, err = man.create(ctx, id, connection, counterpartyClient) if err != nil { return } - ctx, err = obj.Context(ctx, connection.Path, proofs) - if err != nil { - return - } - - err = assertTimeout(ctx, timeoutHeight) + ctx, err = obj.Context(ctx, height, proofs) if err != nil { return } - if !obj.Counterparty.State.Is(ctx, Init) { - err = errors.New("counterparty state not init") + if !obj.Counterparty.Stage.Is(ctx, Init) { + err = errors.New("counterParty state not init") return } @@ -168,17 +143,12 @@ func (man Handshaker) OpenTry(ctx sdk.Context, Counterparty: id, Path: obj.path, }) { - err = errors.New("wrong counterparty connection") + err = errors.New("wrong counterParty connection") return } if !obj.Counterparty.CounterpartyClient.Is(ctx, connection.Client) { - err = errors.New("counterparty client not match") - return - } - - if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { - err = errors.New("unexpected counterparty timeout value") + err = errors.New("counterParty client not match") return } @@ -188,8 +158,8 @@ func (man Handshaker) OpenTry(ctx sdk.Context, /* var expected client.ConsensusState obj.self.Get(ctx, expheight, &expected) - if !obj.counterparty.client.Is(ctx, expected) { - return errors.New("unexpected counterparty client value") + if !obj.counterParty.client.Is(ctx, expected) { + return errors.New("unexpected counterParty client value") } */ @@ -198,58 +168,47 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // assert(get("connections/{desiredIdentifier}") === null) and // set("connections{identifier}", connection) - obj.State.Set(ctx, OpenTry) - obj.NextTimeout.Set(ctx, nextTimeoutHeight) + obj.Stage.Set(ctx, OpenTry) return } -// Using proofs: counterparty.{connection, state, timeout, counterpartyClient, client} +// Using proofs: counterParty.{connection, state, timeout, counterpartyClient, client} func (man Handshaker) OpenAck(ctx sdk.Context, - proofs []commitment.Proof, - id string /*expheight uint64, */, timeoutHeight, nextTimeoutHeight uint64, -) (obj HandshakeObject, err error) { + proofs []commitment.Proof, height uint64, + id string, +) (obj HandshakeState, err error) { obj, err = man.query(ctx, id) if err != nil { return } - ctx, err = obj.Context(ctx, nil, proofs) + ctx, err = obj.Context(ctx, height, proofs) if err != nil { return } - if !obj.State.Transit(ctx, Init, Open) { + if !obj.Stage.Transit(ctx, Init, Open) { err = errors.New("ack on non-init connection") return } - err = assertTimeout(ctx, timeoutHeight) - if err != nil { - return - } - if !obj.Counterparty.Connection.Is(ctx, Connection{ Client: obj.CounterpartyClient.Get(ctx), Counterparty: obj.ID(), Path: obj.path, }) { - err = errors.New("wrong counterparty") + err = errors.New("wrong counterParty") return } - if !obj.Counterparty.State.Is(ctx, OpenTry) { - err = errors.New("counterparty state not opentry") + if !obj.Counterparty.Stage.Is(ctx, OpenTry) { + err = errors.New("counterParty state not opentry") return } if !obj.Counterparty.CounterpartyClient.Is(ctx, obj.GetConnection(ctx).Client) { - err = errors.New("counterparty client not match") - return - } - - if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { - err = errors.New("unexpected counterparty timeout value") + err = errors.New("counterParty client not match") return } @@ -257,160 +216,41 @@ func (man Handshaker) OpenAck(ctx sdk.Context, /* var expected client.ConsensusState // obj.self.Get(ctx, expheight, &expected) - if !obj.counterparty.client.Is(ctx, expected) { - // return errors.New("unexpected counterparty client value") + if !obj.counterParty.client.Is(ctx, expected) { + // return errors.New("unexpected counterParty client value") } */ obj.Available.Set(ctx, true) - obj.NextTimeout.Set(ctx, nextTimeoutHeight) return } -// Using proofs: counterparty.{connection,state, nextTimeout} +// Using proofs: counterParty.{connection,state, nextTimeout} func (man Handshaker) OpenConfirm(ctx sdk.Context, - proofs []commitment.Proof, - id string, timeoutHeight uint64) (obj HandshakeObject, err error) { + proofs []commitment.Proof, height uint64, + id string) (obj HandshakeState, err error) { obj, err = man.query(ctx, id) if err != nil { return } - ctx, err = obj.Context(ctx, nil, proofs) + ctx, err = obj.Context(ctx, height, proofs) if err != nil { return } - if !obj.State.Transit(ctx, OpenTry, Open) { + if !obj.Stage.Transit(ctx, OpenTry, Open) { err = errors.New("confirm on non-try connection") return } - err = assertTimeout(ctx, timeoutHeight) - if err != nil { - return - } - - if !obj.Counterparty.State.Is(ctx, Open) { - err = errors.New("counterparty state not open") - return - } - - if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { - err = errors.New("unexpected counterparty timeout value") + if !obj.Counterparty.Stage.Is(ctx, Open) { + err = errors.New("counterParty state not open") return } obj.Available.Set(ctx, true) - obj.NextTimeout.Set(ctx, 0) return } - -func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { - if !(obj.Client.GetConsensusState(ctx).GetHeight() > obj.NextTimeout.Get(ctx)) { - return errors.New("timeout height not yet reached") - } - - switch obj.State.Get(ctx) { - case Init: - if !obj.Counterparty.Connection.Is(ctx, nil) { - return errors.New("counterparty connection exists") - } - case OpenTry: - if !(obj.Counterparty.State.Is(ctx, Init) || - obj.Counterparty.Connection.Is(ctx, nil)) { - return errors.New("counterparty connection state not init") - } - // XXX: check if we need to verify symmetricity for timeout (already proven in OpenTry) - case Open: - if obj.Counterparty.State.Is(ctx, OpenTry) { - return errors.New("counterparty connection state not tryopen") - } - } - - obj.remove(ctx) - - return nil -} - -func (obj HandshakeObject) CloseInit(ctx sdk.Context, nextTimeout uint64) error { - if !obj.State.Transit(ctx, Open, CloseTry) { - return errors.New("closeinit on non-open connection") - } - - obj.NextTimeout.Set(ctx, nextTimeout) - - return nil -} - -func (obj HandshakeObject) CloseTry(ctx sdk.Context, timeoutHeight, nextTimeoutHeight uint64) error { - if !obj.State.Transit(ctx, Open, Closed) { - return errors.New("closetry on non-open connection") - } - - err := assertTimeout(ctx, timeoutHeight) - if err != nil { - return err - } - - if !obj.Counterparty.State.Is(ctx, CloseTry) { - return errors.New("unexpected counterparty state value") - } - - if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { - return errors.New("unexpected counterparty timeout value") - } - - obj.NextTimeout.Set(ctx, nextTimeoutHeight) - - return nil -} - -func (obj HandshakeObject) CloseAck(ctx sdk.Context, timeoutHeight uint64) error { - if !obj.State.Transit(ctx, CloseTry, Closed) { - return errors.New("closeack on non-closetry connection") - } - - err := assertTimeout(ctx, timeoutHeight) - if err != nil { - return err - } - - if !obj.Counterparty.State.Is(ctx, Closed) { - return errors.New("unexpected counterparty state value") - } - - if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { - return errors.New("unexpected counterparty timeout value") - } - - obj.NextTimeout.Set(ctx, 0) - - return nil -} - -func (obj HandshakeObject) CloseTimeout(ctx sdk.Context) error { - if !(obj.Client.GetConsensusState(ctx).GetHeight() > obj.NextTimeout.Get(ctx)) { - return errors.New("timeout height not yet reached") - } - - // XXX: double check if the user can bypass the verification logic somehow - switch obj.State.Get(ctx) { - case CloseTry: - if !obj.Counterparty.State.Is(ctx, Open) { - return errors.New("counterparty connection state not open") - } - case Closed: - if !obj.Counterparty.State.Is(ctx, CloseTry) { - return errors.New("counterparty connection state not closetry") - } - } - - obj.State.Set(ctx, Open) - obj.NextTimeout.Set(ctx, 0) - - return nil - -} diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index f4e4d6432c29..ffeaaeef6d5f 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -7,8 +7,8 @@ import ( "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) @@ -24,7 +24,7 @@ type Manager struct { func NewManager(protocol state.Mapping, client client.Manager) Manager { return Manager{ - protocol: protocol.Prefix(LocalRoot()), + protocol: protocol.Prefix(LocalRoot()), client: client, counterparty: NewCounterpartyManager(protocol.Cdc()), path: merkle.NewPath([][]byte{[]byte(protocol.StoreName())}, protocol.PrefixBytes()), @@ -47,7 +47,7 @@ func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { } } -type Object struct { +type State struct { id string protocol state.Mapping @@ -56,13 +56,13 @@ type Object struct { Kind state.String - Client client.Object + Client client.State path merkle.Path } -func (man Manager) Object(id string) Object { - return Object{ +func (man Manager) State(id string) State { + return State{ id: id, protocol: man.protocol.Prefix([]byte(id + "/")), @@ -77,7 +77,7 @@ func (man Manager) Object(id string) Object { } } -type CounterObject struct { +type CounterState struct { id string protocol commitment.Mapping @@ -86,11 +86,11 @@ type CounterObject struct { Kind commitment.String - Client client.CounterObject // nolint: unused + Client client.CounterState // nolint: unused } -func (man CounterpartyManager) Object(id string) CounterObject { - return CounterObject{ +func (man CounterpartyManager) CreateState(id string) CounterState { + return CounterState{ id: id, protocol: man.protocol.Prefix([]byte(id + "/")), Connection: man.protocol.Value([]byte(id)), @@ -102,15 +102,15 @@ func (man CounterpartyManager) Object(id string) CounterObject { } } -func (obj Object) Context(ctx sdk.Context, optpath commitment.Path, proofs []commitment.Proof) (sdk.Context, error) { - if optpath == nil { - optpath = obj.GetConnection(ctx).Path +func (obj State) Context(ctx sdk.Context, height uint64, proofs []commitment.Proof) (sdk.Context, error) { + root, err := obj.Client.GetRoot(ctx, height) + if err != nil { + return ctx, err } store, err := commitment.NewStore( - // TODO: proof root should be able to be obtained from the past - obj.Client.GetConsensusState(ctx).GetRoot(), - optpath, + root, + obj.GetConnection(ctx).Path, proofs, ) if err != nil { @@ -120,30 +120,30 @@ func (obj Object) Context(ctx sdk.Context, optpath commitment.Path, proofs []com return commitment.WithStore(ctx, store), nil } -func (obj Object) ID() string { +func (obj State) ID() string { return obj.id } -func (obj Object) GetConnection(ctx sdk.Context) (res Connection) { +func (obj State) GetConnection(ctx sdk.Context) (res Connection) { obj.Connection.Get(ctx, &res) return } -func (obj Object) Sendable(ctx sdk.Context) bool { +func (obj State) Sendable(ctx sdk.Context) bool { return kinds[obj.Kind.Get(ctx)].Sendable } -func (obj Object) Receivable(ctx sdk.Context) bool { +func (obj State) Receivable(ctx sdk.Context) bool { return kinds[obj.Kind.Get(ctx)].Receivable } -func (obj Object) remove(ctx sdk.Context) { +func (obj State) remove(ctx sdk.Context) { obj.Connection.Delete(ctx) obj.Available.Delete(ctx) obj.Kind.Delete(ctx) } -func (obj Object) exists(ctx sdk.Context) bool { +func (obj State) exists(ctx sdk.Context) bool { return obj.Connection.Exists(ctx) } @@ -151,10 +151,10 @@ func (man Manager) Cdc() *codec.Codec { return man.protocol.Cdc() } -func (man Manager) create(ctx sdk.Context, id string, connection Connection, kind string) (obj Object, err error) { - obj = man.Object(id) +func (man Manager) create(ctx sdk.Context, id string, connection Connection, kind string) (obj State, err error) { + obj = man.State(id) if obj.exists(ctx) { - err = errors.New("Object already exists") + err = errors.New("Stage already exists") return } obj.Client, err = man.client.Query(ctx, connection.Client) @@ -169,10 +169,10 @@ func (man Manager) create(ctx sdk.Context, id string, connection Connection, kin // query() is used internally by the connection creators // checks connection kind, doesn't check avilability -func (man Manager) query(ctx sdk.Context, id string, kind string) (obj Object, err error) { - obj = man.Object(id) +func (man Manager) query(ctx sdk.Context, id string, kind string) (obj State, err error) { + obj = man.State(id) if !obj.exists(ctx) { - err = errors.New("Object not exists") + err = errors.New("Stage not exists") return } obj.Client, err = man.client.Query(ctx, obj.GetConnection(ctx).Client) @@ -186,15 +186,15 @@ func (man Manager) query(ctx sdk.Context, id string, kind string) (obj Object, e return } -func (man Manager) Query(ctx sdk.Context, id string) (obj Object, err error) { - obj = man.Object(id) +func (man Manager) Query(ctx sdk.Context, id string) (obj State, err error) { + obj = man.State(id) if !obj.exists(ctx) { - err = errors.New("Object not exists") + err = errors.New("Stage not exists") return } if !obj.Available.Get(ctx) { - err = errors.New("Object not available") + err = errors.New("Stage not available") return } obj.Client, err = man.client.Query(ctx, obj.GetConnection(ctx).Client) diff --git a/x/ibc/03-connection/msgs.go b/x/ibc/03-connection/msgs.go index 3944599ff6a3..5848558554b0 100644 --- a/x/ibc/03-connection/msgs.go +++ b/x/ibc/03-connection/msgs.go @@ -2,18 +2,17 @@ package connection import ( sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) const Route = "ibc" type MsgOpenInit struct { - ConnectionID string - Connection Connection - CounterpartyClient string - NextTimeout uint64 - Signer sdk.AccAddress + ConnectionID string `json:"connection_id"` + Connection Connection `json:"connection"` + CounterpartyClient string `json:"counterparty_client"` + NextTimeout uint64 `json:"next_timeout"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenInit{} @@ -31,7 +30,7 @@ func (msg MsgOpenInit) ValidateBasic() sdk.Error { } func (msg MsgOpenInit) GetSignBytes() []byte { - return nil // TODO + return sdk.MustSortJSON(MsgCdc.MustMarshalJSON(msg)) } func (msg MsgOpenInit) GetSigners() []sdk.AccAddress { @@ -39,13 +38,14 @@ func (msg MsgOpenInit) GetSigners() []sdk.AccAddress { } type MsgOpenTry struct { - ConnectionID string - Connection Connection - CounterpartyClient string - Timeout uint64 - NextTimeout uint64 - Proofs []commitment.Proof - Signer sdk.AccAddress + ConnectionID string `json:"connection_id"` + Connection Connection `json:"connection"` + CounterpartyClient string `json:"counterparty_client"` + Timeout uint64 `json:"timeout"` + NextTimeout uint64 `json:"next_timeout"` + Proofs []commitment.Proof `json:"proofs"` + Height uint64 `json:"height"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenTry{} @@ -63,7 +63,7 @@ func (msg MsgOpenTry) ValidateBasic() sdk.Error { } func (msg MsgOpenTry) GetSignBytes() []byte { - return nil // TODO + return sdk.MustSortJSON(MsgCdc.MustMarshalJSON(msg)) } func (msg MsgOpenTry) GetSigners() []sdk.AccAddress { @@ -71,11 +71,12 @@ func (msg MsgOpenTry) GetSigners() []sdk.AccAddress { } type MsgOpenAck struct { - ConnectionID string - Timeout uint64 - NextTimeout uint64 - Proofs []commitment.Proof - Signer sdk.AccAddress + ConnectionID string `json:"connection_id"` + Timeout uint64 `json:"timeout"` + NextTimeout uint64 `json:"next_timeout"` + Proofs []commitment.Proof `json:"proofs"` + Height uint64 `json:"height"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenAck{} @@ -93,7 +94,7 @@ func (msg MsgOpenAck) ValidateBasic() sdk.Error { } func (msg MsgOpenAck) GetSignBytes() []byte { - return nil // TODO + return sdk.MustSortJSON(MsgCdc.MustMarshalJSON(msg)) } func (msg MsgOpenAck) GetSigners() []sdk.AccAddress { @@ -101,10 +102,11 @@ func (msg MsgOpenAck) GetSigners() []sdk.AccAddress { } type MsgOpenConfirm struct { - ConnectionID string - Timeout uint64 - Proofs []commitment.Proof - Signer sdk.AccAddress + ConnectionID string `json:"connection_id"` + Timeout uint64 `json:"timeout"` + Proofs []commitment.Proof `json:"proofs"` + Height uint64 `json:"height"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenConfirm{} diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index 9fbd375aa4b3..df188acdabf9 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -9,10 +9,10 @@ import ( "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" - "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + tendermint "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) type Node struct { @@ -22,15 +22,15 @@ type Node struct { CounterpartyClient string Connection connection.Connection - State connection.State + State connection.HandshakeStage Cdc *codec.Codec } func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { res := &Node{ - Name: "self", // hard coded, doesnt matter - Node: tendermint.NewNode(self, "teststoreself", []byte("protocol/")), // TODO: test with key prefix + Name: "self", // hard coded, doesnt matter + Node: tendermint.NewNode(self, "teststoreself", []byte("protocol/")), State: connection.Idle, Cdc: cdc, @@ -59,7 +59,7 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { } // TODO: typeify v -func (node *Node) QueryValue(t *testing.T, v interface{KeyBytes() []byte}) ([]byte, commitment.Proof) { +func (node *Node) QueryValue(t *testing.T, v interface{ KeyBytes() []byte }) ([]byte, commitment.Proof) { return node.Query(t, v.KeyBytes()) } @@ -81,7 +81,7 @@ func (node *Node) UpdateClient(t *testing.T, header client.Header) { require.NoError(t, err) } -func (node *Node) SetState(state connection.State) { +func (node *Node) SetState(state connection.HandshakeStage) { node.State = state node.Counterparty.State = state } @@ -92,9 +92,9 @@ func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Conte return ctx, connection.NewHandshaker(man) } -func (node *Node) CLIObject() connection.HandshakeObject { +func (node *Node) CLIState() connection.HandshakeState { _, man := node.Manager() - return connection.NewHandshaker(man).CLIObject(node.Name, node.Name) + return connection.NewHandshaker(man).CLIState(node.Name, node.Name) } func (node *Node) Mapping() state.Mapping { @@ -110,41 +110,41 @@ func (node *Node) Manager() (client.Manager, connection.Manager) { func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenInit(ctx, node.Name, node.Connection, node.CounterpartyClient, 100) // TODO: test timeout + obj, err := man.OpenInit(ctx, node.Name, node.Connection, node.CounterpartyClient) require.NoError(t, err) - require.Equal(t, connection.Init, obj.State.Get(ctx)) + require.Equal(t, connection.Init, obj.Stage.Get(ctx)) require.Equal(t, node.Connection, obj.GetConnection(ctx)) require.Equal(t, node.CounterpartyClient, obj.CounterpartyClient.Get(ctx)) require.False(t, obj.Available.Get(ctx)) node.SetState(connection.Init) } -func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { +func (node *Node) OpenTry(t *testing.T, height uint64, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenTry(ctx, proofs, node.Name, node.Connection, node.CounterpartyClient, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenTry(ctx, proofs, height, node.Name, node.Connection, node.CounterpartyClient) require.NoError(t, err) - require.Equal(t, connection.OpenTry, obj.State.Get(ctx)) + require.Equal(t, connection.OpenTry, obj.Stage.Get(ctx)) require.Equal(t, node.Connection, obj.GetConnection(ctx)) require.Equal(t, node.CounterpartyClient, obj.CounterpartyClient.Get(ctx)) require.False(t, obj.Available.Get(ctx)) node.SetState(connection.OpenTry) } -func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { +func (node *Node) OpenAck(t *testing.T, height uint64, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenAck(ctx, proofs, node.Name, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenAck(ctx, proofs, height, node.Name) require.NoError(t, err) - require.Equal(t, connection.Open, obj.State.Get(ctx)) + require.Equal(t, connection.Open, obj.Stage.Get(ctx)) require.Equal(t, node.Connection, obj.GetConnection(ctx)) require.True(t, obj.Available.Get(ctx)) node.SetState(connection.Open) } -func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { +func (node *Node) OpenConfirm(t *testing.T, height uint64, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenConfirm(ctx, proofs, node.Name, 100 /*TODO*/) + obj, err := man.OpenConfirm(ctx, proofs, height, node.Name) require.NoError(t, err) - require.Equal(t, connection.Open, obj.State.Get(ctx)) + require.Equal(t, connection.Open, obj.Stage.Get(ctx)) require.Equal(t, node.Connection, obj.GetConnection(ctx)) require.True(t, obj.Available.Get(ctx)) node.SetState(connection.CloseTry) @@ -163,30 +163,27 @@ func (node *Node) Handshake(t *testing.T) { // counterparty.OpenTry node.Counterparty.UpdateClient(t, header) - cliobj := node.CLIObject() + cliobj := node.CLIState() _, pconn := node.QueryValue(t, cliobj.Connection) - _, pstate := node.QueryValue(t, cliobj.State) - _, ptimeout := node.QueryValue(t, cliobj.NextTimeout) + _, pstate := node.QueryValue(t, cliobj.Stage) _, pcounterclient := node.QueryValue(t, cliobj.CounterpartyClient) // TODO: implement consensus state checking // _, pclient := node.Query(t, cliobj.Client.ConsensusStateKey) - node.Counterparty.OpenTry(t, pconn, pstate, ptimeout, pcounterclient) + node.Counterparty.OpenTry(t, uint64(header.Height), pconn, pstate, pcounterclient) header = node.Counterparty.Commit() // self.OpenAck node.UpdateClient(t, header) - cliobj = node.Counterparty.CLIObject() + cliobj = node.Counterparty.CLIState() _, pconn = node.Counterparty.QueryValue(t, cliobj.Connection) - _, pstate = node.Counterparty.QueryValue(t, cliobj.State) - _, ptimeout = node.Counterparty.QueryValue(t, cliobj.NextTimeout) + _, pstate = node.Counterparty.QueryValue(t, cliobj.Stage) _, pcounterclient = node.Counterparty.QueryValue(t, cliobj.CounterpartyClient) - node.OpenAck(t, pconn, pstate, ptimeout, pcounterclient) + node.OpenAck(t, uint64(header.Height), pconn, pstate, pcounterclient) header = node.Commit() // counterparty.OpenConfirm node.Counterparty.UpdateClient(t, header) - cliobj = node.CLIObject() - _, pstate = node.QueryValue(t, cliobj.State) - _, ptimeout = node.QueryValue(t, cliobj.NextTimeout) - node.Counterparty.OpenConfirm(t, pstate, ptimeout) + cliobj = node.CLIState() + _, pstate = node.QueryValue(t, cliobj.Stage) + node.Counterparty.OpenConfirm(t, uint64(header.Height), pstate) } diff --git a/x/ibc/03-connection/types.go b/x/ibc/03-connection/types.go index 358d6a451fb9..81c1eca05ae4 100644 --- a/x/ibc/03-connection/types.go +++ b/x/ibc/03-connection/types.go @@ -5,13 +5,13 @@ import ( "errors" "strings" */ - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) type Connection struct { - Client string - Counterparty string - Path commitment.Path + Client string `json:"client"` + Counterparty string `json:"counterParty"` + Path commitment.Path `json:"path"` } /* diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index acfbb9bd8d0f..9e5d803d2fea 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -3,86 +3,79 @@ package channel import ( "bytes" - "github.com/cosmos/cosmos-sdk/client/context" - + "github.com/cosmos/cosmos-sdk/store/state" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func (man Manager) CLIObject(portid, chanid string, connids []string) Object { +func (man Manager) CLIState(portid, chanid string, connids []string) State { obj := man.object(portid, chanid) for _, connid := range connids { - obj.Connections = append(obj.Connections, man.connection.Object(connid)) + obj.Connections = append(obj.Connections, man.connection.State(connid)) } return obj } -func (man Manager) CLIQuery(ctx context.CLIContext, portid, chanid string) (obj Object, err error) { +func (man Manager) CLIQuery(q state.ABCIQuerier, portid, chanid string) (obj State, err error) { obj = man.object(portid, chanid) - channel, _, err := obj.ChannelCLI(ctx) + channel, _, err := obj.ChannelCLI(q) if err != nil { return } for _, connid := range channel.ConnectionHops { - obj.Connections = append(obj.Connections, man.connection.Object(connid)) + obj.Connections = append(obj.Connections, man.connection.State(connid)) } return } -func (obj Object) prefix() []byte { +func (obj State) prefix() []byte { return bytes.Split(obj.Channel.KeyBytes(), LocalRoot())[0] } -func (obj Object) ChannelCLI(ctx context.CLIContext) (res Channel, proof merkle.Proof, err error) { - tmproof, err := obj.Channel.Query(ctx, &res) +func (obj State) ChannelCLI(q state.ABCIQuerier) (res Channel, proof merkle.Proof, err error) { + tmproof, err := obj.Channel.Query(q, &res) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Channel) return } -func (obj Object) AvailableCLI(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { - res, tmproof, err := obj.Available.Query(ctx) +func (obj State) AvailableCLI(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { + res, tmproof, err := obj.Available.Query(q) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Available) return } -func (obj Object) SeqSendCLI(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { - res, tmproof, err := obj.SeqSend.Query(ctx) +func (obj State) SeqSendCLI(q state.ABCIQuerier) (res uint64, proof merkle.Proof, err error) { + res, tmproof, err := obj.SeqSend.Query(q) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.SeqSend) return } -func (obj Object) SeqRecvCLI(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { - res, tmproof, err := obj.SeqRecv.Query(ctx) +func (obj State) SeqRecvCLI(q state.ABCIQuerier) (res uint64, proof merkle.Proof, err error) { + res, tmproof, err := obj.SeqRecv.Query(q) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.SeqRecv) return } -func (obj Object) PacketCLI(ctx context.CLIContext, index uint64) (res Packet, proof merkle.Proof, err error) { +func (obj State) PacketCLI(q state.ABCIQuerier, index uint64) (res Packet, proof merkle.Proof, err error) { packet := obj.Packets.Value(index) - tmproof, err := packet.Query(ctx, &res) + tmproof, err := packet.Query(q, &res) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), packet) return } -func (man Handshaker) CLIQuery(ctx context.CLIContext, portid, chanid string) (HandshakeObject, error) { - obj, err := man.man.CLIQuery(ctx, portid, chanid) +func (man Handshaker) CLIQuery(q state.ABCIQuerier, portid, chanid string) (HandshakeState, error) { + obj, err := man.Manager.CLIQuery(q, portid, chanid) if err != nil { - return HandshakeObject{}, err + return HandshakeState{}, err } - return man.object(obj), nil -} - -func (man Handshaker) CLIObject(portid, chanid string, connids []string) HandshakeObject { - return man.object(man.man.CLIObject(portid, chanid, connids)) + return man.createState(obj), nil } -func (obj HandshakeObject) StateCLI(ctx context.CLIContext) (res State, proof merkle.Proof, err error) { - res, tmproof, err := obj.State.Query(ctx) - proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.State) - return +func (man Handshaker) CLIState(portid, chanid string, connids []string) HandshakeState { + return man.createState(man.Manager.CLIState(portid, chanid, connids)) } -func (obj HandshakeObject) NextTimeoutCLI(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { - res, tmproof, err := obj.NextTimeout.Query(ctx) - proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.NextTimeout) +func (obj HandshakeState) StageCLI(q state.ABCIQuerier) (res Stage, proof merkle.Proof, err error) { + res, tmproof, err := obj.Stage.Query(q) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Stage) return } diff --git a/x/ibc/04-channel/client/cli/query.go b/x/ibc/04-channel/client/cli/query.go index d50573cdc724..aad646c24047 100644 --- a/x/ibc/04-channel/client/cli/query.go +++ b/x/ibc/04-channel/client/cli/query.go @@ -1,60 +1,74 @@ package cli +import ( + "fmt" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + cli "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/state" + sdk "github.com/cosmos/cosmos-sdk/types" + + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/client/utils" + "github.com/cosmos/cosmos-sdk/x/ibc/version" +) + const ( FlagProve = "prove" ) -// TODO -/* -func object(cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid string, connids []string) channel.Object { +func object(ctx context.CLIContext, cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid string) (channel.State, error) { base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) climan := client.NewManager(base) connman := connection.NewManager(base, climan) man := channel.NewManager(base, connman) - return man.CLIObject(portid, chanid, connids) + return man.CLIQuery(state.NewCLIQuerier(ctx), portid, chanid) } func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ibcQueryCmd := &cobra.Command{ - Use: "connection", - Short: "Channel query subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, + Use: "channel", + Short: "Channel query subcommands", + DisableFlagParsing: true, } ibcQueryCmd.AddCommand(cli.GetCommands( - // GetCmdQueryChannel(storeKey, cdc), + GetCmdQueryChannel(storeKey, cdc), )...) + return ibcQueryCmd } -func QueryChannel(ctx context.CLIContext, obj channel.Object, prove bool) (res utils.JSONObject, err error) { - conn, connp, err := obj.ChannelCLI(ctx) +func QueryChannel(ctx context.CLIContext, obj channel.State, prove bool) (res utils.JSONState, err error) { + q := state.NewCLIQuerier(ctx) + + conn, connp, err := obj.ChannelCLI(q) if err != nil { return } - avail, availp, err := obj.AvailableCLI(ctx) + avail, availp, err := obj.AvailableCLI(q) if err != nil { return } - /* - kind, kindp, err := obj.Kind(ctx) - if err != nil { - return - } - seqsend, seqsendp, err := obj.SeqSendCLI(ctx) + seqsend, seqsendp, err := obj.SeqSendCLI(q) if err != nil { return } - seqrecv, seqrecvp, err := obj.SeqRecvCLI(ctx) + seqrecv, seqrecvp, err := obj.SeqRecvCLI(q) if err != nil { return } if prove { - return utils.NewJSONObject( + return utils.NewJSONState( conn, connp, avail, availp, // kind, kindp, @@ -63,7 +77,7 @@ func QueryChannel(ctx context.CLIContext, obj channel.Object, prove bool) (res u ), nil } - return utils.NewJSONObject( + return utils.NewJSONState( conn, nil, avail, nil, seqsend, nil, @@ -71,15 +85,17 @@ func QueryChannel(ctx context.CLIContext, obj channel.Object, prove bool) (res u ), nil } - func GetCmdQueryChannel(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "connection", + Use: "channel", Short: "Query stored connection", - Args: cobra.ExactArgs(1), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) - obj := object(ctx, cdc, storeKey, ibc.Version, args[0], args[1]) + obj, err := object(ctx, cdc, storeKey, version.DefaultPrefix(), args[0], args[1]) + if err != nil { + return err + } jsonobj, err := QueryChannel(ctx, obj, viper.GetBool(FlagProve)) if err != nil { return err @@ -95,4 +111,32 @@ func GetCmdQueryChannel(storeKey string, cdc *codec.Codec) *cobra.Command { return cmd } + +/* +func object(cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid string, connids []string) channel.Stage { + base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) + climan := client.NewManager(base) + connman := connection.NewManager(base, climan) + man := channel.NewManager(base, connman) + return man.CLIState(portid, chanid, connids) +} */ +/* +func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ibcQueryCmd := &cobra.Command{ + Use: "connection", + Short: "Channel query subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + ibcQueryCmd.AddCommand(cli.GetCommands( + // GetCmdQueryChannel(storeKey, cdc), + )...) + return ibcQueryCmd +} +*/ +/* + + + */ diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index c166bda866db..7a8dfc792d57 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -1,10 +1,32 @@ package cli -/* -func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { +import ( + "errors" + "fmt" + "time" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/state" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/version" +) -} -*/ const ( FlagNode1 = "node1" FlagNode2 = "node2" @@ -12,92 +34,143 @@ const ( FlagFrom2 = "from2" ) -// TODO -/* -func handshake(ctx context.CLIContext, cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid string) (channel.HandshakeObject, error) { +func handshake(cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid, connid string) channel.HandshakeState { + base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) + climan := client.NewManager(base) + connman := connection.NewManager(base, climan) + man := channel.NewHandshaker(channel.NewManager(base, connman)) + return man.CLIState(portid, chanid, []string{connid}) +} + +func flush(q state.ABCIQuerier, cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid string) (channel.HandshakeState, error) { base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) climan := client.NewManager(base) connman := connection.NewManager(base, climan) man := channel.NewHandshaker(channel.NewManager(base, connman)) - return man.CLIQuery(ctx, portid, chanid) + return man.CLIQuery(q, portid, chanid) } -func lastheight(ctx context.CLIContext) (uint64, error) { +// TODO: import from connection/client +func conn(q state.ABCIQuerier, cdc *codec.Codec, storeKey string, prefix []byte, connid string) (connection.State, error) { + base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) + clientManager := client.NewManager(base) + man := connection.NewManager(base, clientManager) + return man.CLIQuery(q, connid) +} + +func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "channel", + Short: "IBC channel transaction subcommands", + } + + cmd.AddCommand( + GetCmdHandshake(storeKey, cdc), + GetCmdFlushPackets(storeKey, cdc), + ) + + return cmd +} + +// TODO: move to 02/tendermint +func getHeader(ctx context.CLIContext) (res tendermint.Header, err error) { node, err := ctx.GetNode() if err != nil { - return 0, err + return } info, err := node.ABCIInfo() if err != nil { - return 0, err + return + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return + } + + nextvalidators, err := node.Validators(&height) + if err != nil { + return + } + + res = tendermint.Header{ + SignedHeader: commit.SignedHeader, + ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), } - return uint64(info.Response.LastBlockHeight), nil + return } -func GetCmdChannelHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { +func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "handshake", - Short: "initiate channel handshake between two chains", - Args: cobra.ExactArgs(4), - // Args: []string{connid1, chanid1, chanfilepath1, connid2, chanid2, chanfilepath2} + Short: "initiate connection handshake between two chains", + Args: cobra.ExactArgs(6), + // Args: []string{portid1, chanid1, connid1, portid2, chanid2, connid2} RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - ctx1 := context.NewCLIContext(). + ctx1 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). WithCodec(cdc). WithNodeURI(viper.GetString(FlagNode1)). - WithFrom(viper.GetString(FlagFrom1)) + WithBroadcastMode(flags.BroadcastBlock) + q1 := state.NewCLIQuerier(ctx1) - ctx2 := context.NewCLIContext(). + ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). WithCodec(cdc). WithNodeURI(viper.GetString(FlagNode2)). - WithFrom(viper.GetString(FlagFrom2)) - - conn1id := args[0] - chan1id := args[1] - conn1bz, err := ioutil.ReadFile(args[2]) - if err != nil { - return err - } - var conn1 channel.Channel - if err := cdc.UnmarshalJSON(conn1bz, &conn1); err != nil { - return err + WithBroadcastMode(flags.BroadcastBlock) + q2 := state.NewCLIQuerier(ctx2) + + portid1 := args[0] + chanid1 := args[1] + connid1 := args[2] + portid2 := args[3] + chanid2 := args[4] + connid2 := args[5] + + chan1 := channel.Channel{ + Counterparty: chanid2, + CounterpartyPort: portid2, + ConnectionHops: []string{connid1}, } - obj1, err := handshake(ctx1, cdc, storeKey, ibc.Version, conn1id, chan1id) - if err != nil { - return err + chan2 := channel.Channel{ + Counterparty: chanid1, + CounterpartyPort: portid1, + ConnectionHops: []string{connid2}, } - conn2id := args[3] - chan2id := args[4] - conn2bz, err := ioutil.ReadFile(args[5]) + obj1 := handshake(cdc, storeKey, version.DefaultPrefix(), portid1, chanid1, connid1) + obj2 := handshake(cdc, storeKey, version.DefaultPrefix(), portid2, chanid2, connid2) + + conn1, _, err := obj1.OriginConnection().ConnectionCLI(q1) if err != nil { return err } - var conn2 channel.Channel - if err := cdc.UnmarshalJSON(conn2bz, &conn2); err != nil { - return err - } + clientid1 := conn1.Client - obj2, err := handshake(ctx2, cdc, storeKey, ibc.Version, conn1id, chan1id) + conn2, _, err := obj2.OriginConnection().ConnectionCLI(q2) if err != nil { return err } + clientid2 := conn2.Client // TODO: check state and if not Idle continue existing process - height, err := lastheight(ctx2) - if err != nil { - return err - } - nextTimeout := height + 1000 // TODO: parameterize msginit := channel.MsgOpenInit{ - ConnectionID: conn1id, - ChannelID: chan1id, - Channel: conn1, - NextTimeout: nextTimeout, - Signer: ctx1.GetFromAddress(), + PortID: portid1, + ChannelID: chanid1, + Channel: chan1, + Signer: ctx1.GetFromAddress(), } err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msginit}) @@ -105,33 +178,44 @@ func GetCmdChannelHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - timeout := nextTimeout - height, err = lastheight(ctx1) + // Another block has to be passed after msginit is commited + // to retrieve the correct proofs + time.Sleep(8 * time.Second) + + header, err := getHeader(ctx1) if err != nil { return err } - nextTimeout = height + 1000 - _, pconn, err := obj1.ChannelCLI(ctx1) - if err != nil { - return err + + msgupdate := client.MsgUpdateClient{ + ClientID: clientid2, + Header: header, + Signer: ctx2.GetFromAddress(), } - _, pstate, err := obj1.StateCLI(ctx1) + + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgupdate}) + + fmt.Printf("updated apphash to %X\n", header.AppHash) + + q1 = state.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) + fmt.Printf("querying from %d\n", header.Height-1) + + _, pchan, err := obj1.ChannelCLI(q1) if err != nil { return err } - _, ptimeout, err := obj1.NextTimeoutCLI(ctx1) + _, pstate, err := obj1.StageCLI(q1) if err != nil { return err } msgtry := channel.MsgOpenTry{ - ConnectionID: conn2id, - ChannelID: chan2id, - Channel: conn2, - Timeout: timeout, - NextTimeout: nextTimeout, - Proofs: []commitment.Proof{pconn, pstate, ptimeout}, - Signer: ctx2.GetFromAddress(), + PortID: portid2, + ChannelID: chanid2, + Channel: chan2, + Proofs: []commitment.Proof{pchan, pstate}, + Height: uint64(header.Height), + Signer: ctx2.GetFromAddress(), } err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgtry}) @@ -139,31 +223,40 @@ func GetCmdChannelHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - timeout = nextTimeout - height, err = lastheight(ctx2) + // Another block has to be passed after msginit is commited + // to retrieve the correct proofs + time.Sleep(8 * time.Second) + + header, err = getHeader(ctx2) if err != nil { return err } - nextTimeout = height + 1000 - _, pconn, err = obj2.Channel(ctx2) - if err != nil { - return err + + msgupdate = client.MsgUpdateClient{ + ClientID: clientid1, + Header: header, + Signer: ctx1.GetFromAddress(), } - _, pstate, err = obj2.State(ctx2) + + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgupdate}) + + q2 = state.NewCLIQuerier(ctx2.WithHeight(header.Height - 1)) + + _, pchan, err = obj2.ChannelCLI(q2) if err != nil { return err } - _, ptimeout, err = obj2.NextTimeout(ctx2) + _, pstate, err = obj2.StageCLI(q2) if err != nil { return err } msgack := channel.MsgOpenAck{ - ConnectionID: conn1id, - ChannelID: chan1id, - Timeout: timeout, - Proofs: []commitment.Proof{pconn, pstate, ptimeout}, - Signer: ctx1.GetFromAddress(), + PortID: portid1, + ChannelID: chanid1, + Proofs: []commitment.Proof{pchan, pstate}, + Height: uint64(header.Height), + Signer: ctx1.GetFromAddress(), } err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgack}) @@ -171,22 +264,36 @@ func GetCmdChannelHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - timeout = nextTimeout - _, pstate, err = obj1.State(ctx1) + // Another block has to be passed after msginit is commited + // to retrieve the correct proofs + time.Sleep(8 * time.Second) + + header, err = getHeader(ctx1) if err != nil { return err } - _, ptimeout, err = obj1.NextTimeout(ctx1) + + msgupdate = client.MsgUpdateClient{ + ClientID: clientid2, + Header: header, + Signer: ctx2.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgupdate}) + + q1 = state.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) + + _, pstate, err = obj1.StageCLI(q1) if err != nil { return err } msgconfirm := channel.MsgOpenConfirm{ - ConnectionID: conn2id, - ChannelID: chan2id, - Timeout: timeout, - Proofs: []commitment.Proof{pstate, ptimeout}, - Signer: ctx2.GetFromAddress(), + PortID: portid2, + ChannelID: chanid2, + Proofs: []commitment.Proof{pstate}, + Height: uint64(header.Height), + Signer: ctx2.GetFromAddress(), } err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgconfirm}) @@ -198,87 +305,139 @@ func GetCmdChannelHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { }, } + cmd.Flags().String(FlagNode1, "tcp://localhost:26657", "") + cmd.Flags().String(FlagNode2, "tcp://localhost:26657", "") + cmd.Flags().String(FlagFrom1, "", "") + cmd.Flags().String(FlagFrom2, "", "") + + cmd.MarkFlagRequired(FlagFrom1) + cmd.MarkFlagRequired(FlagFrom2) + return cmd } -func GetCmdRelay(storeKey string, cdc *codec.Codec) *cobra.Command { +func GetCmdFlushPackets(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "relay", - Short: "relay pakcets between two channels", - Args: cobra.ExactArgs(4), - // Args: []string{connid1, chanid1, chanfilepath1, connid2, chanid2, chanfilepath2} + Use: "flush", + Short: "flush packets on queue", + Args: cobra.ExactArgs(2), + // Args: []string{portid, chanid} RunE: func(cmd *cobra.Command, args []string) error { - ctx1 := context.NewCLIContext(). + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + ctx1 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). WithCodec(cdc). WithNodeURI(viper.GetString(FlagNode1)). - WithFrom(viper.GetString(FlagFrom1)) + WithBroadcastMode(flags.BroadcastBlock) + q1 := state.NewCLIQuerier(ctx1) - ctx2 := context.NewCLIContext(). + ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). WithCodec(cdc). WithNodeURI(viper.GetString(FlagNode2)). - WithFrom(viper.GetString(FlagFrom2)) + WithBroadcastMode(flags.BroadcastBlock) + q2 := state.NewCLIQuerier(ctx2) - conn1id, chan1id, conn2id, chan2id := args[0], args[1], args[2], args[3] + portid1, chanid1 := args[0], args[1] - obj1 := object(ctx1, cdc, storeKey, ibc.Version, conn1id, chan1id) - obj2 := object(ctx2, cdc, storeKey, ibc.Version, conn2id, chan2id) + obj1, err := flush(q1, cdc, storeKey, version.DefaultPrefix(), portid1, chanid1) + if err != nil { + return err + } - return relayLoop(cdc, ctx1, ctx2, obj1, obj2, conn1id, chan1id, conn2id, chan2id) - }, - } + chan1, _, err := obj1.ChannelCLI(q1) + if err != nil { + return err + } - return cmd -} + portid2, chanid2 := chan1.CounterpartyPort, chan1.Counterparty -func relayLoop(cdc *codec.Codec, - ctx1, ctx2 context.CLIContext, - obj1, obj2 channel.CLIObject, - conn1id, chan1id, conn2id, chan2id string, -) error { - for { - // TODO: relay() should be goroutine and return error by channel - err := relay(cdc, ctx1, ctx2, obj1, obj2, conn2id, chan2id) - // TODO: relayBetween() should retry several times before halt - if err != nil { - return err - } - time.Sleep(1 * time.Second) - } -} + obj2, err := flush(q2, cdc, storeKey, version.DefaultPrefix(), portid2, chanid2) + if err != nil { + return err + } -func relay(cdc *codec.Codec, ctxFrom, ctxTo context.CLIContext, objFrom, objTo channel.CLIObject, connidTo, chanidTo string) error { - txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + chan2, _, err := obj2.ChannelCLI(q2) + if err != nil { + return err + } - seq, _, err := objTo.SeqRecv(ctxTo) - if err != nil { - return err - } + connobj2, err := conn(q2, cdc, storeKey, version.DefaultPrefix(), chan2.ConnectionHops[0]) + if err != nil { + return err + } - sent, _, err := objFrom.SeqSend(ctxFrom) - if err != nil { - return err - } + conn2, _, err := connobj2.ConnectionCLI(q2) + if err != nil { + return err + } + + client2 := conn2.Client - for i := seq; i <= sent; i++ { - packet, proof, err := objFrom.Packet(ctxFrom, seq) - if err != nil { - return err - } - - msg := channel.MsgReceive{ - ConnectionID: connidTo, - ChannelID: chanidTo, - Packet: packet, - Proofs: []commitment.Proof{proof}, - Signer: ctxTo.GetFromAddress(), - } - - err = utils.GenerateOrBroadcastMsgs(ctxTo, txBldr, []sdk.Msg{msg}) - if err != nil { - return err - } + seqrecv, _, err := obj2.SeqRecvCLI(q2) + if err != nil { + return err + } + + seqsend, _, err := obj1.SeqSendCLI(q1) + if err != nil { + return err + } + + // SeqRecv is the latest received packet index(0 if not exists) + // SeqSend is the latest sent packet index (0 if not exists) + if !(seqsend > seqrecv) { + return errors.New("no unsent packets") + } + + // TODO: optimize, don't updateclient if already updated + header, err := getHeader(ctx1) + if err != nil { + return err + } + + q1 = state.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) + + msgupdate := client.MsgUpdateClient{ + ClientID: client2, + Header: header, + Signer: ctx2.GetFromAddress(), + } + + msgs := []sdk.Msg{msgupdate} + + for i := seqrecv + 1; i <= seqsend; i++ { + packet, proof, err := obj1.PacketCLI(q1, i) + if err != nil { + return err + } + + msg := channel.MsgPacket{ + packet, + chanid2, + []commitment.Proof{proof}, + uint64(header.Height), + ctx2.GetFromAddress(), + } + + msgs = append(msgs, msg) + } + + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, msgs) + if err != nil { + return err + } + + return nil + }, } - return nil + cmd.Flags().String(FlagNode1, "tcp://localhost:26657", "") + cmd.Flags().String(FlagNode2, "tcp://localhost:26657", "") + cmd.Flags().String(FlagFrom1, "", "") + cmd.Flags().String(FlagFrom2, "", "") + + cmd.MarkFlagRequired(FlagFrom1) + cmd.MarkFlagRequired(FlagFrom2) + + return cmd + } -*/ diff --git a/x/ibc/04-channel/client/utils/types.go b/x/ibc/04-channel/client/utils/types.go index 4006e7bacebb..579cead225c8 100644 --- a/x/ibc/04-channel/client/utils/types.go +++ b/x/ibc/04-channel/client/utils/types.go @@ -1,11 +1,11 @@ package utils import ( - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -type JSONObject struct { +type JSONState struct { Channel channel.Channel `json:"channel"` ChannelProof commitment.Proof `json:"channel_proof,omitempty"` Available bool `json:"available"` @@ -18,14 +18,14 @@ type JSONObject struct { // KindProof commitment.Proof `json:"kind_proof,omitempty"` } -func NewJSONObject( +func NewJSONState( channel channel.Channel, channelp commitment.Proof, avail bool, availp commitment.Proof, // kind string, kindp commitment.Proof, seqsend uint64, seqsendp commitment.Proof, seqrecv uint64, seqrecvp commitment.Proof, -) JSONObject { - return JSONObject{ +) JSONState { + return JSONState{ Channel: channel, ChannelProof: channelp, Available: avail, @@ -35,8 +35,8 @@ func NewJSONObject( } } -type HandshakeJSONObject struct { - JSONObject `json:"channel"` +type HandshakeJSONState struct { + JSONState `json:"channel"` State byte `json:"state"` StateProof commitment.Proof `json:"state_proof,omitempty"` CounterpartyClient string `json:"counterparty_client"` @@ -45,7 +45,7 @@ type HandshakeJSONObject struct { NextTimeoutProof commitment.Proof `json:"next_timeout_proof,omitempty"` } -func NewHandshakeJSONObject( +func NewHandshakeJSONState( channel channel.Channel, channelp commitment.Proof, avail bool, availp commitment.Proof, // kind string, kindp commitment.Proof, @@ -54,9 +54,9 @@ func NewHandshakeJSONObject( state byte, statep commitment.Proof, timeout uint64, timeoutp commitment.Proof, -) HandshakeJSONObject { - return HandshakeJSONObject{ - JSONObject: NewJSONObject(channel, channelp, avail, availp, seqsend, seqsendp, seqrecv, seqrecvp), +) HandshakeJSONState { + return HandshakeJSONState{ + JSONState: NewJSONState(channel, channelp, avail, availp, seqsend, seqsendp, seqrecv, seqrecvp), State: state, StateProof: statep, NextTimeout: timeout, diff --git a/x/ibc/04-channel/codec.go b/x/ibc/04-channel/codec.go index 4da636c4edc7..38654da4e6a9 100644 --- a/x/ibc/04-channel/codec.go +++ b/x/ibc/04-channel/codec.go @@ -4,6 +4,17 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) +var msgCdc *codec.Codec + func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*Packet)(nil), nil) + + cdc.RegisterConcrete(MsgOpenInit{}, "ibc/channel/MsgOpenInit", nil) + cdc.RegisterConcrete(MsgOpenTry{}, "ibc/channel/MsgOpenTry", nil) + cdc.RegisterConcrete(MsgOpenAck{}, "ibc/channel/MsgOpenAck", nil) + cdc.RegisterConcrete(MsgOpenConfirm{}, "ibc/channel/MsgOpenConfirm", nil) +} + +func SetMsgCodec(cdc *codec.Codec) { + msgCdc = cdc } diff --git a/x/ibc/04-channel/events.go b/x/ibc/04-channel/events.go new file mode 100644 index 000000000000..f9097af6a3b7 --- /dev/null +++ b/x/ibc/04-channel/events.go @@ -0,0 +1,10 @@ +package channel + +const ( + EventTypeSendPacket = "send_packet" + + AttributeKeySenderPort = "sender_port" + AttributeKeyReceiverPort = "receiver_port" + AttributeKeyChannelID = "channel_id" + AttributeKeySequence = "sequence" +) diff --git a/x/ibc/04-channel/handler.go b/x/ibc/04-channel/handler.go index 02c2c334fb45..0ef8f76a1bfd 100644 --- a/x/ibc/04-channel/handler.go +++ b/x/ibc/04-channel/handler.go @@ -5,7 +5,7 @@ import ( ) func HandleMsgOpenInit(ctx sdk.Context, msg MsgOpenInit, man Handshaker) sdk.Result { - _, err := man.OpenInit(ctx, msg.ConnectionID, msg.ChannelID, msg.Channel, msg.NextTimeout) + _, err := man.OpenInit(ctx, msg.PortID, msg.ChannelID, msg.Channel) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), 100, "").Result() } @@ -13,7 +13,7 @@ func HandleMsgOpenInit(ctx sdk.Context, msg MsgOpenInit, man Handshaker) sdk.Res } func HandleMsgOpenTry(ctx sdk.Context, msg MsgOpenTry, man Handshaker) sdk.Result { - _, err := man.OpenTry(ctx, msg.Proofs, msg.ConnectionID, msg.ChannelID, msg.Channel, msg.Timeout, msg.NextTimeout) + _, err := man.OpenTry(ctx, msg.Proofs, msg.Height, msg.PortID, msg.ChannelID, msg.Channel) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), 200, "").Result() } @@ -21,7 +21,7 @@ func HandleMsgOpenTry(ctx sdk.Context, msg MsgOpenTry, man Handshaker) sdk.Resul } func HandleMsgOpenAck(ctx sdk.Context, msg MsgOpenAck, man Handshaker) sdk.Result { - _, err := man.OpenAck(ctx, msg.Proofs, msg.ConnectionID, msg.ChannelID, msg.Timeout, msg.NextTimeout) + _, err := man.OpenAck(ctx, msg.Proofs, msg.Height, msg.PortID, msg.ChannelID) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), 300, "").Result() } @@ -29,20 +29,9 @@ func HandleMsgOpenAck(ctx sdk.Context, msg MsgOpenAck, man Handshaker) sdk.Resul } func HandleMsgOpenConfirm(ctx sdk.Context, msg MsgOpenConfirm, man Handshaker) sdk.Result { - _, err := man.OpenConfirm(ctx, msg.Proofs, msg.ConnectionID, msg.ChannelID, msg.Timeout) + _, err := man.OpenConfirm(ctx, msg.Proofs, msg.Height, msg.PortID, msg.ChannelID) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), 400, "").Result() } return sdk.Result{} } - -type Handler func(sdk.Context, Packet) sdk.Result - -func HandleMsgReceive(ctx sdk.Context, msg MsgReceive, man Manager) sdk.Result { - err := man.Receive(ctx, msg.Proofs, msg.ConnectionID, msg.ChannelID, msg.Packet) - if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), 500, "").Result() - } - handler := man.router.Route(msg.Packet.Route()) - return handler(ctx, msg.Packet) -} diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index 76e372bb929f..23f34d16eec5 100644 --- a/x/ibc/04-channel/handshake.go +++ b/x/ibc/04-channel/handshake.go @@ -9,10 +9,10 @@ import ( commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -type State = byte +type Stage = byte const ( - Idle State = iota + Idle Stage = iota Init OpenTry Open @@ -21,23 +21,19 @@ const ( ) type Handshaker struct { - man Manager + Manager - counterparty CounterpartyHandshaker + counterParty CounterpartyHandshaker } func (man Handshaker) Kind() string { return "handshake" } -// TODO: ocapify Manager; an actor who holds Manager -// should not be able to construct creaters from it -// or add Seal() method to Manager? func NewHandshaker(man Manager) Handshaker { return Handshaker{ - man: man, - - counterparty: CounterpartyHandshaker{man.counterparty}, + Manager: man, + counterParty: CounterpartyHandshaker{man.counterParty}, } } @@ -45,71 +41,64 @@ type CounterpartyHandshaker struct { man CounterpartyManager } -type HandshakeObject struct { - Object +type HandshakeState struct { + State - State state.Enum - NextTimeout state.Integer + Stage state.Enum - counterparty CounterHandshakeObject + counterParty CounterHandshakeState } -type CounterHandshakeObject struct { - CounterObject +type CounterHandshakeState struct { + CounterState - State commitment.Enum - NextTimeout commitment.Integer + Stage commitment.Enum } // CONTRACT: client and remote must be filled by the caller -func (man Handshaker) object(parent Object) HandshakeObject { - prefix := parent.portid + "/channels/" + parent.chanid - - return HandshakeObject{ - Object: parent, - - State: man.man.protocol.Value([]byte(prefix + "/state")).Enum(), - NextTimeout: man.man.protocol.Value([]byte(prefix + "/timeout")).Integer(state.Dec), +func (man Handshaker) createState(parent State) HandshakeState { + prefix := parent.portId + "/channels/" + parent.chanId - counterparty: man.counterparty.object(parent.counterparty), + return HandshakeState{ + State: parent, + Stage: man.protocol.Value([]byte(prefix + "/state")).Enum(), + counterParty: man.counterParty.createState(parent.counterParty), } } -func (man CounterpartyHandshaker) object(parent CounterObject) CounterHandshakeObject { - prefix := parent.portid + "/channels/" + parent.chanid +func (man CounterpartyHandshaker) createState(parent CounterState) CounterHandshakeState { + prefix := parent.portId + "/channels/" + parent.chanId - return CounterHandshakeObject{ - CounterObject: man.man.object(parent.portid, parent.chanid), - - State: man.man.protocol.Value([]byte(prefix + "/state")).Enum(), - NextTimeout: man.man.protocol.Value([]byte(prefix + "/timeout")).Integer(state.Dec), + return CounterHandshakeState{ + CounterState: man.man.object(parent.portId, parent.chanId), + Stage: man.man.protocol.Value([]byte(prefix + "/state")).Enum(), } } -func (man Handshaker) create(ctx sdk.Context, portid, chanid string, channel Channel) (obj HandshakeObject, err error) { - cobj, err := man.man.create(ctx, portid, chanid, channel) +func (man Handshaker) create(ctx sdk.Context, portid, chanid string, channel Channel) (obj HandshakeState, err error) { + cobj, err := man.Manager.create(ctx, portid, chanid, channel) if err != nil { return } - obj = man.object(cobj) + obj = man.createState(cobj) return obj, nil } -func (man Handshaker) query(ctx sdk.Context, portid, chanid string) (obj HandshakeObject, err error) { - cobj, err := man.man.query(ctx, portid, chanid) +func (man Handshaker) query(ctx sdk.Context, portid, chanid string) (obj HandshakeState, err error) { + cobj, err := man.Manager.query(ctx, portid, chanid) if err != nil { return } - obj = man.object(cobj) + obj = man.createState(cobj) return obj, nil } /* -func (obj HandshakeObject) remove(ctx sdk.Context) { - obj.Object.remove(ctx) - obj.State.Delete(ctx) +func (obj HandshakeState) remove(ctx sdk.Context) { + obj.Stage.remove(ctx) + obj.Stage.Delete(ctx) obj.counterpartyClient.Delete(ctx) obj.NextTimeout.Delete(ctx) } @@ -125,135 +114,99 @@ func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { // Using proofs: none func (man Handshaker) OpenInit(ctx sdk.Context, - portid, chanid string, channel Channel, nextTimeoutHeight uint64, -) (HandshakeObject, error) { + portid, chanid string, channel Channel, +) (HandshakeState, error) { // man.Create() will ensure // assert(connectionHops.length === 2) // assert(get("channels/{identifier}") === null) and // set("channels/{identifier}", connection) if len(channel.ConnectionHops) != 1 { - return HandshakeObject{}, errors.New("ConnectionHops length must be 1") + return HandshakeState{}, errors.New("ConnectionHops length must be 1") } obj, err := man.create(ctx, portid, chanid, channel) if err != nil { - return HandshakeObject{}, err + return HandshakeState{}, err } - obj.NextTimeout.Set(ctx, nextTimeoutHeight) - obj.State.Set(ctx, Init) + obj.Stage.Set(ctx, Init) return obj, nil } -// Using proofs: counterparty.{channel,state,nextTimeout} +// Using proofs: counterParty.{channel,state} func (man Handshaker) OpenTry(ctx sdk.Context, - proofs []commitment.Proof, - portid, chanid string, channel Channel, timeoutHeight, nextTimeoutHeight uint64, -) (obj HandshakeObject, err error) { + proofs []commitment.Proof, height uint64, + portid, chanid string, channel Channel, +) (obj HandshakeState, err error) { if len(channel.ConnectionHops) != 1 { - return HandshakeObject{}, errors.New("ConnectionHops length must be 1") + return HandshakeState{}, errors.New("ConnectionHops length must be 1") } obj, err = man.create(ctx, portid, chanid, channel) if err != nil { return } - ctx, err = obj.Context(ctx, proofs) - if err != nil { - return - } - - err = assertTimeout(ctx, timeoutHeight) + ctx, err = obj.Context(ctx, proofs, height) if err != nil { return } - if !obj.counterparty.State.Is(ctx, Init) { - err = errors.New("counterparty state not init") + if !obj.counterParty.Stage.Is(ctx, Init) { + err = errors.New("counterParty state not init") return } - if !obj.counterparty.Channel.Is(ctx, Channel{ - Port: channel.CounterpartyPort, + if !obj.counterParty.Channel.Is(ctx, Channel{ Counterparty: chanid, - CounterpartyPort: channel.Port, + CounterpartyPort: portid, ConnectionHops: []string{obj.Connections[0].GetConnection(ctx).Counterparty}, }) { - err = errors.New("wrong counterparty connection") - return - } - - if !obj.counterparty.NextTimeout.Is(ctx, timeoutHeight) { - err = errors.New("unexpected counterparty timeout value") + err = errors.New("wrong counterParty connection") return } - // TODO: commented out, need to check whether the stored client is compatible - // make a separate module that manages recent n block headers - // ref #4647 - /* - var expected client.ConsensusState - obj.self.Get(ctx, expheight, &expected) - if !obj.counterparty.client.Is(ctx, expected) { - return errors.New("unexpected counterparty client value") - } - */ - // CONTRACT: OpenTry() should be called after man.Create(), not man.Query(), // which will ensure // assert(get("connections/{desiredIdentifier}") === null) and // set("connections{identifier}", connection) - obj.State.Set(ctx, OpenTry) - obj.NextTimeout.Set(ctx, nextTimeoutHeight) + obj.Stage.Set(ctx, OpenTry) return } -// Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} +// Using proofs: counterParty.{handshake,state,nextTimeout,clientid,client} func (man Handshaker) OpenAck(ctx sdk.Context, - proofs []commitment.Proof, - portid, chanid string, timeoutHeight, nextTimeoutHeight uint64, -) (obj HandshakeObject, err error) { + proofs []commitment.Proof, height uint64, + portid, chanid string, +) (obj HandshakeState, err error) { obj, err = man.query(ctx, portid, chanid) if err != nil { return } - ctx, err = obj.Context(ctx, proofs) + ctx, err = obj.Context(ctx, proofs, height) if err != nil { return } - if !obj.State.Transit(ctx, Init, Open) { + if !obj.Stage.Transit(ctx, Init, Open) { err = errors.New("ack on non-init connection") return } - err = assertTimeout(ctx, timeoutHeight) - if err != nil { - return - } - - channel := obj.GetChannel(ctx) - if !obj.counterparty.Channel.Is(ctx, Channel{ - Port: channel.CounterpartyPort, + if !obj.counterParty.Channel.Is(ctx, Channel{ Counterparty: chanid, - CounterpartyPort: channel.Port, + CounterpartyPort: portid, ConnectionHops: []string{obj.Connections[0].GetConnection(ctx).Counterparty}, }) { - err = errors.New("wrong counterparty") + err = errors.New("wrong counterParty") return } - if !obj.counterparty.State.Is(ctx, OpenTry) { - err = errors.New("counterparty state not opentry") - return - } - - if !obj.counterparty.NextTimeout.Is(ctx, timeoutHeight) { - err = errors.New("unexpected counterparty timeout value") + if !obj.counterParty.Stage.Is(ctx, OpenTry) { + err = errors.New("counterParty state not opentry") return } @@ -261,89 +214,49 @@ func (man Handshaker) OpenAck(ctx sdk.Context, /* var expected client.ConsensusState obj.self.Get(ctx, expheight, &expected) - if !obj.counterparty.client.Is(ctx, expected) { - return errors.New("unexpected counterparty client value") + if !obj.counterParty.client.Is(ctx, expected) { + return errors.New("unexpected counterParty client value") } */ - obj.NextTimeout.Set(ctx, nextTimeoutHeight) obj.Available.Set(ctx, true) return } -// Using proofs: counterparty.{connection,state, nextTimeout} +// Using proofs: counterParty.{connection,state, nextTimeout} func (man Handshaker) OpenConfirm(ctx sdk.Context, - proofs []commitment.Proof, - portid, chanid string, timeoutHeight uint64) (obj HandshakeObject, err error) { + proofs []commitment.Proof, height uint64, + portid, chanid string) (obj HandshakeState, err error) { obj, err = man.query(ctx, portid, chanid) if err != nil { return } - ctx, err = obj.Context(ctx, proofs) + ctx, err = obj.Context(ctx, proofs, height) if err != nil { return } - if !obj.State.Transit(ctx, OpenTry, Open) { + if !obj.Stage.Transit(ctx, OpenTry, Open) { err = errors.New("confirm on non-try connection") return } - err = assertTimeout(ctx, timeoutHeight) - if err != nil { - return - } - - if !obj.counterparty.State.Is(ctx, Open) { - err = errors.New("counterparty state not open") - return - } - - if !obj.counterparty.NextTimeout.Is(ctx, timeoutHeight) { - err = errors.New("unexpected counterparty timeout value") + if !obj.counterParty.Stage.Is(ctx, Open) { + err = errors.New("counterParty state not open") return } obj.Available.Set(ctx, true) - obj.NextTimeout.Set(ctx, 0) return } // TODO /* -func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { - if !(obj.connection.Client().ConsensusState(ctx).GetHeight()) > obj.NextTimeout.Get(ctx)) { - return errors.New("timeout height not yet reached") - } - - switch obj.State.Get(ctx) { - case Init: - if !obj.counterparty.connection.Is(ctx, nil) { - return errors.New("counterparty connection exists") - } - case OpenTry: - if !(obj.counterparty.State.Is(ctx, Init) || - obj.counterparty.connection.Is(ctx, nil)) { - return errors.New("counterparty connection state not init") - } - // XXX: check if we need to verify symmetricity for timeout (already proven in OpenTry) - case Open: - if obj.counterparty.State.Is(ctx, OpenTry) { - return errors.New("counterparty connection state not tryopen") - } - } - - obj.remove(ctx) - - return nil -} - - -func (obj HandshakeObject) CloseInit(ctx sdk.Context, nextTimeout uint64) error { - if !obj.State.Transit(ctx, Open, CloseTry) { +func (obj HandshakeState) CloseInit(ctx sdk.Context, nextTimeout uint64) error { + if !obj.Stage.Transit(ctx, Open, CloseTry) { return errors.New("closeinit on non-open connection") } @@ -351,74 +264,4 @@ func (obj HandshakeObject) CloseInit(ctx sdk.Context, nextTimeout uint64) error return nil } - -func (obj HandshakeObject) CloseTry(ctx sdk.Context, timeoutHeight, nextTimeoutHeight uint64) error { - if !obj.State.Transit(ctx, Open, Closed) { - return errors.New("closetry on non-open connection") - } - - err := assertTimeout(ctx, timeoutHeight) - if err != nil { - return err - } - - if !obj.counterparty.State.Is(ctx, CloseTry) { - return errors.New("unexpected counterparty state value") - } - - if !obj.counterparty.NextTimeout.Is(ctx, timeoutHeight) { - return errors.New("unexpected counterparty timeout value") - } - - obj.NextTimeout.Set(ctx, nextTimeoutHeight) - - return nil -} - -func (obj HandshakeObject) CloseAck(ctx sdk.Context, timeoutHeight uint64) error { - if !obj.State.Transit(ctx, CloseTry, Closed) { - return errors.New("closeack on non-closetry connection") - } - - err := assertTimeout(ctx, timeoutHeight) - if err != nil { - return err - } - - if !obj.counterparty.State.Is(ctx, Closed) { - return errors.New("unexpected counterparty state value") - } - - if !obj.counterparty.NextTimeout.Is(ctx, timeoutHeight) { - return errors.New("unexpected counterparty timeout value") - } - - obj.NextTimeout.Set(ctx, 0) - - return nil -} - -func (obj HandshakeObject) CloseTimeout(ctx sdk.Context) error { - if !(obj.client.ConsensusState(ctx).GetHeight()) > obj.NextTimeout.Get(ctx)) { - return errors.New("timeout height not yet reached") - } - - // XXX: double check if the user can bypass the verification logic somehow - switch obj.State.Get(ctx) { - case CloseTry: - if !obj.counterparty.State.Is(ctx, Open) { - return errors.New("counterparty connection state not open") - } - case Closed: - if !obj.counterparty.State.Is(ctx, CloseTry) { - return errors.New("counterparty connection state not closetry") - } - } - - obj.State.Set(ctx, Open) - obj.NextTimeout.Set(ctx, 0) - - return nil - -} */ diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index 8bcbbddedce5..7bd358152303 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -2,6 +2,7 @@ package channel import ( "errors" + "strconv" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/state" @@ -17,9 +18,7 @@ type Manager struct { connection connection.Manager - counterparty CounterpartyManager - - router Router + counterParty CounterpartyManager ports map[string]struct{} } @@ -34,9 +33,8 @@ func NewManager(protocol state.Mapping, connection connection.Manager) Manager { return Manager{ protocol: protocol.Prefix(LocalRoot()), connection: connection, - counterparty: NewCounterpartyManager(protocol.Cdc()), - - ports: make(map[string]struct{}), + counterParty: NewCounterpartyManager(protocol.Cdc()), + ports: make(map[string]struct{}), } } @@ -49,45 +47,41 @@ func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { } } -// CONTRACT: connection and counterparty must be filled by the caller -func (man Manager) object(portid, chanid string) Object { - key := portid + "/channels/" + chanid - return Object{ - chanid: chanid, - portid: portid, - Channel: man.protocol.Value([]byte(key)), - +// CONTRACT: connection and counterParty must be filled by the caller +func (man Manager) object(portId, chanId string) State { + key := portId + "/channels/" + chanId + return State{ + chanId: chanId, + portId: portId, + Channel: man.protocol.Value([]byte(key)), Available: man.protocol.Value([]byte(key + "/available")).Boolean(), - - SeqSend: man.protocol.Value([]byte(key + "/nextSequenceSend")).Integer(state.Dec), - SeqRecv: man.protocol.Value([]byte(key + "/nextSequenceRecv")).Integer(state.Dec), - Packets: man.protocol.Prefix([]byte(key + "/packets/")).Indexer(state.Dec), + SeqSend: man.protocol.Value([]byte(key + "/nextSequenceSend")).Integer(state.Dec), + SeqRecv: man.protocol.Value([]byte(key + "/nextSequenceRecv")).Integer(state.Dec), + Packets: man.protocol.Prefix([]byte(key + "/packets/")).Indexer(state.Dec), } } -func (man CounterpartyManager) object(portid, chanid string) CounterObject { +func (man CounterpartyManager) object(portid, chanid string) CounterState { key := portid + "/channels/" + chanid - return CounterObject{ - chanid: chanid, - portid: portid, - Channel: man.protocol.Value([]byte(key)), - + return CounterState{ + chanId: chanid, + portId: portid, + Channel: man.protocol.Value([]byte(key)), Available: man.protocol.Value([]byte(key + "/available")).Boolean(), - - SeqSend: man.protocol.Value([]byte(key + "/nextSequenceSend")).Integer(state.Dec), - SeqRecv: man.protocol.Value([]byte(key + "/nextSequenceRecv")).Integer(state.Dec), - Packets: man.protocol.Prefix([]byte(key + "/packets/")).Indexer(state.Dec), + SeqSend: man.protocol.Value([]byte(key + "/nextSequenceSend")).Integer(state.Dec), + SeqRecv: man.protocol.Value([]byte(key + "/nextSequenceRecv")).Integer(state.Dec), + Packets: man.protocol.Prefix([]byte(key + "/packets/")).Indexer(state.Dec), } } -func (man Manager) create(ctx sdk.Context, portid, chanid string, channel Channel) (obj Object, err error) { +func (man Manager) create(ctx sdk.Context, portid, chanid string, channel Channel) (obj State, err error) { obj = man.object(portid, chanid) if obj.exists(ctx) { err = errors.New("channel already exists for the provided id") return } obj.Channel.Set(ctx, channel) - obj.counterparty = man.counterparty.object(channel.CounterpartyPort, channel.Counterparty) + obj.counterParty = man.counterParty.object(channel.CounterpartyPort, channel.Counterparty) for _, hop := range channel.ConnectionHops { connobj, err := man.connection.Query(ctx, hop) @@ -98,15 +92,15 @@ func (man Manager) create(ctx sdk.Context, portid, chanid string, channel Channe } for _, hop := range channel.CounterpartyHops() { - connobj := man.counterparty.connection.Object(hop) - obj.counterparty.Connections = append(obj.counterparty.Connections, connobj) + connobj := man.counterParty.connection.CreateState(hop) + obj.counterParty.Connections = append(obj.counterParty.Connections, connobj) } return } // Does not check availability -func (man Manager) query(ctx sdk.Context, portid, chanid string) (obj Object, err error) { +func (man Manager) query(ctx sdk.Context, portid, chanid string) (obj State, err error) { obj = man.object(portid, chanid) if !obj.exists(ctx) { err = errors.New("channel not exists for the provided id") @@ -114,7 +108,7 @@ func (man Manager) query(ctx sdk.Context, portid, chanid string) (obj Object, er } channel := obj.GetChannel(ctx) - obj.counterparty = man.counterparty.object(channel.CounterpartyPort, channel.Counterparty) + obj.counterParty = man.counterParty.object(channel.CounterpartyPort, channel.Counterparty) for _, hop := range channel.ConnectionHops { connobj, err := man.connection.Query(ctx, hop) if err != nil { @@ -124,73 +118,26 @@ func (man Manager) query(ctx sdk.Context, portid, chanid string) (obj Object, er } for _, hop := range channel.CounterpartyHops() { - connobj := man.counterparty.connection.Object(hop) - obj.counterparty.Connections = append(obj.counterparty.Connections, connobj) + connobj := man.counterParty.connection.CreateState(hop) + obj.counterParty.Connections = append(obj.counterParty.Connections, connobj) } return } -func (man Manager) Query(ctx sdk.Context, portid, chanid string) (obj Object, err error) { +func (man Manager) Query(ctx sdk.Context, portid, chanid string) (obj State, err error) { obj, err = man.query(ctx, portid, chanid) if !obj.Available.Get(ctx) { - err = errors.New("channel not Available") + err = errors.New("channel not available") return } return } -// TODO -/* -func (man Manager) Port(port string, chanid func(string) bool) PortManager { - return PortManager{ - man: man, - port: le, - chanid: chanid, - } -} - -// PortManage is port specific -type PortManager struct { - man Manager - port string - chanid func(string) bool -} - -func (man PortManager) Create(ctx sdk.Context, portid, chanid string, channel Channel) (Object, error) { - if !man.chanid(chanid) { - return Object{}, errors.New("invalid channel id") - } - - if channel.Port != man.port { - return Object{}, errors.New("invalid port") - } - - return man.man.Create(ctx, portid, chanid, channel) -} - -func (man PortManager) Query(ctx sdk.Context, portid, chanid string) (Object, error) { - if !man.chanid(chanid) { - return Object{}, errors.New("invalid channel id") - } - - obj, err := man.man.Query(ctx, portid, chanid) - if err != nil { - return Object{}, err - } - - if obj.Value(ctx).Port != man.port { - return Object{}, errors.New("invalid port") - } - - return obj, nil -} -*/ - -type Object struct { - chanid string - portid string +type State struct { + chanId string + portId string Channel state.Value @@ -200,14 +147,14 @@ type Object struct { Available state.Boolean - Connections []connection.Object + Connections []connection.State - counterparty CounterObject + counterParty CounterState } -type CounterObject struct { - chanid string - portid string +type CounterState struct { + chanId string + portId string Channel commitment.Value @@ -217,50 +164,45 @@ type CounterObject struct { Available commitment.Boolean - Connections []connection.CounterObject + Connections []connection.CounterState } -func (obj Object) OriginConnection() connection.Object { +func (obj State) OriginConnection() connection.State { return obj.Connections[0] } -func (obj Object) Context(ctx sdk.Context, proofs []commitment.Proof) (sdk.Context, error) { - return obj.OriginConnection().Context(ctx, nil, proofs) +func (obj State) Context(ctx sdk.Context, proofs []commitment.Proof, height uint64) (sdk.Context, error) { + return obj.OriginConnection().Context(ctx, height, proofs) } -func (obj Object) ChanID() string { - return obj.chanid +func (obj State) ChanID() string { + return obj.chanId } -func (obj Object) GetChannel(ctx sdk.Context) (res Channel) { +func (obj State) GetChannel(ctx sdk.Context) (res Channel) { obj.Channel.Get(ctx, &res) return } -func (obj Object) PacketCommit(ctx sdk.Context, index uint64) []byte { +func (obj State) PacketCommit(ctx sdk.Context, index uint64) []byte { return obj.Packets.Value(index).GetRaw(ctx) } /* -func (obj Object) Sendable(ctx sdk.Context) bool { +func (obj Stage) Sendable(ctx sdk.Context) bool { return obj.connection } -func (obj Object) Receivable(ctx sdk.Context) bool { +func (obj Stage) Receivable(ctx sdk.Context) bool { return kinds[obj.kind.Get(ctx)].Receivable } */ -func (obj Object) exists(ctx sdk.Context) bool { +func (obj State) exists(ctx sdk.Context) bool { return obj.Channel.Exists(ctx) } -func (man Manager) Send(ctx sdk.Context, portid, chanid string, packet Packet) error { - /* - if !obj.Sendable(ctx) { - return errors.New("cannot send Packets on this channel") - } - */ - obj, err := man.Query(ctx, portid, chanid) +func (man Manager) Send(ctx sdk.Context, chanId string, packet Packet) error { + obj, err := man.Query(ctx, packet.SenderPort(), chanId) if err != nil { return err } @@ -269,12 +211,22 @@ func (man Manager) Send(ctx sdk.Context, portid, chanid string, packet Packet) e return errors.New("timeout height higher than the latest known") } - obj.Packets.Set(ctx, obj.SeqSend.Increment(ctx), packet) + obj.Packets.SetRaw(ctx, obj.SeqSend.Increment(ctx), packet.Marshal()) + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + EventTypeSendPacket, + sdk.NewAttribute(AttributeKeySenderPort, packet.SenderPort()), + sdk.NewAttribute(AttributeKeyReceiverPort, packet.ReceiverPort()), + sdk.NewAttribute(AttributeKeyChannelID, chanId), + sdk.NewAttribute(AttributeKeySequence, strconv.FormatUint(obj.SeqSend.Get(ctx), 10)), + ), + }) return nil } -func (man Manager) Receive(ctx sdk.Context, proofs []commitment.Proof, portid, chanid string, packet Packet) error { +func (man Manager) Receive(ctx sdk.Context, proofs []commitment.Proof, height uint64, portid, chanid string, packet Packet) error { obj, err := man.Query(ctx, portid, chanid) if err != nil { return err @@ -286,7 +238,7 @@ func (man Manager) Receive(ctx sdk.Context, proofs []commitment.Proof, portid, c } */ - ctx, err = obj.Context(ctx, proofs) + ctx, err = obj.Context(ctx, proofs, height) if err != nil { return err } @@ -296,9 +248,7 @@ func (man Manager) Receive(ctx sdk.Context, proofs []commitment.Proof, portid, c return err } - // XXX: increment should happen before verification, reflect on the spec - // TODO: packet should be custom marshalled - if !obj.counterparty.Packets.Value(obj.SeqRecv.Increment(ctx)).Is(ctx, packet) { + if !obj.counterParty.Packets.Value(obj.SeqRecv.Increment(ctx)).IsRaw(ctx, packet.Marshal()) { return errors.New("verification failed") } diff --git a/x/ibc/04-channel/msgs.go b/x/ibc/04-channel/msgs.go index ba35f0bbc406..3fba21f320b4 100644 --- a/x/ibc/04-channel/msgs.go +++ b/x/ibc/04-channel/msgs.go @@ -2,19 +2,16 @@ package channel import ( sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) const Route = "ibc" type MsgOpenInit struct { - ConnectionID string - ChannelID string - Channel Channel - CounterpartyClient string - NextTimeout uint64 - Signer sdk.AccAddress + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Channel Channel `json:"channel"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenInit{} @@ -32,7 +29,7 @@ func (msg MsgOpenInit) ValidateBasic() sdk.Error { } func (msg MsgOpenInit) GetSignBytes() []byte { - return nil // TODO + return sdk.MustSortJSON(msgCdc.MustMarshalJSON(msg)) } func (msg MsgOpenInit) GetSigners() []sdk.AccAddress { @@ -40,14 +37,12 @@ func (msg MsgOpenInit) GetSigners() []sdk.AccAddress { } type MsgOpenTry struct { - ConnectionID string - ChannelID string - Channel Channel - CounterpartyClient string - Timeout uint64 - NextTimeout uint64 - Proofs []commitment.Proof - Signer sdk.AccAddress + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Channel Channel `json:"channel"` + Proofs []commitment.Proof `json:"proofs"` + Height uint64 `json:"height"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenTry{} @@ -65,7 +60,7 @@ func (msg MsgOpenTry) ValidateBasic() sdk.Error { } func (msg MsgOpenTry) GetSignBytes() []byte { - return nil // TODO + return sdk.MustSortJSON(msgCdc.MustMarshalJSON(msg)) } func (msg MsgOpenTry) GetSigners() []sdk.AccAddress { @@ -73,12 +68,11 @@ func (msg MsgOpenTry) GetSigners() []sdk.AccAddress { } type MsgOpenAck struct { - ConnectionID string - ChannelID string - Timeout uint64 - NextTimeout uint64 - Proofs []commitment.Proof - Signer sdk.AccAddress + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Proofs []commitment.Proof `json:"proofs"` + Height uint64 `json:"height"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenAck{} @@ -96,7 +90,7 @@ func (msg MsgOpenAck) ValidateBasic() sdk.Error { } func (msg MsgOpenAck) GetSignBytes() []byte { - return nil // TODO + return sdk.MustSortJSON(msgCdc.MustMarshalJSON(msg)) } func (msg MsgOpenAck) GetSigners() []sdk.AccAddress { @@ -104,11 +98,11 @@ func (msg MsgOpenAck) GetSigners() []sdk.AccAddress { } type MsgOpenConfirm struct { - ConnectionID string - ChannelID string - Timeout uint64 - Proofs []commitment.Proof - Signer sdk.AccAddress + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Proofs []commitment.Proof `json:"proofs"` + Height uint64 `json:"height"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenConfirm{} @@ -126,39 +120,45 @@ func (msg MsgOpenConfirm) ValidateBasic() sdk.Error { } func (msg MsgOpenConfirm) GetSignBytes() []byte { - return nil // TODO + return sdk.MustSortJSON(msgCdc.MustMarshalJSON(msg)) } func (msg MsgOpenConfirm) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } -type MsgReceive struct { - ConnectionID string - ChannelID string - Packet Packet - Proofs []commitment.Proof - Signer sdk.AccAddress +// PortID dependent on type +// ChannelID can be empty if batched & not first MsgPacket +// Height uint64 // height of the commitment root for the proofs +type MsgPacket struct { + Packet `json:"packet" yaml:"packet"` + ChannelID string `json:"channel_id,omitempty" yaml:"channel_id"` + Proofs []commitment.Proof `json:"proofs" yaml:"proofs"` + Height uint64 `json:"height" yaml:"height"` + Signer sdk.AccAddress `json:"signer,omitempty" yaml:"signer"` } -var _ sdk.Msg = MsgReceive{} +var _ sdk.Msg = MsgPacket{} -func (msg MsgReceive) Route() string { - return Route +func (msg MsgPacket) ValidateBasic() sdk.Error { + // Check PortID ChannelID len + // Check packet != nil + // Check proofs != nil + // Signer can be empty + return nil // TODO } -func (msg MsgReceive) Type() string { - return "receive" +func (msg MsgPacket) Route() string { + return msg.ReceiverPort() } -func (msg MsgReceive) ValidateBasic() sdk.Error { - return nil // TODO -} - -func (msg MsgReceive) GetSignBytes() []byte { - return nil // TODO +func (msg MsgPacket) GetSignBytes() []byte { + return sdk.MustSortJSON(msgCdc.MustMarshalJSON(msg)) } -func (msg MsgReceive) GetSigners() []sdk.AccAddress { +func (msg MsgPacket) GetSigners() []sdk.AccAddress { + if msg.Signer.Empty() { + return []sdk.AccAddress{} + } return []sdk.AccAddress{msg.Signer} } diff --git a/x/ibc/04-channel/port.go b/x/ibc/04-channel/port.go index 2b3505a50169..033b932e0e7a 100644 --- a/x/ibc/04-channel/port.go +++ b/x/ibc/04-channel/port.go @@ -1,6 +1,8 @@ package channel import ( + "errors" + sdk "github.com/cosmos/cosmos-sdk/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -8,7 +10,6 @@ import ( type Port struct { channel Manager id string - valid *bool // once invalid forever invalid } // bindPort, expected to be called only at init time @@ -18,20 +19,31 @@ func (man Manager) Port(id string) Port { panic("port already occupied") } man.ports[id] = struct{}{} - valid := true - return Port{man, id, &valid} + return Port{man, id} } // releasePort func (port Port) Release() { delete(port.channel.ports, port.id) - *port.valid = false +} + +func (man Manager) IsValid(port Port) bool { + _, ok := man.ports[port.id] + return ok } func (port Port) Send(ctx sdk.Context, chanid string, packet Packet) error { - return port.channel.Send(ctx, port.id, chanid, packet) + if !port.channel.IsValid(port) { + return errors.New("Port is not in valid state") + } + + if packet.SenderPort() != port.id { + panic("Packet sent on wrong port") + } + + return port.channel.Send(ctx, chanid, packet) } -func (port Port) Receive(ctx sdk.Context, proof []commitment.Proof, chanid string, packet Packet) error { - return port.channel.Receive(ctx, proof, port.id, chanid, packet) +func (port Port) Receive(ctx sdk.Context, proof []commitment.Proof, height uint64, chanid string, packet Packet) error { + return port.channel.Receive(ctx, proof, height, port.id, chanid, packet) } diff --git a/x/ibc/04-channel/router.go b/x/ibc/04-channel/router.go deleted file mode 100644 index 40c2c180fb31..000000000000 --- a/x/ibc/04-channel/router.go +++ /dev/null @@ -1,34 +0,0 @@ -package channel - -type Router interface { - AddRoute(path string, h Handler) Router - Route(path string) Handler -} - -type router struct { - routes map[string]Handler -} - -func NewRouter() Router { - return &router{ - routes: make(map[string]Handler), - } -} - -func (router *router) AddRoute(path string, h Handler) Router { - // TODO - /* - if !isAlphaNumeric(path) { - panic("route expressions can only contain alphanumeric characters") - } - */ - if router.routes[path] != nil { - panic("route " + path + "has already been initialized") - } - router.routes[path] = h - return router -} - -func (router *router) Route(path string) Handler { - return router.routes[path] -} diff --git a/x/ibc/04-channel/tests/channel_test.go b/x/ibc/04-channel/tests/channel_test.go index 82d27dca8089..1bd8edb8d443 100644 --- a/x/ibc/04-channel/tests/channel_test.go +++ b/x/ibc/04-channel/tests/channel_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" tmclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint" @@ -36,17 +37,34 @@ type MyPacket struct { Message string } -/* func (packet MyPacket) Commit() []byte { return []byte(packet.Message) } -*/ + func (packet MyPacket) Timeout() uint64 { return 100 // TODO } -func (MyPacket) Route() string { - return "my" +func (MyPacket) SenderPort() string { + return PortName +} + +func (MyPacket) ReceiverPort() string { + return PortName +} + +func (MyPacket) Type() string { + return "my-packet" +} + +func (MyPacket) ValidateBasic() sdk.Error { + return nil +} + +func (packet MyPacket) Marshal() []byte { + cdc := codec.New() + registerCodec(cdc) + return cdc.MustMarshalBinaryBare(packet) } func TestPacket(t *testing.T) { @@ -61,7 +79,7 @@ func TestPacket(t *testing.T) { header := node.Commit() node.Counterparty.UpdateClient(t, header) - cliobj := node.CLIObject() + cliobj := node.CLIState() _, ppacket := node.QueryValue(t, cliobj.Packets.Value(1)) - node.Counterparty.Receive(t, MyPacket{"ping"}, ppacket) + node.Counterparty.Receive(t, MyPacket{"ping"}, uint64(header.Height), ppacket) } diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index 22c8234fbabe..32221079fb3d 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -15,6 +15,8 @@ import ( commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) +const PortName = "port-test" + type Node struct { *connection.Node Counterparty *Node @@ -26,29 +28,25 @@ type Node struct { func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { res := &Node{ - Node: connection.NewNode(self, counter, cdc), // TODO: test with key prefix - - Cdc: cdc, + Node: connection.NewNode(self, counter, cdc), + Cdc: cdc, } res.Counterparty = &Node{ Node: res.Node.Counterparty, Counterparty: res, - - Cdc: cdc, + Cdc: cdc, } res.Channel = channel.Channel{ - Port: res.Name, Counterparty: res.Counterparty.Name, - CounterpartyPort: res.Counterparty.Name, + CounterpartyPort: PortName, ConnectionHops: []string{res.Name}, } res.Counterparty.Channel = channel.Channel{ - Port: res.Counterparty.Name, Counterparty: res.Name, - CounterpartyPort: res.Name, + CounterpartyPort: PortName, ConnectionHops: []string{res.Counterparty.Name}, } @@ -64,9 +62,9 @@ func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Conte return ctx, channel.NewHandshaker(man) } -func (node *Node) CLIObject() channel.HandshakeObject { +func (node *Node) CLIState() channel.HandshakeState { man := node.Manager() - return channel.NewHandshaker(man).CLIObject(node.Name, node.Name, []string{node.Counterparty.Name, node.Name}) + return channel.NewHandshaker(man).CLIState(PortName, node.Name, []string{node.Name}) } func base(cdc *codec.Codec, key sdk.StoreKey) (state.Mapping, state.Mapping) { @@ -83,38 +81,38 @@ func (node *Node) Manager() channel.Manager { func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenInit(ctx, node.Name, node.Name, node.Channel, 100) // TODO: test timeout + obj, err := man.OpenInit(ctx, PortName, node.Name, node.Channel) require.NoError(t, err) - require.Equal(t, channel.Init, obj.State.Get(ctx)) + require.Equal(t, channel.Init, obj.Stage.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) require.False(t, obj.Available.Get(ctx)) } -func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { +func (node *Node) OpenTry(t *testing.T, height uint64, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenTry(ctx, proofs, node.Name, node.Name, node.Channel, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenTry(ctx, proofs, height, PortName, node.Name, node.Channel) require.NoError(t, err) - require.Equal(t, channel.OpenTry, obj.State.Get(ctx)) + require.Equal(t, channel.OpenTry, obj.Stage.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) require.False(t, obj.Available.Get(ctx)) node.SetState(channel.OpenTry) } -func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { +func (node *Node) OpenAck(t *testing.T, height uint64, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenAck(ctx, proofs, node.Name, node.Name, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenAck(ctx, proofs, height, PortName, node.Name) require.NoError(t, err) - require.Equal(t, channel.Open, obj.State.Get(ctx)) + require.Equal(t, channel.Open, obj.Stage.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) require.True(t, obj.Available.Get(ctx)) node.SetState(channel.Open) } -func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { +func (node *Node) OpenConfirm(t *testing.T, height uint64, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenConfirm(ctx, proofs, node.Name, node.Name, 100 /*TODO*/) + obj, err := man.OpenConfirm(ctx, proofs, height, PortName, node.Name) require.NoError(t, err) - require.Equal(t, channel.Open, obj.State.Get(ctx)) + require.Equal(t, channel.Open, obj.Stage.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) require.True(t, obj.Available.Get(ctx)) node.SetState(channel.CloseTry) @@ -129,47 +127,44 @@ func (node *Node) Handshake(t *testing.T) { // counterparty.OpenTry node.Counterparty.UpdateClient(t, header) - cliobj := node.CLIObject() + cliobj := node.CLIState() _, pchan := node.QueryValue(t, cliobj.Channel) - _, pstate := node.QueryValue(t, cliobj.State) - _, ptimeout := node.QueryValue(t, cliobj.NextTimeout) - node.Counterparty.OpenTry(t, pchan, pstate, ptimeout) + _, pstate := node.QueryValue(t, cliobj.Stage) + node.Counterparty.OpenTry(t, uint64(header.Height), pchan, pstate) header = node.Counterparty.Commit() // self.OpenAck node.UpdateClient(t, header) - cliobj = node.Counterparty.CLIObject() + cliobj = node.Counterparty.CLIState() _, pchan = node.Counterparty.QueryValue(t, cliobj.Channel) - _, pstate = node.Counterparty.QueryValue(t, cliobj.State) - _, ptimeout = node.Counterparty.QueryValue(t, cliobj.NextTimeout) - node.OpenAck(t, pchan, pstate, ptimeout) + _, pstate = node.Counterparty.QueryValue(t, cliobj.Stage) + node.OpenAck(t, uint64(header.Height), pchan, pstate) header = node.Commit() // counterparty.OpenConfirm node.Counterparty.UpdateClient(t, header) - cliobj = node.CLIObject() - _, pstate = node.QueryValue(t, cliobj.State) - _, ptimeout = node.QueryValue(t, cliobj.NextTimeout) - node.Counterparty.OpenConfirm(t, pstate, ptimeout) + cliobj = node.CLIState() + _, pstate = node.QueryValue(t, cliobj.Stage) + node.Counterparty.OpenConfirm(t, uint64(header.Height), pstate) } func (node *Node) Send(t *testing.T, packet channel.Packet) { ctx, man := node.Context(), node.Manager() - obj, err := man.Query(ctx, node.Name, node.Name) + obj, err := man.Query(ctx, PortName, node.Name) require.NoError(t, err) seq := obj.SeqSend.Get(ctx) - err = man.Send(ctx, node.Name, node.Name, packet) + err = man.Send(ctx, node.Name, packet) require.NoError(t, err) require.Equal(t, seq+1, obj.SeqSend.Get(ctx)) require.Equal(t, node.Cdc.MustMarshalBinaryBare(packet), obj.PacketCommit(ctx, seq+1)) } -func (node *Node) Receive(t *testing.T, packet channel.Packet, proofs ...commitment.Proof) { +func (node *Node) Receive(t *testing.T, packet channel.Packet, height uint64, proofs ...commitment.Proof) { ctx, man := node.Context(), node.Manager() - obj, err := man.Query(ctx, node.Name, node.Name) + obj, err := man.Query(ctx, PortName, node.Name) require.NoError(t, err) seq := obj.SeqRecv.Get(ctx) - err = man.Receive(ctx, proofs, node.Name, node.Name, packet) + err = man.Receive(ctx, proofs, height, PortName, node.Name, packet) require.NoError(t, err) require.Equal(t, seq+1, obj.SeqRecv.Get(ctx)) } diff --git a/x/ibc/04-channel/types.go b/x/ibc/04-channel/types.go index fe25a08dfc5f..43688edaa92f 100644 --- a/x/ibc/04-channel/types.go +++ b/x/ibc/04-channel/types.go @@ -1,5 +1,9 @@ package channel +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + /* type Packet struct { Sequence uint64 @@ -15,13 +19,15 @@ type Packet struct { */ type Packet interface { + SenderPort() string + ReceiverPort() string // == Route() + Type() string + ValidateBasic() sdk.Error Timeout() uint64 - // Commit() []byte // Can be a commit message - Route() string + Marshal() []byte // Should exclude PortID/ChannelID info } type Channel struct { - Port string Counterparty string CounterpartyPort string ConnectionHops []string diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index 1606497ec4f8..681c8bd56985 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -7,7 +7,7 @@ import ( "github.com/tendermint/tendermint/crypto/merkle" "github.com/cosmos/cosmos-sdk/store/rootmulti" -// "github.com/cosmos/cosmos-sdk/store/state" + // "github.com/cosmos/cosmos-sdk/store/state" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -20,7 +20,7 @@ var _ commitment.Root = Root{} // Root is Merkle root hash type Root struct { - Hash []byte + Hash []byte `json:"hash"` } // NewRoot constructs a new Root @@ -41,9 +41,9 @@ var _ commitment.Path = Path{} // The constructed key from the Path and the key will be append(Path.KeyPath, append(Path.KeyPrefix, key...)) type Path struct { // KeyPath is the list of keys prepended before the prefixed key - KeyPath [][]byte + KeyPath [][]byte `json:"key_path"` // KeyPrefix is a byte slice prefixed before the key - KeyPrefix []byte + KeyPrefix []byte `json:"key_prefix"` } // NewPath() constructs new Path @@ -63,8 +63,8 @@ var _ commitment.Proof = Proof{} // Proof is Merkle proof with the key information. type Proof struct { - Proof *merkle.Proof - Key []byte + Proof *merkle.Proof `json:"proof"` + Key []byte `json:"key"` } // Implements commitment.Proof @@ -93,7 +93,7 @@ func (proof Proof) Verify(croot commitment.Root, cpath commitment.Path, value [] for _, key := range path.KeyPath { keypath = keypath.AppendKey(key, merkle.KeyEncodingHex) } - keypath = keypath.AppendKey(append(path.KeyPrefix, proof.Key...), merkle.KeyEncodingHex) + keypath = keypath.AppendKey(append(path.KeyPrefix, proof.Key...), merkle.KeyEncodingHex) // TODO: hard coded for now, should be extensible runtime := rootmulti.DefaultProofRuntime() @@ -109,6 +109,5 @@ type Value interface { } func NewProofFromValue(proof *merkle.Proof, prefix []byte, value Value) Proof { - // TODO: check HasPrefix return Proof{proof, bytes.TrimPrefix(value.KeyBytes(), prefix)} } diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 923a065334ea..1283c05983bd 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -3,7 +3,6 @@ package commitment import ( "bytes" "errors" - "fmt" ) // Store proves key-value pairs' inclusion or non-inclusion with @@ -12,7 +11,7 @@ type Store interface { Prove(key, value []byte) bool } -var _ Store = prefix{} // TODO: pointer +var _ Store = prefix{} type prefix struct { store Store @@ -80,7 +79,6 @@ func (store *store) Prove(key, value []byte) bool { } proof, ok := store.proofs[string(key)] if !ok { - fmt.Println(111, string(key)) return false } err := proof.Verify(store.root, store.path, value) diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 947d322c06bd..18de5d941600 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -66,7 +66,6 @@ func (v Value) Is(ctx sdk.Context, value interface{}) bool { // IsRaw() proves the proof with the Value's key and the provided raw value bytes. func (v Value) IsRaw(ctx sdk.Context, value []byte) bool { - return v.m.store(ctx).Prove(v.key, value) } diff --git a/x/ibc/ante.go b/x/ibc/ante.go new file mode 100644 index 000000000000..ae0a00315a05 --- /dev/null +++ b/x/ibc/ante.go @@ -0,0 +1,60 @@ +package ibc + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" +) + +// TODO: Should extract timeout msgs too +func ExtractMsgPackets(msgs []sdk.Msg) (res []MsgPacket, abort bool) { + res = make([]MsgPacket, 0, len(msgs)) + for _, msg := range msgs { + msgp, ok := msg.(MsgPacket) + if ok { + res = append(res, msgp) + } + } + + if len(res) >= 2 { + first := res[0] + for _, msg := range res[1:] { + if len(msg.ChannelID) != 0 && msg.ChannelID != first.ChannelID { + return res, true + } + msg.ChannelID = first.ChannelID + } + } + + return +} + +func VerifyMsgPackets(ctx sdk.Context, channel channel.Manager, msgs []MsgPacket) error { + for _, msg := range msgs { + err := channel.Receive(ctx, msg.Proofs, msg.Height, msg.ReceiverPort(), msg.ChannelID, msg.Packet) + if err != nil { + return err + } + } + + return nil +} + +func NewAnteHandler(channel channel.Manager) sdk.AnteHandler { + return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, res sdk.Result, abort bool) { + msgs, abort := ExtractMsgPackets(tx.GetMsgs()) + if abort { + return + } + + // GasMeter already set by auth.AnteHandler + + err := VerifyMsgPackets(ctx, channel, msgs) + if err != nil { + abort = true + return + } + + return ctx, res, false + } +} diff --git a/x/ibc/keeper.go b/x/ibc/keeper.go new file mode 100644 index 000000000000..df1d2bde063e --- /dev/null +++ b/x/ibc/keeper.go @@ -0,0 +1,33 @@ +package ibc + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/state" + sdk "github.com/cosmos/cosmos-sdk/types" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + "github.com/cosmos/cosmos-sdk/x/ibc/version" +) + +type Keeper struct { + client client.Manager + connection connection.Handshaker + channel channel.Handshaker +} + +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey) Keeper { + base := state.NewMapping(key, cdc, version.DefaultPrefix()) + client := client.NewManager(base) + connman := connection.NewManager(base, client) + chanman := channel.NewManager(base, connman) + return Keeper{ + client: client, + connection: connection.NewHandshaker(connman), + channel: channel.NewHandshaker(chanman), + } +} + +func (k Keeper) Port(id string) channel.Port { + return k.channel.Port(id) +} diff --git a/x/ibc/mock/recv/client/cli/query.go b/x/ibc/mock/recv/client/cli/query.go new file mode 100644 index 000000000000..627027ddea54 --- /dev/null +++ b/x/ibc/mock/recv/client/cli/query.go @@ -0,0 +1,53 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + + "github.com/cosmos/cosmos-sdk/x/ibc/mock/types" +) + +func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { + queryCmd := &cobra.Command{ + Use: "ibcmockrecv", + Short: "Querying commands for the ibcmockrecv module", + RunE: client.ValidateCmd, + } + + queryCmd.AddCommand(client.GetCommands( + GetCmdQuerySequence(queryRoute, cdc), + )...) + + return queryCmd +} + +func GetCmdQuerySequence(storeName string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "sequence [channel-id]", + Short: "Query the current sequence for the channel", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + val, _, err := ctx.QueryStore(types.SequenceKey(args[0]), storeName) + if err != nil { + return err + } + + var res uint64 + if val == nil { + res = 0 + } else { + cdc.MustUnmarshalBinaryBare(val, &res) + } + fmt.Println(res) + + return nil + }, + } +} diff --git a/x/ibc/mock/recv/handler.go b/x/ibc/mock/recv/handler.go new file mode 100644 index 000000000000..d992f799fcb1 --- /dev/null +++ b/x/ibc/mock/recv/handler.go @@ -0,0 +1,32 @@ +package mockrecv + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/ibc" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/types" +) + +func NewHandler(k Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case ibc.MsgPacket: + switch packet := msg.Packet.(type) { + case types.PacketSequence: + return handleMyPacket(ctx, k, packet, msg.ChannelID) + default: + return sdk.ErrUnknownRequest("23331345").Result() + } + default: + return sdk.ErrUnknownRequest("21345").Result() + } + } +} + +func handleMyPacket(ctx sdk.Context, k Keeper, packet types.PacketSequence, chanid string) (res sdk.Result) { + err := k.UpdateSequence(ctx, chanid, packet.Sequence) + if err != nil { + res.Log = "Invalid sequence" // should not return error, set only log + } + return +} diff --git a/x/ibc/mock/recv/keeper.go b/x/ibc/mock/recv/keeper.go new file mode 100644 index 000000000000..99ce5d2e9746 --- /dev/null +++ b/x/ibc/mock/recv/keeper.go @@ -0,0 +1,47 @@ +package mockrecv + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/types" +) + +type Keeper struct { + cdc *codec.Codec + key sdk.StoreKey + port ibc.Port +} + +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, port ibc.Port) Keeper { + return Keeper{ + cdc: cdc, + key: key, + port: port, + } +} + +func (k Keeper) GetSequence(ctx sdk.Context, chanid string) (res uint64) { + store := ctx.KVStore(k.key) + if store.Has(types.SequenceKey(chanid)) { + k.cdc.MustUnmarshalBinaryBare(store.Get(types.SequenceKey(chanid)), &res) + } else { + res = 0 + } + + return +} + +func (k Keeper) SetSequence(ctx sdk.Context, chanid string, seq uint64) { + store := ctx.KVStore(k.key) + store.Set(types.SequenceKey(chanid), k.cdc.MustMarshalBinaryBare(seq)) +} + +func (k Keeper) UpdateSequence(ctx sdk.Context, chanid string, seq uint64) sdk.Error { + if k.GetSequence(ctx, chanid)+1 != seq { + // TODO: proper error + return sdk.NewError(sdk.CodespaceType("ibcmock"), 800, "") + } + k.SetSequence(ctx, chanid, seq) + return nil +} diff --git a/x/ibc/mock/recv/module.go b/x/ibc/mock/recv/module.go new file mode 100644 index 000000000000..89c8ce099a0a --- /dev/null +++ b/x/ibc/mock/recv/module.go @@ -0,0 +1,111 @@ +package mockrecv + +import ( + "encoding/json" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/recv/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/types" +) + +const ( + ModuleName = "ibcmockrecv" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +type AppModuleBasic struct{} + +var _ module.AppModuleBasic = AppModuleBasic{} + +func (AppModuleBasic) Name() string { + return ModuleName +} + +func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { + types.RegisterCodec(cdc) +} + +func (AppModuleBasic) DefaultGenesis() json.RawMessage { + return nil +} + +func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { + return nil +} + +func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { + //noop +} + +func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { + return nil +} + +func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetQueryCmd(ModuleName, cdc) +} + +type AppModule struct { + AppModuleBasic + k Keeper +} + +func NewAppModule(k Keeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{}, + + k: k, + } +} + +func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + +} + +func (AppModule) Name() string { + return ModuleName +} + +func (AppModule) Route() string { + return ModuleName +} + +func (am AppModule) NewHandler() sdk.Handler { + return NewHandler(am.k) +} + +func (am AppModule) QuerierRoute() string { + return ModuleName +} + +func (am AppModule) NewQuerierHandler() sdk.Querier { + return nil +} + +func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { + return nil +} + +func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { + +} + +func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} diff --git a/x/ibc/mock/send/client/cli/query.go b/x/ibc/mock/send/client/cli/query.go new file mode 100644 index 000000000000..2a68794f8587 --- /dev/null +++ b/x/ibc/mock/send/client/cli/query.go @@ -0,0 +1,53 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + + "github.com/cosmos/cosmos-sdk/x/ibc/mock/types" +) + +func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { + queryCmd := &cobra.Command{ + Use: "ibcmocksend", + Short: "Querying commands for the ibcmocksend module", + RunE: client.ValidateCmd, + } + + queryCmd.AddCommand(client.GetCommands( + GetCmdQuerySequence(queryRoute, cdc), + )...) + + return queryCmd +} + +func GetCmdQuerySequence(storeName string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "sequence [channel-id]", + Short: "Query the current sequence for the channel", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + val, _, err := ctx.QueryStore(types.SequenceKey(args[0]), storeName) + if err != nil { + return err + } + + var res uint64 + if val == nil { + res = 0 + } else { + cdc.MustUnmarshalBinaryBare(val, &res) + } + fmt.Println(res) + + return nil + }, + } +} diff --git a/x/ibc/mock/send/client/cli/tx.go b/x/ibc/mock/send/client/cli/tx.go new file mode 100644 index 000000000000..f59a2c67906a --- /dev/null +++ b/x/ibc/mock/send/client/cli/tx.go @@ -0,0 +1,53 @@ +package cli + +import ( + "strconv" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/types" +) + +func GetTxCmd(cdc *codec.Codec) *cobra.Command { + txCmd := &cobra.Command{ + Use: "ibcmocksend", + Short: "IBC mocksend module transaction subcommands", + RunE: client.ValidateCmd, + } + txCmd.AddCommand( + SequenceTxCmd(cdc), + ) + + return txCmd +} + +func SequenceTxCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "sequence [channel-id] [sequence]", + Short: "Send SequencePacket", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + ctx := context.NewCLIContext().WithCodec(cdc) + + chanid := args[0] + seq, err := strconv.ParseUint(args[1], 10, 64) + if err != nil { + return err + } + + msg := types.NewMsgSequence(ctx.GetFromAddress(), chanid, seq) + return utils.GenerateOrBroadcastMsgs(ctx, txBldr, []sdk.Msg{msg}) + }, + } + + cmd = client.PostCommands(cmd)[0] + + return cmd +} diff --git a/x/ibc/mock/send/handler.go b/x/ibc/mock/send/handler.go new file mode 100644 index 000000000000..dfc92719bc61 --- /dev/null +++ b/x/ibc/mock/send/handler.go @@ -0,0 +1,26 @@ +package mocksend + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/mock/types" +) + +func NewHandler(k Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case types.MsgSequence: + return handleMsgSequence(ctx, k, msg) + default: + return sdk.ErrUnknownRequest("21345").Result() + } + } +} + +func handleMsgSequence(ctx sdk.Context, k Keeper, msg types.MsgSequence) (res sdk.Result) { + err := k.UpdateSequence(ctx, msg.ChannelID, msg.Sequence) + if err != nil { + return err.Result() + } + return res +} diff --git a/x/ibc/mock/send/keeper.go b/x/ibc/mock/send/keeper.go new file mode 100644 index 000000000000..ce88988093e3 --- /dev/null +++ b/x/ibc/mock/send/keeper.go @@ -0,0 +1,49 @@ +package mocksend + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/types" +) + +type Keeper struct { + cdc *codec.Codec + key sdk.StoreKey + port ibc.Port +} + +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, port ibc.Port) Keeper { + return Keeper{ + cdc: cdc, + key: key, + port: port, + } +} + +func (k Keeper) UpdateSequence(ctx sdk.Context, chanid string, seq uint64) sdk.Error { + stored := k.GetSequence(ctx, chanid) + if seq != stored+1 { + // TODO: use proper error + return sdk.NewError(sdk.CodespaceType("ibcmocksend"), 600, "invalid sequence") + } + k.SetSequence(ctx, chanid, seq) + k.port.Send(ctx, chanid, types.PacketSequence{seq}) + return nil +} + +func (k Keeper) GetSequence(ctx sdk.Context, chanid string) (res uint64) { + store := ctx.KVStore(k.key) + if store.Has(types.SequenceKey(chanid)) { + k.cdc.MustUnmarshalBinaryBare(store.Get(types.SequenceKey(chanid)), &res) + } else { + res = 0 + } + + return +} + +func (k Keeper) SetSequence(ctx sdk.Context, chanid string, seq uint64) { + store := ctx.KVStore(k.key) + store.Set(types.SequenceKey(chanid), k.cdc.MustMarshalBinaryBare(seq)) +} diff --git a/x/ibc/mock/send/module.go b/x/ibc/mock/send/module.go new file mode 100644 index 000000000000..8e45118fe495 --- /dev/null +++ b/x/ibc/mock/send/module.go @@ -0,0 +1,111 @@ +package mocksend + +import ( + "encoding/json" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/send/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/types" +) + +const ( + ModuleName = "ibcmocksend" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +type AppModuleBasic struct{} + +var _ module.AppModuleBasic = AppModuleBasic{} + +func (AppModuleBasic) Name() string { + return ModuleName +} + +func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { + types.RegisterCodec(cdc) +} + +func (AppModuleBasic) DefaultGenesis() json.RawMessage { + return nil +} + +func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { + return nil +} + +func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { + //noop +} + +func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetTxCmd(cdc) +} + +func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetQueryCmd(ModuleName, cdc) +} + +type AppModule struct { + AppModuleBasic + k Keeper +} + +func NewAppModule(k Keeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{}, + + k: k, + } +} + +func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + +} + +func (AppModule) Name() string { + return ModuleName +} + +func (AppModule) Route() string { + return ModuleName +} + +func (am AppModule) NewHandler() sdk.Handler { + return NewHandler(am.k) +} + +func (am AppModule) QuerierRoute() string { + return ModuleName +} + +func (am AppModule) NewQuerierHandler() sdk.Querier { + return nil +} + +func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { + return nil +} + +func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { + +} + +func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} diff --git a/x/ibc/mock/types/codec.go b/x/ibc/mock/types/codec.go new file mode 100644 index 000000000000..2c1dfe7b2a65 --- /dev/null +++ b/x/ibc/mock/types/codec.go @@ -0,0 +1,9 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(PacketSequence{}, "ibcmock/PacketSequence", nil) +} diff --git a/x/ibc/mock/types/keys.go b/x/ibc/mock/types/keys.go new file mode 100644 index 000000000000..3134a5ad511a --- /dev/null +++ b/x/ibc/mock/types/keys.go @@ -0,0 +1,5 @@ +package types + +func SequenceKey(chanid string) []byte { + return []byte("sequence/" + chanid) +} diff --git a/x/ibc/mock/types/msgs.go b/x/ibc/mock/types/msgs.go new file mode 100644 index 000000000000..09a226b41e63 --- /dev/null +++ b/x/ibc/mock/types/msgs.go @@ -0,0 +1,42 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var cdc = codec.New() + +type MsgSequence struct { + Sequence uint64 + ChannelID string + Signer sdk.AccAddress +} + +func NewMsgSequence(signer sdk.AccAddress, chanid string, sequence uint64) MsgSequence { + return MsgSequence{ + Sequence: sequence, + ChannelID: chanid, + Signer: signer, + } +} + +func (MsgSequence) Route() string { + return "ibcmock" +} + +func (MsgSequence) Type() string { + return "sequence" +} + +func (msg MsgSequence) ValidateBasic() sdk.Error { + return nil +} + +func (msg MsgSequence) GetSignBytes() []byte { + return sdk.MustSortJSON(cdc.MustMarshalJSON(msg)) +} + +func (msg MsgSequence) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} diff --git a/x/ibc/mock/types/packets.go b/x/ibc/mock/types/packets.go new file mode 100644 index 000000000000..745adef2188c --- /dev/null +++ b/x/ibc/mock/types/packets.go @@ -0,0 +1,74 @@ +package types + +import ( + "bytes" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc" +) + +var _ ibc.Packet = PacketSequence{} + +type PacketSequence struct { + Sequence uint64 +} + +func (packet PacketSequence) MarshalAmino() (string, error) { + return fmt.Sprintf("sequence-packet-%d", packet.Sequence), nil +} + +func (packet *PacketSequence) UnmarshalAmino(text string) (err error) { + if !strings.HasPrefix(text, "sequence-packet-") { + return errors.New("invalid PacketSequence string") + } + packet.Sequence, err = strconv.ParseUint(strings.TrimPrefix(text, "sequence-packet-"), 10, 64) + return +} + +func (packet PacketSequence) Marshal() []byte { + cdc := codec.New() + RegisterCodec(cdc) + return cdc.MustMarshalBinaryBare(packet) +} + +func (packet PacketSequence) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf("\"sequence-packet-%d\"", packet.Sequence)), nil +} + +func (packet *PacketSequence) UnmarshalJSON(bz []byte) (err error) { + bz = bz[1 : len(bz)-1] + if !bytes.HasPrefix(bz, []byte("sequence-packet-")) { + return errors.New("invalid PacketSequence string") + } + packet.Sequence, err = strconv.ParseUint(strings.TrimPrefix(string(bz), "sequence-packet-"), 10, 64) + return +} + +func (PacketSequence) SenderPort() string { + return "ibcmocksend" +} + +func (PacketSequence) ReceiverPort() string { + return "ibcmockrecv" +} + +func (PacketSequence) String() string { + return "sequence-packet" +} + +func (PacketSequence) Timeout() uint64 { + return 0 +} + +func (PacketSequence) Type() string { + return "empty-packet" +} + +func (PacketSequence) ValidateBasic() sdk.Error { + return nil +} diff --git a/x/ibc/module.go b/x/ibc/module.go new file mode 100644 index 000000000000..4990660b33f4 --- /dev/null +++ b/x/ibc/module.go @@ -0,0 +1,175 @@ +package ibc + +import ( + "encoding/json" + "fmt" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + clicli "github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + conncli "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/cli" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + chancli "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/client/cli" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +const ( + ModuleName = "ibc" + StoreKey = ModuleName +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +type AppModuleBasic struct{} + +var _ module.AppModuleBasic = AppModuleBasic{} + +func (AppModuleBasic) Name() string { + return ModuleName +} + +func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { + commitment.RegisterCodec(cdc) + merkle.RegisterCodec(cdc) + client.RegisterCodec(cdc) + connection.RegisterCodec(cdc) + tendermint.RegisterCodec(cdc) + channel.RegisterCodec(cdc) + + client.SetMsgCodec(cdc) + connection.SetMsgCodec(cdc) + channel.SetMsgCodec(cdc) +} + +func (AppModuleBasic) DefaultGenesis() json.RawMessage { + return nil +} + +func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { + return nil +} + +func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { + //noop +} + +func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "ibc", + Short: "IBC transaction subcommands", + } + + cmd.AddCommand( + clicli.GetTxCmd(ModuleName, cdc), + conncli.GetTxCmd(ModuleName, cdc), + chancli.GetTxCmd(ModuleName, cdc), + ) + + return cmd +} + +func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "ibc", + Short: "IBC query subcommands", + } + + cmd.AddCommand( + clicli.GetQueryCmd(ModuleName, cdc), + conncli.GetQueryCmd(ModuleName, cdc), + chancli.GetQueryCmd(ModuleName, cdc), + ) + + return cmd +} + +type AppModule struct { + AppModuleBasic + Keeper +} + +func NewAppModule(k Keeper) AppModule { + return AppModule{ + Keeper: k, + } +} + +func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + +} + +func (AppModule) Name() string { + return ModuleName +} + +func (AppModule) Route() string { + return ModuleName +} + +func (am AppModule) NewHandler() sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case client.MsgCreateClient: + return client.HandleMsgCreateClient(ctx, msg, am.client) + case client.MsgUpdateClient: + return client.HandleMsgUpdateClient(ctx, msg, am.client) + case connection.MsgOpenInit: + return connection.HandleMsgOpenInit(ctx, msg, am.connection) + case connection.MsgOpenTry: + return connection.HandleMsgOpenTry(ctx, msg, am.connection) + case connection.MsgOpenAck: + return connection.HandleMsgOpenAck(ctx, msg, am.connection) + case connection.MsgOpenConfirm: + return connection.HandleMsgOpenConfirm(ctx, msg, am.connection) + case channel.MsgOpenInit: + return channel.HandleMsgOpenInit(ctx, msg, am.channel) + case channel.MsgOpenTry: + return channel.HandleMsgOpenTry(ctx, msg, am.channel) + case channel.MsgOpenAck: + return channel.HandleMsgOpenAck(ctx, msg, am.channel) + case channel.MsgOpenConfirm: + return channel.HandleMsgOpenConfirm(ctx, msg, am.channel) + default: + errMsg := fmt.Sprintf("unrecognized IBC message type: %T", msg) + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +func (am AppModule) QuerierRoute() string { + return ModuleName +} + +func (am AppModule) NewQuerierHandler() sdk.Querier { + return nil +} + +func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { + return nil +} + +func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { + +} + +func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} diff --git a/x/ibc/msgs.go b/x/ibc/msgs.go new file mode 100644 index 000000000000..fc05da83d817 --- /dev/null +++ b/x/ibc/msgs.go @@ -0,0 +1,19 @@ +package ibc + +import ( + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" +) + +type MsgCreateClient = client.MsgCreateClient +type MsgUpdateClient = client.MsgUpdateClient +type MsgOpenInitConnection = connection.MsgOpenInit +type MsgOpenTryConnection = connection.MsgOpenTry +type MsgOpenAckConnection = connection.MsgOpenAck +type MsgOpenConfirmConnection = connection.MsgOpenConfirm +type MsgOpenInitChannel = channel.MsgOpenInit +type MsgOpenTryChannel = channel.MsgOpenTry +type MsgOpenAckChannel = channel.MsgOpenAck +type MsgOpenConfirmChannel = channel.MsgOpenConfirm +type MsgPacket = channel.MsgPacket diff --git a/x/ibc/types.go b/x/ibc/types.go new file mode 100644 index 000000000000..be9303d07504 --- /dev/null +++ b/x/ibc/types.go @@ -0,0 +1,9 @@ +package ibc + +import ( + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" +) + +type Port = channel.Port + +type Packet = channel.Packet diff --git a/x/ibc/version.go b/x/ibc/version.go deleted file mode 100644 index b6648efb40c8..000000000000 --- a/x/ibc/version.go +++ /dev/null @@ -1,9 +0,0 @@ -package ibc - -import "strconv" - -const Version int64 = 1 - -func VersionPrefix(version int64) []byte { - return []byte(strconv.FormatInt(version, 10) + "/") -} diff --git a/x/ibc/version/version.go b/x/ibc/version/version.go new file mode 100644 index 000000000000..a7d3275fae5b --- /dev/null +++ b/x/ibc/version/version.go @@ -0,0 +1,13 @@ +package version + +import "strconv" + +const Version int64 = 1 + +func DefaultPrefix() []byte { + return Prefix(Version) +} + +func Prefix(version int64) []byte { + return []byte("v" + strconv.FormatInt(version, 10) + "/") +}