From 9375649bc43172ce8cdca35c57a9174532ecbdd5 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 7 Jun 2019 23:44:43 +0200 Subject: [PATCH 001/378] add mapping --- store/mapping/base.go | 91 +++++++++++++++++ store/mapping/boolean.go | 43 ++++++++ store/mapping/enum.go | 74 ++++++++++++++ store/mapping/indexer.go | 159 ++++++++++++++++++++++++++++++ store/mapping/integer.go | 83 ++++++++++++++++ store/mapping/mapping.go | 186 +++++++++++++++++++++++++++++++++++ store/mapping/queue.go | 43 ++++++++ store/mapping/sorted.go | 66 +++++++++++++ store/mapping/test_common.go | 55 +++++++++++ store/mapping/types.go | 14 +++ store/mapping/value.go | 156 +++++++++++++++++++++++++++++ store/mapping/value_test.go | 32 ++++++ 12 files changed, 1002 insertions(+) create mode 100644 store/mapping/base.go create mode 100644 store/mapping/boolean.go create mode 100644 store/mapping/enum.go create mode 100644 store/mapping/indexer.go create mode 100644 store/mapping/integer.go create mode 100644 store/mapping/mapping.go create mode 100644 store/mapping/queue.go create mode 100644 store/mapping/sorted.go create mode 100644 store/mapping/test_common.go create mode 100644 store/mapping/types.go create mode 100644 store/mapping/value.go create mode 100644 store/mapping/value_test.go diff --git a/store/mapping/base.go b/store/mapping/base.go new file mode 100644 index 000000000000..4d9da596ec9e --- /dev/null +++ b/store/mapping/base.go @@ -0,0 +1,91 @@ +package mapping + +import ( + // "github.com/tendermint/tendermint/crypto/merkle" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +/* +type keypath struct { + keypath merkle.KeyPath + prefix []byte +} + +func (path keypath) _prefix(prefix []byte) (res keypath) { + res.keypath = path.keypath + res.prefix = make([]byte, len(path.prefix)+len(prefix)) + copy(res.prefix[:len(path.prefix)], path.prefix) + copy(res.prefix[len(path.prefix):], prefix) + return +} +*/ +type Base struct { + cdc *codec.Codec + storefn func(Context) KVStore + prefix []byte + // keypath keypath // temporal +} + +func EmptyBase() Base { + return NewBase(nil, nil) +} + +func NewBase(cdc *codec.Codec, key sdk.StoreKey) Base { + return Base{ + cdc: cdc, + storefn: func(ctx Context) KVStore { return ctx.KVStore(key) }, + /* + keypath: keypath{ + keypath: new(KeyPath).AppendKey([]byte(key.Name()), merkle.KeyEncodingHex), + }, + */ + } +} + +func NewBaseWithGetter(cdc *codec.Codec, storefn func(Context) KVStore) Base { + return Base{ + cdc: cdc, + storefn: storefn, + } +} + +func (base Base) store(ctx Context) KVStore { + return prefix.NewStore(base.storefn(ctx), base.prefix) +} + +func (base Base) Prefix(prefix []byte) (res Base) { + res = Base{ + cdc: base.cdc, + storefn: base.storefn, + //keypath: base.keypath._prefix(prefix), + } + res.prefix = join(base.prefix, prefix) + return +} + +func (base Base) Cdc() *codec.Codec { + return base.cdc +} + +func (base Base) key(key []byte) []byte { + return join(base.prefix, key) +} + +func join(a, b []byte) (res []byte) { + res = make([]byte, len(a)+len(b)) + copy(res, a) + copy(res[len(a):], b) + return +} + +/* +func (base Base) KeyPath() merkle.KeyPath { + if len(base.keypath.prefix) != 0 { + return base.keypath.keypath.AppendKey(base.keypath.prefix, merkle.KeyEncodingHex) + } + return base.keypath.keypath +} +*/ diff --git a/store/mapping/boolean.go b/store/mapping/boolean.go new file mode 100644 index 000000000000..0c78707bf6fa --- /dev/null +++ b/store/mapping/boolean.go @@ -0,0 +1,43 @@ +package mapping + +// XXX: interface +type Boolean struct { + Enum +} + +func NewBoolean(v Value) Boolean { + return Boolean{NewEnum(v)} +} + +func (v Boolean) Get(ctx Context) bool { + return v.Enum.Get(ctx) != 0x00 +} + +func (v Boolean) GetIfExists(ctx Context) bool { + return v.Enum.GetIfExists(ctx) != 0x00 +} + +func (v Boolean) GetSafe(ctx Context) (bool, error) { + res, err := v.Enum.GetSafe(ctx) + return res != 0x00, err +} + +func (v Boolean) Set(ctx Context, value bool) { + if value { + v.Enum.Set(ctx, 0x01) + } else { + v.Enum.Set(ctx, 0x00) + } +} + +func (v Boolean) Flip(ctx Context) (res bool) { + res = !v.GetIfExists(ctx) + v.Set(ctx, res) + return +} + +/* +func (v Boolean) Key() []byte { + return v.base.key(v.key) +} +*/ diff --git a/store/mapping/enum.go b/store/mapping/enum.go new file mode 100644 index 000000000000..dffc2b8fc6e4 --- /dev/null +++ b/store/mapping/enum.go @@ -0,0 +1,74 @@ +package mapping + +type Enum interface { + coreValue + Get(Context) byte + GetIfExists(Context) byte + GetSafe(Context) (byte, error) + Set(Context, byte) + Transit(Context, byte, byte) bool + Is(Context, byte) bool +} + +var _ Enum = enum{} + +type enum struct { + Value +} + +func NewEnum(v Value) enum { + return enum{v} +} + +/* +func (v Value) enum() enum { + return enum{v} +} +*/ +func (v enum) Get(ctx Context) byte { + return v.Value.GetRaw(ctx)[0] +} + +func (v enum) GetIfExists(ctx Context) byte { + res := v.Value.GetRaw(ctx) + if res != nil { + return res[0] + } + return 0x00 +} + +func (v enum) GetSafe(ctx Context) (byte, error) { + res := v.Value.GetRaw(ctx) + if res == nil { + return 0x00, &GetSafeError{} + } + return res[0], nil +} + +func (v enum) Set(ctx Context, value byte) { + v.Value.SetRaw(ctx, []byte{value}) +} + +func (v enum) Incr(ctx Context) (res byte) { + res = v.GetIfExists(ctx) + 1 + v.Set(ctx, res) + return +} + +func (v enum) Transit(ctx Context, from, to byte) bool { + if v.GetIfExists(ctx) != from { + return false + } + v.Set(ctx, to) + return true +} + +func (v enum) Is(ctx Context, value byte) bool { + return v.Get(ctx) == value +} + +/* +func (v enum) Key() []byte { + return v.base.key(v.key) +} +*/ diff --git a/store/mapping/indexer.go b/store/mapping/indexer.go new file mode 100644 index 000000000000..5d2cf5f7371f --- /dev/null +++ b/store/mapping/indexer.go @@ -0,0 +1,159 @@ +package mapping + +import ( + "encoding/binary" + "fmt" + "strconv" +) + +type IntEncoding byte + +const ( + Dec IntEncoding = iota + Hex + Bin +) + +type Indexer struct { + m Mapping + + enc IntEncoding +} + +func NewIndexer(base Base, prefix []byte, enc IntEncoding) Indexer { + return Indexer{ + m: NewMapping(base, prefix), + enc: enc, + } +} + +// Identical length independent from the index, ensure ordering +func EncodeInt(index uint64, enc IntEncoding) (res []byte) { + switch enc { + case Dec: + return []byte(fmt.Sprintf("%020d", index)) + case Hex: + return []byte(fmt.Sprintf("%020x", index)) + case Bin: + res = make([]byte, 8) + binary.BigEndian.PutUint64(res, index) + return + default: + panic("invalid IntEncoding") + } +} + +func DecodeInt(bz []byte, enc IntEncoding) (res uint64, err error) { + switch enc { + case Dec: + return strconv.ParseUint(string(bz), 10, 64) + case Hex: + return strconv.ParseUint(string(bz), 16, 64) + case Bin: + return binary.BigEndian.Uint64(bz), nil + default: + panic("invalid IntEncoding") + } +} + +func (ix Indexer) Value(index uint64) Value { + return ix.m.Value(EncodeInt(index, ix.enc)) +} + +func (ix Indexer) Get(ctx Context, index uint64, ptr interface{}) { + ix.Value(index).Get(ctx, ptr) +} + +func (ix Indexer) GetIfExists(ctx Context, index uint64, ptr interface{}) { + ix.Value(index).GetIfExists(ctx, ptr) +} + +func (ix Indexer) GetSafe(ctx Context, index uint64, ptr interface{}) error { + return ix.Value(index).GetSafe(ctx, ptr) +} + +func (ix Indexer) Set(ctx Context, index uint64, o interface{}) { + ix.Value(index).Set(ctx, o) +} + +func (ix Indexer) Has(ctx Context, index uint64) bool { + return ix.Value(index).Exists(ctx) +} + +func (ix Indexer) Delete(ctx Context, index uint64) { + ix.Value(index).Delete(ctx) +} + +func (ix Indexer) IsEmpty(ctx Context) bool { + return ix.m.IsEmpty(ctx) +} + +func (ix Indexer) Prefix(prefix []byte) Indexer { + return Indexer{ + m: ix.m.Prefix(prefix), + + enc: ix.enc, + } +} + +func (ix Indexer) Range(start, end uint64) Indexer { + return Indexer{ + m: ix.m.Range(EncodeInt(start, ix.enc), EncodeInt(end, ix.enc)), + + enc: ix.enc, + } +} + +func (ix Indexer) IterateAscending(ctx Context, ptr interface{}, fn func(uint64) bool) { + ix.m.Iterate(ctx, ptr, func(bz []byte) bool { + key, err := DecodeInt(bz, ix.enc) + if err != nil { + panic(err) + } + return fn(key) + }) +} + +func (ix Indexer) IterateDescending(ctx Context, ptr interface{}, fn func(uint64) bool) { + ix.m.ReverseIterate(ctx, ptr, func(bz []byte) bool { + key, err := DecodeInt(bz, ix.enc) + if err != nil { + panic(err) + } + return fn(key) + }) +} + +func (ix Indexer) First(ctx Context, ptr interface{}) (key uint64, ok bool) { + keybz, ok := ix.m.First(ctx, ptr) + if !ok { + return + } + if len(keybz) != 0 { + key, err := DecodeInt(keybz, ix.enc) + if err != nil { + return key, false + } + } + return +} + +func (ix Indexer) Last(ctx Context, ptr interface{}) (key uint64, ok bool) { + keybz, ok := ix.m.Last(ctx, ptr) + if !ok { + return + } + if len(keybz) != 0 { + key, err := DecodeInt(keybz, ix.enc) + if err != nil { + return key, false + } + } + return +} + +/* +func (ix Indexer) Key(index uint64) []byte { + return ix.m.Key(EncodeInt(index, ix.enc)) +} +*/ diff --git a/store/mapping/integer.go b/store/mapping/integer.go new file mode 100644 index 000000000000..45b484f67a16 --- /dev/null +++ b/store/mapping/integer.go @@ -0,0 +1,83 @@ +package mapping + +type Integer interface { + coreValue + Get(Context) uint64 + GetIfExists(Context) uint64 + GetSafe(Context) (uint64, error) + Set(Context, uint64) + Incr(Context) uint64 + Is(Context, uint64) bool +} + +var _ Integer = integer{} + +type integer struct { + Value + + enc IntEncoding +} + +func NewInteger(v Value, enc IntEncoding) integer { + return integer{ + Value: v, + enc: enc, + } +} + +/* +func (v Value) integer() integer { + return integer{v} +} +*/ +func (v integer) Get(ctx Context) uint64 { + res, err := DecodeInt(v.GetRaw(ctx), v.enc) + if err != nil { + panic(err) + } + return res +} + +func (v integer) GetIfExists(ctx Context) (res uint64) { + bz := v.GetRaw(ctx) + if bz == nil { + return 0 + } + res, err := DecodeInt(bz, v.enc) + if err != nil { + panic(err) + } + return res +} + +func (v integer) GetSafe(ctx Context) (uint64, error) { + bz := v.GetRaw(ctx) + if bz == nil { + return 0, &GetSafeError{} + } + res, err := DecodeInt(bz, v.enc) + if err != nil { + panic(err) + } + return res, nil +} + +func (v integer) Set(ctx Context, value uint64) { + v.SetRaw(ctx, EncodeInt(value, v.enc)) +} + +func (v integer) Incr(ctx Context) (res uint64) { + res = v.GetIfExists(ctx) + 1 + v.Set(ctx, res) + return +} + +func (v integer) Is(ctx Context, value uint64) bool { + return v.Get(ctx) == value +} + +/* +func (v integer) Key() []byte { + return v.base.key(v.key) +} +*/ diff --git a/store/mapping/mapping.go b/store/mapping/mapping.go new file mode 100644 index 000000000000..62343f58e4d4 --- /dev/null +++ b/store/mapping/mapping.go @@ -0,0 +1,186 @@ +package mapping + +import ( + "reflect" + + "github.com/cosmos/cosmos-sdk/store" +) + +type Mapping struct { + base Base + start, end []byte +} + +func NewMapping(base Base, prefix []byte) Mapping { + return Mapping{ + base: base.Prefix(prefix), + start: []byte{}, // preventing nil key access in store.Last + } +} + +func (m Mapping) store(ctx Context) KVStore { + return m.base.store(ctx) +} + +/* +func (m Mapping) keyPath() (res KeyPath) { + if len(m.prefix) != 0 { + return m.base.Prefix(m.prefix).KeyPath() + } + return m.base.KeyPath() +} +*/ +func (m Mapping) Value(key []byte, constructor ...func(Base, []byte) Value) Value { + if len(constructor) == 1 { + return constructor[0](m.base, key) + } + return NewValue(m.base, key) +} + +func (m Mapping) Get(ctx Context, key []byte, ptr interface{}) { + m.Value(key).Get(ctx, ptr) +} + +func (m Mapping) GetIfExists(ctx Context, key []byte, ptr interface{}) { + m.Value(key).GetIfExists(ctx, ptr) +} + +func (m Mapping) GetSafe(ctx Context, key []byte, ptr interface{}) error { + return m.Value(key).GetSafe(ctx, ptr) +} + +func (m Mapping) Set(ctx Context, key []byte, o interface{}) { + if o == nil { + m.Delete(ctx, key) + return + } + m.Value(key).Set(ctx, o) +} + +func (m Mapping) Has(ctx Context, key []byte) bool { + return m.Value(key).Exists(ctx) +} + +func (m Mapping) Delete(ctx Context, key []byte) { + m.Value(key).Delete(ctx) +} + +func (m Mapping) IsEmpty(ctx Context) bool { + iter := m.store(ctx).Iterator(nil, nil) + defer iter.Close() + return iter.Valid() +} + +func (m Mapping) Prefix(prefix []byte) Mapping { + return NewMapping(m.base, prefix) +} + +func (m Mapping) Range(start, end []byte) Mapping { + return Mapping{ + base: m.base, + start: start, + end: end, + } +} + +// go-amino does not support decoding to a non-nil interface +func setnil(ptr interface{}) { + v := reflect.ValueOf(ptr) + v.Elem().Set(reflect.Zero(v.Elem().Type())) +} + +func (m Mapping) Iterate(ctx Context, ptr interface{}, fn func([]byte) bool) { + iter := m.store(ctx).Iterator(m.start, m.end) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + setnil(ptr) + + v := iter.Value() + + m.base.cdc.MustUnmarshalBinaryBare(v, ptr) + + if fn(iter.Key()) { + break + } + } +} + +func (m Mapping) IterateKeys(ctx Context, fn func([]byte) bool) { + iter := m.store(ctx).Iterator(m.start, m.end) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + if fn(iter.Key()) { + break + } + } +} + +func (m Mapping) ReverseIterate(ctx Context, ptr interface{}, fn func([]byte) bool) { + iter := m.store(ctx).ReverseIterator(m.start, m.end) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + setnil(ptr) + + v := iter.Value() + + m.base.cdc.MustUnmarshalBinaryBare(v, ptr) + + if fn(iter.Key()) { + break + } + } +} + +func (m Mapping) ReverseIterateKeys(ctx Context, fn func([]byte) bool) { + iter := m.store(ctx).ReverseIterator(m.start, m.end) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + if fn(iter.Key()) { + break + } + } +} +func (m Mapping) First(ctx Context, ptr interface{}) (key []byte, ok bool) { + kvp, ok := store.First(m.store(ctx), m.start, m.end) + if !ok { + return + } + key = kvp.Key + if ptr != nil { + m.base.cdc.MustUnmarshalBinaryBare(kvp.Value, ptr) + } + return +} + +func (m Mapping) Last(ctx Context, ptr interface{}) (key []byte, ok bool) { + kvp, ok := store.Last(m.store(ctx), m.start, m.end) + if !ok { + return + } + key = kvp.Key + if ptr != nil { + m.base.cdc.MustUnmarshalBinaryBare(kvp.Value, ptr) + } + return +} + +func (m Mapping) Clear(ctx Context) { + var keys [][]byte + + iter := m.store(ctx).ReverseIterator(m.start, m.end) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + keys = append(keys, iter.Key()) + } + + store := m.store(ctx) + for _, key := range keys { + store.Delete(key) + } +} + +/* +func (m Mapping) Key(key []byte) []byte { + return m.Value(key).Key() +} +*/ diff --git a/store/mapping/queue.go b/store/mapping/queue.go new file mode 100644 index 000000000000..ccdbde77b2c6 --- /dev/null +++ b/store/mapping/queue.go @@ -0,0 +1,43 @@ +package mapping + +type Queue struct { + Indexer +} + +func NewQueue(base Base, prefix []byte, enc IntEncoding) Queue { + return Queue{ + Indexer: NewIndexer(base, prefix, enc), + } +} + +func (q Queue) Prefix(prefix []byte) Queue { + return Queue{ + Indexer: q.Indexer.Prefix(prefix), + } +} + +func (q Queue) Peek(ctx Context, ptr interface{}) (ok bool) { + _, ok = q.First(ctx, ptr) + return +} + +func (q Queue) Pop(ctx Context, ptr interface{}) (ok bool) { + key, ok := q.First(ctx, ptr) + if !ok { + return + } + + q.Delete(ctx, key) + return +} + +func (q Queue) Push(ctx Context, o interface{}) { + key, ok := q.Last(ctx, nil) + if !ok { + key = 0 + } else { + key = key + 1 + } + + q.Set(ctx, key, o) +} diff --git a/store/mapping/sorted.go b/store/mapping/sorted.go new file mode 100644 index 000000000000..b78811f710cc --- /dev/null +++ b/store/mapping/sorted.go @@ -0,0 +1,66 @@ +package mapping + +type Sorted struct { + m Mapping + + enc IntEncoding +} + +func NewSorted(base Base, prefix []byte, enc IntEncoding) Sorted { + return Sorted{ + m: NewMapping(base, prefix), + + enc: enc, + } +} + +func (s Sorted) key(power uint64, key []byte) []byte { + return append(EncodeInt(power, s.enc), key...) +} + +func (s Sorted) Value(power uint64, key []byte) Value { + return s.m.Value(s.key(power, key)) +} + +func (s Sorted) Get(ctx Context, power uint64, key []byte, ptr interface{}) { + s.Value(power, key).Get(ctx, ptr) +} + +func (s Sorted) GetIfExists(ctx Context, power uint64, key []byte, ptr interface{}) { + s.Value(power, key).GetIfExists(ctx, ptr) +} + +func (s Sorted) Set(ctx Context, power uint64, key []byte, o interface{}) { + s.Value(power, key).Set(ctx, o) +} + +func (s Sorted) Has(ctx Context, power uint64, key []byte) bool { + return s.Value(power, key).Exists(ctx) +} + +func (s Sorted) Delete(ctx Context, power uint64, key []byte) { + s.Value(power, key).Delete(ctx) +} + +func (s Sorted) IsEmpty(ctx Context) bool { + return s.m.IsEmpty(ctx) +} + +func (s Sorted) Prefix(prefix []byte) Sorted { + return Sorted{ + m: s.m.Prefix(prefix), + enc: s.enc, + } +} + +func (s Sorted) IterateAscending(ctx Context, ptr interface{}, fn func([]byte) bool) { + s.m.Iterate(ctx, ptr, fn) +} + +func (s Sorted) IterateDescending(ctx Context, ptr interface{}, fn func([]byte) bool) { + s.m.ReverseIterate(ctx, ptr, fn) +} + +func (s Sorted) Clear(ctx Context) { + s.m.Clear(ctx) +} diff --git a/store/mapping/test_common.go b/store/mapping/test_common.go new file mode 100644 index 000000000000..250410f88ced --- /dev/null +++ b/store/mapping/test_common.go @@ -0,0 +1,55 @@ +package mapping + +import ( + // "testing" + "math/rand" + + // "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const testsize = 10 + +type test interface { + test() +} + +type teststruct struct { + I uint64 + B bool + SL []byte +} + +var _ test = teststruct{} + +func (teststruct) test() {} + +func newtest() test { + var res teststruct + res.I = rand.Uint64() + res.B = rand.Int()%2 == 0 + res.SL = make([]byte, 20) + rand.Read(res.SL) + return res +} + +func defaultComponents() (sdk.StoreKey, Context, *codec.Codec) { + key := sdk.NewKVStoreKey("test") + db := dbm.NewMemDB() + cms := store.NewCommitMultiStore(db) + cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) + cms.LoadLatestVersion() + ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) + cdc := codec.New() + cdc.RegisterInterface((*test)(nil), nil) + cdc.RegisterConcrete(teststruct{}, "test/struct", nil) + cdc.Seal() + return key, ctx, cdc +} diff --git a/store/mapping/types.go b/store/mapping/types.go new file mode 100644 index 000000000000..74ca2a9168b0 --- /dev/null +++ b/store/mapping/types.go @@ -0,0 +1,14 @@ +package mapping + +import ( + "github.com/tendermint/tendermint/crypto/merkle" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type KVStore = sdk.KVStore +type Context = sdk.Context + +type KeyPath = merkle.KeyPath + +const KeyEncodingHex = merkle.KeyEncodingHex diff --git a/store/mapping/value.go b/store/mapping/value.go new file mode 100644 index 000000000000..f9325f83ec93 --- /dev/null +++ b/store/mapping/value.go @@ -0,0 +1,156 @@ +package mapping + +import ( + "bytes" + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" +) + +// TODO: expose +type coreValue interface { + // Corresponds to the KVStore methods + GetRaw(Context) []byte // Get + SetRaw(Context, []byte) // Set + Exists(Context) bool // Has + Delete(Context) // Delete + Key() []byte +} + +type Value interface { + coreValue + Get(Context, interface{}) + GetIfExists(Context, interface{}) + GetSafe(Context, interface{}) error + Set(Context, interface{}) + Is(Context, interface{}) bool +} + +var _ Value = value{} + +type value struct { + base Base + key []byte +} + +func NewValue(base Base, key []byte) Value { + return value{ + base: base, + key: key, + } +} + +func (v value) store(ctx Context) KVStore { + return v.base.store(ctx) +} + +func (v value) Cdc() *codec.Codec { + return v.base.Cdc() +} + +func (v value) Get(ctx Context, ptr interface{}) { + v.base.cdc.MustUnmarshalBinaryBare(v.store(ctx).Get(v.key), ptr) +} + +func (v value) GetIfExists(ctx Context, ptr interface{}) { + bz := v.store(ctx).Get(v.key) + if bz != nil { + v.base.cdc.MustUnmarshalBinaryBare(bz, ptr) + } +} + +func (v value) GetSafe(ctx Context, ptr interface{}) error { + bz := v.store(ctx).Get(v.key) + if bz == nil { + return ErrEmptyvalue() + } + err := v.base.cdc.UnmarshalBinaryBare(bz, ptr) + if err != nil { + return ErrUnmarshal(err) + } + return nil +} + +func (v value) GetRaw(ctx Context) []byte { + return v.store(ctx).Get(v.key) +} + +func (v value) Set(ctx Context, o interface{}) { + v.store(ctx).Set(v.key, v.base.cdc.MustMarshalBinaryBare(o)) +} + +func (v value) SetRaw(ctx Context, bz []byte) { + v.store(ctx).Set(v.key, bz) +} + +func (v value) Exists(ctx Context) bool { + return v.store(ctx).Has(v.key) +} + +func (v value) Delete(ctx Context) { + v.store(ctx).Delete(v.key) +} + +func (v value) Is(ctx Context, o interface{}) bool { + return bytes.Equal(v.GetRaw(ctx), v.base.cdc.MustMarshalBinaryBare(o)) +} + +func (v value) Key() []byte { + return v.base.key(v.key) +} + +/* +func (v value) KeyPath() KeyPath { + return v.base.KeyPath().AppendKey(v.key, KeyEncodingHex) +} +*/ +type GetSafeErrorType byte + +const ( + ErrTypeEmptyvalue GetSafeErrorType = iota + ErrTypeUnmarshal +) + +func (ty GetSafeErrorType) Format(msg string) (res string) { + switch ty { + case ErrTypeEmptyvalue: + res = fmt.Sprintf("Empty value found") + case ErrTypeUnmarshal: + res = fmt.Sprintf("Error while unmarshal") + default: + panic("Unknown error type") + } + + if msg != "" { + res = fmt.Sprintf("%s: %s", res, msg) + } + + return +} + +type GetSafeError struct { + ty GetSafeErrorType + inner error +} + +var _ error = (*GetSafeError)(nil) // TODO: sdk.Error + +func (err *GetSafeError) Error() string { + if err.inner == nil { + return err.ty.Format("") + } + return err.ty.Format(err.inner.Error()) +} + +func ErrEmptyvalue() *GetSafeError { + return &GetSafeError{ + ty: ErrTypeEmptyvalue, + } +} + +func ErrUnmarshal(err error) *GetSafeError { + return &GetSafeError{ + ty: ErrTypeUnmarshal, + inner: err, + } +} diff --git a/store/mapping/value_test.go b/store/mapping/value_test.go new file mode 100644 index 000000000000..f92ce7327587 --- /dev/null +++ b/store/mapping/value_test.go @@ -0,0 +1,32 @@ +package mapping + +import ( + "math/rand" + "testing" + + "github.com/stretchr/testify/require" +) + +type valuepair struct { + key []byte + value test +} + +func TestValue(t *testing.T) { + key, ctx, cdc := defaultComponents() + base := NewBase(cdc, key) + + cases := make([]valuepair, testsize) + for i := range cases { + cases[i].key = make([]byte, 20) + rand.Read(cases[i].key) + cases[i].value = newtest() + NewValue(base, cases[i].key).Set(ctx, cases[i].value) + } + + for i := range cases { + var val test + NewValue(base, cases[i].key).Get(ctx, &val) + require.Equal(t, cases[i].value, val) + } +} From 16eea6808057c8f24ac5f42fff986108d2e92921 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 19:22:15 +0200 Subject: [PATCH 002/378] rm unused mapping/*, rm interfaces --- store/mapping/boolean.go | 1 - store/mapping/enum.go | 38 ++++++++--------------- store/mapping/integer.go | 36 ++++++++-------------- store/mapping/queue.go | 43 -------------------------- store/mapping/sorted.go | 66 ---------------------------------------- store/mapping/value.go | 63 +++++++++++++------------------------- 6 files changed, 46 insertions(+), 201 deletions(-) delete mode 100644 store/mapping/queue.go delete mode 100644 store/mapping/sorted.go diff --git a/store/mapping/boolean.go b/store/mapping/boolean.go index 0c78707bf6fa..158639a0eab5 100644 --- a/store/mapping/boolean.go +++ b/store/mapping/boolean.go @@ -1,6 +1,5 @@ package mapping -// XXX: interface type Boolean struct { Enum } diff --git a/store/mapping/enum.go b/store/mapping/enum.go index dffc2b8fc6e4..b7aa90332c2d 100644 --- a/store/mapping/enum.go +++ b/store/mapping/enum.go @@ -1,35 +1,23 @@ package mapping -type Enum interface { - coreValue - Get(Context) byte - GetIfExists(Context) byte - GetSafe(Context) (byte, error) - Set(Context, byte) - Transit(Context, byte, byte) bool - Is(Context, byte) bool -} - -var _ Enum = enum{} - -type enum struct { +type Enum struct { Value } -func NewEnum(v Value) enum { - return enum{v} +func NewEnum(v Value) Enum { + return Enum{v} } /* -func (v Value) enum() enum { - return enum{v} +func (v Value) Enum() Enum { + return Enum{v} } */ -func (v enum) Get(ctx Context) byte { +func (v Enum) Get(ctx Context) byte { return v.Value.GetRaw(ctx)[0] } -func (v enum) GetIfExists(ctx Context) byte { +func (v Enum) GetIfExists(ctx Context) byte { res := v.Value.GetRaw(ctx) if res != nil { return res[0] @@ -37,7 +25,7 @@ func (v enum) GetIfExists(ctx Context) byte { return 0x00 } -func (v enum) GetSafe(ctx Context) (byte, error) { +func (v Enum) GetSafe(ctx Context) (byte, error) { res := v.Value.GetRaw(ctx) if res == nil { return 0x00, &GetSafeError{} @@ -45,17 +33,17 @@ func (v enum) GetSafe(ctx Context) (byte, error) { return res[0], nil } -func (v enum) Set(ctx Context, value byte) { +func (v Enum) Set(ctx Context, value byte) { v.Value.SetRaw(ctx, []byte{value}) } -func (v enum) Incr(ctx Context) (res byte) { +func (v Enum) Incr(ctx Context) (res byte) { res = v.GetIfExists(ctx) + 1 v.Set(ctx, res) return } -func (v enum) Transit(ctx Context, from, to byte) bool { +func (v Enum) Transit(ctx Context, from, to byte) bool { if v.GetIfExists(ctx) != from { return false } @@ -63,12 +51,12 @@ func (v enum) Transit(ctx Context, from, to byte) bool { return true } -func (v enum) Is(ctx Context, value byte) bool { +func (v Enum) Is(ctx Context, value byte) bool { return v.Get(ctx) == value } /* -func (v enum) Key() []byte { +func (v Enum) Key() []byte { return v.base.key(v.key) } */ diff --git a/store/mapping/integer.go b/store/mapping/integer.go index 45b484f67a16..159332e624b2 100644 --- a/store/mapping/integer.go +++ b/store/mapping/integer.go @@ -1,36 +1,24 @@ package mapping -type Integer interface { - coreValue - Get(Context) uint64 - GetIfExists(Context) uint64 - GetSafe(Context) (uint64, error) - Set(Context, uint64) - Incr(Context) uint64 - Is(Context, uint64) bool -} - -var _ Integer = integer{} - -type integer struct { +type Integer struct { Value enc IntEncoding } -func NewInteger(v Value, enc IntEncoding) integer { - return integer{ +func NewInteger(v Value, enc IntEncoding) Integer { + return Integer{ Value: v, enc: enc, } } /* -func (v Value) integer() integer { - return integer{v} +func (v Value) Integer() Integer { + return Integer{v} } */ -func (v integer) Get(ctx Context) uint64 { +func (v Integer) Get(ctx Context) uint64 { res, err := DecodeInt(v.GetRaw(ctx), v.enc) if err != nil { panic(err) @@ -38,7 +26,7 @@ func (v integer) Get(ctx Context) uint64 { return res } -func (v integer) GetIfExists(ctx Context) (res uint64) { +func (v Integer) GetIfExists(ctx Context) (res uint64) { bz := v.GetRaw(ctx) if bz == nil { return 0 @@ -50,7 +38,7 @@ func (v integer) GetIfExists(ctx Context) (res uint64) { return res } -func (v integer) GetSafe(ctx Context) (uint64, error) { +func (v Integer) GetSafe(ctx Context) (uint64, error) { bz := v.GetRaw(ctx) if bz == nil { return 0, &GetSafeError{} @@ -62,22 +50,22 @@ func (v integer) GetSafe(ctx Context) (uint64, error) { return res, nil } -func (v integer) Set(ctx Context, value uint64) { +func (v Integer) Set(ctx Context, value uint64) { v.SetRaw(ctx, EncodeInt(value, v.enc)) } -func (v integer) Incr(ctx Context) (res uint64) { +func (v Integer) Incr(ctx Context) (res uint64) { res = v.GetIfExists(ctx) + 1 v.Set(ctx, res) return } -func (v integer) Is(ctx Context, value uint64) bool { +func (v Integer) Is(ctx Context, value uint64) bool { return v.Get(ctx) == value } /* -func (v integer) Key() []byte { +func (v Integer) Key() []byte { return v.base.key(v.key) } */ diff --git a/store/mapping/queue.go b/store/mapping/queue.go deleted file mode 100644 index ccdbde77b2c6..000000000000 --- a/store/mapping/queue.go +++ /dev/null @@ -1,43 +0,0 @@ -package mapping - -type Queue struct { - Indexer -} - -func NewQueue(base Base, prefix []byte, enc IntEncoding) Queue { - return Queue{ - Indexer: NewIndexer(base, prefix, enc), - } -} - -func (q Queue) Prefix(prefix []byte) Queue { - return Queue{ - Indexer: q.Indexer.Prefix(prefix), - } -} - -func (q Queue) Peek(ctx Context, ptr interface{}) (ok bool) { - _, ok = q.First(ctx, ptr) - return -} - -func (q Queue) Pop(ctx Context, ptr interface{}) (ok bool) { - key, ok := q.First(ctx, ptr) - if !ok { - return - } - - q.Delete(ctx, key) - return -} - -func (q Queue) Push(ctx Context, o interface{}) { - key, ok := q.Last(ctx, nil) - if !ok { - key = 0 - } else { - key = key + 1 - } - - q.Set(ctx, key, o) -} diff --git a/store/mapping/sorted.go b/store/mapping/sorted.go deleted file mode 100644 index b78811f710cc..000000000000 --- a/store/mapping/sorted.go +++ /dev/null @@ -1,66 +0,0 @@ -package mapping - -type Sorted struct { - m Mapping - - enc IntEncoding -} - -func NewSorted(base Base, prefix []byte, enc IntEncoding) Sorted { - return Sorted{ - m: NewMapping(base, prefix), - - enc: enc, - } -} - -func (s Sorted) key(power uint64, key []byte) []byte { - return append(EncodeInt(power, s.enc), key...) -} - -func (s Sorted) Value(power uint64, key []byte) Value { - return s.m.Value(s.key(power, key)) -} - -func (s Sorted) Get(ctx Context, power uint64, key []byte, ptr interface{}) { - s.Value(power, key).Get(ctx, ptr) -} - -func (s Sorted) GetIfExists(ctx Context, power uint64, key []byte, ptr interface{}) { - s.Value(power, key).GetIfExists(ctx, ptr) -} - -func (s Sorted) Set(ctx Context, power uint64, key []byte, o interface{}) { - s.Value(power, key).Set(ctx, o) -} - -func (s Sorted) Has(ctx Context, power uint64, key []byte) bool { - return s.Value(power, key).Exists(ctx) -} - -func (s Sorted) Delete(ctx Context, power uint64, key []byte) { - s.Value(power, key).Delete(ctx) -} - -func (s Sorted) IsEmpty(ctx Context) bool { - return s.m.IsEmpty(ctx) -} - -func (s Sorted) Prefix(prefix []byte) Sorted { - return Sorted{ - m: s.m.Prefix(prefix), - enc: s.enc, - } -} - -func (s Sorted) IterateAscending(ctx Context, ptr interface{}, fn func([]byte) bool) { - s.m.Iterate(ctx, ptr, fn) -} - -func (s Sorted) IterateDescending(ctx Context, ptr interface{}, fn func([]byte) bool) { - s.m.ReverseIterate(ctx, ptr, fn) -} - -func (s Sorted) Clear(ctx Context) { - s.m.Clear(ctx) -} diff --git a/store/mapping/value.go b/store/mapping/value.go index f9325f83ec93..0be43cc2932f 100644 --- a/store/mapping/value.go +++ b/store/mapping/value.go @@ -7,62 +7,41 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -// TODO: expose -type coreValue interface { - // Corresponds to the KVStore methods - GetRaw(Context) []byte // Get - SetRaw(Context, []byte) // Set - Exists(Context) bool // Has - Delete(Context) // Delete - Key() []byte -} - -type Value interface { - coreValue - Get(Context, interface{}) - GetIfExists(Context, interface{}) - GetSafe(Context, interface{}) error - Set(Context, interface{}) - Is(Context, interface{}) bool -} - -var _ Value = value{} - -type value struct { +type Value struct { base Base key []byte } func NewValue(base Base, key []byte) Value { - return value{ + return Value{ base: base, key: key, } } -func (v value) store(ctx Context) KVStore { +func (v Value) store(ctx Context) KVStore { return v.base.store(ctx) } -func (v value) Cdc() *codec.Codec { +func (v Value) Cdc() *codec.Codec { return v.base.Cdc() } -func (v value) Get(ctx Context, ptr interface{}) { +func (v Value) Get(ctx Context, ptr interface{}) { v.base.cdc.MustUnmarshalBinaryBare(v.store(ctx).Get(v.key), ptr) } -func (v value) GetIfExists(ctx Context, ptr interface{}) { +func (v Value) GetIfExists(ctx Context, ptr interface{}) { bz := v.store(ctx).Get(v.key) if bz != nil { v.base.cdc.MustUnmarshalBinaryBare(bz, ptr) } } -func (v value) GetSafe(ctx Context, ptr interface{}) error { +func (v Value) GetSafe(ctx Context, ptr interface{}) error { bz := v.store(ctx).Get(v.key) if bz == nil { - return ErrEmptyvalue() + return ErrEmptyValue() } err := v.base.cdc.UnmarshalBinaryBare(bz, ptr) if err != nil { @@ -71,50 +50,50 @@ func (v value) GetSafe(ctx Context, ptr interface{}) error { return nil } -func (v value) GetRaw(ctx Context) []byte { +func (v Value) GetRaw(ctx Context) []byte { return v.store(ctx).Get(v.key) } -func (v value) Set(ctx Context, o interface{}) { +func (v Value) Set(ctx Context, o interface{}) { v.store(ctx).Set(v.key, v.base.cdc.MustMarshalBinaryBare(o)) } -func (v value) SetRaw(ctx Context, bz []byte) { +func (v Value) SetRaw(ctx Context, bz []byte) { v.store(ctx).Set(v.key, bz) } -func (v value) Exists(ctx Context) bool { +func (v Value) Exists(ctx Context) bool { return v.store(ctx).Has(v.key) } -func (v value) Delete(ctx Context) { +func (v Value) Delete(ctx Context) { v.store(ctx).Delete(v.key) } -func (v value) Is(ctx Context, o interface{}) bool { +func (v Value) Is(ctx Context, o interface{}) bool { return bytes.Equal(v.GetRaw(ctx), v.base.cdc.MustMarshalBinaryBare(o)) } -func (v value) Key() []byte { +func (v Value) Key() []byte { return v.base.key(v.key) } /* -func (v value) KeyPath() KeyPath { +func (v Value) KeyPath() KeyPath { return v.base.KeyPath().AppendKey(v.key, KeyEncodingHex) } */ type GetSafeErrorType byte const ( - ErrTypeEmptyvalue GetSafeErrorType = iota + ErrTypeEmptyValue GetSafeErrorType = iota ErrTypeUnmarshal ) func (ty GetSafeErrorType) Format(msg string) (res string) { switch ty { - case ErrTypeEmptyvalue: - res = fmt.Sprintf("Empty value found") + case ErrTypeEmptyValue: + res = fmt.Sprintf("Empty Value found") case ErrTypeUnmarshal: res = fmt.Sprintf("Error while unmarshal") default: @@ -142,9 +121,9 @@ func (err *GetSafeError) Error() string { return err.ty.Format(err.inner.Error()) } -func ErrEmptyvalue() *GetSafeError { +func ErrEmptyValue() *GetSafeError { return &GetSafeError{ - ty: ErrTypeEmptyvalue, + ty: ErrTypeEmptyValue, } } From f73215e989e246483b301623477f0a9c141f18b5 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 12 Jun 2019 00:14:34 +0200 Subject: [PATCH 003/378] rm unused code --- store/mapping/base.go | 53 +++------------- store/mapping/boolean.go | 12 ---- store/mapping/enum.go | 15 ----- store/mapping/indexer.go | 62 ------------------- store/mapping/integer.go | 15 ----- store/mapping/mapping.go | 129 +-------------------------------------- store/mapping/types.go | 6 -- store/mapping/value.go | 14 ----- 8 files changed, 9 insertions(+), 297 deletions(-) diff --git a/store/mapping/base.go b/store/mapping/base.go index 4d9da596ec9e..4fb049d3240e 100644 --- a/store/mapping/base.go +++ b/store/mapping/base.go @@ -8,25 +8,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -/* -type keypath struct { - keypath merkle.KeyPath - prefix []byte -} - -func (path keypath) _prefix(prefix []byte) (res keypath) { - res.keypath = path.keypath - res.prefix = make([]byte, len(path.prefix)+len(prefix)) - copy(res.prefix[:len(path.prefix)], path.prefix) - copy(res.prefix[len(path.prefix):], prefix) - return -} -*/ type Base struct { cdc *codec.Codec storefn func(Context) KVStore prefix []byte - // keypath keypath // temporal } func EmptyBase() Base { @@ -37,18 +22,6 @@ func NewBase(cdc *codec.Codec, key sdk.StoreKey) Base { return Base{ cdc: cdc, storefn: func(ctx Context) KVStore { return ctx.KVStore(key) }, - /* - keypath: keypath{ - keypath: new(KeyPath).AppendKey([]byte(key.Name()), merkle.KeyEncodingHex), - }, - */ - } -} - -func NewBaseWithGetter(cdc *codec.Codec, storefn func(Context) KVStore) Base { - return Base{ - cdc: cdc, - storefn: storefn, } } @@ -56,13 +29,19 @@ func (base Base) store(ctx Context) KVStore { return prefix.NewStore(base.storefn(ctx), base.prefix) } +func join(a, b []byte) (res []byte) { + res = make([]byte, len(a)+len(b)) + copy(res, a) + copy(res[len(a):], b) + return +} + func (base Base) Prefix(prefix []byte) (res Base) { res = Base{ cdc: base.cdc, storefn: base.storefn, - //keypath: base.keypath._prefix(prefix), + prefix: join(base.prefix, prefix), } - res.prefix = join(base.prefix, prefix) return } @@ -73,19 +52,3 @@ func (base Base) Cdc() *codec.Codec { func (base Base) key(key []byte) []byte { return join(base.prefix, key) } - -func join(a, b []byte) (res []byte) { - res = make([]byte, len(a)+len(b)) - copy(res, a) - copy(res[len(a):], b) - return -} - -/* -func (base Base) KeyPath() merkle.KeyPath { - if len(base.keypath.prefix) != 0 { - return base.keypath.keypath.AppendKey(base.keypath.prefix, merkle.KeyEncodingHex) - } - return base.keypath.keypath -} -*/ diff --git a/store/mapping/boolean.go b/store/mapping/boolean.go index 158639a0eab5..aa6ae0d39c99 100644 --- a/store/mapping/boolean.go +++ b/store/mapping/boolean.go @@ -28,15 +28,3 @@ func (v Boolean) Set(ctx Context, value bool) { v.Enum.Set(ctx, 0x00) } } - -func (v Boolean) Flip(ctx Context) (res bool) { - res = !v.GetIfExists(ctx) - v.Set(ctx, res) - return -} - -/* -func (v Boolean) Key() []byte { - return v.base.key(v.key) -} -*/ diff --git a/store/mapping/enum.go b/store/mapping/enum.go index b7aa90332c2d..85f973fef144 100644 --- a/store/mapping/enum.go +++ b/store/mapping/enum.go @@ -8,11 +8,6 @@ func NewEnum(v Value) Enum { return Enum{v} } -/* -func (v Value) Enum() Enum { - return Enum{v} -} -*/ func (v Enum) Get(ctx Context) byte { return v.Value.GetRaw(ctx)[0] } @@ -50,13 +45,3 @@ func (v Enum) Transit(ctx Context, from, to byte) bool { v.Set(ctx, to) return true } - -func (v Enum) Is(ctx Context, value byte) bool { - return v.Get(ctx) == value -} - -/* -func (v Enum) Key() []byte { - return v.base.key(v.key) -} -*/ diff --git a/store/mapping/indexer.go b/store/mapping/indexer.go index 5d2cf5f7371f..28603fc907c2 100644 --- a/store/mapping/indexer.go +++ b/store/mapping/indexer.go @@ -95,65 +95,3 @@ func (ix Indexer) Prefix(prefix []byte) Indexer { enc: ix.enc, } } - -func (ix Indexer) Range(start, end uint64) Indexer { - return Indexer{ - m: ix.m.Range(EncodeInt(start, ix.enc), EncodeInt(end, ix.enc)), - - enc: ix.enc, - } -} - -func (ix Indexer) IterateAscending(ctx Context, ptr interface{}, fn func(uint64) bool) { - ix.m.Iterate(ctx, ptr, func(bz []byte) bool { - key, err := DecodeInt(bz, ix.enc) - if err != nil { - panic(err) - } - return fn(key) - }) -} - -func (ix Indexer) IterateDescending(ctx Context, ptr interface{}, fn func(uint64) bool) { - ix.m.ReverseIterate(ctx, ptr, func(bz []byte) bool { - key, err := DecodeInt(bz, ix.enc) - if err != nil { - panic(err) - } - return fn(key) - }) -} - -func (ix Indexer) First(ctx Context, ptr interface{}) (key uint64, ok bool) { - keybz, ok := ix.m.First(ctx, ptr) - if !ok { - return - } - if len(keybz) != 0 { - key, err := DecodeInt(keybz, ix.enc) - if err != nil { - return key, false - } - } - return -} - -func (ix Indexer) Last(ctx Context, ptr interface{}) (key uint64, ok bool) { - keybz, ok := ix.m.Last(ctx, ptr) - if !ok { - return - } - if len(keybz) != 0 { - key, err := DecodeInt(keybz, ix.enc) - if err != nil { - return key, false - } - } - return -} - -/* -func (ix Indexer) Key(index uint64) []byte { - return ix.m.Key(EncodeInt(index, ix.enc)) -} -*/ diff --git a/store/mapping/integer.go b/store/mapping/integer.go index 159332e624b2..9b74f7828130 100644 --- a/store/mapping/integer.go +++ b/store/mapping/integer.go @@ -13,11 +13,6 @@ func NewInteger(v Value, enc IntEncoding) Integer { } } -/* -func (v Value) Integer() Integer { - return Integer{v} -} -*/ func (v Integer) Get(ctx Context) uint64 { res, err := DecodeInt(v.GetRaw(ctx), v.enc) if err != nil { @@ -59,13 +54,3 @@ func (v Integer) Incr(ctx Context) (res uint64) { v.Set(ctx, res) return } - -func (v Integer) Is(ctx Context, value uint64) bool { - return v.Get(ctx) == value -} - -/* -func (v Integer) Key() []byte { - return v.base.key(v.key) -} -*/ diff --git a/store/mapping/mapping.go b/store/mapping/mapping.go index 62343f58e4d4..1d018ae38d9c 100644 --- a/store/mapping/mapping.go +++ b/store/mapping/mapping.go @@ -1,11 +1,5 @@ package mapping -import ( - "reflect" - - "github.com/cosmos/cosmos-sdk/store" -) - type Mapping struct { base Base start, end []byte @@ -22,18 +16,7 @@ func (m Mapping) store(ctx Context) KVStore { return m.base.store(ctx) } -/* -func (m Mapping) keyPath() (res KeyPath) { - if len(m.prefix) != 0 { - return m.base.Prefix(m.prefix).KeyPath() - } - return m.base.KeyPath() -} -*/ -func (m Mapping) Value(key []byte, constructor ...func(Base, []byte) Value) Value { - if len(constructor) == 1 { - return constructor[0](m.base, key) - } +func (m Mapping) Value(key []byte) Value { return NewValue(m.base, key) } @@ -74,113 +57,3 @@ func (m Mapping) IsEmpty(ctx Context) bool { func (m Mapping) Prefix(prefix []byte) Mapping { return NewMapping(m.base, prefix) } - -func (m Mapping) Range(start, end []byte) Mapping { - return Mapping{ - base: m.base, - start: start, - end: end, - } -} - -// go-amino does not support decoding to a non-nil interface -func setnil(ptr interface{}) { - v := reflect.ValueOf(ptr) - v.Elem().Set(reflect.Zero(v.Elem().Type())) -} - -func (m Mapping) Iterate(ctx Context, ptr interface{}, fn func([]byte) bool) { - iter := m.store(ctx).Iterator(m.start, m.end) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - setnil(ptr) - - v := iter.Value() - - m.base.cdc.MustUnmarshalBinaryBare(v, ptr) - - if fn(iter.Key()) { - break - } - } -} - -func (m Mapping) IterateKeys(ctx Context, fn func([]byte) bool) { - iter := m.store(ctx).Iterator(m.start, m.end) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - if fn(iter.Key()) { - break - } - } -} - -func (m Mapping) ReverseIterate(ctx Context, ptr interface{}, fn func([]byte) bool) { - iter := m.store(ctx).ReverseIterator(m.start, m.end) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - setnil(ptr) - - v := iter.Value() - - m.base.cdc.MustUnmarshalBinaryBare(v, ptr) - - if fn(iter.Key()) { - break - } - } -} - -func (m Mapping) ReverseIterateKeys(ctx Context, fn func([]byte) bool) { - iter := m.store(ctx).ReverseIterator(m.start, m.end) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - if fn(iter.Key()) { - break - } - } -} -func (m Mapping) First(ctx Context, ptr interface{}) (key []byte, ok bool) { - kvp, ok := store.First(m.store(ctx), m.start, m.end) - if !ok { - return - } - key = kvp.Key - if ptr != nil { - m.base.cdc.MustUnmarshalBinaryBare(kvp.Value, ptr) - } - return -} - -func (m Mapping) Last(ctx Context, ptr interface{}) (key []byte, ok bool) { - kvp, ok := store.Last(m.store(ctx), m.start, m.end) - if !ok { - return - } - key = kvp.Key - if ptr != nil { - m.base.cdc.MustUnmarshalBinaryBare(kvp.Value, ptr) - } - return -} - -func (m Mapping) Clear(ctx Context) { - var keys [][]byte - - iter := m.store(ctx).ReverseIterator(m.start, m.end) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - keys = append(keys, iter.Key()) - } - - store := m.store(ctx) - for _, key := range keys { - store.Delete(key) - } -} - -/* -func (m Mapping) Key(key []byte) []byte { - return m.Value(key).Key() -} -*/ diff --git a/store/mapping/types.go b/store/mapping/types.go index 74ca2a9168b0..2454084324ec 100644 --- a/store/mapping/types.go +++ b/store/mapping/types.go @@ -1,14 +1,8 @@ package mapping import ( - "github.com/tendermint/tendermint/crypto/merkle" - sdk "github.com/cosmos/cosmos-sdk/types" ) type KVStore = sdk.KVStore type Context = sdk.Context - -type KeyPath = merkle.KeyPath - -const KeyEncodingHex = merkle.KeyEncodingHex diff --git a/store/mapping/value.go b/store/mapping/value.go index 0be43cc2932f..c61a64049c56 100644 --- a/store/mapping/value.go +++ b/store/mapping/value.go @@ -1,7 +1,6 @@ package mapping import ( - "bytes" "fmt" "github.com/cosmos/cosmos-sdk/codec" @@ -70,19 +69,6 @@ func (v Value) Delete(ctx Context) { v.store(ctx).Delete(v.key) } -func (v Value) Is(ctx Context, o interface{}) bool { - return bytes.Equal(v.GetRaw(ctx), v.base.cdc.MustMarshalBinaryBare(o)) -} - -func (v Value) Key() []byte { - return v.base.key(v.key) -} - -/* -func (v Value) KeyPath() KeyPath { - return v.base.KeyPath().AppendKey(v.key, KeyEncodingHex) -} -*/ type GetSafeErrorType byte const ( From cf0b8f29c3a9c4070ea79cd21ff3fca54522ebaa Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 12 Jun 2019 00:23:53 +0200 Subject: [PATCH 004/378] mv mapping -> state, rm x/ibc --- store/{mapping => state}/base.go | 2 +- store/{mapping => state}/boolean.go | 2 +- store/{mapping => state}/enum.go | 2 +- store/{mapping => state}/indexer.go | 2 +- store/{mapping => state}/integer.go | 2 +- store/{mapping => state}/mapping.go | 2 +- store/{mapping => state}/test_common.go | 7 +- store/{mapping => state}/types.go | 2 +- store/{mapping => state}/value.go | 2 +- store/{mapping => state}/value_test.go | 2 +- x/ibc/app_test.go | 88 ---------- x/ibc/client/cli/README.md | 157 ------------------ x/ibc/client/cli/ibctx.go | 73 -------- x/ibc/client/cli/relay.go | 210 ------------------------ x/ibc/client/rest/transfer.go | 62 ------- x/ibc/codec.go | 11 -- x/ibc/errors.go | 50 ------ x/ibc/expected_keepers.go | 9 - x/ibc/handler.go | 60 ------- x/ibc/handler_test.go | 19 --- x/ibc/ibc_test.go | 160 ------------------ x/ibc/mapper.go | 130 --------------- x/ibc/types.go | 125 -------------- x/ibc/types_test.go | 111 ------------- 24 files changed, 14 insertions(+), 1276 deletions(-) rename store/{mapping => state}/base.go (98%) rename store/{mapping => state}/boolean.go (96%) rename store/{mapping => state}/enum.go (97%) rename store/{mapping => state}/indexer.go (99%) rename store/{mapping => state}/integer.go (98%) rename store/{mapping => state}/mapping.go (98%) rename store/{mapping => state}/test_common.go (93%) rename store/{mapping => state}/types.go (87%) rename store/{mapping => state}/value.go (99%) rename store/{mapping => state}/value_test.go (97%) delete mode 100644 x/ibc/app_test.go delete mode 100644 x/ibc/client/cli/README.md delete mode 100644 x/ibc/client/cli/ibctx.go delete mode 100644 x/ibc/client/cli/relay.go delete mode 100644 x/ibc/client/rest/transfer.go delete mode 100644 x/ibc/codec.go delete mode 100644 x/ibc/errors.go delete mode 100644 x/ibc/expected_keepers.go delete mode 100644 x/ibc/handler.go delete mode 100644 x/ibc/handler_test.go delete mode 100644 x/ibc/ibc_test.go delete mode 100644 x/ibc/mapper.go delete mode 100644 x/ibc/types.go delete mode 100644 x/ibc/types_test.go diff --git a/store/mapping/base.go b/store/state/base.go similarity index 98% rename from store/mapping/base.go rename to store/state/base.go index 4fb049d3240e..25760b77a947 100644 --- a/store/mapping/base.go +++ b/store/state/base.go @@ -1,4 +1,4 @@ -package mapping +package state import ( // "github.com/tendermint/tendermint/crypto/merkle" diff --git a/store/mapping/boolean.go b/store/state/boolean.go similarity index 96% rename from store/mapping/boolean.go rename to store/state/boolean.go index aa6ae0d39c99..c691ceaf9a00 100644 --- a/store/mapping/boolean.go +++ b/store/state/boolean.go @@ -1,4 +1,4 @@ -package mapping +package state type Boolean struct { Enum diff --git a/store/mapping/enum.go b/store/state/enum.go similarity index 97% rename from store/mapping/enum.go rename to store/state/enum.go index 85f973fef144..a44f820a6e5d 100644 --- a/store/mapping/enum.go +++ b/store/state/enum.go @@ -1,4 +1,4 @@ -package mapping +package state type Enum struct { Value diff --git a/store/mapping/indexer.go b/store/state/indexer.go similarity index 99% rename from store/mapping/indexer.go rename to store/state/indexer.go index 28603fc907c2..212be3d0f603 100644 --- a/store/mapping/indexer.go +++ b/store/state/indexer.go @@ -1,4 +1,4 @@ -package mapping +package state import ( "encoding/binary" diff --git a/store/mapping/integer.go b/store/state/integer.go similarity index 98% rename from store/mapping/integer.go rename to store/state/integer.go index 9b74f7828130..758656e29679 100644 --- a/store/mapping/integer.go +++ b/store/state/integer.go @@ -1,4 +1,4 @@ -package mapping +package state type Integer struct { Value diff --git a/store/mapping/mapping.go b/store/state/mapping.go similarity index 98% rename from store/mapping/mapping.go rename to store/state/mapping.go index 1d018ae38d9c..eaf0278ebf3f 100644 --- a/store/mapping/mapping.go +++ b/store/state/mapping.go @@ -1,4 +1,4 @@ -package mapping +package state type Mapping struct { base Base diff --git a/store/mapping/test_common.go b/store/state/test_common.go similarity index 93% rename from store/mapping/test_common.go rename to store/state/test_common.go index 250410f88ced..691b1f0d294b 100644 --- a/store/mapping/test_common.go +++ b/store/state/test_common.go @@ -1,4 +1,4 @@ -package mapping +package state import ( // "testing" @@ -45,7 +45,10 @@ func defaultComponents() (sdk.StoreKey, Context, *codec.Codec) { db := dbm.NewMemDB() cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) - cms.LoadLatestVersion() + err := cms.LoadLatestVersion() + if err != nil { + panic(err) + } ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) cdc := codec.New() cdc.RegisterInterface((*test)(nil), nil) diff --git a/store/mapping/types.go b/store/state/types.go similarity index 87% rename from store/mapping/types.go rename to store/state/types.go index 2454084324ec..a8d34d582a82 100644 --- a/store/mapping/types.go +++ b/store/state/types.go @@ -1,4 +1,4 @@ -package mapping +package state import ( sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/store/mapping/value.go b/store/state/value.go similarity index 99% rename from store/mapping/value.go rename to store/state/value.go index c61a64049c56..cb5d7699168c 100644 --- a/store/mapping/value.go +++ b/store/state/value.go @@ -1,4 +1,4 @@ -package mapping +package state import ( "fmt" diff --git a/store/mapping/value_test.go b/store/state/value_test.go similarity index 97% rename from store/mapping/value_test.go rename to store/state/value_test.go index f92ce7327587..24e4e708c458 100644 --- a/store/mapping/value_test.go +++ b/store/state/value_test.go @@ -1,4 +1,4 @@ -package mapping +package state import ( "math/rand" diff --git a/x/ibc/app_test.go b/x/ibc/app_test.go deleted file mode 100644 index ca51ae9d8b6f..000000000000 --- a/x/ibc/app_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package ibc - -import ( - "testing" - - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/mock" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto/secp256k1" -) - -// initialize the mock application for this module -func getMockApp(t *testing.T) *mock.App { - mapp := mock.NewApp() - - RegisterCodec(mapp.Cdc) - keyIBC := sdk.NewKVStoreKey("ibc") - ibcMapper := NewMapper(mapp.Cdc, keyIBC, DefaultCodespace) - bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, - mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), - bank.DefaultCodespace) - mapp.Router().AddRoute("ibc", NewHandler(ibcMapper, bankKeeper)) - - require.NoError(t, mapp.CompleteSetup(keyIBC)) - return mapp -} - -func TestIBCMsgs(t *testing.T) { - mapp := getMockApp(t) - - sourceChain := "source-chain" - destChain := "dest-chain" - - priv1 := secp256k1.GenPrivKey() - addr1 := sdk.AccAddress(priv1.PubKey().Address()) - coins := sdk.Coins{sdk.NewInt64Coin("foocoin", 10)} - var emptyCoins sdk.Coins - - acc := &auth.BaseAccount{ - Address: addr1, - Coins: coins, - } - accs := []auth.Account{acc} - - mock.SetGenesis(mapp, accs) - - // A checkTx context (true) - ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) - res1 := mapp.AccountKeeper.GetAccount(ctxCheck, addr1) - require.Equal(t, acc, res1) - - packet := IBCPacket{ - SrcAddr: addr1, - DestAddr: addr1, - Coins: coins, - SrcChain: sourceChain, - DestChain: destChain, - } - - transferMsg := MsgIBCTransfer{ - IBCPacket: packet, - } - - receiveMsg := MsgIBCReceive{ - IBCPacket: packet, - Relayer: addr1, - Sequence: 0, - } - - header := abci.Header{Height: mapp.LastBlockHeight() + 1} - mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{transferMsg}, []uint64{0}, []uint64{0}, true, true, priv1) - mock.CheckBalance(t, mapp, addr1, emptyCoins) - - header = abci.Header{Height: mapp.LastBlockHeight() + 1} - mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{transferMsg}, []uint64{0}, []uint64{1}, false, false, priv1) - - header = abci.Header{Height: mapp.LastBlockHeight() + 1} - mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{receiveMsg}, []uint64{0}, []uint64{2}, true, true, priv1) - mock.CheckBalance(t, mapp, addr1, coins) - - header = abci.Header{Height: mapp.LastBlockHeight() + 1} - mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{receiveMsg}, []uint64{0}, []uint64{2}, false, false, priv1) -} diff --git a/x/ibc/client/cli/README.md b/x/ibc/client/cli/README.md deleted file mode 100644 index ab9e8e555840..000000000000 --- a/x/ibc/client/cli/README.md +++ /dev/null @@ -1,157 +0,0 @@ -# IBC Doubble Hubble - -## Remove remaining data - -```console -> rm -r ~/.chain1 -> rm -r ~/.chain2 -> rm -r ~/.basecli -``` - -## Initialize both chains - -```console -> basecoind init --home ~/.chain1 -I[04-02|14:03:33.704] Generated private validator module=main path=/home/mossid/.chain1/config/priv_validator.json -I[04-02|14:03:33.705] Generated genesis file module=main path=/home/mossid/.chain1/config/genesis.json -{ - "secret": "crunch ignore trigger neither differ dance cheap brick situate floor luxury citizen husband decline arrow abandon", - "account": "C69FEB398A29AAB1B3C4F07DE22208F35E711BCC", - "validator": { - "pub_key": { - "type": "ed25519", - "data": "8C9917D5E982E221F5A1450103102B44BBFC1E8768126C606246CB37B5794F4D" - }, - "power": 10, - "name": "" - }, - "node_id": "3ac8e6242315fd62143dc3e52c161edaaa6b1a64", - "chain_id": "test-chain-ZajMfr" -} -> ADDR1=C69FEB398A29AAB1B3C4F07DE22208F35E711BCC -> ID1=test-chain-ZajMfr -> NODE1=tcp://0.0.0.0:36657 -> basecli keys add key1 --recover -Enter a passphrase for your key: -Repeat the passphrase: -Enter your recovery seed phrase: -crunch ignore trigger neither differ dance cheap brick situate floor luxury citizen husband decline arrow abandon -key1 C69FEB398A29AAB1B3C4F07DE22208F35E711BCC - - -> basecoind init --home ~/.chain2 -I[04-02|14:09:14.453] Generated private validator module=main path=/home/mossid/.chain2/config/priv_validator.json -I[04-02|14:09:14.453] Generated genesis file module=main path=/home/mossid/.chain2/config/genesis.json -{ - "secret": "age guide awesome month female left oxygen soccer define high grocery work desert dinner arena abandon", - "account": "DC26002735D3AA9573707CFA6D77C12349E49868", - "validator": { - "pub_key": { - "type": "ed25519", - "data": "A94FE4B9AD763D301F4DD5A2766009812495FB7A79F1275FB8A5AF09B44FD5F3" - }, - "power": 10, - "name": "" - }, - "node_id": "ad26831330e1c72b85276d53c20f0680e6fd4cf5" - "chain_id": "test-chain-4XHTPn" -} -> ADDR2=DC26002735D3AA9573707CFA6D77C12349E49868 -> ID2=test-chain-4XHTPn -> NODE2=tcp://0.0.0.0:26657 -> basecli keys add key2 --recover -Enter a passphrase for your key: -Repeat the passphrase: -Enter your recovery seed phrase: -age guide awesome month female left oxygen soccer define high grocery work desert dinner arena abandon -key2 DC26002735D3AA9573707CFA6D77C12349E49868 - - -> basecoind start --home ~/.chain1 --address tcp://0.0.0.0:36658 --rpc.laddr tcp://0.0.0.0:36657 --p2p.laddr tcp://0.0.0.0:36656 -... - -> basecoind start --home ~/.chain2 # --address tcp://0.0.0.0:26658 --rpc.laddr tcp://0.0.0.0:26657 --p2p.laddr tcp://0.0.0.0:26656 -... -``` -## Check balance - -```console -> basecli account $ADDR1 --node $NODE1 -{ - "address": "C69FEB398A29AAB1B3C4F07DE22208F35E711BCC", - "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } - ], - "public_key": null, - "sequence": 0, - "name": "" -} - -> basecli account $ADDR2 --node $NODE2 -{ - "address": "DC26002735D3AA9573707CFA6D77C12349E49868", - "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } - ], - "public_key": null, - "sequence": 0, - "name": "" -} - -``` - -## Transfer coins (addr1:chain1 -> addr2:chain2) - -```console -> basecli transfer --from key1 --to $ADDR2 --amount 10mycoin --chain $ID2 --chain-id $ID1 --node $NODE1 -Password to sign with 'key1': -Committed at block 1022. Hash: E16019DCC4AA08CA70AFCFBC96028ABCC51B6AD0 -> basecli account $ADDR1 --node $NODE1 -{ - "address": "C69FEB398A29AAB1B3C4F07DE22208F35E711BCC", - "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740982 - } - ], - "public_key": { - "type": "ed25519", - "data": "9828FF1780A066A0D93D840737566B697035448D6C880807322BED8919348B2B" - }, - "sequence": 1, - "name": "" -} -``` - -## Relay IBC packets - -```console -> basecli relay --from key2 --from-chain-id $ID1 --from-chain-node $NODE1 --to-chain-id $ID2 --to-chain-node $NODE2 --chain-id $ID2 -Password to sign with 'key2': -I[04-03|16:18:59.984] Detected IBC packet number=0 -I[04-03|16:19:00.869] Relayed IBC packet number=0 -> basecli account $ADDR2 --node $NODE2 -{ - "address": "DC26002735D3AA9573707CFA6D77C12349E49868", - "coins": [ - { - "denom": "mycoin", - "amount": 9007199254741002 - } - ], - "public_key": { - "type": "ed25519", - "data": "F52B4FA545F4E9BFE5D7AF1DD2236899FDEF905F9B3057C38D7C01BF1B8EB52E" - }, - "sequence": 1, - "name": "" -} - -``` diff --git a/x/ibc/client/cli/ibctx.go b/x/ibc/client/cli/ibctx.go deleted file mode 100644 index 9a5ac05ee661..000000000000 --- a/x/ibc/client/cli/ibctx.go +++ /dev/null @@ -1,73 +0,0 @@ -package cli - -import ( - "encoding/hex" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/utils" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" - "github.com/cosmos/cosmos-sdk/x/ibc" - - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -const ( - flagTo = "to" - flagAmount = "amount" - flagChain = "chain" -) - -// IBCTransferCmd implements the IBC transfer command. -func IBCTransferCmd(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "transfer", - RunE: func(cmd *cobra.Command, args []string) error { - txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContext(). - WithCodec(cdc). - WithAccountDecoder(cdc) - - from := cliCtx.GetFromAddress() - msg, err := buildMsg(from) - if err != nil { - return err - } - - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } - - cmd.Flags().String(flagTo, "", "Address to send coins") - cmd.Flags().String(flagAmount, "", "Amount of coins to send") - cmd.Flags().String(flagChain, "", "Destination chain to send coins") - - return cmd -} - -func buildMsg(from sdk.AccAddress) (sdk.Msg, error) { - amount := viper.GetString(flagAmount) - coins, err := sdk.ParseCoins(amount) - if err != nil { - return nil, err - } - - dest := viper.GetString(flagTo) - bz, err := hex.DecodeString(dest) - if err != nil { - return nil, err - } - to := sdk.AccAddress(bz) - - packet := ibc.NewIBCPacket(from, to, coins, viper.GetString(client.FlagChainID), - viper.GetString(flagChain)) - - msg := ibc.MsgIBCTransfer{ - IBCPacket: packet, - } - - return msg, nil -} diff --git a/x/ibc/client/cli/relay.go b/x/ibc/client/cli/relay.go deleted file mode 100644 index c1c45611eb3f..000000000000 --- a/x/ibc/client/cli/relay.go +++ /dev/null @@ -1,210 +0,0 @@ -package cli - -import ( - "os" - "time" - - "github.com/cosmos/cosmos-sdk/client/utils" - - bam "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/keys" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" - "github.com/cosmos/cosmos-sdk/x/ibc" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/tendermint/tendermint/libs/log" -) - -// flags -const ( - FlagFromChainID = "from-chain-id" - FlagFromChainNode = "from-chain-node" - FlagToChainID = "to-chain-id" - FlagToChainNode = "to-chain-node" -) - -type relayCommander struct { - cdc *codec.Codec - address sdk.AccAddress - decoder auth.AccountDecoder - mainStore string - ibcStore string - accStore string - - logger log.Logger -} - -// IBCRelayCmd implements the IBC relay command. -func IBCRelayCmd(cdc *codec.Codec) *cobra.Command { - cmdr := relayCommander{ - cdc: cdc, - decoder: context.GetAccountDecoder(cdc), - ibcStore: "ibc", - mainStore: bam.MainStoreKey, - accStore: auth.StoreKey, - - logger: log.NewTMLogger(log.NewSyncWriter(os.Stdout)), - } - - cmd := &cobra.Command{ - Use: "relay", - Run: cmdr.runIBCRelay, - } - - cmd.Flags().String(FlagFromChainID, "", "Chain ID for ibc node to check outgoing packets") - cmd.Flags().String(FlagFromChainNode, "tcp://localhost:26657", ": to tendermint rpc interface for this chain") - cmd.Flags().String(FlagToChainID, "", "Chain ID for ibc node to broadcast incoming packets") - cmd.Flags().String(FlagToChainNode, "tcp://localhost:36657", ": to tendermint rpc interface for this chain") - - cmd.MarkFlagRequired(FlagFromChainID) - cmd.MarkFlagRequired(FlagFromChainNode) - cmd.MarkFlagRequired(FlagToChainID) - cmd.MarkFlagRequired(FlagToChainNode) - - viper.BindPFlag(FlagFromChainID, cmd.Flags().Lookup(FlagFromChainID)) - viper.BindPFlag(FlagFromChainNode, cmd.Flags().Lookup(FlagFromChainNode)) - viper.BindPFlag(FlagToChainID, cmd.Flags().Lookup(FlagToChainID)) - viper.BindPFlag(FlagToChainNode, cmd.Flags().Lookup(FlagToChainNode)) - - return cmd -} - -// nolint: unparam -func (c relayCommander) runIBCRelay(cmd *cobra.Command, args []string) { - fromChainID := viper.GetString(FlagFromChainID) - fromChainNode := viper.GetString(FlagFromChainNode) - toChainID := viper.GetString(FlagToChainID) - toChainNode := viper.GetString(FlagToChainNode) - - address := context.NewCLIContext().GetFromAddress() - c.address = address - - c.loop(fromChainID, fromChainNode, toChainID, toChainNode) -} - -// This is nolinted as someone is in the process of refactoring this to remove the goto -func (c relayCommander) loop(fromChainID, fromChainNode, toChainID, toChainNode string) { - cliCtx := context.NewCLIContext() - - name := cliCtx.GetFromName() - passphrase, err := keys.ReadPassphraseFromStdin(name) - if err != nil { - panic(err) - } - - ingressKey := ibc.IngressSequenceKey(fromChainID) - lengthKey := ibc.EgressLengthKey(toChainID) - -OUTER: - for { - time.Sleep(5 * time.Second) - - processedbz, err := query(toChainNode, ingressKey, c.ibcStore) - if err != nil { - panic(err) - } - - var processed uint64 - if processedbz == nil { - processed = 0 - } else if err = c.cdc.UnmarshalBinaryLengthPrefixed(processedbz, &processed); err != nil { - panic(err) - } - - egressLengthbz, err := query(fromChainNode, lengthKey, c.ibcStore) - if err != nil { - c.logger.Error("error querying outgoing packet list length", "err", err) - continue OUTER // TODO replace with continue (I think it should just to the correct place where OUTER is now) - } - - var egressLength uint64 - if egressLengthbz == nil { - egressLength = 0 - } else if err = c.cdc.UnmarshalBinaryLengthPrefixed(egressLengthbz, &egressLength); err != nil { - panic(err) - } - - if egressLength > processed { - c.logger.Info("Detected IBC packet", "number", egressLength-1) - } - - seq := c.getSequence(toChainNode) - - for i := processed; i < egressLength; i++ { - egressbz, err := query(fromChainNode, ibc.EgressKey(toChainID, i), c.ibcStore) - if err != nil { - c.logger.Error("error querying egress packet", "err", err) - continue OUTER // TODO replace to break, will break first loop then send back to the beginning (aka OUTER) - } - - err = c.broadcastTx(toChainNode, c.refine(egressbz, i, seq, passphrase)) - - seq++ - - if err != nil { - c.logger.Error("error broadcasting ingress packet", "err", err) - continue OUTER // TODO replace to break, will break first loop then send back to the beginning (aka OUTER) - } - - c.logger.Info("Relayed IBC packet", "number", i) - } - } -} - -func query(node string, key []byte, storeName string) (res []byte, err error) { - return context.NewCLIContext().WithNodeURI(node).QueryStore(key, storeName) -} - -// nolint: unparam -func (c relayCommander) broadcastTx(node string, tx []byte) error { - _, err := context.NewCLIContext().WithNodeURI(node).BroadcastTx(tx) - return err -} - -func (c relayCommander) getSequence(node string) uint64 { - res, err := query(node, auth.AddressStoreKey(c.address), c.accStore) - if err != nil { - panic(err) - } - - if nil != res { - account, err := c.decoder(res) - if err != nil { - panic(err) - } - - return account.GetSequence() - } - - return 0 -} - -func (c relayCommander) refine(bz []byte, ibcSeq, accSeq uint64, passphrase string) []byte { - var packet ibc.IBCPacket - if err := c.cdc.UnmarshalBinaryLengthPrefixed(bz, &packet); err != nil { - panic(err) - } - - msg := ibc.MsgIBCReceive{ - IBCPacket: packet, - Relayer: c.address, - Sequence: ibcSeq, - } - - txBldr := authtxb.NewTxBuilderFromCLI().WithSequence(accSeq).WithTxEncoder(utils.GetTxEncoder(c.cdc)) - cliCtx := context.NewCLIContext() - - name := cliCtx.GetFromName() - res, err := txBldr.BuildAndSign(name, passphrase, []sdk.Msg{msg}) - if err != nil { - panic(err) - } - - return res -} diff --git a/x/ibc/client/rest/transfer.go b/x/ibc/client/rest/transfer.go deleted file mode 100644 index ee2b4da8cdf1..000000000000 --- a/x/ibc/client/rest/transfer.go +++ /dev/null @@ -1,62 +0,0 @@ -package rest - -import ( - "net/http" - - "github.com/cosmos/cosmos-sdk/client/context" - clientrest "github.com/cosmos/cosmos-sdk/client/rest" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/ibc" - - "github.com/gorilla/mux" -) - -// RegisterRoutes - Central function to define routes that get registered by the main application -func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec, kb keys.Keybase) { - r.HandleFunc("/ibc/{destchain}/{address}/send", TransferRequestHandlerFn(cdc, kb, cliCtx)).Methods("POST") -} - -type transferReq struct { - BaseReq rest.BaseReq `json:"base_req"` - Amount sdk.Coins `json:"amount"` -} - -// TransferRequestHandler - http request handler to transfer coins to a address -// on a different chain via IBC. -func TransferRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - destChainID := vars["destchain"] - bech32Addr := vars["address"] - - to, err := sdk.AccAddressFromBech32(bech32Addr) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - - var req transferReq - if !rest.ReadRESTReq(w, r, cdc, &req) { - return - } - - req.BaseReq = req.BaseReq.Sanitize() - if !req.BaseReq.ValidateBasic(w) { - return - } - - from, err := sdk.AccAddressFromBech32(req.BaseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - - packet := ibc.NewIBCPacket(from, to, req.Amount, req.BaseReq.ChainID, destChainID) - msg := ibc.MsgIBCTransfer{IBCPacket: packet} - - clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg}) - } -} diff --git a/x/ibc/codec.go b/x/ibc/codec.go deleted file mode 100644 index d47abde1abbf..000000000000 --- a/x/ibc/codec.go +++ /dev/null @@ -1,11 +0,0 @@ -package ibc - -import ( - "github.com/cosmos/cosmos-sdk/codec" -) - -// Register concrete types on codec codec -func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(MsgIBCTransfer{}, "cosmos-sdk/MsgIBCTransfer", nil) - cdc.RegisterConcrete(MsgIBCReceive{}, "cosmos-sdk/MsgIBCReceive", nil) -} diff --git a/x/ibc/errors.go b/x/ibc/errors.go deleted file mode 100644 index 96ae58066a5c..000000000000 --- a/x/ibc/errors.go +++ /dev/null @@ -1,50 +0,0 @@ -package ibc - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// IBC errors reserve 200 ~ 299. -const ( - DefaultCodespace sdk.CodespaceType = "ibc" - - // IBC errors reserve 200 - 299. - CodeInvalidSequence sdk.CodeType = 200 - CodeIdenticalChains sdk.CodeType = 201 - CodeUnknownRequest sdk.CodeType = sdk.CodeUnknownRequest -) - -func codeToDefaultMsg(code sdk.CodeType) string { - switch code { - case CodeInvalidSequence: - return "invalid IBC packet sequence" - case CodeIdenticalChains: - return "source and destination chain cannot be identical" - default: - return sdk.CodeToDefaultMsg(code) - } -} - -// nolint -func ErrInvalidSequence(codespace sdk.CodespaceType) sdk.Error { - return newError(codespace, CodeInvalidSequence, "") -} -func ErrIdenticalChains(codespace sdk.CodespaceType) sdk.Error { - return newError(codespace, CodeIdenticalChains, "") -} - -// ------------------------- -// Helpers - -// nolint: unparam -func newError(codespace sdk.CodespaceType, code sdk.CodeType, msg string) sdk.Error { - msg = msgOrDefaultMsg(msg, code) - return sdk.NewError(codespace, code, msg) -} - -func msgOrDefaultMsg(msg string, code sdk.CodeType) string { - if msg != "" { - return msg - } - return codeToDefaultMsg(code) -} diff --git a/x/ibc/expected_keepers.go b/x/ibc/expected_keepers.go deleted file mode 100644 index 54b70b4dd8ef..000000000000 --- a/x/ibc/expected_keepers.go +++ /dev/null @@ -1,9 +0,0 @@ -package ibc - -import sdk "github.com/cosmos/cosmos-sdk/types" - -// expected bank keeper -type BankKeeper interface { - AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) - SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) -} diff --git a/x/ibc/handler.go b/x/ibc/handler.go deleted file mode 100644 index b1b958218a00..000000000000 --- a/x/ibc/handler.go +++ /dev/null @@ -1,60 +0,0 @@ -package ibc - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func NewHandler(ibcm Mapper, ck BankKeeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case MsgIBCTransfer: - return handleIBCTransferMsg(ctx, ibcm, ck, msg) - - case MsgIBCReceive: - return handleIBCReceiveMsg(ctx, ibcm, ck, msg) - - default: - errMsg := fmt.Sprintf("unrecognized IBC message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() - } - } -} - -// MsgIBCTransfer deducts coins from the account and creates an egress IBC packet. -func handleIBCTransferMsg(ctx sdk.Context, ibcm Mapper, ck BankKeeper, msg MsgIBCTransfer) sdk.Result { - packet := msg.IBCPacket - - _, err := ck.SubtractCoins(ctx, packet.SrcAddr, packet.Coins) - if err != nil { - return err.Result() - } - - err = ibcm.PostIBCPacket(ctx, packet) - if err != nil { - return err.Result() - } - - return sdk.Result{} -} - -// MsgIBCReceive adds coins to the destination address and creates an ingress IBC packet. -func handleIBCReceiveMsg(ctx sdk.Context, ibcm Mapper, ck BankKeeper, msg MsgIBCReceive) sdk.Result { - packet := msg.IBCPacket - - seq := ibcm.GetIngressSequence(ctx, packet.SrcChain) - if msg.Sequence != seq { - return ErrInvalidSequence(ibcm.codespace).Result() - } - - // XXX Check that packet.Coins is valid and positive (nonzero) - _, err := ck.AddCoins(ctx, packet.DestAddr, packet.Coins) - if err != nil { - return err.Result() - } - - ibcm.SetIngressSequence(ctx, packet.SrcChain, seq+1) - - return sdk.Result{} -} diff --git a/x/ibc/handler_test.go b/x/ibc/handler_test.go deleted file mode 100644 index fca563474737..000000000000 --- a/x/ibc/handler_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package ibc - -import ( - "strings" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/stretchr/testify/require" -) - -func TestInvalidMsg(t *testing.T) { - m := Mapper{} - h := NewHandler(m, nil) - - res := h(sdk.Context{}, sdk.NewTestMsg()) - require.False(t, res.IsOK()) - require.True(t, strings.Contains(res.Log, "unrecognized IBC message type")) -} diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go deleted file mode 100644 index 3492b723c108..000000000000 --- a/x/ibc/ibc_test.go +++ /dev/null @@ -1,160 +0,0 @@ -package ibc - -import ( - "testing" - - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto/ed25519" - dbm "github.com/tendermint/tendermint/libs/db" - "github.com/tendermint/tendermint/libs/log" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/params" -) - -// AccountKeeper(/Keeper) and IBCMapper should use different StoreKey later - -type testInput struct { - cdc *codec.Codec - ctx sdk.Context - ak auth.AccountKeeper - bk bank.BaseKeeper - ibcKey *sdk.KVStoreKey -} - -func setupTestInput() testInput { - db := dbm.NewMemDB() - cdc := makeCodec() - - ibcKey := sdk.NewKVStoreKey("ibcCapKey") - authCapKey := sdk.NewKVStoreKey("authCapKey") - fckCapKey := sdk.NewKVStoreKey("fckCapKey") - keyParams := sdk.NewKVStoreKey("params") - tkeyParams := sdk.NewTransientStoreKey("transient_params") - - ms := store.NewCommitMultiStore(db) - ms.MountStoreWithDB(ibcKey, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(authCapKey, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(fckCapKey, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db) - ms.LoadLatestVersion() - - pk := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace) - ak := auth.NewAccountKeeper( - cdc, authCapKey, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount, - ) - bk := bank.NewBaseKeeper(ak, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "test-chain-id"}, false, log.NewNopLogger()) - - ak.SetParams(ctx, auth.DefaultParams()) - - return testInput{cdc: cdc, ctx: ctx, ak: ak, bk: bk, ibcKey: ibcKey} -} - -func makeCodec() *codec.Codec { - var cdc = codec.New() - - // Register Msgs - cdc.RegisterInterface((*sdk.Msg)(nil), nil) - cdc.RegisterConcrete(bank.MsgSend{}, "test/ibc/Send", nil) - cdc.RegisterConcrete(MsgIBCTransfer{}, "test/ibc/MsgIBCTransfer", nil) - cdc.RegisterConcrete(MsgIBCReceive{}, "test/ibc/MsgIBCReceive", nil) - - // Register AppAccount - cdc.RegisterInterface((*auth.Account)(nil), nil) - cdc.RegisterConcrete(&auth.BaseAccount{}, "test/ibc/Account", nil) - codec.RegisterCrypto(cdc) - - cdc.Seal() - - return cdc -} - -func newAddress() sdk.AccAddress { - return sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) -} - -func getCoins(ck bank.Keeper, ctx sdk.Context, addr sdk.AccAddress) (sdk.Coins, sdk.Error) { - zero := sdk.Coins(nil) - coins, err := ck.AddCoins(ctx, addr, zero) - return coins, err -} - -func TestIBC(t *testing.T) { - input := setupTestInput() - ctx := input.ctx - - src := newAddress() - dest := newAddress() - chainid := "ibcchain" - zero := sdk.Coins(nil) - mycoins := sdk.Coins{sdk.NewInt64Coin("mycoin", 10)} - - coins, err := input.bk.AddCoins(ctx, src, mycoins) - require.Nil(t, err) - require.Equal(t, mycoins, coins) - - ibcm := NewMapper(input.cdc, input.ibcKey, DefaultCodespace) - h := NewHandler(ibcm, input.bk) - packet := IBCPacket{ - SrcAddr: src, - DestAddr: dest, - Coins: mycoins, - SrcChain: chainid, - DestChain: chainid, - } - - store := ctx.KVStore(input.ibcKey) - - var msg sdk.Msg - var res sdk.Result - var egl uint64 - var igs uint64 - - egl = ibcm.getEgressLength(store, chainid) - require.Equal(t, egl, uint64(0)) - - msg = MsgIBCTransfer{ - IBCPacket: packet, - } - res = h(ctx, msg) - require.True(t, res.IsOK()) - - coins, err = getCoins(input.bk, ctx, src) - require.Nil(t, err) - require.Equal(t, zero, coins) - - egl = ibcm.getEgressLength(store, chainid) - require.Equal(t, egl, uint64(1)) - - igs = ibcm.GetIngressSequence(ctx, chainid) - require.Equal(t, igs, uint64(0)) - - msg = MsgIBCReceive{ - IBCPacket: packet, - Relayer: src, - Sequence: 0, - } - res = h(ctx, msg) - require.True(t, res.IsOK()) - - coins, err = getCoins(input.bk, ctx, dest) - require.Nil(t, err) - require.Equal(t, mycoins, coins) - - igs = ibcm.GetIngressSequence(ctx, chainid) - require.Equal(t, igs, uint64(1)) - - res = h(ctx, msg) - require.False(t, res.IsOK()) - - igs = ibcm.GetIngressSequence(ctx, chainid) - require.Equal(t, igs, uint64(1)) -} diff --git a/x/ibc/mapper.go b/x/ibc/mapper.go deleted file mode 100644 index 101fac03393e..000000000000 --- a/x/ibc/mapper.go +++ /dev/null @@ -1,130 +0,0 @@ -package ibc - -import ( - "fmt" - - codec "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// IBC Mapper -type Mapper struct { - key sdk.StoreKey - cdc *codec.Codec - codespace sdk.CodespaceType -} - -// XXX: The Mapper should not take a CoinKeeper. Rather have the CoinKeeper -// take an Mapper. -func NewMapper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) Mapper { - // XXX: How are these codecs supposed to work? - return Mapper{ - key: key, - cdc: cdc, - codespace: codespace, - } -} - -// XXX: This is not the public API. This will change in MVP2 and will henceforth -// only be invoked from another module directly and not through a user -// transaction. -// TODO: Handle invalid IBC packets and return errors. -func (ibcm Mapper) PostIBCPacket(ctx sdk.Context, packet IBCPacket) sdk.Error { - // write everything into the state - store := ctx.KVStore(ibcm.key) - index := ibcm.getEgressLength(store, packet.DestChain) - bz, err := ibcm.cdc.MarshalBinaryLengthPrefixed(packet) - if err != nil { - panic(err) - } - - store.Set(EgressKey(packet.DestChain, index), bz) - bz, err = ibcm.cdc.MarshalBinaryLengthPrefixed(index + 1) - if err != nil { - panic(err) - } - store.Set(EgressLengthKey(packet.DestChain), bz) - - return nil -} - -// XXX: In the future every module is able to register it's own handler for -// handling it's own IBC packets. The "ibc" handler will only route the packets -// to the appropriate callbacks. -// XXX: For now this handles all interactions with the CoinKeeper. -// XXX: This needs to do some authentication checking. -func (ibcm Mapper) ReceiveIBCPacket(ctx sdk.Context, packet IBCPacket) sdk.Error { - return nil -} - -// -------------------------- -// Functions for accessing the underlying KVStore. - -func marshalBinaryPanic(cdc *codec.Codec, value interface{}) []byte { - res, err := cdc.MarshalBinaryLengthPrefixed(value) - if err != nil { - panic(err) - } - return res -} - -func unmarshalBinaryPanic(cdc *codec.Codec, bz []byte, ptr interface{}) { - err := cdc.UnmarshalBinaryLengthPrefixed(bz, ptr) - if err != nil { - panic(err) - } -} - -// TODO add description -func (ibcm Mapper) GetIngressSequence(ctx sdk.Context, srcChain string) uint64 { - store := ctx.KVStore(ibcm.key) - key := IngressSequenceKey(srcChain) - - bz := store.Get(key) - if bz == nil { - zero := marshalBinaryPanic(ibcm.cdc, int64(0)) - store.Set(key, zero) - return 0 - } - - var res uint64 - unmarshalBinaryPanic(ibcm.cdc, bz, &res) - return res -} - -// TODO add description -func (ibcm Mapper) SetIngressSequence(ctx sdk.Context, srcChain string, sequence uint64) { - store := ctx.KVStore(ibcm.key) - key := IngressSequenceKey(srcChain) - - bz := marshalBinaryPanic(ibcm.cdc, sequence) - store.Set(key, bz) -} - -// Retrieves the index of the currently stored outgoing IBC packets. -func (ibcm Mapper) getEgressLength(store sdk.KVStore, destChain string) uint64 { - bz := store.Get(EgressLengthKey(destChain)) - if bz == nil { - zero := marshalBinaryPanic(ibcm.cdc, int64(0)) - store.Set(EgressLengthKey(destChain), zero) - return 0 - } - var res uint64 - unmarshalBinaryPanic(ibcm.cdc, bz, &res) - return res -} - -// Stores an outgoing IBC packet under "egress/chain_id/index". -func EgressKey(destChain string, index uint64) []byte { - return []byte(fmt.Sprintf("egress/%s/%d", destChain, index)) -} - -// Stores the number of outgoing IBC packets under "egress/index". -func EgressLengthKey(destChain string) []byte { - return []byte(fmt.Sprintf("egress/%s", destChain)) -} - -// Stores the sequence number of incoming IBC packet under "ingress/index". -func IngressSequenceKey(srcChain string) []byte { - return []byte(fmt.Sprintf("ingress/%s", srcChain)) -} diff --git a/x/ibc/types.go b/x/ibc/types.go deleted file mode 100644 index 3b626fdf8d27..000000000000 --- a/x/ibc/types.go +++ /dev/null @@ -1,125 +0,0 @@ -package ibc - -import ( - "encoding/json" - - codec "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -var ( - msgCdc *codec.Codec -) - -func init() { - msgCdc = codec.New() -} - -// ------------------------------ -// IBCPacket - -// nolint - TODO rename to Packet as IBCPacket stutters (golint) -// IBCPacket defines a piece of data that can be send between two separate -// blockchains. -type IBCPacket struct { - SrcAddr sdk.AccAddress `json:"src_addr"` - DestAddr sdk.AccAddress `json:"dest_addr"` - Coins sdk.Coins `json:"coins"` - SrcChain string `json:"src_chain"` - DestChain string `json:"dest_chain"` -} - -func NewIBCPacket(srcAddr sdk.AccAddress, destAddr sdk.AccAddress, coins sdk.Coins, - srcChain string, destChain string) IBCPacket { - - return IBCPacket{ - SrcAddr: srcAddr, - DestAddr: destAddr, - Coins: coins, - SrcChain: srcChain, - DestChain: destChain, - } -} - -//nolint -func (p IBCPacket) GetSignBytes() []byte { - b, err := msgCdc.MarshalJSON(p) - if err != nil { - panic(err) - } - return sdk.MustSortJSON(b) -} - -// validator the ibc packey -func (p IBCPacket) ValidateBasic() sdk.Error { - if p.SrcChain == p.DestChain { - return ErrIdenticalChains(DefaultCodespace).TraceSDK("") - } - if !p.Coins.IsValid() { - return sdk.ErrInvalidCoins("") - } - return nil -} - -// ---------------------------------- -// MsgIBCTransfer - -// nolint - TODO rename to TransferMsg as folks will reference with ibc.TransferMsg -// MsgIBCTransfer defines how another module can send an IBCPacket. -type MsgIBCTransfer struct { - IBCPacket -} - -// nolint -func (msg MsgIBCTransfer) Route() string { return "ibc" } -func (msg MsgIBCTransfer) Type() string { return "transfer" } - -// x/bank/tx.go MsgSend.GetSigners() -func (msg MsgIBCTransfer) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.SrcAddr} } - -// get the sign bytes for ibc transfer message -func (msg MsgIBCTransfer) GetSignBytes() []byte { - return msg.IBCPacket.GetSignBytes() -} - -// validate ibc transfer message -func (msg MsgIBCTransfer) ValidateBasic() sdk.Error { - return msg.IBCPacket.ValidateBasic() -} - -// ---------------------------------- -// MsgIBCReceive - -// nolint - TODO rename to ReceiveMsg as folks will reference with ibc.ReceiveMsg -// MsgIBCReceive defines the message that a relayer uses to post an IBCPacket -// to the destination chain. -type MsgIBCReceive struct { - IBCPacket - Relayer sdk.AccAddress - Sequence uint64 -} - -// nolint -func (msg MsgIBCReceive) Route() string { return "ibc" } -func (msg MsgIBCReceive) Type() string { return "receive" } -func (msg MsgIBCReceive) ValidateBasic() sdk.Error { return msg.IBCPacket.ValidateBasic() } - -// x/bank/tx.go MsgSend.GetSigners() -func (msg MsgIBCReceive) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Relayer} } - -// get the sign bytes for ibc receive message -func (msg MsgIBCReceive) GetSignBytes() []byte { - b, err := msgCdc.MarshalJSON(struct { - IBCPacket json.RawMessage - Relayer sdk.AccAddress - Sequence uint64 - }{ - IBCPacket: json.RawMessage(msg.IBCPacket.GetSignBytes()), - Relayer: msg.Relayer, - Sequence: msg.Sequence, - }) - if err != nil { - panic(err) - } - return sdk.MustSortJSON(b) -} diff --git a/x/ibc/types_test.go b/x/ibc/types_test.go deleted file mode 100644 index 674b4498215e..000000000000 --- a/x/ibc/types_test.go +++ /dev/null @@ -1,111 +0,0 @@ -package ibc - -import ( - "testing" - - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// -------------------------------- -// IBCPacket Tests - -func TestIBCPacketValidation(t *testing.T) { - cases := []struct { - valid bool - packet IBCPacket - }{ - {true, constructIBCPacket(true)}, - {false, constructIBCPacket(false)}, - } - - for i, tc := range cases { - err := tc.packet.ValidateBasic() - if tc.valid { - require.Nil(t, err, "%d: %+v", i, err) - } else { - require.NotNil(t, err, "%d", i) - } - } -} - -// ------------------------------- -// MsgIBCTransfer Tests - -func TestIBCTransferMsg(t *testing.T) { - packet := constructIBCPacket(true) - msg := MsgIBCTransfer{packet} - - require.Equal(t, msg.Route(), "ibc") -} - -func TestIBCTransferMsgValidation(t *testing.T) { - validPacket := constructIBCPacket(true) - invalidPacket := constructIBCPacket(false) - - cases := []struct { - valid bool - msg MsgIBCTransfer - }{ - {true, MsgIBCTransfer{validPacket}}, - {false, MsgIBCTransfer{invalidPacket}}, - } - - for i, tc := range cases { - err := tc.msg.ValidateBasic() - if tc.valid { - require.Nil(t, err, "%d: %+v", i, err) - } else { - require.NotNil(t, err, "%d", i) - } - } -} - -// ------------------------------- -// MsgIBCReceive Tests - -func TestIBCReceiveMsg(t *testing.T) { - packet := constructIBCPacket(true) - msg := MsgIBCReceive{packet, sdk.AccAddress([]byte("relayer")), 0} - - require.Equal(t, msg.Route(), "ibc") -} - -func TestIBCReceiveMsgValidation(t *testing.T) { - validPacket := constructIBCPacket(true) - invalidPacket := constructIBCPacket(false) - - cases := []struct { - valid bool - msg MsgIBCReceive - }{ - {true, MsgIBCReceive{validPacket, sdk.AccAddress([]byte("relayer")), 0}}, - {false, MsgIBCReceive{invalidPacket, sdk.AccAddress([]byte("relayer")), 0}}, - } - - for i, tc := range cases { - err := tc.msg.ValidateBasic() - if tc.valid { - require.Nil(t, err, "%d: %+v", i, err) - } else { - require.NotNil(t, err, "%d", i) - } - } -} - -// ------------------------------- -// Helpers - -func constructIBCPacket(valid bool) IBCPacket { - srcAddr := sdk.AccAddress([]byte("source")) - destAddr := sdk.AccAddress([]byte("destination")) - coins := sdk.Coins{sdk.NewInt64Coin("atom", 10)} - srcChain := "source-chain" - destChain := "dest-chain" - - if valid { - return NewIBCPacket(srcAddr, destAddr, coins, srcChain, destChain) - } - return NewIBCPacket(srcAddr, destAddr, coins, srcChain, srcChain) -} From 2b17a39da71b29b1a058da15791a6e8904b13efc Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 16:11:05 +0200 Subject: [PATCH 005/378] rm GetIfExists --- store/state/boolean.go | 4 ---- store/state/enum.go | 8 ++------ store/state/indexer.go | 4 ---- store/state/integer.go | 12 ++---------- store/state/mapping.go | 4 ---- store/state/value.go | 4 ---- 6 files changed, 4 insertions(+), 32 deletions(-) diff --git a/store/state/boolean.go b/store/state/boolean.go index c691ceaf9a00..b442d9cd2f76 100644 --- a/store/state/boolean.go +++ b/store/state/boolean.go @@ -12,10 +12,6 @@ func (v Boolean) Get(ctx Context) bool { return v.Enum.Get(ctx) != 0x00 } -func (v Boolean) GetIfExists(ctx Context) bool { - return v.Enum.GetIfExists(ctx) != 0x00 -} - func (v Boolean) GetSafe(ctx Context) (bool, error) { res, err := v.Enum.GetSafe(ctx) return res != 0x00, err diff --git a/store/state/enum.go b/store/state/enum.go index a44f820a6e5d..3f1f8b4e2c85 100644 --- a/store/state/enum.go +++ b/store/state/enum.go @@ -9,10 +9,6 @@ func NewEnum(v Value) Enum { } func (v Enum) Get(ctx Context) byte { - return v.Value.GetRaw(ctx)[0] -} - -func (v Enum) GetIfExists(ctx Context) byte { res := v.Value.GetRaw(ctx) if res != nil { return res[0] @@ -33,13 +29,13 @@ func (v Enum) Set(ctx Context, value byte) { } func (v Enum) Incr(ctx Context) (res byte) { - res = v.GetIfExists(ctx) + 1 + res = v.Get(ctx) + 1 v.Set(ctx, res) return } func (v Enum) Transit(ctx Context, from, to byte) bool { - if v.GetIfExists(ctx) != from { + if v.Get(ctx) != from { return false } v.Set(ctx, to) diff --git a/store/state/indexer.go b/store/state/indexer.go index 212be3d0f603..281dea761fd5 100644 --- a/store/state/indexer.go +++ b/store/state/indexer.go @@ -64,10 +64,6 @@ func (ix Indexer) Get(ctx Context, index uint64, ptr interface{}) { ix.Value(index).Get(ctx, ptr) } -func (ix Indexer) GetIfExists(ctx Context, index uint64, ptr interface{}) { - ix.Value(index).GetIfExists(ctx, ptr) -} - func (ix Indexer) GetSafe(ctx Context, index uint64, ptr interface{}) error { return ix.Value(index).GetSafe(ctx, ptr) } diff --git a/store/state/integer.go b/store/state/integer.go index 758656e29679..9dd00cf45d1d 100644 --- a/store/state/integer.go +++ b/store/state/integer.go @@ -13,15 +13,7 @@ func NewInteger(v Value, enc IntEncoding) Integer { } } -func (v Integer) Get(ctx Context) uint64 { - res, err := DecodeInt(v.GetRaw(ctx), v.enc) - if err != nil { - panic(err) - } - return res -} - -func (v Integer) GetIfExists(ctx Context) (res uint64) { +func (v Integer) Get(ctx Context) (res uint64) { bz := v.GetRaw(ctx) if bz == nil { return 0 @@ -50,7 +42,7 @@ func (v Integer) Set(ctx Context, value uint64) { } func (v Integer) Incr(ctx Context) (res uint64) { - res = v.GetIfExists(ctx) + 1 + res = v.Get(ctx) + 1 v.Set(ctx, res) return } diff --git a/store/state/mapping.go b/store/state/mapping.go index eaf0278ebf3f..0b45ab3d37db 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -24,10 +24,6 @@ func (m Mapping) Get(ctx Context, key []byte, ptr interface{}) { m.Value(key).Get(ctx, ptr) } -func (m Mapping) GetIfExists(ctx Context, key []byte, ptr interface{}) { - m.Value(key).GetIfExists(ctx, ptr) -} - func (m Mapping) GetSafe(ctx Context, key []byte, ptr interface{}) error { return m.Value(key).GetSafe(ctx, ptr) } diff --git a/store/state/value.go b/store/state/value.go index cb5d7699168c..df918aaba9fd 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -27,10 +27,6 @@ func (v Value) Cdc() *codec.Codec { } func (v Value) Get(ctx Context, ptr interface{}) { - v.base.cdc.MustUnmarshalBinaryBare(v.store(ctx).Get(v.key), ptr) -} - -func (v Value) GetIfExists(ctx Context, ptr interface{}) { bz := v.store(ctx).Get(v.key) if bz != nil { v.base.cdc.MustUnmarshalBinaryBare(bz, ptr) From dc84e1e031464f38bba529af8ca41bd3574ddbcf Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 16:23:04 +0200 Subject: [PATCH 006/378] add key --- store/state/value.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/store/state/value.go b/store/state/value.go index df918aaba9fd..a087db6064ce 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -65,6 +65,10 @@ func (v Value) Delete(ctx Context) { v.store(ctx).Delete(v.key) } +func (v Value) Key() []byte { + return v.base.key(v.key) +} + type GetSafeErrorType byte const ( From 19d71558f897afcc72432162937ecff930ec0d85 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 15:23:45 +0200 Subject: [PATCH 007/378] rm custom encoding/decoding in enum/bool --- store/state/boolean.go | 21 +++++++++------------ store/state/enum.go | 20 +++++++------------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/store/state/boolean.go b/store/state/boolean.go index b442d9cd2f76..2fb3701680be 100644 --- a/store/state/boolean.go +++ b/store/state/boolean.go @@ -1,26 +1,23 @@ package state type Boolean struct { - Enum + Value } func NewBoolean(v Value) Boolean { - return Boolean{NewEnum(v)} + return Boolean{v} } -func (v Boolean) Get(ctx Context) bool { - return v.Enum.Get(ctx) != 0x00 +func (v Boolean) Get(ctx Context) (res bool) { + v.Value.Get(ctx, &res) + return } -func (v Boolean) GetSafe(ctx Context) (bool, error) { - res, err := v.Enum.GetSafe(ctx) - return res != 0x00, err +func (v Boolean) GetSafe(ctx Context) (res bool, err error) { + err = v.Value.GetSafe(ctx, &res) + return } func (v Boolean) Set(ctx Context, value bool) { - if value { - v.Enum.Set(ctx, 0x01) - } else { - v.Enum.Set(ctx, 0x00) - } + v.Value.Set(ctx, value) } diff --git a/store/state/enum.go b/store/state/enum.go index 3f1f8b4e2c85..1cf1318f6652 100644 --- a/store/state/enum.go +++ b/store/state/enum.go @@ -8,24 +8,18 @@ func NewEnum(v Value) Enum { return Enum{v} } -func (v Enum) Get(ctx Context) byte { - res := v.Value.GetRaw(ctx) - if res != nil { - return res[0] - } - return 0x00 +func (v Enum) Get(ctx Context) (res byte) { + v.Value.Get(ctx, &res) + return } -func (v Enum) GetSafe(ctx Context) (byte, error) { - res := v.Value.GetRaw(ctx) - if res == nil { - return 0x00, &GetSafeError{} - } - return res[0], nil +func (v Enum) GetSafe(ctx Context) (res byte, err error) { + v.Value.GetSafe(ctx, &res) + return } func (v Enum) Set(ctx Context, value byte) { - v.Value.SetRaw(ctx, []byte{value}) + v.Value.Set(ctx, value) } func (v Enum) Incr(ctx Context) (res byte) { From 8affaa75b5e35b0571fbe493641ab3d9ffd03dfd Mon Sep 17 00:00:00 2001 From: mossid Date: Sat, 29 Jun 2019 15:10:12 +0200 Subject: [PATCH 008/378] fix lint --- store/state/enum.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/store/state/enum.go b/store/state/enum.go index 1cf1318f6652..8598f10324b7 100644 --- a/store/state/enum.go +++ b/store/state/enum.go @@ -14,7 +14,7 @@ func (v Enum) Get(ctx Context) (res byte) { } func (v Enum) GetSafe(ctx Context) (res byte, err error) { - v.Value.GetSafe(ctx, &res) + err = v.Value.GetSafe(ctx, &res) return } From a7898b457a2a05176191a79d8d273b5218599d13 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 18:23:47 +0200 Subject: [PATCH 009/378] rm tests --- store/state/mapping.go | 1 + store/state/test_common.go | 58 -------------------------------------- store/state/value_test.go | 32 --------------------- 3 files changed, 1 insertion(+), 90 deletions(-) delete mode 100644 store/state/test_common.go delete mode 100644 store/state/value_test.go diff --git a/store/state/mapping.go b/store/state/mapping.go index 0b45ab3d37db..127f5a0afb7c 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -9,6 +9,7 @@ func NewMapping(base Base, prefix []byte) Mapping { return Mapping{ base: base.Prefix(prefix), start: []byte{}, // preventing nil key access in store.Last + end: nil, } } diff --git a/store/state/test_common.go b/store/state/test_common.go deleted file mode 100644 index 691b1f0d294b..000000000000 --- a/store/state/test_common.go +++ /dev/null @@ -1,58 +0,0 @@ -package state - -import ( - // "testing" - "math/rand" - - // "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tendermint/libs/db" - "github.com/tendermint/tendermint/libs/log" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -const testsize = 10 - -type test interface { - test() -} - -type teststruct struct { - I uint64 - B bool - SL []byte -} - -var _ test = teststruct{} - -func (teststruct) test() {} - -func newtest() test { - var res teststruct - res.I = rand.Uint64() - res.B = rand.Int()%2 == 0 - res.SL = make([]byte, 20) - rand.Read(res.SL) - return res -} - -func defaultComponents() (sdk.StoreKey, Context, *codec.Codec) { - key := sdk.NewKVStoreKey("test") - db := dbm.NewMemDB() - cms := store.NewCommitMultiStore(db) - cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) - err := cms.LoadLatestVersion() - if err != nil { - panic(err) - } - ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) - cdc := codec.New() - cdc.RegisterInterface((*test)(nil), nil) - cdc.RegisterConcrete(teststruct{}, "test/struct", nil) - cdc.Seal() - return key, ctx, cdc -} diff --git a/store/state/value_test.go b/store/state/value_test.go deleted file mode 100644 index 24e4e708c458..000000000000 --- a/store/state/value_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package state - -import ( - "math/rand" - "testing" - - "github.com/stretchr/testify/require" -) - -type valuepair struct { - key []byte - value test -} - -func TestValue(t *testing.T) { - key, ctx, cdc := defaultComponents() - base := NewBase(cdc, key) - - cases := make([]valuepair, testsize) - for i := range cases { - cases[i].key = make([]byte, 20) - rand.Read(cases[i].key) - cases[i].value = newtest() - NewValue(base, cases[i].key).Set(ctx, cases[i].value) - } - - for i := range cases { - var val test - NewValue(base, cases[i].key).Get(ctx, &val) - require.Equal(t, cases[i].value, val) - } -} From afcca90a29b99f7652fbd151eb867272d33eeed9 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 7 Jun 2019 23:46:16 +0200 Subject: [PATCH 010/378] add commitment --- x/ibc/23-commitment/context.go | 17 +++++ x/ibc/23-commitment/store.go | 112 +++++++++++++++++++++++++++++++++ x/ibc/23-commitment/types.go | 19 ++++++ x/ibc/23-commitment/value.go | 61 ++++++++++++++++++ 4 files changed, 209 insertions(+) create mode 100644 x/ibc/23-commitment/context.go create mode 100644 x/ibc/23-commitment/store.go create mode 100644 x/ibc/23-commitment/types.go create mode 100644 x/ibc/23-commitment/value.go diff --git a/x/ibc/23-commitment/context.go b/x/ibc/23-commitment/context.go new file mode 100644 index 000000000000..6d8faa9bbcca --- /dev/null +++ b/x/ibc/23-commitment/context.go @@ -0,0 +1,17 @@ +package commitment + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// TODO: define Context type which embeds sdk.Context and ensures the existence of RemoteKVStore + +type ContextKeyRemoteKVStore struct{} + +func WithStore(ctx sdk.Context, store Store) sdk.Context { + return ctx.WithValue(ContextKeyRemoteKVStore{}, store) +} + +func GetStore(ctx sdk.Context) sdk.KVStore { + return ctx.Value(ContextKeyRemoteKVStore{}).(sdk.KVStore) +} diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go new file mode 100644 index 000000000000..ad70b28d5cfe --- /dev/null +++ b/x/ibc/23-commitment/store.go @@ -0,0 +1,112 @@ +package commitment + +import ( + "io" + + "github.com/cosmos/cosmos-sdk/store/cachekv" + "github.com/cosmos/cosmos-sdk/store/types" +) + +var _ types.KVStore = Store{} + +// Panics when there is no corresponding proof or the proof is invalid +// (to be compatible with KVStore interface) +// The semantics of the methods are redefined and does not compatible(should be improved) +// Get -> Returns the value if the corresponding proof is already verified +// Set -> Proof corresponding to the provided key is verified with the provided value +// Has -> Returns true if the proof is verified, returns false in any other case +// Delete -> Proof corresponding to the provided key is verified with nil value +// Other methods should not be used +type Store struct { + root Root + proofs map[string]Proof + verified map[string][]byte +} + +// Proofs must be provided +func NewStore(root Root, proofs []Proof, fullProofs []FullProof) (store Store, err error) { + store = Store{ + root: root, + proofs: make(map[string]Proof), + verified: make(map[string][]byte), + } + + for _, proof := range proofs { + store.proofs[string(proof.Key())] = proof + } + + for _, proof := range fullProofs { + err = proof.Verify(root) + if err != nil { + return + } + store.verified[string(proof.Proof.Key())] = proof.Value + } + + return +} + +func (store Store) GetStoreType() types.StoreType { + return types.StoreTypeTransient // XXX: check is it right +} + +func (store Store) CacheWrap() types.CacheWrap { + return cachekv.NewStore(store) +} + +func (store Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.CacheWrap { + // FIXME + return store.CacheWrap() +} + +func (store Store) Get(key []byte) []byte { + res, ok := store.verified[string(key)] + if !ok { + panic(UnverifiedKeyError{}) + } + return res +} + +func (store Store) Set(key, value []byte) { + proof, ok := store.proofs[string(key)] + if !ok { + return + } + err := proof.Verify(store.root, key, value) + if err == nil { + store.verified[string(key)] = value + } + + return +} + +// TODO: consider using this method to check whether the proof provided or not +// which may violate KVStore semantics +func (store Store) Has(key []byte) bool { + _, ok := store.verified[string(key)] + return ok +} + +func (store Store) Delete(key []byte) { + store.Set(key, nil) +} + +func (store Store) Iterator(begin, end []byte) types.Iterator { + panic(MethodError{}) +} + +func (store Store) ReverseIterator(begin, end []byte) types.Iterator { + panic(MethodError{}) +} + +type NoProofError struct { + // XXX +} + +type MethodError struct { + // XXX +} + +type UnverifiedKeyError struct { + // XXX +} diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go new file mode 100644 index 000000000000..546fd70825eb --- /dev/null +++ b/x/ibc/23-commitment/types.go @@ -0,0 +1,19 @@ +package commitment + +// XXX: []byte? +type Root interface{} + +// XXX: need to separate membership and non membership proof types +type Proof interface { + Key() []byte + Verify(Root, []byte, []byte) error +} + +type FullProof struct { + Proof Proof + Value []byte +} + +func (proof FullProof) Verify(root Root) error { + return proof.Proof.Verify(root, proof.Proof.Key(), proof.Value) +} diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go new file mode 100644 index 000000000000..36632cca5a61 --- /dev/null +++ b/x/ibc/23-commitment/value.go @@ -0,0 +1,61 @@ +package commitment + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/store/mapping" +) + +var _ mapping.Value = value{} + +type value struct { + mapping.Value +} + +func Value(base mapping.Base, key []byte) mapping.Value { + return value{mapping.NewValue(base, key)} +} + +func (v value) Is(ctx sdk.Context, value interface{}) bool { + // CONTRACT: commitment.value must be used with commitment.Store as its underlying KVStore + // TODO: enforce it + + v.Set(ctx, value) + return v.Exists(ctx) +} + +var _ mapping.Enum = enum{} + +type enum struct { + mapping.Enum +} + +func Enum(v mapping.Value) mapping.Enum { + return enum{mapping.NewEnum(v)} +} + +func (v enum) Is(ctx sdk.Context, value byte) bool { + // CONTRACT: commitment.enum must be used with commitment.Store as its underlying KVStore + // TODO: enforce it + + v.Set(ctx, value) + return v.Exists(ctx) +} + +var _ mapping.Integer = integer{} + +type integer struct { + mapping.Integer +} + +func Integer(v mapping.Value, enc mapping.IntEncoding) mapping.Integer { + return integer{mapping.NewInteger(v, enc)} +} + +func (v integer) Is(ctx sdk.Context, value uint64) bool { + // CONTRACT: commitment.integer must be used with commitment.Store as its underlying KVStore + // TODO: enforce it + + v.Set(ctx, value) + return v.Exists(ctx) +} From d29b601b58cedd563897b3888c075d30bd8011db Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 17:48:51 +0200 Subject: [PATCH 011/378] newtyped remote values --- store/state/base.go | 2 +- store/state/mapping.go | 2 +- store/state/value.go | 2 +- x/ibc/23-commitment/context.go | 14 +++--- x/ibc/23-commitment/store.go | 80 +++++++--------------------------- x/ibc/23-commitment/value.go | 68 +++++++++++++++-------------- 6 files changed, 62 insertions(+), 106 deletions(-) diff --git a/store/state/base.go b/store/state/base.go index 25760b77a947..f163c18b98a0 100644 --- a/store/state/base.go +++ b/store/state/base.go @@ -25,7 +25,7 @@ func NewBase(cdc *codec.Codec, key sdk.StoreKey) Base { } } -func (base Base) store(ctx Context) KVStore { +func (base Base) Store(ctx Context) KVStore { return prefix.NewStore(base.storefn(ctx), base.prefix) } diff --git a/store/state/mapping.go b/store/state/mapping.go index 127f5a0afb7c..566077a62237 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -14,7 +14,7 @@ func NewMapping(base Base, prefix []byte) Mapping { } func (m Mapping) store(ctx Context) KVStore { - return m.base.store(ctx) + return m.base.Store(ctx) } func (m Mapping) Value(key []byte) Value { diff --git a/store/state/value.go b/store/state/value.go index a087db6064ce..e948956e3d57 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -19,7 +19,7 @@ func NewValue(base Base, key []byte) Value { } func (v Value) store(ctx Context) KVStore { - return v.base.store(ctx) + return v.base.Store(ctx) } func (v Value) Cdc() *codec.Codec { diff --git a/x/ibc/23-commitment/context.go b/x/ibc/23-commitment/context.go index 6d8faa9bbcca..adb3bf27e8c6 100644 --- a/x/ibc/23-commitment/context.go +++ b/x/ibc/23-commitment/context.go @@ -4,14 +4,16 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// TODO: define Context type which embeds sdk.Context and ensures the existence of RemoteKVStore +type Context struct { + sdk.Context +} -type ContextKeyRemoteKVStore struct{} +type contextKeyRemoteKVStore struct{} -func WithStore(ctx sdk.Context, store Store) sdk.Context { - return ctx.WithValue(ContextKeyRemoteKVStore{}, store) +func WithStore(ctx sdk.Context, store Store) Context { + return Context{ctx.WithValue(contextKeyRemoteKVStore{}, store)} } -func GetStore(ctx sdk.Context) sdk.KVStore { - return ctx.Value(ContextKeyRemoteKVStore{}).(sdk.KVStore) +func (ctx Context) Store() Store { + return ctx.Value(contextKeyRemoteKVStore{}).(Store) } diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index ad70b28d5cfe..6a3e2e33fae1 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -1,22 +1,9 @@ package commitment import ( - "io" - - "github.com/cosmos/cosmos-sdk/store/cachekv" - "github.com/cosmos/cosmos-sdk/store/types" + "bytes" ) -var _ types.KVStore = Store{} - -// Panics when there is no corresponding proof or the proof is invalid -// (to be compatible with KVStore interface) -// The semantics of the methods are redefined and does not compatible(should be improved) -// Get -> Returns the value if the corresponding proof is already verified -// Set -> Proof corresponding to the provided key is verified with the provided value -// Has -> Returns true if the proof is verified, returns false in any other case -// Delete -> Proof corresponding to the provided key is verified with nil value -// Other methods should not be used type Store struct { root Root proofs map[string]Proof @@ -46,67 +33,30 @@ func NewStore(root Root, proofs []Proof, fullProofs []FullProof) (store Store, e return } -func (store Store) GetStoreType() types.StoreType { - return types.StoreTypeTransient // XXX: check is it right -} - -func (store Store) CacheWrap() types.CacheWrap { - return cachekv.NewStore(store) -} - -func (store Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.CacheWrap { - // FIXME - return store.CacheWrap() -} - -func (store Store) Get(key []byte) []byte { +func (store Store) Get(key []byte) ([]byte, bool) { res, ok := store.verified[string(key)] - if !ok { - panic(UnverifiedKeyError{}) - } - return res + return res, ok } -func (store Store) Set(key, value []byte) { +func (store Store) Prove(key, value []byte) bool { + stored, ok := store.Get(key) + if ok && bytes.Equal(stored, value) { + return true + } proof, ok := store.proofs[string(key)] if !ok { - return + return false } err := proof.Verify(store.root, key, value) - if err == nil { - store.verified[string(key)] = value + if err != nil { + return false } + store.verified[string(key)] = value - return + return true } -// TODO: consider using this method to check whether the proof provided or not -// which may violate KVStore semantics -func (store Store) Has(key []byte) bool { - _, ok := store.verified[string(key)] +func (store Store) Proven(key []byte) bool { + _, ok := store.Get(key) return ok } - -func (store Store) Delete(key []byte) { - store.Set(key, nil) -} - -func (store Store) Iterator(begin, end []byte) types.Iterator { - panic(MethodError{}) -} - -func (store Store) ReverseIterator(begin, end []byte) types.Iterator { - panic(MethodError{}) -} - -type NoProofError struct { - // XXX -} - -type MethodError struct { - // XXX -} - -type UnverifiedKeyError struct { - // XXX -} diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 36632cca5a61..69810320cb98 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -1,61 +1,65 @@ package commitment import ( - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/mapping" ) -var _ mapping.Value = value{} +type Base struct { + cdc *codec.Codec + prefix []byte +} -type value struct { - mapping.Value +func NewBase(cdc *codec.Codec) Base { + return Base{ + cdc: cdc, + } } -func Value(base mapping.Base, key []byte) mapping.Value { - return value{mapping.NewValue(base, key)} +func (base Base) Store(ctx Context) Store { + return ctx.Store() } -func (v value) Is(ctx sdk.Context, value interface{}) bool { - // CONTRACT: commitment.value must be used with commitment.Store as its underlying KVStore - // TODO: enforce it +type Value struct { + base Base + key []byte +} - v.Set(ctx, value) - return v.Exists(ctx) +func NewValue(base Base, key []byte) Value { + return Value{base, key} } -var _ mapping.Enum = enum{} +func (v Value) Is(ctx Context, value interface{}) bool { + return v.base.Store(ctx).Prove(v.key, v.base.cdc.MustMarshalBinaryBare(value)) +} -type enum struct { - mapping.Enum +func (v Value) IsRaw(ctx Context, value []byte) bool { + return v.base.Store(ctx).Prove(v.key, value) } -func Enum(v mapping.Value) mapping.Enum { - return enum{mapping.NewEnum(v)} +type Enum struct { + Value } -func (v enum) Is(ctx sdk.Context, value byte) bool { - // CONTRACT: commitment.enum must be used with commitment.Store as its underlying KVStore - // TODO: enforce it +func NewEnum(v Value) Enum { + return Enum{v} +} - v.Set(ctx, value) - return v.Exists(ctx) +func (v Enum) Is(ctx Context, value byte) bool { + return v.Value.IsRaw(ctx, []byte{value}) } -var _ mapping.Integer = integer{} +type Integer struct { + Value -type integer struct { - mapping.Integer + enc mapping.IntEncoding } -func Integer(v mapping.Value, enc mapping.IntEncoding) mapping.Integer { - return integer{mapping.NewInteger(v, enc)} +func NewInteger(v Value, enc mapping.IntEncoding) Integer { + return Integer{v, enc} } -func (v integer) Is(ctx sdk.Context, value uint64) bool { - // CONTRACT: commitment.integer must be used with commitment.Store as its underlying KVStore - // TODO: enforce it - - v.Set(ctx, value) - return v.Exists(ctx) +func (v Integer) Is(ctx Context, value uint64) bool { + return v.Value.IsRaw(ctx, mapping.EncodeInt(value, v.enc)) } From dd86fa965fc580c7b740355a59a5a920aa109e9a Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 18:05:23 +0200 Subject: [PATCH 012/378] newtyped context --- x/ibc/23-commitment/context.go | 2 +- x/ibc/23-commitment/store.go | 40 +++++++++++++++++++++++++++------- x/ibc/23-commitment/value.go | 26 +++++++++++++++++++++- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/x/ibc/23-commitment/context.go b/x/ibc/23-commitment/context.go index adb3bf27e8c6..a3e4a077e13e 100644 --- a/x/ibc/23-commitment/context.go +++ b/x/ibc/23-commitment/context.go @@ -14,6 +14,6 @@ func WithStore(ctx sdk.Context, store Store) Context { return Context{ctx.WithValue(contextKeyRemoteKVStore{}, store)} } -func (ctx Context) Store() Store { +func (ctx Context) RemoteStore() Store { return ctx.Value(contextKeyRemoteKVStore{}).(Store) } diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 6a3e2e33fae1..94977a9824ea 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -4,22 +4,46 @@ import ( "bytes" ) -type Store struct { +type Store interface { + Prove(key, value []byte) bool +} + +var _ Store = prefix{} + +type prefix struct { + store Store + prefix []byte +} + +func NewPrefix(store Store, pref []byte) prefix { + return prefix{ + store: store, + prefix: pref, + } +} + +func (prefix prefix) Prove(key, value []byte) bool { + return prefix.store.Prove(join(prefix.prefix, key), value) +} + +var _ Store = store{} + +type store struct { root Root proofs map[string]Proof verified map[string][]byte } // Proofs must be provided -func NewStore(root Root, proofs []Proof, fullProofs []FullProof) (store Store, err error) { - store = Store{ +func Newstore(root Root, proofs []Proof, fullProofs []FullProof) (res store, err error) { + res = store{ root: root, proofs: make(map[string]Proof), verified: make(map[string][]byte), } for _, proof := range proofs { - store.proofs[string(proof.Key())] = proof + res.proofs[string(proof.Key())] = proof } for _, proof := range fullProofs { @@ -27,18 +51,18 @@ func NewStore(root Root, proofs []Proof, fullProofs []FullProof) (store Store, e if err != nil { return } - store.verified[string(proof.Proof.Key())] = proof.Value + res.verified[string(proof.Proof.Key())] = proof.Value } return } -func (store Store) Get(key []byte) ([]byte, bool) { +func (store store) Get(key []byte) ([]byte, bool) { res, ok := store.verified[string(key)] return res, ok } -func (store Store) Prove(key, value []byte) bool { +func (store store) Prove(key, value []byte) bool { stored, ok := store.Get(key) if ok && bytes.Equal(stored, value) { return true @@ -56,7 +80,7 @@ func (store Store) Prove(key, value []byte) bool { return true } -func (store Store) Proven(key []byte) bool { +func (store store) Proven(key []byte) bool { _, ok := store.Get(key) return ok } diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 69810320cb98..77a99d1b44ac 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -18,7 +18,31 @@ func NewBase(cdc *codec.Codec) Base { } func (base Base) Store(ctx Context) Store { - return ctx.Store() + return NewPrefix(ctx.RemoteStore(), base.prefix) +} + +func join(a, b []byte) (res []byte) { + res = make([]byte, len(a)+len(b)) + copy(res, a) + copy(res[len(a):], b) + return +} + +func (base Base) Prefix(prefix []byte) Base { + return Base{ + cdc: base.cdc, + prefix: join(base.prefix, prefix), + } +} + +type Mapping struct { + base Base +} + +func NewMapping(base Base, prefix []byte) Mapping { + return Mapping{ + base: base.Prefix(prefix), + } } type Value struct { From 6aad15ff17e1b31d1b7b8e38351d6794de1dfdcd Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 18:41:00 +0200 Subject: [PATCH 013/378] revert context newtype --- x/ibc/23-commitment/context.go | 14 ++++++-------- x/ibc/23-commitment/value.go | 14 +++++++------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/x/ibc/23-commitment/context.go b/x/ibc/23-commitment/context.go index a3e4a077e13e..3680fb6b09bd 100644 --- a/x/ibc/23-commitment/context.go +++ b/x/ibc/23-commitment/context.go @@ -4,16 +4,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -type Context struct { - sdk.Context -} +// TODO: define Context type which embeds sdk.Context and ensures the existence of RemoteKVStore -type contextKeyRemoteKVStore struct{} +type ContextKeyRemoteKVStore struct{} -func WithStore(ctx sdk.Context, store Store) Context { - return Context{ctx.WithValue(contextKeyRemoteKVStore{}, store)} +func WithStore(ctx sdk.Context, store Store) sdk.Context { + return ctx.WithValue(ContextKeyRemoteKVStore{}, store) } -func (ctx Context) RemoteStore() Store { - return ctx.Value(contextKeyRemoteKVStore{}).(Store) +func GetStore(ctx sdk.Context) Store { + return ctx.Value(ContextKeyRemoteKVStore{}).(Store) } diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 77a99d1b44ac..74f72492bf53 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -2,8 +2,8 @@ package commitment import ( "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/mapping" + sdk "github.com/cosmos/cosmos-sdk/types" ) type Base struct { @@ -17,8 +17,8 @@ func NewBase(cdc *codec.Codec) Base { } } -func (base Base) Store(ctx Context) Store { - return NewPrefix(ctx.RemoteStore(), base.prefix) +func (base Base) Store(ctx sdk.Context) Store { + return NewPrefix(GetStore(ctx), base.prefix) } func join(a, b []byte) (res []byte) { @@ -54,11 +54,11 @@ func NewValue(base Base, key []byte) Value { return Value{base, key} } -func (v Value) Is(ctx Context, value interface{}) bool { +func (v Value) Is(ctx sdk.Context, value interface{}) bool { return v.base.Store(ctx).Prove(v.key, v.base.cdc.MustMarshalBinaryBare(value)) } -func (v Value) IsRaw(ctx Context, value []byte) bool { +func (v Value) IsRaw(ctx sdk.Context, value []byte) bool { return v.base.Store(ctx).Prove(v.key, value) } @@ -70,7 +70,7 @@ func NewEnum(v Value) Enum { return Enum{v} } -func (v Enum) Is(ctx Context, value byte) bool { +func (v Enum) Is(ctx sdk.Context, value byte) bool { return v.Value.IsRaw(ctx, []byte{value}) } @@ -84,6 +84,6 @@ func NewInteger(v Value, enc mapping.IntEncoding) Integer { return Integer{v, enc} } -func (v Integer) Is(ctx Context, value uint64) bool { +func (v Integer) Is(ctx sdk.Context, value uint64) bool { return v.Value.IsRaw(ctx, mapping.EncodeInt(value, v.enc)) } From 088836dcc2d6784830a911a8e758b51654ff3013 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 23:37:31 +0200 Subject: [PATCH 014/378] add README, keypath --- x/ibc/23-commitment/README.md | 50 ++++++++++++++++++++++++++++++++++ x/ibc/23-commitment/keypath.go | 27 ++++++++++++++++++ x/ibc/23-commitment/store.go | 12 ++------ x/ibc/23-commitment/types.go | 11 +------- 4 files changed, 80 insertions(+), 20 deletions(-) create mode 100644 x/ibc/23-commitment/README.md create mode 100644 x/ibc/23-commitment/keypath.go diff --git a/x/ibc/23-commitment/README.md b/x/ibc/23-commitment/README.md new file mode 100644 index 000000000000..61a46b99d8a4 --- /dev/null +++ b/x/ibc/23-commitment/README.md @@ -0,0 +1,50 @@ +# ICS 23: Commitment + +Package `commitment` defines types and methods to verify other chain's state. The main type is `Store`, containing +proofs that can be verified when the correct value is provided. The spec functions those are directly related to +verification are: + +## Spec + +```typescript +type verifyMembership = (root: CommitmentRoot, proof: CommitmentProof, key: Key, value: Value) => bool +type verifyNonMembership = (root: CommitmentRoot, proof: CommitmentProof, key: Key) => bool +``` + +## Impl + +### types.go + +`type Proof` implements `spec: type CommitmentProof`. CommitmentProof is an arbitrary object which can be used as +an argument for `spec: verifyMembership` / `spec: verifyNonMembership`, constructed with `spec: createMembershipProof` / +`spec: createNonMembershipProof`. The implementation type `Proof` defines `spec: verify(Non)Membership` as its method +`Verify(Root, []byte) error`, which takes the commitment root and the value bytes argument. The method acts as +`spec: verifyMembership` when the value bytes is not nil, and `spec: verifyNonMembership` if it is nil. + +`type Root` implements `spec: type CommitmentRoot`. + +In Cosmos-SDK implementation, `Root` will be the `AppHash []byte`, and `Proof` will be `merkle.Proof`, which consists +of `SimpleProof` and `IAVLValueProof` + +### store.go + +`Store` assumes that the keys are already known at the time when the transaction is included, so the type `Proof` has +the method `Key() []byte`. The values should also have to be provided in order to verify the proof, but to reduce the +size of the transaction, they are excluded from `Proof` and provided by the application on runtime. + +`NewStore` takes `[]Proof` as its argument, without verifying, since the values are yet unknown. They are stored in +`store.proofs`. + +Proofs can be verified with `store.Prove()` method which takes the key of the proof it will verify and the value +that will be given to the `proof.Verify()`. Verified proofs are stored in `store.verified`. + +### context.go + +All of the ICS internals that requires verification on other chains' state are expected to take `ctx sdk.Context` +argument initialized by `WithStore()`. `WithStore()` sets the `Store` that contains the proofs for the other chain +in the context. Any attept to verify other chain's state without setting `Store` will lead to panic. + +### value.go + +Types in `value.go` is a replication of `store/mapping/*.go`, but only with a single method +`Is(ctx sdk.Context, value T) bool`, which access on the underlying `Store` and performs verification. diff --git a/x/ibc/23-commitment/keypath.go b/x/ibc/23-commitment/keypath.go new file mode 100644 index 000000000000..e3dc62f8af73 --- /dev/null +++ b/x/ibc/23-commitment/keypath.go @@ -0,0 +1,27 @@ +package commitment + +import ( + "github.com/tendermint/tendermint/crypto/merkle" +) + +// Hard coded for now +func SDKPrefix() merkle.KeyPath { + return new(merkle.KeyPath). + AppendKey([]byte("ibc"), merkle.KeyEncodingHex). + AppendKey([]byte{0x00}, merkle.KeyEncodingHex) +} + +func PrefixKeyPath(prefix string, key []byte) (res merkle.KeyPath, err error) { + keys, err := merkle.KeyPathToKeys(prefix) + if err != nil { + return + } + + keys[len(keys)-1] = append(keys[len(keys)], key...) + + for _, key := range keys { + res = res.AppendKey(key, merkle.KeyEncodingHex) + } + + return +} diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 94977a9824ea..92fad62e2771 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -35,7 +35,7 @@ type store struct { } // Proofs must be provided -func Newstore(root Root, proofs []Proof, fullProofs []FullProof) (res store, err error) { +func Newstore(root Root, proofs []Proof) (res store, err error) { res = store{ root: root, proofs: make(map[string]Proof), @@ -46,14 +46,6 @@ func Newstore(root Root, proofs []Proof, fullProofs []FullProof) (res store, err res.proofs[string(proof.Key())] = proof } - for _, proof := range fullProofs { - err = proof.Verify(root) - if err != nil { - return - } - res.verified[string(proof.Proof.Key())] = proof.Value - } - return } @@ -71,7 +63,7 @@ func (store store) Prove(key, value []byte) bool { if !ok { return false } - err := proof.Verify(store.root, key, value) + err := proof.Verify(store.root, value) if err != nil { return false } diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go index 546fd70825eb..5b8cca0a9f5e 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/types.go @@ -6,14 +6,5 @@ type Root interface{} // XXX: need to separate membership and non membership proof types type Proof interface { Key() []byte - Verify(Root, []byte, []byte) error -} - -type FullProof struct { - Proof Proof - Value []byte -} - -func (proof FullProof) Verify(root Root) error { - return proof.Proof.Verify(root, proof.Proof.Key(), proof.Value) + Verify(Root, []byte) error } From cd6f1f2e59aef987a30d6e48af2f8b8b4cb1f2dd Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 12 Jun 2019 00:25:20 +0200 Subject: [PATCH 015/378] reflect downstream ics --- x/ibc/23-commitment/value.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 74f72492bf53..70b8502a44e6 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -2,7 +2,7 @@ package commitment import ( "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/mapping" + "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -77,13 +77,13 @@ func (v Enum) Is(ctx sdk.Context, value byte) bool { type Integer struct { Value - enc mapping.IntEncoding + enc state.IntEncoding } -func NewInteger(v Value, enc mapping.IntEncoding) Integer { +func NewInteger(v Value, enc state.IntEncoding) Integer { return Integer{v, enc} } func (v Integer) Is(ctx sdk.Context, value uint64) bool { - return v.Value.IsRaw(ctx, mapping.EncodeInt(value, v.enc)) + return v.Value.IsRaw(ctx, state.EncodeInt(value, v.enc)) } From d0777cd28e08821c0b71ba2bf318968479fa5514 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 12 Jun 2019 00:51:21 +0200 Subject: [PATCH 016/378] add merkle --- x/ibc/23-commitment/keypath.go | 27 ----------- x/ibc/23-commitment/merkle/merkle.go | 71 ++++++++++++++++++++++++++++ x/ibc/23-commitment/store.go | 2 +- x/ibc/23-commitment/types.go | 2 +- 4 files changed, 73 insertions(+), 29 deletions(-) delete mode 100644 x/ibc/23-commitment/keypath.go create mode 100644 x/ibc/23-commitment/merkle/merkle.go diff --git a/x/ibc/23-commitment/keypath.go b/x/ibc/23-commitment/keypath.go deleted file mode 100644 index e3dc62f8af73..000000000000 --- a/x/ibc/23-commitment/keypath.go +++ /dev/null @@ -1,27 +0,0 @@ -package commitment - -import ( - "github.com/tendermint/tendermint/crypto/merkle" -) - -// Hard coded for now -func SDKPrefix() merkle.KeyPath { - return new(merkle.KeyPath). - AppendKey([]byte("ibc"), merkle.KeyEncodingHex). - AppendKey([]byte{0x00}, merkle.KeyEncodingHex) -} - -func PrefixKeyPath(prefix string, key []byte) (res merkle.KeyPath, err error) { - keys, err := merkle.KeyPathToKeys(prefix) - if err != nil { - return - } - - keys[len(keys)-1] = append(keys[len(keys)], key...) - - for _, key := range keys { - res = res.AppendKey(key, merkle.KeyEncodingHex) - } - - return -} diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go new file mode 100644 index 000000000000..8e234f4873fe --- /dev/null +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -0,0 +1,71 @@ +package merkle + +import ( + "errors" + + "github.com/tendermint/iavl" + "github.com/tendermint/tendermint/crypto/merkle" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +// merkle.Proof implementation of Proof +// Applied on SDK-based IBC implementation + +var _ commitment.Root = Root{} + +type Root = []byte + +var _ commitment.Proof = Proof{} + +type Proof struct { + Proof *merkle.Proof + Key []byte +} + +func (proof Proof) GetKey() []byte { + return proof.Key +} + +func (proof Proof) Verify(croot commitment.Root, value []byte) error { + root, ok := croot.(Root) + if !ok { + return errors.New("invalid commitment root type") + } + + keypath, err := PrefixKeyPath(SDKPrefix().String(), proof.Key) + if err != nil { + return err + } + // Hard coded for now + runtime := merkle.DefaultProofRuntime() + runtime.RegisterOpDecoder(iavl.ProofOpIAVLAbsence, iavl.IAVLAbsenceOpDecoder) + runtime.RegisterOpDecoder(iavl.ProofOpIAVLValue, iavl.IAVLValueOpDecoder) + + if value != nil { + return runtime.VerifyValue(proof.Proof, root, keypath.String(), value) + } + return runtime.VerifyAbsence(proof.Proof, root, keypath.String()) +} + +// Hard coded for now +func SDKPrefix() merkle.KeyPath { + return new(merkle.KeyPath). + AppendKey([]byte("ibc"), merkle.KeyEncodingHex). + AppendKey([]byte{0x00}, merkle.KeyEncodingHex) +} + +func PrefixKeyPath(prefix string, key []byte) (res merkle.KeyPath, err error) { + keys, err := merkle.KeyPathToKeys(prefix) + if err != nil { + return + } + + keys[len(keys)-1] = append(keys[len(keys)], key...) + + for _, key := range keys { + res = res.AppendKey(key, merkle.KeyEncodingHex) + } + + return +} diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 92fad62e2771..a82c59cc5fd7 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -43,7 +43,7 @@ func Newstore(root Root, proofs []Proof) (res store, err error) { } for _, proof := range proofs { - res.proofs[string(proof.Key())] = proof + res.proofs[string(proof.GetKey())] = proof } return diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go index 5b8cca0a9f5e..7d5d374512be 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/types.go @@ -5,6 +5,6 @@ type Root interface{} // XXX: need to separate membership and non membership proof types type Proof interface { - Key() []byte + GetKey() []byte Verify(Root, []byte) error } From df8c05e05545b3f2dc81c0117f6a87e32c8fc2b5 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 12 Jun 2019 14:06:17 +0200 Subject: [PATCH 017/378] add test for proving --- x/ibc/23-commitment/README.md | 2 +- x/ibc/23-commitment/merkle/merkle.go | 9 ++- x/ibc/23-commitment/merkle/merkle_test.go | 72 +++++++++++++++++++++++ x/ibc/23-commitment/store.go | 6 +- 4 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 x/ibc/23-commitment/merkle/merkle_test.go diff --git a/x/ibc/23-commitment/README.md b/x/ibc/23-commitment/README.md index 61a46b99d8a4..759128b0c6de 100644 --- a/x/ibc/23-commitment/README.md +++ b/x/ibc/23-commitment/README.md @@ -24,7 +24,7 @@ an argument for `spec: verifyMembership` / `spec: verifyNonMembership`, construc `type Root` implements `spec: type CommitmentRoot`. In Cosmos-SDK implementation, `Root` will be the `AppHash []byte`, and `Proof` will be `merkle.Proof`, which consists -of `SimpleProof` and `IAVLValueProof` +of `SimpleProof` and `IAVLValueProof`. Defined in `merkle/` ### store.go diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index 8e234f4873fe..1eb48385afad 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -3,9 +3,10 @@ package merkle import ( "errors" - "github.com/tendermint/iavl" "github.com/tendermint/tendermint/crypto/merkle" + "github.com/cosmos/cosmos-sdk/store/rootmulti" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -38,9 +39,7 @@ func (proof Proof) Verify(croot commitment.Root, value []byte) error { return err } // Hard coded for now - runtime := merkle.DefaultProofRuntime() - runtime.RegisterOpDecoder(iavl.ProofOpIAVLAbsence, iavl.IAVLAbsenceOpDecoder) - runtime.RegisterOpDecoder(iavl.ProofOpIAVLValue, iavl.IAVLValueOpDecoder) + runtime := rootmulti.DefaultProofRuntime() if value != nil { return runtime.VerifyValue(proof.Proof, root, keypath.String(), value) @@ -61,7 +60,7 @@ func PrefixKeyPath(prefix string, key []byte) (res merkle.KeyPath, err error) { return } - keys[len(keys)-1] = append(keys[len(keys)], key...) + keys[len(keys)-1] = append(keys[len(keys)-1], key...) for _, key := range keys { res = res.AppendKey(key, merkle.KeyEncodingHex) diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go new file mode 100644 index 000000000000..e252a13268c5 --- /dev/null +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -0,0 +1,72 @@ +package merkle + +import ( + "testing" + + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store" + "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +func defaultComponents() (sdk.StoreKey, sdk.Context, types.CommitMultiStore, *codec.Codec) { + key := sdk.NewKVStoreKey("ibc") + db := dbm.NewMemDB() + cms := store.NewCommitMultiStore(db) + cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) + err := cms.LoadLatestVersion() + if err != nil { + panic(err) + } + ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) + cdc := codec.New() + return key, ctx, cms, cdc +} + +func key(str string) []byte { + return append([]byte{0x00}, []byte(str)...) +} + +func query(t *testing.T, cms types.CommitMultiStore, k string) (value []byte, proof Proof) { + qres := cms.(types.Queryable).Query(abci.RequestQuery{Path: "/ibc/key", Data: key(k), Prove: true}) + require.Equal(t, uint32(0), qres.Code, qres.Log) + value = qres.Value + proof = Proof{ + Key: []byte(k), + Proof: qres.Proof, + } + return +} + +func TestStore(t *testing.T) { + k, ctx, cms, _ := defaultComponents() + kvstore := ctx.KVStore(k) + + kvstore.Set(key("hello"), []byte("world")) + kvstore.Set(key("merkle"), []byte("tree")) + kvstore.Set(key("block"), []byte("chain")) + + cid := cms.Commit() + + v1, p1 := query(t, cms, "hello") + require.Equal(t, []byte("world"), v1) + v2, p2 := query(t, cms, "merkle") + require.Equal(t, []byte("tree"), v2) + v3, p3 := query(t, cms, "block") + require.Equal(t, []byte("chain"), v3) + + cstore, err := commitment.NewStore(cid.Hash, []commitment.Proof{p1, p2, p3}) + require.NoError(t, err) + + require.True(t, cstore.Prove([]byte("hello"), []byte("world"))) + require.True(t, cstore.Prove([]byte("merkle"), []byte("tree"))) + require.True(t, cstore.Prove([]byte("block"), []byte("chain"))) +} diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index a82c59cc5fd7..bdc0bb8902dc 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -2,6 +2,7 @@ package commitment import ( "bytes" + "fmt" ) type Store interface { @@ -35,7 +36,7 @@ type store struct { } // Proofs must be provided -func Newstore(root Root, proofs []Proof) (res store, err error) { +func NewStore(root Root, proofs []Proof) (res store, err error) { res = store{ root: root, proofs: make(map[string]Proof), @@ -57,14 +58,17 @@ func (store store) Get(key []byte) ([]byte, bool) { func (store store) Prove(key, value []byte) bool { stored, ok := store.Get(key) if ok && bytes.Equal(stored, value) { + fmt.Println(1) return true } proof, ok := store.proofs[string(key)] if !ok { + fmt.Println(2) return false } err := proof.Verify(store.root, value) if err != nil { + fmt.Println(err) return false } store.verified[string(key)] = value From 47c33f0d2edfc09b2bc19592117ed0a5091cc0af Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 11:15:10 +0200 Subject: [PATCH 018/378] soft coded root keypath --- x/ibc/23-commitment/merkle/merkle.go | 40 ++++++++++++++++------- x/ibc/23-commitment/merkle/merkle_test.go | 13 +++++--- x/ibc/23-commitment/store.go | 9 ++--- x/ibc/23-commitment/types.go | 7 ++-- 4 files changed, 47 insertions(+), 22 deletions(-) diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index 1eb48385afad..c8362ce7fafb 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -15,7 +15,21 @@ import ( var _ commitment.Root = Root{} -type Root = []byte +type Root struct { + Hash []byte + KeyPrefix [][]byte +} + +func NewRoot(hash []byte, prefixes [][]byte) Root { + return Root{ + Hash: hash, + KeyPrefix: prefixes, + } +} + +func (Root) CommitmentKind() string { + return "merkle" +} var _ commitment.Proof = Proof{} @@ -24,6 +38,10 @@ type Proof struct { Key []byte } +func (Proof) CommitmentKind() string { + return "merkle" +} + func (proof Proof) GetKey() []byte { return proof.Key } @@ -34,24 +52,24 @@ func (proof Proof) Verify(croot commitment.Root, value []byte) error { return errors.New("invalid commitment root type") } - keypath, err := PrefixKeyPath(SDKPrefix().String(), proof.Key) + keypath := merkle.KeyPath{} + + for _, key := range root.KeyPrefix { + keypath = keypath.AppendKey(key, merkle.KeyEncodingHex) + } + + keypath, err := PrefixKeyPath(keypath.String(), proof.Key) if err != nil { return err } + // Hard coded for now runtime := rootmulti.DefaultProofRuntime() if value != nil { - return runtime.VerifyValue(proof.Proof, root, keypath.String(), value) + return runtime.VerifyValue(proof.Proof, root.Hash, keypath.String(), value) } - return runtime.VerifyAbsence(proof.Proof, root, keypath.String()) -} - -// Hard coded for now -func SDKPrefix() merkle.KeyPath { - return new(merkle.KeyPath). - AppendKey([]byte("ibc"), merkle.KeyEncodingHex). - AppendKey([]byte{0x00}, merkle.KeyEncodingHex) + return runtime.VerifyAbsence(proof.Proof, root.Hash, keypath.String()) } func PrefixKeyPath(prefix string, key []byte) (res merkle.KeyPath, err error) { diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index e252a13268c5..6070de09082b 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -18,7 +18,7 @@ import ( ) func defaultComponents() (sdk.StoreKey, sdk.Context, types.CommitMultiStore, *codec.Codec) { - key := sdk.NewKVStoreKey("ibc") + key := sdk.NewKVStoreKey("test") db := dbm.NewMemDB() cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) @@ -36,7 +36,7 @@ func key(str string) []byte { } func query(t *testing.T, cms types.CommitMultiStore, k string) (value []byte, proof Proof) { - qres := cms.(types.Queryable).Query(abci.RequestQuery{Path: "/ibc/key", Data: key(k), Prove: true}) + qres := cms.(types.Queryable).Query(abci.RequestQuery{Path: "/test/key", Data: key(k), Prove: true}) require.Equal(t, uint32(0), qres.Code, qres.Log) value = qres.Value proof = Proof{ @@ -46,6 +46,11 @@ func query(t *testing.T, cms types.CommitMultiStore, k string) (value []byte, pr return } +func commit(cms types.CommitMultiStore) (root Root) { + cid := cms.Commit() + return NewRoot(cid.Hash, [][]byte{[]byte("test"), []byte{0x00}}) +} + func TestStore(t *testing.T) { k, ctx, cms, _ := defaultComponents() kvstore := ctx.KVStore(k) @@ -54,7 +59,7 @@ func TestStore(t *testing.T) { kvstore.Set(key("merkle"), []byte("tree")) kvstore.Set(key("block"), []byte("chain")) - cid := cms.Commit() + root := commit(cms) v1, p1 := query(t, cms, "hello") require.Equal(t, []byte("world"), v1) @@ -63,7 +68,7 @@ func TestStore(t *testing.T) { v3, p3 := query(t, cms, "block") require.Equal(t, []byte("chain"), v3) - cstore, err := commitment.NewStore(cid.Hash, []commitment.Proof{p1, p2, p3}) + cstore, err := commitment.NewStore(root, []commitment.Proof{p1, p2, p3}) require.NoError(t, err) require.True(t, cstore.Prove([]byte("hello"), []byte("world"))) diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index bdc0bb8902dc..8cfaef4baaa1 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -2,7 +2,7 @@ package commitment import ( "bytes" - "fmt" + "errors" ) type Store interface { @@ -44,6 +44,10 @@ func NewStore(root Root, proofs []Proof) (res store, err error) { } for _, proof := range proofs { + if proof.CommitmentKind() != root.CommitmentKind() { + err = errors.New("proof type not matching with root's") + return + } res.proofs[string(proof.GetKey())] = proof } @@ -58,17 +62,14 @@ func (store store) Get(key []byte) ([]byte, bool) { func (store store) Prove(key, value []byte) bool { stored, ok := store.Get(key) if ok && bytes.Equal(stored, value) { - fmt.Println(1) return true } proof, ok := store.proofs[string(key)] if !ok { - fmt.Println(2) return false } err := proof.Verify(store.root, value) if err != nil { - fmt.Println(err) return false } store.verified[string(key)] = value diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go index 7d5d374512be..77561719cd1a 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/types.go @@ -1,10 +1,11 @@ package commitment -// XXX: []byte? -type Root interface{} +type Root interface { + CommitmentKind() string +} -// XXX: need to separate membership and non membership proof types type Proof interface { + CommitmentKind() string GetKey() []byte Verify(Root, []byte) error } From 12ef4027f7f4388ef1d8f306fc55b9423150daa3 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 11:56:38 +0200 Subject: [PATCH 019/378] add update --- x/ibc/23-commitment/merkle/merkle.go | 19 +++++++++++++++ x/ibc/23-commitment/merkle/merkle_test.go | 28 ++++++++++++++++++++--- x/ibc/23-commitment/types.go | 5 ++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index c8362ce7fafb..a5aa577947e7 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -31,6 +31,25 @@ func (Root) CommitmentKind() string { return "merkle" } +func (r Root) Update(cupdate commitment.RootUpdate) (commitment.Root, error) { + update, ok := cupdate.(RootUpdate) + if !ok { + return nil, errors.New("invalid type") + } + return Root{ + Hash: update.Hash, + KeyPrefix: r.KeyPrefix, + }, nil +} + +type RootUpdate struct { + Hash []byte +} + +func (RootUpdate) CommitmentKind() string { + return "merkle" +} + var _ commitment.Proof = Proof{} type Proof struct { diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index 6070de09082b..6fefe4f51d62 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -46,9 +46,11 @@ func query(t *testing.T, cms types.CommitMultiStore, k string) (value []byte, pr return } -func commit(cms types.CommitMultiStore) (root Root) { +func commit(t *testing.T, cms types.CommitMultiStore, root commitment.Root) commitment.Root { cid := cms.Commit() - return NewRoot(cid.Hash, [][]byte{[]byte("test"), []byte{0x00}}) + res, err := root.Update(RootUpdate{cid.Hash}) + require.NoError(t, err) + return res } func TestStore(t *testing.T) { @@ -59,7 +61,7 @@ func TestStore(t *testing.T) { kvstore.Set(key("merkle"), []byte("tree")) kvstore.Set(key("block"), []byte("chain")) - root := commit(cms) + root := commit(t, cms, Root{KeyPrefix: [][]byte{[]byte("test"), []byte{0x00}}}) v1, p1 := query(t, cms, "hello") require.Equal(t, []byte("world"), v1) @@ -74,4 +76,24 @@ func TestStore(t *testing.T) { require.True(t, cstore.Prove([]byte("hello"), []byte("world"))) require.True(t, cstore.Prove([]byte("merkle"), []byte("tree"))) require.True(t, cstore.Prove([]byte("block"), []byte("chain"))) + + kvstore.Set(key("12345"), []byte("67890")) + kvstore.Set(key("qwerty"), []byte("zxcv")) + kvstore.Set(key("hello"), []byte("dlrow")) + + root = commit(t, cms, root) + + v1, p1 = query(t, cms, "12345") + require.Equal(t, []byte("67890"), v1) + v2, p2 = query(t, cms, "qwerty") + require.Equal(t, []byte("zxcv"), v2) + v3, p3 = query(t, cms, "hello") + require.Equal(t, []byte("dlrow"), v3) + + cstore, err = commitment.NewStore(root, []commitment.Proof{p1, p2, p3}) + require.NoError(t, err) + + require.True(t, cstore.Prove([]byte("12345"), []byte("67890"))) + require.True(t, cstore.Prove([]byte("qwerty"), []byte("zxcv"))) + require.True(t, cstore.Prove([]byte("hello"), []byte("dlrow"))) } diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go index 77561719cd1a..7ef8ec1a6efa 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/types.go @@ -2,6 +2,11 @@ package commitment type Root interface { CommitmentKind() string + Update(RootUpdate) (Root, error) +} + +type RootUpdate interface { + CommitmentKind() string } type Proof interface { From 03d5d17b718bfa4bba4882f55327f8deac195b14 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 12:13:21 +0200 Subject: [PATCH 020/378] remove RootUpdate --- x/ibc/23-commitment/merkle/merkle.go | 18 +++--------------- x/ibc/23-commitment/merkle/merkle_test.go | 10 ++++------ x/ibc/23-commitment/types.go | 6 +----- 3 files changed, 8 insertions(+), 26 deletions(-) diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index a5aa577947e7..4c89a6e498e5 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -31,23 +31,11 @@ func (Root) CommitmentKind() string { return "merkle" } -func (r Root) Update(cupdate commitment.RootUpdate) (commitment.Root, error) { - update, ok := cupdate.(RootUpdate) - if !ok { - return nil, errors.New("invalid type") - } +func (r Root) Update(hash []byte) commitment.Root { return Root{ - Hash: update.Hash, + Hash: hash, KeyPrefix: r.KeyPrefix, - }, nil -} - -type RootUpdate struct { - Hash []byte -} - -func (RootUpdate) CommitmentKind() string { - return "merkle" + } } var _ commitment.Proof = Proof{} diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index 6fefe4f51d62..ce67d6c41251 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -46,11 +46,9 @@ func query(t *testing.T, cms types.CommitMultiStore, k string) (value []byte, pr return } -func commit(t *testing.T, cms types.CommitMultiStore, root commitment.Root) commitment.Root { +func commit(cms types.CommitMultiStore, root Root) Root { cid := cms.Commit() - res, err := root.Update(RootUpdate{cid.Hash}) - require.NoError(t, err) - return res + return root.Update(cid.Hash).(Root) } func TestStore(t *testing.T) { @@ -61,7 +59,7 @@ func TestStore(t *testing.T) { kvstore.Set(key("merkle"), []byte("tree")) kvstore.Set(key("block"), []byte("chain")) - root := commit(t, cms, Root{KeyPrefix: [][]byte{[]byte("test"), []byte{0x00}}}) + root := commit(cms, Root{KeyPrefix: [][]byte{[]byte("test"), []byte{0x00}}}) v1, p1 := query(t, cms, "hello") require.Equal(t, []byte("world"), v1) @@ -81,7 +79,7 @@ func TestStore(t *testing.T) { kvstore.Set(key("qwerty"), []byte("zxcv")) kvstore.Set(key("hello"), []byte("dlrow")) - root = commit(t, cms, root) + root = commit(cms, root) v1, p1 = query(t, cms, "12345") require.Equal(t, []byte("67890"), v1) diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go index 7ef8ec1a6efa..e12d8f0fcef6 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/types.go @@ -2,11 +2,7 @@ package commitment type Root interface { CommitmentKind() string - Update(RootUpdate) (Root, error) -} - -type RootUpdate interface { - CommitmentKind() string + Update([]byte) Root } type Proof interface { From 0b79b1dde7881253e8a69ee3a3556b5d28d379e8 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 15:07:00 +0200 Subject: [PATCH 021/378] separate keypath and keuprefix --- x/ibc/23-commitment/merkle/merkle.go | 33 ++++------------ x/ibc/23-commitment/merkle/merkle_test.go | 48 ++++++++++------------- x/ibc/23-commitment/merkle/utils.go | 28 +++++++++++++ 3 files changed, 56 insertions(+), 53 deletions(-) create mode 100644 x/ibc/23-commitment/merkle/utils.go diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index 4c89a6e498e5..bc01e0f112ee 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -17,13 +17,15 @@ var _ commitment.Root = Root{} type Root struct { Hash []byte - KeyPrefix [][]byte + KeyPath [][]byte + KeyPrefix []byte } -func NewRoot(hash []byte, prefixes [][]byte) Root { +func NewRoot(hash []byte, keypath [][]byte, prefix []byte) Root { return Root{ Hash: hash, - KeyPrefix: prefixes, + KeyPath: keypath, + KeyPrefix: prefix, } } @@ -34,6 +36,7 @@ func (Root) CommitmentKind() string { func (r Root) Update(hash []byte) commitment.Root { return Root{ Hash: hash, + KeyPath: r.KeyPath, KeyPrefix: r.KeyPrefix, } } @@ -60,15 +63,10 @@ func (proof Proof) Verify(croot commitment.Root, value []byte) error { } keypath := merkle.KeyPath{} - - for _, key := range root.KeyPrefix { + for _, key := range root.KeyPath { keypath = keypath.AppendKey(key, merkle.KeyEncodingHex) } - - keypath, err := PrefixKeyPath(keypath.String(), proof.Key) - if err != nil { - return err - } + keypath = keypath.AppendKey(append(root.KeyPrefix, proof.Key...), merkle.KeyEncodingHex) // Hard coded for now runtime := rootmulti.DefaultProofRuntime() @@ -78,18 +76,3 @@ func (proof Proof) Verify(croot commitment.Root, value []byte) error { } return runtime.VerifyAbsence(proof.Proof, root.Hash, keypath.String()) } - -func PrefixKeyPath(prefix string, key []byte) (res merkle.KeyPath, err error) { - keys, err := merkle.KeyPathToKeys(prefix) - if err != nil { - return - } - - keys[len(keys)-1] = append(keys[len(keys)-1], key...) - - for _, key := range keys { - res = res.AppendKey(key, merkle.KeyEncodingHex) - } - - return -} diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index ce67d6c41251..487e9496163e 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -31,21 +31,6 @@ func defaultComponents() (sdk.StoreKey, sdk.Context, types.CommitMultiStore, *co return key, ctx, cms, cdc } -func key(str string) []byte { - return append([]byte{0x00}, []byte(str)...) -} - -func query(t *testing.T, cms types.CommitMultiStore, k string) (value []byte, proof Proof) { - qres := cms.(types.Queryable).Query(abci.RequestQuery{Path: "/test/key", Data: key(k), Prove: true}) - require.Equal(t, uint32(0), qres.Code, qres.Log) - value = qres.Value - proof = Proof{ - Key: []byte(k), - Proof: qres.Proof, - } - return -} - func commit(cms types.CommitMultiStore, root Root) Root { cid := cms.Commit() return root.Update(cid.Hash).(Root) @@ -54,18 +39,22 @@ func commit(cms types.CommitMultiStore, root Root) Root { func TestStore(t *testing.T) { k, ctx, cms, _ := defaultComponents() kvstore := ctx.KVStore(k) + root := Root{KeyPath: [][]byte{[]byte("test")}, KeyPrefix: []byte{0x01, 0x03, 0x05}} - kvstore.Set(key("hello"), []byte("world")) - kvstore.Set(key("merkle"), []byte("tree")) - kvstore.Set(key("block"), []byte("chain")) + kvstore.Set(root.Key([]byte("hello")), []byte("world")) + kvstore.Set(root.Key([]byte("merkle")), []byte("tree")) + kvstore.Set(root.Key([]byte("block")), []byte("chain")) - root := commit(cms, Root{KeyPrefix: [][]byte{[]byte("test"), []byte{0x00}}}) + root = commit(cms, root) - v1, p1 := query(t, cms, "hello") + c1, v1, p1 := root.Query(cms, []byte("hello")) + require.Equal(t, uint32(0), c1) require.Equal(t, []byte("world"), v1) - v2, p2 := query(t, cms, "merkle") + c2, v2, p2 := root.Query(cms, []byte("merkle")) + require.Equal(t, uint32(0), c2) require.Equal(t, []byte("tree"), v2) - v3, p3 := query(t, cms, "block") + c3, v3, p3 := root.Query(cms, []byte("block")) + require.Equal(t, uint32(0), c3) require.Equal(t, []byte("chain"), v3) cstore, err := commitment.NewStore(root, []commitment.Proof{p1, p2, p3}) @@ -75,17 +64,20 @@ func TestStore(t *testing.T) { require.True(t, cstore.Prove([]byte("merkle"), []byte("tree"))) require.True(t, cstore.Prove([]byte("block"), []byte("chain"))) - kvstore.Set(key("12345"), []byte("67890")) - kvstore.Set(key("qwerty"), []byte("zxcv")) - kvstore.Set(key("hello"), []byte("dlrow")) + kvstore.Set(root.Key([]byte("12345")), []byte("67890")) + kvstore.Set(root.Key([]byte("qwerty")), []byte("zxcv")) + kvstore.Set(root.Key([]byte("hello")), []byte("dlrow")) root = commit(cms, root) - v1, p1 = query(t, cms, "12345") + c1, v1, p1 = root.Query(cms, []byte("12345")) + require.Equal(t, uint32(0), c1) require.Equal(t, []byte("67890"), v1) - v2, p2 = query(t, cms, "qwerty") + c2, v2, p2 = root.Query(cms, []byte("qwerty")) + require.Equal(t, uint32(0), c2) require.Equal(t, []byte("zxcv"), v2) - v3, p3 = query(t, cms, "hello") + c3, v3, p3 = root.Query(cms, []byte("hello")) + require.Equal(t, uint32(0), c3) require.Equal(t, []byte("dlrow"), v3) cstore, err = commitment.NewStore(root, []commitment.Proof{p1, p2, p3}) diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go new file mode 100644 index 000000000000..1fa13f6a3d32 --- /dev/null +++ b/x/ibc/23-commitment/merkle/utils.go @@ -0,0 +1,28 @@ +package merkle + +import ( + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/store/types" +) + +func (root Root) RequestQuery(key []byte) abci.RequestQuery { + path := "" + for _, inter := range root.KeyPath { + path = path + "/" + string(inter) + } + path = path + "/key" + + data := append(root.KeyPrefix, key...) + + return abci.RequestQuery{Path: path, Data: data, Prove: true} +} + +func (root Root) Query(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { + qres := cms.(types.Queryable).Query(root.RequestQuery(key)) + return qres.Code, qres.Value, Proof{Key: key, Proof: qres.Proof} +} + +func (root Root) Key(key []byte) []byte { + return append(root.KeyPrefix, key...) // XXX: cloneAppend +} From 70469532b0d98e76b0b5c038981029ab287fd226 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 19:12:24 +0200 Subject: [PATCH 022/378] add codec --- x/ibc/23-commitment/codec.go | 10 ++++++++++ x/ibc/23-commitment/merkle/codec.go | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 x/ibc/23-commitment/codec.go create mode 100644 x/ibc/23-commitment/merkle/codec.go diff --git a/x/ibc/23-commitment/codec.go b/x/ibc/23-commitment/codec.go new file mode 100644 index 000000000000..33d5bc490d39 --- /dev/null +++ b/x/ibc/23-commitment/codec.go @@ -0,0 +1,10 @@ +package commitment + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*Root)(nil), nil) + cdc.RegisterInterface((*Proof)(nil), nil) +} diff --git a/x/ibc/23-commitment/merkle/codec.go b/x/ibc/23-commitment/merkle/codec.go new file mode 100644 index 000000000000..a5e088650b0c --- /dev/null +++ b/x/ibc/23-commitment/merkle/codec.go @@ -0,0 +1,10 @@ +package merkle + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(Root{}, "ibc/commitment/merkle/Root", nil) + cdc.RegisterConcrete(Proof{}, "ibc/commitment/merkle/Proof", nil) +} From 46d228a8f3e86d250b3031134e70e120932b3c68 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 7 Jun 2019 23:47:01 +0200 Subject: [PATCH 023/378] add client --- x/ibc/02-client/manager.go | 146 ++++++++++++++++++++++++++++ x/ibc/02-client/tendermint/types.go | 79 +++++++++++++++ x/ibc/02-client/types.go | 46 +++++++++ 3 files changed, 271 insertions(+) create mode 100644 x/ibc/02-client/manager.go create mode 100644 x/ibc/02-client/tendermint/types.go create mode 100644 x/ibc/02-client/types.go diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go new file mode 100644 index 000000000000..89a8a878df49 --- /dev/null +++ b/x/ibc/02-client/manager.go @@ -0,0 +1,146 @@ +package client + +import ( + "errors" + "strconv" + + "github.com/cosmos/cosmos-sdk/store/mapping" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type IDGenerator func(sdk.Context /*Header,*/, mapping.Value) string + +func IntegerIDGenerator(ctx sdk.Context, v mapping.Value) string { + id := mapping.NewInteger(v, mapping.Dec).Incr(ctx) + return strconv.FormatUint(id, 10) +} + +type Manager struct { + protocol mapping.Mapping + + idval mapping.Value + idgen IDGenerator +} + +func NewManager(protocol, free mapping.Base, idgen IDGenerator) Manager { + return Manager{ + protocol: mapping.NewMapping(protocol, []byte("/")), + idval: mapping.NewValue(free, []byte("/id")), + idgen: idgen, + } +} + +/* +func (man Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { + if _, ok := man.pred[kind]; ok { + panic("Kind already registered") + } + man.pred[kind] = pred + return man +} +*/ +func (man Manager) object(id string) Object { + return Object{ + id: id, + client: man.protocol.Value([]byte(id)), + freeze: mapping.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), + } +} + +func (man Manager) Create(ctx sdk.Context, cs Client) string { + id := man.idgen(ctx, man.idval) + err := man.object(id).create(ctx, cs) + if err != nil { + panic(err) + } + return id +} + +func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { + res := man.object(id) + if !res.exists(ctx) { + return Object{}, errors.New("client not exists") + } + return res, nil +} + +type Object struct { + id string + client mapping.Value + freeze mapping.Boolean +} + +func (obj Object) create(ctx sdk.Context, st Client) error { + if obj.exists(ctx) { + return errors.New("Create client on already existing id") + } + obj.client.Set(ctx, st) + return nil +} + +func (obj Object) exists(ctx sdk.Context) bool { + return obj.client.Exists(ctx) +} + +func (obj Object) ID() string { + return obj.id +} + +func (obj Object) Value(ctx sdk.Context) (res Client) { + obj.client.Get(ctx, &res) + return +} + +func (obj Object) Is(ctx sdk.Context, client Client) bool { + return obj.client.Is(ctx, client) +} + +func (obj Object) Update(ctx sdk.Context, header Header) error { + if !obj.exists(ctx) { + panic("should not update nonexisting client") + } + + if obj.freeze.Get(ctx) { + return errors.New("client is frozen") + } + + var stored Client + obj.client.GetIfExists(ctx, &stored) + updated, err := stored.Validate(header) + if err != nil { + return err + } + + obj.client.Set(ctx, updated) + + return nil +} + +func (obj Object) Freeze(ctx sdk.Context) error { + if !obj.exists(ctx) { + panic("should not freeze nonexisting client") + } + + if obj.freeze.Get(ctx) { + return errors.New("client is already frozen") + } + + obj.freeze.Set(ctx, true) + + return nil +} + +func (obj Object) Delete(ctx sdk.Context) error { + if !obj.exists(ctx) { + panic("should not delete nonexisting client") + } + + if !obj.freeze.Get(ctx) { + return errors.New("client is not frozen") + } + + obj.client.Delete(ctx) + obj.freeze.Delete(ctx) + + return nil +} diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go new file mode 100644 index 000000000000..54655cf702d4 --- /dev/null +++ b/x/ibc/02-client/tendermint/types.go @@ -0,0 +1,79 @@ +package tendermint + +import ( + "bytes" + + "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +// Ref tendermint/lite/base_verifier.go + +var _ client.ValidityPredicateBase = ValidityPredicateBase{} + +type ValidityPredicateBase struct { + Height int64 + NextValidatorSet *types.ValidatorSet +} + +func (ValidityPredicateBase) Kind() client.Kind { + return client.Tendermint +} + +func (base ValidityPredicateBase) GetHeight() int64 { + return base.Height +} + +func (base ValidityPredicateBase) Equal(cbase client.ValidityPredicateBase) bool { + base0, ok := cbase.(ValidityPredicateBase) + if !ok { + return false + } + return base.Height == base0.Height && + bytes.Equal(base.NextValidatorSet.Hash(), base0.NextValidatorSet.Hash()) +} + +var _ client.Client = Client{} + +type Client struct { + Base ValidityPredicateBase + Root commitment.Root +} + +func (Client) Kind() client.Kind { + return client.Tendermint +} + +func (client Client) GetBase() client.ValidityPredicateBase { + return client.Base +} + +func (client Client) GetRoot() commitment.Root { + return client.Root +} + +func (client Client) Validate(header client.Header) (client.Client, error) { + return client, nil // XXX +} + +var _ client.Header = Header{} + +type Header struct { + Base ValidityPredicateBase + Root commitment.Root + Votes []*types.CommitSig +} + +func (header Header) Kind() client.Kind { + return client.Tendermint +} + +func (header Header) GetBase() client.ValidityPredicateBase { + return header.Base +} + +func (header Header) GetRoot() commitment.Root { + return header.Root +} diff --git a/x/ibc/02-client/types.go b/x/ibc/02-client/types.go new file mode 100644 index 000000000000..7b9f81ec7789 --- /dev/null +++ b/x/ibc/02-client/types.go @@ -0,0 +1,46 @@ +package client + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +// TODO: types in this file should be (de/)serialized with proto in the future + +type AminoMarshaler interface { + MarshalAmino() (string, error) + UnmarshalAmino(string) error +} + +type ValidityPredicateBase interface { + Kind() Kind + GetHeight() int64 + Equal(ValidityPredicateBase) bool +} + +// ConsensusState +type Client interface { + Kind() Kind + GetBase() ValidityPredicateBase + GetRoot() commitment.Root + Validate(Header) (Client, error) // ValidityPredicate +} + +func Equal(client1, client2 Client) bool { + return client1.Kind() == client2.Kind() && + client1.GetBase().Equal(client2.GetBase()) +} + +type Header interface { + Kind() Kind + // Proof() HeaderProof + GetBase() ValidityPredicateBase // can be nil + GetRoot() commitment.Root +} + +// XXX: Kind should be enum? + +type Kind byte + +const ( + Tendermint Kind = iota +) From 65a904a80964500bc127606c96df68fd6365c838 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 18:14:19 +0200 Subject: [PATCH 024/378] add counterpartymanager --- x/ibc/02-client/manager.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 89a8a878df49..97f281cc9596 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -6,6 +6,8 @@ import ( "github.com/cosmos/cosmos-sdk/store/mapping" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) type IDGenerator func(sdk.Context /*Header,*/, mapping.Value) string @@ -24,12 +26,22 @@ type Manager struct { func NewManager(protocol, free mapping.Base, idgen IDGenerator) Manager { return Manager{ - protocol: mapping.NewMapping(protocol, []byte("/")), - idval: mapping.NewValue(free, []byte("/id")), + protocol: mapping.NewMapping(protocol, []byte("/client")), + idval: mapping.NewValue(free, []byte("/client/id")), idgen: idgen, } } +type CounterpartyManager struct { + protocol commitment.Mapping +} + +func NewCounterpartyManager(protocol commitment.Base) CounterpartyManager { + return CounterpartyManager{ + protocol: commitment.NewMapping(protocol, []byte("/client")), + } +} + /* func (man Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { if _, ok := man.pred[kind]; ok { From 070e7d0df3574292c9913bafb9dab8e39043f5c6 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 18:29:24 +0200 Subject: [PATCH 025/378] fix manager --- x/ibc/02-client/manager.go | 16 ++++++++++++++++ x/ibc/23-commitment/value.go | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 97f281cc9596..c22576b18cd2 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -76,12 +76,28 @@ func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { return res, nil } +func (man CounterpartyManager) object(id string) CounterObject { + return CounterObject{ + id: id, + client: man.protocol.Value([]byte(id)), + } +} + +func (man CounterpartyManager) Query(id string) CounterObject { + return man.object(id) +} + type Object struct { id string client mapping.Value freeze mapping.Boolean } +type CounterObject struct { + id string + client commitment.Value +} + func (obj Object) create(ctx sdk.Context, st Client) error { if obj.exists(ctx) { return errors.New("Create client on already existing id") diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 70b8502a44e6..10b409b28b99 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -45,6 +45,13 @@ func NewMapping(base Base, prefix []byte) Mapping { } } +func (m Mapping) Value(key []byte) Value { + return Value{ + base: m.base, + key: key, + } +} + type Value struct { base Base key []byte From 99ad6d48153f93774da37ffdb2f57c8742d96545 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 18:44:25 +0200 Subject: [PATCH 026/378] add Is() to counterobject --- x/ibc/02-client/manager.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index c22576b18cd2..502478104757 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -123,6 +123,10 @@ func (obj Object) Is(ctx sdk.Context, client Client) bool { return obj.client.Is(ctx, client) } +func (obj CounterObject) Is(ctx sdk.Context, client Client) bool { + return obj.client.Is(ctx, client) +} + func (obj Object) Update(ctx sdk.Context, header Header) error { if !obj.exists(ctx) { panic("should not update nonexisting client") From 9956f0e310375b73e68e0e16c3404b156c38a090 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 12 Jun 2019 00:08:04 +0200 Subject: [PATCH 027/378] add readme, reflect ICS02 revision --- x/ibc/02-client/README.md | 49 ++++++++++++++++++++++++++++++++++++++ x/ibc/02-client/manager.go | 31 ++++++++++-------------- x/ibc/02-client/types.go | 26 ++++++++------------ 3 files changed, 72 insertions(+), 34 deletions(-) create mode 100644 x/ibc/02-client/README.md diff --git a/x/ibc/02-client/README.md b/x/ibc/02-client/README.md new file mode 100644 index 000000000000..a9bd6892771b --- /dev/null +++ b/x/ibc/02-client/README.md @@ -0,0 +1,49 @@ +# ICS 02: Client + +Package `client` defines types and method to store and update light clients which tracks on other chain's state. +The main type is `Client`, which provides `commitment.Root` to verify state proofs and `ConsensusState` to +verify header proofs. + +## Spec + +```typescript +interface ConsensusState { + height: uint64 + root: CommitmentRoot + validityPredicate: ValidityPredicate + eqivocationPredicate: EquivocationPredicate +} + +interface ClientState { + consensusState: ConsensusState + verifiedRoots: Map + frozen: bool +} + +interface Header { + height: uint64 + proof: HeaderProof + state: Maybe[ConsensusState] + root: CommitmentRoot +} + +type ValidityPredicate = (ConsensusState, Header) => Error | ConsensusState + +type EquivocationPredicate = (ConsensusState, Header, Header) => bool +``` + +## Impl + +### types.go + +`spec: interface ConsensusState` is implemented by `type ConsensusState`. `ConsensusState.{GetHeight(), GetRoot(), +Validate(), Equivocation()}` each corresponds to `spec: ConsensusState.{height, root, validityPredicate, +equivocationPredicate}`. `ConsensusState.Kind()` returns `Kind`, which is an enum indicating the type of the +consensus algorithm. + +`spec: interface Header` is implemented by `type Header`. `Header{GetHeight(), Proof(), State(), GetRoot()}` +each corresponds to `spec: Header.{height, proof, state, root}`. + +### manager.go + +`spec: interface ClientState` is implemented by `type Object`. // TODO diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 502478104757..0134d8340d55 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -10,6 +10,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) +// XXX: implement spec: ClientState.verifiedRoots + type IDGenerator func(sdk.Context /*Header,*/, mapping.Value) string func IntegerIDGenerator(ctx sdk.Context, v mapping.Value) string { @@ -59,13 +61,14 @@ func (man Manager) object(id string) Object { } } -func (man Manager) Create(ctx sdk.Context, cs Client) string { +func (man Manager) Create(ctx sdk.Context, cs ConsensusState) (Object, error) { id := man.idgen(ctx, man.idval) - err := man.object(id).create(ctx, cs) - if err != nil { - panic(err) + obj := man.object(id) + if obj.exists(ctx) { + return Object{}, errors.New("Create client on already existing id") } - return id + obj.client.Set(ctx, cs) + return obj, nil } func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { @@ -89,7 +92,7 @@ func (man CounterpartyManager) Query(id string) CounterObject { type Object struct { id string - client mapping.Value + client mapping.Value // ConsensusState freeze mapping.Boolean } @@ -98,14 +101,6 @@ type CounterObject struct { client commitment.Value } -func (obj Object) create(ctx sdk.Context, st Client) error { - if obj.exists(ctx) { - return errors.New("Create client on already existing id") - } - obj.client.Set(ctx, st) - return nil -} - func (obj Object) exists(ctx sdk.Context) bool { return obj.client.Exists(ctx) } @@ -114,16 +109,16 @@ func (obj Object) ID() string { return obj.id } -func (obj Object) Value(ctx sdk.Context) (res Client) { +func (obj Object) Value(ctx sdk.Context) (res ConsensusState) { obj.client.Get(ctx, &res) return } -func (obj Object) Is(ctx sdk.Context, client Client) bool { +func (obj Object) Is(ctx sdk.Context, client ConsensusState) bool { return obj.client.Is(ctx, client) } -func (obj CounterObject) Is(ctx sdk.Context, client Client) bool { +func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { return obj.client.Is(ctx, client) } @@ -136,7 +131,7 @@ func (obj Object) Update(ctx sdk.Context, header Header) error { return errors.New("client is frozen") } - var stored Client + var stored ConsensusState obj.client.GetIfExists(ctx, &stored) updated, err := stored.Validate(header) if err != nil { diff --git a/x/ibc/02-client/types.go b/x/ibc/02-client/types.go index 7b9f81ec7789..2ae484853354 100644 --- a/x/ibc/02-client/types.go +++ b/x/ibc/02-client/types.go @@ -5,35 +5,29 @@ import ( ) // TODO: types in this file should be (de/)serialized with proto in the future - -type AminoMarshaler interface { - MarshalAmino() (string, error) - UnmarshalAmino(string) error -} - -type ValidityPredicateBase interface { - Kind() Kind - GetHeight() int64 - Equal(ValidityPredicateBase) bool -} +// currently amkno codec handles it // ConsensusState -type Client interface { +type ConsensusState interface { Kind() Kind - GetBase() ValidityPredicateBase + GetHeight() uint64 GetRoot() commitment.Root - Validate(Header) (Client, error) // ValidityPredicate + Validate(Header) (ConsensusState, error) // ValidityPredicate + Equivocation(Header, Header) bool // EquivocationPredicate } -func Equal(client1, client2 Client) bool { +/* +func Equal(client1, client2 ConsensusState) bool { return client1.Kind() == client2.Kind() && client1.GetBase().Equal(client2.GetBase()) } +*/ type Header interface { Kind() Kind + GetHeight() uint64 // Proof() HeaderProof - GetBase() ValidityPredicateBase // can be nil + State() ConsensusState // can be nil GetRoot() commitment.Root } From 5f6391876a476f1d1beb75d8677716cfc67ee1e2 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 12 Jun 2019 00:28:13 +0200 Subject: [PATCH 028/378] reflect downstream ics --- x/ibc/02-client/manager.go | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 0134d8340d55..196d62e62fdc 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -4,7 +4,7 @@ import ( "errors" "strconv" - "github.com/cosmos/cosmos-sdk/store/mapping" + "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" @@ -12,24 +12,24 @@ import ( // XXX: implement spec: ClientState.verifiedRoots -type IDGenerator func(sdk.Context /*Header,*/, mapping.Value) string +type IDGenerator func(sdk.Context /*Header,*/, state.Value) string -func IntegerIDGenerator(ctx sdk.Context, v mapping.Value) string { - id := mapping.NewInteger(v, mapping.Dec).Incr(ctx) +func IntegerIDGenerator(ctx sdk.Context, v state.Value) string { + id := state.NewInteger(v, state.Dec).Incr(ctx) return strconv.FormatUint(id, 10) } type Manager struct { - protocol mapping.Mapping + protocol state.Mapping - idval mapping.Value + idval state.Value idgen IDGenerator } -func NewManager(protocol, free mapping.Base, idgen IDGenerator) Manager { +func NewManager(protocol, free state.Base, idgen IDGenerator) Manager { return Manager{ - protocol: mapping.NewMapping(protocol, []byte("/client")), - idval: mapping.NewValue(free, []byte("/client/id")), + protocol: state.NewMapping(protocol, []byte("/client")), + idval: state.NewValue(free, []byte("/client/id")), idgen: idgen, } } @@ -57,7 +57,7 @@ func (man Manager) object(id string) Object { return Object{ id: id, client: man.protocol.Value([]byte(id)), - freeze: mapping.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), + freeze: state.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), } } @@ -92,8 +92,8 @@ func (man CounterpartyManager) Query(id string) CounterObject { type Object struct { id string - client mapping.Value // ConsensusState - freeze mapping.Boolean + client state.Value // ConsensusState + freeze state.Boolean } type CounterObject struct { @@ -114,10 +114,6 @@ func (obj Object) Value(ctx sdk.Context) (res ConsensusState) { return } -func (obj Object) Is(ctx sdk.Context, client ConsensusState) bool { - return obj.client.Is(ctx, client) -} - func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { return obj.client.Is(ctx, client) } From ab3e4e6412a32f71e2a4a41e55a86adf324cd111 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 13 Jun 2019 16:00:18 +0200 Subject: [PATCH 029/378] test in progress --- x/ibc/02-client/tendermint/types.go | 96 ++++++----- x/ibc/02-client/tendermint/types_test.go | 131 ++++++++++++++ x/ibc/02-client/tendermint/valset_test.go | 197 ++++++++++++++++++++++ x/ibc/02-client/types.go | 3 - 4 files changed, 386 insertions(+), 41 deletions(-) create mode 100644 x/ibc/02-client/tendermint/types_test.go create mode 100644 x/ibc/02-client/tendermint/valset_test.go diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 54655cf702d4..1442d91d6c99 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -2,78 +2,98 @@ package tendermint import ( "bytes" + "errors" + "fmt" + lerr "github.com/tendermint/tendermint/lite/errors" "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -// Ref tendermint/lite/base_verifier.go - -var _ client.ValidityPredicateBase = ValidityPredicateBase{} +var _ client.ConsensusState = ConsensusState{} -type ValidityPredicateBase struct { - Height int64 +// Ref tendermint/lite/base_verifier.go +type ConsensusState struct { + ChainID string + Height uint64 + Root commitment.Root NextValidatorSet *types.ValidatorSet } -func (ValidityPredicateBase) Kind() client.Kind { +func (ConsensusState) Kind() client.Kind { return client.Tendermint } -func (base ValidityPredicateBase) GetHeight() int64 { - return base.Height +func (cs ConsensusState) GetHeight() uint64 { + return cs.Height } -func (base ValidityPredicateBase) Equal(cbase client.ValidityPredicateBase) bool { - base0, ok := cbase.(ValidityPredicateBase) - if !ok { - return false +func (cs ConsensusState) GetRoot() commitment.Root { + return cs.Root +} + +func (cs ConsensusState) update(header Header) ConsensusState { + return ConsensusState{ + ChainID: cs.ChainID, + Height: uint64(header.Height), + Root: header.AppHash, + NextValidatorSet: header.NextValidatorSet, } - return base.Height == base0.Height && - bytes.Equal(base.NextValidatorSet.Hash(), base0.NextValidatorSet.Hash()) } -var _ client.Client = Client{} +func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, error) { + header, ok := cheader.(Header) + if !ok { + return nil, errors.New("invalid type") + } -type Client struct { - Base ValidityPredicateBase - Root commitment.Root -} + nextvalset := cs.NextValidatorSet + nexthash := nextvalset.Hash() -func (Client) Kind() client.Kind { - return client.Tendermint -} + if cs.Height == uint64(header.Height-1) { + nexthash = cs.NextValidatorSet.Hash() + if !bytes.Equal(header.ValidatorsHash, nexthash) { + fmt.Println(111) + return nil, lerr.ErrUnexpectedValidators(header.ValidatorsHash, nexthash) + } + } -func (client Client) GetBase() client.ValidityPredicateBase { - return client.Base -} + if !bytes.Equal(header.NextValidatorsHash, header.NextValidatorSet.Hash()) { + fmt.Println(header) + return nil, lerr.ErrUnexpectedValidators(header.NextValidatorsHash, header.NextValidatorSet.Hash()) + } + + err := header.ValidateBasic(cs.ChainID) + if err != nil { + return nil, err + } -func (client Client) GetRoot() commitment.Root { - return client.Root + err = cs.NextValidatorSet.VerifyCommit(cs.ChainID, header.Commit.BlockID, header.Height, header.Commit) + if err != nil { + return nil, err + } + + return cs.update(header), nil } -func (client Client) Validate(header client.Header) (client.Client, error) { - return client, nil // XXX +func (cs ConsensusState) Equivocation(header1, header2 client.Header) bool { + return false // XXX } var _ client.Header = Header{} type Header struct { - Base ValidityPredicateBase - Root commitment.Root - Votes []*types.CommitSig + // XXX: don't take the entire struct + types.SignedHeader + NextValidatorSet *types.ValidatorSet } func (header Header) Kind() client.Kind { return client.Tendermint } -func (header Header) GetBase() client.ValidityPredicateBase { - return header.Base -} - -func (header Header) GetRoot() commitment.Root { - return header.Root +func (header Header) GetHeight() uint64 { + return uint64(header.Height) } diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go new file mode 100644 index 000000000000..44dc0fc9aba9 --- /dev/null +++ b/x/ibc/02-client/tendermint/types_test.go @@ -0,0 +1,131 @@ +package tendermint + +import ( + "testing" + + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store" + stypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const chainid = "testchain" + +func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { + key := sdk.NewKVStoreKey("ibc") + db := dbm.NewMemDB() + cms := store.NewCommitMultiStore(db) + cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) + err := cms.LoadLatestVersion() + if err != nil { + panic(err) + } + ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) + cdc := codec.New() + return key, ctx, cms, cdc +} + +type node struct { + valset MockValidators + + cms sdk.CommitMultiStore + store sdk.KVStore + + commits []tmtypes.SignedHeader +} + +func NewNode(valset MockValidators) *node { + key, ctx, cms, _ := defaultComponents() + return &node{ + valset: valset, + cms: cms, + store: ctx.KVStore(key), + commits: nil, + } +} + +func (node *node) last() tmtypes.SignedHeader { + if len(node.commits) == 0 { + return tmtypes.SignedHeader{} + } + return node.commits[len(node.commits)-1] +} + +func (node *node) Commit() tmtypes.SignedHeader { + valsethash := node.valset.ValidatorSet().Hash() + nextvalset := node.valset.Mutate(false) + nextvalsethash := nextvalset.ValidatorSet().Hash() + commitid := node.cms.Commit() + + header := tmtypes.Header{ + ChainID: chainid, + Height: int64(len(node.commits) + 1), + LastBlockID: tmtypes.BlockID{ + Hash: node.last().Header.Hash(), + }, + + ValidatorsHash: valsethash, + NextValidatorsHash: nextvalsethash, + AppHash: commitid.Hash, + } + + commit := node.valset.Sign(header) + + node.commits = append(node.commits, commit) + + return commit +} + +func (node *node) Set(key, value string) { + node.store.Set(append([]byte{0x00}, []byte(key)...), []byte(value)) +} + +type Verifier struct { + ConsensusState +} + +func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators) *Verifier { + return &Verifier{ + ConsensusState{ + ChainID: chainid, + Height: uint64(header.Height), + Root: header.AppHash, + NextValidatorSet: nextvalset.ValidatorSet(), + }, + } +} + +func (v *Verifier) Validate(header tmtypes.SignedHeader, nextvalset MockValidators) error { + newcs, err := v.ConsensusState.Validate( + Header{ + SignedHeader: header, + NextValidatorSet: nextvalset.ValidatorSet(), + }, + ) + if err != nil { + return err + } + v.ConsensusState = newcs.(ConsensusState) + + return nil +} + +func TestUpdate(t *testing.T) { + node := NewNode(NewMockValidators(100, 10)) + + node.Commit() + + verifier := NewVerifier(node.last(), node.valset) + + header := node.Commit() + + err := verifier.Validate(header, node.valset) + require.NoError(t, err) +} diff --git a/x/ibc/02-client/tendermint/valset_test.go b/x/ibc/02-client/tendermint/valset_test.go new file mode 100644 index 000000000000..10aa5dc0eae7 --- /dev/null +++ b/x/ibc/02-client/tendermint/valset_test.go @@ -0,0 +1,197 @@ +package tendermint + +import ( + "bytes" + "fmt" + "sort" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + tmtypes "github.com/tendermint/tendermint/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// reimplementing tmtypes.MockPV to make it marshallable +type mockPV struct { + PrivKey crypto.PrivKey +} + +var _ tmtypes.PrivValidator = (*mockPV)(nil) + +func newMockPV() *mockPV { + return &mockPV{ed25519.GenPrivKey()} +} + +func (pv *mockPV) GetAddress() tmtypes.Address { + return pv.PrivKey.PubKey().Address() +} + +func (pv *mockPV) GetPubKey() crypto.PubKey { + return pv.PrivKey.PubKey() +} + +func (pv *mockPV) SignVote(chainID string, vote *tmtypes.Vote) error { + signBytes := vote.SignBytes(chainID) + sig, err := pv.PrivKey.Sign(signBytes) + if err != nil { + return err + } + vote.Signature = sig + return nil +} + +func (pv *mockPV) SignProposal(string, *tmtypes.Proposal) error { + panic("not needed") +} + +// MockValset +type MockValidator struct { + MockPV *mockPV + Power sdk.Dec +} + +func NewMockValidator(power sdk.Dec) MockValidator { + return MockValidator{ + MockPV: newMockPV(), + Power: power, + } +} + +func (val MockValidator) GetOperator() sdk.ValAddress { + return sdk.ValAddress(val.MockPV.GetAddress()) +} + +func (val MockValidator) GetConsAddr() sdk.ConsAddress { + return sdk.GetConsAddress(val.MockPV.GetPubKey()) +} + +func (val MockValidator) GetConsPubKey() crypto.PubKey { + return val.MockPV.GetPubKey() +} + +func (val MockValidator) GetPower() sdk.Dec { + return val.Power +} + +func (val MockValidator) Validator() *tmtypes.Validator { + return tmtypes.NewValidator( + val.GetConsPubKey(), + val.GetPower().RoundInt64(), + ) +} + +type MockValidators []MockValidator + +var _ sort.Interface = MockValidators{} + +func NewMockValidators(num int, power int64) MockValidators { + res := make(MockValidators, num) + for i := range res { + res[i] = NewMockValidator(sdk.NewDec(power)) + } + + // ddd + fmt.Println(333) + for _, val := range res { + fmt.Println(val) + } + + // ddd + return res +} + +func (vals MockValidators) Len() int { + return len(vals) +} + +func (vals MockValidators) Less(i, j int) bool { + return bytes.Compare([]byte(vals[i].GetConsAddr()), []byte(vals[j].GetConsAddr())) == -1 +} + +func (vals MockValidators) Swap(i, j int) { + it := vals[j] + vals[j] = vals[i] + vals[i] = it +} + +func (vals MockValidators) TotalPower() sdk.Dec { + res := sdk.ZeroDec() + for _, val := range vals { + res = res.Add(val.Power) + } + return res +} + +func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { + precommits := make([]*tmtypes.CommitSig, len(vals)) + for i, val := range vals { + precommits[i] = (&tmtypes.Vote{ + BlockID: tmtypes.BlockID{ + Hash: header.Hash(), + }, + ValidatorAddress: val.MockPV.GetAddress(), + ValidatorIndex: i, + Height: header.Height, + Type: tmtypes.PrecommitType, + }).CommitSig() + val.MockPV.SignVote("", (*tmtypes.Vote)(precommits[i])) + } + + return tmtypes.SignedHeader{ + Header: &header, + Commit: &tmtypes.Commit{ + BlockID: tmtypes.BlockID{ + Hash: header.Hash(), + }, + Precommits: precommits, + }, + } +} + +// Mutate valset +func (vals MockValidators) Mutate(majority bool) MockValidators { + var num int + if majority { + num = len(vals) * 2 / 3 + } else { + num = len(vals) * 1 / 6 + } + + res := make(MockValidators, len(vals)) + + for i := 0; i < len(vals)-num; i++ { + res[i] = vals[num:][i] + } + + for i := len(vals) - num; i < len(vals); i++ { + res[i] = NewMockValidator(vals[0].Power) + } + + // ddd + fmt.Println(333) + for _, val := range res { + fmt.Println(val) + } + + // ddd + + return res +} + +func (vals MockValidators) ValidatorSet() *tmtypes.ValidatorSet { + tmvals := make([]*tmtypes.Validator, len(vals)) + + for i, val := range vals { + tmvals[i] = val.Validator() + } + + // ddd + fmt.Println(333444) + for _, val := range tmvals { + fmt.Println(val) + } + + // ddd + return tmtypes.NewValidatorSet(tmvals) +} diff --git a/x/ibc/02-client/types.go b/x/ibc/02-client/types.go index 2ae484853354..2a34855085b9 100644 --- a/x/ibc/02-client/types.go +++ b/x/ibc/02-client/types.go @@ -26,9 +26,6 @@ func Equal(client1, client2 ConsensusState) bool { type Header interface { Kind() Kind GetHeight() uint64 - // Proof() HeaderProof - State() ConsensusState // can be nil - GetRoot() commitment.Root } // XXX: Kind should be enum? From e7dde7881baf8bef52661b3260b03f50019ed363 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 13 Jun 2019 19:08:13 +0200 Subject: [PATCH 030/378] add test --- x/ibc/02-client/tendermint/types.go | 6 +- x/ibc/02-client/tendermint/types_test.go | 108 +++++++++++++++++++--- x/ibc/02-client/tendermint/valset_test.go | 46 +++------ 3 files changed, 114 insertions(+), 46 deletions(-) diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 1442d91d6c99..8dd3cfca7294 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -3,7 +3,6 @@ package tendermint import ( "bytes" "errors" - "fmt" lerr "github.com/tendermint/tendermint/lite/errors" "github.com/tendermint/tendermint/types" @@ -55,13 +54,11 @@ func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, if cs.Height == uint64(header.Height-1) { nexthash = cs.NextValidatorSet.Hash() if !bytes.Equal(header.ValidatorsHash, nexthash) { - fmt.Println(111) return nil, lerr.ErrUnexpectedValidators(header.ValidatorsHash, nexthash) } } if !bytes.Equal(header.NextValidatorsHash, header.NextValidatorSet.Hash()) { - fmt.Println(header) return nil, lerr.ErrUnexpectedValidators(header.NextValidatorsHash, header.NextValidatorSet.Hash()) } @@ -70,7 +67,7 @@ func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, return nil, err } - err = cs.NextValidatorSet.VerifyCommit(cs.ChainID, header.Commit.BlockID, header.Height, header.Commit) + err = cs.NextValidatorSet.VerifyFutureCommit(header.ValidatorSet, cs.ChainID, header.Commit.BlockID, header.Height, header.Commit) if err != nil { return nil, err } @@ -87,6 +84,7 @@ var _ client.Header = Header{} type Header struct { // XXX: don't take the entire struct types.SignedHeader + ValidatorSet *types.ValidatorSet NextValidatorSet *types.ValidatorSet } diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go index 44dc0fc9aba9..14ca7adad0ea 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/types_test.go @@ -1,11 +1,13 @@ package tendermint import ( + "math/rand" "testing" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + cmn "github.com/tendermint/tendermint/libs/common" dbm "github.com/tendermint/tendermint/libs/db" "github.com/tendermint/tendermint/libs/log" tmtypes "github.com/tendermint/tendermint/types" @@ -14,6 +16,9 @@ import ( "github.com/cosmos/cosmos-sdk/store" stypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) const chainid = "testchain" @@ -33,7 +38,8 @@ func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *c } type node struct { - valset MockValidators + prevvalset MockValidators + valset MockValidators cms sdk.CommitMultiStore store sdk.KVStore @@ -60,7 +66,7 @@ func (node *node) last() tmtypes.SignedHeader { func (node *node) Commit() tmtypes.SignedHeader { valsethash := node.valset.ValidatorSet().Hash() - nextvalset := node.valset.Mutate(false) + nextvalset := node.valset.Mutate() nextvalsethash := nextvalset.ValidatorSet().Hash() commitid := node.cms.Commit() @@ -78,15 +84,13 @@ func (node *node) Commit() tmtypes.SignedHeader { commit := node.valset.Sign(header) + node.prevvalset = node.valset + node.valset = nextvalset node.commits = append(node.commits, commit) return commit } -func (node *node) Set(key, value string) { - node.store.Set(append([]byte{0x00}, []byte(key)...), []byte(value)) -} - type Verifier struct { ConsensusState } @@ -102,10 +106,11 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators) *Verifi } } -func (v *Verifier) Validate(header tmtypes.SignedHeader, nextvalset MockValidators) error { +func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset MockValidators) error { newcs, err := v.ConsensusState.Validate( Header{ SignedHeader: header, + ValidatorSet: valset.ValidatorSet(), NextValidatorSet: nextvalset.ValidatorSet(), }, ) @@ -117,15 +122,96 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, nextvalset MockValidato return nil } -func TestUpdate(t *testing.T) { +func testUpdate(t *testing.T, interval int, ok bool) { node := NewNode(NewMockValidators(100, 10)) node.Commit() verifier := NewVerifier(node.last(), node.valset) - header := node.Commit() + for i := 0; i < 100; i++ { + header := node.Commit() + + if i%interval == 0 { + err := verifier.Validate(header, node.prevvalset, node.valset) + if ok { + require.NoError(t, err) + } else { + require.Error(t, err) + } + } + } +} + +func TestEveryBlockUpdate(t *testing.T) { + testUpdate(t, 1, true) +} + +func TestEvenBlockUpdate(t *testing.T) { + testUpdate(t, 2, true) +} + +func TestSixthBlockUpdate(t *testing.T) { + testUpdate(t, 6, true) +} + +/* +// This should fail, since the amount of mutation is so large +// Commented out because it sometimes success +func TestTenthBlockUpdate(t *testing.T) { + testUpdate(t, 10, false) +} +*/ + +func key(str []byte) []byte { + return append([]byte{0x00}, str...) +} + +func (node *node) query(t *testing.T, k []byte) ([]byte, commitment.Proof) { + qres := node.cms.(stypes.Queryable).Query(abci.RequestQuery{Path: "/ibc/key", Data: key(k), Prove: true}) + require.Equal(t, uint32(0), qres.Code, qres.Log) + proof := merkle.Proof{ + Key: []byte(k), + Proof: qres.Proof, + } + return qres.Value, proof +} + +func (node *node) Set(k, value []byte) { + node.store.Set(key(k), value) +} + +func testProof(t *testing.T) { + node := NewNode(NewMockValidators(100, 10)) + + node.Commit() + + kvps := cmn.KVPairs{} + for h := 0; h < 20; h++ { + for i := 0; i < 100; i++ { + k := make([]byte, 32) + v := make([]byte, 32) + rand.Read(k) + rand.Read(v) + kvps = append(kvps, cmn.KVPair{Key: k, Value: v}) + node.Set(k, v) + } + header := node.Commit() + proofs := []commitment.Proof{} + for _, kvp := range kvps { + v, p := node.query(t, []byte(kvp.Key)) + require.Equal(t, kvp.Value, v) + proofs = append(proofs, p) + } + cstore, err := commitment.NewStore([]byte(header.AppHash), proofs) + require.NoError(t, err) + + for _, kvp := range kvps { + require.True(t, cstore.Prove(kvp.Key, kvp.Value)) + } + } +} - err := verifier.Validate(header, node.valset) - require.NoError(t, err) +func TestProofs(t *testing.T) { + testProof(t) } diff --git a/x/ibc/02-client/tendermint/valset_test.go b/x/ibc/02-client/tendermint/valset_test.go index 10aa5dc0eae7..5649a3533273 100644 --- a/x/ibc/02-client/tendermint/valset_test.go +++ b/x/ibc/02-client/tendermint/valset_test.go @@ -2,7 +2,6 @@ package tendermint import ( "bytes" - "fmt" "sort" "github.com/tendermint/tendermint/crypto" @@ -91,13 +90,8 @@ func NewMockValidators(num int, power int64) MockValidators { res[i] = NewMockValidator(sdk.NewDec(power)) } - // ddd - fmt.Println(333) - for _, val := range res { - fmt.Println(val) - } + sort.Sort(res) - // ddd return res } @@ -124,9 +118,10 @@ func (vals MockValidators) TotalPower() sdk.Dec { } func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { + precommits := make([]*tmtypes.CommitSig, len(vals)) for i, val := range vals { - precommits[i] = (&tmtypes.Vote{ + vote := &tmtypes.Vote{ BlockID: tmtypes.BlockID{ Hash: header.Hash(), }, @@ -134,8 +129,9 @@ func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { ValidatorIndex: i, Height: header.Height, Type: tmtypes.PrecommitType, - }).CommitSig() - val.MockPV.SignVote("", (*tmtypes.Vote)(precommits[i])) + } + val.MockPV.SignVote(chainid, vote) + precommits[i] = vote.CommitSig() } return tmtypes.SignedHeader{ @@ -150,13 +146,8 @@ func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { } // Mutate valset -func (vals MockValidators) Mutate(majority bool) MockValidators { - var num int - if majority { - num = len(vals) * 2 / 3 - } else { - num = len(vals) * 1 / 6 - } +func (vals MockValidators) Mutate() MockValidators { + num := len(vals) / 20 // 5% change each block res := make(MockValidators, len(vals)) @@ -168,15 +159,15 @@ func (vals MockValidators) Mutate(majority bool) MockValidators { res[i] = NewMockValidator(vals[0].Power) } - // ddd - fmt.Println(333) - for _, val := range res { - fmt.Println(val) - } + sort.Sort(res) - // ddd + for i, val := range vals { + if val != res[i] { + return res + } + } - return res + panic("not mutated") } func (vals MockValidators) ValidatorSet() *tmtypes.ValidatorSet { @@ -186,12 +177,5 @@ func (vals MockValidators) ValidatorSet() *tmtypes.ValidatorSet { tmvals[i] = val.Validator() } - // ddd - fmt.Println(333444) - for _, val := range tmvals { - fmt.Println(val) - } - - // ddd return tmtypes.NewValidatorSet(tmvals) } From 579060f5cd03cb95ed05e8727a166f07c1a4f21f Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 19 Jun 2019 13:07:06 +0100 Subject: [PATCH 031/378] in progres --- x/ibc/client/cli/query.go | 216 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 x/ibc/client/cli/query.go diff --git a/x/ibc/client/cli/query.go b/x/ibc/client/cli/query.go new file mode 100644 index 000000000000..ca979151c499 --- /dev/null +++ b/x/ibc/client/cli/query.go @@ -0,0 +1,216 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + tmtypes "github.com/tendermint/tendermint/types" + + "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/02-client/tendermint" + ibc "github.com/cosmos/cosmos-sdk/x/ibc/keeper" +) + +func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ibcQueryCmd := &cobra.Command{ + Use: "ibc", + Short: "IBC query subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + ibcQueryCmd.AddCommand(client.GetCommands( + GetCmdQueryConsensusState(cdc), + GetCmdQueryHeader(cdc), + GetCmdQueryClient(cdc), + GetCmdQueryConnection(cdc), + GetCmdQueryChannel(cdc), + )...) + return ibcQueryCmd +} + +func GetCmdQueryClient(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "client", + Short: "Query stored client", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + keeper := ibc.DummyKeeper() + + var state ibc.ConsensusState + statebz, _, err := query(ctx, keeper.Client.Object(args[0]).Key()) + if err != nil { + return err + } + cdc.MustUnmarshalBinaryBare(statebz, &state) + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + + return nil + }, + } +} + +func GetCmdQueryConsensusState(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "consensus-state", + Short: "Query the latest consensus state of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + node, err := ctx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return err + } + + state := tendermint.ConsensusState{ + ChainID: commit.ChainID, + Height: uint64(commit.Height), + Root: []byte(commit.AppHash), + NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + + return nil + }, + } +} + +func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "header", + Short: "Query the latest header of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + node, err := ctx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return err + } + + nextvalidators, err := node.Validators(&height) + if err != nil { + return err + } + + header := tendermint.Header{ + SignedHeader: commit.SignedHeader, + ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) + + return nil + }, + } +} + +func GetCmdQueryConnection(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "connection", + Short: "Query an existing connection", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + keeper := ibc.DummyKeeper() + + var conn ibc.Connection + connbz, _, err := query(ctx, keeper.Connection.Object(args[0]).Key()) + if err != nil { + return err + } + cdc.MustUnmarshalBinaryBare(connbz, &conn) + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, conn)) + + return nil + }, + } +} + +func GetCmdQueryChannel(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "channel", + Short: "Query an existing channel", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + keeper := ibc.DummyKeeper() + + var conn ibc.Channel + connbz, _, err := query(ctx, keeper.Channel.Object(args[0], args[1]).Key()) + if err != nil { + return err + } + cdc.MustUnmarshalBinaryBare(connbz, &conn) + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, conn)) + + return nil + }, + } +} + +func GetCmdQuerySendSequence(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "send-sequence", + Short: "Query the send sequence of a channel", + Args: cobra.ExactArgs(), + RunE: func(cmd *cobra.Command, args []string) error { + + }, + } +} + +func GetCmdQueryReceiveSequence(cdc *codec.Codec) *cobra.Command { + +} + +func GetCmdQueryPacket(cdc *codec.Codec) *cobra.Command { +} From b3f4ef5b4216cf587c8cb7f9acc637b24243b35e Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 12:20:15 +0200 Subject: [PATCH 032/378] fin rebase --- x/ibc/02-client/tendermint/types.go | 2 +- x/ibc/02-client/tendermint/types_test.go | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 8dd3cfca7294..26a4c35370e6 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -37,7 +37,7 @@ func (cs ConsensusState) update(header Header) ConsensusState { return ConsensusState{ ChainID: cs.ChainID, Height: uint64(header.Height), - Root: header.AppHash, + Root: cs.GetRoot().Update(header.AppHash), NextValidatorSet: header.NextValidatorSet, } } diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go index 14ca7adad0ea..8bde76d10302 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/types_test.go @@ -24,7 +24,7 @@ import ( const chainid = "testchain" func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { - key := sdk.NewKVStoreKey("ibc") + key := sdk.NewKVStoreKey("test") db := dbm.NewMemDB() cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) @@ -91,6 +91,13 @@ func (node *node) Commit() tmtypes.SignedHeader { return commit } +func keyPrefix() [][]byte { + return [][]byte{ + []byte("test"), + []byte{0x00}, + } +} + type Verifier struct { ConsensusState } @@ -100,7 +107,7 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators) *Verifi ConsensusState{ ChainID: chainid, Height: uint64(header.Height), - Root: header.AppHash, + Root: merkle.NewRoot(header.AppHash, keyPrefix()), NextValidatorSet: nextvalset.ValidatorSet(), }, } @@ -168,7 +175,7 @@ func key(str []byte) []byte { } func (node *node) query(t *testing.T, k []byte) ([]byte, commitment.Proof) { - qres := node.cms.(stypes.Queryable).Query(abci.RequestQuery{Path: "/ibc/key", Data: key(k), Prove: true}) + qres := node.cms.(stypes.Queryable).Query(abci.RequestQuery{Path: "/test/key", Data: key(k), Prove: true}) require.Equal(t, uint32(0), qres.Code, qres.Log) proof := merkle.Proof{ Key: []byte(k), @@ -203,7 +210,7 @@ func testProof(t *testing.T) { require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } - cstore, err := commitment.NewStore([]byte(header.AppHash), proofs) + cstore, err := commitment.NewStore(merkle.NewRoot([]byte(header.AppHash), keyPrefix()), proofs) require.NoError(t, err) for _, kvp := range kvps { From 7b745573c0eebb8692830b01e87fd8a5389ece8d Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 16:07:00 +0200 Subject: [PATCH 033/378] in progress --- x/ibc/02-client/cli.go | 18 ++++++++++ x/ibc/02-client/manager.go | 34 ++++++++++--------- x/ibc/02-client/tendermint/types_test.go | 42 ++++++++++-------------- 3 files changed, 54 insertions(+), 40 deletions(-) create mode 100644 x/ibc/02-client/cli.go diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go new file mode 100644 index 000000000000..5c245ba0378e --- /dev/null +++ b/x/ibc/02-client/cli.go @@ -0,0 +1,18 @@ +package client + +import () + +// CLIObject stores the key for each object fields +type CLIObject struct { + ID string + ConsensusState []byte + Frozen []byte +} + +func (object Object) CLI() CLIObject { + return CLIObject{ + ID: object.id, + ConsensusState: object.consensusState.Key(), + Frozen: object.frozen.Key(), + } +} diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 196d62e62fdc..a99a4bcc785c 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -55,9 +55,9 @@ func (man Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { */ func (man Manager) object(id string) Object { return Object{ - id: id, - client: man.protocol.Value([]byte(id)), - freeze: state.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), + id: id, + consensusState: man.protocol.Value([]byte(id)), + frozen: state.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), } } @@ -67,7 +67,7 @@ func (man Manager) Create(ctx sdk.Context, cs ConsensusState) (Object, error) { if obj.exists(ctx) { return Object{}, errors.New("Create client on already existing id") } - obj.client.Set(ctx, cs) + obj.consensusState.Set(ctx, cs) return obj, nil } @@ -91,9 +91,9 @@ func (man CounterpartyManager) Query(id string) CounterObject { } type Object struct { - id string - client state.Value // ConsensusState - freeze state.Boolean + id string + consensusState state.Value // ConsensusState + frozen state.Boolean } type CounterObject struct { @@ -101,34 +101,38 @@ type CounterObject struct { client commitment.Value } -func (obj Object) exists(ctx sdk.Context) bool { - return obj.client.Exists(ctx) -} - func (obj Object) ID() string { return obj.id } -func (obj Object) Value(ctx sdk.Context) (res ConsensusState) { - obj.client.Get(ctx, &res) +func (obj Object) ConsensusState(ctx sdk.Context) (res ConsensusState) { + obj.consensusState.Get(ctx, &res) return } +func (obj Object) Frozen(ctx sdk.Context) bool { + return obj.frozen.Get(ctx) +} + func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { return obj.client.Is(ctx, client) } +func (obj Object) exists(ctx sdk.Context) bool { + return obj.consensusState.Exists(ctx) +} + func (obj Object) Update(ctx sdk.Context, header Header) error { if !obj.exists(ctx) { panic("should not update nonexisting client") } - if obj.freeze.Get(ctx) { + if obj.Frozen(ctx) { return errors.New("client is frozen") } var stored ConsensusState - obj.client.GetIfExists(ctx, &stored) + obj.client.Get(ctx, &stored) updated, err := stored.Validate(header) if err != nil { return err diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go index 8bde76d10302..3cb99f52b549 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/types_test.go @@ -91,23 +91,16 @@ func (node *node) Commit() tmtypes.SignedHeader { return commit } -func keyPrefix() [][]byte { - return [][]byte{ - []byte("test"), - []byte{0x00}, - } -} - type Verifier struct { ConsensusState } -func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators) *Verifier { +func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root merkle.Root) *Verifier { return &Verifier{ ConsensusState{ ChainID: chainid, Height: uint64(header.Height), - Root: merkle.NewRoot(header.AppHash, keyPrefix()), + Root: root.Update(header.AppHash), NextValidatorSet: nextvalset.ValidatorSet(), }, } @@ -129,12 +122,18 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset Mock return nil } +func newRoot() merkle.Root { + return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) +} + func testUpdate(t *testing.T, interval int, ok bool) { node := NewNode(NewMockValidators(100, 10)) node.Commit() - verifier := NewVerifier(node.last(), node.valset) + root := newRoot() + + verifier := NewVerifier(node.last(), node.valset, root) for i := 0; i < 100; i++ { header := node.Commit() @@ -170,22 +169,14 @@ func TestTenthBlockUpdate(t *testing.T) { } */ -func key(str []byte) []byte { - return append([]byte{0x00}, str...) -} - -func (node *node) query(t *testing.T, k []byte) ([]byte, commitment.Proof) { - qres := node.cms.(stypes.Queryable).Query(abci.RequestQuery{Path: "/test/key", Data: key(k), Prove: true}) - require.Equal(t, uint32(0), qres.Code, qres.Log) - proof := merkle.Proof{ - Key: []byte(k), - Proof: qres.Proof, - } - return qres.Value, proof +func (node *node) query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { + code, value, proof := root.Query(node.cms, k) + require.Equal(t, uint32(0), code) + return value, proof } func (node *node) Set(k, value []byte) { - node.store.Set(key(k), value) + node.store.Set(newRoot().Key(k), value) } func testProof(t *testing.T) { @@ -205,12 +196,13 @@ func testProof(t *testing.T) { } header := node.Commit() proofs := []commitment.Proof{} + root := newRoot().Update(header.AppHash) for _, kvp := range kvps { - v, p := node.query(t, []byte(kvp.Key)) + v, p := node.query(t, root.(merkle.Root), []byte(kvp.Key)) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } - cstore, err := commitment.NewStore(merkle.NewRoot([]byte(header.AppHash), keyPrefix()), proofs) + cstore, err := commitment.NewStore(root, proofs) require.NoError(t, err) for _, kvp := range kvps { From b596fe1f5f3b967a2f02266220299f4bd21b4ff3 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 16:15:17 +0200 Subject: [PATCH 034/378] fin rebase --- x/ibc/02-client/manager.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index a99a4bcc785c..e94d14702b72 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -81,8 +81,8 @@ func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { func (man CounterpartyManager) object(id string) CounterObject { return CounterObject{ - id: id, - client: man.protocol.Value([]byte(id)), + id: id, + consensusState: man.protocol.Value([]byte(id)), } } @@ -97,8 +97,8 @@ type Object struct { } type CounterObject struct { - id string - client commitment.Value + id string + consensusState commitment.Value } func (obj Object) ID() string { @@ -115,7 +115,7 @@ func (obj Object) Frozen(ctx sdk.Context) bool { } func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { - return obj.client.Is(ctx, client) + return obj.consensusState.Is(ctx, client) } func (obj Object) exists(ctx sdk.Context) bool { @@ -132,13 +132,13 @@ func (obj Object) Update(ctx sdk.Context, header Header) error { } var stored ConsensusState - obj.client.Get(ctx, &stored) + obj.consensusState.Get(ctx, &stored) updated, err := stored.Validate(header) if err != nil { return err } - obj.client.Set(ctx, updated) + obj.consensusState.Set(ctx, updated) return nil } @@ -148,11 +148,11 @@ func (obj Object) Freeze(ctx sdk.Context) error { panic("should not freeze nonexisting client") } - if obj.freeze.Get(ctx) { + if obj.Frozen(ctx) { return errors.New("client is already frozen") } - obj.freeze.Set(ctx, true) + obj.frozen.Set(ctx, true) return nil } @@ -162,12 +162,12 @@ func (obj Object) Delete(ctx sdk.Context) error { panic("should not delete nonexisting client") } - if !obj.freeze.Get(ctx) { + if !obj.Frozen(ctx) { return errors.New("client is not frozen") } - obj.client.Delete(ctx) - obj.freeze.Delete(ctx) + obj.consensusState.Delete(ctx) + obj.frozen.Delete(ctx) return nil } From d41b9844738b743cedba55e7a6a132e33a279e39 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 17:10:21 +0200 Subject: [PATCH 035/378] add CLIObject in progress --- client/context/query.go | 38 ++++++++++++++++++----------- x/ibc/02-client/cli.go | 24 ++++++++++++------ x/ibc/23-commitment/merkle/utils.go | 6 ++++- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 87f96aece166..1e52442c6c61 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -31,21 +31,31 @@ func (ctx CLIContext) GetNode() (rpcclient.Client, error) { // Query performs a query to a Tendermint node with the provided path. // It returns the result and height of the query upon success or an error if // the query fails. -func (ctx CLIContext) Query(path string) ([]byte, int64, error) { - return ctx.query(path, nil) +func (ctx CLIContext) Query(path string) (val []byte, height int64, err error) { + val, _, height, err = ctx.query(path, nil) + return } // QueryWithData performs a query to a Tendermint node with the provided path // and a data payload. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryWithData(path string, data []byte) ([]byte, int64, error) { - return ctx.query(path, data) +func (ctx CLIContext) QueryWithData(path string, data []byte) (val []byte, height int64, err error) { + val, _, height, err = ctx.query(path, data) + return } // QueryStore performs a query to a Tendermint node with the provided key and // store name. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, int64, error) { +func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (val []byte, height int64, err error) { + val, _, height, err = ctx.queryStore(key, storeName, "key") + return +} + +// QueryProof performs a query to a Tendermint node with the provided key and +// store name. It returns the result, the proof, and height of the query +// upon success or an error if the query fails. +func (ctx CLIContext) QueryProof(key cmn.HexBytes, storeName string) (val []byte, proof *merkle.Proof, height int64, err error) { return ctx.queryStore(key, storeName, "key") } @@ -53,7 +63,7 @@ func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, in // store name and subspace. It returns key value pair and height of the query // upon success or an error if the query fails. func (ctx CLIContext) QuerySubspace(subspace []byte, storeName string) (res []sdk.KVPair, height int64, err error) { - resRaw, height, err := ctx.queryStore(subspace, storeName, "subspace") + resRaw, _, height, err := ctx.queryStore(subspace, storeName, "subspace") if err != nil { return res, height, err } @@ -75,10 +85,10 @@ func (ctx CLIContext) GetFromName() string { // query performs a query to a Tendermint node with the provided store name // and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) { +func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, proof *merkle.Proof, height int64, err error) { node, err := ctx.GetNode() if err != nil { - return res, height, err + return res, proof, height, err } opts := rpcclient.ABCIQueryOptions{ @@ -88,25 +98,25 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height i result, err := node.ABCIQueryWithOptions(path, key, opts) if err != nil { - return res, height, err + return res, proof, height, err } resp := result.Response if !resp.IsOK() { - return res, height, errors.New(resp.Log) + return res, proof, height, errors.New(resp.Log) } // data from trusted node or subspace query doesn't need verification if ctx.TrustNode || !isQueryStoreWithProof(path) { - return resp.Value, resp.Height, nil + return resp.Value, resp.Proof, resp.Height, nil } err = ctx.verifyProof(path, resp) if err != nil { - return res, height, err + return res, proof, height, err } - return resp.Value, resp.Height, nil + return resp.Value, resp.Proof, resp.Height, nil } // Verify verifies the consensus proof at given height. @@ -165,7 +175,7 @@ func (ctx CLIContext) verifyProof(queryPath string, resp abci.ResponseQuery) err // queryStore performs a query to a Tendermint node with the provided a store // name and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, int64, error) { +func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, *merkle.Proof, int64, error) { path := fmt.Sprintf("/store/%s/%s", storeName, endPath) return ctx.query(path, key) } diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 5c245ba0378e..8767c3032724 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -1,18 +1,26 @@ package client -import () +import ( + "github.com/cosmos/cosmos-sdk/client/context" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) // CLIObject stores the key for each object fields type CLIObject struct { - ID string - ConsensusState []byte - Frozen []byte + ID string + ConsensusStateKey []byte + FrozenKey []byte } -func (object Object) CLI() CLIObject { +func (obj Object) CLI() CLIObject { return CLIObject{ - ID: object.id, - ConsensusState: object.consensusState.Key(), - Frozen: object.frozen.Key(), + ID: obj.id, + ConsensusStateKey: obj.consensusState.Key(), + FrozenKey: obj.frozen.Key(), } } + +func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle..Proof) { + val, proof, _, err := ctx.QueryProof(obj.ConsensusStateKey) +} diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index 1fa13f6a3d32..71650d987f22 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -23,6 +23,10 @@ func (root Root) Query(cms types.CommitMultiStore, key []byte) (uint32, []byte, return qres.Code, qres.Value, Proof{Key: key, Proof: qres.Proof} } -func (root Root) Key(key []byte) []byte { +func (root Root) QueryKey(key []byte) []byte { return append(root.KeyPrefix, key...) // XXX: cloneAppend } + +func (root Root) QueryPath() []byte { + +} From 4ed87ef649ea163b6295509f37f6c9334d74a544 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 15:19:42 +0200 Subject: [PATCH 036/378] cli in progress --- client/context/query.go | 69 ++++++++++++++++------------- store/state/types.go | 5 +++ x/ibc/02-client/cli.go | 34 +++++++++++++- x/ibc/23-commitment/merkle/utils.go | 6 +++ 4 files changed, 82 insertions(+), 32 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 1e52442c6c61..4738808ba4fe 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -31,39 +31,35 @@ func (ctx CLIContext) GetNode() (rpcclient.Client, error) { // Query performs a query to a Tendermint node with the provided path. // It returns the result and height of the query upon success or an error if // the query fails. -func (ctx CLIContext) Query(path string) (val []byte, height int64, err error) { - val, _, height, err = ctx.query(path, nil) - return +func (ctx CLIContext) Query(path string) ([]byte, int64, error) { + return ctx.query(path, nil) } // QueryWithData performs a query to a Tendermint node with the provided path // and a data payload. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryWithData(path string, data []byte) (val []byte, height int64, err error) { - val, _, height, err = ctx.query(path, data) - return +func (ctx CLIContext) QueryWithData(path string, data []byte) ([]byte, int64, error) { + return ctx.query(path, data) } // QueryStore performs a query to a Tendermint node with the provided key and // store name. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (val []byte, height int64, err error) { - val, _, height, err = ctx.queryStore(key, storeName, "key") - return +func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, int64, error) { + return ctx.queryStore(key, storeName, "key") } -// QueryProof performs a query to a Tendermint node with the provided key and -// store name. It returns the result, the proof, and height of the query -// upon success or an error if the query fails. -func (ctx CLIContext) QueryProof(key cmn.HexBytes, storeName string) (val []byte, proof *merkle.Proof, height int64, err error) { - return ctx.queryStore(key, storeName, "key") +// QueryABCI performs a query to a Tendermint node with the provide RequestQuery. +// It returns the ResultQuery obtained from the query. +func (ctx CLIContext) QueryABCI(req abci.RequestQuery) (abci.ResponseQuery, error) { + return ctx.queryABCI(req) } // QuerySubspace performs a query to a Tendermint node with the provided // store name and subspace. It returns key value pair and height of the query // upon success or an error if the query fails. func (ctx CLIContext) QuerySubspace(subspace []byte, storeName string) (res []sdk.KVPair, height int64, err error) { - resRaw, _, height, err := ctx.queryStore(subspace, storeName, "subspace") + resRaw, height, err := ctx.queryStore(subspace, storeName, "subspace") if err != nil { return res, height, err } @@ -82,13 +78,10 @@ func (ctx CLIContext) GetFromName() string { return ctx.FromName } -// query performs a query to a Tendermint node with the provided store name -// and path. It returns the result and height of the query upon success -// or an error if the query fails. -func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, proof *merkle.Proof, height int64, err error) { +func (ctx CLIContext) queryABCI(req abci.RequestQuery) (resp abci.ResponseQuery, err error) { node, err := ctx.GetNode() if err != nil { - return res, proof, height, err + return } opts := rpcclient.ABCIQueryOptions{ @@ -96,27 +89,43 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, proof *m Prove: !ctx.TrustNode, } - result, err := node.ABCIQueryWithOptions(path, key, opts) + result, err := node.ABCIQueryWithOptions(req.Path, req.Data, opts) if err != nil { - return res, proof, height, err + return } - resp := result.Response + resp = result.Response if !resp.IsOK() { - return res, proof, height, errors.New(resp.Log) + err = errors.New(resp.Log) + return } // data from trusted node or subspace query doesn't need verification - if ctx.TrustNode || !isQueryStoreWithProof(path) { - return resp.Value, resp.Proof, resp.Height, nil + if ctx.TrustNode || !isQueryStoreWithProof(req.Path) { + return resp, nil } - err = ctx.verifyProof(path, resp) + err = ctx.verifyProof(req.Path, resp) + if err != nil { + return + } + + return +} + +// query performs a query to a Tendermint node with the provided store name +// and path. It returns the result and height of the query upon success +// or an error if the query fails. +func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) { + resp, err := ctx.queryABCI(abci.RequestQuery{ + Path: path, + Data: key, + }) if err != nil { - return res, proof, height, err + return } - return resp.Value, resp.Proof, resp.Height, nil + return resp.Value, resp.Height, nil } // Verify verifies the consensus proof at given height. @@ -175,7 +184,7 @@ func (ctx CLIContext) verifyProof(queryPath string, resp abci.ResponseQuery) err // queryStore performs a query to a Tendermint node with the provided a store // name and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, *merkle.Proof, int64, error) { +func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, int64, error) { path := fmt.Sprintf("/store/%s/%s", storeName, endPath) return ctx.query(path, key) } diff --git a/store/state/types.go b/store/state/types.go index a8d34d582a82..f5dbb4dc8648 100644 --- a/store/state/types.go +++ b/store/state/types.go @@ -1,8 +1,13 @@ package state import ( + "github.com/tendermint/tendermint/crypto/merkle" + + "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" ) type KVStore = sdk.KVStore type Context = sdk.Context +type CLIContext = context.CLIContext +type Proof = merkle.Proof diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 8767c3032724..f51b882e7725 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -2,6 +2,7 @@ package client import ( "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) @@ -11,6 +12,7 @@ type CLIObject struct { ID string ConsensusStateKey []byte FrozenKey []byte + Cdc *codec.Codec } func (obj Object) CLI() CLIObject { @@ -21,6 +23,34 @@ func (obj Object) CLI() CLIObject { } } -func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle..Proof) { - val, proof, _, err := ctx.QueryProof(obj.ConsensusStateKey) +func query(ctx context.CLIContext, root merkle.Root, key []byte) ([]byte, merkle.Proof, error) { + resp, err := ctx.QueryABCI(root.RequestQuery(key)) + if err != nil { + return nil, merkle.Proof{}, err + } + proof := merkle.Proof{ + Key: key, + Proof: resp.Proof, + } + return resp.Value, proof, nil + +} + +func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle.Proof, err error) { + val, proof, err := query(ctx, root, obj.ConsensusStateKey) + obj.Cdc.MustUnmarshalBinaryBare(val, &res) + return +} + +func (obj CLIObject) Frozen(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { + val, tmproof, _, err := ctx.QueryProof(obj.FrozenKey, "ibc") // TODO + if err != nil { + return + } + proof = merkle.Proof{ + Key: obj.FrozenKey, + Proof: tmproof, + } + obj.Cdc.MustUnmarshalBinaryBare(val, &res) + return } diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index 71650d987f22..2b5e3ab87ca6 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -28,5 +28,11 @@ func (root Root) QueryKey(key []byte) []byte { } func (root Root) QueryPath() []byte { + path := "" + for _, inter := range root.KeyPath { + path = path + "/" + string(inter) + } + path = path + "/key" + return []byte(path) } From 276f18cbc4a2c9a049c9ad37849784d871e77e30 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 15:40:30 +0200 Subject: [PATCH 037/378] add CLIObject --- x/ibc/02-client/cli.go | 31 ++++++++++------------- x/ibc/02-client/tendermint/types_test.go | 2 +- x/ibc/23-commitment/merkle/merkle_test.go | 12 ++++----- x/ibc/23-commitment/merkle/utils.go | 25 ++++++++---------- 4 files changed, 32 insertions(+), 38 deletions(-) diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index f51b882e7725..2592e697573c 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -12,45 +12,42 @@ type CLIObject struct { ID string ConsensusStateKey []byte FrozenKey []byte - Cdc *codec.Codec + + Root merkle.Root + Cdc *codec.Codec } -func (obj Object) CLI() CLIObject { +func (obj Object) CLI(root merkle.Root) CLIObject { return CLIObject{ ID: obj.id, ConsensusStateKey: obj.consensusState.Key(), FrozenKey: obj.frozen.Key(), + + Root: root, + Cdc: obj.consensusState.Cdc(), } } -func query(ctx context.CLIContext, root merkle.Root, key []byte) ([]byte, merkle.Proof, error) { - resp, err := ctx.QueryABCI(root.RequestQuery(key)) +func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { + resp, err := ctx.QueryABCI(obj.Root.RequestQuery(key)) if err != nil { - return nil, merkle.Proof{}, err + return merkle.Proof{}, err } proof := merkle.Proof{ Key: key, Proof: resp.Proof, } - return resp.Value, proof, nil + err = obj.Cdc.UnmarshalBinaryBare(resp.Value, ptr) + return proof, err } func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle.Proof, err error) { - val, proof, err := query(ctx, root, obj.ConsensusStateKey) - obj.Cdc.MustUnmarshalBinaryBare(val, &res) + proof, err = obj.query(ctx, obj.ConsensusStateKey, &res) return } func (obj CLIObject) Frozen(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { - val, tmproof, _, err := ctx.QueryProof(obj.FrozenKey, "ibc") // TODO - if err != nil { - return - } - proof = merkle.Proof{ - Key: obj.FrozenKey, - Proof: tmproof, - } - obj.Cdc.MustUnmarshalBinaryBare(val, &res) + proof, err = obj.query(ctx, obj.FrozenKey, &res) return } diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go index 3cb99f52b549..2b89f9be11c8 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/types_test.go @@ -170,7 +170,7 @@ func TestTenthBlockUpdate(t *testing.T) { */ func (node *node) query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { - code, value, proof := root.Query(node.cms, k) + code, value, proof := root.QueryMultiStore(node.cms, k) require.Equal(t, uint32(0), code) return value, proof } diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index 487e9496163e..a1886519eafc 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -47,13 +47,13 @@ func TestStore(t *testing.T) { root = commit(cms, root) - c1, v1, p1 := root.Query(cms, []byte("hello")) + c1, v1, p1 := root.QueryMultiStore(cms, []byte("hello")) require.Equal(t, uint32(0), c1) require.Equal(t, []byte("world"), v1) - c2, v2, p2 := root.Query(cms, []byte("merkle")) + c2, v2, p2 := root.QueryMultiStore(cms, []byte("merkle")) require.Equal(t, uint32(0), c2) require.Equal(t, []byte("tree"), v2) - c3, v3, p3 := root.Query(cms, []byte("block")) + c3, v3, p3 := root.QueryMultiStore(cms, []byte("block")) require.Equal(t, uint32(0), c3) require.Equal(t, []byte("chain"), v3) @@ -70,13 +70,13 @@ func TestStore(t *testing.T) { root = commit(cms, root) - c1, v1, p1 = root.Query(cms, []byte("12345")) + c1, v1, p1 = root.QueryMultiStore(cms, []byte("12345")) require.Equal(t, uint32(0), c1) require.Equal(t, []byte("67890"), v1) - c2, v2, p2 = root.Query(cms, []byte("qwerty")) + c2, v2, p2 = root.QueryMultiStore(cms, []byte("qwerty")) require.Equal(t, uint32(0), c2) require.Equal(t, []byte("zxcv"), v2) - c3, v3, p3 = root.Query(cms, []byte("hello")) + c3, v3, p3 = root.QueryMultiStore(cms, []byte("hello")) require.Equal(t, uint32(0), c3) require.Equal(t, []byte("dlrow"), v3) diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index 2b5e3ab87ca6..daf4c36b171b 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -7,32 +7,29 @@ import ( ) func (root Root) RequestQuery(key []byte) abci.RequestQuery { - path := "" - for _, inter := range root.KeyPath { - path = path + "/" + string(inter) - } - path = path + "/key" - - data := append(root.KeyPrefix, key...) + req := root.RequestQueryMultiStore(key) + req.Path = "/store" + req.Path + return req +} - return abci.RequestQuery{Path: path, Data: data, Prove: true} +func (root Root) RequestQueryMultiStore(key []byte) abci.RequestQuery { + return abci.RequestQuery{Path: root.Path() + "/key", Data: root.Key(key), Prove: true} } -func (root Root) Query(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { - qres := cms.(types.Queryable).Query(root.RequestQuery(key)) +func (root Root) QueryMultiStore(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { + qres := cms.(types.Queryable).Query(root.RequestQueryMultiStore(key)) return qres.Code, qres.Value, Proof{Key: key, Proof: qres.Proof} } -func (root Root) QueryKey(key []byte) []byte { +func (root Root) Key(key []byte) []byte { return append(root.KeyPrefix, key...) // XXX: cloneAppend } -func (root Root) QueryPath() []byte { +func (root Root) Path() string { path := "" for _, inter := range root.KeyPath { path = path + "/" + string(inter) } - path = path + "/key" - return []byte(path) + return path } From 1078211fa7de89ff39fe4b541b775b242b4726b0 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 15:58:28 +0200 Subject: [PATCH 038/378] separate testing from tendermint --- .../tendermint/tests/tendermint_test.go | 58 ++++++++ .../{types_test.go => tests/types.go} | 125 ++++++------------ .../{valset_test.go => tests/valset.go} | 0 3 files changed, 98 insertions(+), 85 deletions(-) create mode 100644 x/ibc/02-client/tendermint/tests/tendermint_test.go rename x/ibc/02-client/tendermint/{types_test.go => tests/types.go} (57%) rename x/ibc/02-client/tendermint/{valset_test.go => tests/valset.go} (100%) diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go new file mode 100644 index 000000000000..29581e718e4c --- /dev/null +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -0,0 +1,58 @@ +package tendermint + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +func newRoot() merkle.Root { + return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) +} + +func testUpdate(t *testing.T, interval int, ok bool) { + node := NewNode(NewMockValidators(100, 10)) + + node.Commit() + + verifier := node.LastStateVerifier(newRoot()) + + for i := 0; i < 100; i++ { + header := node.Commit() + + if i%interval == 0 { + err := verifier.Validate(header, node.PrevValset, node.Valset) + if ok { + require.NoError(t, err) + } else { + require.Error(t, err) + } + } + } +} + +func TestEveryBlockUpdate(t *testing.T) { + testUpdate(t, 1, true) +} + +func TestEvenBlockUpdate(t *testing.T) { + testUpdate(t, 2, true) +} + +func TestSixthBlockUpdate(t *testing.T) { + testUpdate(t, 6, true) +} + +/* +// This should fail, since the amount of mutation is so large +// Commented out because it sometimes success +func TestTenthBlockUpdate(t *testing.T) { + testUpdate(t, 10, false) +} +*/ + +func TestProofs(t *testing.T) { + testProof(t) +} diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/tests/types.go similarity index 57% rename from x/ibc/02-client/tendermint/types_test.go rename to x/ibc/02-client/tendermint/tests/types.go index 2b89f9be11c8..f32cae8efc9d 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -17,6 +17,8 @@ import ( stypes "github.com/cosmos/cosmos-sdk/store/types" 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" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) @@ -37,44 +39,44 @@ func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *c return key, ctx, cms, cdc } -type node struct { - prevvalset MockValidators - valset MockValidators +type Node struct { + PrevValset MockValidators + Valset MockValidators - cms sdk.CommitMultiStore - store sdk.KVStore + Cms sdk.CommitMultiStore + Store sdk.KVStore - commits []tmtypes.SignedHeader + Commits []tmtypes.SignedHeader } -func NewNode(valset MockValidators) *node { +func NewNode(valset MockValidators) *Node { key, ctx, cms, _ := defaultComponents() - return &node{ - valset: valset, - cms: cms, - store: ctx.KVStore(key), - commits: nil, + return &Node{ + Valset: valset, + Cms: cms, + Store: ctx.KVStore(key), + Commits: nil, } } -func (node *node) last() tmtypes.SignedHeader { - if len(node.commits) == 0 { +func (node *Node) Last() tmtypes.SignedHeader { + if len(node.Commits) == 0 { return tmtypes.SignedHeader{} } - return node.commits[len(node.commits)-1] + return node.Commits[len(node.Commits)-1] } -func (node *node) Commit() tmtypes.SignedHeader { - valsethash := node.valset.ValidatorSet().Hash() - nextvalset := node.valset.Mutate() +func (node *Node) Commit() tmtypes.SignedHeader { + valsethash := node.Valset.ValidatorSet().Hash() + nextvalset := node.Valset.Mutate() nextvalsethash := nextvalset.ValidatorSet().Hash() - commitid := node.cms.Commit() + commitid := node.Cms.Commit() header := tmtypes.Header{ ChainID: chainid, - Height: int64(len(node.commits) + 1), + Height: int64(len(node.Commits) + 1), LastBlockID: tmtypes.BlockID{ - Hash: node.last().Header.Hash(), + Hash: node.Last().Header.Hash(), }, ValidatorsHash: valsethash, @@ -82,22 +84,26 @@ func (node *node) Commit() tmtypes.SignedHeader { AppHash: commitid.Hash, } - commit := node.valset.Sign(header) + commit := node.Valset.Sign(header) - node.prevvalset = node.valset - node.valset = nextvalset - node.commits = append(node.commits, commit) + node.PrevValset = node.Valset + node.Valset = nextvalset + node.Commits = append(node.Commits, commit) return commit } +func (node *Node) LastStateVerifier(root merkle.Root) *Verifier { + return NewVerifier(node.Last(), node.Valset, root) +} + type Verifier struct { - ConsensusState + client.ConsensusState } func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root merkle.Root) *Verifier { return &Verifier{ - ConsensusState{ + tendermint.ConsensusState{ ChainID: chainid, Height: uint64(header.Height), Root: root.Update(header.AppHash), @@ -108,7 +114,7 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root me func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset MockValidators) error { newcs, err := v.ConsensusState.Validate( - Header{ + tendermint.Header{ SignedHeader: header, ValidatorSet: valset.ValidatorSet(), NextValidatorSet: nextvalset.ValidatorSet(), @@ -117,66 +123,19 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset Mock if err != nil { return err } - v.ConsensusState = newcs.(ConsensusState) + v.ConsensusState = newcs.(tendermint.ConsensusState) return nil } -func newRoot() merkle.Root { - return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) -} - -func testUpdate(t *testing.T, interval int, ok bool) { - node := NewNode(NewMockValidators(100, 10)) - - node.Commit() - - root := newRoot() - - verifier := NewVerifier(node.last(), node.valset, root) - - for i := 0; i < 100; i++ { - header := node.Commit() - - if i%interval == 0 { - err := verifier.Validate(header, node.prevvalset, node.valset) - if ok { - require.NoError(t, err) - } else { - require.Error(t, err) - } - } - } -} - -func TestEveryBlockUpdate(t *testing.T) { - testUpdate(t, 1, true) -} - -func TestEvenBlockUpdate(t *testing.T) { - testUpdate(t, 2, true) -} - -func TestSixthBlockUpdate(t *testing.T) { - testUpdate(t, 6, true) -} - -/* -// This should fail, since the amount of mutation is so large -// Commented out because it sometimes success -func TestTenthBlockUpdate(t *testing.T) { - testUpdate(t, 10, false) -} -*/ - -func (node *node) query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { - code, value, proof := root.QueryMultiStore(node.cms, k) +func (node *Node) Query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { + code, value, proof := root.QueryMultiStore(node.Cms, k) require.Equal(t, uint32(0), code) return value, proof } -func (node *node) Set(k, value []byte) { - node.store.Set(newRoot().Key(k), value) +func (node *Node) Set(k, value []byte) { + node.Store.Set(newRoot().Key(k), value) } func testProof(t *testing.T) { @@ -198,7 +157,7 @@ func testProof(t *testing.T) { proofs := []commitment.Proof{} root := newRoot().Update(header.AppHash) for _, kvp := range kvps { - v, p := node.query(t, root.(merkle.Root), []byte(kvp.Key)) + v, p := node.Query(t, root.(merkle.Root), []byte(kvp.Key)) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } @@ -210,7 +169,3 @@ func testProof(t *testing.T) { } } } - -func TestProofs(t *testing.T) { - testProof(t) -} diff --git a/x/ibc/02-client/tendermint/valset_test.go b/x/ibc/02-client/tendermint/tests/valset.go similarity index 100% rename from x/ibc/02-client/tendermint/valset_test.go rename to x/ibc/02-client/tendermint/tests/valset.go From e64a0d21c84ebd92838bc2fc0b8cb2d9f947d79e Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 16:10:21 +0200 Subject: [PATCH 039/378] add key to node --- x/ibc/02-client/tendermint/tests/types.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index f32cae8efc9d..cc6d73592504 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -44,9 +44,12 @@ type Node struct { Valset MockValidators Cms sdk.CommitMultiStore + Key sdk.StoreKey Store sdk.KVStore Commits []tmtypes.SignedHeader + + Root merkle.Root } func NewNode(valset MockValidators) *Node { @@ -54,6 +57,7 @@ func NewNode(valset MockValidators) *Node { return &Node{ Valset: valset, Cms: cms, + Key: key, Store: ctx.KVStore(key), Commits: nil, } From e2a61ac70d0508b2a85a1df4c094d2ae907509da Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 18:58:29 +0200 Subject: [PATCH 040/378] add root and storekey to tests/node, add codec --- x/ibc/02-client/codec.go | 10 ++++++++++ x/ibc/02-client/tendermint/codec.go | 11 +++++++++++ x/ibc/02-client/tendermint/tests/types.go | 8 ++++++-- x/ibc/02-client/tendermint/tests/valset.go | 1 + 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 x/ibc/02-client/codec.go create mode 100644 x/ibc/02-client/tendermint/codec.go diff --git a/x/ibc/02-client/codec.go b/x/ibc/02-client/codec.go new file mode 100644 index 000000000000..fa194562e4f1 --- /dev/null +++ b/x/ibc/02-client/codec.go @@ -0,0 +1,10 @@ +package client + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*ConsensusState)(nil), nil) + cdc.RegisterInterface((*Header)(nil), nil) +} diff --git a/x/ibc/02-client/tendermint/codec.go b/x/ibc/02-client/tendermint/codec.go new file mode 100644 index 000000000000..d8308a3e7ec8 --- /dev/null +++ b/x/ibc/02-client/tendermint/codec.go @@ -0,0 +1,11 @@ +package tendermint + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +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/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index cc6d73592504..88a27fd69f51 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -101,6 +101,10 @@ func (node *Node) LastStateVerifier(root merkle.Root) *Verifier { return NewVerifier(node.Last(), node.Valset, root) } +func (node *Node) Context() sdk.Context { + return sdk.NewContext(node.Cms, abci.Header{}, false, log.NewNopLogger()) +} + type Verifier struct { client.ConsensusState } @@ -139,7 +143,7 @@ func (node *Node) Query(t *testing.T, root merkle.Root, k []byte) ([]byte, commi } func (node *Node) Set(k, value []byte) { - node.Store.Set(newRoot().Key(k), value) + node.Store.Set(node.Root.Key(k), value) } func testProof(t *testing.T) { @@ -159,7 +163,7 @@ func testProof(t *testing.T) { } header := node.Commit() proofs := []commitment.Proof{} - root := newRoot().Update(header.AppHash) + root := node.Root.Update(header.AppHash) for _, kvp := range kvps { v, p := node.Query(t, root.(merkle.Root), []byte(kvp.Key)) require.Equal(t, kvp.Value, v) diff --git a/x/ibc/02-client/tendermint/tests/valset.go b/x/ibc/02-client/tendermint/tests/valset.go index 5649a3533273..0d97a5427c9b 100644 --- a/x/ibc/02-client/tendermint/tests/valset.go +++ b/x/ibc/02-client/tendermint/tests/valset.go @@ -84,6 +84,7 @@ type MockValidators []MockValidator var _ sort.Interface = MockValidators{} +// TODO: differenciate power between the vals func NewMockValidators(num int, power int64) MockValidators { res := make(MockValidators, num) for i := range res { From c6c4c045c82cee09d3b22f2a7c7aecf104afce03 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 12:22:46 +0200 Subject: [PATCH 041/378] rm cli/query.go --- x/ibc/client/cli/query.go | 216 -------------------------------------- 1 file changed, 216 deletions(-) delete mode 100644 x/ibc/client/cli/query.go diff --git a/x/ibc/client/cli/query.go b/x/ibc/client/cli/query.go deleted file mode 100644 index ca979151c499..000000000000 --- a/x/ibc/client/cli/query.go +++ /dev/null @@ -1,216 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/spf13/cobra" - - tmtypes "github.com/tendermint/tendermint/types" - - "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/02-client/tendermint" - ibc "github.com/cosmos/cosmos-sdk/x/ibc/keeper" -) - -func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - ibcQueryCmd := &cobra.Command{ - Use: "ibc", - Short: "IBC query subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - } - - ibcQueryCmd.AddCommand(client.GetCommands( - GetCmdQueryConsensusState(cdc), - GetCmdQueryHeader(cdc), - GetCmdQueryClient(cdc), - GetCmdQueryConnection(cdc), - GetCmdQueryChannel(cdc), - )...) - return ibcQueryCmd -} - -func GetCmdQueryClient(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "client", - Short: "Query stored client", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - keeper := ibc.DummyKeeper() - - var state ibc.ConsensusState - statebz, _, err := query(ctx, keeper.Client.Object(args[0]).Key()) - if err != nil { - return err - } - cdc.MustUnmarshalBinaryBare(statebz, &state) - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) - - return nil - }, - } -} - -func GetCmdQueryConsensusState(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "consensus-state", - Short: "Query the latest consensus state of the running chain", - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - node, err := ctx.GetNode() - if err != nil { - return err - } - - info, err := node.ABCIInfo() - if err != nil { - return err - } - - height := info.Response.LastBlockHeight - prevheight := height - 1 - - commit, err := node.Commit(&height) - if err != nil { - return err - } - - validators, err := node.Validators(&prevheight) - if err != nil { - return err - } - - state := tendermint.ConsensusState{ - ChainID: commit.ChainID, - Height: uint64(commit.Height), - Root: []byte(commit.AppHash), - NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - } - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) - - return nil - }, - } -} - -func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "header", - Short: "Query the latest header of the running chain", - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - node, err := ctx.GetNode() - if err != nil { - return err - } - - info, err := node.ABCIInfo() - if err != nil { - return err - } - - height := info.Response.LastBlockHeight - prevheight := height - 1 - - commit, err := node.Commit(&height) - if err != nil { - return err - } - - validators, err := node.Validators(&prevheight) - if err != nil { - return err - } - - nextvalidators, err := node.Validators(&height) - if err != nil { - return err - } - - header := tendermint.Header{ - SignedHeader: commit.SignedHeader, - ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), - } - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) - - return nil - }, - } -} - -func GetCmdQueryConnection(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "connection", - Short: "Query an existing connection", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - keeper := ibc.DummyKeeper() - - var conn ibc.Connection - connbz, _, err := query(ctx, keeper.Connection.Object(args[0]).Key()) - if err != nil { - return err - } - cdc.MustUnmarshalBinaryBare(connbz, &conn) - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, conn)) - - return nil - }, - } -} - -func GetCmdQueryChannel(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "channel", - Short: "Query an existing channel", - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - keeper := ibc.DummyKeeper() - - var conn ibc.Channel - connbz, _, err := query(ctx, keeper.Channel.Object(args[0], args[1]).Key()) - if err != nil { - return err - } - cdc.MustUnmarshalBinaryBare(connbz, &conn) - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, conn)) - - return nil - }, - } -} - -func GetCmdQuerySendSequence(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "send-sequence", - Short: "Query the send sequence of a channel", - Args: cobra.ExactArgs(), - RunE: func(cmd *cobra.Command, args []string) error { - - }, - } -} - -func GetCmdQueryReceiveSequence(cdc *codec.Codec) *cobra.Command { - -} - -func GetCmdQueryPacket(cdc *codec.Codec) *cobra.Command { -} From 83afdaf2808019c17359fdb5261577871e3971b3 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 18:21:20 +0200 Subject: [PATCH 042/378] fix test --- x/ibc/02-client/tendermint/tests/tendermint_test.go | 2 +- x/ibc/02-client/tendermint/tests/types.go | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go index 29581e718e4c..caf866337c47 100644 --- a/x/ibc/02-client/tendermint/tests/tendermint_test.go +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -13,7 +13,7 @@ func newRoot() merkle.Root { } func testUpdate(t *testing.T, interval int, ok bool) { - node := NewNode(NewMockValidators(100, 10)) + node := NewNode(NewMockValidators(100, 10), newRoot()) node.Commit() diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 88a27fd69f51..d0b7b488db39 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -52,7 +52,7 @@ type Node struct { Root merkle.Root } -func NewNode(valset MockValidators) *Node { +func NewNode(valset MockValidators, root merkle.Root) *Node { key, ctx, cms, _ := defaultComponents() return &Node{ Valset: valset, @@ -60,6 +60,7 @@ func NewNode(valset MockValidators) *Node { Key: key, Store: ctx.KVStore(key), Commits: nil, + Root: root, } } @@ -147,7 +148,7 @@ func (node *Node) Set(k, value []byte) { } func testProof(t *testing.T) { - node := NewNode(NewMockValidators(100, 10)) + node := NewNode(NewMockValidators(100, 10), newRoot()) node.Commit() From 21e0b15698f20924740711a07069c98054a5ec7a Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 18:26:23 +0200 Subject: [PATCH 043/378] fix lint --- x/ibc/02-client/tendermint/tests/valset.go | 2 +- x/ibc/02-client/tendermint/types.go | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/valset.go b/x/ibc/02-client/tendermint/tests/valset.go index 0d97a5427c9b..1b5f88aa949b 100644 --- a/x/ibc/02-client/tendermint/tests/valset.go +++ b/x/ibc/02-client/tendermint/tests/valset.go @@ -84,7 +84,7 @@ type MockValidators []MockValidator var _ sort.Interface = MockValidators{} -// TODO: differenciate power between the vals +// TODO: differentiate power between the vals func NewMockValidators(num int, power int64) MockValidators { res := make(MockValidators, num) for i := range res { diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 26a4c35370e6..6bb1bb1f18dd 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -48,11 +48,8 @@ func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, return nil, errors.New("invalid type") } - nextvalset := cs.NextValidatorSet - nexthash := nextvalset.Hash() - if cs.Height == uint64(header.Height-1) { - nexthash = cs.NextValidatorSet.Hash() + nexthash := cs.NextValidatorSet.Hash() if !bytes.Equal(header.ValidatorsHash, nexthash) { return nil, lerr.ErrUnexpectedValidators(header.ValidatorsHash, nexthash) } From 203eaf3c659aedc4b8f7985ad8c33c0f07187658 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 19:12:36 +0200 Subject: [PATCH 044/378] fix lint --- .../tendermint/tests/tendermint_test.go | 6 ------ x/ibc/02-client/tendermint/tests/types.go | 16 ++++++++++++---- x/ibc/02-client/tendermint/tests/valset.go | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go index caf866337c47..8a1c764f50f2 100644 --- a/x/ibc/02-client/tendermint/tests/tendermint_test.go +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -4,14 +4,8 @@ import ( "testing" "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func newRoot() merkle.Root { - return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) -} - func testUpdate(t *testing.T, interval int, ok bool) { node := NewNode(NewMockValidators(100, 10), newRoot()) diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index d0b7b488db39..5e0af44f3806 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -1,7 +1,7 @@ package tendermint import ( - "math/rand" + "crypto/rand" "testing" "github.com/stretchr/testify/require" @@ -23,6 +23,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) +// nolint: unused +func newRoot() merkle.Root { + return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) +} + const chainid = "testchain" func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { @@ -147,6 +152,7 @@ func (node *Node) Set(k, value []byte) { node.Store.Set(node.Root.Key(k), value) } +// nolint:deadcode,unused func testProof(t *testing.T) { node := NewNode(NewMockValidators(100, 10), newRoot()) @@ -157,8 +163,10 @@ func testProof(t *testing.T) { for i := 0; i < 100; i++ { k := make([]byte, 32) v := make([]byte, 32) - rand.Read(k) - rand.Read(v) + _, err := rand.Read(k) + require.NoError(t, err) + _, err = rand.Read(v) + require.NoError(t, err) kvps = append(kvps, cmn.KVPair{Key: k, Value: v}) node.Set(k, v) } @@ -166,7 +174,7 @@ func testProof(t *testing.T) { proofs := []commitment.Proof{} root := node.Root.Update(header.AppHash) for _, kvp := range kvps { - v, p := node.Query(t, root.(merkle.Root), []byte(kvp.Key)) + v, p := node.Query(t, root.(merkle.Root), kvp.Key) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } diff --git a/x/ibc/02-client/tendermint/tests/valset.go b/x/ibc/02-client/tendermint/tests/valset.go index 1b5f88aa949b..30bd194682c8 100644 --- a/x/ibc/02-client/tendermint/tests/valset.go +++ b/x/ibc/02-client/tendermint/tests/valset.go @@ -131,7 +131,7 @@ func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { Height: header.Height, Type: tmtypes.PrecommitType, } - val.MockPV.SignVote(chainid, vote) + _ = val.MockPV.SignVote(chainid, vote) precommits[i] = vote.CommitSig() } From 0872511e91fa865059e16172cca2d1a2bd2393ee Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 17:10:21 +0200 Subject: [PATCH 045/378] add CLIObject in progress --- client/context/query.go | 28 +++++++++++++++++++--------- x/ibc/02-client/cli.go | 4 ++++ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 4738808ba4fe..b04527f07740 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -31,21 +31,31 @@ func (ctx CLIContext) GetNode() (rpcclient.Client, error) { // Query performs a query to a Tendermint node with the provided path. // It returns the result and height of the query upon success or an error if // the query fails. -func (ctx CLIContext) Query(path string) ([]byte, int64, error) { - return ctx.query(path, nil) +func (ctx CLIContext) Query(path string) (val []byte, height int64, err error) { + val, _, height, err = ctx.query(path, nil) + return } // QueryWithData performs a query to a Tendermint node with the provided path // and a data payload. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryWithData(path string, data []byte) ([]byte, int64, error) { - return ctx.query(path, data) +func (ctx CLIContext) QueryWithData(path string, data []byte) (val []byte, height int64, err error) { + val, _, height, err = ctx.query(path, data) + return } // QueryStore performs a query to a Tendermint node with the provided key and // store name. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, int64, error) { +func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (val []byte, height int64, err error) { + val, _, height, err = ctx.queryStore(key, storeName, "key") + return +} + +// QueryProof performs a query to a Tendermint node with the provided key and +// store name. It returns the result, the proof, and height of the query +// upon success or an error if the query fails. +func (ctx CLIContext) QueryProof(key cmn.HexBytes, storeName string) (val []byte, proof *merkle.Proof, height int64, err error) { return ctx.queryStore(key, storeName, "key") } @@ -59,7 +69,7 @@ func (ctx CLIContext) QueryABCI(req abci.RequestQuery) (abci.ResponseQuery, erro // store name and subspace. It returns key value pair and height of the query // upon success or an error if the query fails. func (ctx CLIContext) QuerySubspace(subspace []byte, storeName string) (res []sdk.KVPair, height int64, err error) { - resRaw, height, err := ctx.queryStore(subspace, storeName, "subspace") + resRaw, _, height, err := ctx.queryStore(subspace, storeName, "subspace") if err != nil { return res, height, err } @@ -116,7 +126,7 @@ func (ctx CLIContext) queryABCI(req abci.RequestQuery) (resp abci.ResponseQuery, // query performs a query to a Tendermint node with the provided store name // and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) { +func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, proof *merkle.Proof, height int64, err error) { resp, err := ctx.queryABCI(abci.RequestQuery{ Path: path, Data: key, @@ -125,7 +135,7 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height i return } - return resp.Value, resp.Height, nil + return resp.Value, resp.Proof, resp.Height, nil } // Verify verifies the consensus proof at given height. @@ -184,7 +194,7 @@ func (ctx CLIContext) verifyProof(queryPath string, resp abci.ResponseQuery) err // queryStore performs a query to a Tendermint node with the provided a store // name and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, int64, error) { +func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, *merkle.Proof, int64, error) { path := fmt.Sprintf("/store/%s/%s", storeName, endPath) return ctx.query(path, key) } diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 2592e697573c..6390bf5ccb8c 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -51,3 +51,7 @@ func (obj CLIObject) Frozen(ctx context.CLIContext, root merkle.Root) (res bool, proof, err = obj.query(ctx, obj.FrozenKey, &res) return } + +func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle..Proof) { + val, proof, _, err := ctx.QueryProof(obj.ConsensusStateKey) +} From fdf09cc5f526517beb987e27d97467b0ba905b0b Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 15:19:42 +0200 Subject: [PATCH 046/378] cli in progress --- client/context/query.go | 27 ++++++++++++------------ x/ibc/02-client/cli.go | 32 +++++++++++++++++++++++++++-- x/ibc/23-commitment/merkle/utils.go | 1 - 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index b04527f07740..237a628bf4e8 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -31,32 +31,31 @@ func (ctx CLIContext) GetNode() (rpcclient.Client, error) { // Query performs a query to a Tendermint node with the provided path. // It returns the result and height of the query upon success or an error if // the query fails. -func (ctx CLIContext) Query(path string) (val []byte, height int64, err error) { - val, _, height, err = ctx.query(path, nil) - return +func (ctx CLIContext) Query(path string) ([]byte, int64, error) { + return ctx.query(path, nil) } // QueryWithData performs a query to a Tendermint node with the provided path // and a data payload. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryWithData(path string, data []byte) (val []byte, height int64, err error) { - val, _, height, err = ctx.query(path, data) - return +func (ctx CLIContext) QueryWithData(path string, data []byte) ([]byte, int64, error) { + return ctx.query(path, data) } // QueryStore performs a query to a Tendermint node with the provided key and // store name. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (val []byte, height int64, err error) { - val, _, height, err = ctx.queryStore(key, storeName, "key") - return +func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, int64, error) { + return ctx.queryStore(key, storeName, "key") } // QueryProof performs a query to a Tendermint node with the provided key and // store name. It returns the result, the proof, and height of the query // upon success or an error if the query fails. func (ctx CLIContext) QueryProof(key cmn.HexBytes, storeName string) (val []byte, proof *merkle.Proof, height int64, err error) { - return ctx.queryStore(key, storeName, "key") + path := fmt.Sprintf("/store/%s/%s", storeName, "key") + resp, err := ctx.queryABCI(abci.RequestQuery{Data: key, Path: path}) + return resp.Value, resp.Proof, resp.Height, err } // QueryABCI performs a query to a Tendermint node with the provide RequestQuery. @@ -69,7 +68,7 @@ func (ctx CLIContext) QueryABCI(req abci.RequestQuery) (abci.ResponseQuery, erro // store name and subspace. It returns key value pair and height of the query // upon success or an error if the query fails. func (ctx CLIContext) QuerySubspace(subspace []byte, storeName string) (res []sdk.KVPair, height int64, err error) { - resRaw, _, height, err := ctx.queryStore(subspace, storeName, "subspace") + resRaw, height, err := ctx.queryStore(subspace, storeName, "subspace") if err != nil { return res, height, err } @@ -126,7 +125,7 @@ func (ctx CLIContext) queryABCI(req abci.RequestQuery) (resp abci.ResponseQuery, // query performs a query to a Tendermint node with the provided store name // and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, proof *merkle.Proof, height int64, err error) { +func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) { resp, err := ctx.queryABCI(abci.RequestQuery{ Path: path, Data: key, @@ -135,7 +134,7 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, proof *m return } - return resp.Value, resp.Proof, resp.Height, nil + return resp.Value, resp.Height, nil } // Verify verifies the consensus proof at given height. @@ -194,7 +193,7 @@ func (ctx CLIContext) verifyProof(queryPath string, resp abci.ResponseQuery) err // queryStore performs a query to a Tendermint node with the provided a store // name and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, *merkle.Proof, int64, error) { +func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, int64, error) { path := fmt.Sprintf("/store/%s/%s", storeName, endPath) return ctx.query(path, key) } diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 6390bf5ccb8c..47302294efcc 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -52,6 +52,34 @@ func (obj CLIObject) Frozen(ctx context.CLIContext, root merkle.Root) (res bool, return } -func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle..Proof) { - val, proof, _, err := ctx.QueryProof(obj.ConsensusStateKey) +func query(ctx context.CLIContext, root merkle.Root, key []byte) ([]byte, merkle.Proof, error) { + resp, err := ctx.QueryABCI(root.RequestQuery(key)) + if err != nil { + return nil, merkle.Proof{}, err + } + proof := merkle.Proof{ + Key: key, + Proof: resp.Proof, + } + return resp.Value, proof, nil + +} + +func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle.Proof, err error) { + val, proof, err := query(ctx, root, obj.ConsensusStateKey) + obj.Cdc.MustUnmarshalBinaryBare(val, &res) + return +} + +func (obj CLIObject) Frozen(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { + val, tmproof, _, err := ctx.QueryProof(obj.FrozenKey, "ibc") // TODO + if err != nil { + return + } + proof = merkle.Proof{ + Key: obj.FrozenKey, + Proof: tmproof, + } + obj.Cdc.MustUnmarshalBinaryBare(val, &res) + return } diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index daf4c36b171b..b16d0854e2af 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -30,6 +30,5 @@ func (root Root) Path() string { for _, inter := range root.KeyPath { path = path + "/" + string(inter) } - return path } From ae663575c50586cbf4cea5747babea72e52130cf Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 7 Jun 2019 23:47:41 +0200 Subject: [PATCH 047/378] add connection --- x/ibc/03-connection/manager.go | 387 +++++++++++++++++++++++++++++++++ x/ibc/03-connection/types.go | 37 ++++ 2 files changed, 424 insertions(+) create mode 100644 x/ibc/03-connection/manager.go create mode 100644 x/ibc/03-connection/types.go diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go new file mode 100644 index 000000000000..5317078f3796 --- /dev/null +++ b/x/ibc/03-connection/manager.go @@ -0,0 +1,387 @@ +package connection + +import ( + "errors" + + "github.com/cosmos/cosmos-sdk/store/mapping" + 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" +) + +// XXX: rename remote to something else +// XXX: all code using external KVStore should be defer-recovered in case of missing proofs + +type Manager struct { + protocol mapping.Mapping + + client client.Manager + + // CONTRACT: remote/self should not be used when remote + remote *Manager + self mapping.Indexer +} + +func NewManager(protocol, free mapping.Base, client client.Manager) Manager { + return Manager{ + protocol: mapping.NewMapping(protocol, []byte("/")), + + client: client, + + self: mapping.NewIndexer(free, []byte("/self"), mapping.Dec), + } +} + +// TODO: return newtyped manager +func NewRemoteManager(protocol mapping.Base, client client.Manager) Manager { + return NewManager(protocol, mapping.EmptyBase(), client) +} + +func (man Manager) Exec(remote Manager, fn func(Manager)) { + fn(Manager{ + protocol: man.protocol, + client: man.client, + self: man.self, + remote: &remote, + }) +} + +// CONTRACT: client and remote must be filled by the caller +func (man Manager) object(id string) Object { + return Object{ + id: id, + connection: man.protocol.Value([]byte(id)), + state: mapping.NewEnum(man.protocol.Value([]byte(id + "/state"))), + nexttimeout: mapping.NewInteger(man.protocol.Value([]byte(id+"/timeout")), mapping.Dec), + + self: man.self, + } +} + +func (man Manager) remoteobject(id string) Object { + return Object{ + id: id, + connection: man.remote.protocol.Value([]byte(id), commitment.Value), + state: commitment.Enum(man.protocol.Value([]byte(id+"/state"), commitment.Value)), + nexttimeout: commitment.Integer(man.protocol.Value([]byte(id+"/timeout"), commitment.Value), mapping.Dec), + } +} + +func (man Manager) Create(ctx sdk.Context, id string, connection Connection) (nobj NihiloObject, err error) { + obj := man.object(id) + if obj.exists(ctx) { + err = errors.New("connection already exists for the provided id") + return + } + obj.connection.Set(ctx, connection) + obj.client, err = man.client.Query(ctx, connection.Client) + if err != nil { + return + } + remote := man.remote.object(connection.Counterparty) + obj.remote = &remote + return NihiloObject(obj), nil +} + +func (man Manager) Query(ctx sdk.Context, key string) (obj Object, err error) { + obj = man.object(key) + if !obj.exists(ctx) { + return Object{}, errors.New("connection not exists for the provided id") + } + conn := obj.Value(ctx) + obj.client, err = man.client.Query(ctx, conn.Client) + if err != nil { + return + } + remote := man.remote.object(conn.Counterparty) + obj.remote = &remote + return +} + +type NihiloObject Object + +type Object struct { + id string + connection mapping.Value + state mapping.Enum + nexttimeout mapping.Integer + + client client.Object + + // CONTRACT: remote/self should not be used when remote + remote *Object + self mapping.Indexer +} + +func (obj Object) ID() string { + return obj.id +} + +func (obj Object) ClientID() string { + return obj.client.ID() +} + +func (obj Object) exists(ctx sdk.Context) bool { + return obj.connection.Exists(ctx) +} + +func (obj Object) remove(ctx sdk.Context) { + obj.connection.Delete(ctx) + obj.state.Delete(ctx) + obj.nexttimeout.Delete(ctx) +} + +func (obj Object) assertSymmetric(ctx sdk.Context) error { + if !obj.Value(ctx).Symmetric(obj.id, obj.remote.Value(ctx)) { + return errors.New("unexpected counterparty connection value") + } + + return nil +} + +func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { + if uint64(ctx.BlockHeight()) > timeoutHeight { + return errors.New("timeout") + } + + return nil +} + +func (obj Object) Value(ctx sdk.Context) (res Connection) { + obj.connection.Get(ctx, &res) + return +} + +func (nobj NihiloObject) OpenInit(ctx sdk.Context, nextTimeoutHeight uint64) error { + + obj := Object(nobj) + if obj.exists(ctx) { + return errors.New("init on existing connection") + } + + if !obj.state.Transit(ctx, Idle, Init) { + return errors.New("init on non-idle connection") + } + + // CONTRACT: OpenInit() should be called after man.Create(), not man.Query(), + // which will ensure + // assert(get("connections/{identifier}") === null) and + // set("connections{identifier}", connection) + + obj.nexttimeout.Set(ctx, nextTimeoutHeight) + + return nil +} + +func (nobj NihiloObject) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { + + obj := Object(nobj) + if !obj.state.Transit(ctx, Idle, OpenTry) { + return errors.New("invalid state") + } + + err := assertTimeout(ctx, timeoutHeight) + if err != nil { + return err + } + + if !obj.remote.state.Is(ctx, Init) { + return errors.New("counterparty state not init") + } + + err = obj.assertSymmetric(ctx) + if err != nil { + return err + } + + if !obj.remote.nexttimeout.Is(ctx, uint64(timeoutHeight)) { + return errors.New("unexpected counterparty timeout value") + } + + var expected client.Client + obj.self.Get(ctx, expheight, &expected) + if !obj.remote.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.nexttimeout.Set(ctx, nextTimeoutHeight) + + return nil +} + +func (obj Object) OpenAck(ctx sdk.Context, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { + + if !obj.state.Transit(ctx, Init, Open) { + return errors.New("ack on non-init connection") + } + + err := assertTimeout(ctx, timeoutHeight) + if err != nil { + return err + } + + if !obj.remote.state.Is(ctx, OpenTry) { + return errors.New("counterparty state not try") + } + + err = obj.assertSymmetric(ctx) + if err != nil { + return err + } + + if !obj.remote.nexttimeout.Is(ctx, uint64(timeoutHeight)) { + return errors.New("unexpected counterparty timeout value") + } + + var expected client.Client + obj.self.Get(ctx, expheight, &expected) + if !obj.remote.client.Is(ctx, expected) { + return errors.New("unexpected counterparty client value") + } + + obj.nexttimeout.Set(ctx, uint64(nextTimeoutHeight)) + + return nil +} + +func (obj Object) OpenConfirm(ctx sdk.Context, timeoutHeight uint64) error { + if !obj.state.Transit(ctx, OpenTry, Open) { + return errors.New("confirm on non-try connection") + } + + err := assertTimeout(ctx, timeoutHeight) + if err != nil { + return err + } + + if !obj.remote.state.Is(ctx, Open) { + return errors.New("counterparty state not open") + } + + err = obj.assertSymmetric(ctx) + if err != nil { + return err + } + + if !obj.remote.nexttimeout.Is(ctx, timeoutHeight) { + return errors.New("unexpected counterparty timeout value") + } + + obj.nexttimeout.Set(ctx, 0) + + return nil +} + +func (obj Object) OpenTimeout(ctx sdk.Context) error { + if !(uint64(obj.client.Value(ctx).GetBase().GetHeight()) > obj.nexttimeout.Get(ctx)) { + return errors.New("timeout height not yet reached") + } + + // XXX: double check if a user can bypass the verification logic somehow + switch obj.state.Get(ctx) { + case Init: + if !obj.remote.connection.Is(ctx, nil) { + return errors.New("counterparty connection exists") + } + case OpenTry: + if !(obj.remote.state.Is(ctx, Init) || + obj.remote.exists(ctx)) { + 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.remote.state.Is(ctx, OpenTry) { + return errors.New("counterparty connection state not tryopen") + } + } + + obj.remove(ctx) + + return nil +} + +func (obj Object) 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 Object) 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.remote.state.Is(ctx, CloseTry) { + return errors.New("unexpected counterparty state value") + } + + if !obj.remote.nexttimeout.Is(ctx, timeoutHeight) { + return errors.New("unexpected counterparty timeout value") + } + + obj.nexttimeout.Set(ctx, nextTimeoutHeight) + + return nil +} + +func (obj Object) 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.remote.state.Is(ctx, Closed) { + return errors.New("unexpected counterparty state value") + } + + if !obj.remote.nexttimeout.Is(ctx, timeoutHeight) { + return errors.New("unexpected counterparty timeout value") + } + + obj.nexttimeout.Set(ctx, 0) + + return nil +} + +func (obj Object) CloseTimeout(ctx sdk.Context) error { + if !(uint64(obj.client.Value(ctx).GetBase().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.remote.state.Is(ctx, Open) { + return errors.New("counterparty connection state not open") + } + case Closed: + if !obj.remote.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/types.go b/x/ibc/03-connection/types.go new file mode 100644 index 000000000000..50df047a6b21 --- /dev/null +++ b/x/ibc/03-connection/types.go @@ -0,0 +1,37 @@ +package connection + +type State = byte + +const ( + Idle State = iota + Init + OpenTry + Open + CloseTry + Closed +) + +// TODO: Connection is amino marshaled currently, need to implement MarshalBinary manually +type Connection struct { + Counterparty string + Client string + CounterpartyClient string +} + +func (conn Connection) Equal(conn0 Connection) bool { + return conn.Counterparty == conn0.Counterparty && + conn.Client == conn0.Client && + conn.CounterpartyClient == conn0.CounterpartyClient +} + +func (conn Connection) Symmetric(id string, conn0 Connection) bool { + return conn0.Equal(conn.Symmetry(id)) +} + +func (conn Connection) Symmetry(id string) Connection { + return Connection{ + Counterparty: id, + Client: conn.CounterpartyClient, + CounterpartyClient: conn.Client, + } +} From 7c44da1f4e0cec7bc88c8a4d902bc8db6128bb0a Mon Sep 17 00:00:00 2001 From: mossid Date: Sat, 8 Jun 2019 00:01:26 +0200 Subject: [PATCH 048/378] fix assertSymmetry --- x/ibc/03-connection/manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 5317078f3796..e08ba97eb809 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -133,7 +133,7 @@ func (obj Object) remove(ctx sdk.Context) { } func (obj Object) assertSymmetric(ctx sdk.Context) error { - if !obj.Value(ctx).Symmetric(obj.id, obj.remote.Value(ctx)) { + if !obj.remote.connection.Is(ctx, obj.Value(ctx).Symmetry(obj.id)) { return errors.New("unexpected counterparty connection value") } From 043de514fef05a7a7abf604739a79f9e14a952ef Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 01:02:15 +0200 Subject: [PATCH 049/378] fix remote in progress in progress in progress --- x/ibc/03-connection/manager.go | 110 +++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 48 deletions(-) diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index e08ba97eb809..09025ad5919f 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -3,6 +3,7 @@ package connection import ( "errors" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/mapping" sdk "github.com/cosmos/cosmos-sdk/types" @@ -18,33 +19,37 @@ type Manager struct { client client.Manager - // CONTRACT: remote/self should not be used when remote - remote *Manager - self mapping.Indexer + self mapping.Indexer + + counterparty CounterpartyManager } -func NewManager(protocol, free mapping.Base, client client.Manager) Manager { +func NewManager(protocol, free mapping.Base, clientman client.Manager) Manager { return Manager{ - protocol: mapping.NewMapping(protocol, []byte("/")), + protocol: mapping.NewMapping(protocol, []byte("/connection/")), + + client: clientman, - client: client, + self: mapping.NewIndexer(free, []byte("/connection/self/"), mapping.Dec), - self: mapping.NewIndexer(free, []byte("/self"), mapping.Dec), + counterparty: NewCounterpartyManager(protocol.Cdc()), } } -// TODO: return newtyped manager -func NewRemoteManager(protocol mapping.Base, client client.Manager) Manager { - return NewManager(protocol, mapping.EmptyBase(), client) +type CounterpartyManager struct { + protocol commitment.Mapping + + client client.CounterpartyManager } -func (man Manager) Exec(remote Manager, fn func(Manager)) { - fn(Manager{ - protocol: man.protocol, - client: man.client, - self: man.self, - remote: &remote, - }) +func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { + protocol := commitment.NewBase(cdc) + + return CounterpartyManager{ + protocol: commitment.NewMapping(protocol, []byte("/connection/")), + + client: client.NewCounterpartyManager(protocol), + } } // CONTRACT: client and remote must be filled by the caller @@ -59,12 +64,13 @@ func (man Manager) object(id string) Object { } } -func (man Manager) remoteobject(id string) Object { - return Object{ +// CONTRACT: client must be filled by the caller +func (man CounterpartyManager) object(id string) CounterObject { + return CounterObject{ id: id, - connection: man.remote.protocol.Value([]byte(id), commitment.Value), - state: commitment.Enum(man.protocol.Value([]byte(id+"/state"), commitment.Value)), - nexttimeout: commitment.Integer(man.protocol.Value([]byte(id+"/timeout"), commitment.Value), mapping.Dec), + connection: man.protocol.Value([]byte(id)), + state: commitment.NewEnum(man.protocol.Value([]byte(id + "/state"))), + nexttimeout: commitment.NewInteger(man.protocol.Value([]byte(id+"/timeout")), mapping.Dec), } } @@ -79,8 +85,8 @@ func (man Manager) Create(ctx sdk.Context, id string, connection Connection) (no if err != nil { return } - remote := man.remote.object(connection.Counterparty) - obj.remote = &remote + obj.counterparty = man.counterparty.object(connection.Counterparty) + obj.counterparty.client = man.counterparty.client.Query(connection.CounterpartyClient) return NihiloObject(obj), nil } @@ -94,8 +100,8 @@ func (man Manager) Query(ctx sdk.Context, key string) (obj Object, err error) { if err != nil { return } - remote := man.remote.object(conn.Counterparty) - obj.remote = &remote + obj.counterparty = man.counterparty.object(conn.Counterparty) + obj.counterparty.client = man.counterparty.client.Query(conn.CounterpartyClient) return } @@ -109,9 +115,17 @@ type Object struct { client client.Object - // CONTRACT: remote/self should not be used when remote - remote *Object - self mapping.Indexer + counterparty CounterObject + self mapping.Indexer +} + +type CounterObject struct { + id string + connection commitment.Value + state commitment.Enum + nexttimeout commitment.Integer + + client client.CounterObject } func (obj Object) ID() string { @@ -133,7 +147,7 @@ func (obj Object) remove(ctx sdk.Context) { } func (obj Object) assertSymmetric(ctx sdk.Context) error { - if !obj.remote.connection.Is(ctx, obj.Value(ctx).Symmetry(obj.id)) { + if !obj.counterparty.connection.Is(ctx, obj.Value(ctx).Symmetry(obj.id)) { return errors.New("unexpected counterparty connection value") } @@ -186,7 +200,7 @@ func (nobj NihiloObject) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeigh return err } - if !obj.remote.state.Is(ctx, Init) { + if !obj.counterparty.state.Is(ctx, Init) { return errors.New("counterparty state not init") } @@ -195,13 +209,13 @@ func (nobj NihiloObject) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeigh return err } - if !obj.remote.nexttimeout.Is(ctx, uint64(timeoutHeight)) { + if !obj.counterparty.nexttimeout.Is(ctx, uint64(timeoutHeight)) { return errors.New("unexpected counterparty timeout value") } var expected client.Client obj.self.Get(ctx, expheight, &expected) - if !obj.remote.client.Is(ctx, expected) { + if !obj.counterparty.client.Is(ctx, expected) { return errors.New("unexpected counterparty client value") } @@ -226,7 +240,7 @@ func (obj Object) OpenAck(ctx sdk.Context, expheight uint64, timeoutHeight, next return err } - if !obj.remote.state.Is(ctx, OpenTry) { + if !obj.counterparty.state.Is(ctx, OpenTry) { return errors.New("counterparty state not try") } @@ -235,13 +249,13 @@ func (obj Object) OpenAck(ctx sdk.Context, expheight uint64, timeoutHeight, next return err } - if !obj.remote.nexttimeout.Is(ctx, uint64(timeoutHeight)) { + if !obj.counterparty.nexttimeout.Is(ctx, uint64(timeoutHeight)) { return errors.New("unexpected counterparty timeout value") } var expected client.Client obj.self.Get(ctx, expheight, &expected) - if !obj.remote.client.Is(ctx, expected) { + if !obj.counterparty.client.Is(ctx, expected) { return errors.New("unexpected counterparty client value") } @@ -260,7 +274,7 @@ func (obj Object) OpenConfirm(ctx sdk.Context, timeoutHeight uint64) error { return err } - if !obj.remote.state.Is(ctx, Open) { + if !obj.counterparty.state.Is(ctx, Open) { return errors.New("counterparty state not open") } @@ -269,7 +283,7 @@ func (obj Object) OpenConfirm(ctx sdk.Context, timeoutHeight uint64) error { return err } - if !obj.remote.nexttimeout.Is(ctx, timeoutHeight) { + if !obj.counterparty.nexttimeout.Is(ctx, timeoutHeight) { return errors.New("unexpected counterparty timeout value") } @@ -286,17 +300,17 @@ func (obj Object) OpenTimeout(ctx sdk.Context) error { // XXX: double check if a user can bypass the verification logic somehow switch obj.state.Get(ctx) { case Init: - if !obj.remote.connection.Is(ctx, nil) { + if !obj.counterparty.connection.Is(ctx, nil) { return errors.New("counterparty connection exists") } case OpenTry: - if !(obj.remote.state.Is(ctx, Init) || - obj.remote.exists(ctx)) { + if !(obj.counterparty.state.Is(ctx, Init) || + obj.counterparty.exists(ctx)) { 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.remote.state.Is(ctx, OpenTry) { + if obj.counterparty.state.Is(ctx, OpenTry) { return errors.New("counterparty connection state not tryopen") } } @@ -326,11 +340,11 @@ func (obj Object) CloseTry(ctx sdk.Context, timeoutHeight, nextTimeoutHeight uin return err } - if !obj.remote.state.Is(ctx, CloseTry) { + if !obj.counterparty.state.Is(ctx, CloseTry) { return errors.New("unexpected counterparty state value") } - if !obj.remote.nexttimeout.Is(ctx, timeoutHeight) { + if !obj.counterparty.nexttimeout.Is(ctx, timeoutHeight) { return errors.New("unexpected counterparty timeout value") } @@ -349,11 +363,11 @@ func (obj Object) CloseAck(ctx sdk.Context, timeoutHeight uint64) error { return err } - if !obj.remote.state.Is(ctx, Closed) { + if !obj.counterparty.state.Is(ctx, Closed) { return errors.New("unexpected counterparty state value") } - if !obj.remote.nexttimeout.Is(ctx, timeoutHeight) { + if !obj.counterparty.nexttimeout.Is(ctx, timeoutHeight) { return errors.New("unexpected counterparty timeout value") } @@ -370,11 +384,11 @@ func (obj Object) CloseTimeout(ctx sdk.Context) error { // XXX: double check if the user can bypass the verification logic somehow switch obj.state.Get(ctx) { case CloseTry: - if !obj.remote.state.Is(ctx, Open) { + if !obj.counterparty.state.Is(ctx, Open) { return errors.New("counterparty connection state not open") } case Closed: - if !obj.remote.state.Is(ctx, CloseTry) { + if !obj.counterparty.state.Is(ctx, CloseTry) { return errors.New("counterparty connection state not closetry") } } From b2841199b6031f0239b7aab36a6563672c9efd33 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 18:49:11 +0200 Subject: [PATCH 050/378] reformat over dependent icss --- x/ibc/03-connection/manager.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 09025ad5919f..d741d9f21977 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -140,6 +140,20 @@ func (obj Object) exists(ctx sdk.Context) bool { return obj.connection.Exists(ctx) } +// If there is no proof provided, assume not exists +func (obj CounterObject) exists(ctx sdk.Context) bool { + /* + // XXX + if !obj.connection.Proven(ctx) { + return false + } + + return obj.connection.Exists(ctx) + */ + + return false +} + func (obj Object) remove(ctx sdk.Context) { obj.connection.Delete(ctx) obj.state.Delete(ctx) From 33b3b2de594762a7f97453a955eabcf53d8aaaef Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 19:11:21 +0200 Subject: [PATCH 051/378] add CounterManager.Query/90 --- x/ibc/03-connection/manager.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index d741d9f21977..fd5e4a7ed78d 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -105,6 +105,11 @@ func (man Manager) Query(ctx sdk.Context, key string) (obj Object, err error) { return } +// XXX: add HasProof() method to commitment.Store, and check it here +func (man CounterpartyManager) Query(id string) CounterObject { + return man.object(id) +} + type NihiloObject Object type Object struct { From f835bab6ca55ad4d010fc2483020fbbe3ef158b7 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 12 Jun 2019 00:29:39 +0200 Subject: [PATCH 052/378] reflect downstream ics --- x/ibc/03-connection/manager.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index fd5e4a7ed78d..71009a7cb27b 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -4,7 +4,7 @@ import ( "errors" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/mapping" + "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client" @@ -15,22 +15,22 @@ import ( // XXX: all code using external KVStore should be defer-recovered in case of missing proofs type Manager struct { - protocol mapping.Mapping + protocol state.Mapping client client.Manager - self mapping.Indexer + self state.Indexer counterparty CounterpartyManager } -func NewManager(protocol, free mapping.Base, clientman client.Manager) Manager { +func NewManager(protocol, free state.Base, clientman client.Manager) Manager { return Manager{ - protocol: mapping.NewMapping(protocol, []byte("/connection/")), + protocol: state.NewMapping(protocol, []byte("/connection/")), client: clientman, - self: mapping.NewIndexer(free, []byte("/connection/self/"), mapping.Dec), + self: state.NewIndexer(free, []byte("/connection/self/"), state.Dec), counterparty: NewCounterpartyManager(protocol.Cdc()), } @@ -57,8 +57,8 @@ func (man Manager) object(id string) Object { return Object{ id: id, connection: man.protocol.Value([]byte(id)), - state: mapping.NewEnum(man.protocol.Value([]byte(id + "/state"))), - nexttimeout: mapping.NewInteger(man.protocol.Value([]byte(id+"/timeout")), mapping.Dec), + state: state.NewEnum(man.protocol.Value([]byte(id + "/state"))), + nexttimeout: state.NewInteger(man.protocol.Value([]byte(id+"/timeout")), state.Dec), self: man.self, } @@ -70,7 +70,7 @@ func (man CounterpartyManager) object(id string) CounterObject { id: id, connection: man.protocol.Value([]byte(id)), state: commitment.NewEnum(man.protocol.Value([]byte(id + "/state"))), - nexttimeout: commitment.NewInteger(man.protocol.Value([]byte(id+"/timeout")), mapping.Dec), + nexttimeout: commitment.NewInteger(man.protocol.Value([]byte(id+"/timeout")), state.Dec), } } @@ -114,14 +114,14 @@ type NihiloObject Object type Object struct { id string - connection mapping.Value - state mapping.Enum - nexttimeout mapping.Integer + connection state.Value + state state.Enum + nexttimeout state.Integer client client.Object counterparty CounterObject - self mapping.Indexer + self state.Indexer } type CounterObject struct { @@ -232,7 +232,7 @@ func (nobj NihiloObject) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeigh return errors.New("unexpected counterparty timeout value") } - var expected client.Client + var expected client.ConsensusState obj.self.Get(ctx, expheight, &expected) if !obj.counterparty.client.Is(ctx, expected) { return errors.New("unexpected counterparty client value") @@ -272,7 +272,7 @@ func (obj Object) OpenAck(ctx sdk.Context, expheight uint64, timeoutHeight, next return errors.New("unexpected counterparty timeout value") } - var expected client.Client + var expected client.ConsensusState obj.self.Get(ctx, expheight, &expected) if !obj.counterparty.client.Is(ctx, expected) { return errors.New("unexpected counterparty client value") @@ -312,7 +312,7 @@ func (obj Object) OpenConfirm(ctx sdk.Context, timeoutHeight uint64) error { } func (obj Object) OpenTimeout(ctx sdk.Context) error { - if !(uint64(obj.client.Value(ctx).GetBase().GetHeight()) > obj.nexttimeout.Get(ctx)) { + if !(uint64(obj.client.Value(ctx).GetHeight()) > obj.nexttimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } @@ -396,7 +396,7 @@ func (obj Object) CloseAck(ctx sdk.Context, timeoutHeight uint64) error { } func (obj Object) CloseTimeout(ctx sdk.Context) error { - if !(uint64(obj.client.Value(ctx).GetBase().GetHeight()) > obj.nexttimeout.Get(ctx)) { + if !(uint64(obj.client.Value(ctx).GetHeight()) > obj.nexttimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } From 6437f5928c773b78916ec69aaf8aadfd3a44f3a1 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 15:48:52 +0200 Subject: [PATCH 053/378] fix --- x/ibc/03-connection/manager.go | 12 ++---------- x/ibc/23-commitment/store.go | 10 ++++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 71009a7cb27b..4f876c326cfa 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -11,9 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -// XXX: rename remote to something else -// XXX: all code using external KVStore should be defer-recovered in case of missing proofs - type Manager struct { protocol state.Mapping @@ -105,11 +102,6 @@ func (man Manager) Query(ctx sdk.Context, key string) (obj Object, err error) { return } -// XXX: add HasProof() method to commitment.Store, and check it here -func (man CounterpartyManager) Query(id string) CounterObject { - return man.object(id) -} - type NihiloObject Object type Object struct { @@ -312,7 +304,7 @@ func (obj Object) OpenConfirm(ctx sdk.Context, timeoutHeight uint64) error { } func (obj Object) OpenTimeout(ctx sdk.Context) error { - if !(uint64(obj.client.Value(ctx).GetHeight()) > obj.nexttimeout.Get(ctx)) { + if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nexttimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } @@ -396,7 +388,7 @@ func (obj Object) CloseAck(ctx sdk.Context, timeoutHeight uint64) error { } func (obj Object) CloseTimeout(ctx sdk.Context) error { - if !(uint64(obj.client.Value(ctx).GetHeight()) > obj.nexttimeout.Get(ctx)) { + if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nexttimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 8cfaef4baaa1..7ad593d6f9d2 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -7,6 +7,7 @@ import ( type Store interface { Prove(key, value []byte) bool + HasProof(key []byte) bool } var _ Store = prefix{} @@ -23,6 +24,10 @@ func NewPrefix(store Store, pref []byte) prefix { } } +func (prefix prefix) HasProof(key []byte) bool { + return prefix.store.HasProof(join(prefix.prefix, key)) +} + func (prefix prefix) Prove(key, value []byte) bool { return prefix.store.Prove(join(prefix.prefix, key), value) } @@ -77,6 +82,11 @@ func (store store) Prove(key, value []byte) bool { return true } +func (store store) HasProof(key []byte) bool { + _, ok := store.proofs[string(key)] + return ok +} + func (store store) Proven(key []byte) bool { _, ok := store.Get(key) return ok From 927a2d07e8bb0b4d45bfc9e2b9832858a8f402b2 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 18:54:40 +0200 Subject: [PATCH 054/378] add test in progress --- x/ibc/03-connection/manager.go | 69 ++++---- x/ibc/03-connection/tests/connection_test.go | 22 +++ x/ibc/03-connection/tests/types.go | 159 +++++++++++++++++++ 3 files changed, 217 insertions(+), 33 deletions(-) create mode 100644 x/ibc/03-connection/tests/connection_test.go create mode 100644 x/ibc/03-connection/tests/types.go diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 4f876c326cfa..f788713bd634 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -21,14 +21,12 @@ type Manager struct { counterparty CounterpartyManager } -func NewManager(protocol, free state.Base, clientman client.Manager) Manager { +func NewManager(protocol state.Base, clientman client.Manager) Manager { return Manager{ protocol: state.NewMapping(protocol, []byte("/connection/")), client: clientman, - self: state.NewIndexer(free, []byte("/connection/self/"), state.Dec), - counterparty: NewCounterpartyManager(protocol.Cdc()), } } @@ -71,8 +69,8 @@ func (man CounterpartyManager) object(id string) CounterObject { } } -func (man Manager) Create(ctx sdk.Context, id string, connection Connection) (nobj NihiloObject, err error) { - obj := man.object(id) +func (man Manager) Create(ctx sdk.Context, id string, connection Connection) (obj Object, err error) { + obj = man.object(id) if obj.exists(ctx) { err = errors.New("connection already exists for the provided id") return @@ -84,7 +82,7 @@ func (man Manager) Create(ctx sdk.Context, id string, connection Connection) (no } obj.counterparty = man.counterparty.object(connection.Counterparty) obj.counterparty.client = man.counterparty.client.Query(connection.CounterpartyClient) - return NihiloObject(obj), nil + return obj, nil } func (man Manager) Query(ctx sdk.Context, key string) (obj Object, err error) { @@ -92,7 +90,7 @@ func (man Manager) Query(ctx sdk.Context, key string) (obj Object, err error) { if !obj.exists(ctx) { return Object{}, errors.New("connection not exists for the provided id") } - conn := obj.Value(ctx) + conn := obj.Connection(ctx) obj.client, err = man.client.Query(ctx, conn.Client) if err != nil { return @@ -102,8 +100,6 @@ func (man Manager) Query(ctx sdk.Context, key string) (obj Object, err error) { return } -type NihiloObject Object - type Object struct { id string connection state.Value @@ -129,8 +125,17 @@ func (obj Object) ID() string { return obj.id } -func (obj Object) ClientID() string { - return obj.client.ID() +func (obj Object) Connection(ctx sdk.Context) (res Connection) { + obj.connection.Get(ctx, &res) + return +} + +func (obj Object) State(ctx sdk.Context) byte { + return obj.state.Get(ctx) +} + +func (obj Object) Client() client.Object { + return obj.client } func (obj Object) exists(ctx sdk.Context) bool { @@ -158,7 +163,7 @@ func (obj Object) remove(ctx sdk.Context) { } func (obj Object) assertSymmetric(ctx sdk.Context) error { - if !obj.counterparty.connection.Is(ctx, obj.Value(ctx).Symmetry(obj.id)) { + if !obj.counterparty.connection.Is(ctx, obj.Connection(ctx).Symmetry(obj.id)) { return errors.New("unexpected counterparty connection value") } @@ -173,14 +178,7 @@ func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { return nil } -func (obj Object) Value(ctx sdk.Context) (res Connection) { - obj.connection.Get(ctx, &res) - return -} - -func (nobj NihiloObject) OpenInit(ctx sdk.Context, nextTimeoutHeight uint64) error { - - obj := Object(nobj) +func (obj Object) OpenInit(ctx sdk.Context, nextTimeoutHeight uint64) error { if obj.exists(ctx) { return errors.New("init on existing connection") } @@ -199,9 +197,7 @@ func (nobj NihiloObject) OpenInit(ctx sdk.Context, nextTimeoutHeight uint64) err return nil } -func (nobj NihiloObject) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { - - obj := Object(nobj) +func (obj Object) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { if !obj.state.Transit(ctx, Idle, OpenTry) { return errors.New("invalid state") } @@ -224,11 +220,15 @@ func (nobj NihiloObject) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeigh return errors.New("unexpected counterparty timeout value") } - var expected client.ConsensusState - obj.self.Get(ctx, expheight, &expected) - if !obj.counterparty.client.Is(ctx, expected) { - return errors.New("unexpected counterparty client value") - } + // TODO: commented out, need to check whether the stored client is compatible + // make a separate module that manages recent n block headers + /* + 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 @@ -264,11 +264,14 @@ func (obj Object) OpenAck(ctx sdk.Context, expheight uint64, timeoutHeight, next return errors.New("unexpected counterparty timeout value") } - var expected client.ConsensusState - obj.self.Get(ctx, expheight, &expected) - if !obj.counterparty.client.Is(ctx, expected) { - return errors.New("unexpected counterparty client value") - } + // TODO: commented out, implement in v1 + /* + var expected client.ConsensusState + obj.self.Get(ctx, expheight, &expected) + if !obj.counterparty.client.Is(ctx, expected) { + return errors.New("unexpected counterparty client value") + } + */ obj.nexttimeout.Set(ctx, uint64(nextTimeoutHeight)) diff --git a/x/ibc/03-connection/tests/connection_test.go b/x/ibc/03-connection/tests/connection_test.go new file mode 100644 index 000000000000..cdd4699b74b5 --- /dev/null +++ b/x/ibc/03-connection/tests/connection_test.go @@ -0,0 +1,22 @@ +package connection + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + + "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" +) + +func registerCodec(cdc *codec.Codec) { + client.RegisterCodec(cdc) +} + +func TestHandshake(t *testing.T) { + cdc := codec.New() + + node := NewNode(tendermint.NewMockValidators(10), tendermint.NewMockValidators(10)) +} diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go new file mode 100644 index 000000000000..cf6faa01712f --- /dev/null +++ b/x/ibc/03-connection/tests/types.go @@ -0,0 +1,159 @@ +package connection + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "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/ibc/02-client" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" +) + +type Node struct { + Name string + *tendermint.Node + Counterparty *CounterpartyNode + + State connection.State + + 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), + + State: connection.Idle, + Cdc: cdc, + } + + res.Counterparty = &CounterpartyNode{ + Name: "counterparty", + Node: tendermint.NewNode(counter), + Cdc: cdc, + + SelfName: &res.Name, + State: &res.State, + } + + return res +} + +func (node *Node) Object(t *testing.T) (sdk.Context, connection.Object) { + ctx, man, conn := node.Context(), node.Manager(), node.Connection() + switch node.State { + case connection.Idle: + obj, err := man.Create(ctx, node.Name, conn) + require.NoError(t, err) + return ctx, obj + default: + obj, err := man.Query(ctx, node.Name) + require.NoError(t, err) + require.Equal(t, conn, obj.Connection(ctx)) + return ctx, obj + } +} + +func (node *Node) Manager() connection.Manager { + base := state.NewBase(node.Cdc, node.Key) + protocol := base.Prefix([]byte("protocol/")) + free := base.Prefix([]byte("free/")) + clientman := client.NewManager(protocol, free, client.IntegerIDGenerator) + return connection.NewManager(base, clientman) +} + +func (node *Node) Connection() connection.Connection { + return connection.Connection{ + Counterparty: node.Counterparty.Name, + Client: node.Name + "client", + CounterpartyClient: node.Counterparty.Name + "client", + } +} + +type CounterpartyNode struct { + Name string + *tendermint.Node + + Cdc *codec.Codec + + // pointer to self + // TODO: improve + State *connection.State + SelfName *string +} + +func (node *CounterpartyNode) Object(t *testing.T) (sdk.Context, connection.Object) { + ctx, man, conn := node.Context(), node.Manager(), node.Connection() + switch *node.State { + case connection.Idle: + obj, err := man.Create(ctx, node.Name, conn) + require.NoError(t, err) + return ctx, obj + default: + obj, err := man.Query(ctx, node.Name) + require.NoError(t, err) + require.Equal(t, conn, obj.Connection(ctx)) + return ctx, obj + } +} +func (node *CounterpartyNode) Connection() connection.Connection { + return connection.Connection{ + Counterparty: *node.SelfName, + Client: node.Name + "client", + CounterpartyClient: *node.SelfName + "client", + } +} + +func (node *CounterpartyNode) Manager() connection.Manager { + base := state.NewBase(node.Cdc, node.Key) + protocol := base.Prefix([]byte("protocol/")) + free := base.Prefix([]byte("free/")) + clientman := client.NewManager(protocol, free, client.IntegerIDGenerator) + return connection.NewManager(base, clientman) +} + +func (node *Node) Advance(t *testing.T) { + switch node.State { + case connection.Idle: // self: Idle -> Init + ctx, obj := node.Object(t) + require.Equal(t, connection.Idle, obj.State(ctx)) + err := obj.OpenInit(ctx, 100) // TODO: test timeout + require.NoError(t, err) + require.Equal(t, connection.Init, obj.State(ctx)) + require.Equal(t, node.Connection(), obj.Connection(ctx)) + node.State = connection.Init + case connection.Init: // counter: Idle -> OpenTry + ctx, obj := node.Counterparty.Object(t) + require.Equal(t, connection.Idle, obj.State(ctx)) + err := obj.OpenTry(ctx, 0 /*TODO*/, 100 /*TODO*/, 100 /*TODO*/) + require.NoError(t, err) + require.Equal(t, connection.OpenTry, obj.State(ctx)) + require.Equal(t, node.Counterparty.Connection(), obj.Connection(ctx)) + node.State = connection.OpenTry + case connection.OpenTry: // self: Init -> Open + ctx, obj := node.Object(t) + require.Equal(t, connection.Init, obj.State(ctx)) + err := obj.OpenAck(ctx, 0 /*TODO*/, 100 /*TODO*/, 100 /*TODO*/) + require.NoError(t, err) + require.Equal(t, connection.Open, obj.State(ctx)) + require.Equal(t, node.Connection(), obj.Connection(ctx)) + node.State = connection.Open + case connection.Open: // counter: OpenTry -> Open + ctx, obj := node.Counterparty.Object(t) + require.Equal(t, connection.OpenTry, obj.State(ctx)) + err := obj.OpenConfirm(ctx, 100 /*TODO*/) + require.NoError(t, err) + require.Equal(t, connection.Open, obj.State(ctx)) + require.Equal(t, node.Counterparty.Connection(), obj.Connection(ctx)) + node.State = connection.CloseTry + // case connection.CloseTry // self: Open -> CloseTry + default: + return + } +} From c0ca538099463aeeffce5cac534c6811eff58266 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 19:09:32 +0200 Subject: [PATCH 055/378] add test in progress --- x/ibc/03-connection/tests/connection_test.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/x/ibc/03-connection/tests/connection_test.go b/x/ibc/03-connection/tests/connection_test.go index cdd4699b74b5..e2b47963044e 100644 --- a/x/ibc/03-connection/tests/connection_test.go +++ b/x/ibc/03-connection/tests/connection_test.go @@ -8,15 +8,26 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + tmclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) func registerCodec(cdc *codec.Codec) { client.RegisterCodec(cdc) + tmclient.RegisterCodec(cdc) + commitment.RegisterCodec(cdc) + merkle.RegisterCodec(cdc) } func TestHandshake(t *testing.T) { cdc := codec.New() + registerCodec(cdc) - node := NewNode(tendermint.NewMockValidators(10), tendermint.NewMockValidators(10)) + node := NewNode(tendermint.NewMockValidators(10), tendermint.NewMockValidators(10), cdc) + node.Advance(t) + node.Advance(t) + node.Advance(t) + node.Advance(t) } From 67818d53d069f5f9884b62a6a1f23ff4ecf505e2 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 28 Jun 2019 17:43:53 +0200 Subject: [PATCH 056/378] add test in progress/ --- x/ibc/02-client/cli.go | 32 ----- .../tendermint/tests/tendermint_test.go | 6 +- x/ibc/02-client/tendermint/tests/types.go | 39 ++--- x/ibc/03-connection/cli.go | 69 +++++++++ x/ibc/03-connection/manager.go | 54 +++---- x/ibc/03-connection/tests/connection_test.go | 32 ++++- x/ibc/03-connection/tests/types.go | 136 +++++++++--------- x/ibc/23-commitment/store.go | 23 +-- 8 files changed, 229 insertions(+), 162 deletions(-) create mode 100644 x/ibc/03-connection/cli.go diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 47302294efcc..2592e697573c 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -51,35 +51,3 @@ func (obj CLIObject) Frozen(ctx context.CLIContext, root merkle.Root) (res bool, proof, err = obj.query(ctx, obj.FrozenKey, &res) return } - -func query(ctx context.CLIContext, root merkle.Root, key []byte) ([]byte, merkle.Proof, error) { - resp, err := ctx.QueryABCI(root.RequestQuery(key)) - if err != nil { - return nil, merkle.Proof{}, err - } - proof := merkle.Proof{ - Key: key, - Proof: resp.Proof, - } - return resp.Value, proof, nil - -} - -func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle.Proof, err error) { - val, proof, err := query(ctx, root, obj.ConsensusStateKey) - obj.Cdc.MustUnmarshalBinaryBare(val, &res) - return -} - -func (obj CLIObject) Frozen(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { - val, tmproof, _, err := ctx.QueryProof(obj.FrozenKey, "ibc") // TODO - if err != nil { - return - } - proof = merkle.Proof{ - Key: obj.FrozenKey, - Proof: tmproof, - } - obj.Cdc.MustUnmarshalBinaryBare(val, &res) - return -} diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go index 8a1c764f50f2..d4a0397ef06b 100644 --- a/x/ibc/02-client/tendermint/tests/tendermint_test.go +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -7,17 +7,17 @@ import ( ) func testUpdate(t *testing.T, interval int, ok bool) { - node := NewNode(NewMockValidators(100, 10), newRoot()) + node := NewNode(NewMockValidators(100, 10), NewRoot([]byte("qwertyuiop"))) node.Commit() - verifier := node.LastStateVerifier(newRoot()) + verifier := node.LastStateVerifier() for i := 0; i < 100; i++ { header := node.Commit() if i%interval == 0 { - err := verifier.Validate(header, node.PrevValset, node.Valset) + err := verifier.Validate(header) if ok { require.NoError(t, err) } else { diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 5e0af44f3806..49b2a3a9460c 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -30,6 +30,9 @@ func newRoot() merkle.Root { const chainid = "testchain" +func NewRoot(keyPrefix []byte) merkle.Root { + return merkle.NewRoot(nil, [][]byte{[]byte("test")}, keyPrefix) +} func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { key := sdk.NewKVStoreKey("test") db := dbm.NewMemDB() @@ -76,7 +79,7 @@ func (node *Node) Last() tmtypes.SignedHeader { return node.Commits[len(node.Commits)-1] } -func (node *Node) Commit() tmtypes.SignedHeader { +func (node *Node) Commit() tendermint.Header { valsethash := node.Valset.ValidatorSet().Hash() nextvalset := node.Valset.Mutate() nextvalsethash := nextvalset.ValidatorSet().Hash() @@ -99,12 +102,17 @@ func (node *Node) Commit() tmtypes.SignedHeader { node.PrevValset = node.Valset node.Valset = nextvalset node.Commits = append(node.Commits, commit) + node.Root = node.Root.Update(header.AppHash).(merkle.Root) - return commit + return tendermint.Header{ + SignedHeader: commit, + ValidatorSet: node.PrevValset.ValidatorSet(), + NextValidatorSet: node.Valset.ValidatorSet(), + } } -func (node *Node) LastStateVerifier(root merkle.Root) *Verifier { - return NewVerifier(node.Last(), node.Valset, root) +func (node *Node) LastStateVerifier() *Verifier { + return NewVerifier(node.Last(), node.Valset, node.Root) } func (node *Node) Context() sdk.Context { @@ -126,14 +134,8 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root me } } -func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset MockValidators) error { - newcs, err := v.ConsensusState.Validate( - tendermint.Header{ - SignedHeader: header, - ValidatorSet: valset.ValidatorSet(), - NextValidatorSet: nextvalset.ValidatorSet(), - }, - ) +func (v *Verifier) Validate(header tendermint.Header) error { + newcs, err := v.ConsensusState.Validate(header) if err != nil { return err } @@ -142,8 +144,8 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset Mock return nil } -func (node *Node) Query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { - code, value, proof := root.QueryMultiStore(node.Cms, k) +func (node *Node) Query(t *testing.T, k []byte) ([]byte, commitment.Proof) { + code, value, proof := node.Root.QueryMultiStore(node.Cms, k) require.Equal(t, uint32(0), code) return value, proof } @@ -154,7 +156,7 @@ func (node *Node) Set(k, value []byte) { // nolint:deadcode,unused func testProof(t *testing.T) { - node := NewNode(NewMockValidators(100, 10), newRoot()) + node := NewNode(NewMockValidators(100, 10), NewRoot([]byte{0x34, 0x90, 0xDA})) node.Commit() @@ -170,15 +172,14 @@ func testProof(t *testing.T) { kvps = append(kvps, cmn.KVPair{Key: k, Value: v}) node.Set(k, v) } - header := node.Commit() + _ = node.Commit() proofs := []commitment.Proof{} - root := node.Root.Update(header.AppHash) for _, kvp := range kvps { - v, p := node.Query(t, root.(merkle.Root), kvp.Key) + v, p := node.Query(t, kvp.Key) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } - cstore, err := commitment.NewStore(root, proofs) + cstore, err := commitment.NewStore(node.Root, proofs) require.NoError(t, err) for _, kvp := range kvps { diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go new file mode 100644 index 000000000000..3df848ffb953 --- /dev/null +++ b/x/ibc/03-connection/cli.go @@ -0,0 +1,69 @@ +package connection + +import ( + "time" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + + "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +// CLIObject stores the key for each object fields +type CLIObject struct { + ID string + ConnectionKey []byte + StateKey []byte + NextTimeoutKey []byte + + Client client.CLIObject + + Root merkle.Root + Cdc *codec.Codec +} + +func (man Manager) CLIObject(root merkle.Root, id string) CLIObject { + obj := man.object(id) + return CLIObject{ + ID: obj.id, + ConnectionKey: obj.connection.Key(), + StateKey: obj.state.Key(), + NextTimeoutKey: obj.nextTimeout.Key(), + + // TODO: unify man.CLIObject() <=> obj.CLI() + Client: obj.client.CLI(root), + + Root: root, + Cdc: obj.connection.Cdc(), + } +} + +func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { + resp, err := ctx.QueryABCI(obj.Root.RequestQuery(key)) + if err != nil { + return merkle.Proof{}, err + } + proof := merkle.Proof{ + Key: key, + Proof: resp.Proof, + } + err = obj.Cdc.UnmarshalBinaryBare(resp.Value, ptr) + return proof, err + +} + +func (obj CLIObject) Connection(ctx context.CLIContext, root merkle.Root) (res Connection, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.ConnectionKey, &res) + return +} + +func (obj CLIObject) State(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.StateKey, &res) + return +} + +func (obj CLIObject) NextTimeout(ctx context.CLIContext, root merkle.Root) (res time.Time, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.NextTimeoutKey, &res) + return +} diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index f788713bd634..7c0668bc0dbd 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -2,6 +2,7 @@ package connection import ( "errors" + "fmt" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/state" @@ -53,7 +54,7 @@ func (man Manager) object(id string) Object { id: id, connection: man.protocol.Value([]byte(id)), state: state.NewEnum(man.protocol.Value([]byte(id + "/state"))), - nexttimeout: state.NewInteger(man.protocol.Value([]byte(id+"/timeout")), state.Dec), + nextTimeout: state.NewInteger(man.protocol.Value([]byte(id+"/timeout")), state.Dec), self: man.self, } @@ -65,11 +66,12 @@ func (man CounterpartyManager) object(id string) CounterObject { id: id, connection: man.protocol.Value([]byte(id)), state: commitment.NewEnum(man.protocol.Value([]byte(id + "/state"))), - nexttimeout: commitment.NewInteger(man.protocol.Value([]byte(id+"/timeout")), state.Dec), + nextTimeout: commitment.NewInteger(man.protocol.Value([]byte(id+"/timeout")), state.Dec), } } func (man Manager) Create(ctx sdk.Context, id string, connection Connection) (obj Object, err error) { + fmt.Println("create", id, connection) obj = man.object(id) if obj.exists(ctx) { err = errors.New("connection already exists for the provided id") @@ -104,7 +106,7 @@ type Object struct { id string connection state.Value state state.Enum - nexttimeout state.Integer + nextTimeout state.Integer client client.Object @@ -116,7 +118,7 @@ type CounterObject struct { id string connection commitment.Value state commitment.Enum - nexttimeout commitment.Integer + nextTimeout commitment.Integer client client.CounterObject } @@ -159,7 +161,7 @@ func (obj CounterObject) exists(ctx sdk.Context) bool { func (obj Object) remove(ctx sdk.Context) { obj.connection.Delete(ctx) obj.state.Delete(ctx) - obj.nexttimeout.Delete(ctx) + obj.nextTimeout.Delete(ctx) } func (obj Object) assertSymmetric(ctx sdk.Context) error { @@ -178,11 +180,8 @@ func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { return nil } +// Using proofs: none func (obj Object) OpenInit(ctx sdk.Context, nextTimeoutHeight uint64) error { - if obj.exists(ctx) { - return errors.New("init on existing connection") - } - if !obj.state.Transit(ctx, Idle, Init) { return errors.New("init on non-idle connection") } @@ -192,31 +191,36 @@ func (obj Object) OpenInit(ctx sdk.Context, nextTimeoutHeight uint64) error { // assert(get("connections/{identifier}") === null) and // set("connections{identifier}", connection) - obj.nexttimeout.Set(ctx, nextTimeoutHeight) + obj.nextTimeout.Set(ctx, nextTimeoutHeight) return nil } +// Using proofs: counterparty.{connection,state,nextTimeout,client} func (obj Object) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { if !obj.state.Transit(ctx, Idle, OpenTry) { return errors.New("invalid state") } + fmt.Println(12345) err := assertTimeout(ctx, timeoutHeight) if err != nil { return err } + fmt.Println(67890) if !obj.counterparty.state.Is(ctx, Init) { return errors.New("counterparty state not init") } + fmt.Println(97) err = obj.assertSymmetric(ctx) if err != nil { return err } - if !obj.counterparty.nexttimeout.Is(ctx, uint64(timeoutHeight)) { + fmt.Println(65) + if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { return errors.New("unexpected counterparty timeout value") } @@ -235,11 +239,12 @@ func (obj Object) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeight, next // assert(get("connections/{desiredIdentifier}") === null) and // set("connections{identifier}", connection) - obj.nexttimeout.Set(ctx, nextTimeoutHeight) + obj.nextTimeout.Set(ctx, nextTimeoutHeight) return nil } +// Using proofs: counterparty.{connection,state, nextTimeout} func (obj Object) OpenAck(ctx sdk.Context, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { if !obj.state.Transit(ctx, Init, Open) { @@ -260,7 +265,7 @@ func (obj Object) OpenAck(ctx sdk.Context, expheight uint64, timeoutHeight, next return err } - if !obj.counterparty.nexttimeout.Is(ctx, uint64(timeoutHeight)) { + if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { return errors.New("unexpected counterparty timeout value") } @@ -273,11 +278,12 @@ func (obj Object) OpenAck(ctx sdk.Context, expheight uint64, timeoutHeight, next } */ - obj.nexttimeout.Set(ctx, uint64(nextTimeoutHeight)) + obj.nextTimeout.Set(ctx, uint64(nextTimeoutHeight)) return nil } +// Using proofs: counterparty.{connection,state, nextTimeout} func (obj Object) OpenConfirm(ctx sdk.Context, timeoutHeight uint64) error { if !obj.state.Transit(ctx, OpenTry, Open) { return errors.New("confirm on non-try connection") @@ -297,17 +303,17 @@ func (obj Object) OpenConfirm(ctx sdk.Context, timeoutHeight uint64) error { return err } - if !obj.counterparty.nexttimeout.Is(ctx, timeoutHeight) { + if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { return errors.New("unexpected counterparty timeout value") } - obj.nexttimeout.Set(ctx, 0) + obj.nextTimeout.Set(ctx, 0) return nil } func (obj Object) OpenTimeout(ctx sdk.Context) error { - if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nexttimeout.Get(ctx)) { + if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } @@ -339,7 +345,7 @@ func (obj Object) CloseInit(ctx sdk.Context, nextTimeout uint64) error { return errors.New("closeinit on non-open connection") } - obj.nexttimeout.Set(ctx, nextTimeout) + obj.nextTimeout.Set(ctx, nextTimeout) return nil } @@ -358,11 +364,11 @@ func (obj Object) CloseTry(ctx sdk.Context, timeoutHeight, nextTimeoutHeight uin return errors.New("unexpected counterparty state value") } - if !obj.counterparty.nexttimeout.Is(ctx, timeoutHeight) { + if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { return errors.New("unexpected counterparty timeout value") } - obj.nexttimeout.Set(ctx, nextTimeoutHeight) + obj.nextTimeout.Set(ctx, nextTimeoutHeight) return nil } @@ -381,17 +387,17 @@ func (obj Object) CloseAck(ctx sdk.Context, timeoutHeight uint64) error { return errors.New("unexpected counterparty state value") } - if !obj.counterparty.nexttimeout.Is(ctx, timeoutHeight) { + if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { return errors.New("unexpected counterparty timeout value") } - obj.nexttimeout.Set(ctx, 0) + obj.nextTimeout.Set(ctx, 0) return nil } func (obj Object) CloseTimeout(ctx sdk.Context) error { - if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nexttimeout.Get(ctx)) { + if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } @@ -408,7 +414,7 @@ func (obj Object) CloseTimeout(ctx sdk.Context) error { } obj.state.Set(ctx, Open) - obj.nexttimeout.Set(ctx, 0) + obj.nextTimeout.Set(ctx, 0) return nil diff --git a/x/ibc/03-connection/tests/connection_test.go b/x/ibc/03-connection/tests/connection_test.go index e2b47963044e..4ff890630135 100644 --- a/x/ibc/03-connection/tests/connection_test.go +++ b/x/ibc/03-connection/tests/connection_test.go @@ -1,10 +1,9 @@ package connection import ( + "fmt" "testing" - "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/ibc/02-client" @@ -19,15 +18,40 @@ func registerCodec(cdc *codec.Codec) { tmclient.RegisterCodec(cdc) commitment.RegisterCodec(cdc) merkle.RegisterCodec(cdc) + codec.RegisterCrypto(cdc) } func TestHandshake(t *testing.T) { cdc := codec.New() registerCodec(cdc) - node := NewNode(tendermint.NewMockValidators(10), tendermint.NewMockValidators(10), cdc) - node.Advance(t) + node := NewNode(tendermint.NewMockValidators(100, 10), tendermint.NewMockValidators(100, 10), cdc) + node.Commit() + node.Counterparty.Commit() + + node.CreateClient(t) + node.Counterparty.CreateClient(t) + + // self.OpenInit node.Advance(t) + header := node.Commit() + + fmt.Printf("ddd\n\n\n\n%+v\n", node.Root) + + // counterparty.OpenTry + node.Counterparty.UpdateClient(t, header) + cliobj := node.CLIObject() + _, pconn := node.Query(t, cliobj.ConnectionKey) + fmt.Printf("\n\n\n\n%s: %+v, %s\n", cliobj.ConnectionKey, pconn.(merkle.Proof).Proof, string(pconn.(merkle.Proof).Key)) + _, pstate := node.Query(t, cliobj.StateKey) + _, ptimeout := node.Query(t, cliobj.NextTimeoutKey) + // TODO: implement consensus state checking + // _, pclient := node.Query(t, cliobj.Client.ConsensusStateKey) + node.Advance(t, pconn, pstate, ptimeout) + + // self.OpenAck node.Advance(t) + + // counterparty.OpenConfirm node.Advance(t) } diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index cf6faa01712f..4a6d31a2f47e 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -12,145 +12,137 @@ import ( "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" ) type Node struct { Name string *tendermint.Node - Counterparty *CounterpartyNode + Counterparty *Node - State connection.State + Connection connection.Connection + State connection.State 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), + Name: "self", // hard coded, doesnt matter + Node: tendermint.NewNode(self, tendermint.NewRoot([]byte("protocol"))), // TODO: test with key prefix State: connection.Idle, Cdc: cdc, } - res.Counterparty = &CounterpartyNode{ - Name: "counterparty", - Node: tendermint.NewNode(counter), - Cdc: cdc, + res.Counterparty = &Node{ + Name: "counterparty", + Node: tendermint.NewNode(counter, tendermint.NewRoot([]byte("protocol"))), + Counterparty: res, - SelfName: &res.Name, - State: &res.State, + State: connection.Idle, + Cdc: cdc, } - return res -} + res.Connection = connection.Connection{ + Counterparty: res.Counterparty.Name, + } -func (node *Node) Object(t *testing.T) (sdk.Context, connection.Object) { - ctx, man, conn := node.Context(), node.Manager(), node.Connection() - switch node.State { - case connection.Idle: - obj, err := man.Create(ctx, node.Name, conn) - require.NoError(t, err) - return ctx, obj - default: - obj, err := man.Query(ctx, node.Name) - require.NoError(t, err) - require.Equal(t, conn, obj.Connection(ctx)) - return ctx, obj + res.Counterparty.Connection = connection.Connection{ + Counterparty: res.Name, } -} -func (node *Node) Manager() connection.Manager { - base := state.NewBase(node.Cdc, node.Key) - protocol := base.Prefix([]byte("protocol/")) - free := base.Prefix([]byte("free/")) - clientman := client.NewManager(protocol, free, client.IntegerIDGenerator) - return connection.NewManager(base, clientman) + return res } -func (node *Node) Connection() connection.Connection { - return connection.Connection{ - Counterparty: node.Counterparty.Name, - Client: node.Name + "client", - CounterpartyClient: node.Counterparty.Name + "client", - } +func (node *Node) CreateClient(t *testing.T) { + ctx := node.Context() + climan, _ := node.Manager() + obj, err := climan.Create(ctx, node.Counterparty.LastStateVerifier().ConsensusState) + require.NoError(t, err) + node.Connection.Client = obj.ID() + node.Counterparty.Connection.CounterpartyClient = obj.ID() } -type CounterpartyNode struct { - Name string - *tendermint.Node - - Cdc *codec.Codec - - // pointer to self - // TODO: improve - State *connection.State - SelfName *string +func (node *Node) UpdateClient(t *testing.T, header client.Header) { + ctx := node.Context() + climan, _ := node.Manager() + obj, err := climan.Query(ctx, node.Connection.Client) + require.NoError(t, err) + err = obj.Update(ctx, header) + require.NoError(t, err) } -func (node *CounterpartyNode) Object(t *testing.T) (sdk.Context, connection.Object) { - ctx, man, conn := node.Context(), node.Manager(), node.Connection() - switch *node.State { +func (node *Node) Object(t *testing.T, proofs []commitment.Proof) (sdk.Context, connection.Object) { + ctx := node.Context() + store, err := commitment.NewStore(node.Counterparty.Root, proofs) + require.NoError(t, err) + ctx = commitment.WithStore(ctx, store) + _, man := node.Manager() + switch node.State { case connection.Idle: - obj, err := man.Create(ctx, node.Name, conn) + obj, err := man.Create(ctx, node.Name, node.Connection) require.NoError(t, err) return ctx, obj default: obj, err := man.Query(ctx, node.Name) require.NoError(t, err) - require.Equal(t, conn, obj.Connection(ctx)) + require.Equal(t, node.Connection, obj.Connection(ctx)) return ctx, obj } } -func (node *CounterpartyNode) Connection() connection.Connection { - return connection.Connection{ - Counterparty: *node.SelfName, - Client: node.Name + "client", - CounterpartyClient: *node.SelfName + "client", - } + +func (node *Node) CLIObject() connection.CLIObject { + _, man := node.Manager() + return man.CLIObject(node.Root, node.Name) +} + +func base(cdc *codec.Codec, key sdk.StoreKey) (state.Base, state.Base) { + base := state.NewBase(cdc, key) + protocol := base.Prefix([]byte("protocol")) + free := base.Prefix([]byte("free")) + return protocol, free } -func (node *CounterpartyNode) Manager() connection.Manager { - base := state.NewBase(node.Cdc, node.Key) - protocol := base.Prefix([]byte("protocol/")) - free := base.Prefix([]byte("free/")) +func (node *Node) Manager() (client.Manager, connection.Manager) { + protocol, free := base(node.Cdc, node.Key) clientman := client.NewManager(protocol, free, client.IntegerIDGenerator) - return connection.NewManager(base, clientman) + return clientman, connection.NewManager(protocol, clientman) } -func (node *Node) Advance(t *testing.T) { +func (node *Node) Advance(t *testing.T, proofs ...commitment.Proof) { switch node.State { case connection.Idle: // self: Idle -> Init - ctx, obj := node.Object(t) + ctx, obj := node.Object(t, proofs) require.Equal(t, connection.Idle, obj.State(ctx)) err := obj.OpenInit(ctx, 100) // TODO: test timeout require.NoError(t, err) require.Equal(t, connection.Init, obj.State(ctx)) - require.Equal(t, node.Connection(), obj.Connection(ctx)) + require.Equal(t, node.Connection, obj.Connection(ctx)) node.State = connection.Init case connection.Init: // counter: Idle -> OpenTry - ctx, obj := node.Counterparty.Object(t) + ctx, obj := node.Counterparty.Object(t, proofs) require.Equal(t, connection.Idle, obj.State(ctx)) err := obj.OpenTry(ctx, 0 /*TODO*/, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.OpenTry, obj.State(ctx)) - require.Equal(t, node.Counterparty.Connection(), obj.Connection(ctx)) + require.Equal(t, node.Counterparty.Connection, obj.Connection(ctx)) node.State = connection.OpenTry case connection.OpenTry: // self: Init -> Open - ctx, obj := node.Object(t) + ctx, obj := node.Object(t, proofs) require.Equal(t, connection.Init, obj.State(ctx)) err := obj.OpenAck(ctx, 0 /*TODO*/, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.Open, obj.State(ctx)) - require.Equal(t, node.Connection(), obj.Connection(ctx)) + require.Equal(t, node.Connection, obj.Connection(ctx)) node.State = connection.Open case connection.Open: // counter: OpenTry -> Open - ctx, obj := node.Counterparty.Object(t) + ctx, obj := node.Counterparty.Object(t, proofs) require.Equal(t, connection.OpenTry, obj.State(ctx)) err := obj.OpenConfirm(ctx, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.Open, obj.State(ctx)) - require.Equal(t, node.Counterparty.Connection(), obj.Connection(ctx)) + require.Equal(t, node.Counterparty.Connection, obj.Connection(ctx)) node.State = connection.CloseTry // case connection.CloseTry // self: Open -> CloseTry default: diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 7ad593d6f9d2..4a90426defcb 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -3,6 +3,7 @@ package commitment import ( "bytes" "errors" + "fmt" ) type Store interface { @@ -10,7 +11,7 @@ type Store interface { HasProof(key []byte) bool } -var _ Store = prefix{} +var _ Store = prefix{} // TODO: pointer type prefix struct { store Store @@ -32,7 +33,7 @@ func (prefix prefix) Prove(key, value []byte) bool { return prefix.store.Prove(join(prefix.prefix, key), value) } -var _ Store = store{} +var _ Store = (*store)(nil) type store struct { root Root @@ -41,8 +42,8 @@ type store struct { } // Proofs must be provided -func NewStore(root Root, proofs []Proof) (res store, err error) { - res = store{ +func NewStore(root Root, proofs []Proof) (res *store, err error) { + res = &store{ root: root, proofs: make(map[string]Proof), verified: make(map[string][]byte), @@ -53,28 +54,34 @@ func NewStore(root Root, proofs []Proof) (res store, err error) { err = errors.New("proof type not matching with root's") return } + fmt.Println("set key", string(proof.GetKey())) res.proofs[string(proof.GetKey())] = proof } + fmt.Printf("%+v\n", res) + return } -func (store store) Get(key []byte) ([]byte, bool) { +func (store *store) Get(key []byte) ([]byte, bool) { res, ok := store.verified[string(key)] return res, ok } -func (store store) Prove(key, value []byte) bool { +func (store *store) Prove(key, value []byte) bool { stored, ok := store.Get(key) if ok && bytes.Equal(stored, value) { return true } proof, ok := store.proofs[string(key)] if !ok { + fmt.Println("no proof") + fmt.Println("get key", string(key)) return false } err := proof.Verify(store.root, value) if err != nil { + fmt.Println("invalid proof") return false } store.verified[string(key)] = value @@ -82,12 +89,12 @@ func (store store) Prove(key, value []byte) bool { return true } -func (store store) HasProof(key []byte) bool { +func (store *store) HasProof(key []byte) bool { _, ok := store.proofs[string(key)] return ok } -func (store store) Proven(key []byte) bool { +func (store *store) Proven(key []byte) bool { _, ok := store.Get(key) return ok } From d5bed425b6687ecf3c8776b4f6c25be46f71933e Mon Sep 17 00:00:00 2001 From: mossid Date: Sat, 29 Jun 2019 14:10:53 +0200 Subject: [PATCH 057/378] add test in progress 02 --- x/ibc/02-client/manager.go | 2 ++ x/ibc/02-client/tendermint/tests/types.go | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index e94d14702b72..5d52613be9df 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -2,6 +2,7 @@ package client import ( "errors" + "fmt" "strconv" "github.com/cosmos/cosmos-sdk/store/state" @@ -27,6 +28,7 @@ type Manager struct { } func NewManager(protocol, free state.Base, idgen IDGenerator) Manager { + fmt.Println(1234567890, protocol, free) return Manager{ protocol: state.NewMapping(protocol, []byte("/client")), idval: state.NewValue(free, []byte("/client/id")), diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 49b2a3a9460c..860cb424e11d 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -145,9 +145,10 @@ func (v *Verifier) Validate(header tendermint.Header) error { } func (node *Node) Query(t *testing.T, k []byte) ([]byte, commitment.Proof) { - code, value, proof := node.Root.QueryMultiStore(node.Cms, k) - require.Equal(t, uint32(0), code) - return value, proof + qres, proof, err := node.Root.QueryMultiStore(node.Cms, k) + require.NoError(t, err) + require.Equal(t, uint32(0), qres.Code) + return qres.Value, proof } func (node *Node) Set(k, value []byte) { From 93f35b8ed2f3e95591f896c53900c46005397ef4 Mon Sep 17 00:00:00 2001 From: mossid Date: Sat, 29 Jun 2019 14:11:04 +0200 Subject: [PATCH 058/378] add test in progress 23 --- x/ibc/23-commitment/merkle/merkle_test.go | 38 +++++++++++------------ x/ibc/23-commitment/merkle/utils.go | 37 ++++++++++++++++++++-- 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index a1886519eafc..5e15b8384cfb 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -36,6 +36,14 @@ func commit(cms types.CommitMultiStore, root Root) Root { return root.Update(cid.Hash).(Root) } +func queryMultiStore(t *testing.T, root Root, cms types.CommitMultiStore, key, value []byte) Proof { + q, p, err := root.QueryMultiStore(cms, key) + require.Equal(t, uint32(0), q.Code) + require.NoError(t, err) + require.Equal(t, value, q.Value) + return p +} + func TestStore(t *testing.T) { k, ctx, cms, _ := defaultComponents() kvstore := ctx.KVStore(k) @@ -47,15 +55,9 @@ func TestStore(t *testing.T) { root = commit(cms, root) - c1, v1, p1 := root.QueryMultiStore(cms, []byte("hello")) - require.Equal(t, uint32(0), c1) - require.Equal(t, []byte("world"), v1) - c2, v2, p2 := root.QueryMultiStore(cms, []byte("merkle")) - require.Equal(t, uint32(0), c2) - require.Equal(t, []byte("tree"), v2) - c3, v3, p3 := root.QueryMultiStore(cms, []byte("block")) - require.Equal(t, uint32(0), c3) - require.Equal(t, []byte("chain"), v3) + p1 := queryMultiStore(t, root, cms, []byte("hello"), []byte("world")) + p2 := queryMultiStore(t, root, cms, []byte("merkle"), []byte("tree")) + p3 := queryMultiStore(t, root, cms, []byte("block"), []byte("chain")) cstore, err := commitment.NewStore(root, []commitment.Proof{p1, p2, p3}) require.NoError(t, err) @@ -70,20 +72,16 @@ func TestStore(t *testing.T) { root = commit(cms, root) - c1, v1, p1 = root.QueryMultiStore(cms, []byte("12345")) - require.Equal(t, uint32(0), c1) - require.Equal(t, []byte("67890"), v1) - c2, v2, p2 = root.QueryMultiStore(cms, []byte("qwerty")) - require.Equal(t, uint32(0), c2) - require.Equal(t, []byte("zxcv"), v2) - c3, v3, p3 = root.QueryMultiStore(cms, []byte("hello")) - require.Equal(t, uint32(0), c3) - require.Equal(t, []byte("dlrow"), v3) - - cstore, err = commitment.NewStore(root, []commitment.Proof{p1, p2, p3}) + p1 = queryMultiStore(t, root, cms, []byte("12345"), []byte("67890")) + p2 = queryMultiStore(t, root, cms, []byte("qwerty"), []byte("zxcv")) + p3 = queryMultiStore(t, root, cms, []byte("hello"), []byte("dlrow")) + p4 := queryMultiStore(t, root, cms, []byte("merkle"), []byte("tree")) + + cstore, err = commitment.NewStore(root, []commitment.Proof{p1, p2, p3, p4}) require.NoError(t, err) require.True(t, cstore.Prove([]byte("12345"), []byte("67890"))) require.True(t, cstore.Prove([]byte("qwerty"), []byte("zxcv"))) require.True(t, cstore.Prove([]byte("hello"), []byte("dlrow"))) + require.True(t, cstore.Prove([]byte("merkle"), []byte("tree"))) } diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index b16d0854e2af..8e4ec43fb021 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -1,8 +1,13 @@ package merkle import ( + "bytes" + "errors" + "fmt" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/store/types" ) @@ -16,9 +21,35 @@ func (root Root) RequestQueryMultiStore(key []byte) abci.RequestQuery { return abci.RequestQuery{Path: root.Path() + "/key", Data: root.Key(key), Prove: true} } -func (root Root) QueryMultiStore(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { - qres := cms.(types.Queryable).Query(root.RequestQueryMultiStore(key)) - return qres.Code, qres.Value, Proof{Key: key, Proof: qres.Proof} +// QueryMultiStore prefixes the root.KeyPrefix to the key +func (root Root) QueryMultiStore(cms types.CommitMultiStore, key []byte) (qres abci.ResponseQuery, proof Proof, err error) { + qres = cms.(types.Queryable).Query(root.RequestQueryMultiStore(key)) + proof = Proof{Key: key, Proof: qres.Proof} + return +} + +// TrimPrefix is used when the input key is generate with prefix +// so need to be trimmed +func (root Root) trimPrefix(key []byte) ([]byte, error) { + if !bytes.HasPrefix(key, root.KeyPrefix) { + fmt.Println(string(key), key, string(root.KeyPrefix), root.KeyPrefix) + return nil, errors.New("key not starting with root key prefix") + } + return bytes.TrimPrefix(key, root.KeyPrefix), nil +} + +// QueryCLI does NOT prefixes the root.KeyPrefix to the key +func (root Root) QueryCLI(ctx context.CLIContext, key []byte) (qres abci.ResponseQuery, proof Proof, err error) { + qres, err = ctx.QueryABCI(root.RequestQueryMultiStore(key)) + if err != nil { + return + } + trimkey, err := root.trimPrefix(key) + if err != nil { + return + } + proof = Proof{Key: trimkey, Proof: qres.Proof} + return } func (root Root) Key(key []byte) []byte { From 82d8a7cb9d0d60b5f86e8ea35224f791c205cd8c Mon Sep 17 00:00:00 2001 From: mossid Date: Sat, 29 Jun 2019 14:40:30 +0200 Subject: [PATCH 059/378] handshake test now working --- store/state/base.go | 12 +++++++--- x/ibc/02-client/manager.go | 2 -- x/ibc/03-connection/manager.go | 6 ----- x/ibc/03-connection/tests/connection_test.go | 22 +++++++++++++------ x/ibc/03-connection/tests/types.go | 23 ++++++++++++-------- x/ibc/23-commitment/store.go | 7 ------ 6 files changed, 38 insertions(+), 34 deletions(-) diff --git a/store/state/base.go b/store/state/base.go index f163c18b98a0..a6f429053248 100644 --- a/store/state/base.go +++ b/store/state/base.go @@ -15,13 +15,19 @@ type Base struct { } func EmptyBase() Base { - return NewBase(nil, nil) + return NewBase(nil, nil, nil) } -func NewBase(cdc *codec.Codec, key sdk.StoreKey) Base { +func NewBase(cdc *codec.Codec, key sdk.StoreKey, rootkey []byte) Base { + if len(rootkey) == 0 { + return Base{ + cdc: cdc, + storefn: func(ctx Context) KVStore { return ctx.KVStore(key) }, + } + } return Base{ cdc: cdc, - storefn: func(ctx Context) KVStore { return ctx.KVStore(key) }, + storefn: func(ctx Context) KVStore { return prefix.NewStore(ctx.KVStore(key), rootkey) }, } } diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 5d52613be9df..e94d14702b72 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -2,7 +2,6 @@ package client import ( "errors" - "fmt" "strconv" "github.com/cosmos/cosmos-sdk/store/state" @@ -28,7 +27,6 @@ type Manager struct { } func NewManager(protocol, free state.Base, idgen IDGenerator) Manager { - fmt.Println(1234567890, protocol, free) return Manager{ protocol: state.NewMapping(protocol, []byte("/client")), idval: state.NewValue(free, []byte("/client/id")), diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 7c0668bc0dbd..3c12fe5851d6 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -2,7 +2,6 @@ package connection import ( "errors" - "fmt" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/state" @@ -71,7 +70,6 @@ func (man CounterpartyManager) object(id string) CounterObject { } func (man Manager) Create(ctx sdk.Context, id string, connection Connection) (obj Object, err error) { - fmt.Println("create", id, connection) obj = man.object(id) if obj.exists(ctx) { err = errors.New("connection already exists for the provided id") @@ -202,24 +200,20 @@ func (obj Object) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeight, next return errors.New("invalid state") } - fmt.Println(12345) err := assertTimeout(ctx, timeoutHeight) if err != nil { return err } - fmt.Println(67890) if !obj.counterparty.state.Is(ctx, Init) { return errors.New("counterparty state not init") } - fmt.Println(97) err = obj.assertSymmetric(ctx) if err != nil { return err } - fmt.Println(65) if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { return errors.New("unexpected counterparty timeout value") } diff --git a/x/ibc/03-connection/tests/connection_test.go b/x/ibc/03-connection/tests/connection_test.go index 4ff890630135..338218542322 100644 --- a/x/ibc/03-connection/tests/connection_test.go +++ b/x/ibc/03-connection/tests/connection_test.go @@ -1,7 +1,6 @@ package connection import ( - "fmt" "testing" "github.com/cosmos/cosmos-sdk/codec" @@ -36,22 +35,31 @@ func TestHandshake(t *testing.T) { node.Advance(t) header := node.Commit() - fmt.Printf("ddd\n\n\n\n%+v\n", node.Root) - // counterparty.OpenTry node.Counterparty.UpdateClient(t, header) cliobj := node.CLIObject() _, pconn := node.Query(t, cliobj.ConnectionKey) - fmt.Printf("\n\n\n\n%s: %+v, %s\n", cliobj.ConnectionKey, pconn.(merkle.Proof).Proof, string(pconn.(merkle.Proof).Key)) _, pstate := node.Query(t, cliobj.StateKey) _, ptimeout := node.Query(t, cliobj.NextTimeoutKey) // TODO: implement consensus state checking // _, pclient := node.Query(t, cliobj.Client.ConsensusStateKey) - node.Advance(t, pconn, pstate, ptimeout) + node.Advance(t, pconn, pstate, ptimeout /*, pclient*/) + header = node.Counterparty.Commit() // self.OpenAck - node.Advance(t) + node.UpdateClient(t, header) + cliobj = node.Counterparty.CLIObject() + _, pconn = node.Counterparty.Query(t, cliobj.ConnectionKey) + _, pstate = node.Counterparty.Query(t, cliobj.StateKey) + _, ptimeout = node.Counterparty.Query(t, cliobj.NextTimeoutKey) + node.Advance(t, pconn, pstate, ptimeout) + header = node.Commit() // counterparty.OpenConfirm - node.Advance(t) + node.Counterparty.UpdateClient(t, header) + cliobj = node.CLIObject() + _, pconn = node.Query(t, cliobj.ConnectionKey) // TODO: check if it is needed + _, pstate = node.Query(t, cliobj.StateKey) + _, ptimeout = node.Query(t, cliobj.NextTimeoutKey) + node.Advance(t, pconn, pstate, ptimeout) } diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index 4a6d31a2f47e..18d941cad038 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -73,6 +73,11 @@ func (node *Node) UpdateClient(t *testing.T, header client.Header) { require.NoError(t, err) } +func (node *Node) SetState(state connection.State) { + node.State = state + node.Counterparty.State = state +} + func (node *Node) Object(t *testing.T, proofs []commitment.Proof) (sdk.Context, connection.Object) { ctx := node.Context() store, err := commitment.NewStore(node.Counterparty.Root, proofs) @@ -80,7 +85,7 @@ func (node *Node) Object(t *testing.T, proofs []commitment.Proof) (sdk.Context, ctx = commitment.WithStore(ctx, store) _, man := node.Manager() switch node.State { - case connection.Idle: + case connection.Idle, connection.Init: obj, err := man.Create(ctx, node.Name, node.Connection) require.NoError(t, err) return ctx, obj @@ -98,9 +103,8 @@ func (node *Node) CLIObject() connection.CLIObject { } func base(cdc *codec.Codec, key sdk.StoreKey) (state.Base, state.Base) { - base := state.NewBase(cdc, key) - protocol := base.Prefix([]byte("protocol")) - free := base.Prefix([]byte("free")) + protocol := state.NewBase(cdc, key, []byte("protocol")) + free := state.NewBase(cdc, key, []byte("free")) return protocol, free } @@ -112,6 +116,7 @@ func (node *Node) Manager() (client.Manager, connection.Manager) { func (node *Node) Advance(t *testing.T, proofs ...commitment.Proof) { switch node.State { + // TODO: use different enum type for node.State case connection.Idle: // self: Idle -> Init ctx, obj := node.Object(t, proofs) require.Equal(t, connection.Idle, obj.State(ctx)) @@ -119,7 +124,7 @@ func (node *Node) Advance(t *testing.T, proofs ...commitment.Proof) { require.NoError(t, err) require.Equal(t, connection.Init, obj.State(ctx)) require.Equal(t, node.Connection, obj.Connection(ctx)) - node.State = connection.Init + node.SetState(connection.Init) case connection.Init: // counter: Idle -> OpenTry ctx, obj := node.Counterparty.Object(t, proofs) require.Equal(t, connection.Idle, obj.State(ctx)) @@ -127,7 +132,7 @@ func (node *Node) Advance(t *testing.T, proofs ...commitment.Proof) { require.NoError(t, err) require.Equal(t, connection.OpenTry, obj.State(ctx)) require.Equal(t, node.Counterparty.Connection, obj.Connection(ctx)) - node.State = connection.OpenTry + node.SetState(connection.OpenTry) case connection.OpenTry: // self: Init -> Open ctx, obj := node.Object(t, proofs) require.Equal(t, connection.Init, obj.State(ctx)) @@ -135,7 +140,7 @@ func (node *Node) Advance(t *testing.T, proofs ...commitment.Proof) { require.NoError(t, err) require.Equal(t, connection.Open, obj.State(ctx)) require.Equal(t, node.Connection, obj.Connection(ctx)) - node.State = connection.Open + node.SetState(connection.Open) case connection.Open: // counter: OpenTry -> Open ctx, obj := node.Counterparty.Object(t, proofs) require.Equal(t, connection.OpenTry, obj.State(ctx)) @@ -143,8 +148,8 @@ func (node *Node) Advance(t *testing.T, proofs ...commitment.Proof) { require.NoError(t, err) require.Equal(t, connection.Open, obj.State(ctx)) require.Equal(t, node.Counterparty.Connection, obj.Connection(ctx)) - node.State = connection.CloseTry - // case connection.CloseTry // self: Open -> CloseTry + node.SetState(connection.CloseTry) + // case connection.CloseTry // self: Open -> CloseTry default: return } diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 4a90426defcb..a5640db907c3 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" ) type Store interface { @@ -54,12 +53,9 @@ func NewStore(root Root, proofs []Proof) (res *store, err error) { err = errors.New("proof type not matching with root's") return } - fmt.Println("set key", string(proof.GetKey())) res.proofs[string(proof.GetKey())] = proof } - fmt.Printf("%+v\n", res) - return } @@ -75,13 +71,10 @@ func (store *store) Prove(key, value []byte) bool { } proof, ok := store.proofs[string(key)] if !ok { - fmt.Println("no proof") - fmt.Println("get key", string(key)) return false } err := proof.Verify(store.root, value) if err != nil { - fmt.Println("invalid proof") return false } store.verified[string(key)] = value From 1b47501d7459efc80964ad86a909289369f22795 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 5 Jul 2019 01:18:36 +0200 Subject: [PATCH 060/378] modularize connection in progress --- store/state/mapping.go | 4 + store/state/string.go | 23 ++ store/state/types.go | 2 + x/ibc/03-connection/cli.go | 27 +- x/ibc/03-connection/handshake/manager.go | 374 ++++++++++++++++++++ x/ibc/03-connection/handshake/types.go | 60 ++++ x/ibc/03-connection/manager.go | 419 +++++------------------ x/ibc/03-connection/types.go | 38 +- x/ibc/23-commitment/value.go | 18 + 9 files changed, 595 insertions(+), 370 deletions(-) create mode 100644 store/state/string.go create mode 100644 x/ibc/03-connection/handshake/manager.go create mode 100644 x/ibc/03-connection/handshake/types.go diff --git a/store/state/mapping.go b/store/state/mapping.go index 566077a62237..0d0ae990cf5a 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -54,3 +54,7 @@ func (m Mapping) IsEmpty(ctx Context) bool { func (m Mapping) Prefix(prefix []byte) Mapping { return NewMapping(m.base, prefix) } + +func (m Mapping) Cdc() *Codec { + return m.base.Cdc() +} diff --git a/store/state/string.go b/store/state/string.go new file mode 100644 index 000000000000..38b92b16ec71 --- /dev/null +++ b/store/state/string.go @@ -0,0 +1,23 @@ +package state + +type String struct { + Value +} + +func NewString(v Value) String { + return String{v} +} + +func (v String) Get(ctx Context) (res string) { + v.Value.Get(ctx, &res) + return +} + +func (v String) GetSafe(ctx Context) (res string, err error) { + v.Value.GetSafe(ctx, &res) + return +} + +func (v String) Set(ctx Context, value string) { + v.Value.Set(ctx, value) +} diff --git a/store/state/types.go b/store/state/types.go index f5dbb4dc8648..a058cf6ddf0a 100644 --- a/store/state/types.go +++ b/store/state/types.go @@ -4,6 +4,7 @@ import ( "github.com/tendermint/tendermint/crypto/merkle" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -11,3 +12,4 @@ type KVStore = sdk.KVStore type Context = sdk.Context type CLIContext = context.CLIContext type Proof = merkle.Proof +type Codec = codec.Codec diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index 3df848ffb953..ffbebcb0d27e 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -1,8 +1,6 @@ package connection import ( - "time" - "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" @@ -12,10 +10,11 @@ import ( // CLIObject stores the key for each object fields type CLIObject struct { - ID string - ConnectionKey []byte - StateKey []byte - NextTimeoutKey []byte + ID string + ConnectionKey []byte + // StateKey []byte + // NextTimeoutKey []byte + PermissionKey []byte Client client.CLIObject @@ -26,10 +25,11 @@ type CLIObject struct { func (man Manager) CLIObject(root merkle.Root, id string) CLIObject { obj := man.object(id) return CLIObject{ - ID: obj.id, - ConnectionKey: obj.connection.Key(), - StateKey: obj.state.Key(), - NextTimeoutKey: obj.nextTimeout.Key(), + ID: obj.id, + ConnectionKey: obj.connection.Key(), + // StateKey: obj.state.Key(), + // NextTimeoutKey: obj.nextTimeout.Key(), + PermissionKey: obj.permission.Key(), // TODO: unify man.CLIObject() <=> obj.CLI() Client: obj.client.CLI(root), @@ -58,6 +58,7 @@ func (obj CLIObject) Connection(ctx context.CLIContext, root merkle.Root) (res C return } +/* func (obj CLIObject) State(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.StateKey, &res) return @@ -67,3 +68,9 @@ func (obj CLIObject) NextTimeout(ctx context.CLIContext, root merkle.Root) (res proof, err = obj.query(ctx, obj.NextTimeoutKey, &res) return } +*/ + +func (obj CLIObject) Permission(ctx context.CLIContext, root merkle.Root) (res string, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.PermissionKey, &res) + return +} diff --git a/x/ibc/03-connection/handshake/manager.go b/x/ibc/03-connection/handshake/manager.go new file mode 100644 index 000000000000..38b4816e0fd4 --- /dev/null +++ b/x/ibc/03-connection/handshake/manager.go @@ -0,0 +1,374 @@ +package handshake + +import ( + "errors" + + "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/ibc/02-client" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +type Manager struct { + connection.PermissionedManager + + counterparty CounterpartyManager +} + +func NewManager(man connection.PermissionedManager) Manager { + return Manager{ + PermissionedManager: man, + + counterparty: NewCounterpartyManager(man.Cdc()), + } +} + +type CounterpartyManager struct { + protocol commitment.Mapping + + client client.CounterpartyManager +} + +func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { + protocol := commitment.NewBase(cdc) + + return CounterpartyManager{ + protocol: commitment.NewMapping(protocol, []byte("/connection/")), + + client: client.NewCounterpartyManager(protocol), + } +} + +// CONTRACT: client and remote must be filled by the caller +func (man Manager) object(parent connection.Object) Object { + return Object{ + Object: parent, + + nextTimeout: state.NewInteger(parent.Mapping().Value([]byte("/timeout")), state.Dec), + + counterparty: man.counterparty.object(parent.Counterparty()), + } +} + +func (man CounterpartyManager) object(parent connection.CounterObject) CounterObject { + return CounterObject{ + CounterObject: parent, + + nextTimeout: commitment.NewInteger(parent.Mapping.Value([]byte("/timeout")), state.Dec), + } +} + +func (man Manager) Create(ctx sdk.Context, id string, connection Connection) (obj Object, err error) { + cobj, err := man.PermissionedManager.Create(ctx, id, connection) + if err != nil { + return + } + obj = man.object(cobj) + return obj, nil +} + +func (man Manager) query(ctx sdk.Context, id string) (obj Object, err error) { + cobj, err := man.PermissionedManager.Query(ctx, id) + if err != nil { + return + } + obj = man.object(cobj) + return +} + +type Object struct { + connection.Object + + nextTimeout state.Integer + + client client.Object + + counterparty CounterObject +} + +type CounterObject struct { + connection.CounterObject + + nextTimeout commitment.Integer + + client client.CounterObject +} + +func (obj Object) NextTimeout(ctx sdk.Context) uint64 { + return obj.nextTimeout.Get(ctx) +} + +// If there is no proof provided, assume not exists +func (obj CounterObject) exists(ctx sdk.Context) bool { + /* + // XXX + if !obj.connection.Proven(ctx) { + return false + } + + return obj.connection.Exists(ctx) + */ + + return false +} + +// TODO: make it private +func (obj Object) Delete(ctx sdk.Context) { + obj.Object.Remove(ctx) + obj.nextTimeout.Delete(ctx) +} + +func (obj Object) assertSymmetric(ctx sdk.Context) error { + if !obj.counterparty.connection.Is(ctx, obj.Connection(ctx).Symmetry(obj.id)) { + return errors.New("unexpected counterparty connection value") + } + + return nil +} + +func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { + if uint64(ctx.BlockHeight()) > timeoutHeight { + return errors.New("timeout") + } + + return nil +} + +// Using proofs: none +func (obj Object) OpenInit(ctx sdk.Context, nextTimeoutHeight uint64) error { + if !obj.state.Transit(ctx, Idle, Init) { + return errors.New("init on non-idle connection") + } + + // CONTRACT: OpenInit() should be called after man.Create(), not man.Query(), + // which will ensure + // assert(get("connections/{identifier}") === null) and + // set("connections{identifier}", connection) + + obj.nextTimeout.Set(ctx, nextTimeoutHeight) + + return nil +} + +// Using proofs: counterparty.{connection,state,nextTimeout,client} +func (obj Object) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { + if !obj.state.Transit(ctx, Idle, OpenTry) { + return errors.New("invalid state") + } + + err := assertTimeout(ctx, timeoutHeight) + if err != nil { + return err + } + + if !obj.counterparty.state.Is(ctx, Init) { + return errors.New("counterparty state not init") + } + + err = obj.assertSymmetric(ctx) + if err != nil { + return err + } + + if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { + return errors.New("unexpected counterparty timeout value") + } + + // TODO: commented out, need to check whether the stored client is compatible + // make a separate module that manages recent n block headers + /* + 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.nextTimeout.Set(ctx, nextTimeoutHeight) + + return nil +} + +// Using proofs: counterparty.{connection,state, nextTimeout} +func (obj Object) OpenAck(ctx sdk.Context, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { + + if !obj.state.Transit(ctx, Init, Open) { + return errors.New("ack on non-init connection") + } + + err := assertTimeout(ctx, timeoutHeight) + if err != nil { + return err + } + + if !obj.counterparty.state.Is(ctx, OpenTry) { + return errors.New("counterparty state not try") + } + + err = obj.assertSymmetric(ctx) + if err != nil { + return err + } + + if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { + return errors.New("unexpected counterparty timeout value") + } + + // TODO: commented out, implement in v1 + /* + var expected client.ConsensusState + obj.self.Get(ctx, expheight, &expected) + if !obj.counterparty.client.Is(ctx, expected) { + return errors.New("unexpected counterparty client value") + } + */ + + obj.nextTimeout.Set(ctx, uint64(nextTimeoutHeight)) + + return nil +} + +// Using proofs: counterparty.{connection,state, nextTimeout} +func (obj Object) OpenConfirm(ctx sdk.Context, timeoutHeight uint64) error { + if !obj.state.Transit(ctx, OpenTry, Open) { + return errors.New("confirm on non-try connection") + } + + err := assertTimeout(ctx, timeoutHeight) + if err != nil { + return err + } + + if !obj.counterparty.state.Is(ctx, Open) { + return errors.New("counterparty state not open") + } + + err = obj.assertSymmetric(ctx) + if err != nil { + return err + } + + if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { + return errors.New("unexpected counterparty timeout value") + } + + obj.nextTimeout.Set(ctx, 0) + + return nil +} + +func (obj Object) OpenTimeout(ctx sdk.Context) error { + if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { + return errors.New("timeout height not yet reached") + } + + // XXX: double check if a user can bypass the verification logic somehow + 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.exists(ctx)) { + 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 Object) 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 Object) 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 Object) 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 Object) CloseTimeout(ctx sdk.Context) error { + if !(uint64(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/03-connection/handshake/types.go b/x/ibc/03-connection/handshake/types.go new file mode 100644 index 000000000000..786948991ad1 --- /dev/null +++ b/x/ibc/03-connection/handshake/types.go @@ -0,0 +1,60 @@ +package handshake + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" +) + +type State = byte + +const ( + Idle State = iota + Init + OpenTry + Open + CloseTry + Closed +) + +var _ connection.Connection = Connection{} + +// TODO: Connection is amino marshaled currently, need to implement MarshalBinary manually +type Connection struct { + Counterparty string + Client string + CounterpartyClient string + State State +} + +func (conn Connection) GetCounterparty() string { + return conn.Counterparty +} + +func (conn Connection) GetClient() string { + return conn.Client +} + +func (conn Connection) GetCounterpartyClient() string { + return conn.CounterpartyClient +} + +func (conn Connection) Available() bool { + return conn.State == Open +} + +func (conn Connection) Equal(conn0 Connection) bool { + return conn.Counterparty == conn0.Counterparty && + conn.Client == conn0.Client && + conn.CounterpartyClient == conn0.CounterpartyClient +} + +func (conn Connection) Symmetric(id string, conn0 Connection) bool { + return conn0.Equal(conn.Symmetry(id)) +} + +func (conn Connection) Symmetry(id string) Connection { + return Connection{ + Counterparty: id, + Client: conn.CounterpartyClient, + CounterpartyClient: conn.Client, + } +} diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 3c12fe5851d6..bd74bddf142e 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -14,111 +14,118 @@ import ( type Manager struct { protocol state.Mapping - client client.Manager + table map[string]struct{} - self state.Indexer + client client.Manager counterparty CounterpartyManager } -func NewManager(protocol state.Base, clientman client.Manager) Manager { - return Manager{ - protocol: state.NewMapping(protocol, []byte("/connection/")), - - client: clientman, - - counterparty: NewCounterpartyManager(protocol.Cdc()), - } -} - type CounterpartyManager struct { protocol commitment.Mapping client client.CounterpartyManager } -func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { - protocol := commitment.NewBase(cdc) +// CONTRACT: should be called on initialization time only +func (man Manager) Register(name string) PermissionedManager { + if _, ok := man.table[name]; ok { + panic("SubManager registered for existing name") + } + man.table[name] = struct{}{} - return CounterpartyManager{ - protocol: commitment.NewMapping(protocol, []byte("/connection/")), + return PermissionedManager{man, name} +} - client: client.NewCounterpartyManager(protocol), - } +func (man Manager) mapping(id string) state.Mapping { + return man.protocol.Prefix([]byte(id)) } -// CONTRACT: client and remote must be filled by the caller func (man Manager) object(id string) Object { return Object{ - id: id, - connection: man.protocol.Value([]byte(id)), - state: state.NewEnum(man.protocol.Value([]byte(id + "/state"))), - nextTimeout: state.NewInteger(man.protocol.Value([]byte(id+"/timeout")), state.Dec), + id: id, + connection: man.protocol.Value([]byte(id)), + permission: state.NewString(man.protocol.Value([]byte(id + "/permission"))), + + mapping: man.protocol.Prefix([]byte(id)), + + // CONTRACT: client should be filled by the caller - self: man.self, + counterparty: man.counterparty.object(id), } } -// CONTRACT: client must be filled by the caller func (man CounterpartyManager) object(id string) CounterObject { return CounterObject{ - id: id, - connection: man.protocol.Value([]byte(id)), - state: commitment.NewEnum(man.protocol.Value([]byte(id + "/state"))), - nextTimeout: commitment.NewInteger(man.protocol.Value([]byte(id+"/timeout")), state.Dec), + ID: id, + Connection: man.protocol.Value([]byte(id)), + Permission: commitment.NewString(man.protocol.Value([]byte(id + "/permission"))), + + // CONTRACT: client should be filled by the caller + + Mapping: man.protocol.Prefix([]byte(id)), } } -func (man Manager) Create(ctx sdk.Context, id string, connection Connection) (obj Object, err error) { +func (man Manager) Query(ctx sdk.Context, id string) (obj Object, err error) { obj = man.object(id) - if obj.exists(ctx) { - err = errors.New("connection already exists for the provided id") + if !obj.exists(ctx) { + err = errors.New("Object not exists") return } - obj.connection.Set(ctx, connection) - obj.client, err = man.client.Query(ctx, connection.Client) - if err != nil { + obj.client, err = man.client.Query(ctx, obj.Connection(ctx).GetClient()) + return +} + +type PermissionedManager struct { + man Manager + name string +} + +func (man PermissionedManager) Cdc() *codec.Codec { + return man.man.protocol.Cdc() +} + +func (man PermissionedManager) object(id string) Object { + return man.man.object(id) +} + +func (man PermissionedManager) Create(ctx sdk.Context, id string, connection Connection) (obj Object, err error) { + obj = man.object(id) + if obj.exists(ctx) { + err = errors.New("Object already exists") return } - obj.counterparty = man.counterparty.object(connection.Counterparty) - obj.counterparty.client = man.counterparty.client.Query(connection.CounterpartyClient) - return obj, nil + obj.connection.Set(ctx, connection) + obj.permission.Set(ctx, man.name) + obj.client, err = man.man.client.Query(ctx, connection.GetClient()) + return } -func (man Manager) Query(ctx sdk.Context, key string) (obj Object, err error) { - obj = man.object(key) +func (man PermissionedManager) Query(ctx sdk.Context, id string) (obj Object, err error) { + obj = man.object(id) if !obj.exists(ctx) { - return Object{}, errors.New("connection not exists for the provided id") + err = errors.New("Object not exists") + return } - conn := obj.Connection(ctx) - obj.client, err = man.client.Query(ctx, conn.Client) - if err != nil { + if obj.Permission(ctx) != man.name { + err = errors.New("Object created with different permission") return } - obj.counterparty = man.counterparty.object(conn.Counterparty) - obj.counterparty.client = man.counterparty.client.Query(conn.CounterpartyClient) + obj.client, err = man.man.client.Query(ctx, obj.Connection(ctx).GetClient()) return } type Object struct { - id string - connection state.Value - state state.Enum - nextTimeout state.Integer + id string + connection state.Value // Connection + permission state.String + + mapping state.Mapping client client.Object counterparty CounterObject - self state.Indexer -} - -type CounterObject struct { - id string - connection commitment.Value - state commitment.Enum - nextTimeout commitment.Integer - - client client.CounterObject } func (obj Object) ID() string { @@ -130,286 +137,42 @@ func (obj Object) Connection(ctx sdk.Context) (res Connection) { return } -func (obj Object) State(ctx sdk.Context) byte { - return obj.state.Get(ctx) +// TODO: it should not be exposed +func (obj Object) Permission(ctx sdk.Context) string { + return obj.permission.Get(ctx) } -func (obj Object) Client() client.Object { - return obj.client +func (obj Object) Mapping() state.Mapping { + return obj.mapping } -func (obj Object) exists(ctx sdk.Context) bool { - return obj.connection.Exists(ctx) +func (obj Object) Counterparty() CounterObject { + return obj.counterparty } -// If there is no proof provided, assume not exists -func (obj CounterObject) exists(ctx sdk.Context) bool { - /* - // XXX - if !obj.connection.Proven(ctx) { - return false - } - - return obj.connection.Exists(ctx) - */ - - return false +func (obj Object) exists(ctx sdk.Context) bool { + return obj.connection.Exists(ctx) } -func (obj Object) remove(ctx sdk.Context) { +func (obj Object) Delete(ctx sdk.Context) { obj.connection.Delete(ctx) - obj.state.Delete(ctx) - obj.nextTimeout.Delete(ctx) -} - -func (obj Object) assertSymmetric(ctx sdk.Context) error { - if !obj.counterparty.connection.Is(ctx, obj.Connection(ctx).Symmetry(obj.id)) { - return errors.New("unexpected counterparty connection value") - } - - return nil -} - -func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { - if uint64(ctx.BlockHeight()) > timeoutHeight { - return errors.New("timeout") - } - - return nil -} - -// Using proofs: none -func (obj Object) OpenInit(ctx sdk.Context, nextTimeoutHeight uint64) error { - if !obj.state.Transit(ctx, Idle, Init) { - return errors.New("init on non-idle connection") - } - - // CONTRACT: OpenInit() should be called after man.Create(), not man.Query(), - // which will ensure - // assert(get("connections/{identifier}") === null) and - // set("connections{identifier}", connection) - - obj.nextTimeout.Set(ctx, nextTimeoutHeight) - - return nil -} - -// Using proofs: counterparty.{connection,state,nextTimeout,client} -func (obj Object) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { - if !obj.state.Transit(ctx, Idle, OpenTry) { - return errors.New("invalid state") - } - - err := assertTimeout(ctx, timeoutHeight) - if err != nil { - return err - } - - if !obj.counterparty.state.Is(ctx, Init) { - return errors.New("counterparty state not init") - } - - err = obj.assertSymmetric(ctx) - if err != nil { - return err - } - - if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { - return errors.New("unexpected counterparty timeout value") - } - - // TODO: commented out, need to check whether the stored client is compatible - // make a separate module that manages recent n block headers - /* - 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.nextTimeout.Set(ctx, nextTimeoutHeight) - - return nil -} - -// Using proofs: counterparty.{connection,state, nextTimeout} -func (obj Object) OpenAck(ctx sdk.Context, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { - - if !obj.state.Transit(ctx, Init, Open) { - return errors.New("ack on non-init connection") - } - - err := assertTimeout(ctx, timeoutHeight) - if err != nil { - return err - } - - if !obj.counterparty.state.Is(ctx, OpenTry) { - return errors.New("counterparty state not try") - } - - err = obj.assertSymmetric(ctx) - if err != nil { - return err - } - - if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { - return errors.New("unexpected counterparty timeout value") - } - - // TODO: commented out, implement in v1 - /* - var expected client.ConsensusState - obj.self.Get(ctx, expheight, &expected) - if !obj.counterparty.client.Is(ctx, expected) { - return errors.New("unexpected counterparty client value") - } - */ - - obj.nextTimeout.Set(ctx, uint64(nextTimeoutHeight)) - - return nil + obj.permission.Delete(ctx) } -// Using proofs: counterparty.{connection,state, nextTimeout} -func (obj Object) OpenConfirm(ctx sdk.Context, timeoutHeight uint64) error { - if !obj.state.Transit(ctx, OpenTry, Open) { - return errors.New("confirm on non-try connection") - } - - err := assertTimeout(ctx, timeoutHeight) - if err != nil { - return err - } - - if !obj.counterparty.state.Is(ctx, Open) { - return errors.New("counterparty state not open") - } - - err = obj.assertSymmetric(ctx) - if err != nil { - return err - } - - if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { - return errors.New("unexpected counterparty timeout value") - } - - obj.nextTimeout.Set(ctx, 0) - - return nil -} - -func (obj Object) OpenTimeout(ctx sdk.Context) error { - if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { - return errors.New("timeout height not yet reached") - } - - // XXX: double check if a user can bypass the verification logic somehow - 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.exists(ctx)) { - 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 Object) 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 Object) 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 Object) 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") - } +type CounterObject struct { + ID string + Connection commitment.Value + Permission commitment.String - obj.nextTimeout.Set(ctx, 0) + Mapping commitment.Mapping - return nil + Client client.CounterObject } -func (obj Object) CloseTimeout(ctx sdk.Context) error { - if !(uint64(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 - -} +// Flow(DEPRECATED): +// 1. a module calls SubManager.{Create, Query}() +// 2. SubManager calls StateManager.RequestBase(id string) +// 3-1. If id is not reserved, StateManager marks id as reserved and returns base +// 3-2. If id is reserved, StateManager checks if the SubManager is one who reserved +// 4. if okay, Manager return the base, which only Manager has access +// 5. SubManager returns the result of method call diff --git a/x/ibc/03-connection/types.go b/x/ibc/03-connection/types.go index 50df047a6b21..62f5de12b2a5 100644 --- a/x/ibc/03-connection/types.go +++ b/x/ibc/03-connection/types.go @@ -1,37 +1,11 @@ package connection -type State = byte +import () -const ( - Idle State = iota - Init - OpenTry - Open - CloseTry - Closed -) +type Connection interface { + GetCounterparty() string + GetClient() string + GetCounterpartyClient() string -// TODO: Connection is amino marshaled currently, need to implement MarshalBinary manually -type Connection struct { - Counterparty string - Client string - CounterpartyClient string -} - -func (conn Connection) Equal(conn0 Connection) bool { - return conn.Counterparty == conn0.Counterparty && - conn.Client == conn0.Client && - conn.CounterpartyClient == conn0.CounterpartyClient -} - -func (conn Connection) Symmetric(id string, conn0 Connection) bool { - return conn0.Equal(conn.Symmetry(id)) -} - -func (conn Connection) Symmetry(id string) Connection { - return Connection{ - Counterparty: id, - Client: conn.CounterpartyClient, - CounterpartyClient: conn.Client, - } + Available() bool } diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 10b409b28b99..d2ef335d00e0 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -45,6 +45,12 @@ func NewMapping(base Base, prefix []byte) Mapping { } } +func (m Mapping) Prefix(prefix []byte) Mapping { + return Mapping{ + base: m.base.Prefix(prefix), + } +} + func (m Mapping) Value(key []byte) Value { return Value{ base: m.base, @@ -81,6 +87,18 @@ func (v Enum) Is(ctx sdk.Context, value byte) bool { return v.Value.IsRaw(ctx, []byte{value}) } +type String struct { + Value +} + +func NewString(v Value) String { + return String{v} +} + +func (v String) Is(ctx sdk.Context, value string) bool { + return v.Value.Is(ctx, value) +} + type Integer struct { Value From a2a0233ba1db6366dbbdbf570d42987653075d0e Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 5 Jul 2019 21:07:46 +0200 Subject: [PATCH 061/378] fix all syntax errors --- x/ibc/03-connection/cli.go | 17 +- .../{handshake/manager.go => handshake.go} | 249 +++++++++--------- x/ibc/03-connection/manager.go | 197 +++++++------- x/ibc/23-commitment/value.go | 12 + 4 files changed, 245 insertions(+), 230 deletions(-) rename x/ibc/03-connection/{handshake/manager.go => handshake.go} (52%) diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index ffbebcb0d27e..a76c89c37097 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -1,5 +1,6 @@ package connection +/* import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" @@ -8,13 +9,12 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) + // CLIObject stores the key for each object fields type CLIObject struct { - ID string - ConnectionKey []byte - // StateKey []byte - // NextTimeoutKey []byte - PermissionKey []byte + ID string + ClientIDKey []byte + AvailableKey []byte Client client.CLIObject @@ -26,6 +26,8 @@ func (man Manager) CLIObject(root merkle.Root, id string) CLIObject { obj := man.object(id) return CLIObject{ ID: obj.id, + ClientIDKey: obj.clientid.Key(), + Available ConnectionKey: obj.connection.Key(), // StateKey: obj.state.Key(), // NextTimeoutKey: obj.nextTimeout.Key(), @@ -68,9 +70,12 @@ func (obj CLIObject) NextTimeout(ctx context.CLIContext, root merkle.Root) (res proof, err = obj.query(ctx, obj.NextTimeoutKey, &res) return } -*/ +:w +:w + func (obj CLIObject) Permission(ctx context.CLIContext, root merkle.Root) (res string, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.PermissionKey, &res) return } +*/ diff --git a/x/ibc/03-connection/handshake/manager.go b/x/ibc/03-connection/handshake.go similarity index 52% rename from x/ibc/03-connection/handshake/manager.go rename to x/ibc/03-connection/handshake.go index 38b4816e0fd4..ed1e3bb405e0 100644 --- a/x/ibc/03-connection/handshake/manager.go +++ b/x/ibc/03-connection/handshake.go @@ -1,134 +1,138 @@ -package handshake +package connection import ( "errors" - "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/ibc/02-client" - "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -type Manager struct { - connection.PermissionedManager +type State = byte - counterparty CounterpartyManager +const ( + Idle State = iota + Init + OpenTry + Open + CloseTry + Closed +) + +type Handshake struct { + Counterparty string + CounterpartyClient string } -func NewManager(man connection.PermissionedManager) Manager { - return Manager{ - PermissionedManager: man, +type Handshaker struct { + man Manager - counterparty: NewCounterpartyManager(man.Cdc()), - } + counterparty CounterpartyHandshaker +} + +func (man Handshaker) Kind() string { + return "handshake" } -type CounterpartyManager struct { - protocol commitment.Mapping +// 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, - client client.CounterpartyManager + counterparty: CounterpartyHandshaker{man.counterparty}, + } } -func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { - protocol := commitment.NewBase(cdc) +type CounterpartyHandshaker struct { + man CounterpartyManager +} - return CounterpartyManager{ - protocol: commitment.NewMapping(protocol, []byte("/connection/")), +type HandshakeObject struct { + Object - client: client.NewCounterpartyManager(protocol), - } + state state.Enum + handshake state.Value // type Handshake + nextTimeout state.Integer + + counterparty CounterHandshakeObject +} + +type CounterHandshakeObject struct { + CounterObject + + state commitment.Enum + handshake commitment.Value + nextTimeout commitment.Integer } // CONTRACT: client and remote must be filled by the caller -func (man Manager) object(parent connection.Object) Object { - return Object{ +func (man Handshaker) object(parent Object) HandshakeObject { + return HandshakeObject{ Object: parent, - nextTimeout: state.NewInteger(parent.Mapping().Value([]byte("/timeout")), state.Dec), + state: state.NewEnum(man.man.protocol.Value([]byte(parent.id + "/state"))), + handshake: man.man.protocol.Value([]byte(parent.id + "/handshake")), + nextTimeout: state.NewInteger(man.man.protocol.Value([]byte(parent.id+"/timeout")), state.Dec), - counterparty: man.counterparty.object(parent.Counterparty()), + // CONTRACT: counterparty must be filled by the caller } } -func (man CounterpartyManager) object(parent connection.CounterObject) CounterObject { - return CounterObject{ - CounterObject: parent, +func (man CounterpartyHandshaker) object(id string) CounterHandshakeObject { + return CounterHandshakeObject{ + CounterObject: man.man.object(id), - nextTimeout: commitment.NewInteger(parent.Mapping.Value([]byte("/timeout")), state.Dec), + state: commitment.NewEnum(man.man.protocol.Value([]byte(id + "/state"))), + handshake: man.man.protocol.Value([]byte(id + "/handshake")), + nextTimeout: commitment.NewInteger(man.man.protocol.Value([]byte(id+"/timeout")), state.Dec), } } -func (man Manager) Create(ctx sdk.Context, id string, connection Connection) (obj Object, err error) { - cobj, err := man.PermissionedManager.Create(ctx, id, connection) +func (man Handshaker) create(ctx sdk.Context, id, clientid string, handshake Handshake) (obj HandshakeObject, err error) { + cobj, err := man.man.create(ctx, id, clientid, man.Kind()) if err != nil { return } obj = man.object(cobj) + obj.handshake.Set(ctx, handshake) + obj.counterparty = man.counterparty.object(handshake.Counterparty) return obj, nil } -func (man Manager) query(ctx sdk.Context, id string) (obj Object, err error) { - cobj, err := man.PermissionedManager.Query(ctx, id) +func (man Handshaker) query(ctx sdk.Context, id string) (obj HandshakeObject, err error) { + cobj, err := man.man.query(ctx, id, man.Kind()) if err != nil { return } obj = man.object(cobj) + handshake := obj.Handshake(ctx) + obj.counterparty = man.counterparty.object(handshake.Counterparty) return } -type Object struct { - connection.Object - - nextTimeout state.Integer - - client client.Object - - counterparty CounterObject -} - -type CounterObject struct { - connection.CounterObject - - nextTimeout commitment.Integer - - client client.CounterObject +func (obj HandshakeObject) Handshake(ctx sdk.Context) (res Handshake) { + obj.handshake.Get(ctx, &res) + return } -func (obj Object) NextTimeout(ctx sdk.Context) uint64 { +func (obj HandshakeObject) Timeout(ctx sdk.Context) uint64 { return obj.nextTimeout.Get(ctx) } -// If there is no proof provided, assume not exists -func (obj CounterObject) exists(ctx sdk.Context) bool { - /* - // XXX - if !obj.connection.Proven(ctx) { - return false - } - - return obj.connection.Exists(ctx) - */ - - return false +func (obj HandshakeObject) NextTimeout(ctx sdk.Context) uint64 { + return obj.nextTimeout.Get(ctx) } -// TODO: make it private -func (obj Object) Delete(ctx sdk.Context) { - obj.Object.Remove(ctx) +func (obj HandshakeObject) remove(ctx sdk.Context) { + obj.Object.remove(ctx) + obj.state.Delete(ctx) + obj.handshake.Delete(ctx) obj.nextTimeout.Delete(ctx) } -func (obj Object) assertSymmetric(ctx sdk.Context) error { - if !obj.counterparty.connection.Is(ctx, obj.Connection(ctx).Symmetry(obj.id)) { - return errors.New("unexpected counterparty connection value") - } - - return nil -} - func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { if uint64(ctx.BlockHeight()) > timeoutHeight { return errors.New("timeout") @@ -138,47 +142,51 @@ func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { } // Using proofs: none -func (obj Object) OpenInit(ctx sdk.Context, nextTimeoutHeight uint64) error { - if !obj.state.Transit(ctx, Idle, Init) { - return errors.New("init on non-idle connection") - } - - // CONTRACT: OpenInit() should be called after man.Create(), not man.Query(), - // which will ensure +func (man Handshaker) OpenInit(ctx sdk.Context, + id, clientid string, handshake Handshake, nextTimeoutHeight uint64, +) error { + // man.Create() will ensure // assert(get("connections/{identifier}") === null) and // set("connections{identifier}", connection) + obj, err := man.create(ctx, id, clientid, handshake) + if err != nil { + return err + } obj.nextTimeout.Set(ctx, nextTimeoutHeight) + obj.state.Set(ctx, Init) return nil } // Using proofs: counterparty.{connection,state,nextTimeout,client} -func (obj Object) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { - if !obj.state.Transit(ctx, Idle, OpenTry) { - return errors.New("invalid state") - } - - err := assertTimeout(ctx, timeoutHeight) +func (man Handshaker) OpenTry(ctx sdk.Context, + id, clientid string, handshake Handshake, timeoutHeight, nextTimeoutHeight uint64, +) error { + obj, err := man.create(ctx, id, clientid, handshake) if err != nil { return err } - if !obj.counterparty.state.Is(ctx, Init) { - return errors.New("counterparty state not init") - } - - err = obj.assertSymmetric(ctx) + err = assertTimeout(ctx, timeoutHeight) if err != nil { return err } + if !obj.counterparty.handshake.Is(ctx, Handshake{ + Counterparty: id, + CounterpartyClient: clientid, + }) { + return errors.New("wrong counterparty") + } + if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { return errors.New("unexpected counterparty timeout value") } // 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) @@ -192,30 +200,33 @@ func (obj Object) OpenTry(ctx sdk.Context, expheight uint64, timeoutHeight, next // assert(get("connections/{desiredIdentifier}") === null) and // set("connections{identifier}", connection) + obj.state.Set(ctx, OpenTry) obj.nextTimeout.Set(ctx, nextTimeoutHeight) return nil } -// Using proofs: counterparty.{connection,state, nextTimeout} -func (obj Object) OpenAck(ctx sdk.Context, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { +// Using proofs: counterparty.{handshake,nextTimeout} +func (man Handshaker) OpenAck(ctx sdk.Context, id string, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { + obj, err := man.query(ctx, id) + if err != nil { + return err + } if !obj.state.Transit(ctx, Init, Open) { return errors.New("ack on non-init connection") } - err := assertTimeout(ctx, timeoutHeight) + err = assertTimeout(ctx, timeoutHeight) if err != nil { return err } - if !obj.counterparty.state.Is(ctx, OpenTry) { - return errors.New("counterparty state not try") - } - - err = obj.assertSymmetric(ctx) - if err != nil { - return err + if !obj.counterparty.handshake.Is(ctx, Handshake{ + Counterparty: obj.ID(), + CounterpartyClient: obj.Client().ID(), + }) { + return errors.New("wrong counterparty") } if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { @@ -237,25 +248,28 @@ func (obj Object) OpenAck(ctx sdk.Context, expheight uint64, timeoutHeight, next } // Using proofs: counterparty.{connection,state, nextTimeout} -func (obj Object) OpenConfirm(ctx sdk.Context, timeoutHeight uint64) error { - if !obj.state.Transit(ctx, OpenTry, Open) { - return errors.New("confirm on non-try connection") - } - - err := assertTimeout(ctx, timeoutHeight) +func (man Handshaker) OpenConfirm(ctx sdk.Context, id string, timeoutHeight uint64) error { + obj, err := man.query(ctx, id) if err != nil { return err } - if !obj.counterparty.state.Is(ctx, Open) { - return errors.New("counterparty state not open") + if !obj.state.Transit(ctx, OpenTry, Open) { + return errors.New("confirm on non-try connection") } - err = obj.assertSymmetric(ctx) + err = assertTimeout(ctx, timeoutHeight) if err != nil { return err } + if !obj.counterparty.handshake.Is(ctx, Handshake{ + Counterparty: obj.ID(), + CounterpartyClient: obj.Client().ID(), + }) { + return errors.New("counterparty state not open or wrong counterparty") + } + if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { return errors.New("unexpected counterparty timeout value") } @@ -265,20 +279,19 @@ func (obj Object) OpenConfirm(ctx sdk.Context, timeoutHeight uint64) error { return nil } -func (obj Object) OpenTimeout(ctx sdk.Context) error { +func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } - // XXX: double check if a user can bypass the verification logic somehow switch obj.state.Get(ctx) { case Init: - if !obj.counterparty.connection.Is(ctx, nil) { + if !obj.counterparty.handshake.Is(ctx, nil) { return errors.New("counterparty connection exists") } case OpenTry: if !(obj.counterparty.state.Is(ctx, Init) || - obj.counterparty.exists(ctx)) { + obj.counterparty.clientid.Is(ctx, "")) /*FIXME: empty string does not work, it should be nil*/ { return errors.New("counterparty connection state not init") } // XXX: check if we need to verify symmetricity for timeout (already proven in OpenTry) @@ -293,7 +306,7 @@ func (obj Object) OpenTimeout(ctx sdk.Context) error { return nil } -func (obj Object) CloseInit(ctx sdk.Context, nextTimeout uint64) error { +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") } @@ -303,7 +316,7 @@ func (obj Object) CloseInit(ctx sdk.Context, nextTimeout uint64) error { return nil } -func (obj Object) CloseTry(ctx sdk.Context, timeoutHeight, nextTimeoutHeight uint64) error { +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") } @@ -326,7 +339,7 @@ func (obj Object) CloseTry(ctx sdk.Context, timeoutHeight, nextTimeoutHeight uin return nil } -func (obj Object) CloseAck(ctx sdk.Context, timeoutHeight uint64) error { +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") } @@ -349,7 +362,7 @@ func (obj Object) CloseAck(ctx sdk.Context, timeoutHeight uint64) error { return nil } -func (obj Object) CloseTimeout(ctx sdk.Context) error { +func (obj HandshakeObject) CloseTimeout(ctx sdk.Context) error { if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index bd74bddf142e..6918224e7eb7 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -14,165 +14,150 @@ import ( type Manager struct { protocol state.Mapping - table map[string]struct{} - client client.Manager counterparty CounterpartyManager } +func NewManager(protocol state.Base, client client.Manager) Manager { + return Manager{ + protocol: state.NewMapping(protocol, ([]byte("/connection/"))), + client: client, + counterparty: NewCounterpartyManager(protocol.Cdc()), + } +} + type CounterpartyManager struct { protocol commitment.Mapping client client.CounterpartyManager } -// CONTRACT: should be called on initialization time only -func (man Manager) Register(name string) PermissionedManager { - if _, ok := man.table[name]; ok { - panic("SubManager registered for existing name") - } - man.table[name] = struct{}{} +func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { + protocol := commitment.NewBase(cdc) - return PermissionedManager{man, name} + return CounterpartyManager{ + protocol: commitment.NewMapping(protocol, []byte("/connection/")), + + client: client.NewCounterpartyManager(protocol), + } } -func (man Manager) mapping(id string) state.Mapping { - return man.protocol.Prefix([]byte(id)) +type Object struct { + id string + + protocol state.Mapping + clientid state.String + available state.Boolean + + kind state.String + + client client.Object } func (man Manager) object(id string) Object { return Object{ - id: id, - connection: man.protocol.Value([]byte(id)), - permission: state.NewString(man.protocol.Value([]byte(id + "/permission"))), + id: id, - mapping: man.protocol.Prefix([]byte(id)), + protocol: man.protocol.Prefix([]byte(id + "/")), + clientid: state.NewString(man.protocol.Value([]byte(id + "/client"))), + available: state.NewBoolean(man.protocol.Value([]byte(id + "/available"))), - // CONTRACT: client should be filled by the caller + kind: state.NewString(man.protocol.Value([]byte(id + "/kind"))), - counterparty: man.counterparty.object(id), + // CONTRACT: client must be filled by the caller } } +type CounterObject struct { + id string + + protocol commitment.Mapping + clientid commitment.String + available commitment.Boolean + + kind commitment.String + + client client.CounterObject +} + func (man CounterpartyManager) object(id string) CounterObject { return CounterObject{ - ID: id, - Connection: man.protocol.Value([]byte(id)), - Permission: commitment.NewString(man.protocol.Value([]byte(id + "/permission"))), + id: id, + protocol: man.protocol.Prefix([]byte(id + "/")), + clientid: commitment.NewString(man.protocol.Value([]byte(id + "/client"))), + available: commitment.NewBoolean(man.protocol.Value([]byte(id + "/available"))), - // CONTRACT: client should be filled by the caller + kind: commitment.NewString(man.protocol.Value([]byte(id + "/kind"))), - Mapping: man.protocol.Prefix([]byte(id)), + // CONTRACT: client should be filled by the caller } } +func (obj Object) ID() string { + return obj.id +} -func (man Manager) Query(ctx sdk.Context, id string) (obj Object, err error) { - obj = man.object(id) - if !obj.exists(ctx) { - err = errors.New("Object not exists") - return - } - obj.client, err = man.client.Query(ctx, obj.Connection(ctx).GetClient()) - return +func (obj Object) ClientID(ctx sdk.Context) string { + return obj.clientid.Get(ctx) } -type PermissionedManager struct { - man Manager - name string +func (obj Object) Available(ctx sdk.Context) bool { + return obj.available.Get(ctx) } -func (man PermissionedManager) Cdc() *codec.Codec { - return man.man.protocol.Cdc() +func (obj Object) Client() client.Object { + return obj.client } -func (man PermissionedManager) object(id string) Object { - return man.man.object(id) +func (obj Object) remove(ctx sdk.Context) { + obj.clientid.Delete(ctx) + obj.available.Delete(ctx) + obj.kind.Delete(ctx) +} + +func (obj Object) exists(ctx sdk.Context) bool { + return obj.clientid.Exists(ctx) } -func (man PermissionedManager) Create(ctx sdk.Context, id string, connection Connection) (obj Object, err error) { +func (man Manager) Cdc() *codec.Codec { + return man.protocol.Cdc() +} + +func (man Manager) create(ctx sdk.Context, id, clientid string, kind string) (obj Object, err error) { obj = man.object(id) if obj.exists(ctx) { err = errors.New("Object already exists") return } - obj.connection.Set(ctx, connection) - obj.permission.Set(ctx, man.name) - obj.client, err = man.man.client.Query(ctx, connection.GetClient()) + obj.clientid.Set(ctx, clientid) + obj.kind.Set(ctx, kind) return } -func (man PermissionedManager) Query(ctx sdk.Context, id string) (obj Object, err error) { - obj = man.object(id) - if !obj.exists(ctx) { - err = errors.New("Object not exists") +// query() is used internally by the connection creators +// checing the connection kind +func (man Manager) query(ctx sdk.Context, id string, kind string) (obj Object, err error) { + obj, err = man.Query(ctx, id) + if err != nil { return } - if obj.Permission(ctx) != man.name { - err = errors.New("Object created with different permission") + if obj.kind.Get(ctx) != kind { + err = errors.New("kind mismatch") return } - obj.client, err = man.man.client.Query(ctx, obj.Connection(ctx).GetClient()) return } -type Object struct { - id string - connection state.Value // Connection - permission state.String - - mapping state.Mapping - - client client.Object - - counterparty CounterObject -} - -func (obj Object) ID() string { - return obj.id -} - -func (obj Object) Connection(ctx sdk.Context) (res Connection) { - obj.connection.Get(ctx, &res) +func (man Manager) Query(ctx sdk.Context, id string) (obj Object, err error) { + obj = man.object(id) + if !obj.exists(ctx) { + err = errors.New("Object not exists") + return + } + if !obj.Available(ctx) { + err = errors.New("object not available") + return + } + obj.client, err = man.client.Query(ctx, obj.ClientID(ctx)) return } - -// TODO: it should not be exposed -func (obj Object) Permission(ctx sdk.Context) string { - return obj.permission.Get(ctx) -} - -func (obj Object) Mapping() state.Mapping { - return obj.mapping -} - -func (obj Object) Counterparty() CounterObject { - return obj.counterparty -} - -func (obj Object) exists(ctx sdk.Context) bool { - return obj.connection.Exists(ctx) -} - -func (obj Object) Delete(ctx sdk.Context) { - obj.connection.Delete(ctx) - obj.permission.Delete(ctx) -} - -type CounterObject struct { - ID string - Connection commitment.Value - Permission commitment.String - - Mapping commitment.Mapping - - Client client.CounterObject -} - -// Flow(DEPRECATED): -// 1. a module calls SubManager.{Create, Query}() -// 2. SubManager calls StateManager.RequestBase(id string) -// 3-1. If id is not reserved, StateManager marks id as reserved and returns base -// 3-2. If id is reserved, StateManager checks if the SubManager is one who reserved -// 4. if okay, Manager return the base, which only Manager has access -// 5. SubManager returns the result of method call diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index d2ef335d00e0..8b8ec4c82941 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -99,6 +99,18 @@ func (v String) Is(ctx sdk.Context, value string) bool { return v.Value.Is(ctx, value) } +type Boolean struct { + Value +} + +func NewBoolean(v Value) Boolean { + return Boolean{v} +} + +func (v Boolean) Is(ctx sdk.Context, value bool) bool { + return v.Value.Is(ctx, value) +} + type Integer struct { Value From 2d4c7233cc56249cc4629b6ba5e1bc3a9ee24df7 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 5 Jul 2019 22:18:31 +0200 Subject: [PATCH 062/378] test reworking --- x/ibc/03-connection/cli.go | 73 +++++++++--- x/ibc/03-connection/handshake.go | 97 ++++++++++------ x/ibc/03-connection/handshake/types.go | 60 ---------- x/ibc/03-connection/manager.go | 9 +- x/ibc/03-connection/tests/connection_test.go | 21 ++-- x/ibc/03-connection/tests/types.go | 110 +++++++++---------- 6 files changed, 188 insertions(+), 182 deletions(-) delete mode 100644 x/ibc/03-connection/handshake/types.go diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index a76c89c37097..a8acda7162f6 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -1,6 +1,5 @@ package connection -/* import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" @@ -9,12 +8,12 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) - // CLIObject stores the key for each object fields type CLIObject struct { - ID string - ClientIDKey []byte - AvailableKey []byte + ID string + ClientIDKey []byte + AvailableKey []byte + KindKey []byte Client client.CLIObject @@ -25,19 +24,16 @@ type CLIObject struct { func (man Manager) CLIObject(root merkle.Root, id string) CLIObject { obj := man.object(id) return CLIObject{ - ID: obj.id, - ClientIDKey: obj.clientid.Key(), - Available - ConnectionKey: obj.connection.Key(), - // StateKey: obj.state.Key(), - // NextTimeoutKey: obj.nextTimeout.Key(), - PermissionKey: obj.permission.Key(), + ID: obj.id, + ClientIDKey: obj.clientid.Key(), + AvailableKey: obj.available.Key(), + KindKey: obj.kind.Key(), // TODO: unify man.CLIObject() <=> obj.CLI() Client: obj.client.CLI(root), Root: root, - Cdc: obj.connection.Cdc(), + Cdc: obj.clientid.Cdc(), } } @@ -55,8 +51,52 @@ func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) } -func (obj CLIObject) Connection(ctx context.CLIContext, root merkle.Root) (res Connection, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.ConnectionKey, &res) +func (obj CLIObject) ClientID(ctx context.CLIContext, root merkle.Root) (res string, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.ClientIDKey, &res) + return +} + +func (obj CLIObject) Available(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.AvailableKey, &res) + return +} + +func (obj CLIObject) Kind(ctx context.CLIContext, root merkle.Root) (res string, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.KindKey, &res) + return +} + +type CLIHandshakeObject struct { + CLIObject + + StateKey []byte + HandshakeKey []byte + TimeoutKey []byte +} + +func (man Handshaker) CLIObject(root merkle.Root, id string) CLIHandshakeObject { + obj := man.object(man.man.object(id)) + return CLIHandshakeObject{ + CLIObject: man.man.CLIObject(root, id), + + StateKey: obj.state.Key(), + HandshakeKey: obj.handshake.Key(), + TimeoutKey: obj.nextTimeout.Key(), + } +} + +func (obj CLIHandshakeObject) ClientID(ctx context.CLIContext, root merkle.Root) (res byte, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.ClientIDKey, &res) + return +} + +func (obj CLIHandshakeObject) Handshake(ctx context.CLIContext, root merkle.Root) (res Handshake, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.HandshakeKey, &res) + return +} + +func (obj CLIHandshakeObject) Timeout(ctx context.CLIContext, root merkle.Root) (res uint64, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.TimeoutKey, &res) return } @@ -70,9 +110,6 @@ func (obj CLIObject) NextTimeout(ctx context.CLIContext, root merkle.Root) (res proof, err = obj.query(ctx, obj.NextTimeoutKey, &res) return } -:w -:w - func (obj CLIObject) Permission(ctx context.CLIContext, root merkle.Root) (res string, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.PermissionKey, &res) diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index ed1e3bb405e0..d08a3209deca 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -113,6 +113,10 @@ func (man Handshaker) query(ctx sdk.Context, id string) (obj HandshakeObject, er return } +func (obj HandshakeObject) State(ctx sdk.Context) byte { + return obj.state.Get(ctx) +} + func (obj HandshakeObject) Handshake(ctx sdk.Context) (res Handshake) { obj.handshake.Get(ctx, &res) return @@ -144,44 +148,56 @@ func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { // Using proofs: none func (man Handshaker) OpenInit(ctx sdk.Context, id, clientid string, handshake Handshake, nextTimeoutHeight uint64, -) error { +) (HandshakeObject, error) { // man.Create() will ensure // assert(get("connections/{identifier}") === null) and // set("connections{identifier}", connection) obj, err := man.create(ctx, id, clientid, handshake) if err != nil { - return err + return HandshakeObject{}, err } obj.nextTimeout.Set(ctx, nextTimeoutHeight) obj.state.Set(ctx, Init) - return nil + return obj, nil } -// Using proofs: counterparty.{connection,state,nextTimeout,client} +// Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} func (man Handshaker) OpenTry(ctx sdk.Context, id, clientid string, handshake Handshake, timeoutHeight, nextTimeoutHeight uint64, -) error { - obj, err := man.create(ctx, id, clientid, handshake) +) (obj HandshakeObject, err error) { + obj, err = man.create(ctx, id, clientid, handshake) if err != nil { - return err + return } err = assertTimeout(ctx, timeoutHeight) if err != nil { - return err + return + } + + if !obj.counterparty.state.Is(ctx, Init) { + err = errors.New("counterparty state not init") + return } if !obj.counterparty.handshake.Is(ctx, Handshake{ Counterparty: id, CounterpartyClient: clientid, }) { - return errors.New("wrong counterparty") + err = errors.New("wrong counterparty") + return + } + + if !obj.counterparty.clientid.Is(ctx, handshake.CounterpartyClient) { + err = errors.New("counterparty client not match") + return } if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { - return errors.New("unexpected counterparty timeout value") + err = errors.New("unexpected counterparty timeout value") + return } // TODO: commented out, need to check whether the stored client is compatible @@ -203,34 +219,49 @@ func (man Handshaker) OpenTry(ctx sdk.Context, obj.state.Set(ctx, OpenTry) obj.nextTimeout.Set(ctx, nextTimeoutHeight) - return nil + return } -// Using proofs: counterparty.{handshake,nextTimeout} -func (man Handshaker) OpenAck(ctx sdk.Context, id string, expheight uint64, timeoutHeight, nextTimeoutHeight uint64) error { - obj, err := man.query(ctx, id) +// Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} +func (man Handshaker) OpenAck(ctx sdk.Context, + id string /*expheight uint64, */, timeoutHeight, nextTimeoutHeight uint64, +) (obj HandshakeObject, err error) { + obj, err = man.query(ctx, id) if err != nil { - return err + return } if !obj.state.Transit(ctx, Init, Open) { - return errors.New("ack on non-init connection") + err = errors.New("ack on non-init connection") + return } err = assertTimeout(ctx, timeoutHeight) if err != nil { - return err + return } if !obj.counterparty.handshake.Is(ctx, Handshake{ Counterparty: obj.ID(), CounterpartyClient: obj.Client().ID(), }) { - return 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.clientid.Is(ctx, obj.Handshake(ctx).CounterpartyClient) { + err = errors.New("counterparty client not match") + return } if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { - return errors.New("unexpected counterparty timeout value") + err = errors.New("unexpected counterparty timeout value") + return } // TODO: commented out, implement in v1 @@ -242,41 +273,43 @@ func (man Handshaker) OpenAck(ctx sdk.Context, id string, expheight uint64, time } */ + obj.available.Set(ctx, true) obj.nextTimeout.Set(ctx, uint64(nextTimeoutHeight)) - return nil + return } // Using proofs: counterparty.{connection,state, nextTimeout} -func (man Handshaker) OpenConfirm(ctx sdk.Context, id string, timeoutHeight uint64) error { - obj, err := man.query(ctx, id) +func (man Handshaker) OpenConfirm(ctx sdk.Context, id string, timeoutHeight uint64) (obj HandshakeObject, err error) { + obj, err = man.query(ctx, id) if err != nil { - return err + return } if !obj.state.Transit(ctx, OpenTry, Open) { - return errors.New("confirm on non-try connection") + err = errors.New("confirm on non-try connection") + return } err = assertTimeout(ctx, timeoutHeight) if err != nil { - return err + return } - if !obj.counterparty.handshake.Is(ctx, Handshake{ - Counterparty: obj.ID(), - CounterpartyClient: obj.Client().ID(), - }) { - return errors.New("counterparty state not open or wrong counterparty") + if !obj.counterparty.state.Is(ctx, Open) { + err = errors.New("counterparty state not open") + return } if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { - return errors.New("unexpected counterparty timeout value") + err = errors.New("unexpected counterparty timeout value") + return } + obj.available.Set(ctx, true) obj.nextTimeout.Set(ctx, 0) - return nil + return } func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { diff --git a/x/ibc/03-connection/handshake/types.go b/x/ibc/03-connection/handshake/types.go deleted file mode 100644 index 786948991ad1..000000000000 --- a/x/ibc/03-connection/handshake/types.go +++ /dev/null @@ -1,60 +0,0 @@ -package handshake - -import ( - "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" -) - -type State = byte - -const ( - Idle State = iota - Init - OpenTry - Open - CloseTry - Closed -) - -var _ connection.Connection = Connection{} - -// TODO: Connection is amino marshaled currently, need to implement MarshalBinary manually -type Connection struct { - Counterparty string - Client string - CounterpartyClient string - State State -} - -func (conn Connection) GetCounterparty() string { - return conn.Counterparty -} - -func (conn Connection) GetClient() string { - return conn.Client -} - -func (conn Connection) GetCounterpartyClient() string { - return conn.CounterpartyClient -} - -func (conn Connection) Available() bool { - return conn.State == Open -} - -func (conn Connection) Equal(conn0 Connection) bool { - return conn.Counterparty == conn0.Counterparty && - conn.Client == conn0.Client && - conn.CounterpartyClient == conn0.CounterpartyClient -} - -func (conn Connection) Symmetric(id string, conn0 Connection) bool { - return conn0.Equal(conn.Symmetry(id)) -} - -func (conn Connection) Symmetry(id string) Connection { - return Connection{ - Counterparty: id, - Client: conn.CounterpartyClient, - CounterpartyClient: conn.Client, - } -} diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 6918224e7eb7..390aa3c6e54a 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -135,9 +135,14 @@ func (man Manager) create(ctx sdk.Context, id, clientid string, kind string) (ob } // query() is used internally by the connection creators -// checing the connection kind +// checks connection kind, doesn't check avilability func (man Manager) query(ctx sdk.Context, id string, kind string) (obj Object, err error) { - obj, err = man.Query(ctx, id) + obj = man.object(id) + if !obj.exists(ctx) { + err = errors.New("Object not exists") + return + } + obj.client, err = man.client.Query(ctx, obj.ClientID(ctx)) if err != nil { return } diff --git a/x/ibc/03-connection/tests/connection_test.go b/x/ibc/03-connection/tests/connection_test.go index 338218542322..a6c0860ff6ff 100644 --- a/x/ibc/03-connection/tests/connection_test.go +++ b/x/ibc/03-connection/tests/connection_test.go @@ -32,34 +32,35 @@ func TestHandshake(t *testing.T) { node.Counterparty.CreateClient(t) // self.OpenInit - node.Advance(t) + node.OpenInit(t) header := node.Commit() // counterparty.OpenTry node.Counterparty.UpdateClient(t, header) cliobj := node.CLIObject() - _, pconn := node.Query(t, cliobj.ConnectionKey) + _, phand := node.Query(t, cliobj.HandshakeKey) _, pstate := node.Query(t, cliobj.StateKey) - _, ptimeout := node.Query(t, cliobj.NextTimeoutKey) + _, ptimeout := node.Query(t, cliobj.TimeoutKey) + _, pclientid := node.Query(t, cliobj.ClientIDKey) // TODO: implement consensus state checking // _, pclient := node.Query(t, cliobj.Client.ConsensusStateKey) - node.Advance(t, pconn, pstate, ptimeout /*, pclient*/) + node.Counterparty.OpenTry(t, phand, pstate, ptimeout, pclientid) header = node.Counterparty.Commit() // self.OpenAck node.UpdateClient(t, header) cliobj = node.Counterparty.CLIObject() - _, pconn = node.Counterparty.Query(t, cliobj.ConnectionKey) + _, phand = node.Counterparty.Query(t, cliobj.HandshakeKey) _, pstate = node.Counterparty.Query(t, cliobj.StateKey) - _, ptimeout = node.Counterparty.Query(t, cliobj.NextTimeoutKey) - node.Advance(t, pconn, pstate, ptimeout) + _, ptimeout = node.Counterparty.Query(t, cliobj.TimeoutKey) + _, pclientid = node.Counterparty.Query(t, cliobj.ClientIDKey) + node.OpenAck(t, phand, pstate, ptimeout, pclientid) header = node.Commit() // counterparty.OpenConfirm node.Counterparty.UpdateClient(t, header) cliobj = node.CLIObject() - _, pconn = node.Query(t, cliobj.ConnectionKey) // TODO: check if it is needed _, pstate = node.Query(t, cliobj.StateKey) - _, ptimeout = node.Query(t, cliobj.NextTimeoutKey) - node.Advance(t, pconn, pstate, ptimeout) + _, ptimeout = node.Query(t, cliobj.TimeoutKey) + node.Counterparty.OpenConfirm(t, pstate, ptimeout) } diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index 18d941cad038..e1112fc43895 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -20,8 +20,9 @@ type Node struct { *tendermint.Node Counterparty *Node - Connection connection.Connection - State connection.State + Client string + Handshake connection.Handshake + State connection.State Cdc *codec.Codec } @@ -44,11 +45,11 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { Cdc: cdc, } - res.Connection = connection.Connection{ + res.Handshake = connection.Handshake{ Counterparty: res.Counterparty.Name, } - res.Counterparty.Connection = connection.Connection{ + res.Counterparty.Handshake = connection.Handshake{ Counterparty: res.Name, } @@ -60,14 +61,14 @@ func (node *Node) CreateClient(t *testing.T) { climan, _ := node.Manager() obj, err := climan.Create(ctx, node.Counterparty.LastStateVerifier().ConsensusState) require.NoError(t, err) - node.Connection.Client = obj.ID() - node.Counterparty.Connection.CounterpartyClient = obj.ID() + node.Client = obj.ID() + node.Counterparty.Handshake.CounterpartyClient = obj.ID() } func (node *Node) UpdateClient(t *testing.T, header client.Header) { ctx := node.Context() climan, _ := node.Manager() - obj, err := climan.Query(ctx, node.Connection.Client) + obj, err := climan.Query(ctx, node.Client) require.NoError(t, err) err = obj.Update(ctx, header) require.NoError(t, err) @@ -78,28 +79,18 @@ func (node *Node) SetState(state connection.State) { node.Counterparty.State = state } -func (node *Node) Object(t *testing.T, proofs []commitment.Proof) (sdk.Context, connection.Object) { +func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Context, connection.Handshaker) { ctx := node.Context() store, err := commitment.NewStore(node.Counterparty.Root, proofs) require.NoError(t, err) ctx = commitment.WithStore(ctx, store) _, man := node.Manager() - switch node.State { - case connection.Idle, connection.Init: - obj, err := man.Create(ctx, node.Name, node.Connection) - require.NoError(t, err) - return ctx, obj - default: - obj, err := man.Query(ctx, node.Name) - require.NoError(t, err) - require.Equal(t, node.Connection, obj.Connection(ctx)) - return ctx, obj - } + return ctx, connection.NewHandshaker(man) } -func (node *Node) CLIObject() connection.CLIObject { +func (node *Node) CLIObject() connection.CLIHandshakeObject { _, man := node.Manager() - return man.CLIObject(node.Root, node.Name) + return connection.NewHandshaker(man).CLIObject(node.Root, node.Name) } func base(cdc *codec.Codec, key sdk.StoreKey) (state.Base, state.Base) { @@ -114,43 +105,42 @@ func (node *Node) Manager() (client.Manager, connection.Manager) { return clientman, connection.NewManager(protocol, clientman) } -func (node *Node) Advance(t *testing.T, proofs ...commitment.Proof) { - switch node.State { - // TODO: use different enum type for node.State - case connection.Idle: // self: Idle -> Init - ctx, obj := node.Object(t, proofs) - require.Equal(t, connection.Idle, obj.State(ctx)) - err := obj.OpenInit(ctx, 100) // TODO: test timeout - require.NoError(t, err) - require.Equal(t, connection.Init, obj.State(ctx)) - require.Equal(t, node.Connection, obj.Connection(ctx)) - node.SetState(connection.Init) - case connection.Init: // counter: Idle -> OpenTry - ctx, obj := node.Counterparty.Object(t, proofs) - require.Equal(t, connection.Idle, obj.State(ctx)) - err := obj.OpenTry(ctx, 0 /*TODO*/, 100 /*TODO*/, 100 /*TODO*/) - require.NoError(t, err) - require.Equal(t, connection.OpenTry, obj.State(ctx)) - require.Equal(t, node.Counterparty.Connection, obj.Connection(ctx)) - node.SetState(connection.OpenTry) - case connection.OpenTry: // self: Init -> Open - ctx, obj := node.Object(t, proofs) - require.Equal(t, connection.Init, obj.State(ctx)) - err := obj.OpenAck(ctx, 0 /*TODO*/, 100 /*TODO*/, 100 /*TODO*/) - require.NoError(t, err) - require.Equal(t, connection.Open, obj.State(ctx)) - require.Equal(t, node.Connection, obj.Connection(ctx)) - node.SetState(connection.Open) - case connection.Open: // counter: OpenTry -> Open - ctx, obj := node.Counterparty.Object(t, proofs) - require.Equal(t, connection.OpenTry, obj.State(ctx)) - err := obj.OpenConfirm(ctx, 100 /*TODO*/) - require.NoError(t, err) - require.Equal(t, connection.Open, obj.State(ctx)) - require.Equal(t, node.Counterparty.Connection, obj.Connection(ctx)) - node.SetState(connection.CloseTry) - // case connection.CloseTry // self: Open -> CloseTry - default: - return - } +func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { + ctx, man := node.Handshaker(t, proofs) + obj, err := man.OpenInit(ctx, node.Name, node.Client, node.Handshake, 100) // TODO: test timeout + require.NoError(t, err) + require.Equal(t, connection.Init, obj.State(ctx)) + require.Equal(t, node.Handshake, obj.Handshake(ctx)) + require.False(t, obj.Available(ctx)) + node.SetState(connection.Init) +} + +func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { + ctx, man := node.Handshaker(t, proofs) + obj, err := man.OpenTry(ctx, node.Name, node.Client, node.Handshake, 100 /*TODO*/, 100 /*TODO*/) + require.NoError(t, err) + require.Equal(t, connection.OpenTry, obj.State(ctx)) + require.Equal(t, node.Handshake, obj.Handshake(ctx)) + require.False(t, obj.Available(ctx)) + node.SetState(connection.OpenTry) +} + +func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { + ctx, man := node.Handshaker(t, proofs) + obj, err := man.OpenAck(ctx, node.Name, 100 /*TODO*/, 100 /*TODO*/) + require.NoError(t, err) + require.Equal(t, connection.Open, obj.State(ctx)) + require.Equal(t, node.Handshake, obj.Handshake(ctx)) + require.True(t, obj.Available(ctx)) + node.SetState(connection.Open) +} + +func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { + ctx, man := node.Handshaker(t, proofs) + obj, err := man.OpenConfirm(ctx, node.Name, 100 /*TODO*/) + require.NoError(t, err) + require.Equal(t, connection.Open, obj.State(ctx)) + require.Equal(t, node.Handshake, obj.Handshake(ctx)) + require.True(t, obj.Available(ctx)) + node.SetState(connection.CloseTry) } From 20489fb3c208165271ccef127d952e1b589c6444 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 14:40:40 +0200 Subject: [PATCH 063/378] change connection structure --- x/ibc/03-connection/cli.go | 55 +++++++------ x/ibc/03-connection/handshake.go | 83 +++++++++----------- x/ibc/03-connection/manager.go | 62 ++++++++------- x/ibc/03-connection/tests/connection_test.go | 12 +-- x/ibc/03-connection/tests/types.go | 42 +++++----- x/ibc/03-connection/types.go | 26 ++++-- 6 files changed, 154 insertions(+), 126 deletions(-) diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index a8acda7162f6..0c8e8de505b1 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -10,10 +10,11 @@ import ( // CLIObject stores the key for each object fields type CLIObject struct { - ID string - ClientIDKey []byte - AvailableKey []byte - KindKey []byte + ID string + ConnectionKey []byte + SendableKey []byte + ReceivableKey []byte + KindKey []byte Client client.CLIObject @@ -24,16 +25,17 @@ type CLIObject struct { func (man Manager) CLIObject(root merkle.Root, id string) CLIObject { obj := man.object(id) return CLIObject{ - ID: obj.id, - ClientIDKey: obj.clientid.Key(), - AvailableKey: obj.available.Key(), - KindKey: obj.kind.Key(), + ID: obj.id, + ConnectionKey: obj.connection.Key(), + SendableKey: obj.sendable.Key(), + ReceivableKey: obj.receivable.Key(), + KindKey: obj.kind.Key(), // TODO: unify man.CLIObject() <=> obj.CLI() Client: obj.client.CLI(root), Root: root, - Cdc: obj.clientid.Cdc(), + Cdc: obj.connection.Cdc(), } } @@ -51,17 +53,22 @@ func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) } -func (obj CLIObject) ClientID(ctx context.CLIContext, root merkle.Root) (res string, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.ClientIDKey, &res) +func (obj CLIObject) Connection(ctx context.CLIContext) (res Connection, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.ConnectionKey, &res) return } -func (obj CLIObject) Available(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.AvailableKey, &res) +func (obj CLIObject) Sendable(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.SendableKey, &res) return } -func (obj CLIObject) Kind(ctx context.CLIContext, root merkle.Root) (res string, proof merkle.Proof, err error) { +func (obj CLIObject) Receivable(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.ReceivableKey, &res) + return +} + +func (obj CLIObject) Kind(ctx context.CLIContext) (res string, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.KindKey, &res) return } @@ -69,9 +76,9 @@ func (obj CLIObject) Kind(ctx context.CLIContext, root merkle.Root) (res string, type CLIHandshakeObject struct { CLIObject - StateKey []byte - HandshakeKey []byte - TimeoutKey []byte + StateKey []byte + CounterpartyClientKey []byte + TimeoutKey []byte } func (man Handshaker) CLIObject(root merkle.Root, id string) CLIHandshakeObject { @@ -79,19 +86,19 @@ func (man Handshaker) CLIObject(root merkle.Root, id string) CLIHandshakeObject return CLIHandshakeObject{ CLIObject: man.man.CLIObject(root, id), - StateKey: obj.state.Key(), - HandshakeKey: obj.handshake.Key(), - TimeoutKey: obj.nextTimeout.Key(), + StateKey: obj.state.Key(), + CounterpartyClientKey: obj.counterpartyClient.Key(), + TimeoutKey: obj.nextTimeout.Key(), } } -func (obj CLIHandshakeObject) ClientID(ctx context.CLIContext, root merkle.Root) (res byte, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.ClientIDKey, &res) +func (obj CLIHandshakeObject) State(ctx context.CLIContext, root merkle.Root) (res byte, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.StateKey, &res) return } -func (obj CLIHandshakeObject) Handshake(ctx context.CLIContext, root merkle.Root) (res Handshake, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.HandshakeKey, &res) +func (obj CLIHandshakeObject) CounterpartyClient(ctx context.CLIContext, root merkle.Root) (res string, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.CounterpartyClientKey, &res) return } diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index d08a3209deca..27fd0389bd12 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -20,11 +20,6 @@ const ( Closed ) -type Handshake struct { - Counterparty string - CounterpartyClient string -} - type Handshaker struct { man Manager @@ -53,9 +48,9 @@ type CounterpartyHandshaker struct { type HandshakeObject struct { Object - state state.Enum - handshake state.Value // type Handshake - nextTimeout state.Integer + state state.Enum + counterpartyClient state.String + nextTimeout state.Integer counterparty CounterHandshakeObject } @@ -63,9 +58,9 @@ type HandshakeObject struct { type CounterHandshakeObject struct { CounterObject - state commitment.Enum - handshake commitment.Value - nextTimeout commitment.Integer + state commitment.Enum + counterpartyClient commitment.String + nextTimeout commitment.Integer } // CONTRACT: client and remote must be filled by the caller @@ -73,9 +68,9 @@ func (man Handshaker) object(parent Object) HandshakeObject { return HandshakeObject{ Object: parent, - state: state.NewEnum(man.man.protocol.Value([]byte(parent.id + "/state"))), - handshake: man.man.protocol.Value([]byte(parent.id + "/handshake")), - nextTimeout: state.NewInteger(man.man.protocol.Value([]byte(parent.id+"/timeout")), state.Dec), + state: state.NewEnum(man.man.protocol.Value([]byte(parent.id + "/state"))), + counterpartyClient: state.NewString(man.man.protocol.Value([]byte(parent.id + "/counterpartyClient"))), + nextTimeout: state.NewInteger(man.man.protocol.Value([]byte(parent.id+"/timeout")), state.Dec), // CONTRACT: counterparty must be filled by the caller } @@ -85,20 +80,20 @@ func (man CounterpartyHandshaker) object(id string) CounterHandshakeObject { return CounterHandshakeObject{ CounterObject: man.man.object(id), - state: commitment.NewEnum(man.man.protocol.Value([]byte(id + "/state"))), - handshake: man.man.protocol.Value([]byte(id + "/handshake")), - nextTimeout: commitment.NewInteger(man.man.protocol.Value([]byte(id+"/timeout")), state.Dec), + state: commitment.NewEnum(man.man.protocol.Value([]byte(id + "/state"))), + counterpartyClient: commitment.NewString(man.man.protocol.Value([]byte(id + "/counterpartyClient"))), + nextTimeout: commitment.NewInteger(man.man.protocol.Value([]byte(id+"/timeout")), state.Dec), } } -func (man Handshaker) create(ctx sdk.Context, id, clientid string, handshake Handshake) (obj HandshakeObject, err error) { - cobj, err := man.man.create(ctx, id, clientid, man.Kind()) +func (man Handshaker) create(ctx sdk.Context, id string, connection Connection, counterpartyClient string) (obj HandshakeObject, err error) { + cobj, err := man.man.create(ctx, id, connection, man.Kind()) if err != nil { return } obj = man.object(cobj) - obj.handshake.Set(ctx, handshake) - obj.counterparty = man.counterparty.object(handshake.Counterparty) + obj.counterpartyClient.Set(ctx, counterpartyClient) + obj.counterparty = man.counterparty.object(connection.Counterparty) return obj, nil } @@ -108,8 +103,7 @@ func (man Handshaker) query(ctx sdk.Context, id string) (obj HandshakeObject, er return } obj = man.object(cobj) - handshake := obj.Handshake(ctx) - obj.counterparty = man.counterparty.object(handshake.Counterparty) + obj.counterparty = man.counterparty.object(obj.Connection(ctx).Counterparty) return } @@ -117,9 +111,8 @@ func (obj HandshakeObject) State(ctx sdk.Context) byte { return obj.state.Get(ctx) } -func (obj HandshakeObject) Handshake(ctx sdk.Context) (res Handshake) { - obj.handshake.Get(ctx, &res) - return +func (obj HandshakeObject) CounterpartyClient(ctx sdk.Context) string { + return obj.counterpartyClient.Get(ctx) } func (obj HandshakeObject) Timeout(ctx sdk.Context) uint64 { @@ -133,7 +126,7 @@ func (obj HandshakeObject) NextTimeout(ctx sdk.Context) uint64 { func (obj HandshakeObject) remove(ctx sdk.Context) { obj.Object.remove(ctx) obj.state.Delete(ctx) - obj.handshake.Delete(ctx) + obj.counterpartyClient.Delete(ctx) obj.nextTimeout.Delete(ctx) } @@ -147,12 +140,12 @@ func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { // Using proofs: none func (man Handshaker) OpenInit(ctx sdk.Context, - id, clientid string, handshake Handshake, nextTimeoutHeight uint64, + id string, connection Connection, counterpartyClient string, nextTimeoutHeight uint64, ) (HandshakeObject, error) { // man.Create() will ensure // assert(get("connections/{identifier}") === null) and // set("connections{identifier}", connection) - obj, err := man.create(ctx, id, clientid, handshake) + obj, err := man.create(ctx, id, connection, counterpartyClient) if err != nil { return HandshakeObject{}, err } @@ -165,9 +158,9 @@ func (man Handshaker) OpenInit(ctx sdk.Context, // Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} func (man Handshaker) OpenTry(ctx sdk.Context, - id, clientid string, handshake Handshake, timeoutHeight, nextTimeoutHeight uint64, + id string, connection Connection, counterpartyClient string, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { - obj, err = man.create(ctx, id, clientid, handshake) + obj, err = man.create(ctx, id, connection, counterpartyClient) if err != nil { return } @@ -182,15 +175,15 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - if !obj.counterparty.handshake.Is(ctx, Handshake{ - Counterparty: id, - CounterpartyClient: clientid, + if !obj.counterparty.connection.Is(ctx, Connection{ + Client: counterpartyClient, + Counterparty: id, }) { - err = errors.New("wrong counterparty") + err = errors.New("wrong counterparty connection") return } - if !obj.counterparty.clientid.Is(ctx, handshake.CounterpartyClient) { + if !obj.counterparty.counterpartyClient.Is(ctx, connection.Client) { err = errors.New("counterparty client not match") return } @@ -241,9 +234,9 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.counterparty.handshake.Is(ctx, Handshake{ - Counterparty: obj.ID(), - CounterpartyClient: obj.Client().ID(), + if !obj.counterparty.connection.Is(ctx, Connection{ + Client: obj.Connection(ctx).Client, + Counterparty: obj.ID(), }) { err = errors.New("wrong counterparty") return @@ -254,7 +247,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.counterparty.clientid.Is(ctx, obj.Handshake(ctx).CounterpartyClient) { + if !obj.counterparty.counterpartyClient.Is(ctx, obj.Connection(ctx).Client) { err = errors.New("counterparty client not match") return } @@ -273,7 +266,8 @@ func (man Handshaker) OpenAck(ctx sdk.Context, } */ - obj.available.Set(ctx, true) + obj.sendable.Set(ctx, true) + obj.receivable.Set(ctx, true) obj.nextTimeout.Set(ctx, uint64(nextTimeoutHeight)) return @@ -306,7 +300,8 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, id string, timeoutHeight uint return } - obj.available.Set(ctx, true) + obj.sendable.Set(ctx, true) + obj.receivable.Set(ctx, true) obj.nextTimeout.Set(ctx, 0) return @@ -319,12 +314,12 @@ func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { switch obj.state.Get(ctx) { case Init: - if !obj.counterparty.handshake.Is(ctx, nil) { + if !obj.counterparty.connection.Is(ctx, nil) { return errors.New("counterparty connection exists") } case OpenTry: if !(obj.counterparty.state.Is(ctx, Init) || - obj.counterparty.clientid.Is(ctx, "")) /*FIXME: empty string does not work, it should be nil*/ { + 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) diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 390aa3c6e54a..ad28264cc594 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -46,9 +46,10 @@ func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { type Object struct { id string - protocol state.Mapping - clientid state.String - available state.Boolean + protocol state.Mapping + connection state.Value + sendable state.Boolean + receivable state.Boolean kind state.String @@ -59,9 +60,10 @@ func (man Manager) object(id string) Object { return Object{ id: id, - protocol: man.protocol.Prefix([]byte(id + "/")), - clientid: state.NewString(man.protocol.Value([]byte(id + "/client"))), - available: state.NewBoolean(man.protocol.Value([]byte(id + "/available"))), + protocol: man.protocol.Prefix([]byte(id + "/")), + connection: man.protocol.Value([]byte(id)), + sendable: state.NewBoolean(man.protocol.Value([]byte(id + "/sendable"))), + receivable: state.NewBoolean(man.protocol.Value([]byte(id + "/receivable"))), kind: state.NewString(man.protocol.Value([]byte(id + "/kind"))), @@ -72,9 +74,10 @@ func (man Manager) object(id string) Object { type CounterObject struct { id string - protocol commitment.Mapping - clientid commitment.String - available commitment.Boolean + protocol commitment.Mapping + connection commitment.Value + sendable commitment.Boolean + receivable commitment.Boolean kind commitment.String @@ -83,10 +86,11 @@ type CounterObject struct { func (man CounterpartyManager) object(id string) CounterObject { return CounterObject{ - id: id, - protocol: man.protocol.Prefix([]byte(id + "/")), - clientid: commitment.NewString(man.protocol.Value([]byte(id + "/client"))), - available: commitment.NewBoolean(man.protocol.Value([]byte(id + "/available"))), + id: id, + protocol: man.protocol.Prefix([]byte(id + "/")), + connection: man.protocol.Value([]byte(id)), + sendable: commitment.NewBoolean(man.protocol.Value([]byte(id + "/sendable"))), + receivable: commitment.NewBoolean(man.protocol.Value([]byte(id + "/receivable"))), kind: commitment.NewString(man.protocol.Value([]byte(id + "/kind"))), @@ -97,12 +101,17 @@ func (obj Object) ID() string { return obj.id } -func (obj Object) ClientID(ctx sdk.Context) string { - return obj.clientid.Get(ctx) +func (obj Object) Connection(ctx sdk.Context) (res Connection) { + obj.connection.Get(ctx, &res) + return +} + +func (obj Object) Sendable(ctx sdk.Context) bool { + return obj.sendable.Get(ctx) } -func (obj Object) Available(ctx sdk.Context) bool { - return obj.available.Get(ctx) +func (obj Object) Receivable(ctx sdk.Context) bool { + return obj.receivable.Get(ctx) } func (obj Object) Client() client.Object { @@ -110,26 +119,27 @@ func (obj Object) Client() client.Object { } func (obj Object) remove(ctx sdk.Context) { - obj.clientid.Delete(ctx) - obj.available.Delete(ctx) + obj.connection.Delete(ctx) + obj.sendable.Delete(ctx) + obj.receivable.Delete(ctx) obj.kind.Delete(ctx) } func (obj Object) exists(ctx sdk.Context) bool { - return obj.clientid.Exists(ctx) + return obj.connection.Exists(ctx) } func (man Manager) Cdc() *codec.Codec { return man.protocol.Cdc() } -func (man Manager) create(ctx sdk.Context, id, clientid string, kind string) (obj Object, err error) { +func (man Manager) create(ctx sdk.Context, id string, connection Connection, kind string) (obj Object, err error) { obj = man.object(id) if obj.exists(ctx) { err = errors.New("Object already exists") return } - obj.clientid.Set(ctx, clientid) + obj.connection.Set(ctx, connection) obj.kind.Set(ctx, kind) return } @@ -142,7 +152,7 @@ func (man Manager) query(ctx sdk.Context, id string, kind string) (obj Object, e err = errors.New("Object not exists") return } - obj.client, err = man.client.Query(ctx, obj.ClientID(ctx)) + obj.client, err = man.client.Query(ctx, obj.Connection(ctx).Client) if err != nil { return } @@ -159,10 +169,6 @@ func (man Manager) Query(ctx sdk.Context, id string) (obj Object, err error) { err = errors.New("Object not exists") return } - if !obj.Available(ctx) { - err = errors.New("object not available") - return - } - obj.client, err = man.client.Query(ctx, obj.ClientID(ctx)) + obj.client, err = man.client.Query(ctx, obj.Connection(ctx).Client) return } diff --git a/x/ibc/03-connection/tests/connection_test.go b/x/ibc/03-connection/tests/connection_test.go index a6c0860ff6ff..2edc9c3ad3cf 100644 --- a/x/ibc/03-connection/tests/connection_test.go +++ b/x/ibc/03-connection/tests/connection_test.go @@ -38,23 +38,23 @@ func TestHandshake(t *testing.T) { // counterparty.OpenTry node.Counterparty.UpdateClient(t, header) cliobj := node.CLIObject() - _, phand := node.Query(t, cliobj.HandshakeKey) + _, pconn := node.Query(t, cliobj.ConnectionKey) _, pstate := node.Query(t, cliobj.StateKey) _, ptimeout := node.Query(t, cliobj.TimeoutKey) - _, pclientid := node.Query(t, cliobj.ClientIDKey) + _, pcounterclient := node.Query(t, cliobj.CounterpartyClientKey) // TODO: implement consensus state checking // _, pclient := node.Query(t, cliobj.Client.ConsensusStateKey) - node.Counterparty.OpenTry(t, phand, pstate, ptimeout, pclientid) + node.Counterparty.OpenTry(t, pconn, pstate, ptimeout, pcounterclient) header = node.Counterparty.Commit() // self.OpenAck node.UpdateClient(t, header) cliobj = node.Counterparty.CLIObject() - _, phand = node.Counterparty.Query(t, cliobj.HandshakeKey) + _, pconn = node.Counterparty.Query(t, cliobj.ConnectionKey) _, pstate = node.Counterparty.Query(t, cliobj.StateKey) _, ptimeout = node.Counterparty.Query(t, cliobj.TimeoutKey) - _, pclientid = node.Counterparty.Query(t, cliobj.ClientIDKey) - node.OpenAck(t, phand, pstate, ptimeout, pclientid) + _, pcounterclient = node.Counterparty.Query(t, cliobj.CounterpartyClientKey) + node.OpenAck(t, pconn, pstate, ptimeout, pcounterclient) header = node.Commit() // counterparty.OpenConfirm diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index e1112fc43895..66bf2434db80 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -20,9 +20,9 @@ type Node struct { *tendermint.Node Counterparty *Node - Client string - Handshake connection.Handshake - State connection.State + CounterpartyClient string + Connection connection.Connection + State connection.State Cdc *codec.Codec } @@ -45,11 +45,11 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { Cdc: cdc, } - res.Handshake = connection.Handshake{ + res.Connection = connection.Connection{ Counterparty: res.Counterparty.Name, } - res.Counterparty.Handshake = connection.Handshake{ + res.Counterparty.Connection = connection.Connection{ Counterparty: res.Name, } @@ -61,14 +61,14 @@ func (node *Node) CreateClient(t *testing.T) { climan, _ := node.Manager() obj, err := climan.Create(ctx, node.Counterparty.LastStateVerifier().ConsensusState) require.NoError(t, err) - node.Client = obj.ID() - node.Counterparty.Handshake.CounterpartyClient = obj.ID() + node.Connection.Client = obj.ID() + node.Counterparty.CounterpartyClient = obj.ID() } func (node *Node) UpdateClient(t *testing.T, header client.Header) { ctx := node.Context() climan, _ := node.Manager() - obj, err := climan.Query(ctx, node.Client) + obj, err := climan.Query(ctx, node.Connection.Client) require.NoError(t, err) err = obj.Update(ctx, header) require.NoError(t, err) @@ -107,21 +107,25 @@ 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.Client, node.Handshake, 100) // TODO: test timeout + obj, err := man.OpenInit(ctx, node.Name, node.Connection, node.CounterpartyClient, 100) // TODO: test timeout require.NoError(t, err) require.Equal(t, connection.Init, obj.State(ctx)) - require.Equal(t, node.Handshake, obj.Handshake(ctx)) - require.False(t, obj.Available(ctx)) + require.Equal(t, node.Connection, obj.Connection(ctx)) + require.Equal(t, node.CounterpartyClient, obj.CounterpartyClient(ctx)) + require.False(t, obj.Sendable(ctx)) + require.False(t, obj.Receivable(ctx)) node.SetState(connection.Init) } func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenTry(ctx, node.Name, node.Client, node.Handshake, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenTry(ctx, node.Name, node.Connection, node.CounterpartyClient, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.OpenTry, obj.State(ctx)) - require.Equal(t, node.Handshake, obj.Handshake(ctx)) - require.False(t, obj.Available(ctx)) + require.Equal(t, node.Connection, obj.Connection(ctx)) + require.Equal(t, node.CounterpartyClient, obj.CounterpartyClient(ctx)) + require.False(t, obj.Sendable(ctx)) + require.False(t, obj.Receivable(ctx)) node.SetState(connection.OpenTry) } @@ -130,8 +134,9 @@ func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { obj, err := man.OpenAck(ctx, node.Name, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.Open, obj.State(ctx)) - require.Equal(t, node.Handshake, obj.Handshake(ctx)) - require.True(t, obj.Available(ctx)) + require.Equal(t, node.Connection, obj.Connection(ctx)) + require.True(t, obj.Sendable(ctx)) + require.True(t, obj.Receivable(ctx)) node.SetState(connection.Open) } @@ -140,7 +145,8 @@ func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { obj, err := man.OpenConfirm(ctx, node.Name, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.Open, obj.State(ctx)) - require.Equal(t, node.Handshake, obj.Handshake(ctx)) - require.True(t, obj.Available(ctx)) + require.Equal(t, node.Connection, obj.Connection(ctx)) + require.True(t, obj.Sendable(ctx)) + require.True(t, obj.Receivable(ctx)) node.SetState(connection.CloseTry) } diff --git a/x/ibc/03-connection/types.go b/x/ibc/03-connection/types.go index 62f5de12b2a5..4811572a5284 100644 --- a/x/ibc/03-connection/types.go +++ b/x/ibc/03-connection/types.go @@ -1,11 +1,25 @@ package connection -import () +import ( + "errors" + "strings" +) -type Connection interface { - GetCounterparty() string - GetClient() string - GetCounterpartyClient() string +type Connection struct { + Client string + Counterparty string +} + +func (conn Connection) MarshalAmino() (string, error) { + return strings.Join([]string{conn.Client, conn.Counterparty}, "/"), nil +} - Available() bool +func (conn *Connection) UnmarshalAmino(text string) (err error) { + fields := strings.Split(text, "/") + if len(fields) < 2 { + return errors.New("not enough number of fields") + } + conn.Client = fields[0] + conn.Counterparty = fields[1] + return nil } From 0b4eab02dd1ff21116293e74722c4091825d760c Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 16:31:45 +0200 Subject: [PATCH 064/378] rm sendable/receivable --- x/ibc/03-connection/cli.go | 15 ++++----------- x/ibc/03-connection/handshake.go | 16 ++++++---------- x/ibc/03-connection/manager.go | 23 +++++++---------------- x/ibc/03-connection/tests/types.go | 12 ++++-------- x/ibc/03-connection/types.go | 9 +++++++++ 5 files changed, 30 insertions(+), 45 deletions(-) diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index 0c8e8de505b1..b6f3cb993749 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -12,8 +12,7 @@ import ( type CLIObject struct { ID string ConnectionKey []byte - SendableKey []byte - ReceivableKey []byte + AvailableKey []byte KindKey []byte Client client.CLIObject @@ -27,8 +26,7 @@ func (man Manager) CLIObject(root merkle.Root, id string) CLIObject { return CLIObject{ ID: obj.id, ConnectionKey: obj.connection.Key(), - SendableKey: obj.sendable.Key(), - ReceivableKey: obj.receivable.Key(), + AvailableKey: obj.available.Key(), KindKey: obj.kind.Key(), // TODO: unify man.CLIObject() <=> obj.CLI() @@ -58,13 +56,8 @@ func (obj CLIObject) Connection(ctx context.CLIContext) (res Connection, proof m return } -func (obj CLIObject) Sendable(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.SendableKey, &res) - return -} - -func (obj CLIObject) Receivable(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.ReceivableKey, &res) +func (obj CLIObject) Available(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.AvailableKey, &res) return } diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index 27fd0389bd12..1f694dbd6927 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -20,16 +20,14 @@ const ( Closed ) +const HandshakeKind = "handshake" + type Handshaker struct { man Manager 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? @@ -87,7 +85,7 @@ func (man CounterpartyHandshaker) object(id string) CounterHandshakeObject { } func (man Handshaker) create(ctx sdk.Context, id string, connection Connection, counterpartyClient string) (obj HandshakeObject, err error) { - cobj, err := man.man.create(ctx, id, connection, man.Kind()) + cobj, err := man.man.create(ctx, id, connection, HandshakeKind) if err != nil { return } @@ -98,7 +96,7 @@ func (man Handshaker) create(ctx sdk.Context, id string, connection Connection, } func (man Handshaker) query(ctx sdk.Context, id string) (obj HandshakeObject, err error) { - cobj, err := man.man.query(ctx, id, man.Kind()) + cobj, err := man.man.query(ctx, id, HandshakeKind) if err != nil { return } @@ -266,8 +264,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, } */ - obj.sendable.Set(ctx, true) - obj.receivable.Set(ctx, true) + obj.available.Set(ctx, true) obj.nextTimeout.Set(ctx, uint64(nextTimeoutHeight)) return @@ -300,8 +297,7 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, id string, timeoutHeight uint return } - obj.sendable.Set(ctx, true) - obj.receivable.Set(ctx, true) + obj.available.Set(ctx, true) obj.nextTimeout.Set(ctx, 0) return diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index ad28264cc594..fff3c1bd1552 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -48,8 +48,7 @@ type Object struct { protocol state.Mapping connection state.Value - sendable state.Boolean - receivable state.Boolean + available state.Boolean kind state.String @@ -62,8 +61,7 @@ func (man Manager) object(id string) Object { protocol: man.protocol.Prefix([]byte(id + "/")), connection: man.protocol.Value([]byte(id)), - sendable: state.NewBoolean(man.protocol.Value([]byte(id + "/sendable"))), - receivable: state.NewBoolean(man.protocol.Value([]byte(id + "/receivable"))), + available: state.NewBoolean(man.protocol.Value([]byte(id + "/available"))), kind: state.NewString(man.protocol.Value([]byte(id + "/kind"))), @@ -76,8 +74,7 @@ type CounterObject struct { protocol commitment.Mapping connection commitment.Value - sendable commitment.Boolean - receivable commitment.Boolean + available commitment.Boolean kind commitment.String @@ -89,8 +86,7 @@ func (man CounterpartyManager) object(id string) CounterObject { id: id, protocol: man.protocol.Prefix([]byte(id + "/")), connection: man.protocol.Value([]byte(id)), - sendable: commitment.NewBoolean(man.protocol.Value([]byte(id + "/sendable"))), - receivable: commitment.NewBoolean(man.protocol.Value([]byte(id + "/receivable"))), + available: commitment.NewBoolean(man.protocol.Value([]byte(id + "/available"))), kind: commitment.NewString(man.protocol.Value([]byte(id + "/kind"))), @@ -106,12 +102,8 @@ func (obj Object) Connection(ctx sdk.Context) (res Connection) { return } -func (obj Object) Sendable(ctx sdk.Context) bool { - return obj.sendable.Get(ctx) -} - -func (obj Object) Receivable(ctx sdk.Context) bool { - return obj.receivable.Get(ctx) +func (obj Object) Available(ctx sdk.Context) bool { + return obj.available.Get(ctx) } func (obj Object) Client() client.Object { @@ -120,8 +112,7 @@ func (obj Object) Client() client.Object { func (obj Object) remove(ctx sdk.Context) { obj.connection.Delete(ctx) - obj.sendable.Delete(ctx) - obj.receivable.Delete(ctx) + obj.available.Delete(ctx) obj.kind.Delete(ctx) } diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index 66bf2434db80..b0574b221ea7 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -112,8 +112,7 @@ func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { require.Equal(t, connection.Init, obj.State(ctx)) require.Equal(t, node.Connection, obj.Connection(ctx)) require.Equal(t, node.CounterpartyClient, obj.CounterpartyClient(ctx)) - require.False(t, obj.Sendable(ctx)) - require.False(t, obj.Receivable(ctx)) + require.False(t, obj.Available(ctx)) node.SetState(connection.Init) } @@ -124,8 +123,7 @@ func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { require.Equal(t, connection.OpenTry, obj.State(ctx)) require.Equal(t, node.Connection, obj.Connection(ctx)) require.Equal(t, node.CounterpartyClient, obj.CounterpartyClient(ctx)) - require.False(t, obj.Sendable(ctx)) - require.False(t, obj.Receivable(ctx)) + require.False(t, obj.Available(ctx)) node.SetState(connection.OpenTry) } @@ -135,8 +133,7 @@ func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { require.NoError(t, err) require.Equal(t, connection.Open, obj.State(ctx)) require.Equal(t, node.Connection, obj.Connection(ctx)) - require.True(t, obj.Sendable(ctx)) - require.True(t, obj.Receivable(ctx)) + require.True(t, obj.Available(ctx)) node.SetState(connection.Open) } @@ -146,7 +143,6 @@ func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { require.NoError(t, err) require.Equal(t, connection.Open, obj.State(ctx)) require.Equal(t, node.Connection, obj.Connection(ctx)) - require.True(t, obj.Sendable(ctx)) - require.True(t, obj.Receivable(ctx)) + require.True(t, obj.Available(ctx)) node.SetState(connection.CloseTry) } diff --git a/x/ibc/03-connection/types.go b/x/ibc/03-connection/types.go index 4811572a5284..428137aad893 100644 --- a/x/ibc/03-connection/types.go +++ b/x/ibc/03-connection/types.go @@ -23,3 +23,12 @@ func (conn *Connection) UnmarshalAmino(text string) (err error) { conn.Counterparty = fields[1] return nil } + +var kinds = map[string]Kind{ + "handshake": Kind{true, true}, +} + +type Kind struct { + Sendable bool + Receivable bool +} From 9481364ce2123ec40d9a2b6acbffa60506a54f56 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 16:34:48 +0200 Subject: [PATCH 065/378] add sendable/receivable method to object --- x/ibc/03-connection/manager.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index fff3c1bd1552..32602dc12ecd 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -110,6 +110,14 @@ func (obj Object) Client() client.Object { return obj.client } +func (obj Object) Sendable(ctx sdk.Context) bool { + return kinds[obj.kind.Get(ctx)].Sendable +} + +func (obj Object) Receivble(ctx sdk.Context) bool { + return kinds[obj.kind.Get(ctx)].Receivable +} + func (obj Object) remove(ctx sdk.Context) { obj.connection.Delete(ctx) obj.available.Delete(ctx) From a3261d7aea42a4dea16e2abd4a3732c722cc6916 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 16:40:01 +0200 Subject: [PATCH 066/378] add checking availabiltiy --- x/ibc/03-connection/manager.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 32602dc12ecd..510867404621 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -168,6 +168,10 @@ func (man Manager) Query(ctx sdk.Context, id string) (obj Object, err error) { err = errors.New("Object not exists") return } + if !obj.Available(ctx) { + err = errors.New("Object not available") + return + } obj.client, err = man.client.Query(ctx, obj.Connection(ctx).Client) return } From ca9ecbca657d1bdd2bbe3576716f32256ba815f0 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 17:47:49 +0200 Subject: [PATCH 067/378] add context() in test --- x/ibc/03-connection/tests/types.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index b0574b221ea7..c9770cfd281b 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -57,7 +57,7 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { } func (node *Node) CreateClient(t *testing.T) { - ctx := node.Context() + ctx := node.Context(t, nil) climan, _ := node.Manager() obj, err := climan.Create(ctx, node.Counterparty.LastStateVerifier().ConsensusState) require.NoError(t, err) @@ -66,7 +66,7 @@ func (node *Node) CreateClient(t *testing.T) { } func (node *Node) UpdateClient(t *testing.T, header client.Header) { - ctx := node.Context() + ctx := node.Context(t, nil) climan, _ := node.Manager() obj, err := climan.Query(ctx, node.Connection.Client) require.NoError(t, err) @@ -79,11 +79,16 @@ func (node *Node) SetState(state connection.State) { node.Counterparty.State = state } -func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Context, connection.Handshaker) { - ctx := node.Context() +func (node *Node) Context(t *testing.T, proofs []commitment.Proof) sdk.Context { + ctx := node.Node.Context() store, err := commitment.NewStore(node.Counterparty.Root, proofs) require.NoError(t, err) ctx = commitment.WithStore(ctx, store) + return ctx +} + +func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Context, connection.Handshaker) { + ctx := node.Context(t, proofs) _, man := node.Manager() return ctx, connection.NewHandshaker(man) } From 83b9f5a92afb2f20a98ea0d1d84aba1d5dba9ca6 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 18:49:29 +0200 Subject: [PATCH 068/378] fix most of lint --- store/state/string.go | 2 +- x/ibc/03-connection/handshake.go | 17 ++++++++--------- x/ibc/03-connection/manager.go | 1 + 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/store/state/string.go b/store/state/string.go index 38b92b16ec71..6bfc0300e2ca 100644 --- a/store/state/string.go +++ b/store/state/string.go @@ -14,7 +14,7 @@ func (v String) Get(ctx Context) (res string) { } func (v String) GetSafe(ctx Context) (res string, err error) { - v.Value.GetSafe(ctx, &res) + err = v.Value.GetSafe(ctx, &res) return } diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index 1f694dbd6927..83dde7db5882 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -186,7 +186,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { + if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { err = errors.New("unexpected counterparty timeout value") return } @@ -250,22 +250,21 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { + if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { err = errors.New("unexpected counterparty timeout value") return } - // TODO: commented out, implement in v1 + // TODO: implement in v1 /* var expected client.ConsensusState - obj.self.Get(ctx, expheight, &expected) + // obj.self.Get(ctx, expheight, &expected) if !obj.counterparty.client.Is(ctx, expected) { - return errors.New("unexpected counterparty client value") + // return errors.New("unexpected counterparty client value") } */ - obj.available.Set(ctx, true) - obj.nextTimeout.Set(ctx, uint64(nextTimeoutHeight)) + obj.nextTimeout.Set(ctx, nextTimeoutHeight) return } @@ -304,7 +303,7 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, id string, timeoutHeight uint } func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { - if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { + if !(obj.client.ConsensusState(ctx).GetHeight() > obj.nextTimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } @@ -387,7 +386,7 @@ func (obj HandshakeObject) CloseAck(ctx sdk.Context, timeoutHeight uint64) error } func (obj HandshakeObject) CloseTimeout(ctx sdk.Context) error { - if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { + if !(obj.client.ConsensusState(ctx).GetHeight() > obj.nextTimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 510867404621..7d472dfc7e08 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -93,6 +93,7 @@ func (man CounterpartyManager) object(id string) CounterObject { // CONTRACT: client should be filled by the caller } } + func (obj Object) ID() string { return obj.id } From 94edc2f73ab37def0e2ce29ab4ef6511faed4c9e Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 19:15:56 +0200 Subject: [PATCH 069/378] fix lijt --- x/ibc/02-client/tendermint/tests/types.go | 5 ----- x/ibc/03-connection/manager.go | 3 ++- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 860cb424e11d..a601479dbec8 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -23,11 +23,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -// nolint: unused -func newRoot() merkle.Root { - return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) -} - const chainid = "testchain" func NewRoot(keyPrefix []byte) merkle.Root { diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 7d472dfc7e08..7e7f85c48975 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -78,7 +78,8 @@ type CounterObject struct { kind commitment.String - client client.CounterObject + // TODO: prove counterparty client in v1 + client client.CounterObject // nolint: unused } func (man CounterpartyManager) object(id string) CounterObject { From db93a8ad6c614fb7e6a96f71ac433a249c549448 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 12 Jul 2019 01:21:00 +0900 Subject: [PATCH 070/378] separate root/path --- x/ibc/23-commitment/merkle/merkle.go | 48 ++++++++++++++--------- x/ibc/23-commitment/merkle/merkle_test.go | 38 +++++++++--------- x/ibc/23-commitment/merkle/utils.go | 22 +++++------ x/ibc/23-commitment/store.go | 11 +++++- x/ibc/23-commitment/types.go | 7 +++- 5 files changed, 74 insertions(+), 52 deletions(-) diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index bc01e0f112ee..9fb11c7f38cb 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -10,37 +10,44 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) +const merkleKind = "merkle" + // merkle.Proof implementation of Proof // Applied on SDK-based IBC implementation - var _ commitment.Root = Root{} type Root struct { - Hash []byte - KeyPath [][]byte - KeyPrefix []byte + Hash []byte } -func NewRoot(hash []byte, keypath [][]byte, prefix []byte) Root { +func NewRoot(hash []byte) Root { return Root{ - Hash: hash, - KeyPath: keypath, - KeyPrefix: prefix, + Hash: hash, } } func (Root) CommitmentKind() string { - return "merkle" + return merkleKind } -func (r Root) Update(hash []byte) commitment.Root { - return Root{ - Hash: hash, - KeyPath: r.KeyPath, - KeyPrefix: r.KeyPrefix, +var _ commitment.Path = Path{} + +type Path struct { + KeyPath [][]byte + KeyPrefix []byte +} + +func NewPath(keypath [][]byte, keyprefix []byte) Path { + return Path{ + KeyPath: keypath, + KeyPrefix: keyprefix, } } +func (Path) CommitmentKind() string { + return merkleKind +} + var _ commitment.Proof = Proof{} type Proof struct { @@ -49,24 +56,29 @@ type Proof struct { } func (Proof) CommitmentKind() string { - return "merkle" + return merkleKind } func (proof Proof) GetKey() []byte { return proof.Key } -func (proof Proof) Verify(croot commitment.Root, value []byte) error { +func (proof Proof) Verify(croot commitment.Root, cpath commitment.Path, value []byte) error { root, ok := croot.(Root) if !ok { return errors.New("invalid commitment root type") } + path, ok := cpath.(Path) + if !ok { + return errors.New("invalid commitment path type") + } + keypath := merkle.KeyPath{} - for _, key := range root.KeyPath { + for _, key := range path.KeyPath { keypath = keypath.AppendKey(key, merkle.KeyEncodingHex) } - keypath = keypath.AppendKey(append(root.KeyPrefix, proof.Key...), merkle.KeyEncodingHex) + keypath = keypath.AppendKey(append(path.KeyPrefix, proof.Key...), merkle.KeyEncodingHex) // Hard coded for now runtime := rootmulti.DefaultProofRuntime() diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index 487e9496163e..f93f64943609 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -31,56 +31,56 @@ func defaultComponents() (sdk.StoreKey, sdk.Context, types.CommitMultiStore, *co return key, ctx, cms, cdc } -func commit(cms types.CommitMultiStore, root Root) Root { +func commit(cms types.CommitMultiStore) Root { cid := cms.Commit() - return root.Update(cid.Hash).(Root) + return NewRoot(cid.Hash) } func TestStore(t *testing.T) { k, ctx, cms, _ := defaultComponents() kvstore := ctx.KVStore(k) - root := Root{KeyPath: [][]byte{[]byte("test")}, KeyPrefix: []byte{0x01, 0x03, 0x05}} + path := Path{KeyPath: [][]byte{[]byte("test")}, KeyPrefix: []byte{0x01, 0x03, 0x05}} - kvstore.Set(root.Key([]byte("hello")), []byte("world")) - kvstore.Set(root.Key([]byte("merkle")), []byte("tree")) - kvstore.Set(root.Key([]byte("block")), []byte("chain")) + kvstore.Set(path.Key([]byte("hello")), []byte("world")) + kvstore.Set(path.Key([]byte("merkle")), []byte("tree")) + kvstore.Set(path.Key([]byte("block")), []byte("chain")) - root = commit(cms, root) + root := commit(cms) - c1, v1, p1 := root.Query(cms, []byte("hello")) + c1, v1, p1 := path.Query(cms, []byte("hello")) require.Equal(t, uint32(0), c1) require.Equal(t, []byte("world"), v1) - c2, v2, p2 := root.Query(cms, []byte("merkle")) + c2, v2, p2 := path.Query(cms, []byte("merkle")) require.Equal(t, uint32(0), c2) require.Equal(t, []byte("tree"), v2) - c3, v3, p3 := root.Query(cms, []byte("block")) + c3, v3, p3 := path.Query(cms, []byte("block")) require.Equal(t, uint32(0), c3) require.Equal(t, []byte("chain"), v3) - cstore, err := commitment.NewStore(root, []commitment.Proof{p1, p2, p3}) + cstore, err := commitment.NewStore(root, path, []commitment.Proof{p1, p2, p3}) require.NoError(t, err) require.True(t, cstore.Prove([]byte("hello"), []byte("world"))) require.True(t, cstore.Prove([]byte("merkle"), []byte("tree"))) require.True(t, cstore.Prove([]byte("block"), []byte("chain"))) - kvstore.Set(root.Key([]byte("12345")), []byte("67890")) - kvstore.Set(root.Key([]byte("qwerty")), []byte("zxcv")) - kvstore.Set(root.Key([]byte("hello")), []byte("dlrow")) + kvstore.Set(path.Key([]byte("12345")), []byte("67890")) + kvstore.Set(path.Key([]byte("qwerty")), []byte("zxcv")) + kvstore.Set(path.Key([]byte("hello")), []byte("dlrow")) - root = commit(cms, root) + root = commit(cms) - c1, v1, p1 = root.Query(cms, []byte("12345")) + c1, v1, p1 = path.Query(cms, []byte("12345")) require.Equal(t, uint32(0), c1) require.Equal(t, []byte("67890"), v1) - c2, v2, p2 = root.Query(cms, []byte("qwerty")) + c2, v2, p2 = path.Query(cms, []byte("qwerty")) require.Equal(t, uint32(0), c2) require.Equal(t, []byte("zxcv"), v2) - c3, v3, p3 = root.Query(cms, []byte("hello")) + c3, v3, p3 = path.Query(cms, []byte("hello")) require.Equal(t, uint32(0), c3) require.Equal(t, []byte("dlrow"), v3) - cstore, err = commitment.NewStore(root, []commitment.Proof{p1, p2, p3}) + cstore, err = commitment.NewStore(root, path, []commitment.Proof{p1, p2, p3}) require.NoError(t, err) require.True(t, cstore.Prove([]byte("12345"), []byte("67890"))) diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index 1fa13f6a3d32..d2eabdaed99d 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -6,23 +6,23 @@ import ( "github.com/cosmos/cosmos-sdk/store/types" ) -func (root Root) RequestQuery(key []byte) abci.RequestQuery { - path := "" - for _, inter := range root.KeyPath { - path = path + "/" + string(inter) +func (path Path) RequestQuery(key []byte) abci.RequestQuery { + pathstr := "" + for _, inter := range path.KeyPath { + pathstr = pathstr + "/" + string(inter) } - path = path + "/key" + pathstr = pathstr + "/key" - data := append(root.KeyPrefix, key...) + data := append(path.KeyPrefix, key...) - return abci.RequestQuery{Path: path, Data: data, Prove: true} + return abci.RequestQuery{Path: pathstr, Data: data, Prove: true} } -func (root Root) Query(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { - qres := cms.(types.Queryable).Query(root.RequestQuery(key)) +func (path Path) Query(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { + qres := cms.(types.Queryable).Query(path.RequestQuery(key)) return qres.Code, qres.Value, Proof{Key: key, Proof: qres.Proof} } -func (root Root) Key(key []byte) []byte { - return append(root.KeyPrefix, key...) // XXX: cloneAppend +func (path Path) Key(key []byte) []byte { + return append(path.KeyPrefix, key...) // XXX: cloneAppend } diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 8cfaef4baaa1..0bae09c8c669 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -31,14 +31,21 @@ var _ Store = store{} type store struct { root Root + path Path proofs map[string]Proof verified map[string][]byte } // Proofs must be provided -func NewStore(root Root, proofs []Proof) (res store, err error) { +func NewStore(root Root, path Path, proofs []Proof) (res store, err error) { + if root.CommitmentKind() != path.CommitmentKind() { + err = errors.New("path type not matching with root's") + return + } + res = store{ root: root, + path: path, proofs: make(map[string]Proof), verified: make(map[string][]byte), } @@ -68,7 +75,7 @@ func (store store) Prove(key, value []byte) bool { if !ok { return false } - err := proof.Verify(store.root, value) + err := proof.Verify(store.root, store.path, value) if err != nil { return false } diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go index e12d8f0fcef6..6453511a24e3 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/types.go @@ -2,11 +2,14 @@ package commitment type Root interface { CommitmentKind() string - Update([]byte) Root +} + +type Path interface { + CommitmentKind() string } type Proof interface { CommitmentKind() string GetKey() []byte - Verify(Root, []byte) error + Verify(Root, Path, []byte) error } From 8da259838247d909c954dc3d0c90427dad10b557 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 7 Jun 2019 23:47:01 +0200 Subject: [PATCH 071/378] add client --- x/ibc/02-client/manager.go | 146 ++++++++++++++++++++++++++++ x/ibc/02-client/tendermint/types.go | 79 +++++++++++++++ x/ibc/02-client/types.go | 46 +++++++++ 3 files changed, 271 insertions(+) create mode 100644 x/ibc/02-client/manager.go create mode 100644 x/ibc/02-client/tendermint/types.go create mode 100644 x/ibc/02-client/types.go diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go new file mode 100644 index 000000000000..89a8a878df49 --- /dev/null +++ b/x/ibc/02-client/manager.go @@ -0,0 +1,146 @@ +package client + +import ( + "errors" + "strconv" + + "github.com/cosmos/cosmos-sdk/store/mapping" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type IDGenerator func(sdk.Context /*Header,*/, mapping.Value) string + +func IntegerIDGenerator(ctx sdk.Context, v mapping.Value) string { + id := mapping.NewInteger(v, mapping.Dec).Incr(ctx) + return strconv.FormatUint(id, 10) +} + +type Manager struct { + protocol mapping.Mapping + + idval mapping.Value + idgen IDGenerator +} + +func NewManager(protocol, free mapping.Base, idgen IDGenerator) Manager { + return Manager{ + protocol: mapping.NewMapping(protocol, []byte("/")), + idval: mapping.NewValue(free, []byte("/id")), + idgen: idgen, + } +} + +/* +func (man Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { + if _, ok := man.pred[kind]; ok { + panic("Kind already registered") + } + man.pred[kind] = pred + return man +} +*/ +func (man Manager) object(id string) Object { + return Object{ + id: id, + client: man.protocol.Value([]byte(id)), + freeze: mapping.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), + } +} + +func (man Manager) Create(ctx sdk.Context, cs Client) string { + id := man.idgen(ctx, man.idval) + err := man.object(id).create(ctx, cs) + if err != nil { + panic(err) + } + return id +} + +func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { + res := man.object(id) + if !res.exists(ctx) { + return Object{}, errors.New("client not exists") + } + return res, nil +} + +type Object struct { + id string + client mapping.Value + freeze mapping.Boolean +} + +func (obj Object) create(ctx sdk.Context, st Client) error { + if obj.exists(ctx) { + return errors.New("Create client on already existing id") + } + obj.client.Set(ctx, st) + return nil +} + +func (obj Object) exists(ctx sdk.Context) bool { + return obj.client.Exists(ctx) +} + +func (obj Object) ID() string { + return obj.id +} + +func (obj Object) Value(ctx sdk.Context) (res Client) { + obj.client.Get(ctx, &res) + return +} + +func (obj Object) Is(ctx sdk.Context, client Client) bool { + return obj.client.Is(ctx, client) +} + +func (obj Object) Update(ctx sdk.Context, header Header) error { + if !obj.exists(ctx) { + panic("should not update nonexisting client") + } + + if obj.freeze.Get(ctx) { + return errors.New("client is frozen") + } + + var stored Client + obj.client.GetIfExists(ctx, &stored) + updated, err := stored.Validate(header) + if err != nil { + return err + } + + obj.client.Set(ctx, updated) + + return nil +} + +func (obj Object) Freeze(ctx sdk.Context) error { + if !obj.exists(ctx) { + panic("should not freeze nonexisting client") + } + + if obj.freeze.Get(ctx) { + return errors.New("client is already frozen") + } + + obj.freeze.Set(ctx, true) + + return nil +} + +func (obj Object) Delete(ctx sdk.Context) error { + if !obj.exists(ctx) { + panic("should not delete nonexisting client") + } + + if !obj.freeze.Get(ctx) { + return errors.New("client is not frozen") + } + + obj.client.Delete(ctx) + obj.freeze.Delete(ctx) + + return nil +} diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go new file mode 100644 index 000000000000..54655cf702d4 --- /dev/null +++ b/x/ibc/02-client/tendermint/types.go @@ -0,0 +1,79 @@ +package tendermint + +import ( + "bytes" + + "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +// Ref tendermint/lite/base_verifier.go + +var _ client.ValidityPredicateBase = ValidityPredicateBase{} + +type ValidityPredicateBase struct { + Height int64 + NextValidatorSet *types.ValidatorSet +} + +func (ValidityPredicateBase) Kind() client.Kind { + return client.Tendermint +} + +func (base ValidityPredicateBase) GetHeight() int64 { + return base.Height +} + +func (base ValidityPredicateBase) Equal(cbase client.ValidityPredicateBase) bool { + base0, ok := cbase.(ValidityPredicateBase) + if !ok { + return false + } + return base.Height == base0.Height && + bytes.Equal(base.NextValidatorSet.Hash(), base0.NextValidatorSet.Hash()) +} + +var _ client.Client = Client{} + +type Client struct { + Base ValidityPredicateBase + Root commitment.Root +} + +func (Client) Kind() client.Kind { + return client.Tendermint +} + +func (client Client) GetBase() client.ValidityPredicateBase { + return client.Base +} + +func (client Client) GetRoot() commitment.Root { + return client.Root +} + +func (client Client) Validate(header client.Header) (client.Client, error) { + return client, nil // XXX +} + +var _ client.Header = Header{} + +type Header struct { + Base ValidityPredicateBase + Root commitment.Root + Votes []*types.CommitSig +} + +func (header Header) Kind() client.Kind { + return client.Tendermint +} + +func (header Header) GetBase() client.ValidityPredicateBase { + return header.Base +} + +func (header Header) GetRoot() commitment.Root { + return header.Root +} diff --git a/x/ibc/02-client/types.go b/x/ibc/02-client/types.go new file mode 100644 index 000000000000..7b9f81ec7789 --- /dev/null +++ b/x/ibc/02-client/types.go @@ -0,0 +1,46 @@ +package client + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +// TODO: types in this file should be (de/)serialized with proto in the future + +type AminoMarshaler interface { + MarshalAmino() (string, error) + UnmarshalAmino(string) error +} + +type ValidityPredicateBase interface { + Kind() Kind + GetHeight() int64 + Equal(ValidityPredicateBase) bool +} + +// ConsensusState +type Client interface { + Kind() Kind + GetBase() ValidityPredicateBase + GetRoot() commitment.Root + Validate(Header) (Client, error) // ValidityPredicate +} + +func Equal(client1, client2 Client) bool { + return client1.Kind() == client2.Kind() && + client1.GetBase().Equal(client2.GetBase()) +} + +type Header interface { + Kind() Kind + // Proof() HeaderProof + GetBase() ValidityPredicateBase // can be nil + GetRoot() commitment.Root +} + +// XXX: Kind should be enum? + +type Kind byte + +const ( + Tendermint Kind = iota +) From 9a07feb7e261b667b3998c53a9f6b9c1edf08e79 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 18:14:19 +0200 Subject: [PATCH 072/378] add counterpartymanager --- x/ibc/02-client/manager.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 89a8a878df49..97f281cc9596 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -6,6 +6,8 @@ import ( "github.com/cosmos/cosmos-sdk/store/mapping" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) type IDGenerator func(sdk.Context /*Header,*/, mapping.Value) string @@ -24,12 +26,22 @@ type Manager struct { func NewManager(protocol, free mapping.Base, idgen IDGenerator) Manager { return Manager{ - protocol: mapping.NewMapping(protocol, []byte("/")), - idval: mapping.NewValue(free, []byte("/id")), + protocol: mapping.NewMapping(protocol, []byte("/client")), + idval: mapping.NewValue(free, []byte("/client/id")), idgen: idgen, } } +type CounterpartyManager struct { + protocol commitment.Mapping +} + +func NewCounterpartyManager(protocol commitment.Base) CounterpartyManager { + return CounterpartyManager{ + protocol: commitment.NewMapping(protocol, []byte("/client")), + } +} + /* func (man Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { if _, ok := man.pred[kind]; ok { From 1c204dc8514c0fa51e0ea242c7f6ddc06c2dd7e8 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 18:29:24 +0200 Subject: [PATCH 073/378] fix manager --- x/ibc/02-client/manager.go | 16 ++++++++++++++++ x/ibc/23-commitment/value.go | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 97f281cc9596..c22576b18cd2 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -76,12 +76,28 @@ func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { return res, nil } +func (man CounterpartyManager) object(id string) CounterObject { + return CounterObject{ + id: id, + client: man.protocol.Value([]byte(id)), + } +} + +func (man CounterpartyManager) Query(id string) CounterObject { + return man.object(id) +} + type Object struct { id string client mapping.Value freeze mapping.Boolean } +type CounterObject struct { + id string + client commitment.Value +} + func (obj Object) create(ctx sdk.Context, st Client) error { if obj.exists(ctx) { return errors.New("Create client on already existing id") diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 70b8502a44e6..10b409b28b99 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -45,6 +45,13 @@ func NewMapping(base Base, prefix []byte) Mapping { } } +func (m Mapping) Value(key []byte) Value { + return Value{ + base: m.base, + key: key, + } +} + type Value struct { base Base key []byte From 6e5346bb37163cfe7b2a3edf564289ab21f18cd4 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 18:44:25 +0200 Subject: [PATCH 074/378] add Is() to counterobject --- x/ibc/02-client/manager.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index c22576b18cd2..502478104757 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -123,6 +123,10 @@ func (obj Object) Is(ctx sdk.Context, client Client) bool { return obj.client.Is(ctx, client) } +func (obj CounterObject) Is(ctx sdk.Context, client Client) bool { + return obj.client.Is(ctx, client) +} + func (obj Object) Update(ctx sdk.Context, header Header) error { if !obj.exists(ctx) { panic("should not update nonexisting client") From 337040845984a443f61df6ad5333eaa542b9c179 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 12 Jun 2019 00:08:04 +0200 Subject: [PATCH 075/378] add readme, reflect ICS02 revision --- x/ibc/02-client/README.md | 49 ++++++++++++++++++++++++++++++++++++++ x/ibc/02-client/manager.go | 31 ++++++++++-------------- x/ibc/02-client/types.go | 26 ++++++++------------ 3 files changed, 72 insertions(+), 34 deletions(-) create mode 100644 x/ibc/02-client/README.md diff --git a/x/ibc/02-client/README.md b/x/ibc/02-client/README.md new file mode 100644 index 000000000000..a9bd6892771b --- /dev/null +++ b/x/ibc/02-client/README.md @@ -0,0 +1,49 @@ +# ICS 02: Client + +Package `client` defines types and method to store and update light clients which tracks on other chain's state. +The main type is `Client`, which provides `commitment.Root` to verify state proofs and `ConsensusState` to +verify header proofs. + +## Spec + +```typescript +interface ConsensusState { + height: uint64 + root: CommitmentRoot + validityPredicate: ValidityPredicate + eqivocationPredicate: EquivocationPredicate +} + +interface ClientState { + consensusState: ConsensusState + verifiedRoots: Map + frozen: bool +} + +interface Header { + height: uint64 + proof: HeaderProof + state: Maybe[ConsensusState] + root: CommitmentRoot +} + +type ValidityPredicate = (ConsensusState, Header) => Error | ConsensusState + +type EquivocationPredicate = (ConsensusState, Header, Header) => bool +``` + +## Impl + +### types.go + +`spec: interface ConsensusState` is implemented by `type ConsensusState`. `ConsensusState.{GetHeight(), GetRoot(), +Validate(), Equivocation()}` each corresponds to `spec: ConsensusState.{height, root, validityPredicate, +equivocationPredicate}`. `ConsensusState.Kind()` returns `Kind`, which is an enum indicating the type of the +consensus algorithm. + +`spec: interface Header` is implemented by `type Header`. `Header{GetHeight(), Proof(), State(), GetRoot()}` +each corresponds to `spec: Header.{height, proof, state, root}`. + +### manager.go + +`spec: interface ClientState` is implemented by `type Object`. // TODO diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 502478104757..0134d8340d55 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -10,6 +10,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) +// XXX: implement spec: ClientState.verifiedRoots + type IDGenerator func(sdk.Context /*Header,*/, mapping.Value) string func IntegerIDGenerator(ctx sdk.Context, v mapping.Value) string { @@ -59,13 +61,14 @@ func (man Manager) object(id string) Object { } } -func (man Manager) Create(ctx sdk.Context, cs Client) string { +func (man Manager) Create(ctx sdk.Context, cs ConsensusState) (Object, error) { id := man.idgen(ctx, man.idval) - err := man.object(id).create(ctx, cs) - if err != nil { - panic(err) + obj := man.object(id) + if obj.exists(ctx) { + return Object{}, errors.New("Create client on already existing id") } - return id + obj.client.Set(ctx, cs) + return obj, nil } func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { @@ -89,7 +92,7 @@ func (man CounterpartyManager) Query(id string) CounterObject { type Object struct { id string - client mapping.Value + client mapping.Value // ConsensusState freeze mapping.Boolean } @@ -98,14 +101,6 @@ type CounterObject struct { client commitment.Value } -func (obj Object) create(ctx sdk.Context, st Client) error { - if obj.exists(ctx) { - return errors.New("Create client on already existing id") - } - obj.client.Set(ctx, st) - return nil -} - func (obj Object) exists(ctx sdk.Context) bool { return obj.client.Exists(ctx) } @@ -114,16 +109,16 @@ func (obj Object) ID() string { return obj.id } -func (obj Object) Value(ctx sdk.Context) (res Client) { +func (obj Object) Value(ctx sdk.Context) (res ConsensusState) { obj.client.Get(ctx, &res) return } -func (obj Object) Is(ctx sdk.Context, client Client) bool { +func (obj Object) Is(ctx sdk.Context, client ConsensusState) bool { return obj.client.Is(ctx, client) } -func (obj CounterObject) Is(ctx sdk.Context, client Client) bool { +func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { return obj.client.Is(ctx, client) } @@ -136,7 +131,7 @@ func (obj Object) Update(ctx sdk.Context, header Header) error { return errors.New("client is frozen") } - var stored Client + var stored ConsensusState obj.client.GetIfExists(ctx, &stored) updated, err := stored.Validate(header) if err != nil { diff --git a/x/ibc/02-client/types.go b/x/ibc/02-client/types.go index 7b9f81ec7789..2ae484853354 100644 --- a/x/ibc/02-client/types.go +++ b/x/ibc/02-client/types.go @@ -5,35 +5,29 @@ import ( ) // TODO: types in this file should be (de/)serialized with proto in the future - -type AminoMarshaler interface { - MarshalAmino() (string, error) - UnmarshalAmino(string) error -} - -type ValidityPredicateBase interface { - Kind() Kind - GetHeight() int64 - Equal(ValidityPredicateBase) bool -} +// currently amkno codec handles it // ConsensusState -type Client interface { +type ConsensusState interface { Kind() Kind - GetBase() ValidityPredicateBase + GetHeight() uint64 GetRoot() commitment.Root - Validate(Header) (Client, error) // ValidityPredicate + Validate(Header) (ConsensusState, error) // ValidityPredicate + Equivocation(Header, Header) bool // EquivocationPredicate } -func Equal(client1, client2 Client) bool { +/* +func Equal(client1, client2 ConsensusState) bool { return client1.Kind() == client2.Kind() && client1.GetBase().Equal(client2.GetBase()) } +*/ type Header interface { Kind() Kind + GetHeight() uint64 // Proof() HeaderProof - GetBase() ValidityPredicateBase // can be nil + State() ConsensusState // can be nil GetRoot() commitment.Root } From 2d43e209046d80a7ff10207c0cba4201ab68de75 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 12 Jun 2019 00:28:13 +0200 Subject: [PATCH 076/378] reflect downstream ics --- x/ibc/02-client/manager.go | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 0134d8340d55..196d62e62fdc 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -4,7 +4,7 @@ import ( "errors" "strconv" - "github.com/cosmos/cosmos-sdk/store/mapping" + "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" @@ -12,24 +12,24 @@ import ( // XXX: implement spec: ClientState.verifiedRoots -type IDGenerator func(sdk.Context /*Header,*/, mapping.Value) string +type IDGenerator func(sdk.Context /*Header,*/, state.Value) string -func IntegerIDGenerator(ctx sdk.Context, v mapping.Value) string { - id := mapping.NewInteger(v, mapping.Dec).Incr(ctx) +func IntegerIDGenerator(ctx sdk.Context, v state.Value) string { + id := state.NewInteger(v, state.Dec).Incr(ctx) return strconv.FormatUint(id, 10) } type Manager struct { - protocol mapping.Mapping + protocol state.Mapping - idval mapping.Value + idval state.Value idgen IDGenerator } -func NewManager(protocol, free mapping.Base, idgen IDGenerator) Manager { +func NewManager(protocol, free state.Base, idgen IDGenerator) Manager { return Manager{ - protocol: mapping.NewMapping(protocol, []byte("/client")), - idval: mapping.NewValue(free, []byte("/client/id")), + protocol: state.NewMapping(protocol, []byte("/client")), + idval: state.NewValue(free, []byte("/client/id")), idgen: idgen, } } @@ -57,7 +57,7 @@ func (man Manager) object(id string) Object { return Object{ id: id, client: man.protocol.Value([]byte(id)), - freeze: mapping.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), + freeze: state.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), } } @@ -92,8 +92,8 @@ func (man CounterpartyManager) Query(id string) CounterObject { type Object struct { id string - client mapping.Value // ConsensusState - freeze mapping.Boolean + client state.Value // ConsensusState + freeze state.Boolean } type CounterObject struct { @@ -114,10 +114,6 @@ func (obj Object) Value(ctx sdk.Context) (res ConsensusState) { return } -func (obj Object) Is(ctx sdk.Context, client ConsensusState) bool { - return obj.client.Is(ctx, client) -} - func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { return obj.client.Is(ctx, client) } From 2bd98e151839f62baa3d73c9d23cc285a3ce9efd Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 13 Jun 2019 16:00:18 +0200 Subject: [PATCH 077/378] test in progress --- x/ibc/02-client/tendermint/types.go | 96 ++++++----- x/ibc/02-client/tendermint/types_test.go | 131 ++++++++++++++ x/ibc/02-client/tendermint/valset_test.go | 197 ++++++++++++++++++++++ x/ibc/02-client/types.go | 3 - 4 files changed, 386 insertions(+), 41 deletions(-) create mode 100644 x/ibc/02-client/tendermint/types_test.go create mode 100644 x/ibc/02-client/tendermint/valset_test.go diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 54655cf702d4..1442d91d6c99 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -2,78 +2,98 @@ package tendermint import ( "bytes" + "errors" + "fmt" + lerr "github.com/tendermint/tendermint/lite/errors" "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -// Ref tendermint/lite/base_verifier.go - -var _ client.ValidityPredicateBase = ValidityPredicateBase{} +var _ client.ConsensusState = ConsensusState{} -type ValidityPredicateBase struct { - Height int64 +// Ref tendermint/lite/base_verifier.go +type ConsensusState struct { + ChainID string + Height uint64 + Root commitment.Root NextValidatorSet *types.ValidatorSet } -func (ValidityPredicateBase) Kind() client.Kind { +func (ConsensusState) Kind() client.Kind { return client.Tendermint } -func (base ValidityPredicateBase) GetHeight() int64 { - return base.Height +func (cs ConsensusState) GetHeight() uint64 { + return cs.Height } -func (base ValidityPredicateBase) Equal(cbase client.ValidityPredicateBase) bool { - base0, ok := cbase.(ValidityPredicateBase) - if !ok { - return false +func (cs ConsensusState) GetRoot() commitment.Root { + return cs.Root +} + +func (cs ConsensusState) update(header Header) ConsensusState { + return ConsensusState{ + ChainID: cs.ChainID, + Height: uint64(header.Height), + Root: header.AppHash, + NextValidatorSet: header.NextValidatorSet, } - return base.Height == base0.Height && - bytes.Equal(base.NextValidatorSet.Hash(), base0.NextValidatorSet.Hash()) } -var _ client.Client = Client{} +func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, error) { + header, ok := cheader.(Header) + if !ok { + return nil, errors.New("invalid type") + } -type Client struct { - Base ValidityPredicateBase - Root commitment.Root -} + nextvalset := cs.NextValidatorSet + nexthash := nextvalset.Hash() -func (Client) Kind() client.Kind { - return client.Tendermint -} + if cs.Height == uint64(header.Height-1) { + nexthash = cs.NextValidatorSet.Hash() + if !bytes.Equal(header.ValidatorsHash, nexthash) { + fmt.Println(111) + return nil, lerr.ErrUnexpectedValidators(header.ValidatorsHash, nexthash) + } + } -func (client Client) GetBase() client.ValidityPredicateBase { - return client.Base -} + if !bytes.Equal(header.NextValidatorsHash, header.NextValidatorSet.Hash()) { + fmt.Println(header) + return nil, lerr.ErrUnexpectedValidators(header.NextValidatorsHash, header.NextValidatorSet.Hash()) + } + + err := header.ValidateBasic(cs.ChainID) + if err != nil { + return nil, err + } -func (client Client) GetRoot() commitment.Root { - return client.Root + err = cs.NextValidatorSet.VerifyCommit(cs.ChainID, header.Commit.BlockID, header.Height, header.Commit) + if err != nil { + return nil, err + } + + return cs.update(header), nil } -func (client Client) Validate(header client.Header) (client.Client, error) { - return client, nil // XXX +func (cs ConsensusState) Equivocation(header1, header2 client.Header) bool { + return false // XXX } var _ client.Header = Header{} type Header struct { - Base ValidityPredicateBase - Root commitment.Root - Votes []*types.CommitSig + // XXX: don't take the entire struct + types.SignedHeader + NextValidatorSet *types.ValidatorSet } func (header Header) Kind() client.Kind { return client.Tendermint } -func (header Header) GetBase() client.ValidityPredicateBase { - return header.Base -} - -func (header Header) GetRoot() commitment.Root { - return header.Root +func (header Header) GetHeight() uint64 { + return uint64(header.Height) } diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go new file mode 100644 index 000000000000..44dc0fc9aba9 --- /dev/null +++ b/x/ibc/02-client/tendermint/types_test.go @@ -0,0 +1,131 @@ +package tendermint + +import ( + "testing" + + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store" + stypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const chainid = "testchain" + +func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { + key := sdk.NewKVStoreKey("ibc") + db := dbm.NewMemDB() + cms := store.NewCommitMultiStore(db) + cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) + err := cms.LoadLatestVersion() + if err != nil { + panic(err) + } + ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) + cdc := codec.New() + return key, ctx, cms, cdc +} + +type node struct { + valset MockValidators + + cms sdk.CommitMultiStore + store sdk.KVStore + + commits []tmtypes.SignedHeader +} + +func NewNode(valset MockValidators) *node { + key, ctx, cms, _ := defaultComponents() + return &node{ + valset: valset, + cms: cms, + store: ctx.KVStore(key), + commits: nil, + } +} + +func (node *node) last() tmtypes.SignedHeader { + if len(node.commits) == 0 { + return tmtypes.SignedHeader{} + } + return node.commits[len(node.commits)-1] +} + +func (node *node) Commit() tmtypes.SignedHeader { + valsethash := node.valset.ValidatorSet().Hash() + nextvalset := node.valset.Mutate(false) + nextvalsethash := nextvalset.ValidatorSet().Hash() + commitid := node.cms.Commit() + + header := tmtypes.Header{ + ChainID: chainid, + Height: int64(len(node.commits) + 1), + LastBlockID: tmtypes.BlockID{ + Hash: node.last().Header.Hash(), + }, + + ValidatorsHash: valsethash, + NextValidatorsHash: nextvalsethash, + AppHash: commitid.Hash, + } + + commit := node.valset.Sign(header) + + node.commits = append(node.commits, commit) + + return commit +} + +func (node *node) Set(key, value string) { + node.store.Set(append([]byte{0x00}, []byte(key)...), []byte(value)) +} + +type Verifier struct { + ConsensusState +} + +func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators) *Verifier { + return &Verifier{ + ConsensusState{ + ChainID: chainid, + Height: uint64(header.Height), + Root: header.AppHash, + NextValidatorSet: nextvalset.ValidatorSet(), + }, + } +} + +func (v *Verifier) Validate(header tmtypes.SignedHeader, nextvalset MockValidators) error { + newcs, err := v.ConsensusState.Validate( + Header{ + SignedHeader: header, + NextValidatorSet: nextvalset.ValidatorSet(), + }, + ) + if err != nil { + return err + } + v.ConsensusState = newcs.(ConsensusState) + + return nil +} + +func TestUpdate(t *testing.T) { + node := NewNode(NewMockValidators(100, 10)) + + node.Commit() + + verifier := NewVerifier(node.last(), node.valset) + + header := node.Commit() + + err := verifier.Validate(header, node.valset) + require.NoError(t, err) +} diff --git a/x/ibc/02-client/tendermint/valset_test.go b/x/ibc/02-client/tendermint/valset_test.go new file mode 100644 index 000000000000..10aa5dc0eae7 --- /dev/null +++ b/x/ibc/02-client/tendermint/valset_test.go @@ -0,0 +1,197 @@ +package tendermint + +import ( + "bytes" + "fmt" + "sort" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + tmtypes "github.com/tendermint/tendermint/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// reimplementing tmtypes.MockPV to make it marshallable +type mockPV struct { + PrivKey crypto.PrivKey +} + +var _ tmtypes.PrivValidator = (*mockPV)(nil) + +func newMockPV() *mockPV { + return &mockPV{ed25519.GenPrivKey()} +} + +func (pv *mockPV) GetAddress() tmtypes.Address { + return pv.PrivKey.PubKey().Address() +} + +func (pv *mockPV) GetPubKey() crypto.PubKey { + return pv.PrivKey.PubKey() +} + +func (pv *mockPV) SignVote(chainID string, vote *tmtypes.Vote) error { + signBytes := vote.SignBytes(chainID) + sig, err := pv.PrivKey.Sign(signBytes) + if err != nil { + return err + } + vote.Signature = sig + return nil +} + +func (pv *mockPV) SignProposal(string, *tmtypes.Proposal) error { + panic("not needed") +} + +// MockValset +type MockValidator struct { + MockPV *mockPV + Power sdk.Dec +} + +func NewMockValidator(power sdk.Dec) MockValidator { + return MockValidator{ + MockPV: newMockPV(), + Power: power, + } +} + +func (val MockValidator) GetOperator() sdk.ValAddress { + return sdk.ValAddress(val.MockPV.GetAddress()) +} + +func (val MockValidator) GetConsAddr() sdk.ConsAddress { + return sdk.GetConsAddress(val.MockPV.GetPubKey()) +} + +func (val MockValidator) GetConsPubKey() crypto.PubKey { + return val.MockPV.GetPubKey() +} + +func (val MockValidator) GetPower() sdk.Dec { + return val.Power +} + +func (val MockValidator) Validator() *tmtypes.Validator { + return tmtypes.NewValidator( + val.GetConsPubKey(), + val.GetPower().RoundInt64(), + ) +} + +type MockValidators []MockValidator + +var _ sort.Interface = MockValidators{} + +func NewMockValidators(num int, power int64) MockValidators { + res := make(MockValidators, num) + for i := range res { + res[i] = NewMockValidator(sdk.NewDec(power)) + } + + // ddd + fmt.Println(333) + for _, val := range res { + fmt.Println(val) + } + + // ddd + return res +} + +func (vals MockValidators) Len() int { + return len(vals) +} + +func (vals MockValidators) Less(i, j int) bool { + return bytes.Compare([]byte(vals[i].GetConsAddr()), []byte(vals[j].GetConsAddr())) == -1 +} + +func (vals MockValidators) Swap(i, j int) { + it := vals[j] + vals[j] = vals[i] + vals[i] = it +} + +func (vals MockValidators) TotalPower() sdk.Dec { + res := sdk.ZeroDec() + for _, val := range vals { + res = res.Add(val.Power) + } + return res +} + +func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { + precommits := make([]*tmtypes.CommitSig, len(vals)) + for i, val := range vals { + precommits[i] = (&tmtypes.Vote{ + BlockID: tmtypes.BlockID{ + Hash: header.Hash(), + }, + ValidatorAddress: val.MockPV.GetAddress(), + ValidatorIndex: i, + Height: header.Height, + Type: tmtypes.PrecommitType, + }).CommitSig() + val.MockPV.SignVote("", (*tmtypes.Vote)(precommits[i])) + } + + return tmtypes.SignedHeader{ + Header: &header, + Commit: &tmtypes.Commit{ + BlockID: tmtypes.BlockID{ + Hash: header.Hash(), + }, + Precommits: precommits, + }, + } +} + +// Mutate valset +func (vals MockValidators) Mutate(majority bool) MockValidators { + var num int + if majority { + num = len(vals) * 2 / 3 + } else { + num = len(vals) * 1 / 6 + } + + res := make(MockValidators, len(vals)) + + for i := 0; i < len(vals)-num; i++ { + res[i] = vals[num:][i] + } + + for i := len(vals) - num; i < len(vals); i++ { + res[i] = NewMockValidator(vals[0].Power) + } + + // ddd + fmt.Println(333) + for _, val := range res { + fmt.Println(val) + } + + // ddd + + return res +} + +func (vals MockValidators) ValidatorSet() *tmtypes.ValidatorSet { + tmvals := make([]*tmtypes.Validator, len(vals)) + + for i, val := range vals { + tmvals[i] = val.Validator() + } + + // ddd + fmt.Println(333444) + for _, val := range tmvals { + fmt.Println(val) + } + + // ddd + return tmtypes.NewValidatorSet(tmvals) +} diff --git a/x/ibc/02-client/types.go b/x/ibc/02-client/types.go index 2ae484853354..2a34855085b9 100644 --- a/x/ibc/02-client/types.go +++ b/x/ibc/02-client/types.go @@ -26,9 +26,6 @@ func Equal(client1, client2 ConsensusState) bool { type Header interface { Kind() Kind GetHeight() uint64 - // Proof() HeaderProof - State() ConsensusState // can be nil - GetRoot() commitment.Root } // XXX: Kind should be enum? From 0e52a48eeb1d90f7b6eb66c456b8c5e4f8088318 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 13 Jun 2019 19:08:13 +0200 Subject: [PATCH 078/378] add test --- x/ibc/02-client/tendermint/types.go | 6 +- x/ibc/02-client/tendermint/types_test.go | 108 +++++++++++++++++++--- x/ibc/02-client/tendermint/valset_test.go | 46 +++------ 3 files changed, 114 insertions(+), 46 deletions(-) diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 1442d91d6c99..8dd3cfca7294 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -3,7 +3,6 @@ package tendermint import ( "bytes" "errors" - "fmt" lerr "github.com/tendermint/tendermint/lite/errors" "github.com/tendermint/tendermint/types" @@ -55,13 +54,11 @@ func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, if cs.Height == uint64(header.Height-1) { nexthash = cs.NextValidatorSet.Hash() if !bytes.Equal(header.ValidatorsHash, nexthash) { - fmt.Println(111) return nil, lerr.ErrUnexpectedValidators(header.ValidatorsHash, nexthash) } } if !bytes.Equal(header.NextValidatorsHash, header.NextValidatorSet.Hash()) { - fmt.Println(header) return nil, lerr.ErrUnexpectedValidators(header.NextValidatorsHash, header.NextValidatorSet.Hash()) } @@ -70,7 +67,7 @@ func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, return nil, err } - err = cs.NextValidatorSet.VerifyCommit(cs.ChainID, header.Commit.BlockID, header.Height, header.Commit) + err = cs.NextValidatorSet.VerifyFutureCommit(header.ValidatorSet, cs.ChainID, header.Commit.BlockID, header.Height, header.Commit) if err != nil { return nil, err } @@ -87,6 +84,7 @@ var _ client.Header = Header{} type Header struct { // XXX: don't take the entire struct types.SignedHeader + ValidatorSet *types.ValidatorSet NextValidatorSet *types.ValidatorSet } diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go index 44dc0fc9aba9..14ca7adad0ea 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/types_test.go @@ -1,11 +1,13 @@ package tendermint import ( + "math/rand" "testing" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + cmn "github.com/tendermint/tendermint/libs/common" dbm "github.com/tendermint/tendermint/libs/db" "github.com/tendermint/tendermint/libs/log" tmtypes "github.com/tendermint/tendermint/types" @@ -14,6 +16,9 @@ import ( "github.com/cosmos/cosmos-sdk/store" stypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) const chainid = "testchain" @@ -33,7 +38,8 @@ func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *c } type node struct { - valset MockValidators + prevvalset MockValidators + valset MockValidators cms sdk.CommitMultiStore store sdk.KVStore @@ -60,7 +66,7 @@ func (node *node) last() tmtypes.SignedHeader { func (node *node) Commit() tmtypes.SignedHeader { valsethash := node.valset.ValidatorSet().Hash() - nextvalset := node.valset.Mutate(false) + nextvalset := node.valset.Mutate() nextvalsethash := nextvalset.ValidatorSet().Hash() commitid := node.cms.Commit() @@ -78,15 +84,13 @@ func (node *node) Commit() tmtypes.SignedHeader { commit := node.valset.Sign(header) + node.prevvalset = node.valset + node.valset = nextvalset node.commits = append(node.commits, commit) return commit } -func (node *node) Set(key, value string) { - node.store.Set(append([]byte{0x00}, []byte(key)...), []byte(value)) -} - type Verifier struct { ConsensusState } @@ -102,10 +106,11 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators) *Verifi } } -func (v *Verifier) Validate(header tmtypes.SignedHeader, nextvalset MockValidators) error { +func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset MockValidators) error { newcs, err := v.ConsensusState.Validate( Header{ SignedHeader: header, + ValidatorSet: valset.ValidatorSet(), NextValidatorSet: nextvalset.ValidatorSet(), }, ) @@ -117,15 +122,96 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, nextvalset MockValidato return nil } -func TestUpdate(t *testing.T) { +func testUpdate(t *testing.T, interval int, ok bool) { node := NewNode(NewMockValidators(100, 10)) node.Commit() verifier := NewVerifier(node.last(), node.valset) - header := node.Commit() + for i := 0; i < 100; i++ { + header := node.Commit() + + if i%interval == 0 { + err := verifier.Validate(header, node.prevvalset, node.valset) + if ok { + require.NoError(t, err) + } else { + require.Error(t, err) + } + } + } +} + +func TestEveryBlockUpdate(t *testing.T) { + testUpdate(t, 1, true) +} + +func TestEvenBlockUpdate(t *testing.T) { + testUpdate(t, 2, true) +} + +func TestSixthBlockUpdate(t *testing.T) { + testUpdate(t, 6, true) +} + +/* +// This should fail, since the amount of mutation is so large +// Commented out because it sometimes success +func TestTenthBlockUpdate(t *testing.T) { + testUpdate(t, 10, false) +} +*/ + +func key(str []byte) []byte { + return append([]byte{0x00}, str...) +} + +func (node *node) query(t *testing.T, k []byte) ([]byte, commitment.Proof) { + qres := node.cms.(stypes.Queryable).Query(abci.RequestQuery{Path: "/ibc/key", Data: key(k), Prove: true}) + require.Equal(t, uint32(0), qres.Code, qres.Log) + proof := merkle.Proof{ + Key: []byte(k), + Proof: qres.Proof, + } + return qres.Value, proof +} + +func (node *node) Set(k, value []byte) { + node.store.Set(key(k), value) +} + +func testProof(t *testing.T) { + node := NewNode(NewMockValidators(100, 10)) + + node.Commit() + + kvps := cmn.KVPairs{} + for h := 0; h < 20; h++ { + for i := 0; i < 100; i++ { + k := make([]byte, 32) + v := make([]byte, 32) + rand.Read(k) + rand.Read(v) + kvps = append(kvps, cmn.KVPair{Key: k, Value: v}) + node.Set(k, v) + } + header := node.Commit() + proofs := []commitment.Proof{} + for _, kvp := range kvps { + v, p := node.query(t, []byte(kvp.Key)) + require.Equal(t, kvp.Value, v) + proofs = append(proofs, p) + } + cstore, err := commitment.NewStore([]byte(header.AppHash), proofs) + require.NoError(t, err) + + for _, kvp := range kvps { + require.True(t, cstore.Prove(kvp.Key, kvp.Value)) + } + } +} - err := verifier.Validate(header, node.valset) - require.NoError(t, err) +func TestProofs(t *testing.T) { + testProof(t) } diff --git a/x/ibc/02-client/tendermint/valset_test.go b/x/ibc/02-client/tendermint/valset_test.go index 10aa5dc0eae7..5649a3533273 100644 --- a/x/ibc/02-client/tendermint/valset_test.go +++ b/x/ibc/02-client/tendermint/valset_test.go @@ -2,7 +2,6 @@ package tendermint import ( "bytes" - "fmt" "sort" "github.com/tendermint/tendermint/crypto" @@ -91,13 +90,8 @@ func NewMockValidators(num int, power int64) MockValidators { res[i] = NewMockValidator(sdk.NewDec(power)) } - // ddd - fmt.Println(333) - for _, val := range res { - fmt.Println(val) - } + sort.Sort(res) - // ddd return res } @@ -124,9 +118,10 @@ func (vals MockValidators) TotalPower() sdk.Dec { } func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { + precommits := make([]*tmtypes.CommitSig, len(vals)) for i, val := range vals { - precommits[i] = (&tmtypes.Vote{ + vote := &tmtypes.Vote{ BlockID: tmtypes.BlockID{ Hash: header.Hash(), }, @@ -134,8 +129,9 @@ func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { ValidatorIndex: i, Height: header.Height, Type: tmtypes.PrecommitType, - }).CommitSig() - val.MockPV.SignVote("", (*tmtypes.Vote)(precommits[i])) + } + val.MockPV.SignVote(chainid, vote) + precommits[i] = vote.CommitSig() } return tmtypes.SignedHeader{ @@ -150,13 +146,8 @@ func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { } // Mutate valset -func (vals MockValidators) Mutate(majority bool) MockValidators { - var num int - if majority { - num = len(vals) * 2 / 3 - } else { - num = len(vals) * 1 / 6 - } +func (vals MockValidators) Mutate() MockValidators { + num := len(vals) / 20 // 5% change each block res := make(MockValidators, len(vals)) @@ -168,15 +159,15 @@ func (vals MockValidators) Mutate(majority bool) MockValidators { res[i] = NewMockValidator(vals[0].Power) } - // ddd - fmt.Println(333) - for _, val := range res { - fmt.Println(val) - } + sort.Sort(res) - // ddd + for i, val := range vals { + if val != res[i] { + return res + } + } - return res + panic("not mutated") } func (vals MockValidators) ValidatorSet() *tmtypes.ValidatorSet { @@ -186,12 +177,5 @@ func (vals MockValidators) ValidatorSet() *tmtypes.ValidatorSet { tmvals[i] = val.Validator() } - // ddd - fmt.Println(333444) - for _, val := range tmvals { - fmt.Println(val) - } - - // ddd return tmtypes.NewValidatorSet(tmvals) } From d234530b8178ea3acdf5b14170ddc679da6213f6 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 19 Jun 2019 13:07:06 +0100 Subject: [PATCH 079/378] in progres --- x/ibc/client/cli/query.go | 216 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 x/ibc/client/cli/query.go diff --git a/x/ibc/client/cli/query.go b/x/ibc/client/cli/query.go new file mode 100644 index 000000000000..ca979151c499 --- /dev/null +++ b/x/ibc/client/cli/query.go @@ -0,0 +1,216 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + tmtypes "github.com/tendermint/tendermint/types" + + "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/02-client/tendermint" + ibc "github.com/cosmos/cosmos-sdk/x/ibc/keeper" +) + +func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ibcQueryCmd := &cobra.Command{ + Use: "ibc", + Short: "IBC query subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + ibcQueryCmd.AddCommand(client.GetCommands( + GetCmdQueryConsensusState(cdc), + GetCmdQueryHeader(cdc), + GetCmdQueryClient(cdc), + GetCmdQueryConnection(cdc), + GetCmdQueryChannel(cdc), + )...) + return ibcQueryCmd +} + +func GetCmdQueryClient(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "client", + Short: "Query stored client", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + keeper := ibc.DummyKeeper() + + var state ibc.ConsensusState + statebz, _, err := query(ctx, keeper.Client.Object(args[0]).Key()) + if err != nil { + return err + } + cdc.MustUnmarshalBinaryBare(statebz, &state) + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + + return nil + }, + } +} + +func GetCmdQueryConsensusState(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "consensus-state", + Short: "Query the latest consensus state of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + node, err := ctx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return err + } + + state := tendermint.ConsensusState{ + ChainID: commit.ChainID, + Height: uint64(commit.Height), + Root: []byte(commit.AppHash), + NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + + return nil + }, + } +} + +func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "header", + Short: "Query the latest header of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + node, err := ctx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return err + } + + nextvalidators, err := node.Validators(&height) + if err != nil { + return err + } + + header := tendermint.Header{ + SignedHeader: commit.SignedHeader, + ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) + + return nil + }, + } +} + +func GetCmdQueryConnection(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "connection", + Short: "Query an existing connection", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + keeper := ibc.DummyKeeper() + + var conn ibc.Connection + connbz, _, err := query(ctx, keeper.Connection.Object(args[0]).Key()) + if err != nil { + return err + } + cdc.MustUnmarshalBinaryBare(connbz, &conn) + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, conn)) + + return nil + }, + } +} + +func GetCmdQueryChannel(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "channel", + Short: "Query an existing channel", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + keeper := ibc.DummyKeeper() + + var conn ibc.Channel + connbz, _, err := query(ctx, keeper.Channel.Object(args[0], args[1]).Key()) + if err != nil { + return err + } + cdc.MustUnmarshalBinaryBare(connbz, &conn) + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, conn)) + + return nil + }, + } +} + +func GetCmdQuerySendSequence(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "send-sequence", + Short: "Query the send sequence of a channel", + Args: cobra.ExactArgs(), + RunE: func(cmd *cobra.Command, args []string) error { + + }, + } +} + +func GetCmdQueryReceiveSequence(cdc *codec.Codec) *cobra.Command { + +} + +func GetCmdQueryPacket(cdc *codec.Codec) *cobra.Command { +} From 8caf0ba2caef5a8edf80427977484eeb4574233a Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 12:20:15 +0200 Subject: [PATCH 080/378] fin rebase --- x/ibc/02-client/tendermint/types.go | 2 +- x/ibc/02-client/tendermint/types_test.go | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 8dd3cfca7294..26a4c35370e6 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -37,7 +37,7 @@ func (cs ConsensusState) update(header Header) ConsensusState { return ConsensusState{ ChainID: cs.ChainID, Height: uint64(header.Height), - Root: header.AppHash, + Root: cs.GetRoot().Update(header.AppHash), NextValidatorSet: header.NextValidatorSet, } } diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go index 14ca7adad0ea..8bde76d10302 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/types_test.go @@ -24,7 +24,7 @@ import ( const chainid = "testchain" func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { - key := sdk.NewKVStoreKey("ibc") + key := sdk.NewKVStoreKey("test") db := dbm.NewMemDB() cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) @@ -91,6 +91,13 @@ func (node *node) Commit() tmtypes.SignedHeader { return commit } +func keyPrefix() [][]byte { + return [][]byte{ + []byte("test"), + []byte{0x00}, + } +} + type Verifier struct { ConsensusState } @@ -100,7 +107,7 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators) *Verifi ConsensusState{ ChainID: chainid, Height: uint64(header.Height), - Root: header.AppHash, + Root: merkle.NewRoot(header.AppHash, keyPrefix()), NextValidatorSet: nextvalset.ValidatorSet(), }, } @@ -168,7 +175,7 @@ func key(str []byte) []byte { } func (node *node) query(t *testing.T, k []byte) ([]byte, commitment.Proof) { - qres := node.cms.(stypes.Queryable).Query(abci.RequestQuery{Path: "/ibc/key", Data: key(k), Prove: true}) + qres := node.cms.(stypes.Queryable).Query(abci.RequestQuery{Path: "/test/key", Data: key(k), Prove: true}) require.Equal(t, uint32(0), qres.Code, qres.Log) proof := merkle.Proof{ Key: []byte(k), @@ -203,7 +210,7 @@ func testProof(t *testing.T) { require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } - cstore, err := commitment.NewStore([]byte(header.AppHash), proofs) + cstore, err := commitment.NewStore(merkle.NewRoot([]byte(header.AppHash), keyPrefix()), proofs) require.NoError(t, err) for _, kvp := range kvps { From 9799769039de7ff1d416932f50563b03c2f6ca5f Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 16:07:00 +0200 Subject: [PATCH 081/378] in progress --- x/ibc/02-client/cli.go | 18 ++++++++++ x/ibc/02-client/manager.go | 34 ++++++++++--------- x/ibc/02-client/tendermint/types_test.go | 42 ++++++++++-------------- 3 files changed, 54 insertions(+), 40 deletions(-) create mode 100644 x/ibc/02-client/cli.go diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go new file mode 100644 index 000000000000..5c245ba0378e --- /dev/null +++ b/x/ibc/02-client/cli.go @@ -0,0 +1,18 @@ +package client + +import () + +// CLIObject stores the key for each object fields +type CLIObject struct { + ID string + ConsensusState []byte + Frozen []byte +} + +func (object Object) CLI() CLIObject { + return CLIObject{ + ID: object.id, + ConsensusState: object.consensusState.Key(), + Frozen: object.frozen.Key(), + } +} diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 196d62e62fdc..a99a4bcc785c 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -55,9 +55,9 @@ func (man Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { */ func (man Manager) object(id string) Object { return Object{ - id: id, - client: man.protocol.Value([]byte(id)), - freeze: state.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), + id: id, + consensusState: man.protocol.Value([]byte(id)), + frozen: state.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), } } @@ -67,7 +67,7 @@ func (man Manager) Create(ctx sdk.Context, cs ConsensusState) (Object, error) { if obj.exists(ctx) { return Object{}, errors.New("Create client on already existing id") } - obj.client.Set(ctx, cs) + obj.consensusState.Set(ctx, cs) return obj, nil } @@ -91,9 +91,9 @@ func (man CounterpartyManager) Query(id string) CounterObject { } type Object struct { - id string - client state.Value // ConsensusState - freeze state.Boolean + id string + consensusState state.Value // ConsensusState + frozen state.Boolean } type CounterObject struct { @@ -101,34 +101,38 @@ type CounterObject struct { client commitment.Value } -func (obj Object) exists(ctx sdk.Context) bool { - return obj.client.Exists(ctx) -} - func (obj Object) ID() string { return obj.id } -func (obj Object) Value(ctx sdk.Context) (res ConsensusState) { - obj.client.Get(ctx, &res) +func (obj Object) ConsensusState(ctx sdk.Context) (res ConsensusState) { + obj.consensusState.Get(ctx, &res) return } +func (obj Object) Frozen(ctx sdk.Context) bool { + return obj.frozen.Get(ctx) +} + func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { return obj.client.Is(ctx, client) } +func (obj Object) exists(ctx sdk.Context) bool { + return obj.consensusState.Exists(ctx) +} + func (obj Object) Update(ctx sdk.Context, header Header) error { if !obj.exists(ctx) { panic("should not update nonexisting client") } - if obj.freeze.Get(ctx) { + if obj.Frozen(ctx) { return errors.New("client is frozen") } var stored ConsensusState - obj.client.GetIfExists(ctx, &stored) + obj.client.Get(ctx, &stored) updated, err := stored.Validate(header) if err != nil { return err diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go index 8bde76d10302..3cb99f52b549 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/types_test.go @@ -91,23 +91,16 @@ func (node *node) Commit() tmtypes.SignedHeader { return commit } -func keyPrefix() [][]byte { - return [][]byte{ - []byte("test"), - []byte{0x00}, - } -} - type Verifier struct { ConsensusState } -func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators) *Verifier { +func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root merkle.Root) *Verifier { return &Verifier{ ConsensusState{ ChainID: chainid, Height: uint64(header.Height), - Root: merkle.NewRoot(header.AppHash, keyPrefix()), + Root: root.Update(header.AppHash), NextValidatorSet: nextvalset.ValidatorSet(), }, } @@ -129,12 +122,18 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset Mock return nil } +func newRoot() merkle.Root { + return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) +} + func testUpdate(t *testing.T, interval int, ok bool) { node := NewNode(NewMockValidators(100, 10)) node.Commit() - verifier := NewVerifier(node.last(), node.valset) + root := newRoot() + + verifier := NewVerifier(node.last(), node.valset, root) for i := 0; i < 100; i++ { header := node.Commit() @@ -170,22 +169,14 @@ func TestTenthBlockUpdate(t *testing.T) { } */ -func key(str []byte) []byte { - return append([]byte{0x00}, str...) -} - -func (node *node) query(t *testing.T, k []byte) ([]byte, commitment.Proof) { - qres := node.cms.(stypes.Queryable).Query(abci.RequestQuery{Path: "/test/key", Data: key(k), Prove: true}) - require.Equal(t, uint32(0), qres.Code, qres.Log) - proof := merkle.Proof{ - Key: []byte(k), - Proof: qres.Proof, - } - return qres.Value, proof +func (node *node) query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { + code, value, proof := root.Query(node.cms, k) + require.Equal(t, uint32(0), code) + return value, proof } func (node *node) Set(k, value []byte) { - node.store.Set(key(k), value) + node.store.Set(newRoot().Key(k), value) } func testProof(t *testing.T) { @@ -205,12 +196,13 @@ func testProof(t *testing.T) { } header := node.Commit() proofs := []commitment.Proof{} + root := newRoot().Update(header.AppHash) for _, kvp := range kvps { - v, p := node.query(t, []byte(kvp.Key)) + v, p := node.query(t, root.(merkle.Root), []byte(kvp.Key)) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } - cstore, err := commitment.NewStore(merkle.NewRoot([]byte(header.AppHash), keyPrefix()), proofs) + cstore, err := commitment.NewStore(root, proofs) require.NoError(t, err) for _, kvp := range kvps { From e67b97b30d66157c380a9106789e744db425d3ca Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 16:15:17 +0200 Subject: [PATCH 082/378] fin rebase --- x/ibc/02-client/manager.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index a99a4bcc785c..e94d14702b72 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -81,8 +81,8 @@ func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { func (man CounterpartyManager) object(id string) CounterObject { return CounterObject{ - id: id, - client: man.protocol.Value([]byte(id)), + id: id, + consensusState: man.protocol.Value([]byte(id)), } } @@ -97,8 +97,8 @@ type Object struct { } type CounterObject struct { - id string - client commitment.Value + id string + consensusState commitment.Value } func (obj Object) ID() string { @@ -115,7 +115,7 @@ func (obj Object) Frozen(ctx sdk.Context) bool { } func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { - return obj.client.Is(ctx, client) + return obj.consensusState.Is(ctx, client) } func (obj Object) exists(ctx sdk.Context) bool { @@ -132,13 +132,13 @@ func (obj Object) Update(ctx sdk.Context, header Header) error { } var stored ConsensusState - obj.client.Get(ctx, &stored) + obj.consensusState.Get(ctx, &stored) updated, err := stored.Validate(header) if err != nil { return err } - obj.client.Set(ctx, updated) + obj.consensusState.Set(ctx, updated) return nil } @@ -148,11 +148,11 @@ func (obj Object) Freeze(ctx sdk.Context) error { panic("should not freeze nonexisting client") } - if obj.freeze.Get(ctx) { + if obj.Frozen(ctx) { return errors.New("client is already frozen") } - obj.freeze.Set(ctx, true) + obj.frozen.Set(ctx, true) return nil } @@ -162,12 +162,12 @@ func (obj Object) Delete(ctx sdk.Context) error { panic("should not delete nonexisting client") } - if !obj.freeze.Get(ctx) { + if !obj.Frozen(ctx) { return errors.New("client is not frozen") } - obj.client.Delete(ctx) - obj.freeze.Delete(ctx) + obj.consensusState.Delete(ctx) + obj.frozen.Delete(ctx) return nil } From fb375d270e4182a66f897e0c2f8e136b0e51c215 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 17:10:21 +0200 Subject: [PATCH 083/378] add CLIObject in progress --- client/context/query.go | 38 ++++++++++++++++++++++++-------------- x/ibc/02-client/cli.go | 24 ++++++++++++++++-------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 87f96aece166..1e52442c6c61 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -31,21 +31,31 @@ func (ctx CLIContext) GetNode() (rpcclient.Client, error) { // Query performs a query to a Tendermint node with the provided path. // It returns the result and height of the query upon success or an error if // the query fails. -func (ctx CLIContext) Query(path string) ([]byte, int64, error) { - return ctx.query(path, nil) +func (ctx CLIContext) Query(path string) (val []byte, height int64, err error) { + val, _, height, err = ctx.query(path, nil) + return } // QueryWithData performs a query to a Tendermint node with the provided path // and a data payload. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryWithData(path string, data []byte) ([]byte, int64, error) { - return ctx.query(path, data) +func (ctx CLIContext) QueryWithData(path string, data []byte) (val []byte, height int64, err error) { + val, _, height, err = ctx.query(path, data) + return } // QueryStore performs a query to a Tendermint node with the provided key and // store name. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, int64, error) { +func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (val []byte, height int64, err error) { + val, _, height, err = ctx.queryStore(key, storeName, "key") + return +} + +// QueryProof performs a query to a Tendermint node with the provided key and +// store name. It returns the result, the proof, and height of the query +// upon success or an error if the query fails. +func (ctx CLIContext) QueryProof(key cmn.HexBytes, storeName string) (val []byte, proof *merkle.Proof, height int64, err error) { return ctx.queryStore(key, storeName, "key") } @@ -53,7 +63,7 @@ func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, in // store name and subspace. It returns key value pair and height of the query // upon success or an error if the query fails. func (ctx CLIContext) QuerySubspace(subspace []byte, storeName string) (res []sdk.KVPair, height int64, err error) { - resRaw, height, err := ctx.queryStore(subspace, storeName, "subspace") + resRaw, _, height, err := ctx.queryStore(subspace, storeName, "subspace") if err != nil { return res, height, err } @@ -75,10 +85,10 @@ func (ctx CLIContext) GetFromName() string { // query performs a query to a Tendermint node with the provided store name // and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) { +func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, proof *merkle.Proof, height int64, err error) { node, err := ctx.GetNode() if err != nil { - return res, height, err + return res, proof, height, err } opts := rpcclient.ABCIQueryOptions{ @@ -88,25 +98,25 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height i result, err := node.ABCIQueryWithOptions(path, key, opts) if err != nil { - return res, height, err + return res, proof, height, err } resp := result.Response if !resp.IsOK() { - return res, height, errors.New(resp.Log) + return res, proof, height, errors.New(resp.Log) } // data from trusted node or subspace query doesn't need verification if ctx.TrustNode || !isQueryStoreWithProof(path) { - return resp.Value, resp.Height, nil + return resp.Value, resp.Proof, resp.Height, nil } err = ctx.verifyProof(path, resp) if err != nil { - return res, height, err + return res, proof, height, err } - return resp.Value, resp.Height, nil + return resp.Value, resp.Proof, resp.Height, nil } // Verify verifies the consensus proof at given height. @@ -165,7 +175,7 @@ func (ctx CLIContext) verifyProof(queryPath string, resp abci.ResponseQuery) err // queryStore performs a query to a Tendermint node with the provided a store // name and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, int64, error) { +func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, *merkle.Proof, int64, error) { path := fmt.Sprintf("/store/%s/%s", storeName, endPath) return ctx.query(path, key) } diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 5c245ba0378e..8767c3032724 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -1,18 +1,26 @@ package client -import () +import ( + "github.com/cosmos/cosmos-sdk/client/context" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) // CLIObject stores the key for each object fields type CLIObject struct { - ID string - ConsensusState []byte - Frozen []byte + ID string + ConsensusStateKey []byte + FrozenKey []byte } -func (object Object) CLI() CLIObject { +func (obj Object) CLI() CLIObject { return CLIObject{ - ID: object.id, - ConsensusState: object.consensusState.Key(), - Frozen: object.frozen.Key(), + ID: obj.id, + ConsensusStateKey: obj.consensusState.Key(), + FrozenKey: obj.frozen.Key(), } } + +func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle..Proof) { + val, proof, _, err := ctx.QueryProof(obj.ConsensusStateKey) +} From 092cd746161d8d9c877081cf80b93769666a2c5f Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 15:19:42 +0200 Subject: [PATCH 084/378] cli in progress --- client/context/query.go | 69 +++++++++++++++++++++++------------------ store/state/types.go | 5 +++ x/ibc/02-client/cli.go | 34 ++++++++++++++++++-- 3 files changed, 76 insertions(+), 32 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 1e52442c6c61..4738808ba4fe 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -31,39 +31,35 @@ func (ctx CLIContext) GetNode() (rpcclient.Client, error) { // Query performs a query to a Tendermint node with the provided path. // It returns the result and height of the query upon success or an error if // the query fails. -func (ctx CLIContext) Query(path string) (val []byte, height int64, err error) { - val, _, height, err = ctx.query(path, nil) - return +func (ctx CLIContext) Query(path string) ([]byte, int64, error) { + return ctx.query(path, nil) } // QueryWithData performs a query to a Tendermint node with the provided path // and a data payload. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryWithData(path string, data []byte) (val []byte, height int64, err error) { - val, _, height, err = ctx.query(path, data) - return +func (ctx CLIContext) QueryWithData(path string, data []byte) ([]byte, int64, error) { + return ctx.query(path, data) } // QueryStore performs a query to a Tendermint node with the provided key and // store name. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (val []byte, height int64, err error) { - val, _, height, err = ctx.queryStore(key, storeName, "key") - return +func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, int64, error) { + return ctx.queryStore(key, storeName, "key") } -// QueryProof performs a query to a Tendermint node with the provided key and -// store name. It returns the result, the proof, and height of the query -// upon success or an error if the query fails. -func (ctx CLIContext) QueryProof(key cmn.HexBytes, storeName string) (val []byte, proof *merkle.Proof, height int64, err error) { - return ctx.queryStore(key, storeName, "key") +// QueryABCI performs a query to a Tendermint node with the provide RequestQuery. +// It returns the ResultQuery obtained from the query. +func (ctx CLIContext) QueryABCI(req abci.RequestQuery) (abci.ResponseQuery, error) { + return ctx.queryABCI(req) } // QuerySubspace performs a query to a Tendermint node with the provided // store name and subspace. It returns key value pair and height of the query // upon success or an error if the query fails. func (ctx CLIContext) QuerySubspace(subspace []byte, storeName string) (res []sdk.KVPair, height int64, err error) { - resRaw, _, height, err := ctx.queryStore(subspace, storeName, "subspace") + resRaw, height, err := ctx.queryStore(subspace, storeName, "subspace") if err != nil { return res, height, err } @@ -82,13 +78,10 @@ func (ctx CLIContext) GetFromName() string { return ctx.FromName } -// query performs a query to a Tendermint node with the provided store name -// and path. It returns the result and height of the query upon success -// or an error if the query fails. -func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, proof *merkle.Proof, height int64, err error) { +func (ctx CLIContext) queryABCI(req abci.RequestQuery) (resp abci.ResponseQuery, err error) { node, err := ctx.GetNode() if err != nil { - return res, proof, height, err + return } opts := rpcclient.ABCIQueryOptions{ @@ -96,27 +89,43 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, proof *m Prove: !ctx.TrustNode, } - result, err := node.ABCIQueryWithOptions(path, key, opts) + result, err := node.ABCIQueryWithOptions(req.Path, req.Data, opts) if err != nil { - return res, proof, height, err + return } - resp := result.Response + resp = result.Response if !resp.IsOK() { - return res, proof, height, errors.New(resp.Log) + err = errors.New(resp.Log) + return } // data from trusted node or subspace query doesn't need verification - if ctx.TrustNode || !isQueryStoreWithProof(path) { - return resp.Value, resp.Proof, resp.Height, nil + if ctx.TrustNode || !isQueryStoreWithProof(req.Path) { + return resp, nil } - err = ctx.verifyProof(path, resp) + err = ctx.verifyProof(req.Path, resp) + if err != nil { + return + } + + return +} + +// query performs a query to a Tendermint node with the provided store name +// and path. It returns the result and height of the query upon success +// or an error if the query fails. +func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) { + resp, err := ctx.queryABCI(abci.RequestQuery{ + Path: path, + Data: key, + }) if err != nil { - return res, proof, height, err + return } - return resp.Value, resp.Proof, resp.Height, nil + return resp.Value, resp.Height, nil } // Verify verifies the consensus proof at given height. @@ -175,7 +184,7 @@ func (ctx CLIContext) verifyProof(queryPath string, resp abci.ResponseQuery) err // queryStore performs a query to a Tendermint node with the provided a store // name and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, *merkle.Proof, int64, error) { +func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, int64, error) { path := fmt.Sprintf("/store/%s/%s", storeName, endPath) return ctx.query(path, key) } diff --git a/store/state/types.go b/store/state/types.go index a8d34d582a82..f5dbb4dc8648 100644 --- a/store/state/types.go +++ b/store/state/types.go @@ -1,8 +1,13 @@ package state import ( + "github.com/tendermint/tendermint/crypto/merkle" + + "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" ) type KVStore = sdk.KVStore type Context = sdk.Context +type CLIContext = context.CLIContext +type Proof = merkle.Proof diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 8767c3032724..f51b882e7725 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -2,6 +2,7 @@ package client import ( "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) @@ -11,6 +12,7 @@ type CLIObject struct { ID string ConsensusStateKey []byte FrozenKey []byte + Cdc *codec.Codec } func (obj Object) CLI() CLIObject { @@ -21,6 +23,34 @@ func (obj Object) CLI() CLIObject { } } -func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle..Proof) { - val, proof, _, err := ctx.QueryProof(obj.ConsensusStateKey) +func query(ctx context.CLIContext, root merkle.Root, key []byte) ([]byte, merkle.Proof, error) { + resp, err := ctx.QueryABCI(root.RequestQuery(key)) + if err != nil { + return nil, merkle.Proof{}, err + } + proof := merkle.Proof{ + Key: key, + Proof: resp.Proof, + } + return resp.Value, proof, nil + +} + +func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle.Proof, err error) { + val, proof, err := query(ctx, root, obj.ConsensusStateKey) + obj.Cdc.MustUnmarshalBinaryBare(val, &res) + return +} + +func (obj CLIObject) Frozen(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { + val, tmproof, _, err := ctx.QueryProof(obj.FrozenKey, "ibc") // TODO + if err != nil { + return + } + proof = merkle.Proof{ + Key: obj.FrozenKey, + Proof: tmproof, + } + obj.Cdc.MustUnmarshalBinaryBare(val, &res) + return } From 9ddab3369f4c4bb365922d5abc9816a976c15b5b Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 15:40:30 +0200 Subject: [PATCH 085/378] add CLIObject --- x/ibc/02-client/cli.go | 31 ++++++++++------------- x/ibc/02-client/tendermint/types_test.go | 2 +- x/ibc/23-commitment/merkle/merkle_test.go | 12 ++++----- x/ibc/23-commitment/merkle/utils.go | 27 ++++++++++++-------- 4 files changed, 38 insertions(+), 34 deletions(-) diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index f51b882e7725..2592e697573c 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -12,45 +12,42 @@ type CLIObject struct { ID string ConsensusStateKey []byte FrozenKey []byte - Cdc *codec.Codec + + Root merkle.Root + Cdc *codec.Codec } -func (obj Object) CLI() CLIObject { +func (obj Object) CLI(root merkle.Root) CLIObject { return CLIObject{ ID: obj.id, ConsensusStateKey: obj.consensusState.Key(), FrozenKey: obj.frozen.Key(), + + Root: root, + Cdc: obj.consensusState.Cdc(), } } -func query(ctx context.CLIContext, root merkle.Root, key []byte) ([]byte, merkle.Proof, error) { - resp, err := ctx.QueryABCI(root.RequestQuery(key)) +func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { + resp, err := ctx.QueryABCI(obj.Root.RequestQuery(key)) if err != nil { - return nil, merkle.Proof{}, err + return merkle.Proof{}, err } proof := merkle.Proof{ Key: key, Proof: resp.Proof, } - return resp.Value, proof, nil + err = obj.Cdc.UnmarshalBinaryBare(resp.Value, ptr) + return proof, err } func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle.Proof, err error) { - val, proof, err := query(ctx, root, obj.ConsensusStateKey) - obj.Cdc.MustUnmarshalBinaryBare(val, &res) + proof, err = obj.query(ctx, obj.ConsensusStateKey, &res) return } func (obj CLIObject) Frozen(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { - val, tmproof, _, err := ctx.QueryProof(obj.FrozenKey, "ibc") // TODO - if err != nil { - return - } - proof = merkle.Proof{ - Key: obj.FrozenKey, - Proof: tmproof, - } - obj.Cdc.MustUnmarshalBinaryBare(val, &res) + proof, err = obj.query(ctx, obj.FrozenKey, &res) return } diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go index 3cb99f52b549..2b89f9be11c8 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/types_test.go @@ -170,7 +170,7 @@ func TestTenthBlockUpdate(t *testing.T) { */ func (node *node) query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { - code, value, proof := root.Query(node.cms, k) + code, value, proof := root.QueryMultiStore(node.cms, k) require.Equal(t, uint32(0), code) return value, proof } diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index f93f64943609..dc7da05dfbc2 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -47,13 +47,13 @@ func TestStore(t *testing.T) { root := commit(cms) - c1, v1, p1 := path.Query(cms, []byte("hello")) + c1, v1, p1 := path.QueryMultiStore(cms, []byte("hello")) require.Equal(t, uint32(0), c1) require.Equal(t, []byte("world"), v1) - c2, v2, p2 := path.Query(cms, []byte("merkle")) + c2, v2, p2 := path.QueryMultiStore(cms, []byte("merkle")) require.Equal(t, uint32(0), c2) require.Equal(t, []byte("tree"), v2) - c3, v3, p3 := path.Query(cms, []byte("block")) + c3, v3, p3 := path.QueryMultiStore(cms, []byte("block")) require.Equal(t, uint32(0), c3) require.Equal(t, []byte("chain"), v3) @@ -70,13 +70,13 @@ func TestStore(t *testing.T) { root = commit(cms) - c1, v1, p1 = path.Query(cms, []byte("12345")) + c1, v1, p1 = path.QueryMultiStore(cms, []byte("12345")) require.Equal(t, uint32(0), c1) require.Equal(t, []byte("67890"), v1) - c2, v2, p2 = path.Query(cms, []byte("qwerty")) + c2, v2, p2 = path.QueryMultiStore(cms, []byte("qwerty")) require.Equal(t, uint32(0), c2) require.Equal(t, []byte("zxcv"), v2) - c3, v3, p3 = path.Query(cms, []byte("hello")) + c3, v3, p3 = path.QueryMultiStore(cms, []byte("hello")) require.Equal(t, uint32(0), c3) require.Equal(t, []byte("dlrow"), v3) diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index d2eabdaed99d..f122b0cd5383 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -7,22 +7,29 @@ import ( ) func (path Path) RequestQuery(key []byte) abci.RequestQuery { - pathstr := "" - for _, inter := range path.KeyPath { - pathstr = pathstr + "/" + string(inter) - } - pathstr = pathstr + "/key" - - data := append(path.KeyPrefix, key...) + req := path.RequestQueryMultiStore(key) + req.Path = "/store" + req.Path + return req +} - return abci.RequestQuery{Path: pathstr, Data: data, Prove: true} +func (path Path) RequestQueryMultiStore(key []byte) abci.RequestQuery { + return abci.RequestQuery{Path: path.Path() + "/key", Data: path.Key(key), Prove: true} } -func (path Path) Query(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { - qres := cms.(types.Queryable).Query(path.RequestQuery(key)) +func (path Path) QueryMultiStore(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { + qres := cms.(types.Queryable).Query(path.RequestQueryMultiStore(key)) return qres.Code, qres.Value, Proof{Key: key, Proof: qres.Proof} } func (path Path) Key(key []byte) []byte { return append(path.KeyPrefix, key...) // XXX: cloneAppend } + +func (path Path) Path() string { + pathstr := "" + for _, inter := range path.KeyPath { + pathstr = pathstr + "/" + string(inter) + } + + return pathstr +} From d1fad94453beb83ae2263be647a3c105f18377cc Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 15:58:28 +0200 Subject: [PATCH 086/378] separate testing from tendermint --- .../tendermint/tests/tendermint_test.go | 58 ++++++++ .../{types_test.go => tests/types.go} | 125 ++++++------------ .../{valset_test.go => tests/valset.go} | 0 3 files changed, 98 insertions(+), 85 deletions(-) create mode 100644 x/ibc/02-client/tendermint/tests/tendermint_test.go rename x/ibc/02-client/tendermint/{types_test.go => tests/types.go} (57%) rename x/ibc/02-client/tendermint/{valset_test.go => tests/valset.go} (100%) diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go new file mode 100644 index 000000000000..29581e718e4c --- /dev/null +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -0,0 +1,58 @@ +package tendermint + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +func newRoot() merkle.Root { + return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) +} + +func testUpdate(t *testing.T, interval int, ok bool) { + node := NewNode(NewMockValidators(100, 10)) + + node.Commit() + + verifier := node.LastStateVerifier(newRoot()) + + for i := 0; i < 100; i++ { + header := node.Commit() + + if i%interval == 0 { + err := verifier.Validate(header, node.PrevValset, node.Valset) + if ok { + require.NoError(t, err) + } else { + require.Error(t, err) + } + } + } +} + +func TestEveryBlockUpdate(t *testing.T) { + testUpdate(t, 1, true) +} + +func TestEvenBlockUpdate(t *testing.T) { + testUpdate(t, 2, true) +} + +func TestSixthBlockUpdate(t *testing.T) { + testUpdate(t, 6, true) +} + +/* +// This should fail, since the amount of mutation is so large +// Commented out because it sometimes success +func TestTenthBlockUpdate(t *testing.T) { + testUpdate(t, 10, false) +} +*/ + +func TestProofs(t *testing.T) { + testProof(t) +} diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/tests/types.go similarity index 57% rename from x/ibc/02-client/tendermint/types_test.go rename to x/ibc/02-client/tendermint/tests/types.go index 2b89f9be11c8..f32cae8efc9d 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -17,6 +17,8 @@ import ( stypes "github.com/cosmos/cosmos-sdk/store/types" 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" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) @@ -37,44 +39,44 @@ func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *c return key, ctx, cms, cdc } -type node struct { - prevvalset MockValidators - valset MockValidators +type Node struct { + PrevValset MockValidators + Valset MockValidators - cms sdk.CommitMultiStore - store sdk.KVStore + Cms sdk.CommitMultiStore + Store sdk.KVStore - commits []tmtypes.SignedHeader + Commits []tmtypes.SignedHeader } -func NewNode(valset MockValidators) *node { +func NewNode(valset MockValidators) *Node { key, ctx, cms, _ := defaultComponents() - return &node{ - valset: valset, - cms: cms, - store: ctx.KVStore(key), - commits: nil, + return &Node{ + Valset: valset, + Cms: cms, + Store: ctx.KVStore(key), + Commits: nil, } } -func (node *node) last() tmtypes.SignedHeader { - if len(node.commits) == 0 { +func (node *Node) Last() tmtypes.SignedHeader { + if len(node.Commits) == 0 { return tmtypes.SignedHeader{} } - return node.commits[len(node.commits)-1] + return node.Commits[len(node.Commits)-1] } -func (node *node) Commit() tmtypes.SignedHeader { - valsethash := node.valset.ValidatorSet().Hash() - nextvalset := node.valset.Mutate() +func (node *Node) Commit() tmtypes.SignedHeader { + valsethash := node.Valset.ValidatorSet().Hash() + nextvalset := node.Valset.Mutate() nextvalsethash := nextvalset.ValidatorSet().Hash() - commitid := node.cms.Commit() + commitid := node.Cms.Commit() header := tmtypes.Header{ ChainID: chainid, - Height: int64(len(node.commits) + 1), + Height: int64(len(node.Commits) + 1), LastBlockID: tmtypes.BlockID{ - Hash: node.last().Header.Hash(), + Hash: node.Last().Header.Hash(), }, ValidatorsHash: valsethash, @@ -82,22 +84,26 @@ func (node *node) Commit() tmtypes.SignedHeader { AppHash: commitid.Hash, } - commit := node.valset.Sign(header) + commit := node.Valset.Sign(header) - node.prevvalset = node.valset - node.valset = nextvalset - node.commits = append(node.commits, commit) + node.PrevValset = node.Valset + node.Valset = nextvalset + node.Commits = append(node.Commits, commit) return commit } +func (node *Node) LastStateVerifier(root merkle.Root) *Verifier { + return NewVerifier(node.Last(), node.Valset, root) +} + type Verifier struct { - ConsensusState + client.ConsensusState } func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root merkle.Root) *Verifier { return &Verifier{ - ConsensusState{ + tendermint.ConsensusState{ ChainID: chainid, Height: uint64(header.Height), Root: root.Update(header.AppHash), @@ -108,7 +114,7 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root me func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset MockValidators) error { newcs, err := v.ConsensusState.Validate( - Header{ + tendermint.Header{ SignedHeader: header, ValidatorSet: valset.ValidatorSet(), NextValidatorSet: nextvalset.ValidatorSet(), @@ -117,66 +123,19 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset Mock if err != nil { return err } - v.ConsensusState = newcs.(ConsensusState) + v.ConsensusState = newcs.(tendermint.ConsensusState) return nil } -func newRoot() merkle.Root { - return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) -} - -func testUpdate(t *testing.T, interval int, ok bool) { - node := NewNode(NewMockValidators(100, 10)) - - node.Commit() - - root := newRoot() - - verifier := NewVerifier(node.last(), node.valset, root) - - for i := 0; i < 100; i++ { - header := node.Commit() - - if i%interval == 0 { - err := verifier.Validate(header, node.prevvalset, node.valset) - if ok { - require.NoError(t, err) - } else { - require.Error(t, err) - } - } - } -} - -func TestEveryBlockUpdate(t *testing.T) { - testUpdate(t, 1, true) -} - -func TestEvenBlockUpdate(t *testing.T) { - testUpdate(t, 2, true) -} - -func TestSixthBlockUpdate(t *testing.T) { - testUpdate(t, 6, true) -} - -/* -// This should fail, since the amount of mutation is so large -// Commented out because it sometimes success -func TestTenthBlockUpdate(t *testing.T) { - testUpdate(t, 10, false) -} -*/ - -func (node *node) query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { - code, value, proof := root.QueryMultiStore(node.cms, k) +func (node *Node) Query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { + code, value, proof := root.QueryMultiStore(node.Cms, k) require.Equal(t, uint32(0), code) return value, proof } -func (node *node) Set(k, value []byte) { - node.store.Set(newRoot().Key(k), value) +func (node *Node) Set(k, value []byte) { + node.Store.Set(newRoot().Key(k), value) } func testProof(t *testing.T) { @@ -198,7 +157,7 @@ func testProof(t *testing.T) { proofs := []commitment.Proof{} root := newRoot().Update(header.AppHash) for _, kvp := range kvps { - v, p := node.query(t, root.(merkle.Root), []byte(kvp.Key)) + v, p := node.Query(t, root.(merkle.Root), []byte(kvp.Key)) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } @@ -210,7 +169,3 @@ func testProof(t *testing.T) { } } } - -func TestProofs(t *testing.T) { - testProof(t) -} diff --git a/x/ibc/02-client/tendermint/valset_test.go b/x/ibc/02-client/tendermint/tests/valset.go similarity index 100% rename from x/ibc/02-client/tendermint/valset_test.go rename to x/ibc/02-client/tendermint/tests/valset.go From 5bc0068d14dffc08fa6b409a94017e383ee073e3 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 16:10:21 +0200 Subject: [PATCH 087/378] add key to node --- x/ibc/02-client/tendermint/tests/types.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index f32cae8efc9d..cc6d73592504 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -44,9 +44,12 @@ type Node struct { Valset MockValidators Cms sdk.CommitMultiStore + Key sdk.StoreKey Store sdk.KVStore Commits []tmtypes.SignedHeader + + Root merkle.Root } func NewNode(valset MockValidators) *Node { @@ -54,6 +57,7 @@ func NewNode(valset MockValidators) *Node { return &Node{ Valset: valset, Cms: cms, + Key: key, Store: ctx.KVStore(key), Commits: nil, } From 10f8e618a86d28901eb4cd11224631be9bae898c Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 18:58:29 +0200 Subject: [PATCH 088/378] add root and storekey to tests/node, add codec --- x/ibc/02-client/codec.go | 10 ++++++++++ x/ibc/02-client/tendermint/codec.go | 11 +++++++++++ x/ibc/02-client/tendermint/tests/types.go | 8 ++++++-- x/ibc/02-client/tendermint/tests/valset.go | 1 + 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 x/ibc/02-client/codec.go create mode 100644 x/ibc/02-client/tendermint/codec.go diff --git a/x/ibc/02-client/codec.go b/x/ibc/02-client/codec.go new file mode 100644 index 000000000000..fa194562e4f1 --- /dev/null +++ b/x/ibc/02-client/codec.go @@ -0,0 +1,10 @@ +package client + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*ConsensusState)(nil), nil) + cdc.RegisterInterface((*Header)(nil), nil) +} diff --git a/x/ibc/02-client/tendermint/codec.go b/x/ibc/02-client/tendermint/codec.go new file mode 100644 index 000000000000..d8308a3e7ec8 --- /dev/null +++ b/x/ibc/02-client/tendermint/codec.go @@ -0,0 +1,11 @@ +package tendermint + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +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/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index cc6d73592504..88a27fd69f51 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -101,6 +101,10 @@ func (node *Node) LastStateVerifier(root merkle.Root) *Verifier { return NewVerifier(node.Last(), node.Valset, root) } +func (node *Node) Context() sdk.Context { + return sdk.NewContext(node.Cms, abci.Header{}, false, log.NewNopLogger()) +} + type Verifier struct { client.ConsensusState } @@ -139,7 +143,7 @@ func (node *Node) Query(t *testing.T, root merkle.Root, k []byte) ([]byte, commi } func (node *Node) Set(k, value []byte) { - node.Store.Set(newRoot().Key(k), value) + node.Store.Set(node.Root.Key(k), value) } func testProof(t *testing.T) { @@ -159,7 +163,7 @@ func testProof(t *testing.T) { } header := node.Commit() proofs := []commitment.Proof{} - root := newRoot().Update(header.AppHash) + root := node.Root.Update(header.AppHash) for _, kvp := range kvps { v, p := node.Query(t, root.(merkle.Root), []byte(kvp.Key)) require.Equal(t, kvp.Value, v) diff --git a/x/ibc/02-client/tendermint/tests/valset.go b/x/ibc/02-client/tendermint/tests/valset.go index 5649a3533273..0d97a5427c9b 100644 --- a/x/ibc/02-client/tendermint/tests/valset.go +++ b/x/ibc/02-client/tendermint/tests/valset.go @@ -84,6 +84,7 @@ type MockValidators []MockValidator var _ sort.Interface = MockValidators{} +// TODO: differenciate power between the vals func NewMockValidators(num int, power int64) MockValidators { res := make(MockValidators, num) for i := range res { From eda101ad754bf0dd9e519227759f869d5d4c7c0a Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 12:22:46 +0200 Subject: [PATCH 089/378] rm cli/query.go --- x/ibc/client/cli/query.go | 216 -------------------------------------- 1 file changed, 216 deletions(-) delete mode 100644 x/ibc/client/cli/query.go diff --git a/x/ibc/client/cli/query.go b/x/ibc/client/cli/query.go deleted file mode 100644 index ca979151c499..000000000000 --- a/x/ibc/client/cli/query.go +++ /dev/null @@ -1,216 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/spf13/cobra" - - tmtypes "github.com/tendermint/tendermint/types" - - "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/02-client/tendermint" - ibc "github.com/cosmos/cosmos-sdk/x/ibc/keeper" -) - -func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - ibcQueryCmd := &cobra.Command{ - Use: "ibc", - Short: "IBC query subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - } - - ibcQueryCmd.AddCommand(client.GetCommands( - GetCmdQueryConsensusState(cdc), - GetCmdQueryHeader(cdc), - GetCmdQueryClient(cdc), - GetCmdQueryConnection(cdc), - GetCmdQueryChannel(cdc), - )...) - return ibcQueryCmd -} - -func GetCmdQueryClient(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "client", - Short: "Query stored client", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - keeper := ibc.DummyKeeper() - - var state ibc.ConsensusState - statebz, _, err := query(ctx, keeper.Client.Object(args[0]).Key()) - if err != nil { - return err - } - cdc.MustUnmarshalBinaryBare(statebz, &state) - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) - - return nil - }, - } -} - -func GetCmdQueryConsensusState(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "consensus-state", - Short: "Query the latest consensus state of the running chain", - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - node, err := ctx.GetNode() - if err != nil { - return err - } - - info, err := node.ABCIInfo() - if err != nil { - return err - } - - height := info.Response.LastBlockHeight - prevheight := height - 1 - - commit, err := node.Commit(&height) - if err != nil { - return err - } - - validators, err := node.Validators(&prevheight) - if err != nil { - return err - } - - state := tendermint.ConsensusState{ - ChainID: commit.ChainID, - Height: uint64(commit.Height), - Root: []byte(commit.AppHash), - NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - } - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) - - return nil - }, - } -} - -func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "header", - Short: "Query the latest header of the running chain", - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - node, err := ctx.GetNode() - if err != nil { - return err - } - - info, err := node.ABCIInfo() - if err != nil { - return err - } - - height := info.Response.LastBlockHeight - prevheight := height - 1 - - commit, err := node.Commit(&height) - if err != nil { - return err - } - - validators, err := node.Validators(&prevheight) - if err != nil { - return err - } - - nextvalidators, err := node.Validators(&height) - if err != nil { - return err - } - - header := tendermint.Header{ - SignedHeader: commit.SignedHeader, - ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), - } - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) - - return nil - }, - } -} - -func GetCmdQueryConnection(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "connection", - Short: "Query an existing connection", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - keeper := ibc.DummyKeeper() - - var conn ibc.Connection - connbz, _, err := query(ctx, keeper.Connection.Object(args[0]).Key()) - if err != nil { - return err - } - cdc.MustUnmarshalBinaryBare(connbz, &conn) - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, conn)) - - return nil - }, - } -} - -func GetCmdQueryChannel(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "channel", - Short: "Query an existing channel", - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - keeper := ibc.DummyKeeper() - - var conn ibc.Channel - connbz, _, err := query(ctx, keeper.Channel.Object(args[0], args[1]).Key()) - if err != nil { - return err - } - cdc.MustUnmarshalBinaryBare(connbz, &conn) - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, conn)) - - return nil - }, - } -} - -func GetCmdQuerySendSequence(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "send-sequence", - Short: "Query the send sequence of a channel", - Args: cobra.ExactArgs(), - RunE: func(cmd *cobra.Command, args []string) error { - - }, - } -} - -func GetCmdQueryReceiveSequence(cdc *codec.Codec) *cobra.Command { - -} - -func GetCmdQueryPacket(cdc *codec.Codec) *cobra.Command { -} From 5c254fbabdcadd7334b7eb873a93c5095b2916f3 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 18:21:20 +0200 Subject: [PATCH 090/378] fix test --- x/ibc/02-client/tendermint/tests/tendermint_test.go | 2 +- x/ibc/02-client/tendermint/tests/types.go | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go index 29581e718e4c..caf866337c47 100644 --- a/x/ibc/02-client/tendermint/tests/tendermint_test.go +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -13,7 +13,7 @@ func newRoot() merkle.Root { } func testUpdate(t *testing.T, interval int, ok bool) { - node := NewNode(NewMockValidators(100, 10)) + node := NewNode(NewMockValidators(100, 10), newRoot()) node.Commit() diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 88a27fd69f51..d0b7b488db39 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -52,7 +52,7 @@ type Node struct { Root merkle.Root } -func NewNode(valset MockValidators) *Node { +func NewNode(valset MockValidators, root merkle.Root) *Node { key, ctx, cms, _ := defaultComponents() return &Node{ Valset: valset, @@ -60,6 +60,7 @@ func NewNode(valset MockValidators) *Node { Key: key, Store: ctx.KVStore(key), Commits: nil, + Root: root, } } @@ -147,7 +148,7 @@ func (node *Node) Set(k, value []byte) { } func testProof(t *testing.T) { - node := NewNode(NewMockValidators(100, 10)) + node := NewNode(NewMockValidators(100, 10), newRoot()) node.Commit() From 6ada539b26634c0ec2add78cfcd6697f137bcc53 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 18:26:23 +0200 Subject: [PATCH 091/378] fix lint --- x/ibc/02-client/tendermint/tests/valset.go | 2 +- x/ibc/02-client/tendermint/types.go | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/valset.go b/x/ibc/02-client/tendermint/tests/valset.go index 0d97a5427c9b..1b5f88aa949b 100644 --- a/x/ibc/02-client/tendermint/tests/valset.go +++ b/x/ibc/02-client/tendermint/tests/valset.go @@ -84,7 +84,7 @@ type MockValidators []MockValidator var _ sort.Interface = MockValidators{} -// TODO: differenciate power between the vals +// TODO: differentiate power between the vals func NewMockValidators(num int, power int64) MockValidators { res := make(MockValidators, num) for i := range res { diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 26a4c35370e6..6bb1bb1f18dd 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -48,11 +48,8 @@ func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, return nil, errors.New("invalid type") } - nextvalset := cs.NextValidatorSet - nexthash := nextvalset.Hash() - if cs.Height == uint64(header.Height-1) { - nexthash = cs.NextValidatorSet.Hash() + nexthash := cs.NextValidatorSet.Hash() if !bytes.Equal(header.ValidatorsHash, nexthash) { return nil, lerr.ErrUnexpectedValidators(header.ValidatorsHash, nexthash) } From f7e1336ca7939330cb9adc2db96f668264390edd Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 19:12:36 +0200 Subject: [PATCH 092/378] fix lint --- .../tendermint/tests/tendermint_test.go | 6 ------ x/ibc/02-client/tendermint/tests/types.go | 16 ++++++++++++---- x/ibc/02-client/tendermint/tests/valset.go | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go index caf866337c47..8a1c764f50f2 100644 --- a/x/ibc/02-client/tendermint/tests/tendermint_test.go +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -4,14 +4,8 @@ import ( "testing" "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func newRoot() merkle.Root { - return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) -} - func testUpdate(t *testing.T, interval int, ok bool) { node := NewNode(NewMockValidators(100, 10), newRoot()) diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index d0b7b488db39..5e0af44f3806 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -1,7 +1,7 @@ package tendermint import ( - "math/rand" + "crypto/rand" "testing" "github.com/stretchr/testify/require" @@ -23,6 +23,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) +// nolint: unused +func newRoot() merkle.Root { + return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) +} + const chainid = "testchain" func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { @@ -147,6 +152,7 @@ func (node *Node) Set(k, value []byte) { node.Store.Set(node.Root.Key(k), value) } +// nolint:deadcode,unused func testProof(t *testing.T) { node := NewNode(NewMockValidators(100, 10), newRoot()) @@ -157,8 +163,10 @@ func testProof(t *testing.T) { for i := 0; i < 100; i++ { k := make([]byte, 32) v := make([]byte, 32) - rand.Read(k) - rand.Read(v) + _, err := rand.Read(k) + require.NoError(t, err) + _, err = rand.Read(v) + require.NoError(t, err) kvps = append(kvps, cmn.KVPair{Key: k, Value: v}) node.Set(k, v) } @@ -166,7 +174,7 @@ func testProof(t *testing.T) { proofs := []commitment.Proof{} root := node.Root.Update(header.AppHash) for _, kvp := range kvps { - v, p := node.Query(t, root.(merkle.Root), []byte(kvp.Key)) + v, p := node.Query(t, root.(merkle.Root), kvp.Key) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } diff --git a/x/ibc/02-client/tendermint/tests/valset.go b/x/ibc/02-client/tendermint/tests/valset.go index 1b5f88aa949b..30bd194682c8 100644 --- a/x/ibc/02-client/tendermint/tests/valset.go +++ b/x/ibc/02-client/tendermint/tests/valset.go @@ -131,7 +131,7 @@ func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { Height: header.Height, Type: tmtypes.PrecommitType, } - val.MockPV.SignVote(chainid, vote) + _ = val.MockPV.SignVote(chainid, vote) precommits[i] = vote.CommitSig() } From 7bd4ba556ea8754c09c70dfb985cbfa98f9046eb Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 9 Jul 2019 23:53:46 +0900 Subject: [PATCH 093/378] add handler/msgs/client --- store/state/base.go | 12 +- x/ibc/02-client/cli.go | 9 +- x/ibc/02-client/client/cli/query.go | 159 ++++++++++++++++++++++++ x/ibc/02-client/client/cli/tx.go | 144 +++++++++++++++++++++ x/ibc/02-client/client/utils/receive.go | 94 ++++++++++++++ x/ibc/02-client/codec.go | 9 ++ x/ibc/02-client/handler.go | 29 +++++ x/ibc/02-client/manager.go | 15 +-- x/ibc/02-client/msgs.go | 69 ++++++++++ x/ibc/02-client/tendermint/codec.go | 7 +- 10 files changed, 526 insertions(+), 21 deletions(-) create mode 100644 x/ibc/02-client/client/cli/query.go create mode 100644 x/ibc/02-client/client/cli/tx.go create mode 100644 x/ibc/02-client/client/utils/receive.go create mode 100644 x/ibc/02-client/handler.go create mode 100644 x/ibc/02-client/msgs.go diff --git a/store/state/base.go b/store/state/base.go index f163c18b98a0..a6f429053248 100644 --- a/store/state/base.go +++ b/store/state/base.go @@ -15,13 +15,19 @@ type Base struct { } func EmptyBase() Base { - return NewBase(nil, nil) + return NewBase(nil, nil, nil) } -func NewBase(cdc *codec.Codec, key sdk.StoreKey) Base { +func NewBase(cdc *codec.Codec, key sdk.StoreKey, rootkey []byte) Base { + if len(rootkey) == 0 { + return Base{ + cdc: cdc, + storefn: func(ctx Context) KVStore { return ctx.KVStore(key) }, + } + } return Base{ cdc: cdc, - storefn: func(ctx Context) KVStore { return ctx.KVStore(key) }, + storefn: func(ctx Context) KVStore { return prefix.NewStore(ctx.KVStore(key), rootkey) }, } } diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 2592e697573c..45f2c9672a4d 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -17,9 +17,10 @@ type CLIObject struct { Cdc *codec.Codec } -func (obj Object) CLI(root merkle.Root) CLIObject { +func (man Manager) CLIObject(root merkle.Root, id string) CLIObject { + obj := man.object(id) return CLIObject{ - ID: obj.id, + ID: id, ConsensusStateKey: obj.consensusState.Key(), FrozenKey: obj.frozen.Key(), @@ -42,12 +43,12 @@ func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) } -func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle.Proof, err error) { +func (obj CLIObject) ConsensusState(ctx context.CLIContext) (res ConsensusState, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.ConsensusStateKey, &res) return } -func (obj CLIObject) Frozen(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { +func (obj CLIObject) Frozen(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.FrozenKey, &res) return } diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go new file mode 100644 index 000000000000..2506ed8dd905 --- /dev/null +++ b/x/ibc/02-client/client/cli/query.go @@ -0,0 +1,159 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + tmtypes "github.com/tendermint/tendermint/types" + + 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" + + "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" +) + +func defaultRoot(storeKey string, root []byte) merkle.Root { + return merkle.NewRoot(root, [][]byte{[]byte(storeKey)}, []byte("protocol")) +} + +func defaultBase(cdc *codec.Codec) (state.Base, state.Base) { + protocol := state.NewBase(cdc, nil, []byte("protocol")) + free := state.NewBase(cdc, nil, []byte("free")) + return protocol, free +} + +func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ibcQueryCmd := &cobra.Command{ + Use: "ibc", + Short: "IBC query subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + ibcQueryCmd.AddCommand(cli.GetCommands( + GetCmdQueryConsensusState(storeKey, cdc), + GetCmdQueryHeader(cdc), + GetCmdQueryClient(storeKey, cdc), + )...) + return ibcQueryCmd +} + +func GetCmdQueryClient(storeKey string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "client", + Short: "Query stored client", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + man := client.NewManager(defaultBase(cdc)) + root := defaultRoot(storeKey, nil) + id := args[0] + + state, _, err := man.CLIObject(root, id).ConsensusState(ctx) + if err != nil { + return err + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + + return nil + }, + } +} + +func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "consensus-state", + Short: "Query the latest consensus state of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + node, err := ctx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return err + } + + state := tendermint.ConsensusState{ + ChainID: commit.ChainID, + Height: uint64(commit.Height), + Root: defaultRoot(storeKey, []byte(commit.AppHash)), + NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + + return nil + }, + } +} + +func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "header", + Short: "Query the latest header of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + node, err := ctx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return err + } + + nextvalidators, err := node.Validators(&height) + if err != nil { + return err + } + + header := tendermint.Header{ + SignedHeader: commit.SignedHeader, + ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) + + return nil + }, + } +} diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go new file mode 100644 index 000000000000..e654d76e7c3d --- /dev/null +++ b/x/ibc/02-client/client/cli/tx.go @@ -0,0 +1,144 @@ +package cli + +import ( + "errors" + "io/ioutil" + // "os" + + "github.com/spf13/cobra" + + // "github.com/tendermint/tendermint/libs/log" + rpcclient "github.com/tendermint/tendermint/rpc/client" + + 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/x/auth/client/utils" + // "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/ibc/02-client" + // "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +const ( + FlagStatePath = "state" + FlagClientID = "client-id" + FlagConnectionID = "connection-id" + FlagChannelID = "channel-id" + FlagCounterpartyID = "counterparty-id" + FlagCounterpartyClientID = "counterparty-client-id" + FlagSourceNode = "source-node" +) + +func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ibcTxCmd := &cobra.Command{ + Use: "ibc", + Short: "IBC transaction subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + ibcTxCmd.AddCommand(cli.PostCommands( + GetCmdCreateClient(cdc), + GetCmdUpdateClient(cdc), + )...) + + return ibcTxCmd +} + +func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "create-client", + Short: "create new client with a consensus state", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext(). + WithCodec(cdc) + + contents, err := ioutil.ReadFile(args[1]) + if err != nil { + return err + } + + var state client.ConsensusState + if err := cdc.UnmarshalJSON(contents, &state); err != nil { + return err + } + + msg := client.MsgCreateClient{ + ClientID: args[0], + ConsensusState: state, + Signer: cliCtx.GetFromAddress(), + } + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + + return cmd +} + +func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "update-client", + Short: "update existing client with a header", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext(). + WithCodec(cdc) + + contents, err := ioutil.ReadFile(args[1]) + if err != nil { + return err + } + + var header client.Header + if err := cdc.UnmarshalJSON(contents, &header); err != nil { + return err + } + + msg := client.MsgUpdateClient{ + ClientID: args[0], + Header: header, + Signer: cliCtx.GetFromAddress(), + } + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + + return cmd +} + +// Copied from client/context/query.go +func query(ctx context.CLIContext, key []byte) ([]byte, merkle.Proof, error) { + node, err := ctx.GetNode() + if err != nil { + return nil, merkle.Proof{}, err + } + + opts := rpcclient.ABCIQueryOptions{ + Height: ctx.Height, + Prove: true, + } + + result, err := node.ABCIQueryWithOptions("/store/ibc/key", key, opts) + if err != nil { + return nil, merkle.Proof{}, err + } + + resp := result.Response + if !resp.IsOK() { + return nil, merkle.Proof{}, errors.New(resp.Log) + } + + return resp.Value, merkle.Proof{ + Key: key, + Proof: resp.Proof, + }, nil +} diff --git a/x/ibc/02-client/client/utils/receive.go b/x/ibc/02-client/client/utils/receive.go new file mode 100644 index 000000000000..7a8df21189fb --- /dev/null +++ b/x/ibc/02-client/client/utils/receive.go @@ -0,0 +1,94 @@ +package cli + +import ( + "errors" + + "github.com/spf13/viper" + + rpcclient "github.com/tendermint/tendermint/rpc/client" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/store/state" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" + ibc "github.com/cosmos/cosmos-sdk/x/ibc/keeper" +) + +const ( + FlagStatePath = "state" + FlagClientID = "client-id" + FlagConnectionID = "connection-id" + FlagChannelID = "channel-id" + FlagCounterpartyID = "counterparty-id" + FlagCounterpartyClientID = "counterparty-client-id" + FlagSourceNode = "source-node" +) + +// Copied from client/context/query.go +func query(ctx context.CLIContext, key []byte) ([]byte, merkle.Proof, error) { + node, err := ctx.GetNode() + if err != nil { + return nil, merkle.Proof{}, err + } + + opts := rpcclient.ABCIQueryOptions{ + Height: ctx.Height, + Prove: true, + } + + result, err := node.ABCIQueryWithOptions("/store/ibc/key", key, opts) + if err != nil { + return nil, merkle.Proof{}, err + } + + resp := result.Response + if !resp.IsOK() { + return nil, merkle.Proof{}, errors.New(resp.Log) + } + + return resp.Value, merkle.Proof{ + Key: key, + Proof: resp.Proof, + }, nil +} + +func GetRelayPacket(cliCtxSource, cliCtx context.CLIContext) (ibc.Packet, ibc.Proof, error) { + keeper := ibc.DummyKeeper() + cdc := cliCtx.Codec + + connid := viper.GetString(FlagConnectionID) + chanid := viper.GetString(FlagChannelID) + + obj := keeper.Channel.Object(connid, chanid) + + seqbz, _, err := query(cliCtx, obj.Seqrecv.Key()) + if err != nil { + return nil, nil, err + } + seq, err := state.DecodeInt(seqbz, state.Dec) + if err != nil { + return nil, nil, err + } + + sentbz, _, err := query(cliCtxSource, obj.Seqsend.Key()) + if err != nil { + return nil, nil, err + } + sent, err := state.DecodeInt(sentbz, state.Dec) + if err != nil { + return nil, nil, err + } + + if seq == sent { + return nil, nil, errors.New("no packet detected") + } + + var packet ibc.Packet + packetbz, proof, err := query(cliCtxSource, obj.Packets.Value(seq).Key()) + if err != nil { + return nil, nil, err + } + cdc.MustUnmarshalBinaryBare(packetbz, &packet) + + return packet, proof, nil +} diff --git a/x/ibc/02-client/codec.go b/x/ibc/02-client/codec.go index fa194562e4f1..ece7e750dc98 100644 --- a/x/ibc/02-client/codec.go +++ b/x/ibc/02-client/codec.go @@ -4,7 +4,16 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) +var MsgCdc = codec.New() + +func init() { + RegisterCodec(MsgCdc) +} + func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*ConsensusState)(nil), nil) cdc.RegisterInterface((*Header)(nil), nil) + + cdc.RegisterConcrete(MsgCreateClient{}, "ibc/client/MsgCreateClient", nil) + cdc.RegisterConcrete(MsgUpdateClient{}, "ibc/client/MsgUpdateClient", nil) } diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go new file mode 100644 index 000000000000..dfab0725b8c4 --- /dev/null +++ b/x/ibc/02-client/handler.go @@ -0,0 +1,29 @@ +package client + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func HandleMsgCreateClient(ctx sdk.Context, msg MsgCreateClient, man Manager) sdk.Result { + _, err := man.Create(ctx, msg.ClientID, msg.ConsensusState) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(100), err.Error()).Result() + } + + // TODO: events + return sdk.Result{} +} + +func HandleMsgUpdateClient(ctx sdk.Context, msg MsgUpdateClient, man Manager) sdk.Result { + obj, err := man.Query(ctx, msg.ClientID) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(200), err.Error()).Result() + } + err = obj.Update(ctx, msg.Header) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(300), err.Error()).Result() + } + + // TODO: events + return sdk.Result{} +} diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index e94d14702b72..67d43a4325eb 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -2,7 +2,6 @@ package client import ( "errors" - "strconv" "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" @@ -12,25 +11,16 @@ import ( // XXX: implement spec: ClientState.verifiedRoots -type IDGenerator func(sdk.Context /*Header,*/, state.Value) string - -func IntegerIDGenerator(ctx sdk.Context, v state.Value) string { - id := state.NewInteger(v, state.Dec).Incr(ctx) - return strconv.FormatUint(id, 10) -} - type Manager struct { protocol state.Mapping idval state.Value - idgen IDGenerator } -func NewManager(protocol, free state.Base, idgen IDGenerator) Manager { +func NewManager(protocol, free state.Base) Manager { return Manager{ protocol: state.NewMapping(protocol, []byte("/client")), idval: state.NewValue(free, []byte("/client/id")), - idgen: idgen, } } @@ -61,8 +51,7 @@ func (man Manager) object(id string) Object { } } -func (man Manager) Create(ctx sdk.Context, cs ConsensusState) (Object, error) { - id := man.idgen(ctx, man.idval) +func (man Manager) Create(ctx sdk.Context, id string, cs ConsensusState) (Object, error) { obj := man.object(id) if obj.exists(ctx) { return Object{}, errors.New("Create client on already existing id") diff --git a/x/ibc/02-client/msgs.go b/x/ibc/02-client/msgs.go new file mode 100644 index 000000000000..7f515c388c8f --- /dev/null +++ b/x/ibc/02-client/msgs.go @@ -0,0 +1,69 @@ +package client + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type MsgCreateClient struct { + ClientID string + ConsensusState ConsensusState + Signer sdk.AccAddress +} + +var _ sdk.Msg = MsgCreateClient{} + +func (msg MsgCreateClient) Route() string { + return "ibc" +} + +func (msg MsgCreateClient) Type() string { + return "create-client" +} + +func (msg MsgCreateClient) ValidateBasic() sdk.Error { + if msg.Signer.Empty() { + return sdk.ErrInvalidAddress("empty address") + } + return nil +} + +func (msg MsgCreateClient) GetSignBytes() []byte { + bz := MsgCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg MsgCreateClient) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +type MsgUpdateClient struct { + ClientID string + Header Header + Signer sdk.AccAddress +} + +var _ sdk.Msg = MsgUpdateClient{} + +func (msg MsgUpdateClient) Route() string { + return "ibc" +} + +func (msg MsgUpdateClient) Type() string { + return "update-client" +} + +func (msg MsgUpdateClient) ValidateBasic() sdk.Error { + if msg.Signer.Empty() { + return sdk.ErrInvalidAddress("empty address") + } + return nil +} + +func (msg MsgUpdateClient) GetSignBytes() []byte { + bz := MsgCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg MsgUpdateClient) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} diff --git a/x/ibc/02-client/tendermint/codec.go b/x/ibc/02-client/tendermint/codec.go index d8308a3e7ec8..eca3b38917fa 100644 --- a/x/ibc/02-client/tendermint/codec.go +++ b/x/ibc/02-client/tendermint/codec.go @@ -2,10 +2,15 @@ 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) - } From f750ac47da1e6e5de46a149e4ce9b3ffeefe278f Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 9 Jul 2019 23:54:32 +0900 Subject: [PATCH 094/378] rm relay --- x/ibc/02-client/client/utils/receive.go | 94 ------------------------- 1 file changed, 94 deletions(-) delete mode 100644 x/ibc/02-client/client/utils/receive.go diff --git a/x/ibc/02-client/client/utils/receive.go b/x/ibc/02-client/client/utils/receive.go deleted file mode 100644 index 7a8df21189fb..000000000000 --- a/x/ibc/02-client/client/utils/receive.go +++ /dev/null @@ -1,94 +0,0 @@ -package cli - -import ( - "errors" - - "github.com/spf13/viper" - - rpcclient "github.com/tendermint/tendermint/rpc/client" - - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/store/state" - - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" - ibc "github.com/cosmos/cosmos-sdk/x/ibc/keeper" -) - -const ( - FlagStatePath = "state" - FlagClientID = "client-id" - FlagConnectionID = "connection-id" - FlagChannelID = "channel-id" - FlagCounterpartyID = "counterparty-id" - FlagCounterpartyClientID = "counterparty-client-id" - FlagSourceNode = "source-node" -) - -// Copied from client/context/query.go -func query(ctx context.CLIContext, key []byte) ([]byte, merkle.Proof, error) { - node, err := ctx.GetNode() - if err != nil { - return nil, merkle.Proof{}, err - } - - opts := rpcclient.ABCIQueryOptions{ - Height: ctx.Height, - Prove: true, - } - - result, err := node.ABCIQueryWithOptions("/store/ibc/key", key, opts) - if err != nil { - return nil, merkle.Proof{}, err - } - - resp := result.Response - if !resp.IsOK() { - return nil, merkle.Proof{}, errors.New(resp.Log) - } - - return resp.Value, merkle.Proof{ - Key: key, - Proof: resp.Proof, - }, nil -} - -func GetRelayPacket(cliCtxSource, cliCtx context.CLIContext) (ibc.Packet, ibc.Proof, error) { - keeper := ibc.DummyKeeper() - cdc := cliCtx.Codec - - connid := viper.GetString(FlagConnectionID) - chanid := viper.GetString(FlagChannelID) - - obj := keeper.Channel.Object(connid, chanid) - - seqbz, _, err := query(cliCtx, obj.Seqrecv.Key()) - if err != nil { - return nil, nil, err - } - seq, err := state.DecodeInt(seqbz, state.Dec) - if err != nil { - return nil, nil, err - } - - sentbz, _, err := query(cliCtxSource, obj.Seqsend.Key()) - if err != nil { - return nil, nil, err - } - sent, err := state.DecodeInt(sentbz, state.Dec) - if err != nil { - return nil, nil, err - } - - if seq == sent { - return nil, nil, errors.New("no packet detected") - } - - var packet ibc.Packet - packetbz, proof, err := query(cliCtxSource, obj.Packets.Value(seq).Key()) - if err != nil { - return nil, nil, err - } - cdc.MustUnmarshalBinaryBare(packetbz, &packet) - - return packet, proof, nil -} From a3e2f9c707cad15373ff68bdde2667888742db96 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 12 Jul 2019 01:33:18 +0900 Subject: [PATCH 095/378] finalize rebase on 23 root/path sep --- x/ibc/02-client/cli.go | 8 +++--- .../tendermint/tests/tendermint_test.go | 8 +++--- x/ibc/02-client/tendermint/tests/types.go | 26 +++++++++---------- x/ibc/02-client/tendermint/types.go | 3 ++- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 45f2c9672a4d..382b1d2d4aea 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -13,24 +13,24 @@ type CLIObject struct { ConsensusStateKey []byte FrozenKey []byte - Root merkle.Root + Path merkle.Path Cdc *codec.Codec } -func (man Manager) CLIObject(root merkle.Root, id string) CLIObject { +func (man Manager) CLIObject(path merkle.Path, id string) CLIObject { obj := man.object(id) return CLIObject{ ID: id, ConsensusStateKey: obj.consensusState.Key(), FrozenKey: obj.frozen.Key(), - Root: root, + Path: path, Cdc: obj.consensusState.Cdc(), } } func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { - resp, err := ctx.QueryABCI(obj.Root.RequestQuery(key)) + resp, err := ctx.QueryABCI(obj.Path.RequestQuery(key)) if err != nil { return merkle.Proof{}, err } diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go index 8a1c764f50f2..61a0944fbaa0 100644 --- a/x/ibc/02-client/tendermint/tests/tendermint_test.go +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -4,14 +4,16 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) func testUpdate(t *testing.T, interval int, ok bool) { - node := NewNode(NewMockValidators(100, 10), newRoot()) + node := NewNode(NewMockValidators(100, 10), newPath()) - node.Commit() + header := node.Commit() - verifier := node.LastStateVerifier(newRoot()) + verifier := node.LastStateVerifier(merkle.NewRoot(header.AppHash)) for i := 0; i < 100; i++ { header := node.Commit() diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 5e0af44f3806..f9fd9fc9f0c8 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -24,8 +24,8 @@ import ( ) // nolint: unused -func newRoot() merkle.Root { - return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) +func newPath() merkle.Path { + return merkle.NewPath([][]byte{[]byte("test")}, []byte{0x12, 0x34}) } const chainid = "testchain" @@ -54,10 +54,10 @@ type Node struct { Commits []tmtypes.SignedHeader - Root merkle.Root + Path merkle.Path } -func NewNode(valset MockValidators, root merkle.Root) *Node { +func NewNode(valset MockValidators, path merkle.Path) *Node { key, ctx, cms, _ := defaultComponents() return &Node{ Valset: valset, @@ -65,7 +65,7 @@ func NewNode(valset MockValidators, root merkle.Root) *Node { Key: key, Store: ctx.KVStore(key), Commits: nil, - Root: root, + Path: path, } } @@ -120,7 +120,7 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root me tendermint.ConsensusState{ ChainID: chainid, Height: uint64(header.Height), - Root: root.Update(header.AppHash), + Root: merkle.NewRoot(header.AppHash), NextValidatorSet: nextvalset.ValidatorSet(), }, } @@ -142,19 +142,19 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset Mock return nil } -func (node *Node) Query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { - code, value, proof := root.QueryMultiStore(node.Cms, k) +func (node *Node) Query(t *testing.T, path merkle.Path, k []byte) ([]byte, commitment.Proof) { + code, value, proof := path.QueryMultiStore(node.Cms, k) require.Equal(t, uint32(0), code) return value, proof } func (node *Node) Set(k, value []byte) { - node.Store.Set(node.Root.Key(k), value) + node.Store.Set(node.Path.Key(k), value) } // nolint:deadcode,unused func testProof(t *testing.T) { - node := NewNode(NewMockValidators(100, 10), newRoot()) + node := NewNode(NewMockValidators(100, 10), newPath()) node.Commit() @@ -172,13 +172,13 @@ func testProof(t *testing.T) { } header := node.Commit() proofs := []commitment.Proof{} - root := node.Root.Update(header.AppHash) + root := merkle.NewRoot(header.AppHash) for _, kvp := range kvps { - v, p := node.Query(t, root.(merkle.Root), kvp.Key) + v, p := node.Query(t, node.Path, kvp.Key) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } - cstore, err := commitment.NewStore(root, proofs) + cstore, err := commitment.NewStore(root, node.Path, proofs) require.NoError(t, err) for _, kvp := range kvps { diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 6bb1bb1f18dd..ca5da8c1cae5 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) var _ client.ConsensusState = ConsensusState{} @@ -37,7 +38,7 @@ func (cs ConsensusState) update(header Header) ConsensusState { return ConsensusState{ ChainID: cs.ChainID, Height: uint64(header.Height), - Root: cs.GetRoot().Update(header.AppHash), + Root: merkle.NewRoot(header.AppHash), NextValidatorSet: header.NextValidatorSet, } } From 56712b1fb32ee5744b52aae4182652d784e9f3dc Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 12 Jul 2019 01:35:54 +0900 Subject: [PATCH 096/378] fix lint, fix syntax --- x/ibc/02-client/client/cli/query.go | 10 +++++----- x/ibc/02-client/client/cli/tx.go | 31 ----------------------------- 2 files changed, 5 insertions(+), 36 deletions(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 2506ed8dd905..9de2231427bb 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -17,8 +17,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func defaultRoot(storeKey string, root []byte) merkle.Root { - return merkle.NewRoot(root, [][]byte{[]byte(storeKey)}, []byte("protocol")) +func defaultPath(storeKey string) merkle.Path { + return merkle.NewPath([][]byte{[]byte(storeKey)}, []byte("protocol")) } func defaultBase(cdc *codec.Codec) (state.Base, state.Base) { @@ -51,10 +51,10 @@ func GetCmdQueryClient(storeKey string, cdc *codec.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) man := client.NewManager(defaultBase(cdc)) - root := defaultRoot(storeKey, nil) + path := defaultPath(storeKey) id := args[0] - state, _, err := man.CLIObject(root, id).ConsensusState(ctx) + state, _, err := man.CLIObject(path, id).ConsensusState(ctx) if err != nil { return err } @@ -99,7 +99,7 @@ func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command state := tendermint.ConsensusState{ ChainID: commit.ChainID, Height: uint64(commit.Height), - Root: defaultRoot(storeKey, []byte(commit.AppHash)), + Root: merkle.NewRoot(commit.AppHash), NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), } diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index e654d76e7c3d..1b18dbe34783 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -1,14 +1,12 @@ package cli import ( - "errors" "io/ioutil" // "os" "github.com/spf13/cobra" // "github.com/tendermint/tendermint/libs/log" - rpcclient "github.com/tendermint/tendermint/rpc/client" cli "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" @@ -20,7 +18,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client" // "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) const ( @@ -114,31 +111,3 @@ func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { return cmd } - -// Copied from client/context/query.go -func query(ctx context.CLIContext, key []byte) ([]byte, merkle.Proof, error) { - node, err := ctx.GetNode() - if err != nil { - return nil, merkle.Proof{}, err - } - - opts := rpcclient.ABCIQueryOptions{ - Height: ctx.Height, - Prove: true, - } - - result, err := node.ABCIQueryWithOptions("/store/ibc/key", key, opts) - if err != nil { - return nil, merkle.Proof{}, err - } - - resp := result.Response - if !resp.IsOK() { - return nil, merkle.Proof{}, errors.New(resp.Log) - } - - return resp.Value, merkle.Proof{ - Key: key, - Proof: resp.Proof, - }, nil -} From ea91bb8c4ce4d5b19498d8766c9b62dd5804b123 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 14 Jul 2019 02:32:36 +0900 Subject: [PATCH 097/378] finalize rebase on merkle root/path separation --- x/ibc/02-client/tendermint/tests/tendermint_test.go | 4 +++- x/ibc/02-client/tendermint/tests/types.go | 13 ++++--------- x/ibc/03-connection/handshake.go | 2 +- x/ibc/03-connection/tests/types.go | 6 +++--- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go index 707d3aa252d2..df63032b3986 100644 --- a/x/ibc/02-client/tendermint/tests/tendermint_test.go +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -4,10 +4,12 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) func testUpdate(t *testing.T, interval int, ok bool) { - node := NewNode(NewMockValidators(100, 10), newPath()) + node := NewNode(NewMockValidators(100, 10), merkle.NewPath([][]byte{[]byte("f8wib")}, []byte{0x98, 0x78})) _ = node.Commit() diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index edd8497ce524..dd45fa0fe374 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -23,15 +23,10 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -// nolint: unused -func newPath() merkle.Path { - return merkle.NewPath([][]byte{[]byte("test")}, []byte{0x12, 0x34}) -} - const chainid = "testchain" -func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { - key := sdk.NewKVStoreKey("test") +func defaultComponents(storename string) (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { + key := sdk.NewKVStoreKey(storename) db := dbm.NewMemDB() cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) @@ -58,7 +53,7 @@ type Node struct { } func NewNode(valset MockValidators, path merkle.Path) *Node { - key, ctx, cms, _ := defaultComponents() + key, ctx, cms, _ := defaultComponents(string(path.KeyPath[0])) return &Node{ Valset: valset, Cms: cms, @@ -156,7 +151,7 @@ func (node *Node) Set(k, value []byte) { // nolint:deadcode,unused func testProof(t *testing.T) { - node := NewNode(NewMockValidators(100, 10), newPath()) + node := NewNode(NewMockValidators(100, 10), merkle.NewPath([][]byte{[]byte("1")}, []byte{0x00, 0x01})) node.Commit() diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index 83dde7db5882..b285c90747c3 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -233,7 +233,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, } if !obj.counterparty.connection.Is(ctx, Connection{ - Client: obj.Connection(ctx).Client, + Client: obj.CounterpartyClient(ctx), Counterparty: obj.ID(), }) { err = errors.New("wrong counterparty") diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index fcb359b3e82e..9464b031143b 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -30,8 +30,8 @@ type Node struct { func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { res := &Node{ - Name: "self", // hard coded, doesnt matter - Node: tendermint.NewNode(self, merkle.NewPath(nil, []byte("protocol"))), // TODO: test with key prefix + Name: "self", // hard coded, doesnt matter + Node: tendermint.NewNode(self, merkle.NewPath([][]byte{[]byte("teststoreself")}, []byte("protocol"))), // TODO: test with key prefix State: connection.Idle, Cdc: cdc, @@ -39,7 +39,7 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { res.Counterparty = &Node{ Name: "counterparty", - Node: tendermint.NewNode(counter, merkle.NewPath(nil, []byte("protocol"))), + Node: tendermint.NewNode(counter, merkle.NewPath([][]byte{[]byte("teststorecounterparty")}, []byte("protocol"))), Counterparty: res, State: connection.Idle, From 812d3abf84ac4d1dbf484ddf82da7a8b5041ecc4 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 14 Jul 2019 02:56:14 +0900 Subject: [PATCH 098/378] add path --- x/ibc/03-connection/manager.go | 1 - x/ibc/03-connection/types.go | 11 ++++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 7e7f85c48975..e5d32fafd454 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -78,7 +78,6 @@ type CounterObject struct { kind commitment.String - // TODO: prove counterparty client in v1 client client.CounterObject // nolint: unused } diff --git a/x/ibc/03-connection/types.go b/x/ibc/03-connection/types.go index 428137aad893..358d6a451fb9 100644 --- a/x/ibc/03-connection/types.go +++ b/x/ibc/03-connection/types.go @@ -1,15 +1,20 @@ package connection import ( - "errors" - "strings" + /* + "errors" + "strings" + */ + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) type Connection struct { Client string Counterparty string + Path commitment.Path } +/* func (conn Connection) MarshalAmino() (string, error) { return strings.Join([]string{conn.Client, conn.Counterparty}, "/"), nil } @@ -23,7 +28,7 @@ func (conn *Connection) UnmarshalAmino(text string) (err error) { conn.Counterparty = fields[1] return nil } - +*/ var kinds = map[string]Kind{ "handshake": Kind{true, true}, } From 02a3b1c4b2b06f11bf4d2a1730b73f20d4a66841 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 14 Jul 2019 03:11:53 +0900 Subject: [PATCH 099/378] add comments for manual proof arguments --- x/ibc/03-connection/handshake.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index b285c90747c3..59bdf7944d8e 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -154,8 +154,10 @@ func (man Handshaker) OpenInit(ctx sdk.Context, return obj, nil } -// Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} +// Using proofs: counterparty.{connection,state,nextTimeout,counterpartyClient, client} func (man Handshaker) OpenTry(ctx sdk.Context, + // TODO: proofs should be manually passed + // connectionp, statep, timeoutp, counterpartyClientp, clientp commitment.Proof, id string, connection Connection, counterpartyClient string, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { obj, err = man.create(ctx, id, connection, counterpartyClient) @@ -213,8 +215,10 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } -// Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} +// Using proofs: counterparty.{connection, state, timeout, counterpartyClient, client} func (man Handshaker) OpenAck(ctx sdk.Context, + // TODO: proofs should be manually passed + // connectionp, statep, timeoutp, counterpartyClientp, clientp commitment.Proof id string /*expheight uint64, */, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { obj, err = man.query(ctx, id) @@ -270,7 +274,11 @@ func (man Handshaker) OpenAck(ctx sdk.Context, } // Using proofs: counterparty.{connection,state, nextTimeout} -func (man Handshaker) OpenConfirm(ctx sdk.Context, id string, timeoutHeight uint64) (obj HandshakeObject, err error) { +func (man Handshaker) OpenConfirm(ctx sdk.Context, + // TODO: proofs should be manually passed + // statep, timeoutp, commitment.Proof, + id string, timeoutHeight uint64) (obj HandshakeObject, err error) { + obj, err = man.query(ctx, id) if err != nil { return From 631d7377cdf81e1c33cca96c2d50484e9ab33972 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 14 Jul 2019 03:36:18 +0900 Subject: [PATCH 100/378] pass proofs manually --- x/ibc/03-connection/handshake.go | 45 ++++++++++++++++++++++++++---- x/ibc/03-connection/tests/types.go | 20 ++++--------- 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index 59bdf7944d8e..e96c805664bf 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -156,8 +156,7 @@ func (man Handshaker) OpenInit(ctx sdk.Context, // Using proofs: counterparty.{connection,state,nextTimeout,counterpartyClient, client} func (man Handshaker) OpenTry(ctx sdk.Context, - // TODO: proofs should be manually passed - // connectionp, statep, timeoutp, counterpartyClientp, clientp commitment.Proof, + connectionp, statep, timeoutp, counterpartyClientp /*, clientp*/ commitment.Proof, id string, connection Connection, counterpartyClient string, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { obj, err = man.create(ctx, id, connection, counterpartyClient) @@ -165,6 +164,18 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } + store, err := commitment.NewStore( + // TODO: proof root should be able to be obtained from the past + obj.client.ConsensusState(ctx).GetRoot(), + connection.Path, + []commitment.Proof{connectionp, statep, timeoutp, counterpartyClientp}, + ) + if err != nil { + return + } + + ctx = commitment.WithStore(ctx, store) + err = assertTimeout(ctx, timeoutHeight) if err != nil { return @@ -217,8 +228,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // Using proofs: counterparty.{connection, state, timeout, counterpartyClient, client} func (man Handshaker) OpenAck(ctx sdk.Context, - // TODO: proofs should be manually passed - // connectionp, statep, timeoutp, counterpartyClientp, clientp commitment.Proof + connectionp, statep, timeoutp, counterpartyClientp /*, clientp*/ commitment.Proof, id string /*expheight uint64, */, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { obj, err = man.query(ctx, id) @@ -226,6 +236,18 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } + store, err := commitment.NewStore( + // TODO: proof root should be able to be obtained from the past + obj.client.ConsensusState(ctx).GetRoot(), + obj.Connection(ctx).Path, + []commitment.Proof{connectionp, statep, timeoutp, counterpartyClientp}, + ) + if err != nil { + return + } + + ctx = commitment.WithStore(ctx, store) + if !obj.state.Transit(ctx, Init, Open) { err = errors.New("ack on non-init connection") return @@ -275,8 +297,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, // Using proofs: counterparty.{connection,state, nextTimeout} func (man Handshaker) OpenConfirm(ctx sdk.Context, - // TODO: proofs should be manually passed - // statep, timeoutp, commitment.Proof, + statep, timeoutp commitment.Proof, id string, timeoutHeight uint64) (obj HandshakeObject, err error) { obj, err = man.query(ctx, id) @@ -284,6 +305,18 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, return } + store, err := commitment.NewStore( + // TODO: proof root should be able to be obtained from the past + obj.client.ConsensusState(ctx).GetRoot(), + obj.Connection(ctx).Path, + []commitment.Proof{statep, timeoutp}, + ) + if err != nil { + return + } + + ctx = commitment.WithStore(ctx, store) + if !obj.state.Transit(ctx, OpenTry, Open) { err = errors.New("confirm on non-try connection") return diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index 9464b031143b..931163dfe6cf 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -58,7 +58,7 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { } func (node *Node) CreateClient(t *testing.T) { - ctx := node.Context(t, nil) + ctx := node.Context() climan, _ := node.Manager() obj, err := climan.Create(ctx, node.Name, node.Counterparty.LastStateVerifier().ConsensusState) require.NoError(t, err) @@ -67,7 +67,7 @@ func (node *Node) CreateClient(t *testing.T) { } func (node *Node) UpdateClient(t *testing.T, header client.Header) { - ctx := node.Context(t, nil) + ctx := node.Context() climan, _ := node.Manager() obj, err := climan.Query(ctx, node.Connection.Client) require.NoError(t, err) @@ -80,16 +80,8 @@ func (node *Node) SetState(state connection.State) { node.Counterparty.State = state } -func (node *Node) Context(t *testing.T, proofs []commitment.Proof) sdk.Context { - ctx := node.Node.Context() - store, err := commitment.NewStore(node.Counterparty.Root(), node.Counterparty.Path, proofs) - require.NoError(t, err) - ctx = commitment.WithStore(ctx, store) - return ctx -} - func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Context, connection.Handshaker) { - ctx := node.Context(t, proofs) + ctx := node.Context() _, man := node.Manager() return ctx, connection.NewHandshaker(man) } @@ -124,7 +116,7 @@ func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenTry(ctx, node.Name, node.Connection, node.CounterpartyClient, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenTry(ctx, proofs[0], proofs[1], proofs[2], proofs[3], node.Name, node.Connection, node.CounterpartyClient, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.OpenTry, obj.State(ctx)) require.Equal(t, node.Connection, obj.Connection(ctx)) @@ -135,7 +127,7 @@ func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenAck(ctx, node.Name, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenAck(ctx, proofs[0], proofs[1], proofs[2], proofs[3], node.Name, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.Open, obj.State(ctx)) require.Equal(t, node.Connection, obj.Connection(ctx)) @@ -145,7 +137,7 @@ func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenConfirm(ctx, node.Name, 100 /*TODO*/) + obj, err := man.OpenConfirm(ctx, proofs[0], proofs[1], node.Name, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.Open, obj.State(ctx)) require.Equal(t, node.Connection, obj.Connection(ctx)) From 37387bfc951e2f662706c63d0e1ce1764fb00240 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 14 Jul 2019 03:37:06 +0900 Subject: [PATCH 101/378] add path to codec --- x/ibc/23-commitment/codec.go | 1 + x/ibc/23-commitment/merkle/codec.go | 1 + 2 files changed, 2 insertions(+) diff --git a/x/ibc/23-commitment/codec.go b/x/ibc/23-commitment/codec.go index 33d5bc490d39..8e0bdf49aa9a 100644 --- a/x/ibc/23-commitment/codec.go +++ b/x/ibc/23-commitment/codec.go @@ -6,5 +6,6 @@ import ( func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*Root)(nil), nil) + cdc.RegisterInterface((*Path)(nil), nil) cdc.RegisterInterface((*Proof)(nil), nil) } diff --git a/x/ibc/23-commitment/merkle/codec.go b/x/ibc/23-commitment/merkle/codec.go index a5e088650b0c..993c46603a3e 100644 --- a/x/ibc/23-commitment/merkle/codec.go +++ b/x/ibc/23-commitment/merkle/codec.go @@ -6,5 +6,6 @@ import ( func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(Root{}, "ibc/commitment/merkle/Root", nil) + cdc.RegisterConcrete(Path{}, "ibc/commitment/merkle/Path", nil) cdc.RegisterConcrete(Proof{}, "ibc/commitment/merkle/Proof", nil) } From 5266fc92c6e4fbce706992cbf59c375b6fe9043e Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 7 Jun 2019 23:47:01 +0200 Subject: [PATCH 102/378] add client --- x/ibc/02-client/manager.go | 146 ++++++++++++++++++++++++++++ x/ibc/02-client/tendermint/types.go | 79 +++++++++++++++ x/ibc/02-client/types.go | 46 +++++++++ 3 files changed, 271 insertions(+) create mode 100644 x/ibc/02-client/manager.go create mode 100644 x/ibc/02-client/tendermint/types.go create mode 100644 x/ibc/02-client/types.go diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go new file mode 100644 index 000000000000..89a8a878df49 --- /dev/null +++ b/x/ibc/02-client/manager.go @@ -0,0 +1,146 @@ +package client + +import ( + "errors" + "strconv" + + "github.com/cosmos/cosmos-sdk/store/mapping" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type IDGenerator func(sdk.Context /*Header,*/, mapping.Value) string + +func IntegerIDGenerator(ctx sdk.Context, v mapping.Value) string { + id := mapping.NewInteger(v, mapping.Dec).Incr(ctx) + return strconv.FormatUint(id, 10) +} + +type Manager struct { + protocol mapping.Mapping + + idval mapping.Value + idgen IDGenerator +} + +func NewManager(protocol, free mapping.Base, idgen IDGenerator) Manager { + return Manager{ + protocol: mapping.NewMapping(protocol, []byte("/")), + idval: mapping.NewValue(free, []byte("/id")), + idgen: idgen, + } +} + +/* +func (man Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { + if _, ok := man.pred[kind]; ok { + panic("Kind already registered") + } + man.pred[kind] = pred + return man +} +*/ +func (man Manager) object(id string) Object { + return Object{ + id: id, + client: man.protocol.Value([]byte(id)), + freeze: mapping.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), + } +} + +func (man Manager) Create(ctx sdk.Context, cs Client) string { + id := man.idgen(ctx, man.idval) + err := man.object(id).create(ctx, cs) + if err != nil { + panic(err) + } + return id +} + +func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { + res := man.object(id) + if !res.exists(ctx) { + return Object{}, errors.New("client not exists") + } + return res, nil +} + +type Object struct { + id string + client mapping.Value + freeze mapping.Boolean +} + +func (obj Object) create(ctx sdk.Context, st Client) error { + if obj.exists(ctx) { + return errors.New("Create client on already existing id") + } + obj.client.Set(ctx, st) + return nil +} + +func (obj Object) exists(ctx sdk.Context) bool { + return obj.client.Exists(ctx) +} + +func (obj Object) ID() string { + return obj.id +} + +func (obj Object) Value(ctx sdk.Context) (res Client) { + obj.client.Get(ctx, &res) + return +} + +func (obj Object) Is(ctx sdk.Context, client Client) bool { + return obj.client.Is(ctx, client) +} + +func (obj Object) Update(ctx sdk.Context, header Header) error { + if !obj.exists(ctx) { + panic("should not update nonexisting client") + } + + if obj.freeze.Get(ctx) { + return errors.New("client is frozen") + } + + var stored Client + obj.client.GetIfExists(ctx, &stored) + updated, err := stored.Validate(header) + if err != nil { + return err + } + + obj.client.Set(ctx, updated) + + return nil +} + +func (obj Object) Freeze(ctx sdk.Context) error { + if !obj.exists(ctx) { + panic("should not freeze nonexisting client") + } + + if obj.freeze.Get(ctx) { + return errors.New("client is already frozen") + } + + obj.freeze.Set(ctx, true) + + return nil +} + +func (obj Object) Delete(ctx sdk.Context) error { + if !obj.exists(ctx) { + panic("should not delete nonexisting client") + } + + if !obj.freeze.Get(ctx) { + return errors.New("client is not frozen") + } + + obj.client.Delete(ctx) + obj.freeze.Delete(ctx) + + return nil +} diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go new file mode 100644 index 000000000000..54655cf702d4 --- /dev/null +++ b/x/ibc/02-client/tendermint/types.go @@ -0,0 +1,79 @@ +package tendermint + +import ( + "bytes" + + "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +// Ref tendermint/lite/base_verifier.go + +var _ client.ValidityPredicateBase = ValidityPredicateBase{} + +type ValidityPredicateBase struct { + Height int64 + NextValidatorSet *types.ValidatorSet +} + +func (ValidityPredicateBase) Kind() client.Kind { + return client.Tendermint +} + +func (base ValidityPredicateBase) GetHeight() int64 { + return base.Height +} + +func (base ValidityPredicateBase) Equal(cbase client.ValidityPredicateBase) bool { + base0, ok := cbase.(ValidityPredicateBase) + if !ok { + return false + } + return base.Height == base0.Height && + bytes.Equal(base.NextValidatorSet.Hash(), base0.NextValidatorSet.Hash()) +} + +var _ client.Client = Client{} + +type Client struct { + Base ValidityPredicateBase + Root commitment.Root +} + +func (Client) Kind() client.Kind { + return client.Tendermint +} + +func (client Client) GetBase() client.ValidityPredicateBase { + return client.Base +} + +func (client Client) GetRoot() commitment.Root { + return client.Root +} + +func (client Client) Validate(header client.Header) (client.Client, error) { + return client, nil // XXX +} + +var _ client.Header = Header{} + +type Header struct { + Base ValidityPredicateBase + Root commitment.Root + Votes []*types.CommitSig +} + +func (header Header) Kind() client.Kind { + return client.Tendermint +} + +func (header Header) GetBase() client.ValidityPredicateBase { + return header.Base +} + +func (header Header) GetRoot() commitment.Root { + return header.Root +} diff --git a/x/ibc/02-client/types.go b/x/ibc/02-client/types.go new file mode 100644 index 000000000000..7b9f81ec7789 --- /dev/null +++ b/x/ibc/02-client/types.go @@ -0,0 +1,46 @@ +package client + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +// TODO: types in this file should be (de/)serialized with proto in the future + +type AminoMarshaler interface { + MarshalAmino() (string, error) + UnmarshalAmino(string) error +} + +type ValidityPredicateBase interface { + Kind() Kind + GetHeight() int64 + Equal(ValidityPredicateBase) bool +} + +// ConsensusState +type Client interface { + Kind() Kind + GetBase() ValidityPredicateBase + GetRoot() commitment.Root + Validate(Header) (Client, error) // ValidityPredicate +} + +func Equal(client1, client2 Client) bool { + return client1.Kind() == client2.Kind() && + client1.GetBase().Equal(client2.GetBase()) +} + +type Header interface { + Kind() Kind + // Proof() HeaderProof + GetBase() ValidityPredicateBase // can be nil + GetRoot() commitment.Root +} + +// XXX: Kind should be enum? + +type Kind byte + +const ( + Tendermint Kind = iota +) From 06257bdfa0595474ff1fb48fe45b76bba435b823 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 18:14:19 +0200 Subject: [PATCH 103/378] add counterpartymanager --- x/ibc/02-client/manager.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 89a8a878df49..97f281cc9596 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -6,6 +6,8 @@ import ( "github.com/cosmos/cosmos-sdk/store/mapping" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) type IDGenerator func(sdk.Context /*Header,*/, mapping.Value) string @@ -24,12 +26,22 @@ type Manager struct { func NewManager(protocol, free mapping.Base, idgen IDGenerator) Manager { return Manager{ - protocol: mapping.NewMapping(protocol, []byte("/")), - idval: mapping.NewValue(free, []byte("/id")), + protocol: mapping.NewMapping(protocol, []byte("/client")), + idval: mapping.NewValue(free, []byte("/client/id")), idgen: idgen, } } +type CounterpartyManager struct { + protocol commitment.Mapping +} + +func NewCounterpartyManager(protocol commitment.Base) CounterpartyManager { + return CounterpartyManager{ + protocol: commitment.NewMapping(protocol, []byte("/client")), + } +} + /* func (man Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { if _, ok := man.pred[kind]; ok { From 5b089e71a2f7671facd3f28e47d31e829cecc888 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 18:29:24 +0200 Subject: [PATCH 104/378] fix manager --- x/ibc/02-client/manager.go | 16 ++++++++++++++++ x/ibc/23-commitment/value.go | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 97f281cc9596..c22576b18cd2 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -76,12 +76,28 @@ func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { return res, nil } +func (man CounterpartyManager) object(id string) CounterObject { + return CounterObject{ + id: id, + client: man.protocol.Value([]byte(id)), + } +} + +func (man CounterpartyManager) Query(id string) CounterObject { + return man.object(id) +} + type Object struct { id string client mapping.Value freeze mapping.Boolean } +type CounterObject struct { + id string + client commitment.Value +} + func (obj Object) create(ctx sdk.Context, st Client) error { if obj.exists(ctx) { return errors.New("Create client on already existing id") diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 70b8502a44e6..10b409b28b99 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -45,6 +45,13 @@ func NewMapping(base Base, prefix []byte) Mapping { } } +func (m Mapping) Value(key []byte) Value { + return Value{ + base: m.base, + key: key, + } +} + type Value struct { base Base key []byte From d0f61b054c4256f540a6da849445c452a24ad8be Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 18:44:25 +0200 Subject: [PATCH 105/378] add Is() to counterobject --- x/ibc/02-client/manager.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index c22576b18cd2..502478104757 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -123,6 +123,10 @@ func (obj Object) Is(ctx sdk.Context, client Client) bool { return obj.client.Is(ctx, client) } +func (obj CounterObject) Is(ctx sdk.Context, client Client) bool { + return obj.client.Is(ctx, client) +} + func (obj Object) Update(ctx sdk.Context, header Header) error { if !obj.exists(ctx) { panic("should not update nonexisting client") From a7b866f438f1e5127b8d1b379e7f2d3167170dc9 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 12 Jun 2019 00:08:04 +0200 Subject: [PATCH 106/378] add readme, reflect ICS02 revision --- x/ibc/02-client/README.md | 49 ++++++++++++++++++++++++++++++++++++++ x/ibc/02-client/manager.go | 31 ++++++++++-------------- x/ibc/02-client/types.go | 26 ++++++++------------ 3 files changed, 72 insertions(+), 34 deletions(-) create mode 100644 x/ibc/02-client/README.md diff --git a/x/ibc/02-client/README.md b/x/ibc/02-client/README.md new file mode 100644 index 000000000000..a9bd6892771b --- /dev/null +++ b/x/ibc/02-client/README.md @@ -0,0 +1,49 @@ +# ICS 02: Client + +Package `client` defines types and method to store and update light clients which tracks on other chain's state. +The main type is `Client`, which provides `commitment.Root` to verify state proofs and `ConsensusState` to +verify header proofs. + +## Spec + +```typescript +interface ConsensusState { + height: uint64 + root: CommitmentRoot + validityPredicate: ValidityPredicate + eqivocationPredicate: EquivocationPredicate +} + +interface ClientState { + consensusState: ConsensusState + verifiedRoots: Map + frozen: bool +} + +interface Header { + height: uint64 + proof: HeaderProof + state: Maybe[ConsensusState] + root: CommitmentRoot +} + +type ValidityPredicate = (ConsensusState, Header) => Error | ConsensusState + +type EquivocationPredicate = (ConsensusState, Header, Header) => bool +``` + +## Impl + +### types.go + +`spec: interface ConsensusState` is implemented by `type ConsensusState`. `ConsensusState.{GetHeight(), GetRoot(), +Validate(), Equivocation()}` each corresponds to `spec: ConsensusState.{height, root, validityPredicate, +equivocationPredicate}`. `ConsensusState.Kind()` returns `Kind`, which is an enum indicating the type of the +consensus algorithm. + +`spec: interface Header` is implemented by `type Header`. `Header{GetHeight(), Proof(), State(), GetRoot()}` +each corresponds to `spec: Header.{height, proof, state, root}`. + +### manager.go + +`spec: interface ClientState` is implemented by `type Object`. // TODO diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 502478104757..0134d8340d55 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -10,6 +10,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) +// XXX: implement spec: ClientState.verifiedRoots + type IDGenerator func(sdk.Context /*Header,*/, mapping.Value) string func IntegerIDGenerator(ctx sdk.Context, v mapping.Value) string { @@ -59,13 +61,14 @@ func (man Manager) object(id string) Object { } } -func (man Manager) Create(ctx sdk.Context, cs Client) string { +func (man Manager) Create(ctx sdk.Context, cs ConsensusState) (Object, error) { id := man.idgen(ctx, man.idval) - err := man.object(id).create(ctx, cs) - if err != nil { - panic(err) + obj := man.object(id) + if obj.exists(ctx) { + return Object{}, errors.New("Create client on already existing id") } - return id + obj.client.Set(ctx, cs) + return obj, nil } func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { @@ -89,7 +92,7 @@ func (man CounterpartyManager) Query(id string) CounterObject { type Object struct { id string - client mapping.Value + client mapping.Value // ConsensusState freeze mapping.Boolean } @@ -98,14 +101,6 @@ type CounterObject struct { client commitment.Value } -func (obj Object) create(ctx sdk.Context, st Client) error { - if obj.exists(ctx) { - return errors.New("Create client on already existing id") - } - obj.client.Set(ctx, st) - return nil -} - func (obj Object) exists(ctx sdk.Context) bool { return obj.client.Exists(ctx) } @@ -114,16 +109,16 @@ func (obj Object) ID() string { return obj.id } -func (obj Object) Value(ctx sdk.Context) (res Client) { +func (obj Object) Value(ctx sdk.Context) (res ConsensusState) { obj.client.Get(ctx, &res) return } -func (obj Object) Is(ctx sdk.Context, client Client) bool { +func (obj Object) Is(ctx sdk.Context, client ConsensusState) bool { return obj.client.Is(ctx, client) } -func (obj CounterObject) Is(ctx sdk.Context, client Client) bool { +func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { return obj.client.Is(ctx, client) } @@ -136,7 +131,7 @@ func (obj Object) Update(ctx sdk.Context, header Header) error { return errors.New("client is frozen") } - var stored Client + var stored ConsensusState obj.client.GetIfExists(ctx, &stored) updated, err := stored.Validate(header) if err != nil { diff --git a/x/ibc/02-client/types.go b/x/ibc/02-client/types.go index 7b9f81ec7789..2ae484853354 100644 --- a/x/ibc/02-client/types.go +++ b/x/ibc/02-client/types.go @@ -5,35 +5,29 @@ import ( ) // TODO: types in this file should be (de/)serialized with proto in the future - -type AminoMarshaler interface { - MarshalAmino() (string, error) - UnmarshalAmino(string) error -} - -type ValidityPredicateBase interface { - Kind() Kind - GetHeight() int64 - Equal(ValidityPredicateBase) bool -} +// currently amkno codec handles it // ConsensusState -type Client interface { +type ConsensusState interface { Kind() Kind - GetBase() ValidityPredicateBase + GetHeight() uint64 GetRoot() commitment.Root - Validate(Header) (Client, error) // ValidityPredicate + Validate(Header) (ConsensusState, error) // ValidityPredicate + Equivocation(Header, Header) bool // EquivocationPredicate } -func Equal(client1, client2 Client) bool { +/* +func Equal(client1, client2 ConsensusState) bool { return client1.Kind() == client2.Kind() && client1.GetBase().Equal(client2.GetBase()) } +*/ type Header interface { Kind() Kind + GetHeight() uint64 // Proof() HeaderProof - GetBase() ValidityPredicateBase // can be nil + State() ConsensusState // can be nil GetRoot() commitment.Root } From 392e3abb3f81e0ce383583123389ba4bbd1b62ea Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 12 Jun 2019 00:28:13 +0200 Subject: [PATCH 107/378] reflect downstream ics --- x/ibc/02-client/manager.go | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 0134d8340d55..196d62e62fdc 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -4,7 +4,7 @@ import ( "errors" "strconv" - "github.com/cosmos/cosmos-sdk/store/mapping" + "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" @@ -12,24 +12,24 @@ import ( // XXX: implement spec: ClientState.verifiedRoots -type IDGenerator func(sdk.Context /*Header,*/, mapping.Value) string +type IDGenerator func(sdk.Context /*Header,*/, state.Value) string -func IntegerIDGenerator(ctx sdk.Context, v mapping.Value) string { - id := mapping.NewInteger(v, mapping.Dec).Incr(ctx) +func IntegerIDGenerator(ctx sdk.Context, v state.Value) string { + id := state.NewInteger(v, state.Dec).Incr(ctx) return strconv.FormatUint(id, 10) } type Manager struct { - protocol mapping.Mapping + protocol state.Mapping - idval mapping.Value + idval state.Value idgen IDGenerator } -func NewManager(protocol, free mapping.Base, idgen IDGenerator) Manager { +func NewManager(protocol, free state.Base, idgen IDGenerator) Manager { return Manager{ - protocol: mapping.NewMapping(protocol, []byte("/client")), - idval: mapping.NewValue(free, []byte("/client/id")), + protocol: state.NewMapping(protocol, []byte("/client")), + idval: state.NewValue(free, []byte("/client/id")), idgen: idgen, } } @@ -57,7 +57,7 @@ func (man Manager) object(id string) Object { return Object{ id: id, client: man.protocol.Value([]byte(id)), - freeze: mapping.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), + freeze: state.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), } } @@ -92,8 +92,8 @@ func (man CounterpartyManager) Query(id string) CounterObject { type Object struct { id string - client mapping.Value // ConsensusState - freeze mapping.Boolean + client state.Value // ConsensusState + freeze state.Boolean } type CounterObject struct { @@ -114,10 +114,6 @@ func (obj Object) Value(ctx sdk.Context) (res ConsensusState) { return } -func (obj Object) Is(ctx sdk.Context, client ConsensusState) bool { - return obj.client.Is(ctx, client) -} - func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { return obj.client.Is(ctx, client) } From 5d46c96f54ab118a7994e92150114835f54b2a8b Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 13 Jun 2019 16:00:18 +0200 Subject: [PATCH 108/378] test in progress --- x/ibc/02-client/tendermint/types.go | 96 ++++++----- x/ibc/02-client/tendermint/types_test.go | 131 ++++++++++++++ x/ibc/02-client/tendermint/valset_test.go | 197 ++++++++++++++++++++++ x/ibc/02-client/types.go | 3 - 4 files changed, 386 insertions(+), 41 deletions(-) create mode 100644 x/ibc/02-client/tendermint/types_test.go create mode 100644 x/ibc/02-client/tendermint/valset_test.go diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 54655cf702d4..1442d91d6c99 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -2,78 +2,98 @@ package tendermint import ( "bytes" + "errors" + "fmt" + lerr "github.com/tendermint/tendermint/lite/errors" "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -// Ref tendermint/lite/base_verifier.go - -var _ client.ValidityPredicateBase = ValidityPredicateBase{} +var _ client.ConsensusState = ConsensusState{} -type ValidityPredicateBase struct { - Height int64 +// Ref tendermint/lite/base_verifier.go +type ConsensusState struct { + ChainID string + Height uint64 + Root commitment.Root NextValidatorSet *types.ValidatorSet } -func (ValidityPredicateBase) Kind() client.Kind { +func (ConsensusState) Kind() client.Kind { return client.Tendermint } -func (base ValidityPredicateBase) GetHeight() int64 { - return base.Height +func (cs ConsensusState) GetHeight() uint64 { + return cs.Height } -func (base ValidityPredicateBase) Equal(cbase client.ValidityPredicateBase) bool { - base0, ok := cbase.(ValidityPredicateBase) - if !ok { - return false +func (cs ConsensusState) GetRoot() commitment.Root { + return cs.Root +} + +func (cs ConsensusState) update(header Header) ConsensusState { + return ConsensusState{ + ChainID: cs.ChainID, + Height: uint64(header.Height), + Root: header.AppHash, + NextValidatorSet: header.NextValidatorSet, } - return base.Height == base0.Height && - bytes.Equal(base.NextValidatorSet.Hash(), base0.NextValidatorSet.Hash()) } -var _ client.Client = Client{} +func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, error) { + header, ok := cheader.(Header) + if !ok { + return nil, errors.New("invalid type") + } -type Client struct { - Base ValidityPredicateBase - Root commitment.Root -} + nextvalset := cs.NextValidatorSet + nexthash := nextvalset.Hash() -func (Client) Kind() client.Kind { - return client.Tendermint -} + if cs.Height == uint64(header.Height-1) { + nexthash = cs.NextValidatorSet.Hash() + if !bytes.Equal(header.ValidatorsHash, nexthash) { + fmt.Println(111) + return nil, lerr.ErrUnexpectedValidators(header.ValidatorsHash, nexthash) + } + } -func (client Client) GetBase() client.ValidityPredicateBase { - return client.Base -} + if !bytes.Equal(header.NextValidatorsHash, header.NextValidatorSet.Hash()) { + fmt.Println(header) + return nil, lerr.ErrUnexpectedValidators(header.NextValidatorsHash, header.NextValidatorSet.Hash()) + } + + err := header.ValidateBasic(cs.ChainID) + if err != nil { + return nil, err + } -func (client Client) GetRoot() commitment.Root { - return client.Root + err = cs.NextValidatorSet.VerifyCommit(cs.ChainID, header.Commit.BlockID, header.Height, header.Commit) + if err != nil { + return nil, err + } + + return cs.update(header), nil } -func (client Client) Validate(header client.Header) (client.Client, error) { - return client, nil // XXX +func (cs ConsensusState) Equivocation(header1, header2 client.Header) bool { + return false // XXX } var _ client.Header = Header{} type Header struct { - Base ValidityPredicateBase - Root commitment.Root - Votes []*types.CommitSig + // XXX: don't take the entire struct + types.SignedHeader + NextValidatorSet *types.ValidatorSet } func (header Header) Kind() client.Kind { return client.Tendermint } -func (header Header) GetBase() client.ValidityPredicateBase { - return header.Base -} - -func (header Header) GetRoot() commitment.Root { - return header.Root +func (header Header) GetHeight() uint64 { + return uint64(header.Height) } diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go new file mode 100644 index 000000000000..44dc0fc9aba9 --- /dev/null +++ b/x/ibc/02-client/tendermint/types_test.go @@ -0,0 +1,131 @@ +package tendermint + +import ( + "testing" + + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store" + stypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const chainid = "testchain" + +func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { + key := sdk.NewKVStoreKey("ibc") + db := dbm.NewMemDB() + cms := store.NewCommitMultiStore(db) + cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) + err := cms.LoadLatestVersion() + if err != nil { + panic(err) + } + ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) + cdc := codec.New() + return key, ctx, cms, cdc +} + +type node struct { + valset MockValidators + + cms sdk.CommitMultiStore + store sdk.KVStore + + commits []tmtypes.SignedHeader +} + +func NewNode(valset MockValidators) *node { + key, ctx, cms, _ := defaultComponents() + return &node{ + valset: valset, + cms: cms, + store: ctx.KVStore(key), + commits: nil, + } +} + +func (node *node) last() tmtypes.SignedHeader { + if len(node.commits) == 0 { + return tmtypes.SignedHeader{} + } + return node.commits[len(node.commits)-1] +} + +func (node *node) Commit() tmtypes.SignedHeader { + valsethash := node.valset.ValidatorSet().Hash() + nextvalset := node.valset.Mutate(false) + nextvalsethash := nextvalset.ValidatorSet().Hash() + commitid := node.cms.Commit() + + header := tmtypes.Header{ + ChainID: chainid, + Height: int64(len(node.commits) + 1), + LastBlockID: tmtypes.BlockID{ + Hash: node.last().Header.Hash(), + }, + + ValidatorsHash: valsethash, + NextValidatorsHash: nextvalsethash, + AppHash: commitid.Hash, + } + + commit := node.valset.Sign(header) + + node.commits = append(node.commits, commit) + + return commit +} + +func (node *node) Set(key, value string) { + node.store.Set(append([]byte{0x00}, []byte(key)...), []byte(value)) +} + +type Verifier struct { + ConsensusState +} + +func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators) *Verifier { + return &Verifier{ + ConsensusState{ + ChainID: chainid, + Height: uint64(header.Height), + Root: header.AppHash, + NextValidatorSet: nextvalset.ValidatorSet(), + }, + } +} + +func (v *Verifier) Validate(header tmtypes.SignedHeader, nextvalset MockValidators) error { + newcs, err := v.ConsensusState.Validate( + Header{ + SignedHeader: header, + NextValidatorSet: nextvalset.ValidatorSet(), + }, + ) + if err != nil { + return err + } + v.ConsensusState = newcs.(ConsensusState) + + return nil +} + +func TestUpdate(t *testing.T) { + node := NewNode(NewMockValidators(100, 10)) + + node.Commit() + + verifier := NewVerifier(node.last(), node.valset) + + header := node.Commit() + + err := verifier.Validate(header, node.valset) + require.NoError(t, err) +} diff --git a/x/ibc/02-client/tendermint/valset_test.go b/x/ibc/02-client/tendermint/valset_test.go new file mode 100644 index 000000000000..10aa5dc0eae7 --- /dev/null +++ b/x/ibc/02-client/tendermint/valset_test.go @@ -0,0 +1,197 @@ +package tendermint + +import ( + "bytes" + "fmt" + "sort" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + tmtypes "github.com/tendermint/tendermint/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// reimplementing tmtypes.MockPV to make it marshallable +type mockPV struct { + PrivKey crypto.PrivKey +} + +var _ tmtypes.PrivValidator = (*mockPV)(nil) + +func newMockPV() *mockPV { + return &mockPV{ed25519.GenPrivKey()} +} + +func (pv *mockPV) GetAddress() tmtypes.Address { + return pv.PrivKey.PubKey().Address() +} + +func (pv *mockPV) GetPubKey() crypto.PubKey { + return pv.PrivKey.PubKey() +} + +func (pv *mockPV) SignVote(chainID string, vote *tmtypes.Vote) error { + signBytes := vote.SignBytes(chainID) + sig, err := pv.PrivKey.Sign(signBytes) + if err != nil { + return err + } + vote.Signature = sig + return nil +} + +func (pv *mockPV) SignProposal(string, *tmtypes.Proposal) error { + panic("not needed") +} + +// MockValset +type MockValidator struct { + MockPV *mockPV + Power sdk.Dec +} + +func NewMockValidator(power sdk.Dec) MockValidator { + return MockValidator{ + MockPV: newMockPV(), + Power: power, + } +} + +func (val MockValidator) GetOperator() sdk.ValAddress { + return sdk.ValAddress(val.MockPV.GetAddress()) +} + +func (val MockValidator) GetConsAddr() sdk.ConsAddress { + return sdk.GetConsAddress(val.MockPV.GetPubKey()) +} + +func (val MockValidator) GetConsPubKey() crypto.PubKey { + return val.MockPV.GetPubKey() +} + +func (val MockValidator) GetPower() sdk.Dec { + return val.Power +} + +func (val MockValidator) Validator() *tmtypes.Validator { + return tmtypes.NewValidator( + val.GetConsPubKey(), + val.GetPower().RoundInt64(), + ) +} + +type MockValidators []MockValidator + +var _ sort.Interface = MockValidators{} + +func NewMockValidators(num int, power int64) MockValidators { + res := make(MockValidators, num) + for i := range res { + res[i] = NewMockValidator(sdk.NewDec(power)) + } + + // ddd + fmt.Println(333) + for _, val := range res { + fmt.Println(val) + } + + // ddd + return res +} + +func (vals MockValidators) Len() int { + return len(vals) +} + +func (vals MockValidators) Less(i, j int) bool { + return bytes.Compare([]byte(vals[i].GetConsAddr()), []byte(vals[j].GetConsAddr())) == -1 +} + +func (vals MockValidators) Swap(i, j int) { + it := vals[j] + vals[j] = vals[i] + vals[i] = it +} + +func (vals MockValidators) TotalPower() sdk.Dec { + res := sdk.ZeroDec() + for _, val := range vals { + res = res.Add(val.Power) + } + return res +} + +func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { + precommits := make([]*tmtypes.CommitSig, len(vals)) + for i, val := range vals { + precommits[i] = (&tmtypes.Vote{ + BlockID: tmtypes.BlockID{ + Hash: header.Hash(), + }, + ValidatorAddress: val.MockPV.GetAddress(), + ValidatorIndex: i, + Height: header.Height, + Type: tmtypes.PrecommitType, + }).CommitSig() + val.MockPV.SignVote("", (*tmtypes.Vote)(precommits[i])) + } + + return tmtypes.SignedHeader{ + Header: &header, + Commit: &tmtypes.Commit{ + BlockID: tmtypes.BlockID{ + Hash: header.Hash(), + }, + Precommits: precommits, + }, + } +} + +// Mutate valset +func (vals MockValidators) Mutate(majority bool) MockValidators { + var num int + if majority { + num = len(vals) * 2 / 3 + } else { + num = len(vals) * 1 / 6 + } + + res := make(MockValidators, len(vals)) + + for i := 0; i < len(vals)-num; i++ { + res[i] = vals[num:][i] + } + + for i := len(vals) - num; i < len(vals); i++ { + res[i] = NewMockValidator(vals[0].Power) + } + + // ddd + fmt.Println(333) + for _, val := range res { + fmt.Println(val) + } + + // ddd + + return res +} + +func (vals MockValidators) ValidatorSet() *tmtypes.ValidatorSet { + tmvals := make([]*tmtypes.Validator, len(vals)) + + for i, val := range vals { + tmvals[i] = val.Validator() + } + + // ddd + fmt.Println(333444) + for _, val := range tmvals { + fmt.Println(val) + } + + // ddd + return tmtypes.NewValidatorSet(tmvals) +} diff --git a/x/ibc/02-client/types.go b/x/ibc/02-client/types.go index 2ae484853354..2a34855085b9 100644 --- a/x/ibc/02-client/types.go +++ b/x/ibc/02-client/types.go @@ -26,9 +26,6 @@ func Equal(client1, client2 ConsensusState) bool { type Header interface { Kind() Kind GetHeight() uint64 - // Proof() HeaderProof - State() ConsensusState // can be nil - GetRoot() commitment.Root } // XXX: Kind should be enum? From b934d57bc256a81d61e29ab658a46062eb4a9dc4 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 13 Jun 2019 19:08:13 +0200 Subject: [PATCH 109/378] add test --- x/ibc/02-client/tendermint/types.go | 6 +- x/ibc/02-client/tendermint/types_test.go | 108 +++++++++++++++++++--- x/ibc/02-client/tendermint/valset_test.go | 46 +++------ 3 files changed, 114 insertions(+), 46 deletions(-) diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 1442d91d6c99..8dd3cfca7294 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -3,7 +3,6 @@ package tendermint import ( "bytes" "errors" - "fmt" lerr "github.com/tendermint/tendermint/lite/errors" "github.com/tendermint/tendermint/types" @@ -55,13 +54,11 @@ func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, if cs.Height == uint64(header.Height-1) { nexthash = cs.NextValidatorSet.Hash() if !bytes.Equal(header.ValidatorsHash, nexthash) { - fmt.Println(111) return nil, lerr.ErrUnexpectedValidators(header.ValidatorsHash, nexthash) } } if !bytes.Equal(header.NextValidatorsHash, header.NextValidatorSet.Hash()) { - fmt.Println(header) return nil, lerr.ErrUnexpectedValidators(header.NextValidatorsHash, header.NextValidatorSet.Hash()) } @@ -70,7 +67,7 @@ func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, return nil, err } - err = cs.NextValidatorSet.VerifyCommit(cs.ChainID, header.Commit.BlockID, header.Height, header.Commit) + err = cs.NextValidatorSet.VerifyFutureCommit(header.ValidatorSet, cs.ChainID, header.Commit.BlockID, header.Height, header.Commit) if err != nil { return nil, err } @@ -87,6 +84,7 @@ var _ client.Header = Header{} type Header struct { // XXX: don't take the entire struct types.SignedHeader + ValidatorSet *types.ValidatorSet NextValidatorSet *types.ValidatorSet } diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go index 44dc0fc9aba9..14ca7adad0ea 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/types_test.go @@ -1,11 +1,13 @@ package tendermint import ( + "math/rand" "testing" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + cmn "github.com/tendermint/tendermint/libs/common" dbm "github.com/tendermint/tendermint/libs/db" "github.com/tendermint/tendermint/libs/log" tmtypes "github.com/tendermint/tendermint/types" @@ -14,6 +16,9 @@ import ( "github.com/cosmos/cosmos-sdk/store" stypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) const chainid = "testchain" @@ -33,7 +38,8 @@ func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *c } type node struct { - valset MockValidators + prevvalset MockValidators + valset MockValidators cms sdk.CommitMultiStore store sdk.KVStore @@ -60,7 +66,7 @@ func (node *node) last() tmtypes.SignedHeader { func (node *node) Commit() tmtypes.SignedHeader { valsethash := node.valset.ValidatorSet().Hash() - nextvalset := node.valset.Mutate(false) + nextvalset := node.valset.Mutate() nextvalsethash := nextvalset.ValidatorSet().Hash() commitid := node.cms.Commit() @@ -78,15 +84,13 @@ func (node *node) Commit() tmtypes.SignedHeader { commit := node.valset.Sign(header) + node.prevvalset = node.valset + node.valset = nextvalset node.commits = append(node.commits, commit) return commit } -func (node *node) Set(key, value string) { - node.store.Set(append([]byte{0x00}, []byte(key)...), []byte(value)) -} - type Verifier struct { ConsensusState } @@ -102,10 +106,11 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators) *Verifi } } -func (v *Verifier) Validate(header tmtypes.SignedHeader, nextvalset MockValidators) error { +func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset MockValidators) error { newcs, err := v.ConsensusState.Validate( Header{ SignedHeader: header, + ValidatorSet: valset.ValidatorSet(), NextValidatorSet: nextvalset.ValidatorSet(), }, ) @@ -117,15 +122,96 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, nextvalset MockValidato return nil } -func TestUpdate(t *testing.T) { +func testUpdate(t *testing.T, interval int, ok bool) { node := NewNode(NewMockValidators(100, 10)) node.Commit() verifier := NewVerifier(node.last(), node.valset) - header := node.Commit() + for i := 0; i < 100; i++ { + header := node.Commit() + + if i%interval == 0 { + err := verifier.Validate(header, node.prevvalset, node.valset) + if ok { + require.NoError(t, err) + } else { + require.Error(t, err) + } + } + } +} + +func TestEveryBlockUpdate(t *testing.T) { + testUpdate(t, 1, true) +} + +func TestEvenBlockUpdate(t *testing.T) { + testUpdate(t, 2, true) +} + +func TestSixthBlockUpdate(t *testing.T) { + testUpdate(t, 6, true) +} + +/* +// This should fail, since the amount of mutation is so large +// Commented out because it sometimes success +func TestTenthBlockUpdate(t *testing.T) { + testUpdate(t, 10, false) +} +*/ + +func key(str []byte) []byte { + return append([]byte{0x00}, str...) +} + +func (node *node) query(t *testing.T, k []byte) ([]byte, commitment.Proof) { + qres := node.cms.(stypes.Queryable).Query(abci.RequestQuery{Path: "/ibc/key", Data: key(k), Prove: true}) + require.Equal(t, uint32(0), qres.Code, qres.Log) + proof := merkle.Proof{ + Key: []byte(k), + Proof: qres.Proof, + } + return qres.Value, proof +} + +func (node *node) Set(k, value []byte) { + node.store.Set(key(k), value) +} + +func testProof(t *testing.T) { + node := NewNode(NewMockValidators(100, 10)) + + node.Commit() + + kvps := cmn.KVPairs{} + for h := 0; h < 20; h++ { + for i := 0; i < 100; i++ { + k := make([]byte, 32) + v := make([]byte, 32) + rand.Read(k) + rand.Read(v) + kvps = append(kvps, cmn.KVPair{Key: k, Value: v}) + node.Set(k, v) + } + header := node.Commit() + proofs := []commitment.Proof{} + for _, kvp := range kvps { + v, p := node.query(t, []byte(kvp.Key)) + require.Equal(t, kvp.Value, v) + proofs = append(proofs, p) + } + cstore, err := commitment.NewStore([]byte(header.AppHash), proofs) + require.NoError(t, err) + + for _, kvp := range kvps { + require.True(t, cstore.Prove(kvp.Key, kvp.Value)) + } + } +} - err := verifier.Validate(header, node.valset) - require.NoError(t, err) +func TestProofs(t *testing.T) { + testProof(t) } diff --git a/x/ibc/02-client/tendermint/valset_test.go b/x/ibc/02-client/tendermint/valset_test.go index 10aa5dc0eae7..5649a3533273 100644 --- a/x/ibc/02-client/tendermint/valset_test.go +++ b/x/ibc/02-client/tendermint/valset_test.go @@ -2,7 +2,6 @@ package tendermint import ( "bytes" - "fmt" "sort" "github.com/tendermint/tendermint/crypto" @@ -91,13 +90,8 @@ func NewMockValidators(num int, power int64) MockValidators { res[i] = NewMockValidator(sdk.NewDec(power)) } - // ddd - fmt.Println(333) - for _, val := range res { - fmt.Println(val) - } + sort.Sort(res) - // ddd return res } @@ -124,9 +118,10 @@ func (vals MockValidators) TotalPower() sdk.Dec { } func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { + precommits := make([]*tmtypes.CommitSig, len(vals)) for i, val := range vals { - precommits[i] = (&tmtypes.Vote{ + vote := &tmtypes.Vote{ BlockID: tmtypes.BlockID{ Hash: header.Hash(), }, @@ -134,8 +129,9 @@ func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { ValidatorIndex: i, Height: header.Height, Type: tmtypes.PrecommitType, - }).CommitSig() - val.MockPV.SignVote("", (*tmtypes.Vote)(precommits[i])) + } + val.MockPV.SignVote(chainid, vote) + precommits[i] = vote.CommitSig() } return tmtypes.SignedHeader{ @@ -150,13 +146,8 @@ func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { } // Mutate valset -func (vals MockValidators) Mutate(majority bool) MockValidators { - var num int - if majority { - num = len(vals) * 2 / 3 - } else { - num = len(vals) * 1 / 6 - } +func (vals MockValidators) Mutate() MockValidators { + num := len(vals) / 20 // 5% change each block res := make(MockValidators, len(vals)) @@ -168,15 +159,15 @@ func (vals MockValidators) Mutate(majority bool) MockValidators { res[i] = NewMockValidator(vals[0].Power) } - // ddd - fmt.Println(333) - for _, val := range res { - fmt.Println(val) - } + sort.Sort(res) - // ddd + for i, val := range vals { + if val != res[i] { + return res + } + } - return res + panic("not mutated") } func (vals MockValidators) ValidatorSet() *tmtypes.ValidatorSet { @@ -186,12 +177,5 @@ func (vals MockValidators) ValidatorSet() *tmtypes.ValidatorSet { tmvals[i] = val.Validator() } - // ddd - fmt.Println(333444) - for _, val := range tmvals { - fmt.Println(val) - } - - // ddd return tmtypes.NewValidatorSet(tmvals) } From 2ac7d8c0482d9d56af262adb47d44dec6c8d99d1 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 19 Jun 2019 13:07:06 +0100 Subject: [PATCH 110/378] in progres --- x/ibc/client/cli/query.go | 216 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 x/ibc/client/cli/query.go diff --git a/x/ibc/client/cli/query.go b/x/ibc/client/cli/query.go new file mode 100644 index 000000000000..ca979151c499 --- /dev/null +++ b/x/ibc/client/cli/query.go @@ -0,0 +1,216 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + tmtypes "github.com/tendermint/tendermint/types" + + "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/02-client/tendermint" + ibc "github.com/cosmos/cosmos-sdk/x/ibc/keeper" +) + +func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ibcQueryCmd := &cobra.Command{ + Use: "ibc", + Short: "IBC query subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + ibcQueryCmd.AddCommand(client.GetCommands( + GetCmdQueryConsensusState(cdc), + GetCmdQueryHeader(cdc), + GetCmdQueryClient(cdc), + GetCmdQueryConnection(cdc), + GetCmdQueryChannel(cdc), + )...) + return ibcQueryCmd +} + +func GetCmdQueryClient(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "client", + Short: "Query stored client", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + keeper := ibc.DummyKeeper() + + var state ibc.ConsensusState + statebz, _, err := query(ctx, keeper.Client.Object(args[0]).Key()) + if err != nil { + return err + } + cdc.MustUnmarshalBinaryBare(statebz, &state) + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + + return nil + }, + } +} + +func GetCmdQueryConsensusState(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "consensus-state", + Short: "Query the latest consensus state of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + node, err := ctx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return err + } + + state := tendermint.ConsensusState{ + ChainID: commit.ChainID, + Height: uint64(commit.Height), + Root: []byte(commit.AppHash), + NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + + return nil + }, + } +} + +func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "header", + Short: "Query the latest header of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + node, err := ctx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return err + } + + nextvalidators, err := node.Validators(&height) + if err != nil { + return err + } + + header := tendermint.Header{ + SignedHeader: commit.SignedHeader, + ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) + + return nil + }, + } +} + +func GetCmdQueryConnection(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "connection", + Short: "Query an existing connection", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + keeper := ibc.DummyKeeper() + + var conn ibc.Connection + connbz, _, err := query(ctx, keeper.Connection.Object(args[0]).Key()) + if err != nil { + return err + } + cdc.MustUnmarshalBinaryBare(connbz, &conn) + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, conn)) + + return nil + }, + } +} + +func GetCmdQueryChannel(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "channel", + Short: "Query an existing channel", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + keeper := ibc.DummyKeeper() + + var conn ibc.Channel + connbz, _, err := query(ctx, keeper.Channel.Object(args[0], args[1]).Key()) + if err != nil { + return err + } + cdc.MustUnmarshalBinaryBare(connbz, &conn) + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, conn)) + + return nil + }, + } +} + +func GetCmdQuerySendSequence(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "send-sequence", + Short: "Query the send sequence of a channel", + Args: cobra.ExactArgs(), + RunE: func(cmd *cobra.Command, args []string) error { + + }, + } +} + +func GetCmdQueryReceiveSequence(cdc *codec.Codec) *cobra.Command { + +} + +func GetCmdQueryPacket(cdc *codec.Codec) *cobra.Command { +} From a5d86b7c627f806d25a1f7d47942c4b6e0eaefcf Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 12:20:15 +0200 Subject: [PATCH 111/378] fin rebase --- x/ibc/02-client/tendermint/types.go | 2 +- x/ibc/02-client/tendermint/types_test.go | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 8dd3cfca7294..26a4c35370e6 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -37,7 +37,7 @@ func (cs ConsensusState) update(header Header) ConsensusState { return ConsensusState{ ChainID: cs.ChainID, Height: uint64(header.Height), - Root: header.AppHash, + Root: cs.GetRoot().Update(header.AppHash), NextValidatorSet: header.NextValidatorSet, } } diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go index 14ca7adad0ea..8bde76d10302 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/types_test.go @@ -24,7 +24,7 @@ import ( const chainid = "testchain" func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { - key := sdk.NewKVStoreKey("ibc") + key := sdk.NewKVStoreKey("test") db := dbm.NewMemDB() cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) @@ -91,6 +91,13 @@ func (node *node) Commit() tmtypes.SignedHeader { return commit } +func keyPrefix() [][]byte { + return [][]byte{ + []byte("test"), + []byte{0x00}, + } +} + type Verifier struct { ConsensusState } @@ -100,7 +107,7 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators) *Verifi ConsensusState{ ChainID: chainid, Height: uint64(header.Height), - Root: header.AppHash, + Root: merkle.NewRoot(header.AppHash, keyPrefix()), NextValidatorSet: nextvalset.ValidatorSet(), }, } @@ -168,7 +175,7 @@ func key(str []byte) []byte { } func (node *node) query(t *testing.T, k []byte) ([]byte, commitment.Proof) { - qres := node.cms.(stypes.Queryable).Query(abci.RequestQuery{Path: "/ibc/key", Data: key(k), Prove: true}) + qres := node.cms.(stypes.Queryable).Query(abci.RequestQuery{Path: "/test/key", Data: key(k), Prove: true}) require.Equal(t, uint32(0), qres.Code, qres.Log) proof := merkle.Proof{ Key: []byte(k), @@ -203,7 +210,7 @@ func testProof(t *testing.T) { require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } - cstore, err := commitment.NewStore([]byte(header.AppHash), proofs) + cstore, err := commitment.NewStore(merkle.NewRoot([]byte(header.AppHash), keyPrefix()), proofs) require.NoError(t, err) for _, kvp := range kvps { From acd44f3067b751f7bc4ee3137fb00ef7aa663468 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 16:07:00 +0200 Subject: [PATCH 112/378] in progress --- x/ibc/02-client/cli.go | 18 ++++++++++ x/ibc/02-client/manager.go | 34 ++++++++++--------- x/ibc/02-client/tendermint/types_test.go | 42 ++++++++++-------------- 3 files changed, 54 insertions(+), 40 deletions(-) create mode 100644 x/ibc/02-client/cli.go diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go new file mode 100644 index 000000000000..5c245ba0378e --- /dev/null +++ b/x/ibc/02-client/cli.go @@ -0,0 +1,18 @@ +package client + +import () + +// CLIObject stores the key for each object fields +type CLIObject struct { + ID string + ConsensusState []byte + Frozen []byte +} + +func (object Object) CLI() CLIObject { + return CLIObject{ + ID: object.id, + ConsensusState: object.consensusState.Key(), + Frozen: object.frozen.Key(), + } +} diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 196d62e62fdc..a99a4bcc785c 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -55,9 +55,9 @@ func (man Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { */ func (man Manager) object(id string) Object { return Object{ - id: id, - client: man.protocol.Value([]byte(id)), - freeze: state.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), + id: id, + consensusState: man.protocol.Value([]byte(id)), + frozen: state.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), } } @@ -67,7 +67,7 @@ func (man Manager) Create(ctx sdk.Context, cs ConsensusState) (Object, error) { if obj.exists(ctx) { return Object{}, errors.New("Create client on already existing id") } - obj.client.Set(ctx, cs) + obj.consensusState.Set(ctx, cs) return obj, nil } @@ -91,9 +91,9 @@ func (man CounterpartyManager) Query(id string) CounterObject { } type Object struct { - id string - client state.Value // ConsensusState - freeze state.Boolean + id string + consensusState state.Value // ConsensusState + frozen state.Boolean } type CounterObject struct { @@ -101,34 +101,38 @@ type CounterObject struct { client commitment.Value } -func (obj Object) exists(ctx sdk.Context) bool { - return obj.client.Exists(ctx) -} - func (obj Object) ID() string { return obj.id } -func (obj Object) Value(ctx sdk.Context) (res ConsensusState) { - obj.client.Get(ctx, &res) +func (obj Object) ConsensusState(ctx sdk.Context) (res ConsensusState) { + obj.consensusState.Get(ctx, &res) return } +func (obj Object) Frozen(ctx sdk.Context) bool { + return obj.frozen.Get(ctx) +} + func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { return obj.client.Is(ctx, client) } +func (obj Object) exists(ctx sdk.Context) bool { + return obj.consensusState.Exists(ctx) +} + func (obj Object) Update(ctx sdk.Context, header Header) error { if !obj.exists(ctx) { panic("should not update nonexisting client") } - if obj.freeze.Get(ctx) { + if obj.Frozen(ctx) { return errors.New("client is frozen") } var stored ConsensusState - obj.client.GetIfExists(ctx, &stored) + obj.client.Get(ctx, &stored) updated, err := stored.Validate(header) if err != nil { return err diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go index 8bde76d10302..3cb99f52b549 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/types_test.go @@ -91,23 +91,16 @@ func (node *node) Commit() tmtypes.SignedHeader { return commit } -func keyPrefix() [][]byte { - return [][]byte{ - []byte("test"), - []byte{0x00}, - } -} - type Verifier struct { ConsensusState } -func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators) *Verifier { +func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root merkle.Root) *Verifier { return &Verifier{ ConsensusState{ ChainID: chainid, Height: uint64(header.Height), - Root: merkle.NewRoot(header.AppHash, keyPrefix()), + Root: root.Update(header.AppHash), NextValidatorSet: nextvalset.ValidatorSet(), }, } @@ -129,12 +122,18 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset Mock return nil } +func newRoot() merkle.Root { + return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) +} + func testUpdate(t *testing.T, interval int, ok bool) { node := NewNode(NewMockValidators(100, 10)) node.Commit() - verifier := NewVerifier(node.last(), node.valset) + root := newRoot() + + verifier := NewVerifier(node.last(), node.valset, root) for i := 0; i < 100; i++ { header := node.Commit() @@ -170,22 +169,14 @@ func TestTenthBlockUpdate(t *testing.T) { } */ -func key(str []byte) []byte { - return append([]byte{0x00}, str...) -} - -func (node *node) query(t *testing.T, k []byte) ([]byte, commitment.Proof) { - qres := node.cms.(stypes.Queryable).Query(abci.RequestQuery{Path: "/test/key", Data: key(k), Prove: true}) - require.Equal(t, uint32(0), qres.Code, qres.Log) - proof := merkle.Proof{ - Key: []byte(k), - Proof: qres.Proof, - } - return qres.Value, proof +func (node *node) query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { + code, value, proof := root.Query(node.cms, k) + require.Equal(t, uint32(0), code) + return value, proof } func (node *node) Set(k, value []byte) { - node.store.Set(key(k), value) + node.store.Set(newRoot().Key(k), value) } func testProof(t *testing.T) { @@ -205,12 +196,13 @@ func testProof(t *testing.T) { } header := node.Commit() proofs := []commitment.Proof{} + root := newRoot().Update(header.AppHash) for _, kvp := range kvps { - v, p := node.query(t, []byte(kvp.Key)) + v, p := node.query(t, root.(merkle.Root), []byte(kvp.Key)) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } - cstore, err := commitment.NewStore(merkle.NewRoot([]byte(header.AppHash), keyPrefix()), proofs) + cstore, err := commitment.NewStore(root, proofs) require.NoError(t, err) for _, kvp := range kvps { From 582fd6ddd1778845fc05e8228b9a2f5b0d51b959 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 16:15:17 +0200 Subject: [PATCH 113/378] fin rebase --- x/ibc/02-client/manager.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index a99a4bcc785c..e94d14702b72 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -81,8 +81,8 @@ func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { func (man CounterpartyManager) object(id string) CounterObject { return CounterObject{ - id: id, - client: man.protocol.Value([]byte(id)), + id: id, + consensusState: man.protocol.Value([]byte(id)), } } @@ -97,8 +97,8 @@ type Object struct { } type CounterObject struct { - id string - client commitment.Value + id string + consensusState commitment.Value } func (obj Object) ID() string { @@ -115,7 +115,7 @@ func (obj Object) Frozen(ctx sdk.Context) bool { } func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { - return obj.client.Is(ctx, client) + return obj.consensusState.Is(ctx, client) } func (obj Object) exists(ctx sdk.Context) bool { @@ -132,13 +132,13 @@ func (obj Object) Update(ctx sdk.Context, header Header) error { } var stored ConsensusState - obj.client.Get(ctx, &stored) + obj.consensusState.Get(ctx, &stored) updated, err := stored.Validate(header) if err != nil { return err } - obj.client.Set(ctx, updated) + obj.consensusState.Set(ctx, updated) return nil } @@ -148,11 +148,11 @@ func (obj Object) Freeze(ctx sdk.Context) error { panic("should not freeze nonexisting client") } - if obj.freeze.Get(ctx) { + if obj.Frozen(ctx) { return errors.New("client is already frozen") } - obj.freeze.Set(ctx, true) + obj.frozen.Set(ctx, true) return nil } @@ -162,12 +162,12 @@ func (obj Object) Delete(ctx sdk.Context) error { panic("should not delete nonexisting client") } - if !obj.freeze.Get(ctx) { + if !obj.Frozen(ctx) { return errors.New("client is not frozen") } - obj.client.Delete(ctx) - obj.freeze.Delete(ctx) + obj.consensusState.Delete(ctx) + obj.frozen.Delete(ctx) return nil } From cb3081df2603576a06b837709b4390d3e3eb5ae0 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 17:10:21 +0200 Subject: [PATCH 114/378] add CLIObject in progress --- client/context/query.go | 38 ++++++++++++++++++++++++-------------- x/ibc/02-client/cli.go | 24 ++++++++++++++++-------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 87f96aece166..1e52442c6c61 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -31,21 +31,31 @@ func (ctx CLIContext) GetNode() (rpcclient.Client, error) { // Query performs a query to a Tendermint node with the provided path. // It returns the result and height of the query upon success or an error if // the query fails. -func (ctx CLIContext) Query(path string) ([]byte, int64, error) { - return ctx.query(path, nil) +func (ctx CLIContext) Query(path string) (val []byte, height int64, err error) { + val, _, height, err = ctx.query(path, nil) + return } // QueryWithData performs a query to a Tendermint node with the provided path // and a data payload. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryWithData(path string, data []byte) ([]byte, int64, error) { - return ctx.query(path, data) +func (ctx CLIContext) QueryWithData(path string, data []byte) (val []byte, height int64, err error) { + val, _, height, err = ctx.query(path, data) + return } // QueryStore performs a query to a Tendermint node with the provided key and // store name. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, int64, error) { +func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (val []byte, height int64, err error) { + val, _, height, err = ctx.queryStore(key, storeName, "key") + return +} + +// QueryProof performs a query to a Tendermint node with the provided key and +// store name. It returns the result, the proof, and height of the query +// upon success or an error if the query fails. +func (ctx CLIContext) QueryProof(key cmn.HexBytes, storeName string) (val []byte, proof *merkle.Proof, height int64, err error) { return ctx.queryStore(key, storeName, "key") } @@ -53,7 +63,7 @@ func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, in // store name and subspace. It returns key value pair and height of the query // upon success or an error if the query fails. func (ctx CLIContext) QuerySubspace(subspace []byte, storeName string) (res []sdk.KVPair, height int64, err error) { - resRaw, height, err := ctx.queryStore(subspace, storeName, "subspace") + resRaw, _, height, err := ctx.queryStore(subspace, storeName, "subspace") if err != nil { return res, height, err } @@ -75,10 +85,10 @@ func (ctx CLIContext) GetFromName() string { // query performs a query to a Tendermint node with the provided store name // and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) { +func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, proof *merkle.Proof, height int64, err error) { node, err := ctx.GetNode() if err != nil { - return res, height, err + return res, proof, height, err } opts := rpcclient.ABCIQueryOptions{ @@ -88,25 +98,25 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height i result, err := node.ABCIQueryWithOptions(path, key, opts) if err != nil { - return res, height, err + return res, proof, height, err } resp := result.Response if !resp.IsOK() { - return res, height, errors.New(resp.Log) + return res, proof, height, errors.New(resp.Log) } // data from trusted node or subspace query doesn't need verification if ctx.TrustNode || !isQueryStoreWithProof(path) { - return resp.Value, resp.Height, nil + return resp.Value, resp.Proof, resp.Height, nil } err = ctx.verifyProof(path, resp) if err != nil { - return res, height, err + return res, proof, height, err } - return resp.Value, resp.Height, nil + return resp.Value, resp.Proof, resp.Height, nil } // Verify verifies the consensus proof at given height. @@ -165,7 +175,7 @@ func (ctx CLIContext) verifyProof(queryPath string, resp abci.ResponseQuery) err // queryStore performs a query to a Tendermint node with the provided a store // name and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, int64, error) { +func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, *merkle.Proof, int64, error) { path := fmt.Sprintf("/store/%s/%s", storeName, endPath) return ctx.query(path, key) } diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 5c245ba0378e..8767c3032724 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -1,18 +1,26 @@ package client -import () +import ( + "github.com/cosmos/cosmos-sdk/client/context" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) // CLIObject stores the key for each object fields type CLIObject struct { - ID string - ConsensusState []byte - Frozen []byte + ID string + ConsensusStateKey []byte + FrozenKey []byte } -func (object Object) CLI() CLIObject { +func (obj Object) CLI() CLIObject { return CLIObject{ - ID: object.id, - ConsensusState: object.consensusState.Key(), - Frozen: object.frozen.Key(), + ID: obj.id, + ConsensusStateKey: obj.consensusState.Key(), + FrozenKey: obj.frozen.Key(), } } + +func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle..Proof) { + val, proof, _, err := ctx.QueryProof(obj.ConsensusStateKey) +} From e48fd1c2bd9eee01986028b0476e73716554321a Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 15:19:42 +0200 Subject: [PATCH 115/378] cli in progress --- client/context/query.go | 69 +++++++++++++++++++++++------------------ store/state/types.go | 5 +++ x/ibc/02-client/cli.go | 34 ++++++++++++++++++-- 3 files changed, 76 insertions(+), 32 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 1e52442c6c61..4738808ba4fe 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -31,39 +31,35 @@ func (ctx CLIContext) GetNode() (rpcclient.Client, error) { // Query performs a query to a Tendermint node with the provided path. // It returns the result and height of the query upon success or an error if // the query fails. -func (ctx CLIContext) Query(path string) (val []byte, height int64, err error) { - val, _, height, err = ctx.query(path, nil) - return +func (ctx CLIContext) Query(path string) ([]byte, int64, error) { + return ctx.query(path, nil) } // QueryWithData performs a query to a Tendermint node with the provided path // and a data payload. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryWithData(path string, data []byte) (val []byte, height int64, err error) { - val, _, height, err = ctx.query(path, data) - return +func (ctx CLIContext) QueryWithData(path string, data []byte) ([]byte, int64, error) { + return ctx.query(path, data) } // QueryStore performs a query to a Tendermint node with the provided key and // store name. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (val []byte, height int64, err error) { - val, _, height, err = ctx.queryStore(key, storeName, "key") - return +func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, int64, error) { + return ctx.queryStore(key, storeName, "key") } -// QueryProof performs a query to a Tendermint node with the provided key and -// store name. It returns the result, the proof, and height of the query -// upon success or an error if the query fails. -func (ctx CLIContext) QueryProof(key cmn.HexBytes, storeName string) (val []byte, proof *merkle.Proof, height int64, err error) { - return ctx.queryStore(key, storeName, "key") +// QueryABCI performs a query to a Tendermint node with the provide RequestQuery. +// It returns the ResultQuery obtained from the query. +func (ctx CLIContext) QueryABCI(req abci.RequestQuery) (abci.ResponseQuery, error) { + return ctx.queryABCI(req) } // QuerySubspace performs a query to a Tendermint node with the provided // store name and subspace. It returns key value pair and height of the query // upon success or an error if the query fails. func (ctx CLIContext) QuerySubspace(subspace []byte, storeName string) (res []sdk.KVPair, height int64, err error) { - resRaw, _, height, err := ctx.queryStore(subspace, storeName, "subspace") + resRaw, height, err := ctx.queryStore(subspace, storeName, "subspace") if err != nil { return res, height, err } @@ -82,13 +78,10 @@ func (ctx CLIContext) GetFromName() string { return ctx.FromName } -// query performs a query to a Tendermint node with the provided store name -// and path. It returns the result and height of the query upon success -// or an error if the query fails. -func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, proof *merkle.Proof, height int64, err error) { +func (ctx CLIContext) queryABCI(req abci.RequestQuery) (resp abci.ResponseQuery, err error) { node, err := ctx.GetNode() if err != nil { - return res, proof, height, err + return } opts := rpcclient.ABCIQueryOptions{ @@ -96,27 +89,43 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, proof *m Prove: !ctx.TrustNode, } - result, err := node.ABCIQueryWithOptions(path, key, opts) + result, err := node.ABCIQueryWithOptions(req.Path, req.Data, opts) if err != nil { - return res, proof, height, err + return } - resp := result.Response + resp = result.Response if !resp.IsOK() { - return res, proof, height, errors.New(resp.Log) + err = errors.New(resp.Log) + return } // data from trusted node or subspace query doesn't need verification - if ctx.TrustNode || !isQueryStoreWithProof(path) { - return resp.Value, resp.Proof, resp.Height, nil + if ctx.TrustNode || !isQueryStoreWithProof(req.Path) { + return resp, nil } - err = ctx.verifyProof(path, resp) + err = ctx.verifyProof(req.Path, resp) + if err != nil { + return + } + + return +} + +// query performs a query to a Tendermint node with the provided store name +// and path. It returns the result and height of the query upon success +// or an error if the query fails. +func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) { + resp, err := ctx.queryABCI(abci.RequestQuery{ + Path: path, + Data: key, + }) if err != nil { - return res, proof, height, err + return } - return resp.Value, resp.Proof, resp.Height, nil + return resp.Value, resp.Height, nil } // Verify verifies the consensus proof at given height. @@ -175,7 +184,7 @@ func (ctx CLIContext) verifyProof(queryPath string, resp abci.ResponseQuery) err // queryStore performs a query to a Tendermint node with the provided a store // name and path. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, *merkle.Proof, int64, error) { +func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, int64, error) { path := fmt.Sprintf("/store/%s/%s", storeName, endPath) return ctx.query(path, key) } diff --git a/store/state/types.go b/store/state/types.go index a8d34d582a82..f5dbb4dc8648 100644 --- a/store/state/types.go +++ b/store/state/types.go @@ -1,8 +1,13 @@ package state import ( + "github.com/tendermint/tendermint/crypto/merkle" + + "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" ) type KVStore = sdk.KVStore type Context = sdk.Context +type CLIContext = context.CLIContext +type Proof = merkle.Proof diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 8767c3032724..f51b882e7725 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -2,6 +2,7 @@ package client import ( "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) @@ -11,6 +12,7 @@ type CLIObject struct { ID string ConsensusStateKey []byte FrozenKey []byte + Cdc *codec.Codec } func (obj Object) CLI() CLIObject { @@ -21,6 +23,34 @@ func (obj Object) CLI() CLIObject { } } -func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle..Proof) { - val, proof, _, err := ctx.QueryProof(obj.ConsensusStateKey) +func query(ctx context.CLIContext, root merkle.Root, key []byte) ([]byte, merkle.Proof, error) { + resp, err := ctx.QueryABCI(root.RequestQuery(key)) + if err != nil { + return nil, merkle.Proof{}, err + } + proof := merkle.Proof{ + Key: key, + Proof: resp.Proof, + } + return resp.Value, proof, nil + +} + +func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle.Proof, err error) { + val, proof, err := query(ctx, root, obj.ConsensusStateKey) + obj.Cdc.MustUnmarshalBinaryBare(val, &res) + return +} + +func (obj CLIObject) Frozen(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { + val, tmproof, _, err := ctx.QueryProof(obj.FrozenKey, "ibc") // TODO + if err != nil { + return + } + proof = merkle.Proof{ + Key: obj.FrozenKey, + Proof: tmproof, + } + obj.Cdc.MustUnmarshalBinaryBare(val, &res) + return } From a372f5607fbfd290e8165f748d790cdc5742e818 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 15:40:30 +0200 Subject: [PATCH 116/378] add CLIObject --- x/ibc/02-client/cli.go | 31 ++++++++++------------- x/ibc/02-client/tendermint/types_test.go | 2 +- x/ibc/23-commitment/merkle/merkle_test.go | 12 ++++----- x/ibc/23-commitment/merkle/utils.go | 27 ++++++++++++-------- 4 files changed, 38 insertions(+), 34 deletions(-) diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index f51b882e7725..2592e697573c 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -12,45 +12,42 @@ type CLIObject struct { ID string ConsensusStateKey []byte FrozenKey []byte - Cdc *codec.Codec + + Root merkle.Root + Cdc *codec.Codec } -func (obj Object) CLI() CLIObject { +func (obj Object) CLI(root merkle.Root) CLIObject { return CLIObject{ ID: obj.id, ConsensusStateKey: obj.consensusState.Key(), FrozenKey: obj.frozen.Key(), + + Root: root, + Cdc: obj.consensusState.Cdc(), } } -func query(ctx context.CLIContext, root merkle.Root, key []byte) ([]byte, merkle.Proof, error) { - resp, err := ctx.QueryABCI(root.RequestQuery(key)) +func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { + resp, err := ctx.QueryABCI(obj.Root.RequestQuery(key)) if err != nil { - return nil, merkle.Proof{}, err + return merkle.Proof{}, err } proof := merkle.Proof{ Key: key, Proof: resp.Proof, } - return resp.Value, proof, nil + err = obj.Cdc.UnmarshalBinaryBare(resp.Value, ptr) + return proof, err } func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle.Proof, err error) { - val, proof, err := query(ctx, root, obj.ConsensusStateKey) - obj.Cdc.MustUnmarshalBinaryBare(val, &res) + proof, err = obj.query(ctx, obj.ConsensusStateKey, &res) return } func (obj CLIObject) Frozen(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { - val, tmproof, _, err := ctx.QueryProof(obj.FrozenKey, "ibc") // TODO - if err != nil { - return - } - proof = merkle.Proof{ - Key: obj.FrozenKey, - Proof: tmproof, - } - obj.Cdc.MustUnmarshalBinaryBare(val, &res) + proof, err = obj.query(ctx, obj.FrozenKey, &res) return } diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/types_test.go index 3cb99f52b549..2b89f9be11c8 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/types_test.go @@ -170,7 +170,7 @@ func TestTenthBlockUpdate(t *testing.T) { */ func (node *node) query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { - code, value, proof := root.Query(node.cms, k) + code, value, proof := root.QueryMultiStore(node.cms, k) require.Equal(t, uint32(0), code) return value, proof } diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index f93f64943609..dc7da05dfbc2 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -47,13 +47,13 @@ func TestStore(t *testing.T) { root := commit(cms) - c1, v1, p1 := path.Query(cms, []byte("hello")) + c1, v1, p1 := path.QueryMultiStore(cms, []byte("hello")) require.Equal(t, uint32(0), c1) require.Equal(t, []byte("world"), v1) - c2, v2, p2 := path.Query(cms, []byte("merkle")) + c2, v2, p2 := path.QueryMultiStore(cms, []byte("merkle")) require.Equal(t, uint32(0), c2) require.Equal(t, []byte("tree"), v2) - c3, v3, p3 := path.Query(cms, []byte("block")) + c3, v3, p3 := path.QueryMultiStore(cms, []byte("block")) require.Equal(t, uint32(0), c3) require.Equal(t, []byte("chain"), v3) @@ -70,13 +70,13 @@ func TestStore(t *testing.T) { root = commit(cms) - c1, v1, p1 = path.Query(cms, []byte("12345")) + c1, v1, p1 = path.QueryMultiStore(cms, []byte("12345")) require.Equal(t, uint32(0), c1) require.Equal(t, []byte("67890"), v1) - c2, v2, p2 = path.Query(cms, []byte("qwerty")) + c2, v2, p2 = path.QueryMultiStore(cms, []byte("qwerty")) require.Equal(t, uint32(0), c2) require.Equal(t, []byte("zxcv"), v2) - c3, v3, p3 = path.Query(cms, []byte("hello")) + c3, v3, p3 = path.QueryMultiStore(cms, []byte("hello")) require.Equal(t, uint32(0), c3) require.Equal(t, []byte("dlrow"), v3) diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index d2eabdaed99d..f122b0cd5383 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -7,22 +7,29 @@ import ( ) func (path Path) RequestQuery(key []byte) abci.RequestQuery { - pathstr := "" - for _, inter := range path.KeyPath { - pathstr = pathstr + "/" + string(inter) - } - pathstr = pathstr + "/key" - - data := append(path.KeyPrefix, key...) + req := path.RequestQueryMultiStore(key) + req.Path = "/store" + req.Path + return req +} - return abci.RequestQuery{Path: pathstr, Data: data, Prove: true} +func (path Path) RequestQueryMultiStore(key []byte) abci.RequestQuery { + return abci.RequestQuery{Path: path.Path() + "/key", Data: path.Key(key), Prove: true} } -func (path Path) Query(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { - qres := cms.(types.Queryable).Query(path.RequestQuery(key)) +func (path Path) QueryMultiStore(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { + qres := cms.(types.Queryable).Query(path.RequestQueryMultiStore(key)) return qres.Code, qres.Value, Proof{Key: key, Proof: qres.Proof} } func (path Path) Key(key []byte) []byte { return append(path.KeyPrefix, key...) // XXX: cloneAppend } + +func (path Path) Path() string { + pathstr := "" + for _, inter := range path.KeyPath { + pathstr = pathstr + "/" + string(inter) + } + + return pathstr +} From 67b1d73575e788bbcef119a8472cd18d573b0cb0 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 15:58:28 +0200 Subject: [PATCH 117/378] separate testing from tendermint --- .../tendermint/tests/tendermint_test.go | 58 ++++++++ .../{types_test.go => tests/types.go} | 125 ++++++------------ .../{valset_test.go => tests/valset.go} | 0 3 files changed, 98 insertions(+), 85 deletions(-) create mode 100644 x/ibc/02-client/tendermint/tests/tendermint_test.go rename x/ibc/02-client/tendermint/{types_test.go => tests/types.go} (57%) rename x/ibc/02-client/tendermint/{valset_test.go => tests/valset.go} (100%) diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go new file mode 100644 index 000000000000..29581e718e4c --- /dev/null +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -0,0 +1,58 @@ +package tendermint + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +func newRoot() merkle.Root { + return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) +} + +func testUpdate(t *testing.T, interval int, ok bool) { + node := NewNode(NewMockValidators(100, 10)) + + node.Commit() + + verifier := node.LastStateVerifier(newRoot()) + + for i := 0; i < 100; i++ { + header := node.Commit() + + if i%interval == 0 { + err := verifier.Validate(header, node.PrevValset, node.Valset) + if ok { + require.NoError(t, err) + } else { + require.Error(t, err) + } + } + } +} + +func TestEveryBlockUpdate(t *testing.T) { + testUpdate(t, 1, true) +} + +func TestEvenBlockUpdate(t *testing.T) { + testUpdate(t, 2, true) +} + +func TestSixthBlockUpdate(t *testing.T) { + testUpdate(t, 6, true) +} + +/* +// This should fail, since the amount of mutation is so large +// Commented out because it sometimes success +func TestTenthBlockUpdate(t *testing.T) { + testUpdate(t, 10, false) +} +*/ + +func TestProofs(t *testing.T) { + testProof(t) +} diff --git a/x/ibc/02-client/tendermint/types_test.go b/x/ibc/02-client/tendermint/tests/types.go similarity index 57% rename from x/ibc/02-client/tendermint/types_test.go rename to x/ibc/02-client/tendermint/tests/types.go index 2b89f9be11c8..f32cae8efc9d 100644 --- a/x/ibc/02-client/tendermint/types_test.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -17,6 +17,8 @@ import ( stypes "github.com/cosmos/cosmos-sdk/store/types" 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" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) @@ -37,44 +39,44 @@ func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *c return key, ctx, cms, cdc } -type node struct { - prevvalset MockValidators - valset MockValidators +type Node struct { + PrevValset MockValidators + Valset MockValidators - cms sdk.CommitMultiStore - store sdk.KVStore + Cms sdk.CommitMultiStore + Store sdk.KVStore - commits []tmtypes.SignedHeader + Commits []tmtypes.SignedHeader } -func NewNode(valset MockValidators) *node { +func NewNode(valset MockValidators) *Node { key, ctx, cms, _ := defaultComponents() - return &node{ - valset: valset, - cms: cms, - store: ctx.KVStore(key), - commits: nil, + return &Node{ + Valset: valset, + Cms: cms, + Store: ctx.KVStore(key), + Commits: nil, } } -func (node *node) last() tmtypes.SignedHeader { - if len(node.commits) == 0 { +func (node *Node) Last() tmtypes.SignedHeader { + if len(node.Commits) == 0 { return tmtypes.SignedHeader{} } - return node.commits[len(node.commits)-1] + return node.Commits[len(node.Commits)-1] } -func (node *node) Commit() tmtypes.SignedHeader { - valsethash := node.valset.ValidatorSet().Hash() - nextvalset := node.valset.Mutate() +func (node *Node) Commit() tmtypes.SignedHeader { + valsethash := node.Valset.ValidatorSet().Hash() + nextvalset := node.Valset.Mutate() nextvalsethash := nextvalset.ValidatorSet().Hash() - commitid := node.cms.Commit() + commitid := node.Cms.Commit() header := tmtypes.Header{ ChainID: chainid, - Height: int64(len(node.commits) + 1), + Height: int64(len(node.Commits) + 1), LastBlockID: tmtypes.BlockID{ - Hash: node.last().Header.Hash(), + Hash: node.Last().Header.Hash(), }, ValidatorsHash: valsethash, @@ -82,22 +84,26 @@ func (node *node) Commit() tmtypes.SignedHeader { AppHash: commitid.Hash, } - commit := node.valset.Sign(header) + commit := node.Valset.Sign(header) - node.prevvalset = node.valset - node.valset = nextvalset - node.commits = append(node.commits, commit) + node.PrevValset = node.Valset + node.Valset = nextvalset + node.Commits = append(node.Commits, commit) return commit } +func (node *Node) LastStateVerifier(root merkle.Root) *Verifier { + return NewVerifier(node.Last(), node.Valset, root) +} + type Verifier struct { - ConsensusState + client.ConsensusState } func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root merkle.Root) *Verifier { return &Verifier{ - ConsensusState{ + tendermint.ConsensusState{ ChainID: chainid, Height: uint64(header.Height), Root: root.Update(header.AppHash), @@ -108,7 +114,7 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root me func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset MockValidators) error { newcs, err := v.ConsensusState.Validate( - Header{ + tendermint.Header{ SignedHeader: header, ValidatorSet: valset.ValidatorSet(), NextValidatorSet: nextvalset.ValidatorSet(), @@ -117,66 +123,19 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset Mock if err != nil { return err } - v.ConsensusState = newcs.(ConsensusState) + v.ConsensusState = newcs.(tendermint.ConsensusState) return nil } -func newRoot() merkle.Root { - return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) -} - -func testUpdate(t *testing.T, interval int, ok bool) { - node := NewNode(NewMockValidators(100, 10)) - - node.Commit() - - root := newRoot() - - verifier := NewVerifier(node.last(), node.valset, root) - - for i := 0; i < 100; i++ { - header := node.Commit() - - if i%interval == 0 { - err := verifier.Validate(header, node.prevvalset, node.valset) - if ok { - require.NoError(t, err) - } else { - require.Error(t, err) - } - } - } -} - -func TestEveryBlockUpdate(t *testing.T) { - testUpdate(t, 1, true) -} - -func TestEvenBlockUpdate(t *testing.T) { - testUpdate(t, 2, true) -} - -func TestSixthBlockUpdate(t *testing.T) { - testUpdate(t, 6, true) -} - -/* -// This should fail, since the amount of mutation is so large -// Commented out because it sometimes success -func TestTenthBlockUpdate(t *testing.T) { - testUpdate(t, 10, false) -} -*/ - -func (node *node) query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { - code, value, proof := root.QueryMultiStore(node.cms, k) +func (node *Node) Query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { + code, value, proof := root.QueryMultiStore(node.Cms, k) require.Equal(t, uint32(0), code) return value, proof } -func (node *node) Set(k, value []byte) { - node.store.Set(newRoot().Key(k), value) +func (node *Node) Set(k, value []byte) { + node.Store.Set(newRoot().Key(k), value) } func testProof(t *testing.T) { @@ -198,7 +157,7 @@ func testProof(t *testing.T) { proofs := []commitment.Proof{} root := newRoot().Update(header.AppHash) for _, kvp := range kvps { - v, p := node.query(t, root.(merkle.Root), []byte(kvp.Key)) + v, p := node.Query(t, root.(merkle.Root), []byte(kvp.Key)) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } @@ -210,7 +169,3 @@ func testProof(t *testing.T) { } } } - -func TestProofs(t *testing.T) { - testProof(t) -} diff --git a/x/ibc/02-client/tendermint/valset_test.go b/x/ibc/02-client/tendermint/tests/valset.go similarity index 100% rename from x/ibc/02-client/tendermint/valset_test.go rename to x/ibc/02-client/tendermint/tests/valset.go From ee95a839d35e5c4f62f5647b3bc64f3d5434c74c Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 16:10:21 +0200 Subject: [PATCH 118/378] add key to node --- x/ibc/02-client/tendermint/tests/types.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index f32cae8efc9d..cc6d73592504 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -44,9 +44,12 @@ type Node struct { Valset MockValidators Cms sdk.CommitMultiStore + Key sdk.StoreKey Store sdk.KVStore Commits []tmtypes.SignedHeader + + Root merkle.Root } func NewNode(valset MockValidators) *Node { @@ -54,6 +57,7 @@ func NewNode(valset MockValidators) *Node { return &Node{ Valset: valset, Cms: cms, + Key: key, Store: ctx.KVStore(key), Commits: nil, } From b6865aa9490cbb0bb24cf2fb771d09b0ef534e8e Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 18:58:29 +0200 Subject: [PATCH 119/378] add root and storekey to tests/node, add codec --- x/ibc/02-client/codec.go | 10 ++++++++++ x/ibc/02-client/tendermint/codec.go | 11 +++++++++++ x/ibc/02-client/tendermint/tests/types.go | 8 ++++++-- x/ibc/02-client/tendermint/tests/valset.go | 1 + 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 x/ibc/02-client/codec.go create mode 100644 x/ibc/02-client/tendermint/codec.go diff --git a/x/ibc/02-client/codec.go b/x/ibc/02-client/codec.go new file mode 100644 index 000000000000..fa194562e4f1 --- /dev/null +++ b/x/ibc/02-client/codec.go @@ -0,0 +1,10 @@ +package client + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*ConsensusState)(nil), nil) + cdc.RegisterInterface((*Header)(nil), nil) +} diff --git a/x/ibc/02-client/tendermint/codec.go b/x/ibc/02-client/tendermint/codec.go new file mode 100644 index 000000000000..d8308a3e7ec8 --- /dev/null +++ b/x/ibc/02-client/tendermint/codec.go @@ -0,0 +1,11 @@ +package tendermint + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +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/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index cc6d73592504..88a27fd69f51 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -101,6 +101,10 @@ func (node *Node) LastStateVerifier(root merkle.Root) *Verifier { return NewVerifier(node.Last(), node.Valset, root) } +func (node *Node) Context() sdk.Context { + return sdk.NewContext(node.Cms, abci.Header{}, false, log.NewNopLogger()) +} + type Verifier struct { client.ConsensusState } @@ -139,7 +143,7 @@ func (node *Node) Query(t *testing.T, root merkle.Root, k []byte) ([]byte, commi } func (node *Node) Set(k, value []byte) { - node.Store.Set(newRoot().Key(k), value) + node.Store.Set(node.Root.Key(k), value) } func testProof(t *testing.T) { @@ -159,7 +163,7 @@ func testProof(t *testing.T) { } header := node.Commit() proofs := []commitment.Proof{} - root := newRoot().Update(header.AppHash) + root := node.Root.Update(header.AppHash) for _, kvp := range kvps { v, p := node.Query(t, root.(merkle.Root), []byte(kvp.Key)) require.Equal(t, kvp.Value, v) diff --git a/x/ibc/02-client/tendermint/tests/valset.go b/x/ibc/02-client/tendermint/tests/valset.go index 5649a3533273..0d97a5427c9b 100644 --- a/x/ibc/02-client/tendermint/tests/valset.go +++ b/x/ibc/02-client/tendermint/tests/valset.go @@ -84,6 +84,7 @@ type MockValidators []MockValidator var _ sort.Interface = MockValidators{} +// TODO: differenciate power between the vals func NewMockValidators(num int, power int64) MockValidators { res := make(MockValidators, num) for i := range res { From 631b72d0a13a66fd05cc0d5c45df240423452d99 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 12:22:46 +0200 Subject: [PATCH 120/378] rm cli/query.go --- x/ibc/client/cli/query.go | 216 -------------------------------------- 1 file changed, 216 deletions(-) delete mode 100644 x/ibc/client/cli/query.go diff --git a/x/ibc/client/cli/query.go b/x/ibc/client/cli/query.go deleted file mode 100644 index ca979151c499..000000000000 --- a/x/ibc/client/cli/query.go +++ /dev/null @@ -1,216 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/spf13/cobra" - - tmtypes "github.com/tendermint/tendermint/types" - - "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/02-client/tendermint" - ibc "github.com/cosmos/cosmos-sdk/x/ibc/keeper" -) - -func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - ibcQueryCmd := &cobra.Command{ - Use: "ibc", - Short: "IBC query subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - } - - ibcQueryCmd.AddCommand(client.GetCommands( - GetCmdQueryConsensusState(cdc), - GetCmdQueryHeader(cdc), - GetCmdQueryClient(cdc), - GetCmdQueryConnection(cdc), - GetCmdQueryChannel(cdc), - )...) - return ibcQueryCmd -} - -func GetCmdQueryClient(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "client", - Short: "Query stored client", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - keeper := ibc.DummyKeeper() - - var state ibc.ConsensusState - statebz, _, err := query(ctx, keeper.Client.Object(args[0]).Key()) - if err != nil { - return err - } - cdc.MustUnmarshalBinaryBare(statebz, &state) - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) - - return nil - }, - } -} - -func GetCmdQueryConsensusState(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "consensus-state", - Short: "Query the latest consensus state of the running chain", - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - node, err := ctx.GetNode() - if err != nil { - return err - } - - info, err := node.ABCIInfo() - if err != nil { - return err - } - - height := info.Response.LastBlockHeight - prevheight := height - 1 - - commit, err := node.Commit(&height) - if err != nil { - return err - } - - validators, err := node.Validators(&prevheight) - if err != nil { - return err - } - - state := tendermint.ConsensusState{ - ChainID: commit.ChainID, - Height: uint64(commit.Height), - Root: []byte(commit.AppHash), - NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - } - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) - - return nil - }, - } -} - -func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "header", - Short: "Query the latest header of the running chain", - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - node, err := ctx.GetNode() - if err != nil { - return err - } - - info, err := node.ABCIInfo() - if err != nil { - return err - } - - height := info.Response.LastBlockHeight - prevheight := height - 1 - - commit, err := node.Commit(&height) - if err != nil { - return err - } - - validators, err := node.Validators(&prevheight) - if err != nil { - return err - } - - nextvalidators, err := node.Validators(&height) - if err != nil { - return err - } - - header := tendermint.Header{ - SignedHeader: commit.SignedHeader, - ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), - } - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) - - return nil - }, - } -} - -func GetCmdQueryConnection(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "connection", - Short: "Query an existing connection", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - keeper := ibc.DummyKeeper() - - var conn ibc.Connection - connbz, _, err := query(ctx, keeper.Connection.Object(args[0]).Key()) - if err != nil { - return err - } - cdc.MustUnmarshalBinaryBare(connbz, &conn) - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, conn)) - - return nil - }, - } -} - -func GetCmdQueryChannel(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "channel", - Short: "Query an existing channel", - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - keeper := ibc.DummyKeeper() - - var conn ibc.Channel - connbz, _, err := query(ctx, keeper.Channel.Object(args[0], args[1]).Key()) - if err != nil { - return err - } - cdc.MustUnmarshalBinaryBare(connbz, &conn) - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, conn)) - - return nil - }, - } -} - -func GetCmdQuerySendSequence(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "send-sequence", - Short: "Query the send sequence of a channel", - Args: cobra.ExactArgs(), - RunE: func(cmd *cobra.Command, args []string) error { - - }, - } -} - -func GetCmdQueryReceiveSequence(cdc *codec.Codec) *cobra.Command { - -} - -func GetCmdQueryPacket(cdc *codec.Codec) *cobra.Command { -} From b9d89296eab4dfb18a1e8bf050fe6527e32b8687 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 18:21:20 +0200 Subject: [PATCH 121/378] fix test --- x/ibc/02-client/tendermint/tests/tendermint_test.go | 2 +- x/ibc/02-client/tendermint/tests/types.go | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go index 29581e718e4c..caf866337c47 100644 --- a/x/ibc/02-client/tendermint/tests/tendermint_test.go +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -13,7 +13,7 @@ func newRoot() merkle.Root { } func testUpdate(t *testing.T, interval int, ok bool) { - node := NewNode(NewMockValidators(100, 10)) + node := NewNode(NewMockValidators(100, 10), newRoot()) node.Commit() diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 88a27fd69f51..d0b7b488db39 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -52,7 +52,7 @@ type Node struct { Root merkle.Root } -func NewNode(valset MockValidators) *Node { +func NewNode(valset MockValidators, root merkle.Root) *Node { key, ctx, cms, _ := defaultComponents() return &Node{ Valset: valset, @@ -60,6 +60,7 @@ func NewNode(valset MockValidators) *Node { Key: key, Store: ctx.KVStore(key), Commits: nil, + Root: root, } } @@ -147,7 +148,7 @@ func (node *Node) Set(k, value []byte) { } func testProof(t *testing.T) { - node := NewNode(NewMockValidators(100, 10)) + node := NewNode(NewMockValidators(100, 10), newRoot()) node.Commit() From dbd6b8349713abf9f6851bb5a03848495b2b4ea1 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 18:26:23 +0200 Subject: [PATCH 122/378] fix lint --- x/ibc/02-client/tendermint/tests/valset.go | 2 +- x/ibc/02-client/tendermint/types.go | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/valset.go b/x/ibc/02-client/tendermint/tests/valset.go index 0d97a5427c9b..1b5f88aa949b 100644 --- a/x/ibc/02-client/tendermint/tests/valset.go +++ b/x/ibc/02-client/tendermint/tests/valset.go @@ -84,7 +84,7 @@ type MockValidators []MockValidator var _ sort.Interface = MockValidators{} -// TODO: differenciate power between the vals +// TODO: differentiate power between the vals func NewMockValidators(num int, power int64) MockValidators { res := make(MockValidators, num) for i := range res { diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 26a4c35370e6..6bb1bb1f18dd 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -48,11 +48,8 @@ func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, return nil, errors.New("invalid type") } - nextvalset := cs.NextValidatorSet - nexthash := nextvalset.Hash() - if cs.Height == uint64(header.Height-1) { - nexthash = cs.NextValidatorSet.Hash() + nexthash := cs.NextValidatorSet.Hash() if !bytes.Equal(header.ValidatorsHash, nexthash) { return nil, lerr.ErrUnexpectedValidators(header.ValidatorsHash, nexthash) } From f6e5f9011ce5da4e6a44c9bbdc383eec7fa533b8 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 19:12:36 +0200 Subject: [PATCH 123/378] fix lint --- .../tendermint/tests/tendermint_test.go | 6 ------ x/ibc/02-client/tendermint/tests/types.go | 16 ++++++++++++---- x/ibc/02-client/tendermint/tests/valset.go | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go index caf866337c47..8a1c764f50f2 100644 --- a/x/ibc/02-client/tendermint/tests/tendermint_test.go +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -4,14 +4,8 @@ import ( "testing" "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func newRoot() merkle.Root { - return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) -} - func testUpdate(t *testing.T, interval int, ok bool) { node := NewNode(NewMockValidators(100, 10), newRoot()) diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index d0b7b488db39..5e0af44f3806 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -1,7 +1,7 @@ package tendermint import ( - "math/rand" + "crypto/rand" "testing" "github.com/stretchr/testify/require" @@ -23,6 +23,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) +// nolint: unused +func newRoot() merkle.Root { + return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) +} + const chainid = "testchain" func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { @@ -147,6 +152,7 @@ func (node *Node) Set(k, value []byte) { node.Store.Set(node.Root.Key(k), value) } +// nolint:deadcode,unused func testProof(t *testing.T) { node := NewNode(NewMockValidators(100, 10), newRoot()) @@ -157,8 +163,10 @@ func testProof(t *testing.T) { for i := 0; i < 100; i++ { k := make([]byte, 32) v := make([]byte, 32) - rand.Read(k) - rand.Read(v) + _, err := rand.Read(k) + require.NoError(t, err) + _, err = rand.Read(v) + require.NoError(t, err) kvps = append(kvps, cmn.KVPair{Key: k, Value: v}) node.Set(k, v) } @@ -166,7 +174,7 @@ func testProof(t *testing.T) { proofs := []commitment.Proof{} root := node.Root.Update(header.AppHash) for _, kvp := range kvps { - v, p := node.Query(t, root.(merkle.Root), []byte(kvp.Key)) + v, p := node.Query(t, root.(merkle.Root), kvp.Key) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } diff --git a/x/ibc/02-client/tendermint/tests/valset.go b/x/ibc/02-client/tendermint/tests/valset.go index 1b5f88aa949b..30bd194682c8 100644 --- a/x/ibc/02-client/tendermint/tests/valset.go +++ b/x/ibc/02-client/tendermint/tests/valset.go @@ -131,7 +131,7 @@ func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { Height: header.Height, Type: tmtypes.PrecommitType, } - val.MockPV.SignVote(chainid, vote) + _ = val.MockPV.SignVote(chainid, vote) precommits[i] = vote.CommitSig() } From 892a12028f88b97c0f8c62594ae642bb585006a3 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 9 Jul 2019 23:53:46 +0900 Subject: [PATCH 124/378] add handler/msgs/client --- store/state/base.go | 12 +- x/ibc/02-client/cli.go | 9 +- x/ibc/02-client/client/cli/query.go | 159 ++++++++++++++++++++++++ x/ibc/02-client/client/cli/tx.go | 144 +++++++++++++++++++++ x/ibc/02-client/client/utils/receive.go | 94 ++++++++++++++ x/ibc/02-client/codec.go | 9 ++ x/ibc/02-client/handler.go | 29 +++++ x/ibc/02-client/manager.go | 15 +-- x/ibc/02-client/msgs.go | 69 ++++++++++ x/ibc/02-client/tendermint/codec.go | 7 +- 10 files changed, 526 insertions(+), 21 deletions(-) create mode 100644 x/ibc/02-client/client/cli/query.go create mode 100644 x/ibc/02-client/client/cli/tx.go create mode 100644 x/ibc/02-client/client/utils/receive.go create mode 100644 x/ibc/02-client/handler.go create mode 100644 x/ibc/02-client/msgs.go diff --git a/store/state/base.go b/store/state/base.go index f163c18b98a0..a6f429053248 100644 --- a/store/state/base.go +++ b/store/state/base.go @@ -15,13 +15,19 @@ type Base struct { } func EmptyBase() Base { - return NewBase(nil, nil) + return NewBase(nil, nil, nil) } -func NewBase(cdc *codec.Codec, key sdk.StoreKey) Base { +func NewBase(cdc *codec.Codec, key sdk.StoreKey, rootkey []byte) Base { + if len(rootkey) == 0 { + return Base{ + cdc: cdc, + storefn: func(ctx Context) KVStore { return ctx.KVStore(key) }, + } + } return Base{ cdc: cdc, - storefn: func(ctx Context) KVStore { return ctx.KVStore(key) }, + storefn: func(ctx Context) KVStore { return prefix.NewStore(ctx.KVStore(key), rootkey) }, } } diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 2592e697573c..45f2c9672a4d 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -17,9 +17,10 @@ type CLIObject struct { Cdc *codec.Codec } -func (obj Object) CLI(root merkle.Root) CLIObject { +func (man Manager) CLIObject(root merkle.Root, id string) CLIObject { + obj := man.object(id) return CLIObject{ - ID: obj.id, + ID: id, ConsensusStateKey: obj.consensusState.Key(), FrozenKey: obj.frozen.Key(), @@ -42,12 +43,12 @@ func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) } -func (obj CLIObject) ConsensusState(ctx context.CLIContext, root merkle.Root) (res ConsensusState, proof merkle.Proof, err error) { +func (obj CLIObject) ConsensusState(ctx context.CLIContext) (res ConsensusState, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.ConsensusStateKey, &res) return } -func (obj CLIObject) Frozen(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { +func (obj CLIObject) Frozen(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.FrozenKey, &res) return } diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go new file mode 100644 index 000000000000..2506ed8dd905 --- /dev/null +++ b/x/ibc/02-client/client/cli/query.go @@ -0,0 +1,159 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + tmtypes "github.com/tendermint/tendermint/types" + + 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" + + "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" +) + +func defaultRoot(storeKey string, root []byte) merkle.Root { + return merkle.NewRoot(root, [][]byte{[]byte(storeKey)}, []byte("protocol")) +} + +func defaultBase(cdc *codec.Codec) (state.Base, state.Base) { + protocol := state.NewBase(cdc, nil, []byte("protocol")) + free := state.NewBase(cdc, nil, []byte("free")) + return protocol, free +} + +func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ibcQueryCmd := &cobra.Command{ + Use: "ibc", + Short: "IBC query subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + ibcQueryCmd.AddCommand(cli.GetCommands( + GetCmdQueryConsensusState(storeKey, cdc), + GetCmdQueryHeader(cdc), + GetCmdQueryClient(storeKey, cdc), + )...) + return ibcQueryCmd +} + +func GetCmdQueryClient(storeKey string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "client", + Short: "Query stored client", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + man := client.NewManager(defaultBase(cdc)) + root := defaultRoot(storeKey, nil) + id := args[0] + + state, _, err := man.CLIObject(root, id).ConsensusState(ctx) + if err != nil { + return err + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + + return nil + }, + } +} + +func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "consensus-state", + Short: "Query the latest consensus state of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + node, err := ctx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return err + } + + state := tendermint.ConsensusState{ + ChainID: commit.ChainID, + Height: uint64(commit.Height), + Root: defaultRoot(storeKey, []byte(commit.AppHash)), + NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + + return nil + }, + } +} + +func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "header", + Short: "Query the latest header of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + node, err := ctx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return err + } + + nextvalidators, err := node.Validators(&height) + if err != nil { + return err + } + + header := tendermint.Header{ + SignedHeader: commit.SignedHeader, + ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) + + return nil + }, + } +} diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go new file mode 100644 index 000000000000..e654d76e7c3d --- /dev/null +++ b/x/ibc/02-client/client/cli/tx.go @@ -0,0 +1,144 @@ +package cli + +import ( + "errors" + "io/ioutil" + // "os" + + "github.com/spf13/cobra" + + // "github.com/tendermint/tendermint/libs/log" + rpcclient "github.com/tendermint/tendermint/rpc/client" + + 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/x/auth/client/utils" + // "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/ibc/02-client" + // "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +const ( + FlagStatePath = "state" + FlagClientID = "client-id" + FlagConnectionID = "connection-id" + FlagChannelID = "channel-id" + FlagCounterpartyID = "counterparty-id" + FlagCounterpartyClientID = "counterparty-client-id" + FlagSourceNode = "source-node" +) + +func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ibcTxCmd := &cobra.Command{ + Use: "ibc", + Short: "IBC transaction subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + ibcTxCmd.AddCommand(cli.PostCommands( + GetCmdCreateClient(cdc), + GetCmdUpdateClient(cdc), + )...) + + return ibcTxCmd +} + +func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "create-client", + Short: "create new client with a consensus state", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext(). + WithCodec(cdc) + + contents, err := ioutil.ReadFile(args[1]) + if err != nil { + return err + } + + var state client.ConsensusState + if err := cdc.UnmarshalJSON(contents, &state); err != nil { + return err + } + + msg := client.MsgCreateClient{ + ClientID: args[0], + ConsensusState: state, + Signer: cliCtx.GetFromAddress(), + } + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + + return cmd +} + +func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "update-client", + Short: "update existing client with a header", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext(). + WithCodec(cdc) + + contents, err := ioutil.ReadFile(args[1]) + if err != nil { + return err + } + + var header client.Header + if err := cdc.UnmarshalJSON(contents, &header); err != nil { + return err + } + + msg := client.MsgUpdateClient{ + ClientID: args[0], + Header: header, + Signer: cliCtx.GetFromAddress(), + } + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + + return cmd +} + +// Copied from client/context/query.go +func query(ctx context.CLIContext, key []byte) ([]byte, merkle.Proof, error) { + node, err := ctx.GetNode() + if err != nil { + return nil, merkle.Proof{}, err + } + + opts := rpcclient.ABCIQueryOptions{ + Height: ctx.Height, + Prove: true, + } + + result, err := node.ABCIQueryWithOptions("/store/ibc/key", key, opts) + if err != nil { + return nil, merkle.Proof{}, err + } + + resp := result.Response + if !resp.IsOK() { + return nil, merkle.Proof{}, errors.New(resp.Log) + } + + return resp.Value, merkle.Proof{ + Key: key, + Proof: resp.Proof, + }, nil +} diff --git a/x/ibc/02-client/client/utils/receive.go b/x/ibc/02-client/client/utils/receive.go new file mode 100644 index 000000000000..7a8df21189fb --- /dev/null +++ b/x/ibc/02-client/client/utils/receive.go @@ -0,0 +1,94 @@ +package cli + +import ( + "errors" + + "github.com/spf13/viper" + + rpcclient "github.com/tendermint/tendermint/rpc/client" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/store/state" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" + ibc "github.com/cosmos/cosmos-sdk/x/ibc/keeper" +) + +const ( + FlagStatePath = "state" + FlagClientID = "client-id" + FlagConnectionID = "connection-id" + FlagChannelID = "channel-id" + FlagCounterpartyID = "counterparty-id" + FlagCounterpartyClientID = "counterparty-client-id" + FlagSourceNode = "source-node" +) + +// Copied from client/context/query.go +func query(ctx context.CLIContext, key []byte) ([]byte, merkle.Proof, error) { + node, err := ctx.GetNode() + if err != nil { + return nil, merkle.Proof{}, err + } + + opts := rpcclient.ABCIQueryOptions{ + Height: ctx.Height, + Prove: true, + } + + result, err := node.ABCIQueryWithOptions("/store/ibc/key", key, opts) + if err != nil { + return nil, merkle.Proof{}, err + } + + resp := result.Response + if !resp.IsOK() { + return nil, merkle.Proof{}, errors.New(resp.Log) + } + + return resp.Value, merkle.Proof{ + Key: key, + Proof: resp.Proof, + }, nil +} + +func GetRelayPacket(cliCtxSource, cliCtx context.CLIContext) (ibc.Packet, ibc.Proof, error) { + keeper := ibc.DummyKeeper() + cdc := cliCtx.Codec + + connid := viper.GetString(FlagConnectionID) + chanid := viper.GetString(FlagChannelID) + + obj := keeper.Channel.Object(connid, chanid) + + seqbz, _, err := query(cliCtx, obj.Seqrecv.Key()) + if err != nil { + return nil, nil, err + } + seq, err := state.DecodeInt(seqbz, state.Dec) + if err != nil { + return nil, nil, err + } + + sentbz, _, err := query(cliCtxSource, obj.Seqsend.Key()) + if err != nil { + return nil, nil, err + } + sent, err := state.DecodeInt(sentbz, state.Dec) + if err != nil { + return nil, nil, err + } + + if seq == sent { + return nil, nil, errors.New("no packet detected") + } + + var packet ibc.Packet + packetbz, proof, err := query(cliCtxSource, obj.Packets.Value(seq).Key()) + if err != nil { + return nil, nil, err + } + cdc.MustUnmarshalBinaryBare(packetbz, &packet) + + return packet, proof, nil +} diff --git a/x/ibc/02-client/codec.go b/x/ibc/02-client/codec.go index fa194562e4f1..ece7e750dc98 100644 --- a/x/ibc/02-client/codec.go +++ b/x/ibc/02-client/codec.go @@ -4,7 +4,16 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) +var MsgCdc = codec.New() + +func init() { + RegisterCodec(MsgCdc) +} + func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*ConsensusState)(nil), nil) cdc.RegisterInterface((*Header)(nil), nil) + + cdc.RegisterConcrete(MsgCreateClient{}, "ibc/client/MsgCreateClient", nil) + cdc.RegisterConcrete(MsgUpdateClient{}, "ibc/client/MsgUpdateClient", nil) } diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go new file mode 100644 index 000000000000..dfab0725b8c4 --- /dev/null +++ b/x/ibc/02-client/handler.go @@ -0,0 +1,29 @@ +package client + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func HandleMsgCreateClient(ctx sdk.Context, msg MsgCreateClient, man Manager) sdk.Result { + _, err := man.Create(ctx, msg.ClientID, msg.ConsensusState) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(100), err.Error()).Result() + } + + // TODO: events + return sdk.Result{} +} + +func HandleMsgUpdateClient(ctx sdk.Context, msg MsgUpdateClient, man Manager) sdk.Result { + obj, err := man.Query(ctx, msg.ClientID) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(200), err.Error()).Result() + } + err = obj.Update(ctx, msg.Header) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(300), err.Error()).Result() + } + + // TODO: events + return sdk.Result{} +} diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index e94d14702b72..67d43a4325eb 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -2,7 +2,6 @@ package client import ( "errors" - "strconv" "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" @@ -12,25 +11,16 @@ import ( // XXX: implement spec: ClientState.verifiedRoots -type IDGenerator func(sdk.Context /*Header,*/, state.Value) string - -func IntegerIDGenerator(ctx sdk.Context, v state.Value) string { - id := state.NewInteger(v, state.Dec).Incr(ctx) - return strconv.FormatUint(id, 10) -} - type Manager struct { protocol state.Mapping idval state.Value - idgen IDGenerator } -func NewManager(protocol, free state.Base, idgen IDGenerator) Manager { +func NewManager(protocol, free state.Base) Manager { return Manager{ protocol: state.NewMapping(protocol, []byte("/client")), idval: state.NewValue(free, []byte("/client/id")), - idgen: idgen, } } @@ -61,8 +51,7 @@ func (man Manager) object(id string) Object { } } -func (man Manager) Create(ctx sdk.Context, cs ConsensusState) (Object, error) { - id := man.idgen(ctx, man.idval) +func (man Manager) Create(ctx sdk.Context, id string, cs ConsensusState) (Object, error) { obj := man.object(id) if obj.exists(ctx) { return Object{}, errors.New("Create client on already existing id") diff --git a/x/ibc/02-client/msgs.go b/x/ibc/02-client/msgs.go new file mode 100644 index 000000000000..7f515c388c8f --- /dev/null +++ b/x/ibc/02-client/msgs.go @@ -0,0 +1,69 @@ +package client + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type MsgCreateClient struct { + ClientID string + ConsensusState ConsensusState + Signer sdk.AccAddress +} + +var _ sdk.Msg = MsgCreateClient{} + +func (msg MsgCreateClient) Route() string { + return "ibc" +} + +func (msg MsgCreateClient) Type() string { + return "create-client" +} + +func (msg MsgCreateClient) ValidateBasic() sdk.Error { + if msg.Signer.Empty() { + return sdk.ErrInvalidAddress("empty address") + } + return nil +} + +func (msg MsgCreateClient) GetSignBytes() []byte { + bz := MsgCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg MsgCreateClient) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +type MsgUpdateClient struct { + ClientID string + Header Header + Signer sdk.AccAddress +} + +var _ sdk.Msg = MsgUpdateClient{} + +func (msg MsgUpdateClient) Route() string { + return "ibc" +} + +func (msg MsgUpdateClient) Type() string { + return "update-client" +} + +func (msg MsgUpdateClient) ValidateBasic() sdk.Error { + if msg.Signer.Empty() { + return sdk.ErrInvalidAddress("empty address") + } + return nil +} + +func (msg MsgUpdateClient) GetSignBytes() []byte { + bz := MsgCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg MsgUpdateClient) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} diff --git a/x/ibc/02-client/tendermint/codec.go b/x/ibc/02-client/tendermint/codec.go index d8308a3e7ec8..eca3b38917fa 100644 --- a/x/ibc/02-client/tendermint/codec.go +++ b/x/ibc/02-client/tendermint/codec.go @@ -2,10 +2,15 @@ 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) - } From dce114840b5933e839819e30b194c9a7c5ea47f6 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 9 Jul 2019 23:54:32 +0900 Subject: [PATCH 125/378] rm relay --- x/ibc/02-client/client/utils/receive.go | 94 ------------------------- 1 file changed, 94 deletions(-) delete mode 100644 x/ibc/02-client/client/utils/receive.go diff --git a/x/ibc/02-client/client/utils/receive.go b/x/ibc/02-client/client/utils/receive.go deleted file mode 100644 index 7a8df21189fb..000000000000 --- a/x/ibc/02-client/client/utils/receive.go +++ /dev/null @@ -1,94 +0,0 @@ -package cli - -import ( - "errors" - - "github.com/spf13/viper" - - rpcclient "github.com/tendermint/tendermint/rpc/client" - - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/store/state" - - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" - ibc "github.com/cosmos/cosmos-sdk/x/ibc/keeper" -) - -const ( - FlagStatePath = "state" - FlagClientID = "client-id" - FlagConnectionID = "connection-id" - FlagChannelID = "channel-id" - FlagCounterpartyID = "counterparty-id" - FlagCounterpartyClientID = "counterparty-client-id" - FlagSourceNode = "source-node" -) - -// Copied from client/context/query.go -func query(ctx context.CLIContext, key []byte) ([]byte, merkle.Proof, error) { - node, err := ctx.GetNode() - if err != nil { - return nil, merkle.Proof{}, err - } - - opts := rpcclient.ABCIQueryOptions{ - Height: ctx.Height, - Prove: true, - } - - result, err := node.ABCIQueryWithOptions("/store/ibc/key", key, opts) - if err != nil { - return nil, merkle.Proof{}, err - } - - resp := result.Response - if !resp.IsOK() { - return nil, merkle.Proof{}, errors.New(resp.Log) - } - - return resp.Value, merkle.Proof{ - Key: key, - Proof: resp.Proof, - }, nil -} - -func GetRelayPacket(cliCtxSource, cliCtx context.CLIContext) (ibc.Packet, ibc.Proof, error) { - keeper := ibc.DummyKeeper() - cdc := cliCtx.Codec - - connid := viper.GetString(FlagConnectionID) - chanid := viper.GetString(FlagChannelID) - - obj := keeper.Channel.Object(connid, chanid) - - seqbz, _, err := query(cliCtx, obj.Seqrecv.Key()) - if err != nil { - return nil, nil, err - } - seq, err := state.DecodeInt(seqbz, state.Dec) - if err != nil { - return nil, nil, err - } - - sentbz, _, err := query(cliCtxSource, obj.Seqsend.Key()) - if err != nil { - return nil, nil, err - } - sent, err := state.DecodeInt(sentbz, state.Dec) - if err != nil { - return nil, nil, err - } - - if seq == sent { - return nil, nil, errors.New("no packet detected") - } - - var packet ibc.Packet - packetbz, proof, err := query(cliCtxSource, obj.Packets.Value(seq).Key()) - if err != nil { - return nil, nil, err - } - cdc.MustUnmarshalBinaryBare(packetbz, &packet) - - return packet, proof, nil -} From 26e80388c4238d40c5d261f4cf932bd2a151ad8a Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 12 Jul 2019 01:33:18 +0900 Subject: [PATCH 126/378] finalize rebase on 23 root/path sep --- x/ibc/02-client/cli.go | 8 +++--- .../tendermint/tests/tendermint_test.go | 8 +++--- x/ibc/02-client/tendermint/tests/types.go | 26 +++++++++---------- x/ibc/02-client/tendermint/types.go | 3 ++- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 45f2c9672a4d..382b1d2d4aea 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -13,24 +13,24 @@ type CLIObject struct { ConsensusStateKey []byte FrozenKey []byte - Root merkle.Root + Path merkle.Path Cdc *codec.Codec } -func (man Manager) CLIObject(root merkle.Root, id string) CLIObject { +func (man Manager) CLIObject(path merkle.Path, id string) CLIObject { obj := man.object(id) return CLIObject{ ID: id, ConsensusStateKey: obj.consensusState.Key(), FrozenKey: obj.frozen.Key(), - Root: root, + Path: path, Cdc: obj.consensusState.Cdc(), } } func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { - resp, err := ctx.QueryABCI(obj.Root.RequestQuery(key)) + resp, err := ctx.QueryABCI(obj.Path.RequestQuery(key)) if err != nil { return merkle.Proof{}, err } diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go index 8a1c764f50f2..61a0944fbaa0 100644 --- a/x/ibc/02-client/tendermint/tests/tendermint_test.go +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -4,14 +4,16 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) func testUpdate(t *testing.T, interval int, ok bool) { - node := NewNode(NewMockValidators(100, 10), newRoot()) + node := NewNode(NewMockValidators(100, 10), newPath()) - node.Commit() + header := node.Commit() - verifier := node.LastStateVerifier(newRoot()) + verifier := node.LastStateVerifier(merkle.NewRoot(header.AppHash)) for i := 0; i < 100; i++ { header := node.Commit() diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 5e0af44f3806..f9fd9fc9f0c8 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -24,8 +24,8 @@ import ( ) // nolint: unused -func newRoot() merkle.Root { - return merkle.NewRoot(nil, [][]byte{[]byte("test")}, []byte{0x12, 0x34}) +func newPath() merkle.Path { + return merkle.NewPath([][]byte{[]byte("test")}, []byte{0x12, 0x34}) } const chainid = "testchain" @@ -54,10 +54,10 @@ type Node struct { Commits []tmtypes.SignedHeader - Root merkle.Root + Path merkle.Path } -func NewNode(valset MockValidators, root merkle.Root) *Node { +func NewNode(valset MockValidators, path merkle.Path) *Node { key, ctx, cms, _ := defaultComponents() return &Node{ Valset: valset, @@ -65,7 +65,7 @@ func NewNode(valset MockValidators, root merkle.Root) *Node { Key: key, Store: ctx.KVStore(key), Commits: nil, - Root: root, + Path: path, } } @@ -120,7 +120,7 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root me tendermint.ConsensusState{ ChainID: chainid, Height: uint64(header.Height), - Root: root.Update(header.AppHash), + Root: merkle.NewRoot(header.AppHash), NextValidatorSet: nextvalset.ValidatorSet(), }, } @@ -142,19 +142,19 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset Mock return nil } -func (node *Node) Query(t *testing.T, root merkle.Root, k []byte) ([]byte, commitment.Proof) { - code, value, proof := root.QueryMultiStore(node.Cms, k) +func (node *Node) Query(t *testing.T, path merkle.Path, k []byte) ([]byte, commitment.Proof) { + code, value, proof := path.QueryMultiStore(node.Cms, k) require.Equal(t, uint32(0), code) return value, proof } func (node *Node) Set(k, value []byte) { - node.Store.Set(node.Root.Key(k), value) + node.Store.Set(node.Path.Key(k), value) } // nolint:deadcode,unused func testProof(t *testing.T) { - node := NewNode(NewMockValidators(100, 10), newRoot()) + node := NewNode(NewMockValidators(100, 10), newPath()) node.Commit() @@ -172,13 +172,13 @@ func testProof(t *testing.T) { } header := node.Commit() proofs := []commitment.Proof{} - root := node.Root.Update(header.AppHash) + root := merkle.NewRoot(header.AppHash) for _, kvp := range kvps { - v, p := node.Query(t, root.(merkle.Root), kvp.Key) + v, p := node.Query(t, node.Path, kvp.Key) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } - cstore, err := commitment.NewStore(root, proofs) + cstore, err := commitment.NewStore(root, node.Path, proofs) require.NoError(t, err) for _, kvp := range kvps { diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index 6bb1bb1f18dd..ca5da8c1cae5 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) var _ client.ConsensusState = ConsensusState{} @@ -37,7 +38,7 @@ func (cs ConsensusState) update(header Header) ConsensusState { return ConsensusState{ ChainID: cs.ChainID, Height: uint64(header.Height), - Root: cs.GetRoot().Update(header.AppHash), + Root: merkle.NewRoot(header.AppHash), NextValidatorSet: header.NextValidatorSet, } } From 812bea4a62b62263866b87b3e716939a65b200b2 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 12 Jul 2019 01:35:54 +0900 Subject: [PATCH 127/378] fix lint, fix syntax --- x/ibc/02-client/client/cli/query.go | 10 +++++----- x/ibc/02-client/client/cli/tx.go | 31 ----------------------------- 2 files changed, 5 insertions(+), 36 deletions(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 2506ed8dd905..9de2231427bb 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -17,8 +17,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func defaultRoot(storeKey string, root []byte) merkle.Root { - return merkle.NewRoot(root, [][]byte{[]byte(storeKey)}, []byte("protocol")) +func defaultPath(storeKey string) merkle.Path { + return merkle.NewPath([][]byte{[]byte(storeKey)}, []byte("protocol")) } func defaultBase(cdc *codec.Codec) (state.Base, state.Base) { @@ -51,10 +51,10 @@ func GetCmdQueryClient(storeKey string, cdc *codec.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) man := client.NewManager(defaultBase(cdc)) - root := defaultRoot(storeKey, nil) + path := defaultPath(storeKey) id := args[0] - state, _, err := man.CLIObject(root, id).ConsensusState(ctx) + state, _, err := man.CLIObject(path, id).ConsensusState(ctx) if err != nil { return err } @@ -99,7 +99,7 @@ func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command state := tendermint.ConsensusState{ ChainID: commit.ChainID, Height: uint64(commit.Height), - Root: defaultRoot(storeKey, []byte(commit.AppHash)), + Root: merkle.NewRoot(commit.AppHash), NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), } diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index e654d76e7c3d..1b18dbe34783 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -1,14 +1,12 @@ package cli import ( - "errors" "io/ioutil" // "os" "github.com/spf13/cobra" // "github.com/tendermint/tendermint/libs/log" - rpcclient "github.com/tendermint/tendermint/rpc/client" cli "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" @@ -20,7 +18,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client" // "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) const ( @@ -114,31 +111,3 @@ func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { return cmd } - -// Copied from client/context/query.go -func query(ctx context.CLIContext, key []byte) ([]byte, merkle.Proof, error) { - node, err := ctx.GetNode() - if err != nil { - return nil, merkle.Proof{}, err - } - - opts := rpcclient.ABCIQueryOptions{ - Height: ctx.Height, - Prove: true, - } - - result, err := node.ABCIQueryWithOptions("/store/ibc/key", key, opts) - if err != nil { - return nil, merkle.Proof{}, err - } - - resp := result.Response - if !resp.IsOK() { - return nil, merkle.Proof{}, errors.New(resp.Log) - } - - return resp.Value, merkle.Proof{ - Key: key, - Proof: resp.Proof, - }, nil -} From 00df063c8adac70c4c15822ed1d72a828ecce78b Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 14 Jul 2019 04:45:14 +0900 Subject: [PATCH 128/378] fix querying --- store/state/base.go | 33 ++++++++++++----------- store/state/mapping.go | 4 +++ x/ibc/02-client/tendermint/tests/types.go | 14 +++++++--- x/ibc/03-connection/cli.go | 15 +++++++---- x/ibc/03-connection/handshake.go | 2 ++ x/ibc/03-connection/manager.go | 12 +++++++++ x/ibc/03-connection/tests/types.go | 2 ++ x/ibc/23-commitment/merkle/merkle.go | 10 ++++++- x/ibc/23-commitment/store.go | 7 ++--- x/ibc/23-commitment/types.go | 1 + 10 files changed, 73 insertions(+), 27 deletions(-) diff --git a/store/state/base.go b/store/state/base.go index a6f429053248..d4575f779679 100644 --- a/store/state/base.go +++ b/store/state/base.go @@ -9,9 +9,9 @@ import ( ) type Base struct { - cdc *codec.Codec - storefn func(Context) KVStore - prefix []byte + storeKey sdk.StoreKey + cdc *codec.Codec + prefix []byte } func EmptyBase() Base { @@ -19,20 +19,15 @@ func EmptyBase() Base { } func NewBase(cdc *codec.Codec, key sdk.StoreKey, rootkey []byte) Base { - if len(rootkey) == 0 { - return Base{ - cdc: cdc, - storefn: func(ctx Context) KVStore { return ctx.KVStore(key) }, - } - } return Base{ - cdc: cdc, - storefn: func(ctx Context) KVStore { return prefix.NewStore(ctx.KVStore(key), rootkey) }, + storeKey: key, + cdc: cdc, + prefix: rootkey, } } func (base Base) Store(ctx Context) KVStore { - return prefix.NewStore(base.storefn(ctx), base.prefix) + return prefix.NewStore(ctx.KVStore(base.storeKey), base.prefix) } func join(a, b []byte) (res []byte) { @@ -44,9 +39,9 @@ func join(a, b []byte) (res []byte) { func (base Base) Prefix(prefix []byte) (res Base) { res = Base{ - cdc: base.cdc, - storefn: base.storefn, - prefix: join(base.prefix, prefix), + storeKey: base.storeKey, + cdc: base.cdc, + prefix: join(base.prefix, prefix), } return } @@ -58,3 +53,11 @@ func (base Base) Cdc() *codec.Codec { func (base Base) key(key []byte) []byte { return join(base.prefix, key) } + +func (base Base) StoreName() string { + return base.storeKey.Name() +} + +func (base Base) PrefixBytes() []byte { + return base.prefix +} diff --git a/store/state/mapping.go b/store/state/mapping.go index 0d0ae990cf5a..cc3c2f8a4495 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -58,3 +58,7 @@ func (m Mapping) Prefix(prefix []byte) Mapping { func (m Mapping) Cdc() *Codec { return m.base.Cdc() } + +func (m Mapping) StoreName() string { + return m.base.StoreName() +} diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 1627f4451764..5c0d009095e6 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -143,9 +143,17 @@ func (v *Verifier) Validate(header tendermint.Header, valset, nextvalset MockVal } func (node *Node) Query(t *testing.T, k []byte) ([]byte, commitment.Proof) { - code, value, proof := node.Path.QueryMultiStore(node.Cms, k) - require.Equal(t, uint32(0), code) - return value, proof + resp := node.Cms.(stypes.Queryable).Query(abci.RequestQuery{ + Path: "/" + string(node.Path.KeyPath[0]) + "/key", + Data: k, + Prove: true, + }) + require.Equal(t, uint32(0), resp.Code) + proof := merkle.Proof{ + Key: k, + Proof: resp.Proof, + } + return resp.Value, proof } func (node *Node) Set(k, value []byte) { diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index 9334a251aec2..85a2e4d53ccf 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -1,6 +1,8 @@ package connection import ( + abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" @@ -17,8 +19,8 @@ type CLIObject struct { Client client.CLIObject - Path merkle.Path - Cdc *codec.Codec + StoreName string + Cdc *codec.Codec } func (man Manager) CLIObject(path merkle.Path, id string, clientid string) CLIObject { @@ -31,13 +33,16 @@ func (man Manager) CLIObject(path merkle.Path, id string, clientid string) CLIOb Client: man.client.CLIObject(path, clientid), - Path: path, - Cdc: obj.connection.Cdc(), + StoreName: man.protocol.StoreName(), + Cdc: obj.connection.Cdc(), } } func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { - resp, err := ctx.QueryABCI(obj.Path.RequestQuery(key)) + resp, err := ctx.QueryABCI(abci.RequestQuery{ + Path: "/store/" + obj.StoreName + "/key", + Data: key, + }) if err != nil { return merkle.Proof{}, err } diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index e96c805664bf..83f040457f8f 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -189,6 +189,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, if !obj.counterparty.connection.Is(ctx, Connection{ Client: counterpartyClient, Counterparty: id, + Path: obj.path, }) { err = errors.New("wrong counterparty connection") return @@ -261,6 +262,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, if !obj.counterparty.connection.Is(ctx, Connection{ Client: obj.CounterpartyClient(ctx), Counterparty: obj.ID(), + Path: obj.path, }) { err = errors.New("wrong counterparty") return diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index e5d32fafd454..41976053917a 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) type Manager struct { @@ -17,6 +18,8 @@ type Manager struct { client client.Manager counterparty CounterpartyManager + + path merkle.Path } func NewManager(protocol state.Base, client client.Manager) Manager { @@ -24,6 +27,7 @@ func NewManager(protocol state.Base, client client.Manager) Manager { protocol: state.NewMapping(protocol, ([]byte("/connection/"))), client: client, counterparty: NewCounterpartyManager(protocol.Cdc()), + path: merkle.NewPath([][]byte{[]byte(protocol.StoreName())}, protocol.PrefixBytes()), } } @@ -53,6 +57,8 @@ type Object struct { kind state.String client client.Object + + path merkle.Path } func (man Manager) object(id string) Object { @@ -66,6 +72,8 @@ func (man Manager) object(id string) Object { kind: state.NewString(man.protocol.Value([]byte(id + "/kind"))), // CONTRACT: client must be filled by the caller + + path: man.path, } } @@ -139,6 +147,10 @@ func (man Manager) create(ctx sdk.Context, id string, connection Connection, kin err = errors.New("Object already exists") return } + obj.client, err = man.client.Query(ctx, connection.Client) + if err != nil { + return + } obj.connection.Set(ctx, connection) obj.kind.Set(ctx, kind) return diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index 931163dfe6cf..608446439be0 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -48,10 +48,12 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { res.Connection = connection.Connection{ Counterparty: res.Counterparty.Name, + Path: res.Counterparty.Path, } res.Counterparty.Connection = connection.Connection{ Counterparty: res.Name, + Path: res.Path, } return res diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index 9fb11c7f38cb..5a0c6e9565a2 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -48,6 +48,13 @@ func (Path) CommitmentKind() string { return merkleKind } +func (path Path) Pathify(key []byte) (res []byte) { + res = make([]byte, len(path.KeyPrefix)+len(key)) + copy(res, path.KeyPrefix) + copy(res[len(path.KeyPrefix):], key) + return +} + var _ commitment.Proof = Proof{} type Proof struct { @@ -78,7 +85,8 @@ 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) + // KeyPrefix is not appended, we assume that the proof.Key already contains it + keypath = keypath.AppendKey(proof.Key, merkle.KeyEncodingHex) // Hard coded for now runtime := rootmulti.DefaultProofRuntime() diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index e3acb1158f34..7e469dcda483 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -72,11 +72,12 @@ func (store *store) Get(key []byte) ([]byte, bool) { } func (store *store) Prove(key, value []byte) bool { - stored, ok := store.Get(key) + pathkey := store.path.Pathify(key) + stored, ok := store.Get(pathkey) if ok && bytes.Equal(stored, value) { return true } - proof, ok := store.proofs[string(key)] + proof, ok := store.proofs[string(pathkey)] if !ok { return false } @@ -84,7 +85,7 @@ func (store *store) Prove(key, value []byte) bool { if err != nil { return false } - store.verified[string(key)] = value + store.verified[string(pathkey)] = value return true } diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go index 6453511a24e3..543965eb68f0 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/types.go @@ -6,6 +6,7 @@ type Root interface { type Path interface { CommitmentKind() string + Pathify([]byte) []byte } type Proof interface { From 19321f1cfed50f3deda880962b44cd7f401e38d0 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 14 Jul 2019 04:55:28 +0900 Subject: [PATCH 129/378] extract out context withstore --- x/ibc/03-connection/handshake.go | 27 +++------------------------ x/ibc/03-connection/manager.go | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index 83f040457f8f..467aa664b64b 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -164,18 +164,11 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - store, err := commitment.NewStore( - // TODO: proof root should be able to be obtained from the past - obj.client.ConsensusState(ctx).GetRoot(), - connection.Path, - []commitment.Proof{connectionp, statep, timeoutp, counterpartyClientp}, - ) + ctx, err = obj.Context(ctx, connection.Path, connectionp, statep, timeoutp, counterpartyClientp) if err != nil { return } - ctx = commitment.WithStore(ctx, store) - err = assertTimeout(ctx, timeoutHeight) if err != nil { return @@ -237,18 +230,11 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - store, err := commitment.NewStore( - // TODO: proof root should be able to be obtained from the past - obj.client.ConsensusState(ctx).GetRoot(), - obj.Connection(ctx).Path, - []commitment.Proof{connectionp, statep, timeoutp, counterpartyClientp}, - ) + ctx, err = obj.Context(ctx, nil, connectionp, statep, timeoutp, counterpartyClientp) if err != nil { return } - ctx = commitment.WithStore(ctx, store) - if !obj.state.Transit(ctx, Init, Open) { err = errors.New("ack on non-init connection") return @@ -307,18 +293,11 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, return } - store, err := commitment.NewStore( - // TODO: proof root should be able to be obtained from the past - obj.client.ConsensusState(ctx).GetRoot(), - obj.Connection(ctx).Path, - []commitment.Proof{statep, timeoutp}, - ) + ctx, err = obj.Context(ctx, nil, statep, timeoutp) if err != nil { return } - ctx = commitment.WithStore(ctx, store) - if !obj.state.Transit(ctx, OpenTry, Open) { err = errors.New("confirm on non-try connection") return diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 41976053917a..2663b4dcdcf4 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -102,6 +102,24 @@ 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.Connection(ctx).Path + } + + store, err := commitment.NewStore( + // TODO: proof root should be able to be obtained from the past + obj.client.ConsensusState(ctx).GetRoot(), + optpath, + proofs, + ) + if err != nil { + return ctx, err + } + + return commitment.WithStore(ctx, store), nil +} + func (obj Object) ID() string { return obj.id } From 486e862187c2cda48825b16ed846044eddc8409f Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 14 Jul 2019 05:11:14 +0900 Subject: [PATCH 130/378] fix 02-client test --- x/ibc/02-client/tendermint/tests/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 5c0d009095e6..1bb843698122 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -183,7 +183,7 @@ func testProof(t *testing.T) { proofs := []commitment.Proof{} root := merkle.NewRoot(header.AppHash) for _, kvp := range kvps { - v, p := node.Query(t, kvp.Key) + v, p := node.Query(t, node.Path.Key(kvp.Key)) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) From 67a3e1b63c9a38c6d35e068cf2b1c2e2f071823e Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 14 Jul 2019 05:20:25 +0900 Subject: [PATCH 131/378] fix 23-commitment test --- x/ibc/23-commitment/merkle/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index f122b0cd5383..43c14648fa15 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -18,7 +18,7 @@ func (path Path) RequestQueryMultiStore(key []byte) abci.RequestQuery { func (path Path) QueryMultiStore(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { qres := cms.(types.Queryable).Query(path.RequestQueryMultiStore(key)) - return qres.Code, qres.Value, Proof{Key: key, Proof: qres.Proof} + return qres.Code, qres.Value, Proof{Key: path.Key(key), Proof: qres.Proof} } func (path Path) Key(key []byte) []byte { From 8e660ea0c106c3e5c33e5cce5e74eeeea7238025 Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 15 Jul 2019 17:40:43 +0900 Subject: [PATCH 132/378] add query in progress --- x/ibc/03-connection/client/cli/query.go | 159 ++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 x/ibc/03-connection/client/cli/query.go diff --git a/x/ibc/03-connection/client/cli/query.go b/x/ibc/03-connection/client/cli/query.go new file mode 100644 index 000000000000..ba283c4cf97d --- /dev/null +++ b/x/ibc/03-connection/client/cli/query.go @@ -0,0 +1,159 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + tmtypes "github.com/tendermint/tendermint/types" + + 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" + + "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/merkle" +) + +func defaultPath(storeKey string) merkle.Path { + return merkle.NewPath([][]byte{[]byte(storeKey)}, []byte("protocol")) +} + +func defaultBase(cdc *codec.Codec) (state.Base, state.Base) { + protocol := state.NewBase(cdc, nil, []byte("protocol")) + free := state.NewBase(cdc, nil, []byte("free")) + return protocol, free +} + +func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ibcQueryCmd := &cobra.Command{ + Use: "connection", + Short: "Connection query subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + ibcQueryCmd.AddCommand(cli.GetCommands( + GetCmdQueryConnection(storeKey, cdc), + GetCmdQueryHandshake(storeKey, cdc), + )...) + return ibcQueryCmd +} + +func GetCmdQueryConnection(storeKey string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "connection", + Short: "Query stored connection", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + protocol, _ := defaultBase(cdc) + man := connection.NewManager(client.NewManager(protocol), protocol) + path := defaultPath(storeKey) + id := args[0] + + state, _, err := man.CLIObject(path, id).Connection(ctx) + if err != nil { + return err + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + + return nil + }, + } +} + +func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "consensus-state", + Short: "Query the latest consensus state of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + node, err := ctx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return err + } + + state := tendermint.ConsensusState{ + ChainID: commit.ChainID, + Height: uint64(commit.Height), + Root: merkle.NewRoot(commit.AppHash), + NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + + return nil + }, + } +} + +func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "header", + Short: "Query the latest header of the running chain", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + + node, err := ctx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return err + } + + nextvalidators, err := node.Validators(&height) + if err != nil { + return err + } + + header := tendermint.Header{ + SignedHeader: commit.SignedHeader, + ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) + + return nil + }, + } +} From dbd47aa9abcb66e59626a8aa5c51926798b39396 Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 15 Jul 2019 17:52:19 +0900 Subject: [PATCH 133/378] rm freebase, reformat query --- x/ibc/02-client/client/cli/query.go | 24 ++++++++++++------------ x/ibc/02-client/manager.go | 5 +---- x/ibc/version.go | 3 +++ 3 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 x/ibc/version.go diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 9de2231427bb..fb2c7f73da0e 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -2,6 +2,7 @@ package cli import ( "fmt" + "strconv" "github.com/spf13/cobra" @@ -11,26 +12,25 @@ import ( "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" + "github.com/cosmos/cosmos-sdk/x/ibc" "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" ) -func defaultPath(storeKey string) merkle.Path { - return merkle.NewPath([][]byte{[]byte(storeKey)}, []byte("protocol")) -} - -func defaultBase(cdc *codec.Codec) (state.Base, state.Base) { - protocol := state.NewBase(cdc, nil, []byte("protocol")) - free := state.NewBase(cdc, nil, []byte("free")) - return protocol, free +func components(cdc *codec.Codec, storeKey string, version int64) (path merkle.Path, base state.Base) { + prefix := []byte(strconv.FormatInt(version, 10) + "/") + path = merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) + base = state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) + return } func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ibcQueryCmd := &cobra.Command{ - Use: "ibc", - Short: "IBC query subcommands", + Use: "client", + Short: "IBC client query subcommands", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, } @@ -50,8 +50,8 @@ 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) - man := client.NewManager(defaultBase(cdc)) - path := defaultPath(storeKey) + path, base := components(cdc, storeKey, ibc.Version) + man := client.NewManager(base) id := args[0] state, _, err := man.CLIObject(path, id).ConsensusState(ctx) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 67d43a4325eb..4f5195bc1850 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -13,14 +13,11 @@ import ( type Manager struct { protocol state.Mapping - - idval state.Value } -func NewManager(protocol, free state.Base) Manager { +func NewManager(protocol state.Base) Manager { return Manager{ protocol: state.NewMapping(protocol, []byte("/client")), - idval: state.NewValue(free, []byte("/client/id")), } } diff --git a/x/ibc/version.go b/x/ibc/version.go new file mode 100644 index 000000000000..11bd8ee5b3d3 --- /dev/null +++ b/x/ibc/version.go @@ -0,0 +1,3 @@ +package ibc + +const Version int64 = 1 From 5584cebffe7c65bc1ce8b2744e404a3fe28db610 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 16 Jul 2019 04:10:06 +0900 Subject: [PATCH 134/378] add cli/handler/msg in progress --- x/ibc/03-connection/cli.go | 17 ++- x/ibc/03-connection/client/cli/query.go | 158 +++++++--------------- x/ibc/03-connection/client/cli/tx.go | 65 +++++++++ x/ibc/03-connection/client/utils/types.go | 59 ++++++++ x/ibc/03-connection/handler.go | 8 ++ x/ibc/03-connection/msgs.go | 68 ++++++++++ 6 files changed, 261 insertions(+), 114 deletions(-) create mode 100644 x/ibc/03-connection/client/cli/tx.go create mode 100644 x/ibc/03-connection/client/utils/types.go create mode 100644 x/ibc/03-connection/handler.go create mode 100644 x/ibc/03-connection/msgs.go diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index 85a2e4d53ccf..e85594ead21b 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -23,19 +23,24 @@ type CLIObject struct { Cdc *codec.Codec } -func (man Manager) CLIObject(path merkle.Path, id string, clientid string) CLIObject { +func (man Manager) CLIObject(ctx context.CLIContext, path merkle.Path, id string) CLIObject { obj := man.object(id) - return CLIObject{ + res := CLIObject{ ID: obj.id, ConnectionKey: obj.connection.Key(), AvailableKey: obj.available.Key(), KindKey: obj.kind.Key(), - Client: man.client.CLIObject(path, clientid), - StoreName: man.protocol.StoreName(), Cdc: obj.connection.Cdc(), } + + connection, _, err := res.Connection(ctx) + if err != nil { + return res + } + res.Client = man.client.CLIObject(path, connection.Client) + return res } func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { @@ -78,10 +83,10 @@ type CLIHandshakeObject struct { TimeoutKey []byte } -func (man Handshaker) CLIObject(path merkle.Path, id string, clientid string) CLIHandshakeObject { +func (man Handshaker) CLIObject(ctx context.CLIContext, path merkle.Path, id string) CLIHandshakeObject { obj := man.object(man.man.object(id)) return CLIHandshakeObject{ - CLIObject: man.man.CLIObject(path, id, clientid), + CLIObject: man.man.CLIObject(ctx, path, id), StateKey: obj.state.Key(), CounterpartyClientKey: obj.counterpartyClient.Key(), diff --git a/x/ibc/03-connection/client/cli/query.go b/x/ibc/03-connection/client/cli/query.go index ba283c4cf97d..da606af27c50 100644 --- a/x/ibc/03-connection/client/cli/query.go +++ b/x/ibc/03-connection/client/cli/query.go @@ -2,29 +2,35 @@ package cli import ( "fmt" + "strconv" "github.com/spf13/cobra" - - tmtypes "github.com/tendermint/tendermint/types" + "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" + "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/03-connection/client/utils" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func defaultPath(storeKey string) merkle.Path { - return merkle.NewPath([][]byte{[]byte(storeKey)}, []byte("protocol")) -} +const ( + FlagProve = "prove" +) -func defaultBase(cdc *codec.Codec) (state.Base, state.Base) { - protocol := state.NewBase(cdc, nil, []byte("protocol")) - free := state.NewBase(cdc, nil, []byte("free")) - return protocol, free +func object(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, id string) connection.CLIObject { + prefix := []byte(strconv.FormatInt(version, 10) + "/") + path := merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) + base := state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) + climan := client.NewManager(base) + man := connection.NewManager(base, climan) + return man.CLIObject(ctx, path, id) } func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { @@ -37,123 +43,59 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ibcQueryCmd.AddCommand(cli.GetCommands( GetCmdQueryConnection(storeKey, cdc), - GetCmdQueryHandshake(storeKey, cdc), )...) return ibcQueryCmd } -func GetCmdQueryConnection(storeKey string, cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "connection", - Short: "Query stored connection", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - protocol, _ := defaultBase(cdc) - man := connection.NewManager(client.NewManager(protocol), protocol) - path := defaultPath(storeKey) - id := args[0] - - state, _, err := man.CLIObject(path, id).Connection(ctx) - if err != nil { - return err - } - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) +func QueryConnection(ctx context.CLIContext, obj connection.CLIObject, prove bool) (res utils.JSONObject, err error) { + conn, connp, err := obj.Connection(ctx) + if err != nil { + return + } + avail, availp, err := obj.Available(ctx) + if err != nil { + return + } + kind, kindp, err := obj.Kind(ctx) + if err != nil { + return + } - return nil - }, + if prove { + return utils.NewJSONObject( + conn, connp, + avail, availp, + kind, kindp, + ), nil } + + return utils.NewJSONObject( + conn, nil, + avail, nil, + kind, nil, + ), nil } -func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "consensus-state", - Short: "Query the latest consensus state of the running chain", +func GetCmdQueryConnection(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "connection", + Short: "Query stored connection", + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) - - node, err := ctx.GetNode() - if err != nil { - return err - } - - info, err := node.ABCIInfo() - if err != nil { - return err - } - - height := info.Response.LastBlockHeight - prevheight := height - 1 - - commit, err := node.Commit(&height) - if err != nil { - return err - } - - validators, err := node.Validators(&prevheight) + obj := object(ctx, cdc, storeKey, ibc.Version, args[0]) + jsonobj, err := QueryConnection(ctx, obj, viper.GetBool(FlagProve)) if err != nil { return err } - state := tendermint.ConsensusState{ - ChainID: commit.ChainID, - Height: uint64(commit.Height), - Root: merkle.NewRoot(commit.AppHash), - NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - } - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, jsonobj)) return nil }, } -} - -func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "header", - Short: "Query the latest header of the running chain", - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - node, err := ctx.GetNode() - if err != nil { - return err - } + cmd.Flags().Bool(FlagProve, false, "(optional) show proofs for the query results") - info, err := node.ABCIInfo() - if err != nil { - return err - } - - height := info.Response.LastBlockHeight - prevheight := height - 1 - - commit, err := node.Commit(&height) - if err != nil { - return err - } - - validators, err := node.Validators(&prevheight) - if err != nil { - return err - } - - nextvalidators, err := node.Validators(&height) - if err != nil { - return err - } - - header := tendermint.Header{ - SignedHeader: commit.SignedHeader, - ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), - } - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) - - return nil - }, - } + return cmd } diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go new file mode 100644 index 000000000000..bbbfd8642860 --- /dev/null +++ b/x/ibc/03-connection/client/cli/tx.go @@ -0,0 +1,65 @@ +package cli + +import ( + "strconv" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "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" + + "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/merkle" +) + +/* +func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + +} +*/ +const ( + FlagNode1 = "node1" + FlagNode2 = "node2" + FlagFrom1 = "from1" + FlagFrom2 = "from2" +) + +func handshake(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, id string) connection.CLIHandshakeObject { + prefix := []byte(strconv.FormatInt(version, 10) + "/") + path := merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) + base := state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) + climan := client.NewManager(base) + man := connection.NewHandshaker(connection.NewManager(base, climan)) + return man.CLIObject(ctx, path, id) +} + +func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "handshake", + Short: "initiate connection handshake between two chains", + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + ctx1 := context.NewCLIContext(). + WithCodec(cdc). + WithNodeURI(viper.GetString(FlagNode1)). + WithFrom(viper.GetString(FlagFrom1)) + + ctx2 := context.NewCLIContext(). + WithCodec(cdc). + WithNodeURI(viper.GetString(FlagNode2)). + WithFrom(viper.GetString(FlagFrom2)) + + obj1 := object(ctx1, cdc, storeKey, ibc.Version, args[0]) + obj2 := object(ctx2, cdc, storeKey, ibc.Version, args[1]) + + }, + } +} diff --git a/x/ibc/03-connection/client/utils/types.go b/x/ibc/03-connection/client/utils/types.go new file mode 100644 index 000000000000..33480a68291f --- /dev/null +++ b/x/ibc/03-connection/client/utils/types.go @@ -0,0 +1,59 @@ +package utils + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +type JSONObject 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"` +} + +func NewJSONObject( + conn connection.Connection, connp commitment.Proof, + avail bool, availp commitment.Proof, + kind string, kindp commitment.Proof, +) JSONObject { + return JSONObject{ + Connection: conn, + ConnectionProof: connp, + Available: avail, + AvailableProof: availp, + Kind: kind, + KindProof: kindp, + } +} + +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( + 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), + State: state, + StateProof: statep, + CounterpartyClient: cpclient, + CounterpartyClientProof: cpclientp, + NextTimeout: timeout, + NextTimeoutProof: timeoutp, + } +} diff --git a/x/ibc/03-connection/handler.go b/x/ibc/03-connection/handler.go new file mode 100644 index 000000000000..7ed58cdb9f41 --- /dev/null +++ b/x/ibc/03-connection/handler.go @@ -0,0 +1,8 @@ +package connection + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func HandleMsgOpenInit(ctx sdk.Context, msg MsgOpenInit, man Manager) sdk.Result { +} diff --git a/x/ibc/03-connection/msgs.go b/x/ibc/03-connection/msgs.go new file mode 100644 index 000000000000..71f529927fd6 --- /dev/null +++ b/x/ibc/03-connection/msgs.go @@ -0,0 +1,68 @@ +package connection + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +type MsgOpenInit struct { + ConnectionID string + Connection Connection + CounterpartyClient string + NextTimeout uint64 + Signer sdk.AccAddress +} + +var _ sdk.Msg = MsgOpenInit{} + +func (msg MsgOpenInit) Route() string { + return "ibc" +} + +func (msg MsgOpenInit) Type() string { + return "open-init" +} + +func (msg MsgOpenInit) ValidateBasic() sdk.Error { + return nil // TODO +} + +func (msg MsgOpenInit) GetSignBytes() []byte { + return nil // TODO +} + +func (msg MsgOpenInit) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +type MsgOpenTry struct { + ConnectionID string + Connection Connection + CounterpartyClient string + Timeout uint64 + NextTimeout uint64 + Proofs []commitment.Proof + Signer sdk.AccAddress +} + +var _ sdk.Msg = MsgOpenTry{} + +type MsgOpenAck struct { + ConnectionID string + Timeout uint64 + NextTimeout uint64 + Proofs []commitment.Proof + Signer sdk.AccAddress +} + +var _ sdk.Msg = MsgOpenAck{} + +type MsgOpenConfirm struct { + ConnectionID string + Timeout uint64 + Proofs []commitment.Proof + Signer sdk.AccAddress +} + +var _ sdk.Msg = MsgOpenConfirm{} From 503a399a493e7f0d2fdf8f7f8ff351b96b1d00ab Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 17 Jul 2019 15:34:54 +0900 Subject: [PATCH 135/378] add cli/msg/handler --- x/ibc/03-connection/cli.go | 6 +- x/ibc/03-connection/client/cli/tx.go | 160 ++++++++++++++++++++++++++- x/ibc/03-connection/handler.go | 31 +++++- x/ibc/03-connection/handshake.go | 12 +- x/ibc/03-connection/manager.go | 2 +- x/ibc/03-connection/msgs.go | 60 ++++++++++ 6 files changed, 258 insertions(+), 13 deletions(-) diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index e85594ead21b..0f6ed658eba6 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -94,17 +94,17 @@ func (man Handshaker) CLIObject(ctx context.CLIContext, path merkle.Path, id str } } -func (obj CLIHandshakeObject) State(ctx context.CLIContext, root merkle.Root) (res byte, proof merkle.Proof, err error) { +func (obj CLIHandshakeObject) State(ctx context.CLIContext) (res byte, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.StateKey, &res) return } -func (obj CLIHandshakeObject) CounterpartyClient(ctx context.CLIContext, root merkle.Root) (res string, proof merkle.Proof, err error) { +func (obj CLIHandshakeObject) CounterpartyClient(ctx context.CLIContext) (res string, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.CounterpartyClientKey, &res) return } -func (obj CLIHandshakeObject) Timeout(ctx context.CLIContext, root merkle.Root) (res uint64, proof merkle.Proof, err error) { +func (obj CLIHandshakeObject) NextTimeout(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.TimeoutKey, &res) return } diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index bbbfd8642860..e29a402b2979 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -1,6 +1,7 @@ package cli import ( + "io/ioutil" "strconv" "github.com/spf13/cobra" @@ -16,6 +17,7 @@ import ( "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" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) @@ -40,11 +42,26 @@ func handshake(ctx context.CLIContext, cdc *codec.Codec, storeKey string, versio return man.CLIObject(ctx, path, id) } +func lastheight(ctx context.CLIContext) (uint64, error) { + node, err := ctx.GetNode() + if err != nil { + return 0, err + } + + info, err := node.ABCIInfo() + if err != nil { + return 0, err + } + + return uint64(info.Response.LastBlockHeight), nil +} + func GetCmdConnectionHandshake(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} RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) ctx1 := context.NewCLIContext(). @@ -57,9 +74,148 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command WithNodeURI(viper.GetString(FlagNode2)). WithFrom(viper.GetString(FlagFrom2)) - obj1 := object(ctx1, cdc, storeKey, ibc.Version, args[0]) - obj2 := object(ctx2, cdc, storeKey, ibc.Version, args[1]) + conn1id := args[0] + conn1bz, err := ioutil.ReadFile(args[1]) + if err != nil { + return err + } + var conn1 connection.Connection + if err := cdc.UnmarshalJSON(conn1bz, &conn1); err != nil { + return err + } + + obj1 := handshake(ctx1, cdc, storeKey, ibc.Version, conn1id) + + conn2id := args[2] + conn2bz, err := ioutil.ReadFile(args[3]) + if err != nil { + return err + } + var conn2 connection.Connection + if err := cdc.UnmarshalJSON(conn2bz, &conn2); err != nil { + return err + } + + obj2 := handshake(ctx2, cdc, storeKey, ibc.Version, conn1id) + + // 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, + Connection: conn1, + CounterpartyClient: conn2.Client, + NextTimeout: nextTimeout, + Signer: ctx1.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msginit}) + if err != nil { + return err + } + timeout := nextTimeout + height, err = lastheight(ctx1) + if err != nil { + return err + } + nextTimeout = height + 1000 + _, pconn, err := obj1.Connection(ctx1) + if err != nil { + return err + } + _, pstate, err := obj1.State(ctx1) + if err != nil { + return err + } + _, ptimeout, err := obj1.NextTimeout(ctx1) + if err != nil { + return err + } + _, pcounter, err := obj1.CounterpartyClient(ctx1) + if err != nil { + return err + } + + msgtry := connection.MsgOpenTry{ + ConnectionID: conn2id, + Connection: conn2, + CounterpartyClient: conn1.Client, + Timeout: timeout, + NextTimeout: nextTimeout, + Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, + Signer: ctx2.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgtry}) + if err != nil { + return err + } + + timeout = nextTimeout + height, err = lastheight(ctx2) + if err != nil { + return err + } + nextTimeout = height + 1000 + _, pconn, err = obj2.Connection(ctx2) + if err != nil { + return err + } + _, pstate, err = obj2.State(ctx2) + if err != nil { + return err + } + _, ptimeout, err = obj2.NextTimeout(ctx2) + if err != nil { + return err + } + _, pcounter, err = obj2.CounterpartyClient(ctx2) + if err != nil { + return err + } + + msgack := connection.MsgOpenAck{ + ConnectionID: conn1id, + Timeout: timeout, + NextTimeout: nextTimeout, + Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, + Signer: ctx1.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgack}) + if err != nil { + return err + } + + timeout = nextTimeout + _, pstate, err = obj1.State(ctx1) + if err != nil { + return err + } + _, ptimeout, err = obj1.NextTimeout(ctx1) + if err != nil { + return err + } + + msgconfirm := connection.MsgOpenConfirm{ + ConnectionID: conn2id, + Timeout: timeout, + Proofs: []commitment.Proof{pstate, ptimeout}, + Signer: ctx2.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgconfirm}) + if err != nil { + return err + } + + return nil }, } + + return cmd } diff --git a/x/ibc/03-connection/handler.go b/x/ibc/03-connection/handler.go index 7ed58cdb9f41..738ba38da7e0 100644 --- a/x/ibc/03-connection/handler.go +++ b/x/ibc/03-connection/handler.go @@ -4,5 +4,34 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -func HandleMsgOpenInit(ctx sdk.Context, msg MsgOpenInit, man Manager) sdk.Result { +func HandleMsgOpenInit(ctx sdk.Context, msg MsgOpenInit, man Handshaker) sdk.Result { + _, err := man.OpenInit(ctx, msg.ConnectionID, msg.Connection, msg.CounterpartyClient, msg.NextTimeout) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), 100, "").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) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), 200, "").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) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), 300, "").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) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), 400, "").Result() + } + return sdk.Result{} } diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index 467aa664b64b..c8a69c7fb9b5 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -156,7 +156,7 @@ func (man Handshaker) OpenInit(ctx sdk.Context, // Using proofs: counterparty.{connection,state,nextTimeout,counterpartyClient, client} func (man Handshaker) OpenTry(ctx sdk.Context, - connectionp, statep, timeoutp, counterpartyClientp /*, clientp*/ commitment.Proof, + proofs []commitment.Proof, id string, connection Connection, counterpartyClient string, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { obj, err = man.create(ctx, id, connection, counterpartyClient) @@ -164,7 +164,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - ctx, err = obj.Context(ctx, connection.Path, connectionp, statep, timeoutp, counterpartyClientp) + ctx, err = obj.Context(ctx, connection.Path, proofs) if err != nil { return } @@ -222,7 +222,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // Using proofs: counterparty.{connection, state, timeout, counterpartyClient, client} func (man Handshaker) OpenAck(ctx sdk.Context, - connectionp, statep, timeoutp, counterpartyClientp /*, clientp*/ commitment.Proof, + proofs []commitment.Proof, id string /*expheight uint64, */, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { obj, err = man.query(ctx, id) @@ -230,7 +230,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - ctx, err = obj.Context(ctx, nil, connectionp, statep, timeoutp, counterpartyClientp) + ctx, err = obj.Context(ctx, nil, proofs) if err != nil { return } @@ -285,7 +285,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, // Using proofs: counterparty.{connection,state, nextTimeout} func (man Handshaker) OpenConfirm(ctx sdk.Context, - statep, timeoutp commitment.Proof, + proofs []commitment.Proof, id string, timeoutHeight uint64) (obj HandshakeObject, err error) { obj, err = man.query(ctx, id) @@ -293,7 +293,7 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, return } - ctx, err = obj.Context(ctx, nil, statep, timeoutp) + ctx, err = obj.Context(ctx, nil, proofs) if err != nil { return } diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 2663b4dcdcf4..5a693d58c2e4 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -102,7 +102,7 @@ func (man CounterpartyManager) object(id string) CounterObject { } } -func (obj Object) Context(ctx sdk.Context, optpath commitment.Path, proofs ...commitment.Proof) (sdk.Context, error) { +func (obj Object) Context(ctx sdk.Context, optpath commitment.Path, proofs []commitment.Proof) (sdk.Context, error) { if optpath == nil { optpath = obj.Connection(ctx).Path } diff --git a/x/ibc/03-connection/msgs.go b/x/ibc/03-connection/msgs.go index 71f529927fd6..6ec74ef03696 100644 --- a/x/ibc/03-connection/msgs.go +++ b/x/ibc/03-connection/msgs.go @@ -48,6 +48,26 @@ type MsgOpenTry struct { var _ sdk.Msg = MsgOpenTry{} +func (msg MsgOpenTry) Route() string { + return "ibc" +} + +func (msg MsgOpenTry) Type() string { + return "open-init" +} + +func (msg MsgOpenTry) ValidateBasic() sdk.Error { + return nil // TODO +} + +func (msg MsgOpenTry) GetSignBytes() []byte { + return nil // TODO +} + +func (msg MsgOpenTry) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + type MsgOpenAck struct { ConnectionID string Timeout uint64 @@ -58,6 +78,26 @@ type MsgOpenAck struct { var _ sdk.Msg = MsgOpenAck{} +func (msg MsgOpenAck) Route() string { + return "ibc" +} + +func (msg MsgOpenAck) Type() string { + return "open-init" +} + +func (msg MsgOpenAck) ValidateBasic() sdk.Error { + return nil // TODO +} + +func (msg MsgOpenAck) GetSignBytes() []byte { + return nil // TODO +} + +func (msg MsgOpenAck) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + type MsgOpenConfirm struct { ConnectionID string Timeout uint64 @@ -66,3 +106,23 @@ type MsgOpenConfirm struct { } var _ sdk.Msg = MsgOpenConfirm{} + +func (msg MsgOpenConfirm) Route() string { + return "ibc" +} + +func (msg MsgOpenConfirm) Type() string { + return "open-init" +} + +func (msg MsgOpenConfirm) ValidateBasic() sdk.Error { + return nil // TODO +} + +func (msg MsgOpenConfirm) GetSignBytes() []byte { + return nil // TODO +} + +func (msg MsgOpenConfirm) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} From 3351a6adfef50a20db093fc8c718df887746ed7e Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 18 Jul 2019 03:02:41 +0900 Subject: [PATCH 136/378] add CLIQuery, fix tests --- x/ibc/03-connection/cli.go | 40 ++++++++++++++++++------- x/ibc/03-connection/client/cli/query.go | 2 +- x/ibc/03-connection/client/cli/tx.go | 2 +- x/ibc/03-connection/tests/types.go | 15 +++++----- 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index 0f6ed658eba6..a9617d4b0e38 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -23,24 +23,30 @@ type CLIObject struct { Cdc *codec.Codec } -func (man Manager) CLIObject(ctx context.CLIContext, path merkle.Path, id string) CLIObject { +func (man Manager) CLIQuery(ctx context.CLIContext, path merkle.Path, id string) CLIObject { + res := man.CLIObject(path, id, "") + + connection, _, err := res.Connection(ctx) + if err != nil { + return res + } + res.Client = man.client.CLIObject(path, connection.Client) + return res +} + +func (man Manager) CLIObject(path merkle.Path, id, clientid string) CLIObject { obj := man.object(id) - res := CLIObject{ + return CLIObject{ ID: obj.id, ConnectionKey: obj.connection.Key(), AvailableKey: obj.available.Key(), KindKey: obj.kind.Key(), + Client: man.client.CLIObject(path, clientid), + StoreName: man.protocol.StoreName(), Cdc: obj.connection.Cdc(), } - - connection, _, err := res.Connection(ctx) - if err != nil { - return res - } - res.Client = man.client.CLIObject(path, connection.Client) - return res } func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { @@ -83,10 +89,10 @@ type CLIHandshakeObject struct { TimeoutKey []byte } -func (man Handshaker) CLIObject(ctx context.CLIContext, path merkle.Path, id string) CLIHandshakeObject { +func (man Handshaker) CLIQuery(ctx context.CLIContext, path merkle.Path, id string) CLIHandshakeObject { obj := man.object(man.man.object(id)) return CLIHandshakeObject{ - CLIObject: man.man.CLIObject(ctx, path, id), + CLIObject: man.man.CLIQuery(ctx, path, id), StateKey: obj.state.Key(), CounterpartyClientKey: obj.counterpartyClient.Key(), @@ -94,6 +100,18 @@ func (man Handshaker) CLIObject(ctx context.CLIContext, path merkle.Path, id str } } +func (man Handshaker) CLIObject(path merkle.Path, id, clientid string) CLIHandshakeObject { + obj := man.object(man.man.object(id)) + return CLIHandshakeObject{ + CLIObject: man.man.CLIObject(path, id, clientid), + + StateKey: obj.state.Key(), + CounterpartyClientKey: obj.counterpartyClient.Key(), + TimeoutKey: obj.nextTimeout.Key(), + } + +} + func (obj CLIHandshakeObject) State(ctx context.CLIContext) (res byte, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.StateKey, &res) return diff --git a/x/ibc/03-connection/client/cli/query.go b/x/ibc/03-connection/client/cli/query.go index da606af27c50..efc30534e913 100644 --- a/x/ibc/03-connection/client/cli/query.go +++ b/x/ibc/03-connection/client/cli/query.go @@ -30,7 +30,7 @@ func object(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version i base := state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) climan := client.NewManager(base) man := connection.NewManager(base, climan) - return man.CLIObject(ctx, path, id) + return man.CLIQuery(ctx, path, id) } func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index e29a402b2979..0aaa1c5cda27 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -39,7 +39,7 @@ func handshake(ctx context.CLIContext, cdc *codec.Codec, storeKey string, versio base := state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) climan := client.NewManager(base) man := connection.NewHandshaker(connection.NewManager(base, climan)) - return man.CLIObject(ctx, path, id) + return man.CLIQuery(ctx, path, id) } func lastheight(ctx context.CLIContext) (uint64, error) { diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index 608446439be0..0b4444b05338 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -93,15 +93,14 @@ func (node *Node) CLIObject() connection.CLIHandshakeObject { return connection.NewHandshaker(man).CLIObject(node.Path, node.Name, node.Name) } -func base(cdc *codec.Codec, key sdk.StoreKey) (state.Base, state.Base) { +func base(cdc *codec.Codec, key sdk.StoreKey) state.Base { protocol := state.NewBase(cdc, key, []byte("protocol")) - free := state.NewBase(cdc, key, []byte("free")) - return protocol, free + return protocol } func (node *Node) Manager() (client.Manager, connection.Manager) { - protocol, free := base(node.Cdc, node.Key) - clientman := client.NewManager(protocol, free) + protocol := base(node.Cdc, node.Key) + clientman := client.NewManager(protocol) return clientman, connection.NewManager(protocol, clientman) } @@ -118,7 +117,7 @@ func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenTry(ctx, proofs[0], proofs[1], proofs[2], proofs[3], node.Name, node.Connection, node.CounterpartyClient, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenTry(ctx, proofs, node.Name, node.Connection, node.CounterpartyClient, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.OpenTry, obj.State(ctx)) require.Equal(t, node.Connection, obj.Connection(ctx)) @@ -129,7 +128,7 @@ func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenAck(ctx, proofs[0], proofs[1], proofs[2], proofs[3], node.Name, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenAck(ctx, proofs, node.Name, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.Open, obj.State(ctx)) require.Equal(t, node.Connection, obj.Connection(ctx)) @@ -139,7 +138,7 @@ func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenConfirm(ctx, proofs[0], proofs[1], node.Name, 100 /*TODO*/) + obj, err := man.OpenConfirm(ctx, proofs, node.Name, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.Open, obj.State(ctx)) require.Equal(t, node.Connection, obj.Connection(ctx)) From bed527607a2645995cf67e19ede49b29671183ad Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 19 Jul 2019 00:55:18 +0900 Subject: [PATCH 137/378] fix golangci --- x/ibc/03-connection/msgs.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/x/ibc/03-connection/msgs.go b/x/ibc/03-connection/msgs.go index 6ec74ef03696..3944599ff6a3 100644 --- a/x/ibc/03-connection/msgs.go +++ b/x/ibc/03-connection/msgs.go @@ -6,6 +6,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) +const Route = "ibc" + type MsgOpenInit struct { ConnectionID string Connection Connection @@ -17,7 +19,7 @@ type MsgOpenInit struct { var _ sdk.Msg = MsgOpenInit{} func (msg MsgOpenInit) Route() string { - return "ibc" + return Route } func (msg MsgOpenInit) Type() string { @@ -49,11 +51,11 @@ type MsgOpenTry struct { var _ sdk.Msg = MsgOpenTry{} func (msg MsgOpenTry) Route() string { - return "ibc" + return Route } func (msg MsgOpenTry) Type() string { - return "open-init" + return "open-try" } func (msg MsgOpenTry) ValidateBasic() sdk.Error { @@ -79,11 +81,11 @@ type MsgOpenAck struct { var _ sdk.Msg = MsgOpenAck{} func (msg MsgOpenAck) Route() string { - return "ibc" + return Route } func (msg MsgOpenAck) Type() string { - return "open-init" + return "open-ack" } func (msg MsgOpenAck) ValidateBasic() sdk.Error { @@ -108,11 +110,11 @@ type MsgOpenConfirm struct { var _ sdk.Msg = MsgOpenConfirm{} func (msg MsgOpenConfirm) Route() string { - return "ibc" + return Route } func (msg MsgOpenConfirm) Type() string { - return "open-init" + return "open-confirm" } func (msg MsgOpenConfirm) ValidateBasic() sdk.Error { From f60924903d6531df2be76e6f698f4c2341041043 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 25 Jul 2019 01:20:19 +0900 Subject: [PATCH 138/378] add docs in progre --- store/state/base.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/store/state/base.go b/store/state/base.go index 25760b77a947..280ae70e7ad9 100644 --- a/store/state/base.go +++ b/store/state/base.go @@ -8,6 +8,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// Base is a state accessor base layer, consists of Codec, KVStore getter function, and key prefix. +// type Base struct { cdc *codec.Codec storefn func(Context) KVStore From 7da69c124e97a99a042a5f201ed4642774097a58 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 26 Jul 2019 00:47:41 +0900 Subject: [PATCH 139/378] add comments --- store/state/base.go | 48 ++++++++++++++++++++--------- store/state/boolean.go | 2 ++ store/state/enum.go | 5 +++ store/state/errors.go | 56 +++++++++++++++++++++++++++++++++ store/state/indexer.go | 25 +++++---------- store/state/integer.go | 27 +++++----------- store/state/mapping.go | 16 +++------- store/state/string.go | 25 +++++++++++++++ store/state/value.go | 70 ++++++++++-------------------------------- 9 files changed, 158 insertions(+), 116 deletions(-) create mode 100644 store/state/errors.go create mode 100644 store/state/string.go diff --git a/store/state/base.go b/store/state/base.go index 280ae70e7ad9..19d85ffb16f4 100644 --- a/store/state/base.go +++ b/store/state/base.go @@ -8,27 +8,29 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// Base is a state accessor base layer, consists of Codec, KVStore getter function, and key prefix. +// Base is a state accessor base layer, consists of Codec, StoreKey, and prefix. +// StoreKey is used to get the KVStore, cdc is used to marshal/unmarshal the interfaces, +// and the prefix is prefixed to the key. // +// Base has practically the same capability with the storeKey. +// It should not be passed to an untrusted actor. type Base struct { - cdc *codec.Codec - storefn func(Context) KVStore - prefix []byte + storeKey sdk.StoreKey + cdc *codec.Codec + prefix []byte } -func EmptyBase() Base { - return NewBase(nil, nil) -} - -func NewBase(cdc *codec.Codec, key sdk.StoreKey) Base { +// NewBase() is the constructor for Base() +func NewBase(cdc *codec.Codec, key sdk.StoreKey, rootkey []byte) Base { return Base{ - cdc: cdc, - storefn: func(ctx Context) KVStore { return ctx.KVStore(key) }, + storeKey: key, + cdc: cdc, + prefix: rootkey, } } func (base Base) store(ctx Context) KVStore { - return prefix.NewStore(base.storefn(ctx), base.prefix) + return prefix.NewStore(ctx.KVStore(base.storeKey), base.prefix) } func join(a, b []byte) (res []byte) { @@ -38,15 +40,17 @@ func join(a, b []byte) (res []byte) { return } +// Prefix() returns a copy of the Base with the updated prefix. func (base Base) Prefix(prefix []byte) (res Base) { res = Base{ - cdc: base.cdc, - storefn: base.storefn, - prefix: join(base.prefix, prefix), + storeKey: base.storeKey, + cdc: base.cdc, + prefix: join(base.prefix, prefix), } return } +// Cdc() returns the codec of the base. It is safe to expose the codec. func (base Base) Cdc() *codec.Codec { return base.cdc } @@ -54,3 +58,17 @@ func (base Base) Cdc() *codec.Codec { func (base Base) key(key []byte) []byte { return join(base.prefix, key) } + +// StoreName() returns the name of the storeKey. It is safe to expose the store name. +// Used by the CLI side query operations. +func (base Base) StoreName() string { + return base.storeKey.Name() +} + +// PrefixBytes() returns the prefix bytes. It is safe to expsoe the prefix bytes. +// Used by the CLI side query operations. +func (base Base) PrefixBytes() (res []byte) { + res = make([]byte, len(base.prefix)) + copy(res, base.prefix) + return +} diff --git a/store/state/boolean.go b/store/state/boolean.go index 2fb3701680be..dab4d5bbf67e 100644 --- a/store/state/boolean.go +++ b/store/state/boolean.go @@ -1,5 +1,7 @@ package state +// Boolean is a bool typed wrapper for Value. +// Except for the type checking, it does not alter the behaviour. type Boolean struct { Value } diff --git a/store/state/enum.go b/store/state/enum.go index 8598f10324b7..57fbdc9f3e92 100644 --- a/store/state/enum.go +++ b/store/state/enum.go @@ -1,5 +1,7 @@ package state +// Enum is a byte typed wrapper for Value. +// Except for the type checking, it does not alter the behaviour. type Enum struct { Value } @@ -22,12 +24,15 @@ func (v Enum) Set(ctx Context, value byte) { v.Value.Set(ctx, value) } +// Incr() increments the stored value, and returns the updated value. func (v Enum) Incr(ctx Context) (res byte) { res = v.Get(ctx) + 1 v.Set(ctx, res) return } +// Transit() checks whether the stored value matching with the "from" argument. +// If it matches, it stores the "to" argument to the state and returns true. func (v Enum) Transit(ctx Context, from, to byte) bool { if v.Get(ctx) != from { return false diff --git a/store/state/errors.go b/store/state/errors.go new file mode 100644 index 000000000000..936066b0ac29 --- /dev/null +++ b/store/state/errors.go @@ -0,0 +1,56 @@ +package state + +import ( + "fmt" +) + +type GetSafeErrorType byte + +const ( + ErrTypeEmptyValue GetSafeErrorType = iota + ErrTypeUnmarshal +) + +func (ty GetSafeErrorType) Format(msg string) (res string) { + switch ty { + case ErrTypeEmptyValue: + res = fmt.Sprintf("Empty Value found") + case ErrTypeUnmarshal: + res = fmt.Sprintf("Error while unmarshal") + default: + panic("Unknown error type") + } + + if msg != "" { + res = fmt.Sprintf("%s: %s", res, msg) + } + + return +} + +type GetSafeError struct { + ty GetSafeErrorType + inner error +} + +var _ error = (*GetSafeError)(nil) // TODO: sdk.Error + +func (err *GetSafeError) Error() string { + if err.inner == nil { + return err.ty.Format("") + } + return err.ty.Format(err.inner.Error()) +} + +func ErrEmptyValue() *GetSafeError { + return &GetSafeError{ + ty: ErrTypeEmptyValue, + } +} + +func ErrUnmarshal(err error) *GetSafeError { + return &GetSafeError{ + ty: ErrTypeUnmarshal, + inner: err, + } +} diff --git a/store/state/indexer.go b/store/state/indexer.go index 281dea761fd5..72be902b3ddc 100644 --- a/store/state/indexer.go +++ b/store/state/indexer.go @@ -3,7 +3,6 @@ package state import ( "encoding/binary" "fmt" - "strconv" ) type IntEncoding byte @@ -14,12 +13,16 @@ const ( Bin ) +// Indexer is a integer typed key wrapper for Mapping. +// Except for the type checking, it does not alter the behaviour. +// All keys are encoded depending on the IntEncoding type Indexer struct { m Mapping enc IntEncoding } +// NewIndexer() constructs the Indexer with a predetermined prefix and IntEncoding func NewIndexer(base Base, prefix []byte, enc IntEncoding) Indexer { return Indexer{ m: NewMapping(base, prefix), @@ -31,10 +34,13 @@ func NewIndexer(base Base, prefix []byte, enc IntEncoding) Indexer { func EncodeInt(index uint64, enc IntEncoding) (res []byte) { switch enc { case Dec: + // Returns decimal number index, 20-length 0 padded return []byte(fmt.Sprintf("%020d", index)) case Hex: + // Returns hexadecimal number index, 20-length 0 padded return []byte(fmt.Sprintf("%020x", index)) case Bin: + // Returns bigendian encoded number index, 8-length res = make([]byte, 8) binary.BigEndian.PutUint64(res, index) return @@ -43,19 +49,6 @@ func EncodeInt(index uint64, enc IntEncoding) (res []byte) { } } -func DecodeInt(bz []byte, enc IntEncoding) (res uint64, err error) { - switch enc { - case Dec: - return strconv.ParseUint(string(bz), 10, 64) - case Hex: - return strconv.ParseUint(string(bz), 16, 64) - case Bin: - return binary.BigEndian.Uint64(bz), nil - default: - panic("invalid IntEncoding") - } -} - func (ix Indexer) Value(index uint64) Value { return ix.m.Value(EncodeInt(index, ix.enc)) } @@ -80,10 +73,6 @@ func (ix Indexer) Delete(ctx Context, index uint64) { ix.Value(index).Delete(ctx) } -func (ix Indexer) IsEmpty(ctx Context) bool { - return ix.m.IsEmpty(ctx) -} - func (ix Indexer) Prefix(prefix []byte) Indexer { return Indexer{ m: ix.m.Prefix(prefix), diff --git a/store/state/integer.go b/store/state/integer.go index 9dd00cf45d1d..0ca86572aba2 100644 --- a/store/state/integer.go +++ b/store/state/integer.go @@ -1,5 +1,7 @@ package state +// Integer is a uint64 types wrapper for Value. +// Except for the type checking, it does not alter the behaviour. type Integer struct { Value @@ -14,33 +16,20 @@ func NewInteger(v Value, enc IntEncoding) Integer { } func (v Integer) Get(ctx Context) (res uint64) { - bz := v.GetRaw(ctx) - if bz == nil { - return 0 - } - res, err := DecodeInt(bz, v.enc) - if err != nil { - panic(err) - } + v.Value.Get(ctx, &res) return res } -func (v Integer) GetSafe(ctx Context) (uint64, error) { - bz := v.GetRaw(ctx) - if bz == nil { - return 0, &GetSafeError{} - } - res, err := DecodeInt(bz, v.enc) - if err != nil { - panic(err) - } - return res, nil +func (v Integer) GetSafe(ctx Context) (res uint64, err error) { + err = v.Value.GetSafe(ctx, &res) + return } func (v Integer) Set(ctx Context, value uint64) { - v.SetRaw(ctx, EncodeInt(value, v.enc)) + v.Value.Set(ctx, value) } +// Incr() increments the stored value, and returns the updated value. func (v Integer) Incr(ctx Context) (res uint64) { res = v.Get(ctx) + 1 v.Set(ctx, res) diff --git a/store/state/mapping.go b/store/state/mapping.go index 127f5a0afb7c..91565ea2c2af 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -1,15 +1,14 @@ package state +// Mapping is key []byte -> value []byte mapping using a base(possibly prefixed) type Mapping struct { - base Base - start, end []byte + base Base } +// NewMapping() constructs a Mapping with a provided prefix func NewMapping(base Base, prefix []byte) Mapping { return Mapping{ - base: base.Prefix(prefix), - start: []byte{}, // preventing nil key access in store.Last - end: nil, + base: base.Prefix(prefix), } } @@ -17,6 +16,7 @@ func (m Mapping) store(ctx Context) KVStore { return m.base.store(ctx) } +// Value() returns the Value corresponding to the provided key func (m Mapping) Value(key []byte) Value { return NewValue(m.base, key) } @@ -45,12 +45,6 @@ func (m Mapping) Delete(ctx Context, key []byte) { m.Value(key).Delete(ctx) } -func (m Mapping) IsEmpty(ctx Context) bool { - iter := m.store(ctx).Iterator(nil, nil) - defer iter.Close() - return iter.Valid() -} - func (m Mapping) Prefix(prefix []byte) Mapping { return NewMapping(m.base, prefix) } diff --git a/store/state/string.go b/store/state/string.go new file mode 100644 index 000000000000..7198f7869a85 --- /dev/null +++ b/store/state/string.go @@ -0,0 +1,25 @@ +package state + +// String is a string types wrapper for Value. +// Except for the type checking, it does not alter the behaviour. +type String struct { + Value +} + +func NewString(v Value) String { + return String{v} +} + +func (v String) Get(ctx Context) (res string) { + v.Value.Get(ctx, &res) + return +} + +func (v String) GetSafe(ctx Context) (res string, err error) { + err = v.Value.GetSafe(ctx, &res) + return +} + +func (v String) Set(ctx Context, value string) { + v.Value.Set(ctx, value) +} diff --git a/store/state/value.go b/store/state/value.go index a087db6064ce..87bbeec9f805 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -1,16 +1,18 @@ package state import ( - "fmt" - "github.com/cosmos/cosmos-sdk/codec" ) +// Value is a capability for reading and writing on a specific key-value point in the state. +// Value consists of Base and key []byte. +// An actor holding a Value has a full access right on that state point. type Value struct { base Base key []byte } +// NewValue() constructs a Value func NewValue(base Base, key []byte) Value { return Value{ base: base, @@ -22,10 +24,13 @@ func (v Value) store(ctx Context) KVStore { return v.base.store(ctx) } +// Cdc() returns the codec that the value is using to marshal/unmarshal func (v Value) Cdc() *codec.Codec { return v.base.Cdc() } +// Get() unmarshales and sets the stored value to the pointer if it exists. +// It will panic if the value exists but not unmarshalable. func (v Value) Get(ctx Context, ptr interface{}) { bz := v.store(ctx).Get(v.key) if bz != nil { @@ -33,6 +38,8 @@ func (v Value) Get(ctx Context, ptr interface{}) { } } +// GetSafe() unmarshales and sets the stored value to the pointer. +// It will return an error if the value does not exist or unmarshalable. func (v Value) GetSafe(ctx Context, ptr interface{}) error { bz := v.store(ctx).Get(v.key) if bz == nil { @@ -45,77 +52,34 @@ func (v Value) GetSafe(ctx Context, ptr interface{}) error { return nil } +// GetRaw() returns the raw bytes that is stored in the state. func (v Value) GetRaw(ctx Context) []byte { return v.store(ctx).Get(v.key) } +// Set() marshales sets the "o" argument to the state. func (v Value) Set(ctx Context, o interface{}) { v.store(ctx).Set(v.key, v.base.cdc.MustMarshalBinaryBare(o)) } +// SetRaw() sets the raw bytes to the state. func (v Value) SetRaw(ctx Context, bz []byte) { v.store(ctx).Set(v.key, bz) } +// Exists() returns true if the stored value is not nil. +// Calles KVStore.Has() internally func (v Value) Exists(ctx Context) bool { return v.store(ctx).Has(v.key) } +// Delete() deletes the stored value. +// Calles KVStore.Delete() internally func (v Value) Delete(ctx Context) { v.store(ctx).Delete(v.key) } +// Key() returns the prefixed key that the Value is providing to the KVStore func (v Value) Key() []byte { return v.base.key(v.key) } - -type GetSafeErrorType byte - -const ( - ErrTypeEmptyValue GetSafeErrorType = iota - ErrTypeUnmarshal -) - -func (ty GetSafeErrorType) Format(msg string) (res string) { - switch ty { - case ErrTypeEmptyValue: - res = fmt.Sprintf("Empty Value found") - case ErrTypeUnmarshal: - res = fmt.Sprintf("Error while unmarshal") - default: - panic("Unknown error type") - } - - if msg != "" { - res = fmt.Sprintf("%s: %s", res, msg) - } - - return -} - -type GetSafeError struct { - ty GetSafeErrorType - inner error -} - -var _ error = (*GetSafeError)(nil) // TODO: sdk.Error - -func (err *GetSafeError) Error() string { - if err.inner == nil { - return err.ty.Format("") - } - return err.ty.Format(err.inner.Error()) -} - -func ErrEmptyValue() *GetSafeError { - return &GetSafeError{ - ty: ErrTypeEmptyValue, - } -} - -func ErrUnmarshal(err error) *GetSafeError { - return &GetSafeError{ - ty: ErrTypeUnmarshal, - inner: err, - } -} From 600445aabe9c5e555eb2794c7c63cedd63f44407 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 26 Jul 2019 01:06:51 +0900 Subject: [PATCH 140/378] add comments --- store/state/base.go | 2 -- store/state/mapping.go | 4 ---- 2 files changed, 6 deletions(-) diff --git a/store/state/base.go b/store/state/base.go index 19d85ffb16f4..7049732feaf8 100644 --- a/store/state/base.go +++ b/store/state/base.go @@ -1,8 +1,6 @@ package state import ( - // "github.com/tendermint/tendermint/crypto/merkle" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/store/state/mapping.go b/store/state/mapping.go index 91565ea2c2af..9db242e867de 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -12,10 +12,6 @@ func NewMapping(base Base, prefix []byte) Mapping { } } -func (m Mapping) store(ctx Context) KVStore { - return m.base.store(ctx) -} - // Value() returns the Value corresponding to the provided key func (m Mapping) Value(key []byte) Value { return NewValue(m.base, key) From 98720bbe37aa878c1e75b1c6192b75e3fdc9f2ed Mon Sep 17 00:00:00 2001 From: Joon Date: Fri, 26 Jul 2019 01:27:40 +0900 Subject: [PATCH 141/378] Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> --- x/ibc/23-commitment/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/ibc/23-commitment/README.md b/x/ibc/23-commitment/README.md index 759128b0c6de..256e77f0b95d 100644 --- a/x/ibc/23-commitment/README.md +++ b/x/ibc/23-commitment/README.md @@ -11,14 +11,14 @@ type verifyMembership = (root: CommitmentRoot, proof: CommitmentProof, key: Key, type verifyNonMembership = (root: CommitmentRoot, proof: CommitmentProof, key: Key) => bool ``` -## Impl +## Implementation ### types.go `type Proof` implements `spec: type CommitmentProof`. CommitmentProof is an arbitrary object which can be used as an argument for `spec: verifyMembership` / `spec: verifyNonMembership`, constructed with `spec: createMembershipProof` / `spec: createNonMembershipProof`. The implementation type `Proof` defines `spec: verify(Non)Membership` as its method -`Verify(Root, []byte) error`, which takes the commitment root and the value bytes argument. The method acts as +`Verify(Root, []byte) error`, which takes the commitment root and the value bytes as arguments. The method acts as `spec: verifyMembership` when the value bytes is not nil, and `spec: verifyNonMembership` if it is nil. `type Root` implements `spec: type CommitmentRoot`. From cdee396a4152c7912cf80a6a870de1f7864eda48 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 26 Jul 2019 01:35:03 +0900 Subject: [PATCH 142/378] add comments in progress --- x/ibc/23-commitment/merkle/merkle.go | 6 ++---- x/ibc/23-commitment/merkle/merkle_test.go | 2 ++ x/ibc/23-commitment/merkle/utils.go | 6 +++++- x/ibc/23-commitment/utils.go | 8 ++++++++ x/ibc/23-commitment/value.go | 7 ------- 5 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 x/ibc/23-commitment/utils.go diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index 9fb11c7f38cb..a4a00a47db7b 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -21,9 +21,7 @@ type Root struct { } func NewRoot(hash []byte) Root { - return Root{ - Hash: hash, - } + return Root{hash} } func (Root) CommitmentKind() string { @@ -80,7 +78,7 @@ func (proof Proof) Verify(croot commitment.Root, cpath commitment.Path, value [] } keypath = keypath.AppendKey(append(path.KeyPrefix, proof.Key...), merkle.KeyEncodingHex) - // Hard coded for now + // TODO: Hard coded for now, proof runtime should be extensible for other proof types runtime := rootmulti.DefaultProofRuntime() if value != nil { diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index f93f64943609..e17c80ddf74f 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -36,6 +36,8 @@ func commit(cms types.CommitMultiStore) Root { return NewRoot(cid.Hash) } +// TestStore tests Merkle proof on the commitment.Store +// Sets/upates key-value pairs and prove with the query result proofs func TestStore(t *testing.T) { k, ctx, cms, _ := defaultComponents() kvstore := ctx.KVStore(k) diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index d2eabdaed99d..801651f09aa6 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -19,7 +19,11 @@ func (path Path) RequestQuery(key []byte) abci.RequestQuery { } func (path Path) Query(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { - qres := cms.(types.Queryable).Query(path.RequestQuery(key)) + queryable, ok := cms.(types.Queryable) + if !ok { + panic("CommitMultiStore not queryable") + } + qres := queryable.Query(path.RequestQuery(key)) return qres.Code, qres.Value, Proof{Key: key, Proof: qres.Proof} } diff --git a/x/ibc/23-commitment/utils.go b/x/ibc/23-commitment/utils.go new file mode 100644 index 000000000000..e49dc15319a0 --- /dev/null +++ b/x/ibc/23-commitment/utils.go @@ -0,0 +1,8 @@ +package commitment + +func join(a, b []byte) (res []byte) { + res = make([]byte, len(a)+len(b)) + copy(res, a) + copy(res[len(a):], b) + return +} diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 70b8502a44e6..87d41251d111 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -21,13 +21,6 @@ func (base Base) Store(ctx sdk.Context) Store { return NewPrefix(GetStore(ctx), base.prefix) } -func join(a, b []byte) (res []byte) { - res = make([]byte, len(a)+len(b)) - copy(res, a) - copy(res[len(a):], b) - return -} - func (base Base) Prefix(prefix []byte) Base { return Base{ cdc: base.cdc, From 8d9e77904cbabf78ed1e05e2e2e7e9a5870121b4 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 26 Jul 2019 20:07:46 +0900 Subject: [PATCH 143/378] add comments --- store/state/boolean.go | 6 ++++++ store/state/enum.go | 6 ++++++ store/state/indexer.go | 9 +++++++++ store/state/integer.go | 11 +++++++---- store/state/mapping.go | 11 ++++++++++- store/state/string.go | 6 ++++++ store/state/value.go | 2 +- 7 files changed, 45 insertions(+), 6 deletions(-) diff --git a/store/state/boolean.go b/store/state/boolean.go index dab4d5bbf67e..efc142dd1a1d 100644 --- a/store/state/boolean.go +++ b/store/state/boolean.go @@ -6,20 +6,26 @@ type Boolean struct { Value } +// NewBoolean() wraps the argument Value as Boolean func NewBoolean(v Value) Boolean { return Boolean{v} } +// Get() unmarshales and returns the stored boolean value if it exists. +// It will panic if the value exists but is not boolean type. func (v Boolean) Get(ctx Context) (res bool) { v.Value.Get(ctx, &res) return } +// GetSafe() unmarshales and returns the stored boolean value. +// It will return an error if the value does not exist or not boolean. func (v Boolean) GetSafe(ctx Context) (res bool, err error) { err = v.Value.GetSafe(ctx, &res) return } +// Set() marshales and sets the boolean argument to the state. func (v Boolean) Set(ctx Context, value bool) { v.Value.Set(ctx, value) } diff --git a/store/state/enum.go b/store/state/enum.go index 57fbdc9f3e92..617af5b3e446 100644 --- a/store/state/enum.go +++ b/store/state/enum.go @@ -6,20 +6,26 @@ type Enum struct { Value } +// NewEnum() wraps the argument value as Enum func NewEnum(v Value) Enum { return Enum{v} } +// Get() unmarshales and returns the stored byte value if it exists. +// It will panic if the value exists but is not byte type. func (v Enum) Get(ctx Context) (res byte) { v.Value.Get(ctx, &res) return } +// GetSafe() unmarshales and returns the stored byte value. +// It will returns an error if the value does not exists or not byte. func (v Enum) GetSafe(ctx Context) (res byte, err error) { err = v.Value.GetSafe(ctx, &res) return } +// Set() marshales and sets the byte argument to the state. func (v Enum) Set(ctx Context, value byte) { v.Value.Set(ctx, value) } diff --git a/store/state/indexer.go b/store/state/indexer.go index 72be902b3ddc..d60eba60d5db 100644 --- a/store/state/indexer.go +++ b/store/state/indexer.go @@ -49,30 +49,39 @@ func EncodeInt(index uint64, enc IntEncoding) (res []byte) { } } +// Value() returns the Value corresponding to the provided index func (ix Indexer) Value(index uint64) Value { return ix.m.Value(EncodeInt(index, ix.enc)) } +// Get() unmarshales and sets the stored value to the pointer if it exists. +// It will panic if the value exists but not unmarshalable. func (ix Indexer) Get(ctx Context, index uint64, ptr interface{}) { ix.Value(index).Get(ctx, ptr) } +// GetSafe() unmarshales and sets the stored value to the pointer. +// It will return an error if the value does not exist or unmarshalable. func (ix Indexer) GetSafe(ctx Context, index uint64, ptr interface{}) error { return ix.Value(index).GetSafe(ctx, ptr) } +// Set() marshales and sets the argument to the state. func (ix Indexer) Set(ctx Context, index uint64, o interface{}) { ix.Value(index).Set(ctx, o) } +// Has() returns true if the stored value is not nil func (ix Indexer) Has(ctx Context, index uint64) bool { return ix.Value(index).Exists(ctx) } +// Delete() delets the stored value. func (ix Indexer) Delete(ctx Context, index uint64) { ix.Value(index).Delete(ctx) } +// Prefix() returns a new Indexer with the updated prefix func (ix Indexer) Prefix(prefix []byte) Indexer { return Indexer{ m: ix.m.Prefix(prefix), diff --git a/store/state/integer.go b/store/state/integer.go index 0ca86572aba2..ec3dcb21ed9f 100644 --- a/store/state/integer.go +++ b/store/state/integer.go @@ -4,27 +4,30 @@ package state // Except for the type checking, it does not alter the behaviour. type Integer struct { Value - - enc IntEncoding } -func NewInteger(v Value, enc IntEncoding) Integer { +// NewInteger() wraps the argument value as Integer +func NewInteger(v Value) Integer { return Integer{ Value: v, - enc: enc, } } +// Get() unmarshales and returns the stored uint64 value if it exists. +// If will panic if the value exists but is not uint64 type. func (v Integer) Get(ctx Context) (res uint64) { v.Value.Get(ctx, &res) return res } +// GetSafe() unmarshales and returns the stored uint64 value. +// It will return an error if the value does not exist or not uint64. func (v Integer) GetSafe(ctx Context) (res uint64, err error) { err = v.Value.GetSafe(ctx, &res) return } +// Set() marshales and sets the uint64 argument to the state. func (v Integer) Set(ctx Context, value uint64) { v.Value.Set(ctx, value) } diff --git a/store/state/mapping.go b/store/state/mapping.go index 9db242e867de..46d578b50613 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -1,6 +1,7 @@ package state -// Mapping is key []byte -> value []byte mapping using a base(possibly prefixed) +// Mapping is key []byte -> value []byte mapping using a base(possibly prefixed). +// All store accessing operations are redirected to the Value corresponding to the key argument type Mapping struct { base Base } @@ -17,14 +18,19 @@ func (m Mapping) Value(key []byte) Value { return NewValue(m.base, key) } +// Get() unmarshales and sets the stored value to the pointer if it exists. +// It will panic if the value exists but not unmarshalable. func (m Mapping) Get(ctx Context, key []byte, ptr interface{}) { m.Value(key).Get(ctx, ptr) } +// GetSafe() unmarshales and sets the stored value to the pointer. +// It will return an error if the value does not exists or unmarshalable. func (m Mapping) GetSafe(ctx Context, key []byte, ptr interface{}) error { return m.Value(key).GetSafe(ctx, ptr) } +// Set() marshales and sets the argument to the state. func (m Mapping) Set(ctx Context, key []byte, o interface{}) { if o == nil { m.Delete(ctx, key) @@ -33,14 +39,17 @@ func (m Mapping) Set(ctx Context, key []byte, o interface{}) { m.Value(key).Set(ctx, o) } +// Has() returns true if the stored value is not nil func (m Mapping) Has(ctx Context, key []byte) bool { return m.Value(key).Exists(ctx) } +// Delete() deletes the stored value. func (m Mapping) Delete(ctx Context, key []byte) { m.Value(key).Delete(ctx) } +// Prefix() returns a new mapping with the updated prefix. func (m Mapping) Prefix(prefix []byte) Mapping { return NewMapping(m.base, prefix) } diff --git a/store/state/string.go b/store/state/string.go index 7198f7869a85..8d7d6f9fdb4f 100644 --- a/store/state/string.go +++ b/store/state/string.go @@ -6,20 +6,26 @@ type String struct { Value } +// NewString() wraps the argument value as String func NewString(v Value) String { return String{v} } +// Get() unmarshales and returns the stored string value if it exists. +// It will panic if the value exists but is not strin type. func (v String) Get(ctx Context) (res string) { v.Value.Get(ctx, &res) return } +// GetSafe() unmarshales and returns the stored string value. +// It will return an error if the value does not exist or not string func (v String) GetSafe(ctx Context) (res string, err error) { err = v.Value.GetSafe(ctx, &res) return } +// Set() marshales and sets the string argument to the state. func (v String) Set(ctx Context, value string) { v.Value.Set(ctx, value) } diff --git a/store/state/value.go b/store/state/value.go index 87bbeec9f805..ae7d572ee40b 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -57,7 +57,7 @@ func (v Value) GetRaw(ctx Context) []byte { return v.store(ctx).Get(v.key) } -// Set() marshales sets the "o" argument to the state. +// Set() marshales and sets the argument to the state. func (v Value) Set(ctx Context, o interface{}) { v.store(ctx).Set(v.key, v.base.cdc.MustMarshalBinaryBare(o)) } From 92d0fb497c7345027b685846f3df18d49ebaec00 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 26 Jul 2019 20:13:12 +0900 Subject: [PATCH 144/378] fix comment --- store/state/mapping.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/store/state/mapping.go b/store/state/mapping.go index 46d578b50613..2943e690d673 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -25,12 +25,13 @@ func (m Mapping) Get(ctx Context, key []byte, ptr interface{}) { } // GetSafe() unmarshales and sets the stored value to the pointer. -// It will return an error if the value does not exists or unmarshalable. +// It will return an error if the value does not exist or unmarshalable. func (m Mapping) GetSafe(ctx Context, key []byte, ptr interface{}) error { return m.Value(key).GetSafe(ctx, ptr) } // Set() marshales and sets the argument to the state. +// Calls Delete() if the argument is nil. func (m Mapping) Set(ctx Context, key []byte, o interface{}) { if o == nil { m.Delete(ctx, key) From f70d3bdb8d03c44b313978c706000e30aa6eb0cf Mon Sep 17 00:00:00 2001 From: mossid Date: Sat, 27 Jul 2019 21:06:29 +0900 Subject: [PATCH 145/378] add comments in progress --- x/ibc/23-commitment/merkle/utils.go | 11 +++++++++++ x/ibc/23-commitment/value.go | 17 +++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index 801651f09aa6..86c6d6d18f3e 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -6,11 +6,22 @@ import ( "github.com/cosmos/cosmos-sdk/store/types" ) +// RequestQuery() constructs the abci.RequestQuery. +// +// RequestQuery.Path is a slash separated key list, ending with "/key" +// +// RequestQuery.Data is the concatanation of path.KeyPrefix and key argument +// +// RequestQuery.Prove is set to true func (path Path) RequestQuery(key []byte) abci.RequestQuery { pathstr := "" for _, inter := range path.KeyPath { + // The Queryable() stores uses slash-separated keypath format for querying pathstr = pathstr + "/" + string(inter) } + // Suffixing pathstr with "/key". + // iavl.Store.Query() switches over the last path element, + // and performs key-value query only if it is "/key" pathstr = pathstr + "/key" data := append(path.KeyPrefix, key...) diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 87d41251d111..6e361fa75188 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -6,6 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// Base is a proof store accessor, consists of Codec and prefix. +// The base uses the commitment store which is expected to be filled with the proofs. type Base struct { cdc *codec.Codec prefix []byte @@ -38,6 +40,8 @@ func NewMapping(base Base, prefix []byte) Mapping { } } +// Value is for proving commitment proof on a speicifc key-value point in the other state +// using the already initialized commitment store. type Value struct { base Base key []byte @@ -47,34 +51,39 @@ func NewValue(base Base, key []byte) Value { return Value{base, key} } +// Is() proves the proof with the Value's key and the provided value. func (v Value) Is(ctx sdk.Context, value interface{}) bool { return v.base.Store(ctx).Prove(v.key, v.base.cdc.MustMarshalBinaryBare(value)) } +// 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.base.Store(ctx).Prove(v.key, value) } +// Enum is a byte typed wrapper for Value. +// Except for the type checking, it does not alter the behaviour. type Enum struct { Value } +// NewEnum() wraps the argument Value as Enum func NewEnum(v Value) Enum { return Enum{v} } +// Is() proves the proof with the Enum's key and the provided value func (v Enum) Is(ctx sdk.Context, value byte) bool { return v.Value.IsRaw(ctx, []byte{value}) } +// Integer is a uint64 types wrapper for Value. type Integer struct { Value - - enc state.IntEncoding } -func NewInteger(v Value, enc state.IntEncoding) Integer { - return Integer{v, enc} +func NewInteger(v Value) Integer { + return Integer{v} } func (v Integer) Is(ctx sdk.Context, value uint64) bool { From 5d913b7bbdb1e3b013d4d708dd5a7ddef31f4304 Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 29 Jul 2019 16:07:45 +0900 Subject: [PATCH 146/378] recover IntEncoding scheme for integer --- store/state/indexer.go | 27 +++++++++++++++++++++++++-- store/state/integer.go | 32 +++++++++++++++++++++++++------- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/store/state/indexer.go b/store/state/indexer.go index d60eba60d5db..fab6db992858 100644 --- a/store/state/indexer.go +++ b/store/state/indexer.go @@ -3,13 +3,22 @@ package state import ( "encoding/binary" "fmt" + "strconv" ) +// IntEncoding is an enum type defining the integer serialization scheme. +// All encoding schemes preserves order. type IntEncoding byte const ( + // Dec is human readable decimal encoding scheme. + // Has fixed length of 20 bytes. Dec IntEncoding = iota + // Hex is human readable hexadecimal encoding scheme + // Has fixed length of 16 bytes. Hex + // Bin is machine readable big endian encoding scheme + // Has fixed length of 8 bytes Bin ) @@ -30,7 +39,7 @@ func NewIndexer(base Base, prefix []byte, enc IntEncoding) Indexer { } } -// Identical length independent from the index, ensure ordering +// Order preserving integer encoding function. func EncodeInt(index uint64, enc IntEncoding) (res []byte) { switch enc { case Dec: @@ -38,7 +47,7 @@ func EncodeInt(index uint64, enc IntEncoding) (res []byte) { return []byte(fmt.Sprintf("%020d", index)) case Hex: // Returns hexadecimal number index, 20-length 0 padded - return []byte(fmt.Sprintf("%020x", index)) + return []byte(fmt.Sprintf("%016x", index)) case Bin: // Returns bigendian encoded number index, 8-length res = make([]byte, 8) @@ -49,6 +58,20 @@ func EncodeInt(index uint64, enc IntEncoding) (res []byte) { } } +// Integer decoding function, inversion of EncodeInt +func DecodeInt(bz []byte, enc IntEncoding) (res uint64, err error) { + switch enc { + case Dec: + return strconv.ParseUint(string(bz), 10, 64) + case Hex: + return strconv.ParseUint(string(bz), 16, 64) + case Bin: + return binary.BigEndian.Uint64(bz), nil + default: + panic("invalid IntEncoding") + } +} + // Value() returns the Value corresponding to the provided index func (ix Indexer) Value(index uint64) Value { return ix.m.Value(EncodeInt(index, ix.enc)) diff --git a/store/state/integer.go b/store/state/integer.go index ec3dcb21ed9f..6c2695b8fd86 100644 --- a/store/state/integer.go +++ b/store/state/integer.go @@ -1,35 +1,53 @@ package state // Integer is a uint64 types wrapper for Value. -// Except for the type checking, it does not alter the behaviour. +// The serialization follows the @IntEncoding@ format provided to the NewInteger. type Integer struct { Value + + enc IntEncoding } // NewInteger() wraps the argument value as Integer -func NewInteger(v Value) Integer { +func NewInteger(v Value, enc IntEncoding) Integer { return Integer{ Value: v, + + enc: enc, } } // Get() unmarshales and returns the stored uint64 value if it exists. -// If will panic if the value exists but is not uint64 type. -func (v Integer) Get(ctx Context) (res uint64) { - v.Value.Get(ctx, &res) +// If will panic if the value exists but not decodable. +func (v Integer) Get(ctx Context) uint64 { + bz := v.Value.GetRaw(ctx) + if bz == nil { + return 0 + } + res, err := DecodeInt(bz, v.enc) + if err != nil { + panic(err) + } return res } // GetSafe() unmarshales and returns the stored uint64 value. // It will return an error if the value does not exist or not uint64. func (v Integer) GetSafe(ctx Context) (res uint64, err error) { - err = v.Value.GetSafe(ctx, &res) + bz := v.Value.GetRaw(ctx) + if bz == nil { + return 0, ErrEmptyValue() + } + res, err = DecodeInt(bz, v.enc) + if err != nil { + err = ErrUnmarshal(err) + } return } // Set() marshales and sets the uint64 argument to the state. func (v Integer) Set(ctx Context, value uint64) { - v.Value.Set(ctx, value) + v.Value.SetRaw(ctx, EncodeInt(value, v.enc)) } // Incr() increments the stored value, and returns the updated value. From 699b0ba157e24f0775746c530645781d4e845521 Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 29 Jul 2019 22:14:51 +0900 Subject: [PATCH 147/378] add uint tests, don't use codec in custom types --- store/state/base.go | 72 --------- store/state/boolean.go | 7 +- store/state/enum.go | 17 +- store/state/indexer.go | 4 +- store/state/integer.go | 9 +- store/state/mapping.go | 48 +++++- store/state/mapping_test.go | 123 +++++++++++++++ store/state/string.go | 17 +- store/state/value.go | 26 ++-- store/state/value_test.go | 300 ++++++++++++++++++++++++++++++++++++ 10 files changed, 505 insertions(+), 118 deletions(-) delete mode 100644 store/state/base.go create mode 100644 store/state/mapping_test.go create mode 100644 store/state/value_test.go diff --git a/store/state/base.go b/store/state/base.go deleted file mode 100644 index 7049732feaf8..000000000000 --- a/store/state/base.go +++ /dev/null @@ -1,72 +0,0 @@ -package state - -import ( - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// Base is a state accessor base layer, consists of Codec, StoreKey, and prefix. -// StoreKey is used to get the KVStore, cdc is used to marshal/unmarshal the interfaces, -// and the prefix is prefixed to the key. -// -// Base has practically the same capability with the storeKey. -// It should not be passed to an untrusted actor. -type Base struct { - storeKey sdk.StoreKey - cdc *codec.Codec - prefix []byte -} - -// NewBase() is the constructor for Base() -func NewBase(cdc *codec.Codec, key sdk.StoreKey, rootkey []byte) Base { - return Base{ - storeKey: key, - cdc: cdc, - prefix: rootkey, - } -} - -func (base Base) store(ctx Context) KVStore { - return prefix.NewStore(ctx.KVStore(base.storeKey), base.prefix) -} - -func join(a, b []byte) (res []byte) { - res = make([]byte, len(a)+len(b)) - copy(res, a) - copy(res[len(a):], b) - return -} - -// Prefix() returns a copy of the Base with the updated prefix. -func (base Base) Prefix(prefix []byte) (res Base) { - res = Base{ - storeKey: base.storeKey, - cdc: base.cdc, - prefix: join(base.prefix, prefix), - } - return -} - -// Cdc() returns the codec of the base. It is safe to expose the codec. -func (base Base) Cdc() *codec.Codec { - return base.cdc -} - -func (base Base) key(key []byte) []byte { - return join(base.prefix, key) -} - -// StoreName() returns the name of the storeKey. It is safe to expose the store name. -// Used by the CLI side query operations. -func (base Base) StoreName() string { - return base.storeKey.Name() -} - -// PrefixBytes() returns the prefix bytes. It is safe to expsoe the prefix bytes. -// Used by the CLI side query operations. -func (base Base) PrefixBytes() (res []byte) { - res = make([]byte, len(base.prefix)) - copy(res, base.prefix) - return -} diff --git a/store/state/boolean.go b/store/state/boolean.go index efc142dd1a1d..5d582b6869d7 100644 --- a/store/state/boolean.go +++ b/store/state/boolean.go @@ -1,13 +1,14 @@ package state // Boolean is a bool typed wrapper for Value. -// Except for the type checking, it does not alter the behaviour. +// +// false <-> []byte{0x00} +// true <-> []byte{0x01} type Boolean struct { Value } -// NewBoolean() wraps the argument Value as Boolean -func NewBoolean(v Value) Boolean { +func (v Value) Boolean() Boolean { return Boolean{v} } diff --git a/store/state/enum.go b/store/state/enum.go index 617af5b3e446..67f18a4a2584 100644 --- a/store/state/enum.go +++ b/store/state/enum.go @@ -1,33 +1,34 @@ package state // Enum is a byte typed wrapper for Value. -// Except for the type checking, it does not alter the behaviour. +// x <-> []byte{x} type Enum struct { Value } -// NewEnum() wraps the argument value as Enum -func NewEnum(v Value) Enum { +func (v Value) Enum() Enum { return Enum{v} } // Get() unmarshales and returns the stored byte value if it exists. // It will panic if the value exists but is not byte type. func (v Enum) Get(ctx Context) (res byte) { - v.Value.Get(ctx, &res) - return + return v.Value.GetRaw(ctx)[0] } // GetSafe() unmarshales and returns the stored byte value. // It will returns an error if the value does not exists or not byte. func (v Enum) GetSafe(ctx Context) (res byte, err error) { - err = v.Value.GetSafe(ctx, &res) - return + bz := v.Value.GetRaw(ctx) + if bz == nil { + return res, ErrEmptyValue() + } + return bz[0], nil // TODO: check length } // Set() marshales and sets the byte argument to the state. func (v Enum) Set(ctx Context, value byte) { - v.Value.Set(ctx, value) + v.Value.SetRaw(ctx, []byte{value}) } // Incr() increments the stored value, and returns the updated value. diff --git a/store/state/indexer.go b/store/state/indexer.go index fab6db992858..6b837c2021a3 100644 --- a/store/state/indexer.go +++ b/store/state/indexer.go @@ -32,9 +32,9 @@ type Indexer struct { } // NewIndexer() constructs the Indexer with a predetermined prefix and IntEncoding -func NewIndexer(base Base, prefix []byte, enc IntEncoding) Indexer { +func NewIndexer(m Mapping, enc IntEncoding) Indexer { return Indexer{ - m: NewMapping(base, prefix), + m: m, enc: enc, } } diff --git a/store/state/integer.go b/store/state/integer.go index 6c2695b8fd86..187fd718d55e 100644 --- a/store/state/integer.go +++ b/store/state/integer.go @@ -8,13 +8,8 @@ type Integer struct { enc IntEncoding } -// NewInteger() wraps the argument value as Integer -func NewInteger(v Value, enc IntEncoding) Integer { - return Integer{ - Value: v, - - enc: enc, - } +func (v Value) Integer(enc IntEncoding) Integer { + return Integer{v, enc} } // Get() unmarshales and returns the stored uint64 value if it exists. diff --git a/store/state/mapping.go b/store/state/mapping.go index 2943e690d673..95a96974416b 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -1,21 +1,30 @@ package state +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" +) + // Mapping is key []byte -> value []byte mapping using a base(possibly prefixed). // All store accessing operations are redirected to the Value corresponding to the key argument type Mapping struct { - base Base + storeKey sdk.StoreKey + cdc *codec.Codec + prefix []byte } // NewMapping() constructs a Mapping with a provided prefix -func NewMapping(base Base, prefix []byte) Mapping { +func NewMapping(storeKey sdk.StoreKey, cdc *codec.Codec, prefix []byte) Mapping { return Mapping{ - base: base.Prefix(prefix), + storeKey: storeKey, + cdc: cdc, + prefix: prefix, } } // Value() returns the Value corresponding to the provided key func (m Mapping) Value(key []byte) Value { - return NewValue(m.base, key) + return NewValue(m, key) } // Get() unmarshales and sets the stored value to the pointer if it exists. @@ -50,7 +59,36 @@ func (m Mapping) Delete(ctx Context, key []byte) { m.Value(key).Delete(ctx) } +func (m Mapping) Cdc() *codec.Codec { + return m.cdc +} + +func (m Mapping) StoreName() string { + return m.storeKey.Name() +} + +func (m Mapping) PrefixBytes() (res []byte) { + res = make([]byte, len(m.prefix)) + copy(res, m.prefix) + return +} + +func (m Mapping) KeyBytes(key []byte) (res []byte) { + return join(m.prefix, key) +} + +func join(a, b []byte) (res []byte) { + res = make([]byte, len(a)+len(b)) + copy(res, a) + copy(res[len(a):], b) + return +} + // Prefix() returns a new mapping with the updated prefix. func (m Mapping) Prefix(prefix []byte) Mapping { - return NewMapping(m.base, prefix) + return Mapping{ + storeKey: m.storeKey, + cdc: m.cdc, + prefix: join(m.prefix, prefix), + } } diff --git a/store/state/mapping_test.go b/store/state/mapping_test.go new file mode 100644 index 000000000000..0a29fead8a6e --- /dev/null +++ b/store/state/mapping_test.go @@ -0,0 +1,123 @@ +package state + +import ( + "math/rand" + "reflect" + "testing" + + "github.com/stretchr/testify/require" +) + +type mapping interface { + Get(Context, interface{}, interface{}) + GetSafe(Context, interface{}, interface{}) error + Set(Context, interface{}, interface{}) + Has(Context, interface{}) bool + Delete(Context, interface{}) + RandomKey() interface{} +} + +type mappingT struct { + Mapping +} + +var _ mapping = mappingT{} + +func newMapping() mappingT { + return mappingT{NewMapping(testkey, testcdc, nil)} +} + +func (m mappingT) Get(ctx Context, key interface{}, ptr interface{}) { + m.Mapping.Get(ctx, []byte(key.(string)), ptr) +} + +func (m mappingT) GetSafe(ctx Context, key interface{}, ptr interface{}) error { + return m.Mapping.GetSafe(ctx, []byte(key.(string)), ptr) +} + +func (m mappingT) Set(ctx Context, key interface{}, o interface{}) { + m.Mapping.Set(ctx, []byte(key.(string)), o) +} + +func (m mappingT) Has(ctx Context, key interface{}) bool { + return m.Mapping.Has(ctx, []byte(key.(string))) +} + +func (m mappingT) Delete(ctx Context, key interface{}) { + m.Mapping.Delete(ctx, []byte(key.(string))) +} + +func (m mappingT) RandomKey() interface{} { + bz := make([]byte, 64) + rand.Read(bz) + return string(bz) +} + +type indexerT struct { + Indexer +} + +var _ mapping = indexerT{} + +func newIndexer(enc IntEncoding) indexerT { + return indexerT{NewIndexer(NewMapping(testkey, testcdc, nil), enc)} +} + +func (m indexerT) Get(ctx Context, key interface{}, ptr interface{}) { + m.Indexer.Get(ctx, key.(uint64), ptr) +} + +func (m indexerT) GetSafe(ctx Context, key interface{}, ptr interface{}) error { + return m.Indexer.GetSafe(ctx, key.(uint64), ptr) +} + +func (m indexerT) Set(ctx Context, key interface{}, o interface{}) { + m.Indexer.Set(ctx, key.(uint64), o) +} + +func (m indexerT) Has(ctx Context, key interface{}) bool { + return m.Indexer.Has(ctx, key.(uint64)) +} + +func (m indexerT) Delete(ctx Context, key interface{}) { + m.Indexer.Delete(ctx, key.(uint64)) +} + +func (m indexerT) RandomKey() interface{} { + return rand.Uint64() +} + +func TestMapping(t *testing.T) { + ctx := defaultComponents() + table := []mapping{newMapping(), newIndexer(Dec), newIndexer(Hex), newIndexer(Bin)} + + for _, m := range table { + exp := make(map[interface{}]uint64) + for n := 0; n < 10e4; n++ { + k, v := m.RandomKey(), rand.Uint64() + require.False(t, m.Has(ctx, k)) + exp[k] = v + m.Set(ctx, k, v) + } + + for k, v := range exp { + ptr := new(uint64) + m.Get(ctx, k, ptr) + require.Equal(t, v, indirect(ptr)) + + ptr = new(uint64) + err := m.GetSafe(ctx, k, ptr) + require.NoError(t, err) + require.Equal(t, v, indirect(ptr)) + + require.True(t, m.Has(ctx, k)) + + m.Delete(ctx, k) + require.False(t, m.Has(ctx, k)) + ptr = new(uint64) + err = m.GetSafe(ctx, k, ptr) + require.Error(t, err) + require.Equal(t, reflect.Zero(reflect.TypeOf(ptr).Elem()).Interface(), indirect(ptr)) + } + } +} diff --git a/store/state/string.go b/store/state/string.go index 8d7d6f9fdb4f..72c85340d01f 100644 --- a/store/state/string.go +++ b/store/state/string.go @@ -1,31 +1,32 @@ package state // String is a string types wrapper for Value. -// Except for the type checking, it does not alter the behaviour. +// x <-> []byte(x) type String struct { Value } -// NewString() wraps the argument value as String -func NewString(v Value) String { +func (v Value) String() String { return String{v} } // Get() unmarshales and returns the stored string value if it exists. // It will panic if the value exists but is not strin type. func (v String) Get(ctx Context) (res string) { - v.Value.Get(ctx, &res) - return + return string(v.Value.GetRaw(ctx)) } // GetSafe() unmarshales and returns the stored string value. // It will return an error if the value does not exist or not string func (v String) GetSafe(ctx Context) (res string, err error) { - err = v.Value.GetSafe(ctx, &res) - return + bz := v.Value.GetRaw(ctx) + if bz == nil { + return res, ErrEmptyValue() + } + return string(bz), nil } // Set() marshales and sets the string argument to the state. func (v String) Set(ctx Context, value string) { - v.Value.Set(ctx, value) + v.Value.SetRaw(ctx, []byte(value)) } diff --git a/store/state/value.go b/store/state/value.go index ae7d572ee40b..7878ae2f191e 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -8,25 +8,25 @@ import ( // Value consists of Base and key []byte. // An actor holding a Value has a full access right on that state point. type Value struct { - base Base - key []byte + m Mapping + key []byte } // NewValue() constructs a Value -func NewValue(base Base, key []byte) Value { +func NewValue(m Mapping, key []byte) Value { return Value{ - base: base, - key: key, + m: m, + key: key, } } func (v Value) store(ctx Context) KVStore { - return v.base.store(ctx) + return ctx.KVStore(v.m.storeKey) } // Cdc() returns the codec that the value is using to marshal/unmarshal func (v Value) Cdc() *codec.Codec { - return v.base.Cdc() + return v.m.Cdc() } // Get() unmarshales and sets the stored value to the pointer if it exists. @@ -34,7 +34,7 @@ func (v Value) Cdc() *codec.Codec { func (v Value) Get(ctx Context, ptr interface{}) { bz := v.store(ctx).Get(v.key) if bz != nil { - v.base.cdc.MustUnmarshalBinaryBare(bz, ptr) + v.m.cdc.MustUnmarshalBinaryBare(bz, ptr) } } @@ -45,7 +45,7 @@ func (v Value) GetSafe(ctx Context, ptr interface{}) error { if bz == nil { return ErrEmptyValue() } - err := v.base.cdc.UnmarshalBinaryBare(bz, ptr) + err := v.m.cdc.UnmarshalBinaryBare(bz, ptr) if err != nil { return ErrUnmarshal(err) } @@ -59,7 +59,7 @@ func (v Value) GetRaw(ctx Context) []byte { // Set() marshales and sets the argument to the state. func (v Value) Set(ctx Context, o interface{}) { - v.store(ctx).Set(v.key, v.base.cdc.MustMarshalBinaryBare(o)) + v.store(ctx).Set(v.key, v.m.cdc.MustMarshalBinaryBare(o)) } // SetRaw() sets the raw bytes to the state. @@ -79,7 +79,7 @@ func (v Value) Delete(ctx Context) { v.store(ctx).Delete(v.key) } -// Key() returns the prefixed key that the Value is providing to the KVStore -func (v Value) Key() []byte { - return v.base.key(v.key) +// KeyBytes() returns the prefixed key that the Value is providing to the KVStore +func (v Value) KeyBytes() []byte { + return v.m.KeyBytes(v.key) } diff --git a/store/state/value_test.go b/store/state/value_test.go new file mode 100644 index 000000000000..37e42d382d95 --- /dev/null +++ b/store/state/value_test.go @@ -0,0 +1,300 @@ +package state + +import ( + "crypto/rand" + "reflect" + "testing" + + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/rootmulti" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var testcdc = codec.New() +var testkey = sdk.NewKVStoreKey("test") + +func init() { + // register +} + +func key() (res []byte) { + res = make([]byte, 64) + rand.Read(res) + return +} + +type value interface { + Get(Context, interface{}) + GetSafe(Context, interface{}) error + GetRaw(Context) []byte + Set(Context, interface{}) + SetRaw(Context, []byte) + Exists(Context) bool + Delete(Context) + Marshal(interface{}) []byte + Unmarshal([]byte, interface{}) +} + +type typeValue interface { + value + Proto() interface{} +} + +type valueT struct { + Value +} + +var _ value = valueT{} + +func (v valueT) Marshal(o interface{}) []byte { + return v.m.cdc.MustMarshalBinaryBare(o) +} + +func (v valueT) Unmarshal(bz []byte, ptr interface{}) { + v.m.cdc.MustUnmarshalBinaryBare(bz, ptr) +} + +type booleanT struct { + Boolean +} + +var _ typeValue = booleanT{} + +func newBoolean() booleanT { + return booleanT{NewMapping(testkey, testcdc, nil).Value(key()).Boolean()} +} + +func (booleanT) Proto() interface{} { + return new(bool) +} + +func (v booleanT) Get(ctx Context, ptr interface{}) { + reflect.ValueOf(ptr).Elem().SetBool(v.Boolean.Get(ctx)) +} + +func (v booleanT) GetSafe(ctx Context, ptr interface{}) error { + res, err := v.Boolean.GetSafe(ctx) + if err != nil { + return err + } + reflect.ValueOf(ptr).Elem().SetBool(res) + return nil +} + +func (v booleanT) Set(ctx Context, o interface{}) { + v.Boolean.Set(ctx, o.(bool)) +} + +func (v booleanT) Marshal(o interface{}) []byte { + switch o.(bool) { + case false: + return []byte{0x00} + case true: + return []byte{0x01} + } + panic("invalid boolean type") +} + +func (v booleanT) Unmarshal(bz []byte, ptr interface{}) { + switch bz[0] { + case 0x00: + reflect.ValueOf(ptr).Elem().SetBool(false) + case 0x01: + reflect.ValueOf(ptr).Elem().SetBool(true) + } +} + +type integerT struct { + Integer +} + +var _ typeValue = integerT{} + +func newInteger(enc IntEncoding) integerT { + return integerT{NewMapping(testkey, testcdc, nil).Value(key()).Integer(enc)} +} + +func (integerT) Proto() interface{} { + return new(uint64) +} + +func (v integerT) Get(ctx Context, ptr interface{}) { + reflect.ValueOf(ptr).Elem().SetUint(v.Integer.Get(ctx)) +} + +func (v integerT) GetSafe(ctx Context, ptr interface{}) error { + res, err := v.Integer.GetSafe(ctx) + if err != nil { + return err + } + reflect.ValueOf(ptr).Elem().SetUint(res) + return nil +} + +func (v integerT) Set(ctx Context, o interface{}) { + v.Integer.Set(ctx, o.(uint64)) +} + +func (v integerT) Marshal(o interface{}) []byte { + return EncodeInt(o.(uint64), v.enc) +} + +func (v integerT) Unmarshal(bz []byte, ptr interface{}) { + res, err := DecodeInt(bz, v.enc) + if err != nil { + panic(err) + } + reflect.ValueOf(ptr).Elem().SetUint(res) +} + +type enumT struct { + Enum +} + +var _ typeValue = enumT{} + +func newEnum() enumT { + return enumT{NewMapping(testkey, testcdc, nil).Value(key()).Enum()} +} + +func (enumT) Proto() interface{} { + return new(byte) +} + +func (v enumT) Get(ctx Context, ptr interface{}) { + reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v.Enum.Get(ctx))) +} + +func (v enumT) GetSafe(ctx Context, ptr interface{}) error { + res, err := v.Enum.GetSafe(ctx) + if err != nil { + return err + } + reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(res)) + return nil +} + +func (v enumT) Set(ctx Context, o interface{}) { + v.Enum.Set(ctx, o.(byte)) +} + +func (v enumT) Marshal(o interface{}) []byte { + return []byte{o.(byte)} +} + +func (v enumT) Unmarshal(bz []byte, ptr interface{}) { + reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(bz[0])) +} + +type stringT struct { + String +} + +var _ typeValue = stringT{} + +func newString() stringT { + return stringT{NewMapping(testkey, testcdc, nil).Value(key()).String()} +} + +func (stringT) Proto() interface{} { + return new(string) +} + +func (v stringT) Get(ctx Context, ptr interface{}) { + reflect.ValueOf(ptr).Elem().SetString(v.String.Get(ctx)) +} + +func (v stringT) GetSafe(ctx Context, ptr interface{}) error { + res, err := v.String.GetSafe(ctx) + if err != nil { + return err + } + reflect.ValueOf(ptr).Elem().SetString(res) + return nil +} + +func (v stringT) Set(ctx Context, o interface{}) { + v.String.Set(ctx, o.(string)) +} + +func (v stringT) Marshal(o interface{}) []byte { + return []byte(o.(string)) +} + +func (v stringT) Unmarshal(bz []byte, ptr interface{}) { + reflect.ValueOf(ptr).Elem().SetString(string(bz)) +} + +func defaultComponents() sdk.Context { + 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 +} + +func indirect(ptr interface{}) interface{} { + return reflect.ValueOf(ptr).Elem().Interface() +} + +func TestTypeValue(t *testing.T) { + ctx := defaultComponents() + + var table = []struct { + ty typeValue + orig interface{} + }{ + {newBoolean(), false}, + {newBoolean(), true}, + {newInteger(Dec), uint64(1024000)}, + {newInteger(Dec), uint64(2048000)}, + {newInteger(Bin), uint64(4096000)}, + {newInteger(Bin), uint64(8192000)}, + {newInteger(Hex), uint64(16384000)}, + {newInteger(Hex), uint64(32768000)}, + {newEnum(), byte(0x00)}, + {newEnum(), byte(0x78)}, + {newEnum(), byte(0xA0)}, + {newString(), "1234567890"}, + {newString(), "asdfghjkl"}, + {newString(), "qwertyuiop"}, + } + + for i, tc := range table { + v := tc.ty + // Exists expected false + require.False(t, v.Exists(ctx)) + + // Simple get-set + v.Set(ctx, tc.orig) + ptr := v.Proto() + v.Get(ctx, ptr) + require.Equal(t, tc.orig, indirect(ptr), "Expected equal on tc %d", i) + ptr = v.Proto() + err := v.GetSafe(ctx, ptr) + require.NoError(t, err) + require.Equal(t, tc.orig, indirect(ptr), "Expected equal on tc %d", i) + + // Raw get + require.Equal(t, v.Marshal(tc.orig), v.GetRaw(ctx), "Expected equal on tc %d", i) + + // Exists expected true + require.True(t, v.Exists(ctx)) + + // After delete + v.Delete(ctx) + require.False(t, v.Exists(ctx)) + ptr = v.Proto() + err = v.GetSafe(ctx, ptr) + require.Error(t, err) + require.Equal(t, reflect.Zero(reflect.TypeOf(ptr).Elem()).Interface(), indirect(ptr)) + require.Nil(t, v.GetRaw(ctx)) + } +} From 9a077eb6ddcb1411de330b5a0eec771a0abfd7bd Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 29 Jul 2019 22:45:40 +0900 Subject: [PATCH 148/378] finalize merge --- x/ibc/23-commitment/value.go | 53 +++++++++++++++--------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 6e361fa75188..dd7205385616 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -6,59 +6,48 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// Base is a proof store accessor, consists of Codec and prefix. -// The base uses the commitment store which is expected to be filled with the proofs. -type Base struct { +type Mapping struct { cdc *codec.Codec prefix []byte } -func NewBase(cdc *codec.Codec) Base { - return Base{ - cdc: cdc, - } -} - -func (base Base) Store(ctx sdk.Context) Store { - return NewPrefix(GetStore(ctx), base.prefix) -} - -func (base Base) Prefix(prefix []byte) Base { - return Base{ - cdc: base.cdc, - prefix: join(base.prefix, prefix), +func NewMapping(cdc *codec.Codec, prefix []byte) Mapping { + return Mapping{ + cdc: cdc, + prefix: prefix, } } -type Mapping struct { - base Base +func (m Mapping) store(ctx sdk.Context) Store { + return NewPrefix(GetStore(ctx), m.prefix) } -func NewMapping(base Base, prefix []byte) Mapping { +func (m Mapping) Prefix(prefix []byte) Mapping { return Mapping{ - base: base.Prefix(prefix), + cdc: m.cdc, + prefix: join(m.prefix, prefix), } } // Value is for proving commitment proof on a speicifc key-value point in the other state // using the already initialized commitment store. type Value struct { - base Base - key []byte + m Mapping + key []byte } -func NewValue(base Base, key []byte) Value { - return Value{base, key} +func (m Mapping) Value(key []byte) Value { + return Value{m, key} } // Is() proves the proof with the Value's key and the provided value. func (v Value) Is(ctx sdk.Context, value interface{}) bool { - return v.base.Store(ctx).Prove(v.key, v.base.cdc.MustMarshalBinaryBare(value)) + return v.m.store(ctx).Prove(v.key, v.m.cdc.MustMarshalBinaryBare(value)) } // 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.base.Store(ctx).Prove(v.key, value) + return v.m.store(ctx).Prove(v.key, value) } // Enum is a byte typed wrapper for Value. @@ -67,8 +56,8 @@ type Enum struct { Value } -// NewEnum() wraps the argument Value as Enum -func NewEnum(v Value) Enum { +// Enum() wraps the argument Value as Enum +func (v Value) Enum() Enum { return Enum{v} } @@ -80,10 +69,12 @@ func (v Enum) Is(ctx sdk.Context, value byte) bool { // Integer is a uint64 types wrapper for Value. type Integer struct { Value + + enc state.IntEncoding } -func NewInteger(v Value) Integer { - return Integer{v} +func (v Value) Integer(enc state.IntEncoding) Integer { + return Integer{v, enc} } func (v Integer) Is(ctx sdk.Context, value uint64) bool { From a4a20d64dd27352d9b8f1d6ea1754492bd7cfdba Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 30 Jul 2019 17:03:42 +0900 Subject: [PATCH 149/378] add godoc --- x/ibc/23-commitment/codec.go | 1 + x/ibc/23-commitment/context.go | 11 ++++++----- x/ibc/23-commitment/store.go | 9 ++++++++- x/ibc/23-commitment/types.go | 9 +++++++++ x/ibc/23-commitment/value.go | 7 +++++++ 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/x/ibc/23-commitment/codec.go b/x/ibc/23-commitment/codec.go index 8e0bdf49aa9a..5b6573497e86 100644 --- a/x/ibc/23-commitment/codec.go +++ b/x/ibc/23-commitment/codec.go @@ -4,6 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) +// RegisterCodec registeres types declared in this package func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*Root)(nil), nil) cdc.RegisterInterface((*Path)(nil), nil) diff --git a/x/ibc/23-commitment/context.go b/x/ibc/23-commitment/context.go index 3680fb6b09bd..a0404e2a8927 100644 --- a/x/ibc/23-commitment/context.go +++ b/x/ibc/23-commitment/context.go @@ -4,14 +4,15 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// TODO: define Context type which embeds sdk.Context and ensures the existence of RemoteKVStore - -type ContextKeyRemoteKVStore struct{} +// ContextKeyCommitmentKVStore is a singleton type used as the key for the commitment store +type ContextKeyCommitmentKVStore struct{} +// WithStore returns the context updated with the store func WithStore(ctx sdk.Context, store Store) sdk.Context { - return ctx.WithValue(ContextKeyRemoteKVStore{}, store) + return ctx.WithValue(ContextKeyCommitmentKVStore{}, store) } +// GetStore returns the store from the context func GetStore(ctx sdk.Context) Store { - return ctx.Value(ContextKeyRemoteKVStore{}).(Store) + return ctx.Value(ContextKeyCommitmentKVStore{}).(Store) } diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 0bae09c8c669..efb52a151a20 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -5,6 +5,8 @@ import ( "errors" ) +// Store proves key-value pairs' inclusion or non-inclusion with +// the stored commitment proofs against the commitment root. type Store interface { Prove(key, value []byte) bool } @@ -36,7 +38,9 @@ type store struct { verified map[string][]byte } -// Proofs must be provided +// NewStore constructs a new Store with the root, path, and proofs. +// The proofs are not proven immediately because proofs require value bytes to verify. +// If the kinds of the arguments don't match, returns error. func NewStore(root Root, path Path, proofs []Proof) (res store, err error) { if root.CommitmentKind() != path.CommitmentKind() { err = errors.New("path type not matching with root's") @@ -61,11 +65,13 @@ func NewStore(root Root, path Path, proofs []Proof) (res store, err error) { return } +// Get() returns the value only if it is already proven. func (store store) Get(key []byte) ([]byte, bool) { res, ok := store.verified[string(key)] return res, ok } +// Prove() proves the key-value pair with the stored proof. func (store store) Prove(key, value []byte) bool { stored, ok := store.Get(key) if ok && bytes.Equal(stored, value) { @@ -84,6 +90,7 @@ func (store store) Prove(key, value []byte) bool { return true } +// Proven() returns true if the key-value pair is already proven func (store store) Proven(key []byte) bool { _, ok := store.Get(key) return ok diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go index 6453511a24e3..006e2b08c69e 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/types.go @@ -1,13 +1,22 @@ package commitment +// Root is the interface for commitment root. +// A root is constructed from a set of key-value pairs, +// and the inclusion or non-inclusion of an arbitrary key-value pair +// can be proven with the proof. type Root interface { CommitmentKind() string } +// Path is the additional information provided to the verification function. +// Path represents the common "prefix" that a set of keys shares. type Path interface { CommitmentKind() string } +// Proof can prove whether the key-value pair is a part of the Root or not. +// Each proof has designated key-value pair it is able to prove. +// Proofs stores key but value is provided dynamically at the verification time. type Proof interface { CommitmentKind() string GetKey() []byte diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index dd7205385616..65297b91b361 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -6,11 +6,15 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// Mapping is key []byte -> value []byte mapping, possibly prefixed. +// Proof verification should be done over Value constructed from the Mapping. type Mapping struct { cdc *codec.Codec prefix []byte } +// NewMapping() constructs a new Mapping. +// The KVStore accessor is fixed to the commitment store. func NewMapping(cdc *codec.Codec, prefix []byte) Mapping { return Mapping{ cdc: cdc, @@ -22,6 +26,7 @@ func (m Mapping) store(ctx sdk.Context) Store { return NewPrefix(GetStore(ctx), m.prefix) } +// Prefix() returns a new Mapping with the updated prefix func (m Mapping) Prefix(prefix []byte) Mapping { return Mapping{ cdc: m.cdc, @@ -73,10 +78,12 @@ type Integer struct { enc state.IntEncoding } +// Integer() wraps the argument Value as Integer func (v Value) Integer(enc state.IntEncoding) Integer { return Integer{v, enc} } +// Is() proves the proof with the Integer's key and the provided value func (v Integer) Is(ctx sdk.Context, value uint64) bool { return v.Value.IsRaw(ctx, state.EncodeInt(value, v.enc)) } From 02a9ba541cc09a127d759300ebedf497671de5ef Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 30 Jul 2019 17:46:12 +0900 Subject: [PATCH 150/378] add godoc in progress --- x/ibc/02-client/types.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/x/ibc/02-client/types.go b/x/ibc/02-client/types.go index 2a34855085b9..134837a43aa8 100644 --- a/x/ibc/02-client/types.go +++ b/x/ibc/02-client/types.go @@ -5,15 +5,24 @@ import ( ) // TODO: types in this file should be (de/)serialized with proto in the future -// currently amkno codec handles it +// currently amino codec handles it -// ConsensusState +// ConsensusState is the state of the consensus process. type ConsensusState interface { + // Kind() is the kind of the consensus algorithm. Kind() Kind GetHeight() uint64 + + // GetRoot() returns the commitment root of the consensus state, + // which is used for key-value pair verification. GetRoot() commitment.Root + + // Validate() returns the updated consensus state + // only if the header is a descendent of this consensus state. Validate(Header) (ConsensusState, error) // ValidityPredicate - Equivocation(Header, Header) bool // EquivocationPredicate + + // Equivocation checks two headers' confliction. + Equivocation(Header, Header) bool // EquivocationPredicate } /* @@ -23,8 +32,11 @@ func Equal(client1, client2 ConsensusState) bool { } */ +// Header is the consensus state update information. type Header interface { + // Kind() is the kind of the consensus algorithm. Kind() Kind + GetHeight() uint64 } From a9adb588dbdbc95099f08380f636128f9975d9c9 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 30 Jul 2019 18:07:31 +0900 Subject: [PATCH 151/378] reformat test --- x/ibc/23-commitment/merkle/merkle_test.go | 127 ++++++++++++++-------- 1 file changed, 82 insertions(+), 45 deletions(-) diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index e17c80ddf74f..a407d17c1868 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -1,6 +1,7 @@ package merkle import ( + "crypto/rand" "testing" "github.com/stretchr/testify/require" @@ -43,49 +44,85 @@ func TestStore(t *testing.T) { kvstore := ctx.KVStore(k) path := Path{KeyPath: [][]byte{[]byte("test")}, KeyPrefix: []byte{0x01, 0x03, 0x05}} - kvstore.Set(path.Key([]byte("hello")), []byte("world")) - kvstore.Set(path.Key([]byte("merkle")), []byte("tree")) - kvstore.Set(path.Key([]byte("block")), []byte("chain")) - - root := commit(cms) - - c1, v1, p1 := path.Query(cms, []byte("hello")) - require.Equal(t, uint32(0), c1) - require.Equal(t, []byte("world"), v1) - c2, v2, p2 := path.Query(cms, []byte("merkle")) - require.Equal(t, uint32(0), c2) - require.Equal(t, []byte("tree"), v2) - c3, v3, p3 := path.Query(cms, []byte("block")) - require.Equal(t, uint32(0), c3) - require.Equal(t, []byte("chain"), v3) - - cstore, err := commitment.NewStore(root, path, []commitment.Proof{p1, p2, p3}) - require.NoError(t, err) - - require.True(t, cstore.Prove([]byte("hello"), []byte("world"))) - require.True(t, cstore.Prove([]byte("merkle"), []byte("tree"))) - require.True(t, cstore.Prove([]byte("block"), []byte("chain"))) - - kvstore.Set(path.Key([]byte("12345")), []byte("67890")) - kvstore.Set(path.Key([]byte("qwerty")), []byte("zxcv")) - kvstore.Set(path.Key([]byte("hello")), []byte("dlrow")) - - root = commit(cms) - - c1, v1, p1 = path.Query(cms, []byte("12345")) - require.Equal(t, uint32(0), c1) - require.Equal(t, []byte("67890"), v1) - c2, v2, p2 = path.Query(cms, []byte("qwerty")) - require.Equal(t, uint32(0), c2) - require.Equal(t, []byte("zxcv"), v2) - c3, v3, p3 = path.Query(cms, []byte("hello")) - require.Equal(t, uint32(0), c3) - require.Equal(t, []byte("dlrow"), v3) - - cstore, err = commitment.NewStore(root, path, []commitment.Proof{p1, p2, p3}) - require.NoError(t, err) - - require.True(t, cstore.Prove([]byte("12345"), []byte("67890"))) - require.True(t, cstore.Prove([]byte("qwerty"), []byte("zxcv"))) - require.True(t, cstore.Prove([]byte("hello"), []byte("dlrow"))) + m := make(map[string][]byte) + kvpn := 1000 + + // Repeat 100 times to test on multiple commits + for repeat := 0; repeat < 10; repeat++ { + + // Initializes random generated key-value pairs + for i := 0; i < kvpn; i++ { + k, v := make([]byte, 64), make([]byte, 64) + rand.Read(k) + rand.Read(v) + m[string(k)] = v + kvstore.Set(path.Key(k), v) + } + + // Commit store + root := commit(cms) + + // Test query, and accumulate proofs + proofs := make([]commitment.Proof, 0, kvpn) + for k, v := range m { + c, v0, p := path.Query(cms, []byte(k)) + require.Equal(t, uint32(0), c) + require.Equal(t, v, v0) + proofs = append(proofs, p) + } + + // Add some exclusion proofs + for i := 0; i < 100; i++ { + k := make([]byte, 64) + rand.Read(k) + c, v, p := path.Query(cms, k) + require.Equal(t, uint32(0), c) + require.Nil(t, v) + proofs = append(proofs, p) + m[string(k)] = []byte{} + } + + cstore, err := commitment.NewStore(root, path, proofs) + require.NoError(t, err) + + // Test commitment store + for k, v := range m { + if len(v) != 0 { + require.True(t, cstore.Prove([]byte(k), v)) + } else { + require.True(t, cstore.Prove([]byte(k), nil)) + } + } + + // Modify existing data + for k := range m { + v := make([]byte, 64) + rand.Read(v) + m[k] = v + kvstore.Set(path.Key([]byte(k)), v) + } + + root = commit(cms) + + // Test query, and accumulate proofs + proofs = make([]commitment.Proof, 0, kvpn) + for k, v := range m { + c, v0, p := path.Query(cms, []byte(k)) + require.Equal(t, uint32(0), c) + require.Equal(t, v, v0) + proofs = append(proofs, p) + } + + cstore, err = commitment.NewStore(root, path, proofs) + require.NoError(t, err) + + // Test commitment store + for k, v := range m { + if len(v) != 0 { + require.True(t, cstore.Prove([]byte(k), v)) + } else { + require.True(t, cstore.Prove([]byte(k), nil)) + } + } + } } From abb2f5131d487882c0abb2ce83daa163c91dd0b8 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 30 Jul 2019 18:08:50 +0900 Subject: [PATCH 152/378] rm XXX --- x/ibc/23-commitment/merkle/utils.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index 86c6d6d18f3e..1a0880a3659f 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -39,5 +39,12 @@ func (path Path) Query(cms types.CommitMultiStore, key []byte) (uint32, []byte, } func (path Path) Key(key []byte) []byte { - return append(path.KeyPrefix, key...) // XXX: cloneAppend + return join(path.KeyPrefix, key) +} + +func join(a, b []byte) (res []byte) { + res = make([]byte, len(a)+len(b)) + copy(res, a) + copy(res[len(a):], b) + return } From 361aa42a93a4290766a54c38bf7959a1de3aee23 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 31 Jul 2019 04:01:46 +0900 Subject: [PATCH 153/378] add godoc --- x/ibc/23-commitment/merkle/merkle.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index a4a00a47db7b..a5acbdd43c3a 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -16,25 +16,35 @@ const merkleKind = "merkle" // Applied on SDK-based IBC implementation var _ commitment.Root = Root{} +// Root is Merkle root hash type Root struct { Hash []byte } +// NewRoot constructs a new Root func NewRoot(hash []byte) Root { - return Root{hash} + return Root{ + Hash: hash, + } } +// Implements commitment.Root func (Root) CommitmentKind() string { return merkleKind } var _ commitment.Path = Path{} +// Path is merkle path prefixed to the key. +// The constructed key from the Path and the key will be append(Path.KeyPath, append(Path.KeyPrefix, key...)) type Path struct { - KeyPath [][]byte + // KeyPath is the list of keys prepended before the prefixed key + KeyPath [][]byte + // KeyPrefix is a byte slice prefixed before the key KeyPrefix []byte } +// NewPath() constructs new Path func NewPath(keypath [][]byte, keyprefix []byte) Path { return Path{ KeyPath: keypath, @@ -42,25 +52,30 @@ func NewPath(keypath [][]byte, keyprefix []byte) Path { } } +// Implements commitment.Path func (Path) CommitmentKind() string { return merkleKind } var _ commitment.Proof = Proof{} +// Proof is Merkle proof with the key information. type Proof struct { Proof *merkle.Proof Key []byte } +// Implements commitment.Proof func (Proof) CommitmentKind() string { return merkleKind } +// Returns the key of the proof func (proof Proof) GetKey() []byte { return proof.Key } +// Verify() proves the proof against the given root, path, and value. func (proof Proof) Verify(croot commitment.Root, cpath commitment.Path, value []byte) error { root, ok := croot.(Root) if !ok { @@ -78,7 +93,7 @@ func (proof Proof) Verify(croot commitment.Root, cpath commitment.Path, value [] } keypath = keypath.AppendKey(append(path.KeyPrefix, proof.Key...), merkle.KeyEncodingHex) - // TODO: Hard coded for now, proof runtime should be extensible for other proof types + // TODO: hard coded for now, should be extensible runtime := rootmulti.DefaultProofRuntime() if value != nil { From 54a67b0b2106522dd65a80453abefe0585eef13c Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 31 Jul 2019 17:46:32 +0900 Subject: [PATCH 154/378] modify store --- x/ibc/02-client/cli.go | 42 +++---------- x/ibc/02-client/client/cli/query.go | 10 +-- x/ibc/02-client/manager.go | 74 +++++++++++------------ x/ibc/23-commitment/merkle/merkle.go | 16 ++++- x/ibc/23-commitment/merkle/merkle_test.go | 6 +- x/ibc/23-commitment/merkle/utils.go | 26 +++++++- 6 files changed, 92 insertions(+), 82 deletions(-) diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 382b1d2d4aea..d4a02a028c3a 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -2,53 +2,29 @@ package client import ( "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -// CLIObject stores the key for each object fields type CLIObject struct { - ID string - ConsensusStateKey []byte - FrozenKey []byte - - Path merkle.Path - Cdc *codec.Codec + obj Object } -func (man Manager) CLIObject(path merkle.Path, id string) CLIObject { - obj := man.object(id) - return CLIObject{ - ID: id, - ConsensusStateKey: obj.consensusState.Key(), - FrozenKey: obj.frozen.Key(), - - Path: path, - Cdc: obj.consensusState.Cdc(), - } +func (obj Object) CLIObject() CLIObject { + return CLIObject{obj} } -func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { - resp, err := ctx.QueryABCI(obj.Path.RequestQuery(key)) - if err != nil { - return merkle.Proof{}, err - } - proof := merkle.Proof{ - Key: key, - Proof: resp.Proof, - } - err = obj.Cdc.UnmarshalBinaryBare(resp.Value, ptr) - return proof, err - -} +// (path, ) func (obj CLIObject) ConsensusState(ctx context.CLIContext) (res ConsensusState, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.ConsensusStateKey, &res) + tmproof, err := obj.obj.ConsensusState.Query(ctx, &res) + proof = merkle.NewProofFromValue(tmproof, obj.obj.ConsensusState) return } func (obj CLIObject) Frozen(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.FrozenKey, &res) + res, tmproof, err := obj.obj.Frozen.Query(ctx) + proof = merkle.NewProofFromValue(tmproof, obj.obj.Frozen) return } + diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index fb2c7f73da0e..ed044444eeb8 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -15,15 +15,15 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + 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" ) -func components(cdc *codec.Codec, storeKey string, version int64) (path merkle.Path, base state.Base) { +func components(cdc *codec.Codec, storeKey string, version int64) (path merkle.Path, mapp state.Mapping) { prefix := []byte(strconv.FormatInt(version, 10) + "/") path = merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) - base = state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) + mapp = state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) return } @@ -50,8 +50,8 @@ 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) - path, base := components(cdc, storeKey, ibc.Version) - man := client.NewManager(base) + path, mapp := components(cdc, storeKey, ibc.Version) + man := client.NewManager(mapp) id := args[0] state, _, err := man.CLIObject(path, id).ConsensusState(ctx) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 4f5195bc1850..fe69a59caa05 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -3,21 +3,21 @@ package client import ( "errors" + "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/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -// XXX: implement spec: ClientState.verifiedRoots - +// Any actor holding the Manager can access on and modify any client information type Manager struct { protocol state.Mapping } -func NewManager(protocol state.Base) Manager { +func NewManager(base state.Mapping) Manager { return Manager{ - protocol: state.NewMapping(protocol, []byte("/client")), + protocol: base.Prefix([]byte("/client")), } } @@ -25,9 +25,9 @@ type CounterpartyManager struct { protocol commitment.Mapping } -func NewCounterpartyManager(protocol commitment.Base) CounterpartyManager { +func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { return CounterpartyManager{ - protocol: commitment.NewMapping(protocol, []byte("/client")), + protocol: commitment.NewMapping(cdc, []byte("/client")), } } @@ -40,72 +40,69 @@ func (man Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { return man } */ -func (man Manager) object(id string) Object { +func (man Manager) Object(id string) Object { return Object{ id: id, - consensusState: man.protocol.Value([]byte(id)), - frozen: state.NewBoolean(man.protocol.Value([]byte(id + "/freeze"))), + 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) + obj := man.Object(id) if obj.exists(ctx) { return Object{}, errors.New("Create client on already existing id") } - obj.consensusState.Set(ctx, cs) + obj.ConsensusState.Set(ctx, cs) return obj, nil } func (man Manager) Query(ctx sdk.Context, id string) (Object, error) { - res := man.object(id) + res := man.Object(id) if !res.exists(ctx) { return Object{}, errors.New("client not exists") } return res, nil } -func (man CounterpartyManager) object(id string) CounterObject { +func (man CounterpartyManager) Object(id string) CounterObject { return CounterObject{ id: id, - consensusState: man.protocol.Value([]byte(id)), + ConsensusState: man.protocol.Value([]byte(id)), } } func (man CounterpartyManager) Query(id string) CounterObject { - return man.object(id) + return man.Object(id) } +// Any actor holding the Object can access on and modify that client information type Object struct { id string - consensusState state.Value // ConsensusState - frozen state.Boolean + ConsensusState state.Value // ConsensusState + Frozen state.Boolean } type CounterObject struct { id string - consensusState commitment.Value + ConsensusState commitment.Value } func (obj Object) ID() string { return obj.id } -func (obj Object) ConsensusState(ctx sdk.Context) (res ConsensusState) { - obj.consensusState.Get(ctx, &res) +func (obj Object) GetConsensusState(ctx sdk.Context) (res ConsensusState) { + obj.ConsensusState.Get(ctx, &res) return } -func (obj Object) Frozen(ctx sdk.Context) bool { - return obj.frozen.Get(ctx) -} - func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { - return obj.consensusState.Is(ctx, client) + return obj.ConsensusState.Is(ctx, client) } func (obj Object) exists(ctx sdk.Context) bool { - return obj.consensusState.Exists(ctx) + return obj.ConsensusState.Exists(ctx) } func (obj Object) Update(ctx sdk.Context, header Header) error { @@ -113,18 +110,17 @@ func (obj Object) Update(ctx sdk.Context, header Header) error { panic("should not update nonexisting client") } - if obj.Frozen(ctx) { - return errors.New("client is frozen") + if obj.Frozen.Get(ctx) { + return errors.New("client is Frozen") } - var stored ConsensusState - obj.consensusState.Get(ctx, &stored) + stored := obj.GetConsensusState(ctx) updated, err := stored.Validate(header) if err != nil { return err } - obj.consensusState.Set(ctx, updated) + obj.ConsensusState.Set(ctx, updated) return nil } @@ -134,11 +130,11 @@ func (obj Object) Freeze(ctx sdk.Context) error { panic("should not freeze nonexisting client") } - if obj.Frozen(ctx) { - return errors.New("client is already frozen") + if obj.Frozen.Get(ctx) { + return errors.New("client is already Frozen") } - obj.frozen.Set(ctx, true) + obj.Frozen.Set(ctx, true) return nil } @@ -148,12 +144,12 @@ func (obj Object) Delete(ctx sdk.Context) error { panic("should not delete nonexisting client") } - if !obj.Frozen(ctx) { - return errors.New("client is not frozen") + if !obj.Frozen.Get(ctx) { + return errors.New("client is not Frozen") } - obj.consensusState.Delete(ctx) - obj.frozen.Delete(ctx) + obj.ConsensusState.Delete(ctx) + obj.Frozen.Delete(ctx) return nil } diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index a5acbdd43c3a..9e0b5e6b1152 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -6,8 +6,9 @@ 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/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) const merkleKind = "merkle" @@ -57,6 +58,10 @@ func (Path) CommitmentKind() string { return merkleKind } +func NewPathFromMapping(mapp state.Mapping) Path { + return NewPath([][]byte{[]byte(mapp.StoreName())}, mapp.PrefixBytes()) +} + var _ commitment.Proof = Proof{} // Proof is Merkle proof with the key information. @@ -101,3 +106,12 @@ func (proof Proof) Verify(croot commitment.Root, cpath commitment.Path, value [] } return runtime.VerifyAbsence(proof.Proof, root.Hash, keypath.String()) } + +type Value interface { + KeyBytes() []byte + Unmarshal([]byte, interface{}) +} + +func NewProofFromValue(proof *merkle.Proof, value Value) Proof { + return Proof{proof, value.KeyBytes()} +} diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index fab3880a06a0..4c4f49ce274a 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -65,7 +65,7 @@ func TestStore(t *testing.T) { // Test query, and accumulate proofs proofs := make([]commitment.Proof, 0, kvpn) for k, v := range m { - c, v0, p := path.Query(cms, []byte(k)) + c, v0, p := path.QueryMultiStore(cms, []byte(k)) require.Equal(t, uint32(0), c) require.Equal(t, v, v0) proofs = append(proofs, p) @@ -75,7 +75,7 @@ func TestStore(t *testing.T) { for i := 0; i < 100; i++ { k := make([]byte, 64) rand.Read(k) - c, v, p := path.Query(cms, k) + c, v, p := path.QueryMultiStore(cms, k) require.Equal(t, uint32(0), c) require.Nil(t, v) proofs = append(proofs, p) @@ -107,7 +107,7 @@ func TestStore(t *testing.T) { // Test query, and accumulate proofs proofs = make([]commitment.Proof, 0, kvpn) for k, v := range m { - c, v0, p := path.Query(cms, []byte(k)) + c, v0, p := path.QueryMultiStore(cms, []byte(k)) require.Equal(t, uint32(0), c) require.Equal(t, v, v0) proofs = append(proofs, p) diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index e1659d696432..b8497c757cae 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -1,8 +1,12 @@ package merkle import ( + "errors" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/types" ) @@ -28,12 +32,32 @@ func (path Path) RequestQueryMultiStore(key []byte) abci.RequestQuery { return abci.RequestQuery{Path: path.Path() + "/key", Data: path.Key(key), Prove: true} } +func (path Path) Query(ctx context.CLIContext, key []byte) (code uint32, value []byte, proof Proof, err error) { + resp, err := ctx.QueryABCI(path.RequestQuery(key)) + if err != nil { + return code, value, proof, err + } + if !resp.IsOK() { + return resp.Code, value, proof, errors.New(resp.Log) + } + return resp.Code, resp.Value, Proof{Key: key, Proof: resp.Proof}, nil +} + +func (path Path) QueryValue(ctx context.CLIContext, cdc *codec.Codec, key []byte, ptr interface{}) (Proof, error) { + _, value, proof, err := path.Query(ctx, key) + if err != nil { + return Proof{}, err + } + err = cdc.UnmarshalBinaryBare(value, ptr) // TODO + return proof, err +} + func (path Path) QueryMultiStore(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { queryable, ok := cms.(types.Queryable) if !ok { panic("CommitMultiStore not queryable") } - qres := queryable.Query(path.RequestQuery(key)) + qres := queryable.Query(path.RequestQueryMultiStore(key)) return qres.Code, qres.Value, Proof{Key: key, Proof: qres.Proof} } From 24e621a128de159bb32eb7eb5f847a63b367e51f Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 31 Jul 2019 18:58:47 +0900 Subject: [PATCH 155/378] add query --- store/state/enum.go | 5 +++++ store/state/integer.go | 9 ++++++++ store/state/string.go | 5 +++++ store/state/types.go | 5 +++++ store/state/value.go | 50 +++++++++++++++++++++++++++++++++++++++--- 5 files changed, 71 insertions(+), 3 deletions(-) diff --git a/store/state/enum.go b/store/state/enum.go index 67f18a4a2584..bc43f8c69007 100644 --- a/store/state/enum.go +++ b/store/state/enum.go @@ -47,3 +47,8 @@ func (v Enum) Transit(ctx Context, from, to byte) bool { v.Set(ctx, to) return true } + +func (v Enum) Query(ctx CLIContext) (res byte, proof *Proof, err error) { + value, proof, err := v.Value.QueryRaw(ctx) + return value[0], proof, err +} diff --git a/store/state/integer.go b/store/state/integer.go index 187fd718d55e..499fbe414ec2 100644 --- a/store/state/integer.go +++ b/store/state/integer.go @@ -51,3 +51,12 @@ func (v Integer) Incr(ctx Context) (res uint64) { v.Set(ctx, res) return } + +func (v Integer) Query(ctx CLIContext) (res uint64, proof *Proof, err error) { + value, proof, err := v.Value.QueryRaw(ctx) + if err != nil { + return + } + res, err = DecodeInt(value, v.enc) + return +} diff --git a/store/state/string.go b/store/state/string.go index 72c85340d01f..c084362d0e03 100644 --- a/store/state/string.go +++ b/store/state/string.go @@ -30,3 +30,8 @@ func (v String) GetSafe(ctx Context) (res string, err error) { func (v String) Set(ctx Context, value string) { v.Value.SetRaw(ctx, []byte(value)) } + +func (v String) Query(ctx CLIContext) (res string, proof *Proof, err error) { + value, proof, err := v.Value.QueryRaw(ctx) + return string(value), proof, err +} diff --git a/store/state/types.go b/store/state/types.go index a8d34d582a82..f5dbb4dc8648 100644 --- a/store/state/types.go +++ b/store/state/types.go @@ -1,8 +1,13 @@ package state import ( + "github.com/tendermint/tendermint/crypto/merkle" + + "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" ) type KVStore = sdk.KVStore type Context = sdk.Context +type CLIContext = context.CLIContext +type Proof = merkle.Proof diff --git a/store/state/value.go b/store/state/value.go index 7878ae2f191e..5b39818aeebb 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -1,6 +1,10 @@ package state import ( + "errors" + + abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/codec" ) @@ -29,12 +33,24 @@ func (v Value) Cdc() *codec.Codec { return v.m.Cdc() } +func (v Value) Marshal(value interface{}) []byte { + return v.m.cdc.MustMarshalBinaryBare(value) +} + +func (v Value) Unmarshal(bz []byte, ptr interface{}) error { + return v.m.cdc.UnmarshalBinaryBare(bz, ptr) +} + +func (v Value) mustUnmarshal(bz []byte, ptr interface{}) { + v.m.cdc.MustUnmarshalBinaryBare(bz, ptr) +} + // Get() unmarshales and sets the stored value to the pointer if it exists. // It will panic if the value exists but not unmarshalable. func (v Value) Get(ctx Context, ptr interface{}) { bz := v.store(ctx).Get(v.key) if bz != nil { - v.m.cdc.MustUnmarshalBinaryBare(bz, ptr) + v.mustUnmarshal(bz, ptr) } } @@ -45,7 +61,7 @@ func (v Value) GetSafe(ctx Context, ptr interface{}) error { if bz == nil { return ErrEmptyValue() } - err := v.m.cdc.UnmarshalBinaryBare(bz, ptr) + err := v.Unmarshal(bz, ptr) if err != nil { return ErrUnmarshal(err) } @@ -59,7 +75,7 @@ func (v Value) GetRaw(ctx Context) []byte { // Set() marshales and sets the argument to the state. func (v Value) Set(ctx Context, o interface{}) { - v.store(ctx).Set(v.key, v.m.cdc.MustMarshalBinaryBare(o)) + v.store(ctx).Set(v.key, v.Marshal(o)) } // SetRaw() sets the raw bytes to the state. @@ -83,3 +99,31 @@ func (v Value) Delete(ctx Context) { func (v Value) KeyBytes() []byte { return v.m.KeyBytes(v.key) } + +func (v Value) QueryRaw(ctx CLIContext) ([]byte, *Proof, error) { + req := abci.RequestQuery{ + Path: "/store" + v.m.StoreName() + "/key", + Data: v.KeyBytes(), + Prove: true, + } + + resp, err := ctx.QueryABCI(req) + if err != nil { + return nil, nil, err + } + + if !resp.IsOK() { + return nil, nil, errors.New(resp.Log) + } + + return resp.Value, resp.Proof, nil +} + +func (v Value) Query(ctx CLIContext, ptr interface{}) (*Proof, error) { + value, proof, err := v.QueryRaw(ctx) + if err != nil { + return nil, err + } + err = v.Cdc().UnmarshalBinaryBare(value, ptr) + return proof, err +} From 64c0381ff00f489b1426f2425de2153e4b834677 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 31 Jul 2019 19:05:53 +0900 Subject: [PATCH 156/378] update query.go --- client/context/query.go | 47 +++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 2dc8ab217f59..98cd30690f0c 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -49,6 +49,12 @@ func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, in return ctx.queryStore(key, storeName, "key") } +// QueryABCI performs a query to a Tendermint node with the provide RequestQuery. +// It returns the ResultQuery obtained from the query. +func (ctx CLIContext) QueryABCI(req abci.RequestQuery) (abci.ResponseQuery, error) { + return ctx.queryABCI(req) +} + // QuerySubspace performs a query to a Tendermint node with the provided // store name and subspace. It returns key value pair and height of the query // upon success or an error if the query fails. @@ -72,13 +78,10 @@ func (ctx CLIContext) GetFromName() string { return ctx.FromName } -// query performs a query to a Tendermint node with the provided store name -// and path. It returns the result and height of the query upon success -// or an error if the query fails. -func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) { +func (ctx CLIContext) queryABCI(req abci.RequestQuery) (resp abci.ResponseQuery, err error) { node, err := ctx.GetNode() if err != nil { - return res, height, err + return } // When a client did not provide a query height, manually query for it so it can @@ -86,7 +89,7 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height i if ctx.Height == 0 { status, err := node.Status() if err != nil { - return res, height, err + return resp, err } ctx = ctx.WithHeight(status.SyncInfo.LatestBlockHeight) } @@ -96,24 +99,40 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height i Prove: !ctx.TrustNode, } - result, err := node.ABCIQueryWithOptions(path, key, opts) + result, err := node.ABCIQueryWithOptions(req.Path, req.Data, opts) if err != nil { - return res, height, err + return } - resp := result.Response + resp = result.Response if !resp.IsOK() { - return res, height, errors.New(resp.Log) + err = errors.New(resp.Log) + return } // data from trusted node or subspace query doesn't need verification - if ctx.TrustNode || !isQueryStoreWithProof(path) { - return resp.Value, resp.Height, nil + if ctx.TrustNode || !isQueryStoreWithProof(req.Path) { + return resp, nil } - err = ctx.verifyProof(path, resp) + err = ctx.verifyProof(req.Path, resp) if err != nil { - return res, height, err + return + } + + return +} + +// query performs a query to a Tendermint node with the provided store name +// and path. It returns the result and height of the query upon success +// or an error if the query fails. +func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) { + resp, err := ctx.queryABCI(abci.RequestQuery{ + Path: path, + Data: key, + }) + if err != nil { + return } return resp.Value, resp.Height, nil From 971a642a721031faae20eea9a9cef86f4bed7215 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 31 Jul 2019 19:13:57 +0900 Subject: [PATCH 157/378] update query.go --- client/context/query.go | 47 +++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 2dc8ab217f59..98cd30690f0c 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -49,6 +49,12 @@ func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, in return ctx.queryStore(key, storeName, "key") } +// QueryABCI performs a query to a Tendermint node with the provide RequestQuery. +// It returns the ResultQuery obtained from the query. +func (ctx CLIContext) QueryABCI(req abci.RequestQuery) (abci.ResponseQuery, error) { + return ctx.queryABCI(req) +} + // QuerySubspace performs a query to a Tendermint node with the provided // store name and subspace. It returns key value pair and height of the query // upon success or an error if the query fails. @@ -72,13 +78,10 @@ func (ctx CLIContext) GetFromName() string { return ctx.FromName } -// query performs a query to a Tendermint node with the provided store name -// and path. It returns the result and height of the query upon success -// or an error if the query fails. -func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) { +func (ctx CLIContext) queryABCI(req abci.RequestQuery) (resp abci.ResponseQuery, err error) { node, err := ctx.GetNode() if err != nil { - return res, height, err + return } // When a client did not provide a query height, manually query for it so it can @@ -86,7 +89,7 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height i if ctx.Height == 0 { status, err := node.Status() if err != nil { - return res, height, err + return resp, err } ctx = ctx.WithHeight(status.SyncInfo.LatestBlockHeight) } @@ -96,24 +99,40 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height i Prove: !ctx.TrustNode, } - result, err := node.ABCIQueryWithOptions(path, key, opts) + result, err := node.ABCIQueryWithOptions(req.Path, req.Data, opts) if err != nil { - return res, height, err + return } - resp := result.Response + resp = result.Response if !resp.IsOK() { - return res, height, errors.New(resp.Log) + err = errors.New(resp.Log) + return } // data from trusted node or subspace query doesn't need verification - if ctx.TrustNode || !isQueryStoreWithProof(path) { - return resp.Value, resp.Height, nil + if ctx.TrustNode || !isQueryStoreWithProof(req.Path) { + return resp, nil } - err = ctx.verifyProof(path, resp) + err = ctx.verifyProof(req.Path, resp) if err != nil { - return res, height, err + return + } + + return +} + +// query performs a query to a Tendermint node with the provided store name +// and path. It returns the result and height of the query upon success +// or an error if the query fails. +func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) { + resp, err := ctx.queryABCI(abci.RequestQuery{ + Path: path, + Data: key, + }) + if err != nil { + return } return resp.Value, resp.Height, nil From e7f67085a8411f0c4f10f0ab4056da321b6a145b Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 31 Jul 2019 22:42:51 +0900 Subject: [PATCH 158/378] cli refactor in progress --- x/ibc/02-client/cli.go | 2 -- x/ibc/02-client/client/cli/query.go | 10 ++++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index d4a02a028c3a..acf0ecc2218c 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -14,8 +14,6 @@ func (obj Object) CLIObject() CLIObject { return CLIObject{obj} } -// (path, ) - func (obj CLIObject) ConsensusState(ctx context.CLIContext) (res ConsensusState, proof merkle.Proof, err error) { tmproof, err := obj.obj.ConsensusState.Query(ctx, &res) proof = merkle.NewProofFromValue(tmproof, obj.obj.ConsensusState) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index ed044444eeb8..6232d50e2a5f 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -20,11 +20,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func components(cdc *codec.Codec, storeKey string, version int64) (path merkle.Path, mapp state.Mapping) { +func mapping(cdc *codec.Codec, storeKey string, version int64) state.Mapping { prefix := []byte(strconv.FormatInt(version, 10) + "/") - path = merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) - mapp = state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) - return + return state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) } func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { @@ -50,11 +48,11 @@ 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) - path, mapp := components(cdc, storeKey, ibc.Version) + mapp := mapping(cdc, storeKey, ibc.Version) man := client.NewManager(mapp) id := args[0] - state, _, err := man.CLIObject(path, id).ConsensusState(ctx) + state, _, err := man.Object(id).CLIObject().ConsensusState(ctx) if err != nil { return err } From 0d134d5e61afad671cde87c02a1a217edd19f63c Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 31 Jul 2019 22:43:20 +0900 Subject: [PATCH 159/378] cli refactor in progress --- x/ibc/23-commitment/merkle/merkle.go | 7 ++- x/ibc/23-commitment/merkle/merkle_test.go | 32 ++++++----- x/ibc/23-commitment/merkle/utils.go | 67 ++++++++++++++--------- 3 files changed, 63 insertions(+), 43 deletions(-) diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index 9e0b5e6b1152..615b49ccadb9 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -1,6 +1,7 @@ package merkle import ( + "bytes" "errors" "github.com/tendermint/tendermint/crypto/merkle" @@ -109,9 +110,9 @@ func (proof Proof) Verify(croot commitment.Root, cpath commitment.Path, value [] type Value interface { KeyBytes() []byte - Unmarshal([]byte, interface{}) } -func NewProofFromValue(proof *merkle.Proof, value Value) Proof { - return Proof{proof, value.KeyBytes()} +func NewProofFromValue(proof *merkle.Proof, path Path, value Value) Proof { + // TODO: check HasPrefix + return Proof{proof, bytes.TrimPrefix(value.KeyBytes(), path.KeyPrefix)} } diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index 4c4f49ce274a..3c49a2dee82b 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store" + "github.com/cosmos/cosmos-sdk/store/state" "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -40,23 +41,24 @@ func commit(cms types.CommitMultiStore) Root { // TestStore tests Merkle proof on the commitment.Store // Sets/upates key-value pairs and prove with the query result proofs func TestStore(t *testing.T) { - k, ctx, cms, _ := defaultComponents() - kvstore := ctx.KVStore(k) - path := Path{KeyPath: [][]byte{[]byte("test")}, KeyPrefix: []byte{0x01, 0x03, 0x05}} + k, ctx, cms, cdc := defaultComponents() + prefix := []byte{0x01, 0x03, 0x05, 0xAA, 0xBB} + mapp := state.NewMapping(k, cdc, prefix) + path := NewPath([][]byte{[]byte(k.Name())}, prefix) m := make(map[string][]byte) - kvpn := 1000 + kvpn := 10 - // Repeat 100 times to test on multiple commits + // Repeat to test on multiple commits for repeat := 0; repeat < 10; repeat++ { // Initializes random generated key-value pairs for i := 0; i < kvpn; i++ { - k, v := make([]byte, 64), make([]byte, 64) + k, v := make([]byte, 16), make([]byte, 16) rand.Read(k) rand.Read(v) m[string(k)] = v - kvstore.Set(path.Key(k), v) + mapp.Value(k).Set(ctx, v) } // Commit store @@ -65,18 +67,18 @@ func TestStore(t *testing.T) { // Test query, and accumulate proofs proofs := make([]commitment.Proof, 0, kvpn) for k, v := range m { - c, v0, p := path.QueryMultiStore(cms, []byte(k)) - require.Equal(t, uint32(0), c) + v0, p, err := QueryMultiStore(cms, path, []byte(k)) + require.NoError(t, err) require.Equal(t, v, v0) proofs = append(proofs, p) } // Add some exclusion proofs - for i := 0; i < 100; i++ { + for i := 0; i < 10; i++ { k := make([]byte, 64) rand.Read(k) - c, v, p := path.QueryMultiStore(cms, k) - require.Equal(t, uint32(0), c) + v, p, err := QueryMultiStore(cms, path, k) + require.NoError(t, err) require.Nil(t, v) proofs = append(proofs, p) m[string(k)] = []byte{} @@ -99,7 +101,7 @@ func TestStore(t *testing.T) { v := make([]byte, 64) rand.Read(v) m[k] = v - kvstore.Set(path.Key([]byte(k)), v) + mapp.Value([]byte(k)).Set(ctx, v) } root = commit(cms) @@ -107,8 +109,8 @@ func TestStore(t *testing.T) { // Test query, and accumulate proofs proofs = make([]commitment.Proof, 0, kvpn) for k, v := range m { - c, v0, p := path.QueryMultiStore(cms, []byte(k)) - require.Equal(t, uint32(0), c) + v0, p, err := QueryMultiStore(cms, path, []byte(k)) + require.NoError(t, err) require.Equal(t, v, v0) proofs = append(proofs, p) } diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index b8497c757cae..4dbd6cb292ec 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -1,15 +1,53 @@ package merkle import ( + "bytes" "errors" + "fmt" abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/types" ) +func QueryMultiStore(cms types.CommitMultiStore, path Path, key []byte) ([]byte, Proof, error) { + queryable, ok := cms.(types.Queryable) + if !ok { + panic("CommitMultiStore not queryable") + } + qres := queryable.Query(RequestQueryMultiStore(path, key)) + if !qres.IsOK() { + return nil, Proof{}, errors.New(qres.Log) + } + + fmt.Printf("Q: %X -> %X\n", path.Key(key), qres.Value) + return qres.Value, Proof{Key: key, Proof: qres.Proof}, nil +} + +func RequestQueryMultiStore(path Path, key []byte) abci.RequestQuery { + // Suffixing path with "/key". + // iavl.Store.Query() switches over the last path element, + // and performs key-value query only if it is "/key" + return abci.RequestQuery{ + Path: "/" + string(bytes.Join(path.KeyPath, []byte("/"))) + "/key", + Data: path.Key(key), + Prove: true, + } +} + +func (path Path) Key(key []byte) []byte { + return join(path.KeyPrefix, key) +} + +func join(a, b []byte) (res []byte) { + res = make([]byte, len(a)+len(b)) + copy(res, a) + copy(res[len(a):], b) + return +} + +/* + // RequestQuery() constructs the abci.RequestQuery. // // RequestQuery.Path is a slash separated key list, ending with "/key" @@ -25,12 +63,6 @@ func (path Path) RequestQuery(key []byte) abci.RequestQuery { return req } -func (path Path) RequestQueryMultiStore(key []byte) abci.RequestQuery { - // Suffixing path with "/key". - // iavl.Store.Query() switches over the last path element, - // and performs key-value query only if it is "/key" - return abci.RequestQuery{Path: path.Path() + "/key", Data: path.Key(key), Prove: true} -} func (path Path) Query(ctx context.CLIContext, key []byte) (code uint32, value []byte, proof Proof, err error) { resp, err := ctx.QueryABCI(path.RequestQuery(key)) @@ -52,25 +84,9 @@ func (path Path) QueryValue(ctx context.CLIContext, cdc *codec.Codec, key []byte return proof, err } -func (path Path) QueryMultiStore(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { - queryable, ok := cms.(types.Queryable) - if !ok { - panic("CommitMultiStore not queryable") - } - qres := queryable.Query(path.RequestQueryMultiStore(key)) - return qres.Code, qres.Value, Proof{Key: key, Proof: qres.Proof} -} -func (path Path) Key(key []byte) []byte { - return join(path.KeyPrefix, key) -} -func join(a, b []byte) (res []byte) { - res = make([]byte, len(a)+len(b)) - copy(res, a) - copy(res[len(a):], b) - return -} + func (path Path) Path() string { pathstr := "" @@ -81,3 +97,4 @@ func (path Path) Path() string { return pathstr } +*/ From fcad48756a63197911b95685e3e382014ceee207 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 1 Aug 2019 21:02:44 +0900 Subject: [PATCH 160/378] add Query to boolean.go --- store/state/boolean.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/store/state/boolean.go b/store/state/boolean.go index 5d582b6869d7..f7873c2e775a 100644 --- a/store/state/boolean.go +++ b/store/state/boolean.go @@ -30,3 +30,8 @@ func (v Boolean) GetSafe(ctx Context) (res bool, err error) { func (v Boolean) Set(ctx Context, value bool) { v.Value.Set(ctx, value) } + +func (v Boolean) Query(ctx CLIContext) (res bool, proof *Proof, err error) { + proof, err = v.Value.Query(ctx, &res) + return +} From 6de0ed530aa2e05bb353041f4fe103b2407df410 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 1 Aug 2019 22:34:01 +0900 Subject: [PATCH 161/378] fix key --- store/state/value.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/store/state/value.go b/store/state/value.go index 5b39818aeebb..c54445f59e9f 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -48,7 +48,7 @@ func (v Value) mustUnmarshal(bz []byte, ptr interface{}) { // Get() unmarshales and sets the stored value to the pointer if it exists. // It will panic if the value exists but not unmarshalable. func (v Value) Get(ctx Context, ptr interface{}) { - bz := v.store(ctx).Get(v.key) + bz := v.store(ctx).Get(v.KeyBytes()) if bz != nil { v.mustUnmarshal(bz, ptr) } @@ -57,7 +57,7 @@ func (v Value) Get(ctx Context, ptr interface{}) { // GetSafe() unmarshales and sets the stored value to the pointer. // It will return an error if the value does not exist or unmarshalable. func (v Value) GetSafe(ctx Context, ptr interface{}) error { - bz := v.store(ctx).Get(v.key) + bz := v.store(ctx).Get(v.KeyBytes()) if bz == nil { return ErrEmptyValue() } @@ -70,29 +70,29 @@ func (v Value) GetSafe(ctx Context, ptr interface{}) error { // GetRaw() returns the raw bytes that is stored in the state. func (v Value) GetRaw(ctx Context) []byte { - return v.store(ctx).Get(v.key) + return v.store(ctx).Get(v.KeyBytes()) } // Set() marshales and sets the argument to the state. func (v Value) Set(ctx Context, o interface{}) { - v.store(ctx).Set(v.key, v.Marshal(o)) + v.store(ctx).Set(v.KeyBytes(), v.Marshal(o)) } // SetRaw() sets the raw bytes to the state. func (v Value) SetRaw(ctx Context, bz []byte) { - v.store(ctx).Set(v.key, bz) + v.store(ctx).Set(v.KeyBytes(), bz) } // Exists() returns true if the stored value is not nil. // Calles KVStore.Has() internally func (v Value) Exists(ctx Context) bool { - return v.store(ctx).Has(v.key) + return v.store(ctx).Has(v.KeyBytes()) } // Delete() deletes the stored value. // Calles KVStore.Delete() internally func (v Value) Delete(ctx Context) { - v.store(ctx).Delete(v.key) + v.store(ctx).Delete(v.KeyBytes()) } // KeyBytes() returns the prefixed key that the Value is providing to the KVStore From 62b7d75ebe3718b9b016a1bbb7c479650c7ce68c Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 1 Aug 2019 23:41:12 +0900 Subject: [PATCH 162/378] fix cli / merkle test --- x/ibc/02-client/cli.go | 20 ++++++-------------- x/ibc/02-client/client/cli/query.go | 8 ++++---- x/ibc/02-client/tendermint/tests/types.go | 4 ++-- x/ibc/23-commitment/merkle/merkle_test.go | 8 ++++---- x/ibc/23-commitment/merkle/utils.go | 2 -- 5 files changed, 16 insertions(+), 26 deletions(-) diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index acf0ecc2218c..aa563f3c170b 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -6,23 +6,15 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -type CLIObject struct { - obj Object -} - -func (obj Object) CLIObject() CLIObject { - return CLIObject{obj} -} - -func (obj CLIObject) ConsensusState(ctx context.CLIContext) (res ConsensusState, proof merkle.Proof, err error) { - tmproof, err := obj.obj.ConsensusState.Query(ctx, &res) - proof = merkle.NewProofFromValue(tmproof, obj.obj.ConsensusState) +func (obj Object) ConsensusStateCLI(ctx context.CLIContext, path merkle.Path) (res ConsensusState, proof merkle.Proof, err error) { + tmproof, err := obj.ConsensusState.Query(ctx, &res) + proof = merkle.NewProofFromValue(tmproof, path, obj.ConsensusState) return } -func (obj CLIObject) Frozen(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { - res, tmproof, err := obj.obj.Frozen.Query(ctx) - proof = merkle.NewProofFromValue(tmproof, obj.obj.Frozen) +func (obj Object) FrozenCLI(ctx context.CLIContext, path merkle.Path) (res bool, proof merkle.Proof, err error) { + res, tmproof, err := obj.Frozen.Query(ctx) + proof = merkle.NewProofFromValue(tmproof, path, obj.Frozen) return } diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 6232d50e2a5f..1cf445dae389 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -20,9 +20,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func mapping(cdc *codec.Codec, storeKey string, version int64) state.Mapping { +func mapping(cdc *codec.Codec, storeKey string, version int64) (state.Mapping, merkle.Path) { prefix := []byte(strconv.FormatInt(version, 10) + "/") - return state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) + return state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix), merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) } func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { @@ -48,11 +48,11 @@ 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) + mapp, path := mapping(cdc, storeKey, ibc.Version) man := client.NewManager(mapp) id := args[0] - state, _, err := man.Object(id).CLIObject().ConsensusState(ctx) + state, _, err := man.Object(id).ConsensusStateCLI(ctx, path) if err != nil { return err } diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index f9fd9fc9f0c8..40caa5d6f041 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -143,8 +143,8 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset Mock } func (node *Node) Query(t *testing.T, path merkle.Path, k []byte) ([]byte, commitment.Proof) { - code, value, proof := path.QueryMultiStore(node.Cms, k) - require.Equal(t, uint32(0), code) + value, proof, err := merkle.QueryMultiStore(node.Cms, path, k) + require.NoError(t, err) return value, proof } diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index 3c49a2dee82b..2624d54eccde 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -69,7 +69,7 @@ func TestStore(t *testing.T) { for k, v := range m { v0, p, err := QueryMultiStore(cms, path, []byte(k)) require.NoError(t, err) - require.Equal(t, v, v0) + require.Equal(t, cdc.MustMarshalBinaryBare(v), v0, "Queried value different at %d", repeat) proofs = append(proofs, p) } @@ -90,7 +90,7 @@ func TestStore(t *testing.T) { // Test commitment store for k, v := range m { if len(v) != 0 { - require.True(t, cstore.Prove([]byte(k), v)) + require.True(t, cstore.Prove([]byte(k), cdc.MustMarshalBinaryBare(v))) } else { require.True(t, cstore.Prove([]byte(k), nil)) } @@ -111,7 +111,7 @@ func TestStore(t *testing.T) { for k, v := range m { v0, p, err := QueryMultiStore(cms, path, []byte(k)) require.NoError(t, err) - require.Equal(t, v, v0) + require.Equal(t, cdc.MustMarshalBinaryBare(v), v0) proofs = append(proofs, p) } @@ -121,7 +121,7 @@ func TestStore(t *testing.T) { // Test commitment store for k, v := range m { if len(v) != 0 { - require.True(t, cstore.Prove([]byte(k), v)) + require.True(t, cstore.Prove([]byte(k), cdc.MustMarshalBinaryBare(v))) } else { require.True(t, cstore.Prove([]byte(k), nil)) } diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index 4dbd6cb292ec..b71d4500963b 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -3,7 +3,6 @@ package merkle import ( "bytes" "errors" - "fmt" abci "github.com/tendermint/tendermint/abci/types" @@ -20,7 +19,6 @@ func QueryMultiStore(cms types.CommitMultiStore, path Path, key []byte) ([]byte, return nil, Proof{}, errors.New(qres.Log) } - fmt.Printf("Q: %X -> %X\n", path.Key(key), qres.Value) return qres.Value, Proof{Key: key, Proof: qres.Proof}, nil } From 6dc912ff9d31b9ab67ace2c6cc652714094d0c2a Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 7 Aug 2019 09:18:53 -0400 Subject: [PATCH 163/378] godoc cleanup --- client/context/query.go | 2 +- store/state/boolean.go | 10 +++++----- store/state/enum.go | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 98cd30690f0c..1e2d8136bf07 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -81,7 +81,7 @@ func (ctx CLIContext) GetFromName() string { func (ctx CLIContext) queryABCI(req abci.RequestQuery) (resp abci.ResponseQuery, err error) { node, err := ctx.GetNode() if err != nil { - return + return resp, err } // When a client did not provide a query height, manually query for it so it can diff --git a/store/state/boolean.go b/store/state/boolean.go index 5d582b6869d7..5c9d1fd5e863 100644 --- a/store/state/boolean.go +++ b/store/state/boolean.go @@ -12,21 +12,21 @@ func (v Value) Boolean() Boolean { return Boolean{v} } -// Get() unmarshales and returns the stored boolean value if it exists. -// It will panic if the value exists but is not boolean type. +// Get decodes and returns the stored boolean value if it exists. It will panic +// if the value exists but is not boolean type. func (v Boolean) Get(ctx Context) (res bool) { v.Value.Get(ctx, &res) return } -// GetSafe() unmarshales and returns the stored boolean value. -// It will return an error if the value does not exist or not boolean. +// GetSafe decodes and returns the stored boolean value. It will return an error +// if the value does not exist or not boolean. func (v Boolean) GetSafe(ctx Context) (res bool, err error) { err = v.Value.GetSafe(ctx, &res) return } -// Set() marshales and sets the boolean argument to the state. +// Set encodes and sets the boolean argument to the state. func (v Boolean) Set(ctx Context, value bool) { v.Value.Set(ctx, value) } diff --git a/store/state/enum.go b/store/state/enum.go index bc43f8c69007..a638b854f8f0 100644 --- a/store/state/enum.go +++ b/store/state/enum.go @@ -10,14 +10,14 @@ func (v Value) Enum() Enum { return Enum{v} } -// Get() unmarshales and returns the stored byte value if it exists. -// It will panic if the value exists but is not byte type. +// Get decodes and returns the stored byte value if it exists. It will panic if +// the value exists but is not byte type. func (v Enum) Get(ctx Context) (res byte) { return v.Value.GetRaw(ctx)[0] } -// GetSafe() unmarshales and returns the stored byte value. -// It will returns an error if the value does not exists or not byte. +// GetSafe decodes and returns the stored byte value. It will returns an error +// if the value does not exists or not byte. func (v Enum) GetSafe(ctx Context) (res byte, err error) { bz := v.Value.GetRaw(ctx) if bz == nil { @@ -26,19 +26,19 @@ func (v Enum) GetSafe(ctx Context) (res byte, err error) { return bz[0], nil // TODO: check length } -// Set() marshales and sets the byte argument to the state. +// Set encodes and sets the byte argument to the state. func (v Enum) Set(ctx Context, value byte) { v.Value.SetRaw(ctx, []byte{value}) } -// Incr() increments the stored value, and returns the updated value. +// Incr increments the stored value, and returns the updated value. func (v Enum) Incr(ctx Context) (res byte) { res = v.Get(ctx) + 1 v.Set(ctx, res) return } -// Transit() checks whether the stored value matching with the "from" argument. +// Transit checks whether the stored value matching with the "from" argument. // If it matches, it stores the "to" argument to the state and returns true. func (v Enum) Transit(ctx Context, from, to byte) bool { if v.Get(ctx) != from { From 63c6f3ce2427292b55023d60db4a73bd5f5790aa Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 7 Aug 2019 09:26:58 -0400 Subject: [PATCH 164/378] godoc cleanup --- store/state/indexer.go | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/store/state/indexer.go b/store/state/indexer.go index 6b837c2021a3..8eea25e520a8 100644 --- a/store/state/indexer.go +++ b/store/state/indexer.go @@ -22,16 +22,16 @@ const ( Bin ) -// Indexer is a integer typed key wrapper for Mapping. -// Except for the type checking, it does not alter the behaviour. -// All keys are encoded depending on the IntEncoding +// Indexer is a integer typed key wrapper for Mapping. Except for the type +// checking, it does not alter the behaviour. All keys are encoded depending on +// the IntEncoding. type Indexer struct { m Mapping enc IntEncoding } -// NewIndexer() constructs the Indexer with a predetermined prefix and IntEncoding +// NewIndexer constructs the Indexer with a predetermined prefix and IntEncoding. func NewIndexer(m Mapping, enc IntEncoding) Indexer { return Indexer{ m: m, @@ -39,72 +39,78 @@ func NewIndexer(m Mapping, enc IntEncoding) Indexer { } } -// Order preserving integer encoding function. +// EncodeInt provides order preserving integer encoding function. func EncodeInt(index uint64, enc IntEncoding) (res []byte) { switch enc { case Dec: - // Returns decimal number index, 20-length 0 padded + // return decimal number index, 20-length 0 padded return []byte(fmt.Sprintf("%020d", index)) + case Hex: - // Returns hexadecimal number index, 20-length 0 padded + // return hexadecimal number index, 20-length 0 padded return []byte(fmt.Sprintf("%016x", index)) + case Bin: - // Returns bigendian encoded number index, 8-length + // return bigendian encoded number index, 8-length res = make([]byte, 8) binary.BigEndian.PutUint64(res, index) return + default: panic("invalid IntEncoding") } } -// Integer decoding function, inversion of EncodeInt +// DecodeInt provides integer decoding function, inversion of EncodeInt. func DecodeInt(bz []byte, enc IntEncoding) (res uint64, err error) { switch enc { case Dec: return strconv.ParseUint(string(bz), 10, 64) + case Hex: return strconv.ParseUint(string(bz), 16, 64) + case Bin: return binary.BigEndian.Uint64(bz), nil + default: panic("invalid IntEncoding") } } -// Value() returns the Value corresponding to the provided index +// Value returns the Value corresponding to the provided index. func (ix Indexer) Value(index uint64) Value { return ix.m.Value(EncodeInt(index, ix.enc)) } -// Get() unmarshales and sets the stored value to the pointer if it exists. -// It will panic if the value exists but not unmarshalable. +// Get decodes and sets the stored value to the pointer if it exists. It will +// panic if the value exists but not unmarshalable. func (ix Indexer) Get(ctx Context, index uint64, ptr interface{}) { ix.Value(index).Get(ctx, ptr) } -// GetSafe() unmarshales and sets the stored value to the pointer. -// It will return an error if the value does not exist or unmarshalable. +// GetSafe decodes and sets the stored value to the pointer. It will return an +// error if the value does not exist or unmarshalable. func (ix Indexer) GetSafe(ctx Context, index uint64, ptr interface{}) error { return ix.Value(index).GetSafe(ctx, ptr) } -// Set() marshales and sets the argument to the state. +// Set encodes and sets the argument to the state. func (ix Indexer) Set(ctx Context, index uint64, o interface{}) { ix.Value(index).Set(ctx, o) } -// Has() returns true if the stored value is not nil +// Has returns true if the stored value is not nil. func (ix Indexer) Has(ctx Context, index uint64) bool { return ix.Value(index).Exists(ctx) } -// Delete() delets the stored value. +// Delete removes the stored value. func (ix Indexer) Delete(ctx Context, index uint64) { ix.Value(index).Delete(ctx) } -// Prefix() returns a new Indexer with the updated prefix +// Prefix returns a new Indexer with the updated prefix func (ix Indexer) Prefix(prefix []byte) Indexer { return Indexer{ m: ix.m.Prefix(prefix), From b6441c04c525d2d9b945de280d3dc22b21618658 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 7 Aug 2019 09:30:28 -0400 Subject: [PATCH 165/378] godoc cleanup --- store/state/mapping.go | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/store/state/mapping.go b/store/state/mapping.go index 95a96974416b..ae7b3dc18151 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -6,14 +6,15 @@ import ( ) // Mapping is key []byte -> value []byte mapping using a base(possibly prefixed). -// All store accessing operations are redirected to the Value corresponding to the key argument +// All store accessing operations are redirected to the Value corresponding to +// the key argument. type Mapping struct { storeKey sdk.StoreKey cdc *codec.Codec prefix []byte } -// NewMapping() constructs a Mapping with a provided prefix +// NewMapping constructs a Mapping with a provided prefix. func NewMapping(storeKey sdk.StoreKey, cdc *codec.Codec, prefix []byte) Mapping { return Mapping{ storeKey: storeKey, @@ -22,25 +23,25 @@ func NewMapping(storeKey sdk.StoreKey, cdc *codec.Codec, prefix []byte) Mapping } } -// Value() returns the Value corresponding to the provided key +// Value returns the Value corresponding to the provided key. func (m Mapping) Value(key []byte) Value { return NewValue(m, key) } -// Get() unmarshales and sets the stored value to the pointer if it exists. -// It will panic if the value exists but not unmarshalable. +// Get decodes and sets the stored value to the pointer if it exists. It will +// panic if the value exists but not unmarshalable. func (m Mapping) Get(ctx Context, key []byte, ptr interface{}) { m.Value(key).Get(ctx, ptr) } -// GetSafe() unmarshales and sets the stored value to the pointer. -// It will return an error if the value does not exist or unmarshalable. +// GetSafe decodes and sets the stored value to the pointer. It will return an +// error if the value does not exist or unmarshalable. func (m Mapping) GetSafe(ctx Context, key []byte, ptr interface{}) error { return m.Value(key).GetSafe(ctx, ptr) } -// Set() marshales and sets the argument to the state. -// Calls Delete() if the argument is nil. +// Set encodes and sets the argument to the state. It calls Delete if the +// argument is nil. func (m Mapping) Set(ctx Context, key []byte, o interface{}) { if o == nil { m.Delete(ctx, key) @@ -49,12 +50,12 @@ func (m Mapping) Set(ctx Context, key []byte, o interface{}) { m.Value(key).Set(ctx, o) } -// Has() returns true if the stored value is not nil +// Has returns true if the stored value is not nil. func (m Mapping) Has(ctx Context, key []byte) bool { return m.Value(key).Exists(ctx) } -// Delete() deletes the stored value. +// Delete removes the stored value. func (m Mapping) Delete(ctx Context, key []byte) { m.Value(key).Delete(ctx) } @@ -63,16 +64,19 @@ func (m Mapping) Cdc() *codec.Codec { return m.cdc } +// StoreName returns the mapping's store name. func (m Mapping) StoreName() string { return m.storeKey.Name() } +// PrefixBytes returns the mapping's prefix bytes. func (m Mapping) PrefixBytes() (res []byte) { res = make([]byte, len(m.prefix)) copy(res, m.prefix) return } +// KeyBytes returns the mapping's key bytes. func (m Mapping) KeyBytes(key []byte) (res []byte) { return join(m.prefix, key) } @@ -84,7 +88,7 @@ func join(a, b []byte) (res []byte) { return } -// Prefix() returns a new mapping with the updated prefix. +// Prefix returns a new mapping with an updated prefix. func (m Mapping) Prefix(prefix []byte) Mapping { return Mapping{ storeKey: m.storeKey, From 4d723ae8484661f396f1038449b07a29a0d14bc5 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 7 Aug 2019 09:32:25 -0400 Subject: [PATCH 166/378] godoc cleanup --- store/state/string.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/store/state/string.go b/store/state/string.go index c084362d0e03..233a88adae6a 100644 --- a/store/state/string.go +++ b/store/state/string.go @@ -10,14 +10,14 @@ func (v Value) String() String { return String{v} } -// Get() unmarshales and returns the stored string value if it exists. -// It will panic if the value exists but is not strin type. +// Get decodes and returns the stored string value if it exists. It will panic +// if the value exists but is not string type. func (v String) Get(ctx Context) (res string) { return string(v.Value.GetRaw(ctx)) } -// GetSafe() unmarshales and returns the stored string value. -// It will return an error if the value does not exist or not string +// GetSafe decodes and returns the stored string value. It will return an error +// if the value does not exist or not string. func (v String) GetSafe(ctx Context) (res string, err error) { bz := v.Value.GetRaw(ctx) if bz == nil { @@ -26,7 +26,7 @@ func (v String) GetSafe(ctx Context) (res string, err error) { return string(bz), nil } -// Set() marshales and sets the string argument to the state. +// Set encodes and sets the string argument to the state. func (v String) Set(ctx Context, value string) { v.Value.SetRaw(ctx, []byte(value)) } From 244d2c256c352aa521be779bc2bf7d20a66b0dfb Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 7 Aug 2019 09:35:20 -0400 Subject: [PATCH 167/378] godoc cleanup --- store/state/value.go | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/store/state/value.go b/store/state/value.go index 5b39818aeebb..8aa591304fd4 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -8,15 +8,15 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -// Value is a capability for reading and writing on a specific key-value point in the state. -// Value consists of Base and key []byte. -// An actor holding a Value has a full access right on that state point. +// Value is a capability for reading and writing on a specific key-value point +// in the state. Value consists of Base and key []byte. An actor holding a Value +// has a full access right on that state point. type Value struct { m Mapping key []byte } -// NewValue() constructs a Value +// NewValue constructs a Value. func NewValue(m Mapping, key []byte) Value { return Value{ m: m, @@ -45,8 +45,8 @@ func (v Value) mustUnmarshal(bz []byte, ptr interface{}) { v.m.cdc.MustUnmarshalBinaryBare(bz, ptr) } -// Get() unmarshales and sets the stored value to the pointer if it exists. -// It will panic if the value exists but not unmarshalable. +// Get decodes and sets the stored value to the pointer if it exists. It will +// panic if the value exists but not unmarshalable. func (v Value) Get(ctx Context, ptr interface{}) { bz := v.store(ctx).Get(v.key) if bz != nil { @@ -54,8 +54,8 @@ func (v Value) Get(ctx Context, ptr interface{}) { } } -// GetSafe() unmarshales and sets the stored value to the pointer. -// It will return an error if the value does not exist or unmarshalable. +// GetSafe decodes and sets the stored value to the pointer. It will return an +// error if the value does not exist or unmarshalable. func (v Value) GetSafe(ctx Context, ptr interface{}) error { bz := v.store(ctx).Get(v.key) if bz == nil { @@ -68,34 +68,33 @@ func (v Value) GetSafe(ctx Context, ptr interface{}) error { return nil } -// GetRaw() returns the raw bytes that is stored in the state. +// GetRaw returns the raw bytes that is stored in the state. func (v Value) GetRaw(ctx Context) []byte { return v.store(ctx).Get(v.key) } -// Set() marshales and sets the argument to the state. +// Set encodes and sets the argument to the state. func (v Value) Set(ctx Context, o interface{}) { v.store(ctx).Set(v.key, v.Marshal(o)) } -// SetRaw() sets the raw bytes to the state. +// SetRaw sets the raw bytes to the state. func (v Value) SetRaw(ctx Context, bz []byte) { v.store(ctx).Set(v.key, bz) } -// Exists() returns true if the stored value is not nil. -// Calles KVStore.Has() internally +// Exists returns true if the stored value is not nil. It calls KVStore.Has() +// internally. func (v Value) Exists(ctx Context) bool { return v.store(ctx).Has(v.key) } -// Delete() deletes the stored value. -// Calles KVStore.Delete() internally +// Delete removes the stored value. It calls KVStore.Delete() internally. func (v Value) Delete(ctx Context) { v.store(ctx).Delete(v.key) } -// KeyBytes() returns the prefixed key that the Value is providing to the KVStore +// KeyBytes returns the prefixed key that the Value is providing to the KVStore. func (v Value) KeyBytes() []byte { return v.m.KeyBytes(v.key) } From 7286fed7868a390be026fa32610b9701e1e81793 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 15 Aug 2019 02:22:47 +0900 Subject: [PATCH 168/378] fix test --- store/state/value.go | 12 ++ x/ibc/02-client/keys.go | 5 + x/ibc/02-client/manager.go | 4 +- .../tendermint/tests/tendermint_test.go | 4 +- x/ibc/02-client/tendermint/tests/types.go | 30 ++-- x/ibc/02-client/tendermint/tests/utils.go | 8 + x/ibc/03-connection/cli.go | 142 +++-------------- x/ibc/03-connection/client/cli/query.go | 6 +- x/ibc/03-connection/handshake.go | 150 ++++++++---------- x/ibc/03-connection/keys.go | 5 + x/ibc/03-connection/manager.go | 90 +++++------ x/ibc/03-connection/tests/connection_test.go | 20 +-- x/ibc/03-connection/tests/types.go | 52 +++--- x/ibc/23-commitment/merkle/merkle.go | 6 +- x/ibc/23-commitment/merkle/merkle_test.go | 9 +- x/ibc/23-commitment/merkle/utils.go | 11 +- x/ibc/23-commitment/store.go | 10 +- x/ibc/23-commitment/value.go | 8 +- 18 files changed, 248 insertions(+), 324 deletions(-) create mode 100644 x/ibc/02-client/keys.go create mode 100644 x/ibc/02-client/tendermint/tests/utils.go create mode 100644 x/ibc/03-connection/keys.go diff --git a/store/state/value.go b/store/state/value.go index c54445f59e9f..c3b4b3089bbc 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -95,6 +95,18 @@ func (v Value) Delete(ctx Context) { v.store(ctx).Delete(v.KeyBytes()) } +func (v Value) StoreName() string { + return v.m.StoreName() +} + +func (v Value) PrefixBytes() []byte { + return v.m.PrefixBytes() +} + +func (v Value) KeyBytesRaw() []byte { + return v.key +} + // KeyBytes() returns the prefixed key that the Value is providing to the KVStore func (v Value) KeyBytes() []byte { return v.m.KeyBytes(v.key) diff --git a/x/ibc/02-client/keys.go b/x/ibc/02-client/keys.go new file mode 100644 index 000000000000..a67761f20d36 --- /dev/null +++ b/x/ibc/02-client/keys.go @@ -0,0 +1,5 @@ +package client + +func LocalRoot() []byte { + return []byte("client/") +} diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index fe69a59caa05..eb9a83ff7d2e 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -17,7 +17,7 @@ type Manager struct { func NewManager(base state.Mapping) Manager { return Manager{ - protocol: base.Prefix([]byte("/client")), + protocol: base.Prefix(LocalRoot()), } } @@ -27,7 +27,7 @@ type CounterpartyManager struct { func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { return CounterpartyManager{ - protocol: commitment.NewMapping(cdc, []byte("/client")), + protocol: commitment.NewMapping(cdc, LocalRoot()), } } diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go index df63032b3986..e7d09644126a 100644 --- a/x/ibc/02-client/tendermint/tests/tendermint_test.go +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -4,12 +4,10 @@ import ( "testing" "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) func testUpdate(t *testing.T, interval int, ok bool) { - node := NewNode(NewMockValidators(100, 10), merkle.NewPath([][]byte{[]byte("f8wib")}, []byte{0x98, 0x78})) + node := NewNode(NewMockValidators(100, 10), "f8wib", []byte{0x98, 0x78}) _ = node.Commit() diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index c27ad9837822..027d3a28a5f5 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -3,6 +3,7 @@ package tendermint import ( "crypto/rand" "testing" + "bytes" "github.com/stretchr/testify/require" @@ -50,11 +51,12 @@ type Node struct { Commits []tmtypes.SignedHeader - Path merkle.Path + StoreName string + Prefix []byte } -func NewNode(valset MockValidators, path merkle.Path) *Node { - key, ctx, cms, _ := defaultComponents(string(path.KeyPath[0])) +func NewNode(valset MockValidators, storeName string, prefix []byte) *Node { + key, ctx, cms, _ := defaultComponents(storeName) return &Node{ Valset: valset, @@ -62,10 +64,15 @@ func NewNode(valset MockValidators, path merkle.Path) *Node { Key: key, Store: ctx.KVStore(key), Commits: nil, - Path: path, + StoreName: storeName, + Prefix: prefix, } } +func (node *Node) Path() merkle.Path { + return merkle.NewPath([][]byte{[]byte(node.StoreName)}, node.Prefix) +} + func (node *Node) Last() tmtypes.SignedHeader { if len(node.Commits) == 0 { return tmtypes.SignedHeader{} @@ -143,19 +150,22 @@ func (v *Verifier) Validate(header tendermint.Header, valset, nextvalset MockVal } -func (node *Node) Query(t *testing.T, path merkle.Path, k []byte) ([]byte, commitment.Proof) { - value, proof, err := merkle.QueryMultiStore(node.Cms, path, k) +func (node *Node) Query(t *testing.T, k []byte) ([]byte, commitment.Proof) { + if bytes.HasPrefix(k, node.Prefix) { + k = bytes.TrimPrefix(k, node.Prefix) + } + value, proof, err := merkle.QueryMultiStore(node.Cms, node.StoreName, node.Prefix, k) require.NoError(t, err) return value, proof } func (node *Node) Set(k, value []byte) { - node.Store.Set(node.Path.Key(k), value) + node.Store.Set(join(node.Prefix, k), value) } // nolint:deadcode,unused func testProof(t *testing.T) { - node := NewNode(NewMockValidators(100, 10), merkle.NewPath([][]byte{[]byte("1")}, []byte{0x00, 0x01})) + node := NewNode(NewMockValidators(100, 10), "1", []byte{0x00, 0x01}) node.Commit() @@ -176,12 +186,12 @@ func testProof(t *testing.T) { proofs := []commitment.Proof{} root := merkle.NewRoot(header.AppHash) for _, kvp := range kvps { - v, p := node.Query(t, node.Path.Key(kvp.Key)) + v, p := node.Query(t, kvp.Key) require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } - cstore, err := commitment.NewStore(root, node.Path, proofs) + cstore, err := commitment.NewStore(root, node.Path(), proofs) require.NoError(t, err) for _, kvp := range kvps { diff --git a/x/ibc/02-client/tendermint/tests/utils.go b/x/ibc/02-client/tendermint/tests/utils.go new file mode 100644 index 000000000000..d5262a14a29b --- /dev/null +++ b/x/ibc/02-client/tendermint/tests/utils.go @@ -0,0 +1,8 @@ +package tendermint + +func join(a, b []byte) (res []byte) { + res = make([]byte, len(a)+len(b)) + copy(res, a) + copy(res[len(a):], b) + return +} diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index a9617d4b0e38..8503be6b02e6 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -1,145 +1,53 @@ package connection import ( - abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -// CLIObject stores the key for each object fields -type CLIObject struct { - ID string - ConnectionKey []byte - AvailableKey []byte - KindKey []byte - - Client client.CLIObject - - StoreName string - Cdc *codec.Codec -} - -func (man Manager) CLIQuery(ctx context.CLIContext, path merkle.Path, id string) CLIObject { - res := man.CLIObject(path, id, "") - - connection, _, err := res.Connection(ctx) - if err != nil { - return res - } - res.Client = man.client.CLIObject(path, connection.Client) - return res -} - -func (man Manager) CLIObject(path merkle.Path, id, clientid string) CLIObject { - obj := man.object(id) - return CLIObject{ - ID: obj.id, - ConnectionKey: obj.connection.Key(), - AvailableKey: obj.available.Key(), - KindKey: obj.kind.Key(), - - Client: man.client.CLIObject(path, clientid), - - StoreName: man.protocol.StoreName(), - Cdc: obj.connection.Cdc(), - } -} - -func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { - resp, err := ctx.QueryABCI(abci.RequestQuery{ - Path: "/store/" + obj.StoreName + "/key", - Data: key, - }) - if err != nil { - return merkle.Proof{}, err - } - proof := merkle.Proof{ - Key: key, - Proof: resp.Proof, - } - err = obj.Cdc.UnmarshalBinaryBare(resp.Value, ptr) - return proof, err - +func (man Manager) CLIObject(connid, clientid string) Object { + obj := man.Object(connid) + obj.Client = man.client.Object(clientid) + return obj } -func (obj CLIObject) Connection(ctx context.CLIContext) (res Connection, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.ConnectionKey, &res) +func (obj Object) ConnectionCLI(ctx context.CLIContext, path merkle.Path) (res Connection, proof merkle.Proof, err error) { + tmproof, err := obj.Connection.Query(ctx, &res) + proof = merkle.NewProofFromValue(tmproof, path, obj.Connection) return } -func (obj CLIObject) Available(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.AvailableKey, &res) +func (obj Object) AvailableCLI(ctx context.CLIContext, path merkle.Path) (res bool, proof merkle.Proof, err error) { + res, tmproof, err := obj.Available.Query(ctx) + proof = merkle.NewProofFromValue(tmproof, path, obj.Available) return } -func (obj CLIObject) Kind(ctx context.CLIContext) (res string, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.KindKey, &res) +func (obj Object) KindCLI(ctx context.CLIContext, path merkle.Path) (res string, proof merkle.Proof, err error) { + res, tmproof, err := obj.Kind.Query(ctx) + proof = merkle.NewProofFromValue(tmproof, path, obj.Kind) return } -type CLIHandshakeObject struct { - CLIObject - - StateKey []byte - CounterpartyClientKey []byte - TimeoutKey []byte +func (man Handshaker) CLIObject(connid, clientid string) HandshakeObject { + return man.Object(man.man.CLIObject(connid, clientid)) } -func (man Handshaker) CLIQuery(ctx context.CLIContext, path merkle.Path, id string) CLIHandshakeObject { - obj := man.object(man.man.object(id)) - return CLIHandshakeObject{ - CLIObject: man.man.CLIQuery(ctx, path, id), - - StateKey: obj.state.Key(), - CounterpartyClientKey: obj.counterpartyClient.Key(), - TimeoutKey: obj.nextTimeout.Key(), - } -} - -func (man Handshaker) CLIObject(path merkle.Path, id, clientid string) CLIHandshakeObject { - obj := man.object(man.man.object(id)) - return CLIHandshakeObject{ - CLIObject: man.man.CLIObject(path, id, clientid), - - StateKey: obj.state.Key(), - CounterpartyClientKey: obj.counterpartyClient.Key(), - TimeoutKey: obj.nextTimeout.Key(), - } - -} - -func (obj CLIHandshakeObject) State(ctx context.CLIContext) (res byte, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.StateKey, &res) - return -} - -func (obj CLIHandshakeObject) CounterpartyClient(ctx context.CLIContext) (res string, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.CounterpartyClientKey, &res) +func (obj HandshakeObject) StateCLI(ctx context.CLIContext, path merkle.Path) (res byte, proof merkle.Proof, err error){ + res, tmproof, err := obj.State.Query(ctx) + proof = merkle.NewProofFromValue(tmproof, path, obj.State) return } -func (obj CLIHandshakeObject) NextTimeout(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.TimeoutKey, &res) - return -} - -/* -func (obj CLIObject) State(ctx context.CLIContext, root merkle.Root) (res bool, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.StateKey, &res) - return -} - -func (obj CLIObject) NextTimeout(ctx context.CLIContext, root merkle.Root) (res time.Time, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.NextTimeoutKey, &res) - return +func (obj HandshakeObject) CounterpartyClientCLI(ctx context.CLIContext, path merkle.Path) (res string, proof merkle.Proof, err error) { + res, tmproof, err := obj.CounterpartyClient.Query(ctx) + proof = merkle.NewProofFromValue(tmproof, path, obj.CounterpartyClient) + return } -func (obj CLIObject) Permission(ctx context.CLIContext, root merkle.Root) (res string, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.PermissionKey, &res) +func (obj HandshakeObject) NextTimeoutCLI(ctx context.CLIContext, path merkle.Path) (res uint64, proof merkle.Proof, err error){ + res, tmproof, err := obj.NextTimeout.Query(ctx) + proof = merkle.NewProofFromValue(tmproof, path, obj.NextTimeout) return } -*/ diff --git a/x/ibc/03-connection/client/cli/query.go b/x/ibc/03-connection/client/cli/query.go index efc30534e913..6be3c81bd9ce 100644 --- a/x/ibc/03-connection/client/cli/query.go +++ b/x/ibc/03-connection/client/cli/query.go @@ -24,13 +24,13 @@ const ( FlagProve = "prove" ) -func object(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, id string) connection.CLIObject { +func object(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, id string) connection.Object { prefix := []byte(strconv.FormatInt(version, 10) + "/") path := merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) - base := state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) + base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) climan := client.NewManager(base) man := connection.NewManager(base, climan) - return man.CLIQuery(ctx, path, id) + return man.Query(ctx, path, id) } func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index c8a69c7fb9b5..c5d9debba1a3 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -46,41 +46,41 @@ type CounterpartyHandshaker struct { type HandshakeObject struct { Object - state state.Enum - counterpartyClient state.String - nextTimeout state.Integer + State state.Enum + CounterpartyClient state.String + NextTimeout state.Integer - counterparty CounterHandshakeObject + Counterparty CounterHandshakeObject } type CounterHandshakeObject struct { CounterObject - state commitment.Enum - counterpartyClient commitment.String - nextTimeout commitment.Integer + State 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 { +func (man Handshaker) Object(parent Object) HandshakeObject { return HandshakeObject{ Object: parent, - state: state.NewEnum(man.man.protocol.Value([]byte(parent.id + "/state"))), - counterpartyClient: state.NewString(man.man.protocol.Value([]byte(parent.id + "/counterpartyClient"))), - nextTimeout: state.NewInteger(man.man.protocol.Value([]byte(parent.id+"/timeout")), state.Dec), + State: 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 } } -func (man CounterpartyHandshaker) object(id string) CounterHandshakeObject { +func (man CounterpartyHandshaker) Object(id string) CounterHandshakeObject { return CounterHandshakeObject{ - CounterObject: man.man.object(id), + CounterObject: man.man.Object(id), - state: commitment.NewEnum(man.man.protocol.Value([]byte(id + "/state"))), - counterpartyClient: commitment.NewString(man.man.protocol.Value([]byte(id + "/counterpartyClient"))), - nextTimeout: commitment.NewInteger(man.man.protocol.Value([]byte(id+"/timeout")), state.Dec), + State: 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), } } @@ -89,9 +89,9 @@ func (man Handshaker) create(ctx sdk.Context, id string, connection Connection, if err != nil { return } - obj = man.object(cobj) - obj.counterpartyClient.Set(ctx, counterpartyClient) - obj.counterparty = man.counterparty.object(connection.Counterparty) + obj = man.Object(cobj) + obj.CounterpartyClient.Set(ctx, counterpartyClient) + obj.Counterparty = man.counterparty.Object(connection.Counterparty) return obj, nil } @@ -100,32 +100,16 @@ func (man Handshaker) query(ctx sdk.Context, id string) (obj HandshakeObject, er if err != nil { return } - obj = man.object(cobj) - obj.counterparty = man.counterparty.object(obj.Connection(ctx).Counterparty) + obj = man.Object(cobj) + obj.Counterparty = man.counterparty.Object(obj.GetConnection(ctx).Counterparty) return } -func (obj HandshakeObject) State(ctx sdk.Context) byte { - return obj.state.Get(ctx) -} - -func (obj HandshakeObject) CounterpartyClient(ctx sdk.Context) string { - return obj.counterpartyClient.Get(ctx) -} - -func (obj HandshakeObject) Timeout(ctx sdk.Context) uint64 { - return obj.nextTimeout.Get(ctx) -} - -func (obj HandshakeObject) NextTimeout(ctx sdk.Context) uint64 { - return obj.nextTimeout.Get(ctx) -} - func (obj HandshakeObject) remove(ctx sdk.Context) { obj.Object.remove(ctx) - obj.state.Delete(ctx) - obj.counterpartyClient.Delete(ctx) - obj.nextTimeout.Delete(ctx) + obj.State.Delete(ctx) + obj.CounterpartyClient.Delete(ctx) + obj.NextTimeout.Delete(ctx) } func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { @@ -148,8 +132,8 @@ func (man Handshaker) OpenInit(ctx sdk.Context, return HandshakeObject{}, err } - obj.nextTimeout.Set(ctx, nextTimeoutHeight) - obj.state.Set(ctx, Init) + obj.NextTimeout.Set(ctx, nextTimeoutHeight) + obj.State.Set(ctx, Init) return obj, nil } @@ -174,12 +158,12 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - if !obj.counterparty.state.Is(ctx, Init) { + if !obj.Counterparty.State.Is(ctx, Init) { err = errors.New("counterparty state not init") return } - if !obj.counterparty.connection.Is(ctx, Connection{ + if !obj.Counterparty.Connection.Is(ctx, Connection{ Client: counterpartyClient, Counterparty: id, Path: obj.path, @@ -188,12 +172,12 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - if !obj.counterparty.counterpartyClient.Is(ctx, connection.Client) { + if !obj.Counterparty.CounterpartyClient.Is(ctx, connection.Client) { err = errors.New("counterparty client not match") return } - if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { + if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { err = errors.New("unexpected counterparty timeout value") return } @@ -214,8 +198,8 @@ 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.State.Set(ctx, OpenTry) + obj.NextTimeout.Set(ctx, nextTimeoutHeight) return } @@ -235,7 +219,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.state.Transit(ctx, Init, Open) { + if !obj.State.Transit(ctx, Init, Open) { err = errors.New("ack on non-init connection") return } @@ -245,8 +229,8 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.counterparty.connection.Is(ctx, Connection{ - Client: obj.CounterpartyClient(ctx), + if !obj.Counterparty.Connection.Is(ctx, Connection{ + Client: obj.CounterpartyClient.Get(ctx), Counterparty: obj.ID(), Path: obj.path, }) { @@ -254,17 +238,17 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.counterparty.state.Is(ctx, OpenTry) { + if !obj.Counterparty.State.Is(ctx, OpenTry) { err = errors.New("counterparty state not opentry") return } - if !obj.counterparty.counterpartyClient.Is(ctx, obj.Connection(ctx).Client) { + 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) { + if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { err = errors.New("unexpected counterparty timeout value") return } @@ -277,8 +261,8 @@ func (man Handshaker) OpenAck(ctx sdk.Context, // return errors.New("unexpected counterparty client value") } */ - obj.available.Set(ctx, true) - obj.nextTimeout.Set(ctx, nextTimeoutHeight) + obj.Available.Set(ctx, true) + obj.NextTimeout.Set(ctx, nextTimeoutHeight) return } @@ -298,7 +282,7 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, return } - if !obj.state.Transit(ctx, OpenTry, Open) { + if !obj.State.Transit(ctx, OpenTry, Open) { err = errors.New("confirm on non-try connection") return } @@ -308,40 +292,40 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, return } - if !obj.counterparty.state.Is(ctx, Open) { + if !obj.Counterparty.State.Is(ctx, Open) { err = errors.New("counterparty state not open") return } - if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { + if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { err = errors.New("unexpected counterparty timeout value") return } - obj.available.Set(ctx, true) - obj.nextTimeout.Set(ctx, 0) + obj.Available.Set(ctx, true) + obj.NextTimeout.Set(ctx, 0) return } func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { - if !(obj.client.ConsensusState(ctx).GetHeight() > obj.nextTimeout.Get(ctx)) { + if !(obj.Client.GetConsensusState(ctx).GetHeight() > obj.NextTimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } - switch obj.state.Get(ctx) { + switch obj.State.Get(ctx) { case Init: - if !obj.counterparty.connection.Is(ctx, nil) { + 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)) { + 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) { + if obj.Counterparty.State.Is(ctx, OpenTry) { return errors.New("counterparty connection state not tryopen") } } @@ -352,17 +336,17 @@ func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { } func (obj HandshakeObject) CloseInit(ctx sdk.Context, nextTimeout uint64) error { - if !obj.state.Transit(ctx, Open, CloseTry) { + if !obj.State.Transit(ctx, Open, CloseTry) { return errors.New("closeinit on non-open connection") } - obj.nextTimeout.Set(ctx, nextTimeout) + 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) { + if !obj.State.Transit(ctx, Open, Closed) { return errors.New("closetry on non-open connection") } @@ -371,21 +355,21 @@ func (obj HandshakeObject) CloseTry(ctx sdk.Context, timeoutHeight, nextTimeoutH return err } - if !obj.counterparty.state.Is(ctx, CloseTry) { + if !obj.Counterparty.State.Is(ctx, CloseTry) { return errors.New("unexpected counterparty state value") } - if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { + if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { return errors.New("unexpected counterparty timeout value") } - obj.nextTimeout.Set(ctx, nextTimeoutHeight) + obj.NextTimeout.Set(ctx, nextTimeoutHeight) return nil } func (obj HandshakeObject) CloseAck(ctx sdk.Context, timeoutHeight uint64) error { - if !obj.state.Transit(ctx, CloseTry, Closed) { + if !obj.State.Transit(ctx, CloseTry, Closed) { return errors.New("closeack on non-closetry connection") } @@ -394,38 +378,38 @@ func (obj HandshakeObject) CloseAck(ctx sdk.Context, timeoutHeight uint64) error return err } - if !obj.counterparty.state.Is(ctx, Closed) { + if !obj.Counterparty.State.Is(ctx, Closed) { return errors.New("unexpected counterparty state value") } - if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { + if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { return errors.New("unexpected counterparty timeout value") } - obj.nextTimeout.Set(ctx, 0) + 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)) { + 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) { + switch obj.State.Get(ctx) { case CloseTry: - if !obj.counterparty.state.Is(ctx, Open) { + if !obj.Counterparty.State.Is(ctx, Open) { return errors.New("counterparty connection state not open") } case Closed: - if !obj.counterparty.state.Is(ctx, CloseTry) { + 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) + obj.State.Set(ctx, Open) + obj.NextTimeout.Set(ctx, 0) return nil diff --git a/x/ibc/03-connection/keys.go b/x/ibc/03-connection/keys.go new file mode 100644 index 000000000000..3ce706ab0bc7 --- /dev/null +++ b/x/ibc/03-connection/keys.go @@ -0,0 +1,5 @@ +package connection + +func LocalRoot() []byte { + return []byte("connection/") +} diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 5a693d58c2e4..cc5da97a1386 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -22,9 +22,9 @@ type Manager struct { path merkle.Path } -func NewManager(protocol state.Base, client client.Manager) Manager { +func NewManager(protocol state.Mapping, client client.Manager) Manager { return Manager{ - protocol: state.NewMapping(protocol, ([]byte("/connection/"))), + protocol: protocol.Prefix(LocalRoot()), client: client, counterparty: NewCounterpartyManager(protocol.Cdc()), path: merkle.NewPath([][]byte{[]byte(protocol.StoreName())}, protocol.PrefixBytes()), @@ -38,12 +38,12 @@ type CounterpartyManager struct { } func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { - protocol := commitment.NewBase(cdc) + protocol := commitment.NewMapping(cdc, nil) return CounterpartyManager{ - protocol: commitment.NewMapping(protocol, []byte("/connection/")), + protocol: protocol.Prefix(LocalRoot()), - client: client.NewCounterpartyManager(protocol), + client: client.NewCounterpartyManager(cdc), } } @@ -51,25 +51,25 @@ type Object struct { id string protocol state.Mapping - connection state.Value - available state.Boolean + Connection state.Value + Available state.Boolean - kind state.String + Kind state.String - client client.Object + Client client.Object path merkle.Path } -func (man Manager) object(id string) Object { +func (man Manager) Object(id string) Object { return Object{ id: id, protocol: man.protocol.Prefix([]byte(id + "/")), - connection: man.protocol.Value([]byte(id)), - available: state.NewBoolean(man.protocol.Value([]byte(id + "/available"))), + Connection: man.protocol.Value([]byte(id)), + Available: man.protocol.Value([]byte(id + "/available")).Boolean(), - kind: state.NewString(man.protocol.Value([]byte(id + "/kind"))), + Kind: man.protocol.Value([]byte(id + "/kind")).String(), // CONTRACT: client must be filled by the caller @@ -81,22 +81,22 @@ type CounterObject struct { id string protocol commitment.Mapping - connection commitment.Value - available commitment.Boolean + Connection commitment.Value + Available commitment.Boolean - kind commitment.String + Kind commitment.String - client client.CounterObject // nolint: unused + Client client.CounterObject // nolint: unused } -func (man CounterpartyManager) object(id string) CounterObject { +func (man CounterpartyManager) Object(id string) CounterObject { return CounterObject{ id: id, protocol: man.protocol.Prefix([]byte(id + "/")), - connection: man.protocol.Value([]byte(id)), - available: commitment.NewBoolean(man.protocol.Value([]byte(id + "/available"))), + Connection: man.protocol.Value([]byte(id)), + Available: man.protocol.Value([]byte(id + "/available")).Boolean(), - kind: commitment.NewString(man.protocol.Value([]byte(id + "/kind"))), + Kind: man.protocol.Value([]byte(id + "/kind")).String(), // CONTRACT: client should be filled by the caller } @@ -104,12 +104,12 @@ 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.Connection(ctx).Path + optpath = obj.GetConnection(ctx).Path } store, err := commitment.NewStore( // TODO: proof root should be able to be obtained from the past - obj.client.ConsensusState(ctx).GetRoot(), + obj.Client.GetConsensusState(ctx).GetRoot(), optpath, proofs, ) @@ -124,35 +124,27 @@ func (obj Object) ID() string { return obj.id } -func (obj Object) Connection(ctx sdk.Context) (res Connection) { - obj.connection.Get(ctx, &res) +func (obj Object) GetConnection(ctx sdk.Context) (res Connection) { + obj.Connection.Get(ctx, &res) return } -func (obj Object) Available(ctx sdk.Context) bool { - return obj.available.Get(ctx) -} - -func (obj Object) Client() client.Object { - return obj.client -} - func (obj Object) Sendable(ctx sdk.Context) bool { - return kinds[obj.kind.Get(ctx)].Sendable + return kinds[obj.Kind.Get(ctx)].Sendable } func (obj Object) Receivble(ctx sdk.Context) bool { - return kinds[obj.kind.Get(ctx)].Receivable + return kinds[obj.Kind.Get(ctx)].Receivable } func (obj Object) remove(ctx sdk.Context) { - obj.connection.Delete(ctx) - obj.available.Delete(ctx) - obj.kind.Delete(ctx) + obj.Connection.Delete(ctx) + obj.Available.Delete(ctx) + obj.Kind.Delete(ctx) } func (obj Object) exists(ctx sdk.Context) bool { - return obj.connection.Exists(ctx) + return obj.Connection.Exists(ctx) } func (man Manager) Cdc() *codec.Codec { @@ -160,33 +152,33 @@ func (man Manager) Cdc() *codec.Codec { } func (man Manager) create(ctx sdk.Context, id string, connection Connection, kind string) (obj Object, err error) { - obj = man.object(id) + obj = man.Object(id) if obj.exists(ctx) { err = errors.New("Object already exists") return } - obj.client, err = man.client.Query(ctx, connection.Client) + obj.Client, err = man.client.Query(ctx, connection.Client) if err != nil { return } - obj.connection.Set(ctx, connection) - obj.kind.Set(ctx, kind) + obj.Connection.Set(ctx, connection) + obj.Kind.Set(ctx, kind) return } // 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) + obj = man.Object(id) if !obj.exists(ctx) { err = errors.New("Object not exists") return } - obj.client, err = man.client.Query(ctx, obj.Connection(ctx).Client) + obj.Client, err = man.client.Query(ctx, obj.GetConnection(ctx).Client) if err != nil { return } - if obj.kind.Get(ctx) != kind { + if obj.Kind.Get(ctx) != kind { err = errors.New("kind mismatch") return } @@ -194,15 +186,15 @@ func (man Manager) query(ctx sdk.Context, id string, kind string) (obj Object, e } func (man Manager) Query(ctx sdk.Context, id string) (obj Object, err error) { - obj = man.object(id) + obj = man.Object(id) if !obj.exists(ctx) { err = errors.New("Object not exists") return } - if !obj.Available(ctx) { + if !obj.Available.Get(ctx) { err = errors.New("Object not available") return } - obj.client, err = man.client.Query(ctx, obj.Connection(ctx).Client) + obj.Client, err = man.client.Query(ctx, obj.GetConnection(ctx).Client) return } diff --git a/x/ibc/03-connection/tests/connection_test.go b/x/ibc/03-connection/tests/connection_test.go index 2edc9c3ad3cf..665f15b3142d 100644 --- a/x/ibc/03-connection/tests/connection_test.go +++ b/x/ibc/03-connection/tests/connection_test.go @@ -38,10 +38,10 @@ func TestHandshake(t *testing.T) { // counterparty.OpenTry node.Counterparty.UpdateClient(t, header) cliobj := node.CLIObject() - _, pconn := node.Query(t, cliobj.ConnectionKey) - _, pstate := node.Query(t, cliobj.StateKey) - _, ptimeout := node.Query(t, cliobj.TimeoutKey) - _, pcounterclient := node.Query(t, cliobj.CounterpartyClientKey) + _, pconn := node.QueryValue(t, cliobj.Connection) + _, pstate := node.QueryValue(t, cliobj.State) + _, ptimeout := node.QueryValue(t, cliobj.NextTimeout) + _, 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) @@ -50,17 +50,17 @@ func TestHandshake(t *testing.T) { // self.OpenAck node.UpdateClient(t, header) cliobj = node.Counterparty.CLIObject() - _, pconn = node.Counterparty.Query(t, cliobj.ConnectionKey) - _, pstate = node.Counterparty.Query(t, cliobj.StateKey) - _, ptimeout = node.Counterparty.Query(t, cliobj.TimeoutKey) - _, pcounterclient = node.Counterparty.Query(t, cliobj.CounterpartyClientKey) + _, pconn = node.Counterparty.QueryValue(t, cliobj.Connection) + _, pstate = node.Counterparty.QueryValue(t, cliobj.State) + _, ptimeout = node.Counterparty.QueryValue(t, cliobj.NextTimeout) + _, pcounterclient = node.Counterparty.QueryValue(t, cliobj.CounterpartyClient) node.OpenAck(t, pconn, pstate, ptimeout, pcounterclient) header = node.Commit() // counterparty.OpenConfirm node.Counterparty.UpdateClient(t, header) cliobj = node.CLIObject() - _, pstate = node.Query(t, cliobj.StateKey) - _, ptimeout = node.Query(t, cliobj.TimeoutKey) + _, pstate = node.QueryValue(t, cliobj.State) + _, ptimeout = node.QueryValue(t, cliobj.NextTimeout) node.Counterparty.OpenConfirm(t, pstate, ptimeout) } diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index 0b4444b05338..29b7b0706721 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -13,7 +13,6 @@ import ( "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" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) type Node struct { @@ -31,7 +30,7 @@ type Node struct { func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { res := &Node{ Name: "self", // hard coded, doesnt matter - Node: tendermint.NewNode(self, merkle.NewPath([][]byte{[]byte("teststoreself")}, []byte("protocol"))), // TODO: test with key prefix + Node: tendermint.NewNode(self, "teststoreself", []byte("protocol/")), // TODO: test with key prefix State: connection.Idle, Cdc: cdc, @@ -39,7 +38,7 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { res.Counterparty = &Node{ Name: "counterparty", - Node: tendermint.NewNode(counter, merkle.NewPath([][]byte{[]byte("teststorecounterparty")}, []byte("protocol"))), + Node: tendermint.NewNode(counter, "teststorecounterparty", []byte("protocol/")), Counterparty: res, State: connection.Idle, @@ -48,17 +47,22 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { res.Connection = connection.Connection{ Counterparty: res.Counterparty.Name, - Path: res.Counterparty.Path, + Path: res.Counterparty.Path(), } res.Counterparty.Connection = connection.Connection{ Counterparty: res.Name, - Path: res.Path, + Path: res.Path(), } return res } +// TODO: typeify v +func (node *Node) QueryValue(t *testing.T, v interface{KeyBytes() []byte}) ([]byte, commitment.Proof) { + return node.Query(t, v.KeyBytes()) +} + func (node *Node) CreateClient(t *testing.T) { ctx := node.Context() climan, _ := node.Manager() @@ -88,18 +92,18 @@ func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Conte return ctx, connection.NewHandshaker(man) } -func (node *Node) CLIObject() connection.CLIHandshakeObject { +func (node *Node) CLIObject() connection.HandshakeObject { _, man := node.Manager() - return connection.NewHandshaker(man).CLIObject(node.Path, node.Name, node.Name) + return connection.NewHandshaker(man).CLIObject(node.Name, node.Name) } -func base(cdc *codec.Codec, key sdk.StoreKey) state.Base { - protocol := state.NewBase(cdc, key, []byte("protocol")) +func (node *Node) Mapping() state.Mapping { + protocol := state.NewMapping(node.Key, node.Cdc, node.Prefix) return protocol } func (node *Node) Manager() (client.Manager, connection.Manager) { - protocol := base(node.Cdc, node.Key) + protocol := node.Mapping() clientman := client.NewManager(protocol) return clientman, connection.NewManager(protocol, clientman) } @@ -108,10 +112,10 @@ 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 require.NoError(t, err) - require.Equal(t, connection.Init, obj.State(ctx)) - require.Equal(t, node.Connection, obj.Connection(ctx)) - require.Equal(t, node.CounterpartyClient, obj.CounterpartyClient(ctx)) - require.False(t, obj.Available(ctx)) + require.Equal(t, connection.Init, obj.State.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) } @@ -119,10 +123,10 @@ func (node *Node) OpenTry(t *testing.T, 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*/) require.NoError(t, err) - require.Equal(t, connection.OpenTry, obj.State(ctx)) - require.Equal(t, node.Connection, obj.Connection(ctx)) - require.Equal(t, node.CounterpartyClient, obj.CounterpartyClient(ctx)) - require.False(t, obj.Available(ctx)) + require.Equal(t, connection.OpenTry, obj.State.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) } @@ -130,9 +134,9 @@ func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) obj, err := man.OpenAck(ctx, proofs, node.Name, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) - require.Equal(t, connection.Open, obj.State(ctx)) - require.Equal(t, node.Connection, obj.Connection(ctx)) - require.True(t, obj.Available(ctx)) + require.Equal(t, connection.Open, obj.State.Get(ctx)) + require.Equal(t, node.Connection, obj.GetConnection(ctx)) + require.True(t, obj.Available.Get(ctx)) node.SetState(connection.Open) } @@ -140,8 +144,8 @@ func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) obj, err := man.OpenConfirm(ctx, proofs, node.Name, 100 /*TODO*/) require.NoError(t, err) - require.Equal(t, connection.Open, obj.State(ctx)) - require.Equal(t, node.Connection, obj.Connection(ctx)) - require.True(t, obj.Available(ctx)) + require.Equal(t, connection.Open, obj.State.Get(ctx)) + require.Equal(t, node.Connection, obj.GetConnection(ctx)) + require.True(t, obj.Available.Get(ctx)) node.SetState(connection.CloseTry) } diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index e97a2a9896e3..5dda3702a186 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" ) @@ -59,10 +59,6 @@ func (Path) CommitmentKind() string { return merkleKind } -func NewPathFromMapping(mapp state.Mapping) Path { - return NewPath([][]byte{[]byte(mapp.StoreName())}, mapp.PrefixBytes()) -} - var _ commitment.Proof = Proof{} // Proof is Merkle proof with the key information. diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index 2624d54eccde..222a6bf5abd9 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -42,9 +42,10 @@ func commit(cms types.CommitMultiStore) Root { // Sets/upates key-value pairs and prove with the query result proofs func TestStore(t *testing.T) { k, ctx, cms, cdc := defaultComponents() + storeName := k.Name() prefix := []byte{0x01, 0x03, 0x05, 0xAA, 0xBB} mapp := state.NewMapping(k, cdc, prefix) - path := NewPath([][]byte{[]byte(k.Name())}, prefix) + path := NewPath([][]byte{[]byte(storeName)}, prefix) m := make(map[string][]byte) kvpn := 10 @@ -67,7 +68,7 @@ func TestStore(t *testing.T) { // Test query, and accumulate proofs proofs := make([]commitment.Proof, 0, kvpn) for k, v := range m { - v0, p, err := QueryMultiStore(cms, path, []byte(k)) + v0, p, err := QueryMultiStore(cms, storeName, prefix, []byte(k)) require.NoError(t, err) require.Equal(t, cdc.MustMarshalBinaryBare(v), v0, "Queried value different at %d", repeat) proofs = append(proofs, p) @@ -77,7 +78,7 @@ func TestStore(t *testing.T) { for i := 0; i < 10; i++ { k := make([]byte, 64) rand.Read(k) - v, p, err := QueryMultiStore(cms, path, k) + v, p, err := QueryMultiStore(cms, storeName, prefix, k) require.NoError(t, err) require.Nil(t, v) proofs = append(proofs, p) @@ -109,7 +110,7 @@ func TestStore(t *testing.T) { // Test query, and accumulate proofs proofs = make([]commitment.Proof, 0, kvpn) for k, v := range m { - v0, p, err := QueryMultiStore(cms, path, []byte(k)) + v0, p, err := QueryMultiStore(cms, storeName, prefix, []byte(k)) require.NoError(t, err) require.Equal(t, cdc.MustMarshalBinaryBare(v), v0) proofs = append(proofs, p) diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index bd96cf84fdce..636fae569c28 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -1,7 +1,6 @@ package merkle import ( - "bytes" "errors" abci "github.com/tendermint/tendermint/abci/types" @@ -9,12 +8,12 @@ import ( "github.com/cosmos/cosmos-sdk/store/types" ) -func QueryMultiStore(cms types.CommitMultiStore, path Path, key []byte) ([]byte, Proof, error) { +func QueryMultiStore(cms types.CommitMultiStore, storeName string, prefix []byte, key []byte) ([]byte, Proof, error) { queryable, ok := cms.(types.Queryable) if !ok { panic("CommitMultiStore not queryable") } - qres := queryable.Query(RequestQueryMultiStore(path, key)) + qres := queryable.Query(RequestQueryMultiStore(storeName, prefix, key)) if !qres.IsOK() { return nil, Proof{}, errors.New(qres.Log) } @@ -22,13 +21,13 @@ func QueryMultiStore(cms types.CommitMultiStore, path Path, key []byte) ([]byte, return qres.Value, Proof{Key: key, Proof: qres.Proof}, nil } -func RequestQueryMultiStore(path Path, key []byte) abci.RequestQuery { +func RequestQueryMultiStore(storeName string, prefix []byte, key []byte) abci.RequestQuery { // Suffixing path with "/key". // iavl.Store.Query() switches over the last path element, // and performs key-value query only if it is "/key" return abci.RequestQuery{ - Path: "/" + string(bytes.Join(path.KeyPath, []byte("/"))) + "/key", - Data: path.Key(key), + Path: "/" + storeName + "/key", + Data: join(prefix, key), Prove: true, } } diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index cc5ac4a2fdc3..cf76caac4b39 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -42,13 +42,13 @@ type store struct { // NewStore constructs a new Store with the root, path, and proofs. // The proofs are not proven immediately because proofs require value bytes to verify. // If the kinds of the arguments don't match, returns error. -func NewStore(root Root, path Path, proofs []Proof) (res store, err error) { +func NewStore(root Root, path Path, proofs []Proof) (res *store, err error) { if root.CommitmentKind() != path.CommitmentKind() { err = errors.New("path type not matching with root's") return } - res = store{ + res = &store{ root: root, path: path, proofs: make(map[string]Proof), @@ -67,13 +67,13 @@ func NewStore(root Root, path Path, proofs []Proof) (res store, err error) { } // Get() returns the value only if it is already proven. -func (store store) Get(key []byte) ([]byte, bool) { +func (store *store) Get(key []byte) ([]byte, bool) { res, ok := store.verified[string(key)] return res, ok } // Prove() proves the key-value pair with the stored proof. -func (store store) Prove(key, value []byte) bool { +func (store *store) Prove(key, value []byte) bool { stored, ok := store.Get(key) if ok && bytes.Equal(stored, value) { return true @@ -93,7 +93,7 @@ func (store store) Prove(key, value []byte) bool { // Proven() returns true if the key-value pair is already proven -func (store store) Proven(key []byte) bool { +func (store *store) Proven(key []byte) bool { _, ok := store.Get(key) return ok } diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 5162b0453d39..165b3666d4d3 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -1,6 +1,7 @@ package commitment import ( + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" @@ -52,6 +53,7 @@ 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) } @@ -75,19 +77,19 @@ type String struct { Value } -func NewString(v Value) String { +func (v Value) String() String { return String{v} } func (v String) Is(ctx sdk.Context, value string) bool { - return v.Value.Is(ctx, value) + return v.Value.IsRaw(ctx, []byte(value)) } type Boolean struct { Value } -func NewBoolean(v Value) Boolean { +func (v Value) Boolean() Boolean { return Boolean{v} } From f81d7b4b55c801da83e6fe42bb160bbdc098539e Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 15 Aug 2019 02:53:01 +0900 Subject: [PATCH 169/378] fix client --- store/state/value.go | 4 --- x/ibc/02-client/cli.go | 14 ++++++--- x/ibc/02-client/client/cli/query.go | 8 ++--- x/ibc/03-connection/cli.go | 42 ++++++++++++++++++------- x/ibc/03-connection/client/cli/query.go | 19 +++++------ x/ibc/03-connection/client/cli/tx.go | 40 ++++++++++++----------- x/ibc/23-commitment/merkle/merkle.go | 4 +-- x/ibc/version.go | 6 ++++ 8 files changed, 81 insertions(+), 56 deletions(-) diff --git a/store/state/value.go b/store/state/value.go index c3b4b3089bbc..eb8cd12cf76a 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -103,10 +103,6 @@ func (v Value) PrefixBytes() []byte { return v.m.PrefixBytes() } -func (v Value) KeyBytesRaw() []byte { - return v.key -} - // KeyBytes() returns the prefixed key that the Value is providing to the KVStore func (v Value) KeyBytes() []byte { return v.m.KeyBytes(v.key) diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index aa563f3c170b..f199ac00d2b6 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -1,20 +1,26 @@ package client import ( + "bytes" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func (obj Object) ConsensusStateCLI(ctx context.CLIContext, path merkle.Path) (res ConsensusState, proof merkle.Proof, err error) { +func (obj Object) 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) - proof = merkle.NewProofFromValue(tmproof, path, obj.ConsensusState) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.ConsensusState) return } -func (obj Object) FrozenCLI(ctx context.CLIContext, path merkle.Path) (res bool, proof merkle.Proof, err error) { +func (obj Object) FrozenCLI(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { res, tmproof, err := obj.Frozen.Query(ctx) - proof = merkle.NewProofFromValue(tmproof, path, obj.Frozen) + 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 1cf445dae389..c4238dae8cdb 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -20,9 +20,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func mapping(cdc *codec.Codec, storeKey string, version int64) (state.Mapping, merkle.Path) { +func mapping(cdc *codec.Codec, storeKey string, version int64) state.Mapping { prefix := []byte(strconv.FormatInt(version, 10) + "/") - return state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix), merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) + return state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) } func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { @@ -48,11 +48,11 @@ 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, path := mapping(cdc, storeKey, ibc.Version) + mapp := mapping(cdc, storeKey, ibc.Version) man := client.NewManager(mapp) id := args[0] - state, _, err := man.Object(id).ConsensusStateCLI(ctx, path) + state, _, err := man.Object(id).ConsensusStateCLI(ctx) if err != nil { return err } diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index 8503be6b02e6..769792c16358 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -1,6 +1,8 @@ package connection import ( + "bytes" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" @@ -12,21 +14,27 @@ func (man Manager) CLIObject(connid, clientid string) Object { return obj } -func (obj Object) ConnectionCLI(ctx context.CLIContext, path merkle.Path) (res Connection, proof merkle.Proof, err error) { + + +func (obj Object) 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) - proof = merkle.NewProofFromValue(tmproof, path, obj.Connection) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Connection) return } -func (obj Object) AvailableCLI(ctx context.CLIContext, path merkle.Path) (res bool, proof merkle.Proof, err error) { +func (obj Object) AvailableCLI(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { res, tmproof, err := obj.Available.Query(ctx) - proof = merkle.NewProofFromValue(tmproof, path, obj.Available) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Available) return } -func (obj Object) KindCLI(ctx context.CLIContext, path merkle.Path) (res string, proof merkle.Proof, err error) { +func (obj Object) KindCLI(ctx context.CLIContext) (res string, proof merkle.Proof, err error) { res, tmproof, err := obj.Kind.Query(ctx) - proof = merkle.NewProofFromValue(tmproof, path, obj.Kind) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Kind) return } @@ -34,20 +42,30 @@ func (man Handshaker) CLIObject(connid, clientid string) HandshakeObject { return man.Object(man.man.CLIObject(connid, clientid)) } -func (obj HandshakeObject) StateCLI(ctx context.CLIContext, path merkle.Path) (res byte, proof merkle.Proof, err error){ +func (man Handshaker) CLIQuery(ctx context.CLIContext, connid string) (HandshakeObject, error) { + obj := man.man.Object(connid) + conn, _, err := obj.ConnectionCLI(ctx) + if err != nil { + return HandshakeObject{}, err + } + obj.Client = man.man.client.Object(conn.Client) + return man.Object(obj), 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, path, obj.State) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.State) return } -func (obj HandshakeObject) CounterpartyClientCLI(ctx context.CLIContext, path merkle.Path) (res string, proof merkle.Proof, err error) { +func (obj HandshakeObject) CounterpartyClientCLI(ctx context.CLIContext) (res string, proof merkle.Proof, err error) { res, tmproof, err := obj.CounterpartyClient.Query(ctx) - proof = merkle.NewProofFromValue(tmproof, path, obj.CounterpartyClient) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.CounterpartyClient) return } -func (obj HandshakeObject) NextTimeoutCLI(ctx context.CLIContext, path merkle.Path) (res uint64, proof merkle.Proof, err error){ +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, path, obj.NextTimeout) + 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 6be3c81bd9ce..efc330969faa 100644 --- a/x/ibc/03-connection/client/cli/query.go +++ b/x/ibc/03-connection/client/cli/query.go @@ -2,7 +2,6 @@ package cli import ( "fmt" - "strconv" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -17,20 +16,18 @@ import ( "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/03-connection/client/utils" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) const ( FlagProve = "prove" ) -func object(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, id string) connection.Object { - prefix := []byte(strconv.FormatInt(version, 10) + "/") - path := merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) + +func object(cdc *codec.Codec, storeKey string, prefix []byte, connid, clientid string) connection.Object { base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) climan := client.NewManager(base) man := connection.NewManager(base, climan) - return man.Query(ctx, path, id) + return man.CLIObject(connid, clientid) } func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { @@ -47,16 +44,16 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { return ibcQueryCmd } -func QueryConnection(ctx context.CLIContext, obj connection.CLIObject, prove bool) (res utils.JSONObject, err error) { - conn, connp, err := obj.Connection(ctx) +func QueryConnection(ctx context.CLIContext, obj connection.Object, prove bool) (res utils.JSONObject, err error) { + conn, connp, err := obj.ConnectionCLI(ctx) if err != nil { return } - avail, availp, err := obj.Available(ctx) + avail, availp, err := obj.AvailableCLI(ctx) if err != nil { return } - kind, kindp, err := obj.Kind(ctx) + kind, kindp, err := obj.KindCLI(ctx) if err != nil { return } @@ -83,7 +80,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(ctx, cdc, storeKey, ibc.Version, args[0]) + obj := object(cdc, storeKey, ibc.VersionPrefix(ibc.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 0aaa1c5cda27..68283021c36e 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -2,7 +2,6 @@ package cli import ( "io/ioutil" - "strconv" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -18,7 +17,6 @@ import ( "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" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) /* @@ -33,13 +31,11 @@ const ( FlagFrom2 = "from2" ) -func handshake(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, id string) connection.CLIHandshakeObject { - prefix := []byte(strconv.FormatInt(version, 10) + "/") - path := merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) - base := state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) +func handshake(ctx context.CLIContext, cdc *codec.Codec, storeKey string, prefix []byte, connid string) (connection.HandshakeObject, error) { + base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) climan := client.NewManager(base) man := connection.NewHandshaker(connection.NewManager(base, climan)) - return man.CLIQuery(ctx, path, id) + return man.CLIQuery(ctx, connid) } func lastheight(ctx context.CLIContext) (uint64, error) { @@ -84,7 +80,10 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } - obj1 := handshake(ctx1, cdc, storeKey, ibc.Version, conn1id) + obj1, err := handshake(ctx1, cdc, storeKey, ibc.VersionPrefix(ibc.Version), conn1id) + if err != nil { + return err + } conn2id := args[2] conn2bz, err := ioutil.ReadFile(args[3]) @@ -96,7 +95,10 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } - obj2 := handshake(ctx2, cdc, storeKey, ibc.Version, conn1id) + obj2, err := handshake(ctx2, cdc, storeKey, ibc.VersionPrefix(ibc.Version), conn1id) + if err != nil { + return err + } // TODO: check state and if not Idle continue existing process height, err := lastheight(ctx2) @@ -123,19 +125,19 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } nextTimeout = height + 1000 - _, pconn, err := obj1.Connection(ctx1) + _, pconn, err := obj1.ConnectionCLI(ctx1) if err != nil { return err } - _, pstate, err := obj1.State(ctx1) + _, pstate, err := obj1.StateCLI(ctx1) if err != nil { return err } - _, ptimeout, err := obj1.NextTimeout(ctx1) + _, ptimeout, err := obj1.NextTimeoutCLI(ctx1) if err != nil { return err } - _, pcounter, err := obj1.CounterpartyClient(ctx1) + _, pcounter, err := obj1.CounterpartyClientCLI(ctx1) if err != nil { return err } @@ -161,19 +163,19 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } nextTimeout = height + 1000 - _, pconn, err = obj2.Connection(ctx2) + _, pconn, err = obj2.ConnectionCLI(ctx2) if err != nil { return err } - _, pstate, err = obj2.State(ctx2) + _, pstate, err = obj2.StateCLI(ctx2) if err != nil { return err } - _, ptimeout, err = obj2.NextTimeout(ctx2) + _, ptimeout, err = obj2.NextTimeoutCLI(ctx2) if err != nil { return err } - _, pcounter, err = obj2.CounterpartyClient(ctx2) + _, pcounter, err = obj2.CounterpartyClientCLI(ctx2) if err != nil { return err } @@ -192,11 +194,11 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command } timeout = nextTimeout - _, pstate, err = obj1.State(ctx1) + _, pstate, err = obj1.StateCLI(ctx1) if err != nil { return err } - _, ptimeout, err = obj1.NextTimeout(ctx1) + _, ptimeout, err = obj1.NextTimeoutCLI(ctx1) if err != nil { return err } diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index 5dda3702a186..1606497ec4f8 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -108,7 +108,7 @@ type Value interface { KeyBytes() []byte } -func NewProofFromValue(proof *merkle.Proof, path Path, value Value) Proof { +func NewProofFromValue(proof *merkle.Proof, prefix []byte, value Value) Proof { // TODO: check HasPrefix - return Proof{proof, bytes.TrimPrefix(value.KeyBytes(), path.KeyPrefix)} + return Proof{proof, bytes.TrimPrefix(value.KeyBytes(), prefix)} } diff --git a/x/ibc/version.go b/x/ibc/version.go index 11bd8ee5b3d3..b6648efb40c8 100644 --- a/x/ibc/version.go +++ b/x/ibc/version.go @@ -1,3 +1,9 @@ package ibc +import "strconv" + const Version int64 = 1 + +func VersionPrefix(version int64) []byte { + return []byte(strconv.FormatInt(version, 10) + "/") +} From 30aff5504d2ea9f153600b307d20a713e6a0ac00 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 25 Jun 2019 17:10:21 +0200 Subject: [PATCH 170/378] add CLIObject in progress --- client/context/query.go | 15 +++++++++------ x/ibc/02-client/cli.go | 1 - 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 98cd30690f0c..e8790cf3d5bf 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -31,22 +31,25 @@ func (ctx CLIContext) GetNode() (rpcclient.Client, error) { // Query performs a query to a Tendermint node with the provided path. // It returns the result and height of the query upon success or an error if // the query fails. -func (ctx CLIContext) Query(path string) ([]byte, int64, error) { - return ctx.query(path, nil) +func (ctx CLIContext) Query(path string) (val []byte, height int64, err error) { + val, height, err = ctx.query(path, nil) + return } // QueryWithData performs a query to a Tendermint node with the provided path // and a data payload. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryWithData(path string, data []byte) ([]byte, int64, error) { - return ctx.query(path, data) +func (ctx CLIContext) QueryWithData(path string, data []byte) (val []byte, height int64, err error) { + val, height, err = ctx.query(path, data) + return } // QueryStore performs a query to a Tendermint node with the provided key and // store name. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, int64, error) { - return ctx.queryStore(key, storeName, "key") +func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (val []byte, height int64, err error) { + val, height, err = ctx.queryStore(key, storeName, "key") + return } // QueryABCI performs a query to a Tendermint node with the provide RequestQuery. diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index f199ac00d2b6..db03c1441329 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -23,4 +23,3 @@ func (obj Object) FrozenCLI(ctx context.CLIContext) (res bool, proof merkle.Proo proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Frozen) return } - From 9e46e5fa5a86117d1a9c784875122026661d79b1 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 26 Jun 2019 15:19:42 +0200 Subject: [PATCH 171/378] cli in progress --- client/context/query.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index e8790cf3d5bf..98cd30690f0c 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -31,25 +31,22 @@ func (ctx CLIContext) GetNode() (rpcclient.Client, error) { // Query performs a query to a Tendermint node with the provided path. // It returns the result and height of the query upon success or an error if // the query fails. -func (ctx CLIContext) Query(path string) (val []byte, height int64, err error) { - val, height, err = ctx.query(path, nil) - return +func (ctx CLIContext) Query(path string) ([]byte, int64, error) { + return ctx.query(path, nil) } // QueryWithData performs a query to a Tendermint node with the provided path // and a data payload. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryWithData(path string, data []byte) (val []byte, height int64, err error) { - val, height, err = ctx.query(path, data) - return +func (ctx CLIContext) QueryWithData(path string, data []byte) ([]byte, int64, error) { + return ctx.query(path, data) } // QueryStore performs a query to a Tendermint node with the provided key and // store name. It returns the result and height of the query upon success // or an error if the query fails. -func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (val []byte, height int64, err error) { - val, height, err = ctx.queryStore(key, storeName, "key") - return +func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) ([]byte, int64, error) { + return ctx.queryStore(key, storeName, "key") } // QueryABCI performs a query to a Tendermint node with the provide RequestQuery. From ee8d154f94a9c9f432c66884123855ccf1f5bccb Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 28 Jun 2019 17:43:53 +0200 Subject: [PATCH 172/378] add test in progress/ --- x/ibc/03-connection/manager.go | 2 ++ x/ibc/03-connection/tests/connection_test.go | 1 + x/ibc/23-commitment/store.go | 7 +++++++ 3 files changed, 10 insertions(+) diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index cc5da97a1386..ad3dd830503d 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -164,6 +164,7 @@ func (man Manager) create(ctx sdk.Context, id string, connection Connection, kin obj.Connection.Set(ctx, connection) obj.Kind.Set(ctx, kind) return + } // query() is used internally by the connection creators @@ -190,6 +191,7 @@ func (man Manager) Query(ctx sdk.Context, id string) (obj Object, err error) { if !obj.exists(ctx) { err = errors.New("Object not exists") return + } if !obj.Available.Get(ctx) { err = errors.New("Object not available") diff --git a/x/ibc/03-connection/tests/connection_test.go b/x/ibc/03-connection/tests/connection_test.go index 665f15b3142d..241e0acbc9ad 100644 --- a/x/ibc/03-connection/tests/connection_test.go +++ b/x/ibc/03-connection/tests/connection_test.go @@ -63,4 +63,5 @@ func TestHandshake(t *testing.T) { _, pstate = node.QueryValue(t, cliobj.State) _, ptimeout = node.QueryValue(t, cliobj.NextTimeout) node.Counterparty.OpenConfirm(t, pstate, ptimeout) + } diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index cf76caac4b39..aa67723709b9 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -3,6 +3,7 @@ package commitment import ( "bytes" "errors" + "fmt" ) // Store proves key-value pairs' inclusion or non-inclusion with @@ -60,9 +61,12 @@ func NewStore(root Root, path Path, proofs []Proof) (res *store, err error) { err = errors.New("proof type not matching with root's") return } + fmt.Println("set key", string(proof.GetKey())) res.proofs[string(proof.GetKey())] = proof } + fmt.Printf("%+v\n", res) + return } @@ -80,10 +84,13 @@ func (store *store) Prove(key, value []byte) bool { } proof, ok := store.proofs[string(key)] if !ok { + fmt.Println("no proof") + fmt.Println("get key", string(key)) return false } err := proof.Verify(store.root, store.path, value) if err != nil { + fmt.Println("invalid proof") return false } store.verified[string(key)] = value From 10835cfaa0b03c2c360305d84b7c408e56000f12 Mon Sep 17 00:00:00 2001 From: mossid Date: Sat, 29 Jun 2019 14:40:30 +0200 Subject: [PATCH 173/378] handshake test now working --- x/ibc/03-connection/tests/connection_test.go | 1 - x/ibc/23-commitment/store.go | 7 ------- 2 files changed, 8 deletions(-) diff --git a/x/ibc/03-connection/tests/connection_test.go b/x/ibc/03-connection/tests/connection_test.go index 241e0acbc9ad..665f15b3142d 100644 --- a/x/ibc/03-connection/tests/connection_test.go +++ b/x/ibc/03-connection/tests/connection_test.go @@ -63,5 +63,4 @@ func TestHandshake(t *testing.T) { _, pstate = node.QueryValue(t, cliobj.State) _, ptimeout = node.QueryValue(t, cliobj.NextTimeout) node.Counterparty.OpenConfirm(t, pstate, ptimeout) - } diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index aa67723709b9..cf76caac4b39 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 @@ -61,12 +60,9 @@ func NewStore(root Root, path Path, proofs []Proof) (res *store, err error) { err = errors.New("proof type not matching with root's") return } - fmt.Println("set key", string(proof.GetKey())) res.proofs[string(proof.GetKey())] = proof } - fmt.Printf("%+v\n", res) - return } @@ -84,13 +80,10 @@ func (store *store) Prove(key, value []byte) bool { } proof, ok := store.proofs[string(key)] if !ok { - fmt.Println("no proof") - fmt.Println("get key", string(key)) return false } err := proof.Verify(store.root, store.path, value) if err != nil { - fmt.Println("invalid proof") return false } store.verified[string(key)] = value From d7a5c3075d528f3688502fd8bcc370f82ab197a5 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 00:43:01 +0200 Subject: [PATCH 174/378] in progress --- x/ibc/04-channel/manager.go | 75 +++++++++++++++++++++++++++++++++++++ x/ibc/04-channel/types.go | 29 ++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 x/ibc/04-channel/manager.go create mode 100644 x/ibc/04-channel/types.go diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go new file mode 100644 index 000000000000..62e3ea9c5310 --- /dev/null +++ b/x/ibc/04-channel/manager.go @@ -0,0 +1,75 @@ +package channel + +import ( + "github.com/cosmos/cosmos-sdk/store/mapping" + + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +type Manager struct { + protocol mapping.Mapping + + connection connection.Manager + + remote *Manager +} + +func NewManager(protocol mapping.Base, connection connection.Manager) Manager { + return Manager{ + protocol: mapping.NewMapping(protocol, []byte("/")), + connection: connection, + } +} + +// CONTRACT: remote must be filled by the caller +func (man Manager) object(connid, chanid string) Object { + key := connid + "/channels/" + chanid + return Object{ + connid: connid, + chanid: chanid, + channel: man.protocol.Value([]byte(key)), + state: mapping.NewEnum(man.protocol.Value([]byte(key + "/state"))), + nexttimeout: mapping.NewInteger(man.protocol.Value([]byte(key+"/timeout")), mapping.Dec), + + // TODO: remove length functionality from mapping.Indeer(will be handled manually) + seqsend: mapping.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), mapping.Dec), + seqrecv: mapping.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceRecv")), mapping.Dec), + packets: mapping.NewIndexer(man.protocol.Prefix([]byte(key+"/packets/")), mapping.Dec), + } +} + +func (man Manager) Create(ctx sdk.Context, connid, chanid string, channel Channel) (obj Object, err error) { + obj := man.object(connid, chanid) + if obj.exists(ctx) { + err = errors.New("channel already exists for the provided id") + return + } + obj.connection, err = man.connection.Query(ctx, connid) + if err != nil { + return + } + obj.channel.Set(ctx, channel) + remote := man.remote.object() +} + +type Object struct { + connid string + chanid string + channel mapping.Value + state mapping.Enum + nexttimeout mapping.Integer + + seqsend mapping.Integer + seqrecv mapping.Integer + packets mapping.Indexer + + connection connection.Object + + // CONTRACT: remote should not be used when remote + remote *Object +} + +func (obj Object) OpenInit(ctx sdk.Context) error { + // OpenInit will +} diff --git a/x/ibc/04-channel/types.go b/x/ibc/04-channel/types.go new file mode 100644 index 000000000000..339b7c067c52 --- /dev/null +++ b/x/ibc/04-channel/types.go @@ -0,0 +1,29 @@ +package channel + +type State = byte + +const ( + Init State = iota + OpenTry + Open + CloseTry + Closed +) + +type Packet struct { + Sequence uint64 + TimeoutHeight uint64 + + SourceConnection string + SourceChannel string + DestConnection string + DestChannel string + + Data []byte +} + +type Channel struct { + Module string + Counterparty string + CounterpartyModule string +} From f951098175c01bf7805379dd4aa05cef81456d72 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 01:48:36 +0200 Subject: [PATCH 175/378] in progress --- x/ibc/04-channel/manager.go | 118 ++++++++++++++++++++++++++++++++++-- x/ibc/04-channel/types.go | 3 +- 2 files changed, 115 insertions(+), 6 deletions(-) diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index 62e3ea9c5310..649dbc5cb75b 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -1,7 +1,11 @@ package channel import ( + "errors" + + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/mapping" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" @@ -16,8 +20,21 @@ type Manager struct { } func NewManager(protocol mapping.Base, connection connection.Manager) Manager { + man := newManager(protocol, connection) + man.remote = newRemoteManager(protocol.Cdc()) + return man +} + +func newRemoteManager(cdc *codec.Codec) *Manager { + protocol := mapping.NewBaseWithGetter(cdc, commitment.GetStore) + connection := connection.NewRemoteManager(cdc) + res := newManager(protocol, *connection) + return &res +} + +func newManager(protocol mapping.Base, connection connection.Manager) Manager { return Manager{ - protocol: mapping.NewMapping(protocol, []byte("/")), + protocol: mapping.NewMapping(protocol, []byte("/connection/")), connection: connection, } } @@ -40,7 +57,7 @@ func (man Manager) object(connid, chanid string) Object { } func (man Manager) Create(ctx sdk.Context, connid, chanid string, channel Channel) (obj Object, err error) { - obj := man.object(connid, chanid) + obj = man.object(connid, chanid) if obj.exists(ctx) { err = errors.New("channel already exists for the provided id") return @@ -49,8 +66,35 @@ func (man Manager) Create(ctx sdk.Context, connid, chanid string, channel Channe if err != nil { return } + if obj.connection.State(ctx) != connection.Open { + err = errors.New("connection exists but not opened") + return + } obj.channel.Set(ctx, channel) - remote := man.remote.object() + remote := man.remote.object(obj.connection.Value(ctx).Counterparty, channel.Counterparty) + obj.remote = &remote + return +} + +func (man Manager) Query(ctx sdk.Context, connid, chanid string) (obj Object, err error) { + obj = man.object(connid, chanid) + if !obj.exists(ctx) { + err = errors.New("channel not exists for the provided id") + return + } + obj.connection, err = man.connection.Query(ctx, connid) + if err != nil { + return + } + if obj.connection.State(ctx) != connection.Open { + err = errors.New("connection exists but not opened") + return + } + + channel := obj.Value(ctx) + remote := man.remote.object(obj.connection.Value(ctx).Counterparty, channel.Counterparty) + obj.remote = &remote + return } type Object struct { @@ -70,6 +114,70 @@ type Object struct { remote *Object } -func (obj Object) OpenInit(ctx sdk.Context) error { - // OpenInit will +func (obj Object) ConnID() string { + return obj.connid +} + +func (obj Object) ChanID() string { + return obj.chanid +} + +func (obj Object) Value(ctx sdk.Context) (res Channel) { + obj.channel.Get(ctx, &res) + return +} + +func (obj Object) exists(ctx sdk.Context) bool { + return obj.channel.Exists(ctx) +} + +func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { + if uint64(ctx.BlockHeight()) > timeoutHeight { + return errors.New("timeout") + } + return nil +} + +// TODO: ocapify callingModule +func (obj Object) OpenInit(ctx sdk.Context, callingModule string) error { + // CONTRACT: OpenInit() should be called after man.Create(), not man.Query(), + // which will ensure + // assert(get() === null) and + // set() and + // connection.state == open + + if !obj.state.Transit(ctx, Idle, Init) { + return errors.New("init on non-idle channel") + } + + channel := obj.Value(ctx) + if callingModule != channel.Module { + return errors.New("setting wrong module") + } + + obj.seqsend.Set(ctx, 0) + obj.seqrecv.Set(ctx, 0) + + return nil +} + +func (obj Object) OpenTry(ctx sdk.Context, callingModule string, timeoutHeight, nextTimeoutHeight uint64) error { + if !obj.state.Transit(ctx, Idle, OpenTry) { + return errors.New("opentry on non-idle channel") + } + + err := assertTimeout(ctx, timeoutHeight) + if err != nil { + return err + } + + // XXX +} + +func (obj Object) Send(ctx sdk.Context, packet Packet) { + +} + +func (obj Object) Receive(ctx sdk.Context, packet Packet) { + } diff --git a/x/ibc/04-channel/types.go b/x/ibc/04-channel/types.go index 339b7c067c52..a679780a6cba 100644 --- a/x/ibc/04-channel/types.go +++ b/x/ibc/04-channel/types.go @@ -3,7 +3,8 @@ package channel type State = byte const ( - Init State = iota + Idle State = iota + Init OpenTry Open CloseTry From 7a0b2550ffd6922f55d5482aa4e0428de83c3335 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 17:11:46 +0200 Subject: [PATCH 176/378] add send/receive --- x/ibc/04-channel/manager.go | 93 +++++++++++++++++++++++++++++++++---- x/ibc/04-channel/types.go | 7 +++ 2 files changed, 91 insertions(+), 9 deletions(-) diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index 649dbc5cb75b..65831512a465 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) +// Manager is unrestricted type Manager struct { protocol mapping.Mapping @@ -97,6 +98,51 @@ func (man Manager) Query(ctx sdk.Context, connid, chanid string) (obj Object, er return } +func (man Manager) Module(module string, chanid func(string) bool) ModuleManager { + return ModuleManager{ + man: man, + module: module, + chanid: chanid, + } +} + +// ModuleManage is module specific +type ModuleManager struct { + man Manager + module string + chanid func(string) bool +} + +func (man ModuleManager) Create(ctx sdk.Context, connid, chanid string, channel Channel) (Object, error) { + if !man.chanid(chanid) { + return Object{}, errors.New("invalid channel id") + } + + if channel.Module != man.module { + return Object{}, errors.New("invalid module") + } + + return man.man.Create(ctx, connid, chanid, channel) +} + +func (man ModuleManager) Query(ctx sdk.Context, connid, chanid string) (Object, error) { + if !man.chanid(chanid) { + return Object{}, errors.New("invalid channel id") + } + + obj, err := man.man.Query(ctx, connid, chanid) + if err != nil { + return Object{}, err + } + + if obj.Value(ctx).Module != man.module { + return Object{}, errors.New("invalid module") + } + + return obj, nil +} + +// XXX: remove connid(already exists in connection.id) type Object struct { connid string chanid string @@ -139,29 +185,26 @@ func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { } // TODO: ocapify callingModule -func (obj Object) OpenInit(ctx sdk.Context, callingModule string) error { +func (obj Object) OpenInit(ctx sdk.Context) error { // CONTRACT: OpenInit() should be called after man.Create(), not man.Query(), // which will ensure // assert(get() === null) and // set() and // connection.state == open + // getCallingModule() === channel.moduleIdentifier is ensured by ModuleManager + if !obj.state.Transit(ctx, Idle, Init) { return errors.New("init on non-idle channel") } - channel := obj.Value(ctx) - if callingModule != channel.Module { - return errors.New("setting wrong module") - } - obj.seqsend.Set(ctx, 0) obj.seqrecv.Set(ctx, 0) return nil } -func (obj Object) OpenTry(ctx sdk.Context, callingModule string, timeoutHeight, nextTimeoutHeight uint64) error { +func (obj Object) OpenTry(ctx sdk.Context, timeoutHeight, nextTimeoutHeight uint64) error { if !obj.state.Transit(ctx, Idle, OpenTry) { return errors.New("opentry on non-idle channel") } @@ -174,10 +217,42 @@ func (obj Object) OpenTry(ctx sdk.Context, callingModule string, timeoutHeight, // XXX } -func (obj Object) Send(ctx sdk.Context, packet Packet) { +func (obj Object) Send(ctx sdk.Context, packet Packet) error { + if obj.state.Get(ctx) != Open { + return errors.New("send on non-open channel") + } + + if obj.connection.State(ctx) != Open { + return errors.New("send on non-open connection") + } + + if uint64(obj.connection.Client(ctx).GetBase().GetHeight()) >= packet.Timeout() { + return errors.New("timeout height higher than the latest known") + } + obj.packets.Set(ctx, obj.seqsend.Incr(ctx), packet) + + return nil } -func (obj Object) Receive(ctx sdk.Context, packet Packet) { +func (obj Object) Receive(ctx sdk.Context, packet Packet) error { + if obj.state.Get(ctx) != Open { + return errors.New("send on non-open channel") + } + + if obj.connection.State(ctx) != Open { + return errors.New("send on non-open connection") + } + + err := assertTimeout(ctx, packet.Timeout()) + if err != nil { + return err + } + // XXX: increment should happen before verification, reflect on the spec + if !obj.remote.packets.Value(obj.seqrecv.Incr(ctx)).Is(ctx, packet.Commit()) { + return errors.New("verification failed") + } + + return nil } diff --git a/x/ibc/04-channel/types.go b/x/ibc/04-channel/types.go index a679780a6cba..ede4dc69c8d6 100644 --- a/x/ibc/04-channel/types.go +++ b/x/ibc/04-channel/types.go @@ -11,6 +11,7 @@ const ( Closed ) +/* type Packet struct { Sequence uint64 TimeoutHeight uint64 @@ -22,6 +23,12 @@ type Packet struct { Data []byte } +*/ + +type Packet interface { + Timeout() uint64 + Commit() []byte // Can be a commit message +} type Channel struct { Module string From e8f16aa99e2bbb1e80970c9148c4b386b771d6f2 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 19:08:55 +0200 Subject: [PATCH 177/378] in progress --- x/ibc/04-channel/manager.go | 85 +++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index 65831512a465..854d9095e791 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -17,34 +17,36 @@ type Manager struct { connection connection.Manager - remote *Manager + counterparty CounterpartyManager } -func NewManager(protocol mapping.Base, connection connection.Manager) Manager { - man := newManager(protocol, connection) - man.remote = newRemoteManager(protocol.Cdc()) - return man -} +type CounterpartyManager struct { + protocol commitment.Mapping -func newRemoteManager(cdc *codec.Codec) *Manager { - protocol := mapping.NewBaseWithGetter(cdc, commitment.GetStore) - connection := connection.NewRemoteManager(cdc) - res := newManager(protocol, *connection) - return &res + connection connection.CounterpartyManager } -func newManager(protocol mapping.Base, connection connection.Manager) Manager { +func NewManager(protocol mapping.Base, connection connection.Manager) Manager { return Manager{ - protocol: mapping.NewMapping(protocol, []byte("/connection/")), - connection: connection, + protocol: mapping.NewMapping(protocol, []byte("/connection/")), + connection: connection, + counterparty: NewCounterpartyManager(protocol.Cdc()), + } +} + +func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { + protocol := commitment.NewBase(cdc) + + return CounterpartyManager{ + protocol: commitment.NewMapping(protocol, []byte("/connection/")), + connection: connection.NewCounterpartyManager(cdc), } } -// CONTRACT: remote must be filled by the caller +// CONTRACT: connection and counterparty must be filled by the caller func (man Manager) object(connid, chanid string) Object { key := connid + "/channels/" + chanid return Object{ - connid: connid, chanid: chanid, channel: man.protocol.Value([]byte(key)), state: mapping.NewEnum(man.protocol.Value([]byte(key + "/state"))), @@ -57,6 +59,20 @@ func (man Manager) object(connid, chanid string) Object { } } +func (man CounterpartyManager) object(connid, chanid string) CounterObject { + key := connid + "/channels/" + chanid + return CounterObject{ + chanid: chanid, + channel: man.protocol.Value([]byte(key)), + state: commitment.NewEnum(man.protocol.Value([]byte(key + "/state"))), + nexttimeout: commitment.NewInteger(man.protocol.Value([]byte(key+"/timeout")), mapping.Dec), + + seqsend: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), mapping.Dec), + seqrecv: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceRecv")), mapping.Dec), + // packets: commitment.NewIndexer(man.protocol.Prefix([]byte(key + "/packets")), mapping.Dec), + } +} + func (man Manager) Create(ctx sdk.Context, connid, chanid string, channel Channel) (obj Object, err error) { obj = man.object(connid, chanid) if obj.exists(ctx) { @@ -67,13 +83,12 @@ func (man Manager) Create(ctx sdk.Context, connid, chanid string, channel Channe if err != nil { return } - if obj.connection.State(ctx) != connection.Open { - err = errors.New("connection exists but not opened") - return - } + counterconnid := obj.connection.Value(ctx).Counterparty + obj.counterparty = man.counterparty.object(counterconnid, channel.Counterparty) + obj.counterparty.connection = man.counterparty.connection.Query(counterconnid) + obj.channel.Set(ctx, channel) - remote := man.remote.object(obj.connection.Value(ctx).Counterparty, channel.Counterparty) - obj.remote = &remote + return } @@ -93,8 +108,10 @@ func (man Manager) Query(ctx sdk.Context, connid, chanid string) (obj Object, er } channel := obj.Value(ctx) - remote := man.remote.object(obj.connection.Value(ctx).Counterparty, channel.Counterparty) - obj.remote = &remote + counterconnid := obj.connection.Value(ctx).Counterparty + obj.counterparty = man.counterparty.object(counterconnid, channel.Counterparty) + obj.counterparty.connection = man.counterparty.connection.Query(counterconnid) + return } @@ -142,9 +159,7 @@ func (man ModuleManager) Query(ctx sdk.Context, connid, chanid string) (Object, return obj, nil } -// XXX: remove connid(already exists in connection.id) type Object struct { - connid string chanid string channel mapping.Value state mapping.Enum @@ -156,12 +171,20 @@ type Object struct { connection connection.Object - // CONTRACT: remote should not be used when remote - remote *Object + counterparty CounterObject } -func (obj Object) ConnID() string { - return obj.connid +type CounterObject struct { + chanid string + channel commitment.Value + state commitment.Enum + nexttimeout commitment.Integer + + seqsend commitment.Integer + seqrecv commitment.Integer + //packets commitment.Indexer + + connection connection.CounterObject } func (obj Object) ChanID() string { @@ -250,7 +273,7 @@ func (obj Object) Receive(ctx sdk.Context, packet Packet) error { } // XXX: increment should happen before verification, reflect on the spec - if !obj.remote.packets.Value(obj.seqrecv.Incr(ctx)).Is(ctx, packet.Commit()) { + if !obj.counterparty.packets.Value(obj.seqrecv.Incr(ctx)).Is(ctx, packet.Commit()) { return errors.New("verification failed") } From 833aeab40a60140bac6f593c8f4c19b8c2541fba Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Jun 2019 19:16:45 +0200 Subject: [PATCH 178/378] fix packets --- x/ibc/04-channel/manager.go | 4 ++-- x/ibc/23-commitment/value.go | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index 854d9095e791..d56451ba1195 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -69,7 +69,7 @@ func (man CounterpartyManager) object(connid, chanid string) CounterObject { seqsend: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), mapping.Dec), seqrecv: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceRecv")), mapping.Dec), - // packets: commitment.NewIndexer(man.protocol.Prefix([]byte(key + "/packets")), mapping.Dec), + packets: commitment.NewIndexer(man.protocol.Prefix([]byte(key+"/packets")), mapping.Dec), } } @@ -182,7 +182,7 @@ type CounterObject struct { seqsend commitment.Integer seqrecv commitment.Integer - //packets commitment.Indexer + packets commitment.Indexer connection connection.CounterObject } diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 165b3666d4d3..18e1a19c2a9e 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -35,8 +35,22 @@ func (m Mapping) Prefix(prefix []byte) Mapping { } } -// Value is for proving commitment proof on a speicifc key-value point in the other state -// using the already initialized commitment store. +type Indexer struct { + Mapping + enc state.IntEncoding +} + +func NewIndexer(m Mapping, enc state.IntEncoding) Indexer { + return Indexer{ + Mapping: m, + enc: enc, + } +} + +func (ix Indexer) Value(index uint64) Value { + return ix.Mapping.Value(state.EncodeInt(index, ix.enc)) +} + type Value struct { m Mapping key []byte From 8893b4b989f4de335717d9e6415fcbafe874643d Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 13 Jun 2019 16:59:05 +0200 Subject: [PATCH 179/378] in progress --- x/ibc/04-channel/manager.go | 45 +++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index d56451ba1195..0eccb94b5dd8 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -4,7 +4,7 @@ import ( "errors" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/mapping" + "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" @@ -13,7 +13,7 @@ import ( // Manager is unrestricted type Manager struct { - protocol mapping.Mapping + protocol state.Mapping connection connection.Manager @@ -26,9 +26,9 @@ type CounterpartyManager struct { connection connection.CounterpartyManager } -func NewManager(protocol mapping.Base, connection connection.Manager) Manager { +func NewManager(protocol state.Base, connection connection.Manager) Manager { return Manager{ - protocol: mapping.NewMapping(protocol, []byte("/connection/")), + protocol: state.NewMapping(protocol, []byte("/connection/")), connection: connection, counterparty: NewCounterpartyManager(protocol.Cdc()), } @@ -49,13 +49,13 @@ func (man Manager) object(connid, chanid string) Object { return Object{ chanid: chanid, channel: man.protocol.Value([]byte(key)), - state: mapping.NewEnum(man.protocol.Value([]byte(key + "/state"))), - nexttimeout: mapping.NewInteger(man.protocol.Value([]byte(key+"/timeout")), mapping.Dec), + state: state.NewEnum(man.protocol.Value([]byte(key + "/state"))), + nexttimeout: state.NewInteger(man.protocol.Value([]byte(key+"/timeout")), state.Dec), - // TODO: remove length functionality from mapping.Indeer(will be handled manually) - seqsend: mapping.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), mapping.Dec), - seqrecv: mapping.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceRecv")), mapping.Dec), - packets: mapping.NewIndexer(man.protocol.Prefix([]byte(key+"/packets/")), mapping.Dec), + // TODO: remove length functionality from state.Indeer(will be handled manually) + seqsend: state.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), state.Dec), + seqrecv: state.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceRecv")), state.Dec), + packets: state.NewIndexer(man.protocol.Prefix([]byte(key+"/packets/")), state.Dec), } } @@ -65,11 +65,11 @@ func (man CounterpartyManager) object(connid, chanid string) CounterObject { chanid: chanid, channel: man.protocol.Value([]byte(key)), state: commitment.NewEnum(man.protocol.Value([]byte(key + "/state"))), - nexttimeout: commitment.NewInteger(man.protocol.Value([]byte(key+"/timeout")), mapping.Dec), + nexttimeout: commitment.NewInteger(man.protocol.Value([]byte(key+"/timeout")), state.Dec), - seqsend: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), mapping.Dec), - seqrecv: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceRecv")), mapping.Dec), - packets: commitment.NewIndexer(man.protocol.Prefix([]byte(key+"/packets")), mapping.Dec), + seqsend: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), state.Dec), + seqrecv: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceRecv")), state.Dec), + packets: commitment.NewIndexer(man.protocol.Prefix([]byte(key+"/packets")), state.Dec), } } @@ -161,13 +161,13 @@ func (man ModuleManager) Query(ctx sdk.Context, connid, chanid string) (Object, type Object struct { chanid string - channel mapping.Value - state mapping.Enum - nexttimeout mapping.Integer + channel state.Value + state state.Enum + nexttimeout state.Integer - seqsend mapping.Integer - seqrecv mapping.Integer - packets mapping.Indexer + seqsend state.Integer + seqrecv state.Integer + packets state.Indexer connection connection.Object @@ -227,6 +227,7 @@ func (obj Object) OpenInit(ctx sdk.Context) error { return nil } +/* func (obj Object) OpenTry(ctx sdk.Context, timeoutHeight, nextTimeoutHeight uint64) error { if !obj.state.Transit(ctx, Idle, OpenTry) { return errors.New("opentry on non-idle channel") @@ -239,7 +240,7 @@ func (obj Object) OpenTry(ctx sdk.Context, timeoutHeight, nextTimeoutHeight uint // XXX } - +*/ func (obj Object) Send(ctx sdk.Context, packet Packet) error { if obj.state.Get(ctx) != Open { return errors.New("send on non-open channel") @@ -249,7 +250,7 @@ func (obj Object) Send(ctx sdk.Context, packet Packet) error { return errors.New("send on non-open connection") } - if uint64(obj.connection.Client(ctx).GetBase().GetHeight()) >= packet.Timeout() { + if uint64(obj.connection.Client(ctx).GetHeight()) >= packet.Timeout() { return errors.New("timeout height higher than the latest known") } From 99de876fba2f587872ca8481c8288f357f8f0847 Mon Sep 17 00:00:00 2001 From: mossid Date: Sat, 6 Jul 2019 19:59:22 +0200 Subject: [PATCH 180/378] in progress --- x/ibc/04-channel/cli.go | 91 +++++++++++++++++++++++++++++++++ x/ibc/04-channel/manager.go | 28 +++++----- x/ibc/04-channel/tests/types.go | 28 ++++++++++ x/ibc/04-channel/types.go | 6 +-- x/ibc/05-port/manager.go | 14 +++++ 5 files changed, 150 insertions(+), 17 deletions(-) create mode 100644 x/ibc/04-channel/cli.go create mode 100644 x/ibc/04-channel/tests/types.go create mode 100644 x/ibc/05-port/manager.go diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go new file mode 100644 index 000000000000..600c8d2bacee --- /dev/null +++ b/x/ibc/04-channel/cli.go @@ -0,0 +1,91 @@ +package channel + +import ( + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +// CLIObject stores the key for each object fields +type CLIObject struct { + ChanID string + ChannelKey []byte + StateKey []byte + TimeoutKey []byte + + SeqSendKey []byte + SeqRecvKey []byte + PacketKey func(index uint64) []byte + + Connection connection.CLIObject + + Root merkle.Root + Cdc *codec.Codec +} + +func (man Manager) CLIObject(root merkle.Root, connid, chanid string) CLIObject { + obj := man.object(connid, chanid) + return CLIObject{ + ChanID: chanid, + ChannelKey: obj.channel.Key(), + StateKey: obj.state.Key(), + TimeoutKey: obj.nexttimeout.Key(), + + SeqSendKey: obj.seqsend.Key(), + SeqRecvKey: obj.seqrecv.Key(), + PacketKey: func(index uint64) []byte { + return obj.packets.Value(index).Key() + }, + + Connection: man.connection.CLIObject(root, connid), + + Root: root, + Cdc: obj.channel.Cdc(), + } +} + +func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { + resp, err := ctx.QueryABCI(obj.Root.RequestQuery(key)) + if err != nil { + return merkle.Proof{}, err + } + proof := merkle.Proof{ + Key: key, + Proof: resp.Proof, + } + err = obj.Cdc.UnmarshalBinaryBare(resp.Value, ptr) + return proof, err + +} + +func (obj CLIObject) Channel(ctx context.CLIContext) (res Channel, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.ChannelKey, &res) + return +} + +func (obj CLIObject) State(ctx context.CLIContext) (res State, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.StateKey, &res) + return +} + +func (obj CLIObject) Timeout(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.TimeoutKey, &res) + return +} + +func (obj CLIObject) SeqSend(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.SeqSendKey, &res) + return +} + +func (obj CLIObject) SeqRecv(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.SeqRecvKey, &res) + return +} + +func (obj CLIObject) Packet(ctx context.CLIContext, index uint64) (res Packet, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.PacketKey(index), &res) + return +} diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index 0eccb94b5dd8..e32c113ff716 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -115,34 +115,34 @@ func (man Manager) Query(ctx sdk.Context, connid, chanid string) (obj Object, er return } -func (man Manager) Module(module string, chanid func(string) bool) ModuleManager { - return ModuleManager{ +func (man Manager) Port(port string, chanid func(string) bool) PortManager { + return PortManager{ man: man, - module: module, + port: module, chanid: chanid, } } -// ModuleManage is module specific -type ModuleManager struct { +// PortManage is port specific +type PortManager struct { man Manager - module string + port string chanid func(string) bool } -func (man ModuleManager) Create(ctx sdk.Context, connid, chanid string, channel Channel) (Object, error) { +func (man PortManager) Create(ctx sdk.Context, connid, chanid string, channel Channel) (Object, error) { if !man.chanid(chanid) { return Object{}, errors.New("invalid channel id") } - if channel.Module != man.module { - return Object{}, errors.New("invalid module") + if channel.Port != man.port { + return Object{}, errors.New("invalid port") } return man.man.Create(ctx, connid, chanid, channel) } -func (man ModuleManager) Query(ctx sdk.Context, connid, chanid string) (Object, error) { +func (man PortManager) Query(ctx sdk.Context, connid, chanid string) (Object, error) { if !man.chanid(chanid) { return Object{}, errors.New("invalid channel id") } @@ -152,8 +152,8 @@ func (man ModuleManager) Query(ctx sdk.Context, connid, chanid string) (Object, return Object{}, err } - if obj.Value(ctx).Module != man.module { - return Object{}, errors.New("invalid module") + if obj.Value(ctx).Port != man.port { + return Object{}, errors.New("invalid port") } return obj, nil @@ -207,7 +207,7 @@ func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { return nil } -// TODO: ocapify callingModule +// TODO: ocapify callingPort func (obj Object) OpenInit(ctx sdk.Context) error { // CONTRACT: OpenInit() should be called after man.Create(), not man.Query(), // which will ensure @@ -215,7 +215,7 @@ func (obj Object) OpenInit(ctx sdk.Context) error { // set() and // connection.state == open - // getCallingModule() === channel.moduleIdentifier is ensured by ModuleManager + // getCallingPort() === channel.portIdentifier is ensured by PortManager if !obj.state.Transit(ctx, Idle, Init) { return errors.New("init on non-idle channel") diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go new file mode 100644 index 000000000000..049556b0ecd3 --- /dev/null +++ b/x/ibc/04-channel/tests/types.go @@ -0,0 +1,28 @@ +package channel + +import ( + "github.com/cosmos/cosmos-sdk/codec" + + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/tests" +) + +type Node struct { + *connection.Node + Counterparty *Node +} + +func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { + conn := connection.NewNode(self, counter, cdc) + + res := &Node{ + Node: conn, + } + + res.Counterparty = &Node{ + Node: conn.Counterparty, + Counterparty: res, + } + + return res +} diff --git a/x/ibc/04-channel/types.go b/x/ibc/04-channel/types.go index ede4dc69c8d6..2a8922b41abc 100644 --- a/x/ibc/04-channel/types.go +++ b/x/ibc/04-channel/types.go @@ -31,7 +31,7 @@ type Packet interface { } type Channel struct { - Module string - Counterparty string - CounterpartyModule string + Port string + Counterparty string + CounterpartyPort string } diff --git a/x/ibc/05-port/manager.go b/x/ibc/05-port/manager.go new file mode 100644 index 000000000000..782bf7202763 --- /dev/null +++ b/x/ibc/05-port/manager.go @@ -0,0 +1,14 @@ +package port + +import ( + "github.com/cosmos/cosmos-sdk/store/state" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type Manager struct { + protocol state.Mapping +} + +func NewManager(protocol state.Base) Manager { + return Manager +} From 48d9088aaffb1c36731a9efaaf2e2bfdde0d8940 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 13:05:02 +0200 Subject: [PATCH 181/378] in progress --- x/ibc/04-channel/manager.go | 25 +++++++++++++++---------- x/ibc/04-channel/tests/types.go | 5 +++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index e32c113ff716..f4926d529f75 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -160,25 +160,30 @@ func (man PortManager) Query(ctx sdk.Context, connid, chanid string) (Object, er } type Object struct { - chanid string - channel state.Value - state state.Enum - nexttimeout state.Integer + chanid string + + protocol state.Mapping + channel state.Value + /* + state state.Enum + nexttimeout state.Integer + */ seqsend state.Integer seqrecv state.Integer packets state.Indexer connection connection.Object - - counterparty CounterObject } type CounterObject struct { - chanid string - channel commitment.Value - state commitment.Enum - nexttimeout commitment.Integer + chanid string + channel commitment.Value + + /* + state commitment.Enum + nexttimeout commitment.Integer + */ seqsend commitment.Integer seqrecv commitment.Integer diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index 049556b0ecd3..cb2e94bfc780 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -26,3 +26,8 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { return res } + +func OpenInit(t *testing.T) { + ctx, man := node.Handshaker(t) + +} From b991e8451003046cca0374fcdb7073d54b8817f6 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 15:16:38 +0200 Subject: [PATCH 182/378] in progress --- x/ibc/04-channel/handshake.go | 420 ++++++++++++++++++++++++++++++++++ x/ibc/04-channel/manager.go | 20 +- 2 files changed, 432 insertions(+), 8 deletions(-) create mode 100644 x/ibc/04-channel/handshake.go diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go new file mode 100644 index 000000000000..d08a3209deca --- /dev/null +++ b/x/ibc/04-channel/handshake.go @@ -0,0 +1,420 @@ +package connection + +import ( + "errors" + + "github.com/cosmos/cosmos-sdk/store/state" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +type State = byte + +const ( + Idle State = iota + Init + OpenTry + Open + CloseTry + Closed +) + +type Handshake struct { + Counterparty string + CounterpartyClient string +} + +type Handshaker struct { + man Manager + + 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}, + } +} + +type CounterpartyHandshaker struct { + man CounterpartyManager +} + +type HandshakeObject struct { + Object + + state state.Enum + handshake state.Value // type Handshake + nextTimeout state.Integer + + counterparty CounterHandshakeObject +} + +type CounterHandshakeObject struct { + CounterObject + + state commitment.Enum + handshake commitment.Value + 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: state.NewEnum(man.man.protocol.Value([]byte(parent.id + "/state"))), + handshake: man.man.protocol.Value([]byte(parent.id + "/handshake")), + nextTimeout: state.NewInteger(man.man.protocol.Value([]byte(parent.id+"/timeout")), state.Dec), + + // CONTRACT: counterparty must be filled by the caller + } +} + +func (man CounterpartyHandshaker) object(id string) CounterHandshakeObject { + return CounterHandshakeObject{ + CounterObject: man.man.object(id), + + state: commitment.NewEnum(man.man.protocol.Value([]byte(id + "/state"))), + handshake: man.man.protocol.Value([]byte(id + "/handshake")), + nextTimeout: commitment.NewInteger(man.man.protocol.Value([]byte(id+"/timeout")), state.Dec), + } +} + +func (man Handshaker) create(ctx sdk.Context, id, clientid string, handshake Handshake) (obj HandshakeObject, err error) { + cobj, err := man.man.create(ctx, id, clientid, man.Kind()) + if err != nil { + return + } + obj = man.object(cobj) + obj.handshake.Set(ctx, handshake) + obj.counterparty = man.counterparty.object(handshake.Counterparty) + return obj, nil +} + +func (man Handshaker) query(ctx sdk.Context, id string) (obj HandshakeObject, err error) { + cobj, err := man.man.query(ctx, id, man.Kind()) + if err != nil { + return + } + obj = man.object(cobj) + handshake := obj.Handshake(ctx) + obj.counterparty = man.counterparty.object(handshake.Counterparty) + return +} + +func (obj HandshakeObject) State(ctx sdk.Context) byte { + return obj.state.Get(ctx) +} + +func (obj HandshakeObject) Handshake(ctx sdk.Context) (res Handshake) { + obj.handshake.Get(ctx, &res) + return +} + +func (obj HandshakeObject) Timeout(ctx sdk.Context) uint64 { + return obj.nextTimeout.Get(ctx) +} + +func (obj HandshakeObject) NextTimeout(ctx sdk.Context) uint64 { + return obj.nextTimeout.Get(ctx) +} + +func (obj HandshakeObject) remove(ctx sdk.Context) { + obj.Object.remove(ctx) + obj.state.Delete(ctx) + obj.handshake.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, clientid string, handshake Handshake, nextTimeoutHeight uint64, +) (HandshakeObject, error) { + // man.Create() will ensure + // assert(get("connections/{identifier}") === null) and + // set("connections{identifier}", connection) + obj, err := man.create(ctx, id, clientid, handshake) + if err != nil { + return HandshakeObject{}, err + } + + obj.nextTimeout.Set(ctx, nextTimeoutHeight) + obj.state.Set(ctx, Init) + + return obj, nil +} + +// Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} +func (man Handshaker) OpenTry(ctx sdk.Context, + id, clientid string, handshake Handshake, timeoutHeight, nextTimeoutHeight uint64, +) (obj HandshakeObject, err error) { + obj, err = man.create(ctx, id, clientid, handshake) + if err != nil { + return + } + + err = assertTimeout(ctx, timeoutHeight) + if err != nil { + return + } + + if !obj.counterparty.state.Is(ctx, Init) { + err = errors.New("counterparty state not init") + return + } + + if !obj.counterparty.handshake.Is(ctx, Handshake{ + Counterparty: id, + CounterpartyClient: clientid, + }) { + err = errors.New("wrong counterparty") + return + } + + if !obj.counterparty.clientid.Is(ctx, handshake.CounterpartyClient) { + err = errors.New("counterparty client not match") + return + } + + if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { + err = errors.New("unexpected counterparty timeout value") + 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) + + return +} + +// Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} +func (man Handshaker) OpenAck(ctx sdk.Context, + id string /*expheight uint64, */, timeoutHeight, nextTimeoutHeight uint64, +) (obj HandshakeObject, err error) { + obj, err = man.query(ctx, id) + if err != nil { + return + } + + if !obj.state.Transit(ctx, Init, Open) { + err = errors.New("ack on non-init connection") + return + } + + err = assertTimeout(ctx, timeoutHeight) + if err != nil { + return + } + + if !obj.counterparty.handshake.Is(ctx, Handshake{ + Counterparty: obj.ID(), + CounterpartyClient: obj.Client().ID(), + }) { + err = errors.New("wrong counterparty") + return + } + + if !obj.counterparty.state.Is(ctx, OpenTry) { + err = errors.New("counterparty state not opentry") + return + } + + if !obj.counterparty.clientid.Is(ctx, obj.Handshake(ctx).CounterpartyClient) { + err = errors.New("counterparty client not match") + return + } + + if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { + err = errors.New("unexpected counterparty timeout value") + return + } + + // TODO: commented out, implement in v1 + /* + var expected client.ConsensusState + obj.self.Get(ctx, expheight, &expected) + if !obj.counterparty.client.Is(ctx, expected) { + return errors.New("unexpected counterparty client value") + } + */ + + obj.available.Set(ctx, true) + obj.nextTimeout.Set(ctx, uint64(nextTimeoutHeight)) + + return +} + +// Using proofs: counterparty.{connection,state, nextTimeout} +func (man Handshaker) OpenConfirm(ctx sdk.Context, id string, timeoutHeight uint64) (obj HandshakeObject, err error) { + obj, err = man.query(ctx, id) + if err != nil { + return + } + + if !obj.state.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") + return + } + + obj.available.Set(ctx, true) + obj.nextTimeout.Set(ctx, 0) + + return +} + +func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { + if !(uint64(obj.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.handshake.Is(ctx, nil) { + return errors.New("counterparty connection exists") + } + case OpenTry: + if !(obj.counterparty.state.Is(ctx, Init) || + obj.counterparty.clientid.Is(ctx, "")) /*FIXME: empty string does not work, it should be 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 !(uint64(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 f4926d529f75..f9ac5b2f047b 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -47,10 +47,12 @@ func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { func (man Manager) object(connid, chanid string) Object { key := connid + "/channels/" + chanid return Object{ - chanid: chanid, - channel: man.protocol.Value([]byte(key)), - state: state.NewEnum(man.protocol.Value([]byte(key + "/state"))), - nexttimeout: state.NewInteger(man.protocol.Value([]byte(key+"/timeout")), state.Dec), + chanid: chanid, + channel: man.protocol.Value([]byte(key)), + /* + state: state.NewEnum(man.protocol.Value([]byte(key + "/state"))), + nexttimeout: state.NewInteger(man.protocol.Value([]byte(key+"/timeout")), state.Dec), + */ // TODO: remove length functionality from state.Indeer(will be handled manually) seqsend: state.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), state.Dec), @@ -62,10 +64,12 @@ func (man Manager) object(connid, chanid string) Object { func (man CounterpartyManager) object(connid, chanid string) CounterObject { key := connid + "/channels/" + chanid return CounterObject{ - chanid: chanid, - channel: man.protocol.Value([]byte(key)), - state: commitment.NewEnum(man.protocol.Value([]byte(key + "/state"))), - nexttimeout: commitment.NewInteger(man.protocol.Value([]byte(key+"/timeout")), state.Dec), + chanid: chanid, + channel: man.protocol.Value([]byte(key)), + /* + state: commitment.NewEnum(man.protocol.Value([]byte(key + "/state"))), + nexttimeout: commitment.NewInteger(man.protocol.Value([]byte(key+"/timeout")), state.Dec), + */ seqsend: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), state.Dec), seqrecv: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceRecv")), state.Dec), From 9b5b38e9cf400b87fe0306ad74010d4c578bc11f Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 16:23:25 +0200 Subject: [PATCH 183/378] in progress --- x/ibc/04-channel/handshake.go | 89 +++++++++++++++-------------------- x/ibc/04-channel/manager.go | 18 +++---- x/ibc/04-channel/types.go | 11 ----- 3 files changed, 45 insertions(+), 73 deletions(-) diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index d08a3209deca..d90846727fbb 100644 --- a/x/ibc/04-channel/handshake.go +++ b/x/ibc/04-channel/handshake.go @@ -1,4 +1,4 @@ -package connection +package channel import ( "errors" @@ -20,11 +20,6 @@ const ( Closed ) -type Handshake struct { - Counterparty string - CounterpartyClient string -} - type Handshaker struct { man Manager @@ -54,7 +49,6 @@ type HandshakeObject struct { Object state state.Enum - handshake state.Value // type Handshake nextTimeout state.Integer counterparty CounterHandshakeObject @@ -64,52 +58,51 @@ type CounterHandshakeObject struct { CounterObject state commitment.Enum - handshake commitment.Value nextTimeout commitment.Integer } // CONTRACT: client and remote must be filled by the caller func (man Handshaker) object(parent Object) HandshakeObject { + prefix := parent.connection.ID() + "/channels/" + parent.chanid + return HandshakeObject{ Object: parent, - state: state.NewEnum(man.man.protocol.Value([]byte(parent.id + "/state"))), - handshake: man.man.protocol.Value([]byte(parent.id + "/handshake")), - nextTimeout: state.NewInteger(man.man.protocol.Value([]byte(parent.id+"/timeout")), state.Dec), + state: state.NewEnum(man.man.protocol.Value([]byte(prefix + "/state"))), + nextTimeout: state.NewInteger(man.man.protocol.Value([]byte(prefix+"/timeout")), state.Dec), // CONTRACT: counterparty must be filled by the caller } } -func (man CounterpartyHandshaker) object(id string) CounterHandshakeObject { +func (man CounterpartyHandshaker) object(connid, chanid string) CounterHandshakeObject { + prefix := connid + "/channels/" + chanid + return CounterHandshakeObject{ - CounterObject: man.man.object(id), + CounterObject: man.man.object(connid, chanid), - state: commitment.NewEnum(man.man.protocol.Value([]byte(id + "/state"))), - handshake: man.man.protocol.Value([]byte(id + "/handshake")), - nextTimeout: commitment.NewInteger(man.man.protocol.Value([]byte(id+"/timeout")), state.Dec), + state: commitment.NewEnum(man.man.protocol.Value([]byte(prefix + "/state"))), + nextTimeout: commitment.NewInteger(man.man.protocol.Value([]byte(prefix+"/timeout")), state.Dec), } } -func (man Handshaker) create(ctx sdk.Context, id, clientid string, handshake Handshake) (obj HandshakeObject, err error) { - cobj, err := man.man.create(ctx, id, clientid, man.Kind()) +func (man Handshaker) create(ctx sdk.Context, connid, chanid string, channel Channel) (obj HandshakeObject, err error) { + cobj, err := man.man.create(ctx, connid, chanid, channel) if err != nil { return } obj = man.object(cobj) - obj.handshake.Set(ctx, handshake) - obj.counterparty = man.counterparty.object(handshake.Counterparty) + obj.counterparty = man.counterparty.object(obj.connection.Connection(ctx).Counterparty, channel.Counterparty) return obj, nil } -func (man Handshaker) query(ctx sdk.Context, id string) (obj HandshakeObject, err error) { - cobj, err := man.man.query(ctx, id, man.Kind()) +func (man Handshaker) query(ctx sdk.Context, connid, chanid string) (obj HandshakeObject, err error) { + cobj, err := man.man.Query(ctx, connid, chanid) if err != nil { return } obj = man.object(cobj) - handshake := obj.Handshake(ctx) - obj.counterparty = man.counterparty.object(handshake.Counterparty) + obj.counterparty = man.counterparty.object(obj.connection.Connection(ctx).Counterparty, obj.Channel(ctx).Counterparty) return } @@ -117,11 +110,6 @@ func (obj HandshakeObject) State(ctx sdk.Context) byte { return obj.state.Get(ctx) } -func (obj HandshakeObject) Handshake(ctx sdk.Context) (res Handshake) { - obj.handshake.Get(ctx, &res) - return -} - func (obj HandshakeObject) Timeout(ctx sdk.Context) uint64 { return obj.nextTimeout.Get(ctx) } @@ -130,12 +118,14 @@ func (obj HandshakeObject) NextTimeout(ctx sdk.Context) uint64 { return obj.nextTimeout.Get(ctx) } +/* func (obj HandshakeObject) remove(ctx sdk.Context) { obj.Object.remove(ctx) obj.state.Delete(ctx) - obj.handshake.Delete(ctx) + obj.counterpartyClient.Delete(ctx) obj.nextTimeout.Delete(ctx) } +*/ func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { if uint64(ctx.BlockHeight()) > timeoutHeight { @@ -147,12 +137,12 @@ func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { // Using proofs: none func (man Handshaker) OpenInit(ctx sdk.Context, - id, clientid string, handshake Handshake, nextTimeoutHeight uint64, + connid, chanid string, channel Channel, nextTimeoutHeight uint64, ) (HandshakeObject, error) { // man.Create() will ensure - // assert(get("connections/{identifier}") === null) and - // set("connections{identifier}", connection) - obj, err := man.create(ctx, id, clientid, handshake) + // assert(get("channels/{identifier}") === null) and + // set("channels/{identifier}", connection) + obj, err := man.create(ctx, connid, chanid, channel) if err != nil { return HandshakeObject{}, err } @@ -165,9 +155,9 @@ func (man Handshaker) OpenInit(ctx sdk.Context, // Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} func (man Handshaker) OpenTry(ctx sdk.Context, - id, clientid string, handshake Handshake, timeoutHeight, nextTimeoutHeight uint64, + connid, chanid string, channel Channel, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { - obj, err = man.create(ctx, id, clientid, handshake) + obj, err = man.create(ctx, connid, chanid, channel) if err != nil { return } @@ -182,15 +172,12 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - if !obj.counterparty.handshake.Is(ctx, Handshake{ - Counterparty: id, - CounterpartyClient: clientid, - }) { - err = errors.New("wrong counterparty") + if !obj.counterparty.channel.Is(ctx) { + err = errors.New("wrong counterparty connection") return } - if !obj.counterparty.clientid.Is(ctx, handshake.CounterpartyClient) { + if !obj.counterparty.counterpartyClient.Is(ctx, connection.Client) { err = errors.New("counterparty client not match") return } @@ -241,9 +228,9 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.counterparty.handshake.Is(ctx, Handshake{ - Counterparty: obj.ID(), - CounterpartyClient: obj.Client().ID(), + if !obj.counterparty.connection.Is(ctx, Connection{ + Client: obj.Connection(ctx).Client, + Counterparty: obj.ID(), }) { err = errors.New("wrong counterparty") return @@ -254,7 +241,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.counterparty.clientid.Is(ctx, obj.Handshake(ctx).CounterpartyClient) { + if !obj.counterparty.counterpartyClient.Is(ctx, obj.Connection(ctx).Client) { err = errors.New("counterparty client not match") return } @@ -273,7 +260,8 @@ func (man Handshaker) OpenAck(ctx sdk.Context, } */ - obj.available.Set(ctx, true) + obj.sendable.Set(ctx, true) + obj.receivable.Set(ctx, true) obj.nextTimeout.Set(ctx, uint64(nextTimeoutHeight)) return @@ -306,7 +294,8 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, id string, timeoutHeight uint return } - obj.available.Set(ctx, true) + obj.sendable.Set(ctx, true) + obj.receivable.Set(ctx, true) obj.nextTimeout.Set(ctx, 0) return @@ -319,12 +308,12 @@ func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { switch obj.state.Get(ctx) { case Init: - if !obj.counterparty.handshake.Is(ctx, nil) { + if !obj.counterparty.connection.Is(ctx, nil) { return errors.New("counterparty connection exists") } case OpenTry: if !(obj.counterparty.state.Is(ctx, Init) || - obj.counterparty.clientid.Is(ctx, "")) /*FIXME: empty string does not work, it should be nil*/ { + 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) diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index f9ac5b2f047b..703b9d77bfa7 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -77,7 +77,7 @@ func (man CounterpartyManager) object(connid, chanid string) CounterObject { } } -func (man Manager) Create(ctx sdk.Context, connid, chanid string, channel Channel) (obj Object, err error) { +func (man Manager) create(ctx sdk.Context, connid, chanid string, channel Channel) (obj Object, err error) { obj = man.object(connid, chanid) if obj.exists(ctx) { err = errors.New("channel already exists for the provided id") @@ -106,10 +106,6 @@ func (man Manager) Query(ctx sdk.Context, connid, chanid string) (obj Object, er if err != nil { return } - if obj.connection.State(ctx) != connection.Open { - err = errors.New("connection exists but not opened") - return - } channel := obj.Value(ctx) counterconnid := obj.connection.Value(ctx).Counterparty @@ -200,6 +196,11 @@ func (obj Object) ChanID() string { return obj.chanid } +func (obj Object) Channel(ctx sdk.Context) (res Channel) { + obj.channel.Get(ctx, &res) + return +} + func (obj Object) Value(ctx sdk.Context) (res Channel) { obj.channel.Get(ctx, &res) return @@ -209,13 +210,6 @@ func (obj Object) exists(ctx sdk.Context) bool { return obj.channel.Exists(ctx) } -func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { - if uint64(ctx.BlockHeight()) > timeoutHeight { - return errors.New("timeout") - } - return nil -} - // TODO: ocapify callingPort func (obj Object) OpenInit(ctx sdk.Context) error { // CONTRACT: OpenInit() should be called after man.Create(), not man.Query(), diff --git a/x/ibc/04-channel/types.go b/x/ibc/04-channel/types.go index 2a8922b41abc..11c73fe834d4 100644 --- a/x/ibc/04-channel/types.go +++ b/x/ibc/04-channel/types.go @@ -1,16 +1,5 @@ package channel -type State = byte - -const ( - Idle State = iota - Init - OpenTry - Open - CloseTry - Closed -) - /* type Packet struct { Sequence uint64 From ad8b7bf52f5b5d35ae72ac3c51e9e47432beb46a Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 16:39:22 +0200 Subject: [PATCH 184/378] in progress --- x/ibc/04-channel/handshake.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index d90846727fbb..bde8af1e7773 100644 --- a/x/ibc/04-channel/handshake.go +++ b/x/ibc/04-channel/handshake.go @@ -172,16 +172,15 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - if !obj.counterparty.channel.Is(ctx) { + if !obj.counterparty.channel.Is(ctx, Channel{ + Port: channel.CounterpartyPort, + Counterparty: chanid, + CounterpartyPort: "", // TODO + }) { 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, uint64(timeoutHeight)) { err = errors.New("unexpected counterparty timeout value") return From be293beb9c3a2388f3b9625b8efc40293dc52ed9 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 17:44:32 +0200 Subject: [PATCH 185/378] implement test in progress --- x/ibc/03-connection/manager.go | 2 +- x/ibc/03-connection/tests/connection_test.go | 39 +---- x/ibc/03-connection/tests/types.go | 41 +++++ x/ibc/04-channel/cli.go | 53 ++++--- x/ibc/04-channel/codec.go | 9 ++ x/ibc/04-channel/handshake.go | 47 +++--- x/ibc/04-channel/manager.go | 133 ++++++++-------- x/ibc/04-channel/tests/channel_test.go | 57 +++++++ x/ibc/04-channel/tests/types.go | 152 ++++++++++++++++++- 9 files changed, 378 insertions(+), 155 deletions(-) create mode 100644 x/ibc/04-channel/codec.go create mode 100644 x/ibc/04-channel/tests/channel_test.go diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index ad3dd830503d..f4e4d6432c29 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -133,7 +133,7 @@ func (obj Object) Sendable(ctx sdk.Context) bool { return kinds[obj.Kind.Get(ctx)].Sendable } -func (obj Object) Receivble(ctx sdk.Context) bool { +func (obj Object) Receivable(ctx sdk.Context) bool { return kinds[obj.Kind.Get(ctx)].Receivable } diff --git a/x/ibc/03-connection/tests/connection_test.go b/x/ibc/03-connection/tests/connection_test.go index 665f15b3142d..62a8e52fbf85 100644 --- a/x/ibc/03-connection/tests/connection_test.go +++ b/x/ibc/03-connection/tests/connection_test.go @@ -25,42 +25,5 @@ func TestHandshake(t *testing.T) { registerCodec(cdc) node := NewNode(tendermint.NewMockValidators(100, 10), tendermint.NewMockValidators(100, 10), cdc) - node.Commit() - node.Counterparty.Commit() - - node.CreateClient(t) - node.Counterparty.CreateClient(t) - - // self.OpenInit - node.OpenInit(t) - header := node.Commit() - - // counterparty.OpenTry - node.Counterparty.UpdateClient(t, header) - cliobj := node.CLIObject() - _, pconn := node.QueryValue(t, cliobj.Connection) - _, pstate := node.QueryValue(t, cliobj.State) - _, ptimeout := node.QueryValue(t, cliobj.NextTimeout) - _, 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) - header = node.Counterparty.Commit() - - // self.OpenAck - node.UpdateClient(t, header) - cliobj = node.Counterparty.CLIObject() - _, pconn = node.Counterparty.QueryValue(t, cliobj.Connection) - _, pstate = node.Counterparty.QueryValue(t, cliobj.State) - _, ptimeout = node.Counterparty.QueryValue(t, cliobj.NextTimeout) - _, pcounterclient = node.Counterparty.QueryValue(t, cliobj.CounterpartyClient) - node.OpenAck(t, pconn, pstate, ptimeout, 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) + node.Handshake(t) } diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index 29b7b0706721..9fbd375aa4b3 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -149,3 +149,44 @@ func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { require.True(t, obj.Available.Get(ctx)) node.SetState(connection.CloseTry) } + +func (node *Node) Handshake(t *testing.T) { + node.Commit() + node.Counterparty.Commit() + + node.CreateClient(t) + node.Counterparty.CreateClient(t) + + // self.OpenInit + node.OpenInit(t) + header := node.Commit() + + // counterparty.OpenTry + node.Counterparty.UpdateClient(t, header) + cliobj := node.CLIObject() + _, pconn := node.QueryValue(t, cliobj.Connection) + _, pstate := node.QueryValue(t, cliobj.State) + _, ptimeout := node.QueryValue(t, cliobj.NextTimeout) + _, 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) + header = node.Counterparty.Commit() + + // self.OpenAck + node.UpdateClient(t, header) + cliobj = node.Counterparty.CLIObject() + _, pconn = node.Counterparty.QueryValue(t, cliobj.Connection) + _, pstate = node.Counterparty.QueryValue(t, cliobj.State) + _, ptimeout = node.Counterparty.QueryValue(t, cliobj.NextTimeout) + _, pcounterclient = node.Counterparty.QueryValue(t, cliobj.CounterpartyClient) + node.OpenAck(t, pconn, pstate, ptimeout, 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) +} diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index 600c8d2bacee..bbf965808388 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -12,12 +12,11 @@ import ( type CLIObject struct { ChanID string ChannelKey []byte - StateKey []byte - TimeoutKey []byte - SeqSendKey []byte - SeqRecvKey []byte - PacketKey func(index uint64) []byte + AvailableKey []byte + SeqSendKey []byte + SeqRecvKey []byte + PacketKey func(index uint64) []byte Connection connection.CLIObject @@ -30,11 +29,10 @@ func (man Manager) CLIObject(root merkle.Root, connid, chanid string) CLIObject return CLIObject{ ChanID: chanid, ChannelKey: obj.channel.Key(), - StateKey: obj.state.Key(), - TimeoutKey: obj.nexttimeout.Key(), - SeqSendKey: obj.seqsend.Key(), - SeqRecvKey: obj.seqrecv.Key(), + AvailableKey: obj.available.Key(), + SeqSendKey: obj.seqsend.Key(), + SeqRecvKey: obj.seqrecv.Key(), PacketKey: func(index uint64) []byte { return obj.packets.Value(index).Key() }, @@ -65,16 +63,6 @@ func (obj CLIObject) Channel(ctx context.CLIContext) (res Channel, proof merkle. return } -func (obj CLIObject) State(ctx context.CLIContext) (res State, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.StateKey, &res) - return -} - -func (obj CLIObject) Timeout(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.TimeoutKey, &res) - return -} - func (obj CLIObject) SeqSend(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.SeqSendKey, &res) return @@ -89,3 +77,30 @@ func (obj CLIObject) Packet(ctx context.CLIContext, index uint64) (res Packet, p proof, err = obj.query(ctx, obj.PacketKey(index), &res) return } + +type CLIHandshakeObject struct { + CLIObject + + StateKey []byte + TimeoutKey []byte +} + +func (man Handshaker) CLIObject(root merkle.Root, connid, chanid string) CLIHandshakeObject { + obj := man.object(man.man.object(connid, chanid)) + return CLIHandshakeObject{ + CLIObject: man.man.CLIObject(root, connid, chanid), + + StateKey: obj.state.Key(), + TimeoutKey: obj.nextTimeout.Key(), + } +} + +func (obj CLIHandshakeObject) State(ctx context.CLIContext) (res State, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.StateKey, &res) + return +} + +func (obj CLIHandshakeObject) Timeout(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.TimeoutKey, &res) + return +} diff --git a/x/ibc/04-channel/codec.go b/x/ibc/04-channel/codec.go new file mode 100644 index 000000000000..4da636c4edc7 --- /dev/null +++ b/x/ibc/04-channel/codec.go @@ -0,0 +1,9 @@ +package channel + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*Packet)(nil), nil) +} diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index bde8af1e7773..27fc54cb7d1e 100644 --- a/x/ibc/04-channel/handshake.go +++ b/x/ibc/04-channel/handshake.go @@ -63,7 +63,7 @@ type CounterHandshakeObject struct { // CONTRACT: client and remote must be filled by the caller func (man Handshaker) object(parent Object) HandshakeObject { - prefix := parent.connection.ID() + "/channels/" + parent.chanid + prefix := parent.connid + "/channels/" + parent.chanid return HandshakeObject{ Object: parent, @@ -92,17 +92,23 @@ func (man Handshaker) create(ctx sdk.Context, connid, chanid string, channel Cha return } obj = man.object(cobj) - obj.counterparty = man.counterparty.object(obj.connection.Connection(ctx).Counterparty, channel.Counterparty) + counterconnid := obj.connection.Connection(ctx).Counterparty + obj.counterparty = man.counterparty.object(counterconnid, channel.Counterparty) + obj.counterparty.connection = man.counterparty.man.connection.Object(counterconnid) + return obj, nil } func (man Handshaker) query(ctx sdk.Context, connid, chanid string) (obj HandshakeObject, err error) { - cobj, err := man.man.Query(ctx, connid, chanid) + cobj, err := man.man.query(ctx, connid, chanid) if err != nil { return } obj = man.object(cobj) - obj.counterparty = man.counterparty.object(obj.connection.Connection(ctx).Counterparty, obj.Channel(ctx).Counterparty) + channel := obj.Channel(ctx) + counterconnid := obj.connection.Connection(ctx).Counterparty + obj.counterparty = man.counterparty.object(counterconnid, channel.Counterparty) + obj.counterparty.connection = man.counterparty.man.connection.Object(counterconnid) return } @@ -210,9 +216,9 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} func (man Handshaker) OpenAck(ctx sdk.Context, - id string /*expheight uint64, */, timeoutHeight, nextTimeoutHeight uint64, + connid, chanid string, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { - obj, err = man.query(ctx, id) + obj, err = man.query(ctx, connid, chanid) if err != nil { return } @@ -227,9 +233,11 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.counterparty.connection.Is(ctx, Connection{ - Client: obj.Connection(ctx).Client, - Counterparty: obj.ID(), + channel := obj.Channel(ctx) + if !obj.counterparty.channel.Is(ctx, Channel{ + Port: channel.CounterpartyPort, + Counterparty: chanid, + CounterpartyPort: "", // TODO }) { err = errors.New("wrong counterparty") return @@ -240,11 +248,6 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.counterparty.counterpartyClient.Is(ctx, obj.Connection(ctx).Client) { - err = errors.New("counterparty client not match") - return - } - if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { err = errors.New("unexpected counterparty timeout value") return @@ -259,16 +262,15 @@ func (man Handshaker) OpenAck(ctx sdk.Context, } */ - obj.sendable.Set(ctx, true) - obj.receivable.Set(ctx, true) obj.nextTimeout.Set(ctx, uint64(nextTimeoutHeight)) + obj.available.Set(ctx, true) return } // Using proofs: counterparty.{connection,state, nextTimeout} -func (man Handshaker) OpenConfirm(ctx sdk.Context, id string, timeoutHeight uint64) (obj HandshakeObject, err error) { - obj, err = man.query(ctx, id) +func (man Handshaker) OpenConfirm(ctx sdk.Context, connid, chanid string, timeoutHeight uint64) (obj HandshakeObject, err error) { + obj, err = man.query(ctx, connid, chanid) if err != nil { return } @@ -293,15 +295,16 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, id string, timeoutHeight uint return } - obj.sendable.Set(ctx, true) - obj.receivable.Set(ctx, true) + obj.available.Set(ctx, true) obj.nextTimeout.Set(ctx, 0) return } +// TODO +/* func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { - if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { + if !(uint64(obj.connection.Client().ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } @@ -327,6 +330,7 @@ func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { 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") @@ -406,3 +410,4 @@ func (obj HandshakeObject) CloseTimeout(ctx sdk.Context) error { return nil } +*/ diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index 703b9d77bfa7..a1595608463b 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -48,13 +48,11 @@ func (man Manager) object(connid, chanid string) Object { key := connid + "/channels/" + chanid return Object{ chanid: chanid, + connid: connid, channel: man.protocol.Value([]byte(key)), - /* - state: state.NewEnum(man.protocol.Value([]byte(key + "/state"))), - nexttimeout: state.NewInteger(man.protocol.Value([]byte(key+"/timeout")), state.Dec), - */ - // TODO: remove length functionality from state.Indeer(will be handled manually) + available: state.NewBoolean(man.protocol.Value([]byte(key + "/available"))), + seqsend: state.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), state.Dec), seqrecv: state.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceRecv")), state.Dec), packets: state.NewIndexer(man.protocol.Prefix([]byte(key+"/packets/")), state.Dec), @@ -65,11 +63,10 @@ func (man CounterpartyManager) object(connid, chanid string) CounterObject { key := connid + "/channels/" + chanid return CounterObject{ chanid: chanid, + connid: connid, channel: man.protocol.Value([]byte(key)), - /* - state: commitment.NewEnum(man.protocol.Value([]byte(key + "/state"))), - nexttimeout: commitment.NewInteger(man.protocol.Value([]byte(key+"/timeout")), state.Dec), - */ + + available: commitment.NewBoolean(man.protocol.Value([]byte(key + "/available"))), seqsend: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), state.Dec), seqrecv: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceRecv")), state.Dec), @@ -87,16 +84,17 @@ func (man Manager) create(ctx sdk.Context, connid, chanid string, channel Channe if err != nil { return } - counterconnid := obj.connection.Value(ctx).Counterparty - obj.counterparty = man.counterparty.object(counterconnid, channel.Counterparty) - obj.counterparty.connection = man.counterparty.connection.Query(counterconnid) - obj.channel.Set(ctx, channel) + counterconnid := obj.connection.Connection(ctx).Counterparty + obj.counterparty = man.counterparty.object(counterconnid, channel.Counterparty) + obj.counterparty.connection = man.counterparty.connection.Object(counterconnid) + return } -func (man Manager) Query(ctx sdk.Context, connid, chanid string) (obj Object, err error) { +// Does not check availability +func (man Manager) query(ctx sdk.Context, connid, chanid string) (obj Object, err error) { obj = man.object(connid, chanid) if !obj.exists(ctx) { err = errors.New("channel not exists for the provided id") @@ -107,18 +105,29 @@ func (man Manager) Query(ctx sdk.Context, connid, chanid string) (obj Object, er return } - channel := obj.Value(ctx) - counterconnid := obj.connection.Value(ctx).Counterparty - obj.counterparty = man.counterparty.object(counterconnid, channel.Counterparty) - obj.counterparty.connection = man.counterparty.connection.Query(counterconnid) + counterconnid := obj.connection.Connection(ctx).Counterparty + obj.counterparty = man.counterparty.object(counterconnid, obj.Channel(ctx).Counterparty) + obj.counterparty.connection = man.counterparty.connection.Object(counterconnid) return + } +func (man Manager) Query(ctx sdk.Context, connid, chanid string) (obj Object, err error) { + obj, err = man.query(ctx, connid, chanid) + if !obj.Available(ctx) { + 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: module, + port: le, chanid: chanid, } } @@ -158,37 +167,37 @@ func (man PortManager) Query(ctx sdk.Context, connid, chanid string) (Object, er return obj, nil } +*/ type Object struct { chanid string + connid string protocol state.Mapping channel state.Value - /* - state state.Enum - nexttimeout state.Integer - */ seqsend state.Integer seqrecv state.Integer packets state.Indexer + available state.Boolean + connection connection.Object + + counterparty CounterObject } type CounterObject struct { chanid string + connid string channel commitment.Value - /* - state commitment.Enum - nexttimeout commitment.Integer - */ - seqsend commitment.Integer seqrecv commitment.Integer packets commitment.Indexer + available commitment.Boolean + connection connection.CounterObject } @@ -206,54 +215,42 @@ func (obj Object) Value(ctx sdk.Context) (res Channel) { return } -func (obj Object) exists(ctx sdk.Context) bool { - return obj.channel.Exists(ctx) +func (obj Object) Available(ctx sdk.Context) bool { + return obj.available.Get(ctx) } -// TODO: ocapify callingPort -func (obj Object) OpenInit(ctx sdk.Context) error { - // CONTRACT: OpenInit() should be called after man.Create(), not man.Query(), - // which will ensure - // assert(get() === null) and - // set() and - // connection.state == open - - // getCallingPort() === channel.portIdentifier is ensured by PortManager - - if !obj.state.Transit(ctx, Idle, Init) { - return errors.New("init on non-idle channel") - } +func (obj Object) Sendable(ctx sdk.Context) bool { + // TODO: sendable/receivable should be also defined for channels + return obj.connection.Sendable(ctx) +} - obj.seqsend.Set(ctx, 0) - obj.seqrecv.Set(ctx, 0) +func (obj Object) Receivable(ctx sdk.Context) bool { + return obj.connection.Receivable(ctx) +} - return nil +func (obj Object) SeqSend(ctx sdk.Context) uint64 { + return obj.seqsend.Get(ctx) } -/* -func (obj Object) OpenTry(ctx sdk.Context, timeoutHeight, nextTimeoutHeight uint64) error { - if !obj.state.Transit(ctx, Idle, OpenTry) { - return errors.New("opentry on non-idle channel") - } +func (obj Object) SeqRecv(ctx sdk.Context) uint64 { + return obj.seqrecv.Get(ctx) +} - err := assertTimeout(ctx, timeoutHeight) - if err != nil { - return err - } +func (obj Object) Packet(ctx sdk.Context, index uint64) (res Packet) { + obj.packets.Value(index).Get(ctx, &res) + return +} - // XXX +func (obj Object) exists(ctx sdk.Context) bool { + return obj.channel.Exists(ctx) } -*/ -func (obj Object) Send(ctx sdk.Context, packet Packet) error { - if obj.state.Get(ctx) != Open { - return errors.New("send on non-open channel") - } - if obj.connection.State(ctx) != Open { - return errors.New("send on non-open connection") +func (obj Object) Send(ctx sdk.Context, packet Packet) error { + if !obj.Sendable(ctx) { + return errors.New("cannot send packets on this channel") } - if uint64(obj.connection.Client(ctx).GetHeight()) >= packet.Timeout() { + if uint64(obj.connection.Client().ConsensusState(ctx).GetHeight()) >= packet.Timeout() { return errors.New("timeout height higher than the latest known") } @@ -263,12 +260,8 @@ func (obj Object) Send(ctx sdk.Context, packet Packet) error { } func (obj Object) Receive(ctx sdk.Context, packet Packet) error { - if obj.state.Get(ctx) != Open { - return errors.New("send on non-open channel") - } - - if obj.connection.State(ctx) != Open { - return errors.New("send on non-open connection") + if !obj.Receivable(ctx) { + return errors.New("cannot receive packets on this channel") } err := assertTimeout(ctx, packet.Timeout()) diff --git a/x/ibc/04-channel/tests/channel_test.go b/x/ibc/04-channel/tests/channel_test.go new file mode 100644 index 000000000000..c145dcaf4f71 --- /dev/null +++ b/x/ibc/04-channel/tests/channel_test.go @@ -0,0 +1,57 @@ +package channel + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + + "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + tmclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +func registerCodec(cdc *codec.Codec) { + client.RegisterCodec(cdc) + tmclient.RegisterCodec(cdc) + commitment.RegisterCodec(cdc) + merkle.RegisterCodec(cdc) + codec.RegisterCrypto(cdc) + channel.RegisterCodec(cdc) + cdc.RegisterConcrete(MyPacket{}, "test/MyPacket", nil) +} + +func TestHandshake(t *testing.T) { + cdc := codec.New() + registerCodec(cdc) + + node := NewNode(tendermint.NewMockValidators(100, 10), tendermint.NewMockValidators(100, 10), cdc) + + node.Handshake(t) +} + +type MyPacket struct { + Message string +} + +func (packet MyPacket) Commit() []byte { + return []byte(packet.Message) +} + +func (packet MyPacket) Timeout() uint64 { + return 100 // TODO +} + +func TestPacket(t *testing.T) { + cdc := codec.New() + registerCodec(cdc) + + node := NewNode(tendermint.NewMockValidators(100, 10), tendermint.NewMockValidators(100, 10), cdc) + + node.Handshake(t) + + node.Send(t, MyPacket{"ping"}) + node.Counterparty.Receive(t, MyPacket{"ping"}) +} diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index cb2e94bfc780..24873f7df738 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -1,33 +1,173 @@ package channel import ( + "testing" + + "github.com/stretchr/testify/require" + "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/ibc/02-client/tendermint/tests" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/tests" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) type Node struct { *connection.Node Counterparty *Node + + Channel channel.Channel + + Cdc *codec.Codec } func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { - conn := connection.NewNode(self, counter, cdc) - res := &Node{ - Node: conn, + Node: connection.NewNode(self, counter, cdc), // TODO: test with key prefix + + Cdc: cdc, } res.Counterparty = &Node{ - Node: conn.Counterparty, + Node: res.Node.Counterparty, Counterparty: res, + + Cdc: cdc, + } + + res.Channel = channel.Channel{ + Port: "", // TODO + Counterparty: res.Counterparty.Name, + CounterpartyPort: "", //TODO + } + + res.Counterparty.Channel = channel.Channel{ + Port: "", // TODO + Counterparty: res.Name, + CounterpartyPort: "", // TODO } return res } -func OpenInit(t *testing.T) { - ctx, man := node.Handshaker(t) +func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Context, channel.Handshaker) { + ctx := node.Context() + store, err := commitment.NewStore(node.Counterparty.Root, proofs) + require.NoError(t, err) + ctx = commitment.WithStore(ctx, store) + man := node.Manager() + return ctx, channel.NewHandshaker(man) +} + +func (node *Node) CLIObject() channel.CLIHandshakeObject { + man := node.Manager() + return channel.NewHandshaker(man).CLIObject(node.Root, node.Name, node.Name) +} + +func base(cdc *codec.Codec, key sdk.StoreKey) (state.Base, state.Base) { + protocol := state.NewBase(cdc, key, []byte("protocol")) + free := state.NewBase(cdc, key, []byte("free")) + return protocol, free +} + +func (node *Node) Manager() channel.Manager { + protocol, _ := base(node.Cdc, node.Key) + _, connman := node.Node.Manager() + return channel.NewManager(protocol, connman) +} + +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 + require.NoError(t, err) + require.Equal(t, channel.Init, obj.State(ctx)) + require.Equal(t, node.Channel, obj.Channel(ctx)) + require.False(t, obj.Available(ctx)) +} + +func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { + ctx, man := node.Handshaker(t, proofs) + obj, err := man.OpenTry(ctx, node.Name, node.Name, node.Channel, 100 /*TODO*/, 100 /*TODO*/) + require.NoError(t, err) + require.Equal(t, channel.OpenTry, obj.State(ctx)) + require.Equal(t, node.Channel, obj.Channel(ctx)) + require.False(t, obj.Available(ctx)) + node.SetState(channel.OpenTry) +} + +func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { + ctx, man := node.Handshaker(t, proofs) + obj, err := man.OpenAck(ctx, node.Name, node.Name, 100 /*TODO*/, 100 /*TODO*/) + require.NoError(t, err) + require.Equal(t, channel.Open, obj.State(ctx)) + require.Equal(t, node.Channel, obj.Channel(ctx)) + require.True(t, obj.Available(ctx)) + node.SetState(channel.Open) +} + +func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { + ctx, man := node.Handshaker(t, proofs) + obj, err := man.OpenConfirm(ctx, node.Name, node.Name, 100 /*TODO*/) + require.NoError(t, err) + require.Equal(t, channel.Open, obj.State(ctx)) + require.Equal(t, node.Channel, obj.Channel(ctx)) + require.True(t, obj.Available(ctx)) + node.SetState(channel.CloseTry) +} + +func (node *Node) Handshake(t *testing.T) { + node.Node.Handshake(t) + + // self.OpenInit + node.OpenInit(t) + header := node.Commit() + + // counterparty.OpenTry + node.Counterparty.UpdateClient(t, header) + cliobj := node.CLIObject() + _, pchan := node.Query(t, cliobj.ChannelKey) + _, pstate := node.Query(t, cliobj.StateKey) + _, ptimeout := node.Query(t, cliobj.TimeoutKey) + node.Counterparty.OpenTry(t, pchan, pstate, ptimeout) + header = node.Counterparty.Commit() + + // self.OpenAck + node.UpdateClient(t, header) + cliobj = node.Counterparty.CLIObject() + _, pchan = node.Counterparty.Query(t, cliobj.ChannelKey) + _, pstate = node.Counterparty.Query(t, cliobj.StateKey) + _, ptimeout = node.Counterparty.Query(t, cliobj.TimeoutKey) + node.OpenAck(t, pchan, pstate, ptimeout) + header = node.Commit() + + // counterparty.OpenConfirm + node.Counterparty.UpdateClient(t, header) + cliobj = node.CLIObject() + _, pstate = node.Query(t, cliobj.StateKey) + _, ptimeout = node.Query(t, cliobj.TimeoutKey) + node.Counterparty.OpenConfirm(t, pstate, ptimeout) +} + +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) + require.NoError(t, err) + seq := obj.SeqSend(ctx) + err = obj.Send(ctx, packet) + require.NoError(t, err) + require.Equal(t, seq+1, obj.SeqSend(ctx)) + require.Equal(t, packet, obj.Packet(ctx, seq+1)) +} +func (node *Node) Receive(t *testing.T, packet channel.Packet) { + ctx, man := node.Context(), node.Manager() + obj, err := man.Query(ctx, node.Name, node.Name) + require.NoError(t, err) + seq := obj.SeqRecv(ctx) + err = obj.Receive(ctx, packet) + require.NoError(t, err) + require.Equal(t, seq+1, obj.SeqRecv(ctx)) } From bf1d7f7817f2d952eca03db1b5d58703aa7dbb11 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 18:09:26 +0200 Subject: [PATCH 186/378] send/receive test working --- store/state/indexer.go | 4 ++++ store/state/mapping.go | 4 ++++ x/ibc/04-channel/cli.go | 14 +++++++------- x/ibc/04-channel/manager.go | 11 +++++------ x/ibc/04-channel/tests/channel_test.go | 7 ++++++- x/ibc/04-channel/tests/types.go | 10 +++++----- x/ibc/05-port/manager.go | 14 -------------- 7 files changed, 31 insertions(+), 33 deletions(-) delete mode 100644 x/ibc/05-port/manager.go diff --git a/store/state/indexer.go b/store/state/indexer.go index 6b837c2021a3..666d31b45667 100644 --- a/store/state/indexer.go +++ b/store/state/indexer.go @@ -94,6 +94,10 @@ func (ix Indexer) Set(ctx Context, index uint64, o interface{}) { ix.Value(index).Set(ctx, o) } +func (ix Indexer) SetRaw(ctx Context, index uint64, value []byte) { + ix.Value(index).SetRaw(ctx, value) +} + // Has() returns true if the stored value is not nil func (ix Indexer) Has(ctx Context, index uint64) bool { return ix.Value(index).Exists(ctx) diff --git a/store/state/mapping.go b/store/state/mapping.go index 7bc120ffaed7..8cebbf97c1d7 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -49,6 +49,10 @@ func (m Mapping) Set(ctx Context, key []byte, o interface{}) { m.Value(key).Set(ctx, o) } +func (m Mapping) SetRaw(ctx Context, key []byte, value []byte) { + m.Value(key).SetRaw(ctx, value) +} + // Has() returns true if the stored value is not nil func (m Mapping) Has(ctx Context, key []byte) bool { return m.Value(key).Exists(ctx) diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index bbf965808388..51a6c8d526e0 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -13,10 +13,10 @@ type CLIObject struct { ChanID string ChannelKey []byte - AvailableKey []byte - SeqSendKey []byte - SeqRecvKey []byte - PacketKey func(index uint64) []byte + AvailableKey []byte + SeqSendKey []byte + SeqRecvKey []byte + PacketCommitKey func(index uint64) []byte Connection connection.CLIObject @@ -33,7 +33,7 @@ func (man Manager) CLIObject(root merkle.Root, connid, chanid string) CLIObject AvailableKey: obj.available.Key(), SeqSendKey: obj.seqsend.Key(), SeqRecvKey: obj.seqrecv.Key(), - PacketKey: func(index uint64) []byte { + PacketCommitKey: func(index uint64) []byte { return obj.packets.Value(index).Key() }, @@ -73,8 +73,8 @@ func (obj CLIObject) SeqRecv(ctx context.CLIContext) (res uint64, proof merkle.P return } -func (obj CLIObject) Packet(ctx context.CLIContext, index uint64) (res Packet, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.PacketKey(index), &res) +func (obj CLIObject) PacketCommit(ctx context.CLIContext, index uint64) (res Packet, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.PacketCommitKey(index), &res) return } diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index a1595608463b..baffac7fabf5 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -70,7 +70,7 @@ func (man CounterpartyManager) object(connid, chanid string) CounterObject { seqsend: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), state.Dec), seqrecv: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceRecv")), state.Dec), - packets: commitment.NewIndexer(man.protocol.Prefix([]byte(key+"/packets")), state.Dec), + packets: commitment.NewIndexer(man.protocol.Prefix([]byte(key+"/packets/")), state.Dec), } } @@ -236,9 +236,8 @@ func (obj Object) SeqRecv(ctx sdk.Context) uint64 { return obj.seqrecv.Get(ctx) } -func (obj Object) Packet(ctx sdk.Context, index uint64) (res Packet) { - obj.packets.Value(index).Get(ctx, &res) - return +func (obj Object) PacketCommit(ctx sdk.Context, index uint64) []byte { + return obj.packets.Value(index).GetRaw(ctx) } func (obj Object) exists(ctx sdk.Context) bool { @@ -254,7 +253,7 @@ func (obj Object) Send(ctx sdk.Context, packet Packet) error { return errors.New("timeout height higher than the latest known") } - obj.packets.Set(ctx, obj.seqsend.Incr(ctx), packet) + obj.packets.SetRaw(ctx, obj.seqsend.Incr(ctx), packet.Commit()) return nil } @@ -270,7 +269,7 @@ func (obj Object) Receive(ctx sdk.Context, packet Packet) error { } // XXX: increment should happen before verification, reflect on the spec - if !obj.counterparty.packets.Value(obj.seqrecv.Incr(ctx)).Is(ctx, packet.Commit()) { + if !obj.counterparty.packets.Value(obj.seqrecv.Incr(ctx)).IsRaw(ctx, packet.Commit()) { return errors.New("verification failed") } diff --git a/x/ibc/04-channel/tests/channel_test.go b/x/ibc/04-channel/tests/channel_test.go index c145dcaf4f71..db2aac451268 100644 --- a/x/ibc/04-channel/tests/channel_test.go +++ b/x/ibc/04-channel/tests/channel_test.go @@ -53,5 +53,10 @@ func TestPacket(t *testing.T) { node.Handshake(t) node.Send(t, MyPacket{"ping"}) - node.Counterparty.Receive(t, MyPacket{"ping"}) + header := node.Commit() + + node.Counterparty.UpdateClient(t, header) + cliobj := node.CLIObject() + _, ppacket := node.Query(t, cliobj.PacketCommitKey(1)) + node.Counterparty.Receive(t, MyPacket{"ping"}, ppacket) } diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index 24873f7df738..56021467d4db 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -54,7 +54,7 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { } func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Context, channel.Handshaker) { - ctx := node.Context() + ctx := node.Context(t, proofs) store, err := commitment.NewStore(node.Counterparty.Root, proofs) require.NoError(t, err) ctx = commitment.WithStore(ctx, store) @@ -152,18 +152,18 @@ func (node *Node) Handshake(t *testing.T) { } func (node *Node) Send(t *testing.T, packet channel.Packet) { - ctx, man := node.Context(), node.Manager() + ctx, man := node.Context(t, nil), node.Manager() obj, err := man.Query(ctx, node.Name, node.Name) require.NoError(t, err) seq := obj.SeqSend(ctx) err = obj.Send(ctx, packet) require.NoError(t, err) require.Equal(t, seq+1, obj.SeqSend(ctx)) - require.Equal(t, packet, obj.Packet(ctx, seq+1)) + require.Equal(t, packet.Commit(), obj.PacketCommit(ctx, seq+1)) } -func (node *Node) Receive(t *testing.T, packet channel.Packet) { - ctx, man := node.Context(), node.Manager() +func (node *Node) Receive(t *testing.T, packet channel.Packet, proofs ...commitment.Proof) { + ctx, man := node.Context(t, proofs), node.Manager() obj, err := man.Query(ctx, node.Name, node.Name) require.NoError(t, err) seq := obj.SeqRecv(ctx) diff --git a/x/ibc/05-port/manager.go b/x/ibc/05-port/manager.go deleted file mode 100644 index 782bf7202763..000000000000 --- a/x/ibc/05-port/manager.go +++ /dev/null @@ -1,14 +0,0 @@ -package port - -import ( - "github.com/cosmos/cosmos-sdk/store/state" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -type Manager struct { - protocol state.Mapping -} - -func NewManager(protocol state.Base) Manager { - return Manager -} From 705b1099de0f2c21c83a208d8731bfe7d3413aab Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 7 Jul 2019 19:05:41 +0200 Subject: [PATCH 187/378] fix most of lint --- x/ibc/04-channel/handshake.go | 10 +++++----- x/ibc/04-channel/manager.go | 5 ++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index 27fc54cb7d1e..eb38c63f5475 100644 --- a/x/ibc/04-channel/handshake.go +++ b/x/ibc/04-channel/handshake.go @@ -187,7 +187,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { + if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { err = errors.New("unexpected counterparty timeout value") return } @@ -248,7 +248,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.counterparty.nextTimeout.Is(ctx, uint64(timeoutHeight)) { + if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { err = errors.New("unexpected counterparty timeout value") return } @@ -262,7 +262,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, } */ - obj.nextTimeout.Set(ctx, uint64(nextTimeoutHeight)) + obj.nextTimeout.Set(ctx, nextTimeoutHeight) obj.available.Set(ctx, true) return @@ -304,7 +304,7 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, connid, chanid string, timeou // TODO /* func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { - if !(uint64(obj.connection.Client().ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { + if !(obj.connection.Client().ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } @@ -388,7 +388,7 @@ func (obj HandshakeObject) CloseAck(ctx sdk.Context, timeoutHeight uint64) error } func (obj HandshakeObject) CloseTimeout(ctx sdk.Context) error { - if !(uint64(obj.client.ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { + if !(obj.client.ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index baffac7fabf5..8d8287a1f3d8 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -173,8 +173,7 @@ type Object struct { chanid string connid string - protocol state.Mapping - channel state.Value + channel state.Value seqsend state.Integer seqrecv state.Integer @@ -249,7 +248,7 @@ func (obj Object) Send(ctx sdk.Context, packet Packet) error { return errors.New("cannot send packets on this channel") } - if uint64(obj.connection.Client().ConsensusState(ctx).GetHeight()) >= packet.Timeout() { + if obj.connection.Client().ConsensusState(ctx).GetHeight() >= packet.Timeout() { return errors.New("timeout height higher than the latest known") } From 72090e7e1962b0bfa86228e43cd20ec721f8f869 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 14 Jul 2019 02:41:21 +0900 Subject: [PATCH 188/378] finalize rebase on merkle path / root separatio --- x/ibc/04-channel/cli.go | 14 +++++++------- x/ibc/04-channel/tests/types.go | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index 51a6c8d526e0..52e1780ec237 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -20,11 +20,11 @@ type CLIObject struct { Connection connection.CLIObject - Root merkle.Root + Path merkle.Path Cdc *codec.Codec } -func (man Manager) CLIObject(root merkle.Root, connid, chanid string) CLIObject { +func (man Manager) CLIObject(path merkle.Path, chanid, connid, clientid string) CLIObject { obj := man.object(connid, chanid) return CLIObject{ ChanID: chanid, @@ -37,15 +37,15 @@ func (man Manager) CLIObject(root merkle.Root, connid, chanid string) CLIObject return obj.packets.Value(index).Key() }, - Connection: man.connection.CLIObject(root, connid), + Connection: man.connection.CLIObject(path, connid, clientid), - Root: root, + Path: path, Cdc: obj.channel.Cdc(), } } func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { - resp, err := ctx.QueryABCI(obj.Root.RequestQuery(key)) + resp, err := ctx.QueryABCI(obj.Path.RequestQuery(key)) if err != nil { return merkle.Proof{}, err } @@ -85,10 +85,10 @@ type CLIHandshakeObject struct { TimeoutKey []byte } -func (man Handshaker) CLIObject(root merkle.Root, connid, chanid string) CLIHandshakeObject { +func (man Handshaker) CLIObject(path merkle.Path, chanid, connid, clientid string) CLIHandshakeObject { obj := man.object(man.man.object(connid, chanid)) return CLIHandshakeObject{ - CLIObject: man.man.CLIObject(root, connid, chanid), + CLIObject: man.man.CLIObject(path, chanid, connid, clientid), StateKey: obj.state.Key(), TimeoutKey: obj.nextTimeout.Key(), diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index 56021467d4db..fc62aa251510 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -55,7 +55,7 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Context, channel.Handshaker) { ctx := node.Context(t, proofs) - store, err := commitment.NewStore(node.Counterparty.Root, proofs) + store, err := commitment.NewStore(node.Counterparty.Root(), node.Counterparty.Path, proofs) require.NoError(t, err) ctx = commitment.WithStore(ctx, store) man := node.Manager() @@ -64,7 +64,7 @@ func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Conte func (node *Node) CLIObject() channel.CLIHandshakeObject { man := node.Manager() - return channel.NewHandshaker(man).CLIObject(node.Root, node.Name, node.Name) + return channel.NewHandshaker(man).CLIObject(node.Path, node.Name, node.Name, node.Name) } func base(cdc *codec.Codec, key sdk.StoreKey) (state.Base, state.Base) { From 5f57caa04e68fae1608811d1d493146c12c485a7 Mon Sep 17 00:00:00 2001 From: mossid Date: Sun, 14 Jul 2019 05:03:31 +0900 Subject: [PATCH 189/378] manually pass proofs --- x/ibc/04-channel/handshake.go | 23 +++++++++++++++++++++-- x/ibc/04-channel/manager.go | 13 +++++++++++-- x/ibc/04-channel/tests/types.go | 14 +++++++------- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index eb38c63f5475..2889aa8183fc 100644 --- a/x/ibc/04-channel/handshake.go +++ b/x/ibc/04-channel/handshake.go @@ -159,8 +159,9 @@ func (man Handshaker) OpenInit(ctx sdk.Context, return obj, nil } -// Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} +// Using proofs: counterparty.{channel,state,nextTimeout} func (man Handshaker) OpenTry(ctx sdk.Context, + pchannel, pstate, ptimeout commitment.Proof, connid, chanid string, channel Channel, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { obj, err = man.create(ctx, connid, chanid, channel) @@ -168,6 +169,11 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } + ctx, err = obj.Context(ctx, pchannel, pstate, ptimeout) + if err != nil { + return + } + err = assertTimeout(ctx, timeoutHeight) if err != nil { return @@ -216,6 +222,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} func (man Handshaker) OpenAck(ctx sdk.Context, + pchannel, pstate, ptimeout commitment.Proof, connid, chanid string, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { obj, err = man.query(ctx, connid, chanid) @@ -223,6 +230,11 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } + ctx, err = obj.Context(ctx, pchannel, pstate, ptimeout) + if err != nil { + return + } + if !obj.state.Transit(ctx, Init, Open) { err = errors.New("ack on non-init connection") return @@ -269,12 +281,19 @@ func (man Handshaker) OpenAck(ctx sdk.Context, } // Using proofs: counterparty.{connection,state, nextTimeout} -func (man Handshaker) OpenConfirm(ctx sdk.Context, connid, chanid string, timeoutHeight uint64) (obj HandshakeObject, err error) { +func (man Handshaker) OpenConfirm(ctx sdk.Context, + pstate, ptimeout commitment.Proof, + connid, chanid string, timeoutHeight uint64) (obj HandshakeObject, err error) { obj, err = man.query(ctx, connid, chanid) if err != nil { return } + ctx, err = obj.Context(ctx, pstate, ptimeout) + if err != nil { + return + } + if !obj.state.Transit(ctx, OpenTry, Open) { err = errors.New("confirm on non-try connection") return diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index 8d8287a1f3d8..fe095ec8dfe4 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -200,6 +200,10 @@ type CounterObject struct { connection connection.CounterObject } +func (obj Object) Context(ctx sdk.Context, proofs ...commitment.Proof) (sdk.Context, error) { + return obj.connection.Context(ctx, nil, proofs...) +} + func (obj Object) ChanID() string { return obj.chanid } @@ -257,12 +261,17 @@ func (obj Object) Send(ctx sdk.Context, packet Packet) error { return nil } -func (obj Object) Receive(ctx sdk.Context, packet Packet) error { +func (obj Object) Receive(ctx sdk.Context, ppacket commitment.Proof, packet Packet) error { if !obj.Receivable(ctx) { return errors.New("cannot receive packets on this channel") } - err := assertTimeout(ctx, packet.Timeout()) + ctx, err := obj.Context(ctx, ppacket) + if err != nil { + return err + } + + err = assertTimeout(ctx, packet.Timeout()) if err != nil { return err } diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index fc62aa251510..80f94e7e248c 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -54,7 +54,7 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { } func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Context, channel.Handshaker) { - ctx := node.Context(t, proofs) + ctx := node.Context() store, err := commitment.NewStore(node.Counterparty.Root(), node.Counterparty.Path, proofs) require.NoError(t, err) ctx = commitment.WithStore(ctx, store) @@ -90,7 +90,7 @@ func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenTry(ctx, node.Name, node.Name, node.Channel, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenTry(ctx, proofs[0], proofs[1], proofs[2], node.Name, node.Name, node.Channel, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, channel.OpenTry, obj.State(ctx)) require.Equal(t, node.Channel, obj.Channel(ctx)) @@ -100,7 +100,7 @@ func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenAck(ctx, node.Name, node.Name, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenAck(ctx, proofs[0], proofs[1], proofs[2], node.Name, node.Name, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, channel.Open, obj.State(ctx)) require.Equal(t, node.Channel, obj.Channel(ctx)) @@ -110,7 +110,7 @@ func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenConfirm(ctx, node.Name, node.Name, 100 /*TODO*/) + obj, err := man.OpenConfirm(ctx, proofs[0], proofs[1], node.Name, node.Name, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, channel.Open, obj.State(ctx)) require.Equal(t, node.Channel, obj.Channel(ctx)) @@ -152,7 +152,7 @@ func (node *Node) Handshake(t *testing.T) { } func (node *Node) Send(t *testing.T, packet channel.Packet) { - ctx, man := node.Context(t, nil), node.Manager() + ctx, man := node.Context(), node.Manager() obj, err := man.Query(ctx, node.Name, node.Name) require.NoError(t, err) seq := obj.SeqSend(ctx) @@ -163,11 +163,11 @@ func (node *Node) Send(t *testing.T, packet channel.Packet) { } func (node *Node) Receive(t *testing.T, packet channel.Packet, proofs ...commitment.Proof) { - ctx, man := node.Context(t, proofs), node.Manager() + ctx, man := node.Context(), node.Manager() obj, err := man.Query(ctx, node.Name, node.Name) require.NoError(t, err) seq := obj.SeqRecv(ctx) - err = obj.Receive(ctx, packet) + err = obj.Receive(ctx, proofs[0], packet) require.NoError(t, err) require.Equal(t, seq+1, obj.SeqRecv(ctx)) } From b01c3f963612c6567295691395cf17c3f250c41f Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 18 Jul 2019 02:43:47 +0900 Subject: [PATCH 190/378] add msgs/handler in progress --- x/ibc/04-channel/cli.go | 8 +- x/ibc/04-channel/client/cli/query.go | 101 +++++++++++ x/ibc/04-channel/client/cli/tx.go | 221 +++++++++++++++++++++++++ x/ibc/04-channel/client/utils/types.go | 59 +++++++ x/ibc/04-channel/handler.go | 37 +++++ x/ibc/04-channel/handshake.go | 12 +- x/ibc/04-channel/manager.go | 8 +- x/ibc/04-channel/msgs.go | 132 +++++++++++++++ 8 files changed, 564 insertions(+), 14 deletions(-) create mode 100644 x/ibc/04-channel/client/cli/query.go create mode 100644 x/ibc/04-channel/client/cli/tx.go create mode 100644 x/ibc/04-channel/client/utils/types.go create mode 100644 x/ibc/04-channel/handler.go create mode 100644 x/ibc/04-channel/msgs.go diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index 52e1780ec237..8512182615a6 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -24,7 +24,7 @@ type CLIObject struct { Cdc *codec.Codec } -func (man Manager) CLIObject(path merkle.Path, chanid, connid, clientid string) CLIObject { +func (man Manager) CLIObject(ctx context.CLIContext, path merkle.Path, chanid, connid string) CLIObject { obj := man.object(connid, chanid) return CLIObject{ ChanID: chanid, @@ -37,7 +37,7 @@ func (man Manager) CLIObject(path merkle.Path, chanid, connid, clientid string) return obj.packets.Value(index).Key() }, - Connection: man.connection.CLIObject(path, connid, clientid), + Connection: man.connection.CLIObject(ctx, path, connid), Path: path, Cdc: obj.channel.Cdc(), @@ -85,10 +85,10 @@ type CLIHandshakeObject struct { TimeoutKey []byte } -func (man Handshaker) CLIObject(path merkle.Path, chanid, connid, clientid string) CLIHandshakeObject { +func (man Handshaker) CLIObject(ctx context.CLIContext, path merkle.Path, chanid, connid string) CLIHandshakeObject { obj := man.object(man.man.object(connid, chanid)) return CLIHandshakeObject{ - CLIObject: man.man.CLIObject(path, chanid, connid, clientid), + CLIObject: man.man.CLIObject(ctx, path, chanid, connid), StateKey: obj.state.Key(), TimeoutKey: obj.nextTimeout.Key(), diff --git a/x/ibc/04-channel/client/cli/query.go b/x/ibc/04-channel/client/cli/query.go new file mode 100644 index 000000000000..33cf4c7faa64 --- /dev/null +++ b/x/ibc/04-channel/client/cli/query.go @@ -0,0 +1,101 @@ +package cli + +import ( + "fmt" + "strconv" + + "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" + + "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/utils" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +const ( + FlagProve = "prove" +) + +func object(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, id string) channel.CLIObject { + prefix := []byte(strconv.FormatInt(version, 10) + "/") + path := merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) + base := state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) + climan := client.NewManager(base) + man := channel.NewManager(base, climan) + return man.CLIObject(ctx, path, id) +} + +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 +} + +func QueryChannel(ctx context.CLIContext, obj channel.CLIObject, prove bool) (res utils.JSONObject, err error) { + conn, connp, err := obj.Channel(ctx) + if err != nil { + return + } + avail, availp, err := obj.Available(ctx) + if err != nil { + return + } + kind, kindp, err := obj.Kind(ctx) + if err != nil { + return + } + + if prove { + return utils.NewJSONObject( + conn, connp, + avail, availp, + kind, kindp, + ), nil + } + + return utils.NewJSONObject( + conn, nil, + avail, nil, + kind, nil, + ), nil +} + +func GetCmdQueryChannel(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "connection", + Short: "Query stored connection", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCLIContext().WithCodec(cdc) + obj := object(ctx, cdc, storeKey, ibc.Version, args[0]) + jsonobj, err := QueryChannel(ctx, obj, viper.GetBool(FlagProve)) + if err != nil { + return err + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, jsonobj)) + + return nil + }, + } + + cmd.Flags().Bool(FlagProve, false, "(optional) show proofs for the query results") + + return cmd +} diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go new file mode 100644 index 000000000000..e29a402b2979 --- /dev/null +++ b/x/ibc/04-channel/client/cli/tx.go @@ -0,0 +1,221 @@ +package cli + +import ( + "io/ioutil" + "strconv" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "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" + + "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" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +/* +func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + +} +*/ +const ( + FlagNode1 = "node1" + FlagNode2 = "node2" + FlagFrom1 = "from1" + FlagFrom2 = "from2" +) + +func handshake(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, id string) connection.CLIHandshakeObject { + prefix := []byte(strconv.FormatInt(version, 10) + "/") + path := merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) + base := state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) + climan := client.NewManager(base) + man := connection.NewHandshaker(connection.NewManager(base, climan)) + return man.CLIObject(ctx, path, id) +} + +func lastheight(ctx context.CLIContext) (uint64, error) { + node, err := ctx.GetNode() + if err != nil { + return 0, err + } + + info, err := node.ABCIInfo() + if err != nil { + return 0, err + } + + return uint64(info.Response.LastBlockHeight), nil +} + +func GetCmdConnectionHandshake(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} + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + ctx1 := context.NewCLIContext(). + WithCodec(cdc). + WithNodeURI(viper.GetString(FlagNode1)). + WithFrom(viper.GetString(FlagFrom1)) + + ctx2 := context.NewCLIContext(). + WithCodec(cdc). + WithNodeURI(viper.GetString(FlagNode2)). + WithFrom(viper.GetString(FlagFrom2)) + + conn1id := args[0] + conn1bz, err := ioutil.ReadFile(args[1]) + if err != nil { + return err + } + var conn1 connection.Connection + if err := cdc.UnmarshalJSON(conn1bz, &conn1); err != nil { + return err + } + + obj1 := handshake(ctx1, cdc, storeKey, ibc.Version, conn1id) + + conn2id := args[2] + conn2bz, err := ioutil.ReadFile(args[3]) + if err != nil { + return err + } + var conn2 connection.Connection + if err := cdc.UnmarshalJSON(conn2bz, &conn2); err != nil { + return err + } + + obj2 := handshake(ctx2, cdc, storeKey, ibc.Version, conn1id) + + // 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, + Connection: conn1, + CounterpartyClient: conn2.Client, + NextTimeout: nextTimeout, + Signer: ctx1.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msginit}) + if err != nil { + return err + } + + timeout := nextTimeout + height, err = lastheight(ctx1) + if err != nil { + return err + } + nextTimeout = height + 1000 + _, pconn, err := obj1.Connection(ctx1) + if err != nil { + return err + } + _, pstate, err := obj1.State(ctx1) + if err != nil { + return err + } + _, ptimeout, err := obj1.NextTimeout(ctx1) + if err != nil { + return err + } + _, pcounter, err := obj1.CounterpartyClient(ctx1) + if err != nil { + return err + } + + msgtry := connection.MsgOpenTry{ + ConnectionID: conn2id, + Connection: conn2, + CounterpartyClient: conn1.Client, + Timeout: timeout, + NextTimeout: nextTimeout, + Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, + Signer: ctx2.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgtry}) + if err != nil { + return err + } + + timeout = nextTimeout + height, err = lastheight(ctx2) + if err != nil { + return err + } + nextTimeout = height + 1000 + _, pconn, err = obj2.Connection(ctx2) + if err != nil { + return err + } + _, pstate, err = obj2.State(ctx2) + if err != nil { + return err + } + _, ptimeout, err = obj2.NextTimeout(ctx2) + if err != nil { + return err + } + _, pcounter, err = obj2.CounterpartyClient(ctx2) + if err != nil { + return err + } + + msgack := connection.MsgOpenAck{ + ConnectionID: conn1id, + Timeout: timeout, + NextTimeout: nextTimeout, + Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, + Signer: ctx1.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgack}) + if err != nil { + return err + } + + timeout = nextTimeout + _, pstate, err = obj1.State(ctx1) + if err != nil { + return err + } + _, ptimeout, err = obj1.NextTimeout(ctx1) + if err != nil { + return err + } + + msgconfirm := connection.MsgOpenConfirm{ + ConnectionID: conn2id, + Timeout: timeout, + Proofs: []commitment.Proof{pstate, ptimeout}, + Signer: ctx2.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgconfirm}) + if err != nil { + return err + } + + return nil + }, + } + + return cmd +} diff --git a/x/ibc/04-channel/client/utils/types.go b/x/ibc/04-channel/client/utils/types.go new file mode 100644 index 000000000000..33480a68291f --- /dev/null +++ b/x/ibc/04-channel/client/utils/types.go @@ -0,0 +1,59 @@ +package utils + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +type JSONObject 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"` +} + +func NewJSONObject( + conn connection.Connection, connp commitment.Proof, + avail bool, availp commitment.Proof, + kind string, kindp commitment.Proof, +) JSONObject { + return JSONObject{ + Connection: conn, + ConnectionProof: connp, + Available: avail, + AvailableProof: availp, + Kind: kind, + KindProof: kindp, + } +} + +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( + 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), + State: state, + StateProof: statep, + CounterpartyClient: cpclient, + CounterpartyClientProof: cpclientp, + NextTimeout: timeout, + NextTimeoutProof: timeoutp, + } +} diff --git a/x/ibc/04-channel/handler.go b/x/ibc/04-channel/handler.go new file mode 100644 index 000000000000..76d9ace3e6e4 --- /dev/null +++ b/x/ibc/04-channel/handler.go @@ -0,0 +1,37 @@ +package channel + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func HandleMsgOpenInit(ctx sdk.Context, msg MsgOpenInit, man Handshaker) sdk.Result { + _, err := man.OpenInit(ctx, msg.ConnectionID, msg.ChannelID, msg.Channel, msg.NextTimeout) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), 100, "").Result() + } + return sdk.Result{} +} + +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) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), 200, "").Result() + } + return sdk.Result{} +} + +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) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), 300, "").Result() + } + return sdk.Result{} +} + +func HandleMsgOpenConfirm(ctx sdk.Context, msg MsgOpenConfirm, man Handshaker) sdk.Result { + _, err := man.OpenConfirm(ctx, msg.Proofs, msg.ConnectionID, msg.ChannelID, msg.Timeout) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), 400, "").Result() + } + return sdk.Result{} +} diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index 2889aa8183fc..96ceefe1cef9 100644 --- a/x/ibc/04-channel/handshake.go +++ b/x/ibc/04-channel/handshake.go @@ -161,7 +161,7 @@ func (man Handshaker) OpenInit(ctx sdk.Context, // Using proofs: counterparty.{channel,state,nextTimeout} func (man Handshaker) OpenTry(ctx sdk.Context, - pchannel, pstate, ptimeout commitment.Proof, + proofs []commitment.Proof, connid, chanid string, channel Channel, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { obj, err = man.create(ctx, connid, chanid, channel) @@ -169,7 +169,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - ctx, err = obj.Context(ctx, pchannel, pstate, ptimeout) + ctx, err = obj.Context(ctx, proofs) if err != nil { return } @@ -222,7 +222,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} func (man Handshaker) OpenAck(ctx sdk.Context, - pchannel, pstate, ptimeout commitment.Proof, + proofs []commitment.Proof, connid, chanid string, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { obj, err = man.query(ctx, connid, chanid) @@ -230,7 +230,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - ctx, err = obj.Context(ctx, pchannel, pstate, ptimeout) + ctx, err = obj.Context(ctx, proofs) if err != nil { return } @@ -282,14 +282,14 @@ func (man Handshaker) OpenAck(ctx sdk.Context, // Using proofs: counterparty.{connection,state, nextTimeout} func (man Handshaker) OpenConfirm(ctx sdk.Context, - pstate, ptimeout commitment.Proof, + proofs []commitment.Proof, connid, chanid string, timeoutHeight uint64) (obj HandshakeObject, err error) { obj, err = man.query(ctx, connid, chanid) if err != nil { return } - ctx, err = obj.Context(ctx, pstate, ptimeout) + ctx, err = obj.Context(ctx, proofs) if err != nil { return } diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index fe095ec8dfe4..3163d3c50455 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -200,8 +200,8 @@ type CounterObject struct { connection connection.CounterObject } -func (obj Object) Context(ctx sdk.Context, proofs ...commitment.Proof) (sdk.Context, error) { - return obj.connection.Context(ctx, nil, proofs...) +func (obj Object) Context(ctx sdk.Context, proofs []commitment.Proof) (sdk.Context, error) { + return obj.connection.Context(ctx, nil, proofs) } func (obj Object) ChanID() string { @@ -261,12 +261,12 @@ func (obj Object) Send(ctx sdk.Context, packet Packet) error { return nil } -func (obj Object) Receive(ctx sdk.Context, ppacket commitment.Proof, packet Packet) error { +func (obj Object) Receive(ctx sdk.Context, proofs []commitment.Proof, packet Packet) error { if !obj.Receivable(ctx) { return errors.New("cannot receive packets on this channel") } - ctx, err := obj.Context(ctx, ppacket) + ctx, err := obj.Context(ctx, proofs) if err != nil { return err } diff --git a/x/ibc/04-channel/msgs.go b/x/ibc/04-channel/msgs.go new file mode 100644 index 000000000000..b62d3a16bdf5 --- /dev/null +++ b/x/ibc/04-channel/msgs.go @@ -0,0 +1,132 @@ +package channel + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +type MsgOpenInit struct { + ConnectionID string + ChannelID string + Channel Channel + CounterpartyClient string + NextTimeout uint64 + Signer sdk.AccAddress +} + +var _ sdk.Msg = MsgOpenInit{} + +func (msg MsgOpenInit) Route() string { + return "ibc" +} + +func (msg MsgOpenInit) Type() string { + return "open-init" +} + +func (msg MsgOpenInit) ValidateBasic() sdk.Error { + return nil // TODO +} + +func (msg MsgOpenInit) GetSignBytes() []byte { + return nil // TODO +} + +func (msg MsgOpenInit) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +type MsgOpenTry struct { + ConnectionID string + ChannelID string + Channel Channel + CounterpartyClient string + Timeout uint64 + NextTimeout uint64 + Proofs []commitment.Proof + Signer sdk.AccAddress +} + +var _ sdk.Msg = MsgOpenTry{} + +func (msg MsgOpenTry) Route() string { + return "ibc" +} + +func (msg MsgOpenTry) Type() string { + return "open-init" +} + +func (msg MsgOpenTry) ValidateBasic() sdk.Error { + return nil // TODO +} + +func (msg MsgOpenTry) GetSignBytes() []byte { + return nil // TODO +} + +func (msg MsgOpenTry) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +type MsgOpenAck struct { + ConnectionID string + ChannelID string + Timeout uint64 + NextTimeout uint64 + Proofs []commitment.Proof + Signer sdk.AccAddress +} + +var _ sdk.Msg = MsgOpenAck{} + +func (msg MsgOpenAck) Route() string { + return "ibc" +} + +func (msg MsgOpenAck) Type() string { + return "open-init" +} + +func (msg MsgOpenAck) ValidateBasic() sdk.Error { + return nil // TODO +} + +func (msg MsgOpenAck) GetSignBytes() []byte { + return nil // TODO +} + +func (msg MsgOpenAck) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +type MsgOpenConfirm struct { + ConnectionID string + ChannelID string + Timeout uint64 + Proofs []commitment.Proof + Signer sdk.AccAddress +} + +var _ sdk.Msg = MsgOpenConfirm{} + +func (msg MsgOpenConfirm) Route() string { + return "ibc" +} + +func (msg MsgOpenConfirm) Type() string { + return "open-init" +} + +func (msg MsgOpenConfirm) ValidateBasic() sdk.Error { + return nil // TODO +} + +func (msg MsgOpenConfirm) GetSignBytes() []byte { + return nil // TODO +} + +func (msg MsgOpenConfirm) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} From 2ae06c4d6972e799228858a849ef0a256ea0bc88 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 18 Jul 2019 15:33:38 +0900 Subject: [PATCH 191/378] add client query/tx --- x/ibc/04-channel/cli.go | 37 ++++++++++-- x/ibc/04-channel/client/cli/query.go | 32 ++++++++--- x/ibc/04-channel/client/cli/tx.go | 79 +++++++++++++------------- x/ibc/04-channel/client/utils/types.go | 58 ++++++++++--------- x/ibc/04-channel/tests/types.go | 8 +-- 5 files changed, 129 insertions(+), 85 deletions(-) diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index 8512182615a6..f3d165ac7d4a 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -24,7 +24,7 @@ type CLIObject struct { Cdc *codec.Codec } -func (man Manager) CLIObject(ctx context.CLIContext, path merkle.Path, chanid, connid string) CLIObject { +func (man Manager) cliObject(path merkle.Path, chanid, connid string) CLIObject { obj := man.object(connid, chanid) return CLIObject{ ChanID: chanid, @@ -37,13 +37,23 @@ func (man Manager) CLIObject(ctx context.CLIContext, path merkle.Path, chanid, c return obj.packets.Value(index).Key() }, - Connection: man.connection.CLIObject(ctx, path, connid), - Path: path, Cdc: obj.channel.Cdc(), } } +func (man Manager) CLIQuery(ctx context.CLIContext, path merkle.Path, chanid, connid string) CLIObject { + obj := man.cliObject(path, chanid, connid) + obj.Connection = man.connection.CLIQuery(ctx, path, connid) + return obj +} + +func (man Manager) CLIObject(path merkle.Path, chanid, connid, clientid string) CLIObject { + obj := man.cliObject(path, chanid, connid) + obj.Connection = man.connection.CLIObject(path, connid, clientid) + return obj +} + func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { resp, err := ctx.QueryABCI(obj.Path.RequestQuery(key)) if err != nil { @@ -63,6 +73,11 @@ func (obj CLIObject) Channel(ctx context.CLIContext) (res Channel, proof merkle. return } +func (obj CLIObject) Available(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { + proof, err = obj.query(ctx, obj.AvailableKey, &res) + return +} + func (obj CLIObject) SeqSend(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.SeqSendKey, &res) return @@ -85,10 +100,20 @@ type CLIHandshakeObject struct { TimeoutKey []byte } -func (man Handshaker) CLIObject(ctx context.CLIContext, path merkle.Path, chanid, connid string) CLIHandshakeObject { +func (man Handshaker) CLIQuery(ctx context.CLIContext, path merkle.Path, chanid, connid string) CLIHandshakeObject { + obj := man.object(man.man.object(connid, chanid)) + return CLIHandshakeObject{ + CLIObject: man.man.CLIQuery(ctx, path, chanid, connid), + + StateKey: obj.state.Key(), + TimeoutKey: obj.nextTimeout.Key(), + } +} + +func (man Handshaker) CLIObject(path merkle.Path, chanid, connid, clientid string) CLIHandshakeObject { obj := man.object(man.man.object(connid, chanid)) return CLIHandshakeObject{ - CLIObject: man.man.CLIObject(ctx, path, chanid, connid), + CLIObject: man.man.CLIObject(path, chanid, connid, clientid), StateKey: obj.state.Key(), TimeoutKey: obj.nextTimeout.Key(), @@ -100,7 +125,7 @@ func (obj CLIHandshakeObject) State(ctx context.CLIContext) (res State, proof me return } -func (obj CLIHandshakeObject) Timeout(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { +func (obj CLIHandshakeObject) NextTimeout(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.TimeoutKey, &res) return } diff --git a/x/ibc/04-channel/client/cli/query.go b/x/ibc/04-channel/client/cli/query.go index 33cf4c7faa64..6f11957f7ab3 100644 --- a/x/ibc/04-channel/client/cli/query.go +++ b/x/ibc/04-channel/client/cli/query.go @@ -15,8 +15,9 @@ import ( "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/utils" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" "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/23-commitment/merkle" ) @@ -24,13 +25,14 @@ const ( FlagProve = "prove" ) -func object(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, id string) channel.CLIObject { +func object(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, connid, chanid string) channel.CLIObject { prefix := []byte(strconv.FormatInt(version, 10) + "/") path := merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) base := state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) climan := client.NewManager(base) - man := channel.NewManager(base, climan) - return man.CLIObject(ctx, path, id) + connman := connection.NewManager(base, climan) + man := channel.NewManager(base, connman) + return man.CLIQuery(ctx, path, connid, chanid) } func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { @@ -56,7 +58,18 @@ func QueryChannel(ctx context.CLIContext, obj channel.CLIObject, prove bool) (re if err != nil { return } - kind, kindp, err := obj.Kind(ctx) + /* + kind, kindp, err := obj.Kind(ctx) + if err != nil { + return + } + */ + seqsend, seqsendp, err := obj.SeqSend(ctx) + if err != nil { + return + } + + seqrecv, seqrecvp, err := obj.SeqRecv(ctx) if err != nil { return } @@ -65,14 +78,17 @@ func QueryChannel(ctx context.CLIContext, obj channel.CLIObject, prove bool) (re return utils.NewJSONObject( conn, connp, avail, availp, - kind, kindp, + // kind, kindp, + seqsend, seqsendp, + seqrecv, seqrecvp, ), nil } return utils.NewJSONObject( conn, nil, avail, nil, - kind, nil, + seqsend, nil, + seqrecv, nil, ), nil } @@ -83,7 +99,7 @@ func GetCmdQueryChannel(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(ctx, cdc, storeKey, ibc.Version, args[0]) + obj := object(ctx, cdc, storeKey, ibc.Version, args[0], args[1]) jsonobj, err := QueryChannel(ctx, obj, viper.GetBool(FlagProve)) if err != nil { return err diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index e29a402b2979..bad1375a08b8 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -17,6 +17,7 @@ import ( "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/04-channel" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) @@ -33,13 +34,14 @@ const ( FlagFrom2 = "from2" ) -func handshake(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, id string) connection.CLIHandshakeObject { +func handshake(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, connid, chanid string) channel.CLIHandshakeObject { prefix := []byte(strconv.FormatInt(version, 10) + "/") path := merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) base := state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) climan := client.NewManager(base) - man := connection.NewHandshaker(connection.NewManager(base, climan)) - return man.CLIObject(ctx, path, id) + connman := connection.NewManager(base, climan) + man := channel.NewHandshaker(channel.NewManager(base, connman)) + return man.CLIQuery(ctx, path, connid, chanid) } func lastheight(ctx context.CLIContext) (uint64, error) { @@ -56,12 +58,12 @@ func lastheight(ctx context.CLIContext) (uint64, error) { return uint64(info.Response.LastBlockHeight), nil } -func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { +func GetCmdChannelHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "handshake", - Short: "initiate connection handshake between two chains", + Short: "initiate channel handshake between two chains", Args: cobra.ExactArgs(4), - // Args: []string{connid1, connfilepath1, connid2, connfilepath2} + // Args: []string{connid1, chanid1, chanfilepath1, connid2, chanid2, chanfilepath2} RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) ctx1 := context.NewCLIContext(). @@ -75,28 +77,30 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command WithFrom(viper.GetString(FlagFrom2)) conn1id := args[0] - conn1bz, err := ioutil.ReadFile(args[1]) + chan1id := args[1] + conn1bz, err := ioutil.ReadFile(args[2]) if err != nil { return err } - var conn1 connection.Connection + var conn1 channel.Channel if err := cdc.UnmarshalJSON(conn1bz, &conn1); err != nil { return err } - obj1 := handshake(ctx1, cdc, storeKey, ibc.Version, conn1id) + obj1 := handshake(ctx1, cdc, storeKey, ibc.Version, conn1id, chan1id) - conn2id := args[2] - conn2bz, err := ioutil.ReadFile(args[3]) + conn2id := args[3] + chan2id := args[4] + conn2bz, err := ioutil.ReadFile(args[5]) if err != nil { return err } - var conn2 connection.Connection + var conn2 channel.Channel if err := cdc.UnmarshalJSON(conn2bz, &conn2); err != nil { return err } - obj2 := handshake(ctx2, cdc, storeKey, ibc.Version, conn1id) + obj2 := handshake(ctx2, cdc, storeKey, ibc.Version, conn1id, chan1id) // TODO: check state and if not Idle continue existing process height, err := lastheight(ctx2) @@ -104,12 +108,12 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } nextTimeout := height + 1000 // TODO: parameterize - msginit := connection.MsgOpenInit{ - ConnectionID: conn1id, - Connection: conn1, - CounterpartyClient: conn2.Client, - NextTimeout: nextTimeout, - Signer: ctx1.GetFromAddress(), + msginit := channel.MsgOpenInit{ + ConnectionID: conn1id, + ChannelID: chan1id, + Channel: conn1, + NextTimeout: nextTimeout, + Signer: ctx1.GetFromAddress(), } err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msginit}) @@ -123,7 +127,7 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } nextTimeout = height + 1000 - _, pconn, err := obj1.Connection(ctx1) + _, pconn, err := obj1.Channel(ctx1) if err != nil { return err } @@ -135,19 +139,15 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command if err != nil { return err } - _, pcounter, err := obj1.CounterpartyClient(ctx1) - if err != nil { - return err - } - msgtry := connection.MsgOpenTry{ - ConnectionID: conn2id, - Connection: conn2, - CounterpartyClient: conn1.Client, - Timeout: timeout, - NextTimeout: nextTimeout, - Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, - Signer: ctx2.GetFromAddress(), + msgtry := channel.MsgOpenTry{ + ConnectionID: conn2id, + ChannelID: chan2id, + Channel: conn2, + Timeout: timeout, + NextTimeout: nextTimeout, + Proofs: []commitment.Proof{pconn, pstate, ptimeout}, + Signer: ctx2.GetFromAddress(), } err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgtry}) @@ -161,7 +161,7 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } nextTimeout = height + 1000 - _, pconn, err = obj2.Connection(ctx2) + _, pconn, err = obj2.Channel(ctx2) if err != nil { return err } @@ -173,16 +173,12 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command if err != nil { return err } - _, pcounter, err = obj2.CounterpartyClient(ctx2) - if err != nil { - return err - } - msgack := connection.MsgOpenAck{ + msgack := channel.MsgOpenAck{ ConnectionID: conn1id, + ChannelID: chan1id, Timeout: timeout, - NextTimeout: nextTimeout, - Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, + Proofs: []commitment.Proof{pconn, pstate, ptimeout}, Signer: ctx1.GetFromAddress(), } @@ -201,8 +197,9 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } - msgconfirm := connection.MsgOpenConfirm{ + msgconfirm := channel.MsgOpenConfirm{ ConnectionID: conn2id, + ChannelID: chan2id, Timeout: timeout, Proofs: []commitment.Proof{pstate, ptimeout}, Signer: ctx2.GetFromAddress(), diff --git a/x/ibc/04-channel/client/utils/types.go b/x/ibc/04-channel/client/utils/types.go index 33480a68291f..4006e7bacebb 100644 --- a/x/ibc/04-channel/client/utils/types.go +++ b/x/ibc/04-channel/client/utils/types.go @@ -1,36 +1,42 @@ package utils import ( - "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) type JSONObject 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"` + Channel channel.Channel `json:"channel"` + ChannelProof commitment.Proof `json:"channel_proof,omitempty"` + Available bool `json:"available"` + AvailableProof commitment.Proof `json:"available_proof,omitempty"` + SequenceSend uint64 `json:"sequence_send"` + SequenceSendProof commitment.Proof `json:"sequence_send_proof,omitempty"` + SequenceReceive uint64 `json:"sequence_receive"` + SequenceReceiveProof commitment.Proof `json:"sequence_receive_proof,omitempty"` + // Kind string `json:"kind"` + // KindProof commitment.Proof `json:"kind_proof,omitempty"` } func NewJSONObject( - conn connection.Connection, connp commitment.Proof, + channel channel.Channel, channelp commitment.Proof, avail bool, availp commitment.Proof, - kind string, kindp commitment.Proof, + // kind string, kindp commitment.Proof, + seqsend uint64, seqsendp commitment.Proof, + seqrecv uint64, seqrecvp commitment.Proof, ) JSONObject { return JSONObject{ - Connection: conn, - ConnectionProof: connp, - Available: avail, - AvailableProof: availp, - Kind: kind, - KindProof: kindp, + Channel: channel, + ChannelProof: channelp, + Available: avail, + AvailableProof: availp, + // Kind: kind, + // KindProof: kindp, } } type HandshakeJSONObject struct { - JSONObject `json:"connection"` + JSONObject `json:"channel"` State byte `json:"state"` StateProof commitment.Proof `json:"state_proof,omitempty"` CounterpartyClient string `json:"counterparty_client"` @@ -40,20 +46,20 @@ type HandshakeJSONObject struct { } func NewHandshakeJSONObject( - conn connection.Connection, connp commitment.Proof, + channel channel.Channel, channelp commitment.Proof, avail bool, availp commitment.Proof, - kind string, kindp commitment.Proof, + // kind string, kindp commitment.Proof, + seqsend uint64, seqsendp commitment.Proof, + seqrecv uint64, seqrecvp 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), - State: state, - StateProof: statep, - CounterpartyClient: cpclient, - CounterpartyClientProof: cpclientp, - NextTimeout: timeout, - NextTimeoutProof: timeoutp, + JSONObject: NewJSONObject(channel, channelp, avail, availp, seqsend, seqsendp, seqrecv, seqrecvp), + State: state, + StateProof: statep, + NextTimeout: timeout, + NextTimeoutProof: timeoutp, } } diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index 80f94e7e248c..fae2418d4ee3 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -90,7 +90,7 @@ func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenTry(ctx, proofs[0], proofs[1], proofs[2], node.Name, node.Name, node.Channel, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenTry(ctx, proofs, node.Name, node.Name, node.Channel, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, channel.OpenTry, obj.State(ctx)) require.Equal(t, node.Channel, obj.Channel(ctx)) @@ -100,7 +100,7 @@ func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenAck(ctx, proofs[0], proofs[1], proofs[2], node.Name, node.Name, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenAck(ctx, proofs, node.Name, node.Name, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, channel.Open, obj.State(ctx)) require.Equal(t, node.Channel, obj.Channel(ctx)) @@ -110,7 +110,7 @@ func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenConfirm(ctx, proofs[0], proofs[1], node.Name, node.Name, 100 /*TODO*/) + obj, err := man.OpenConfirm(ctx, proofs, node.Name, node.Name, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, channel.Open, obj.State(ctx)) require.Equal(t, node.Channel, obj.Channel(ctx)) @@ -167,7 +167,7 @@ func (node *Node) Receive(t *testing.T, packet channel.Packet, proofs ...commitm obj, err := man.Query(ctx, node.Name, node.Name) require.NoError(t, err) seq := obj.SeqRecv(ctx) - err = obj.Receive(ctx, proofs[0], packet) + err = obj.Receive(ctx, proofs, packet) require.NoError(t, err) require.Equal(t, seq+1, obj.SeqRecv(ctx)) } From 7ecd36016199acdfe16f96e2f620e7b9b03eb36f Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 19 Jul 2019 00:56:10 +0900 Subject: [PATCH 192/378] fix golangci --- x/ibc/04-channel/msgs.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/x/ibc/04-channel/msgs.go b/x/ibc/04-channel/msgs.go index b62d3a16bdf5..9e4d5fe987a5 100644 --- a/x/ibc/04-channel/msgs.go +++ b/x/ibc/04-channel/msgs.go @@ -6,6 +6,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) +const Route = "ibc" + type MsgOpenInit struct { ConnectionID string ChannelID string @@ -18,7 +20,7 @@ type MsgOpenInit struct { var _ sdk.Msg = MsgOpenInit{} func (msg MsgOpenInit) Route() string { - return "ibc" + return Route } func (msg MsgOpenInit) Type() string { @@ -51,11 +53,11 @@ type MsgOpenTry struct { var _ sdk.Msg = MsgOpenTry{} func (msg MsgOpenTry) Route() string { - return "ibc" + return Route } func (msg MsgOpenTry) Type() string { - return "open-init" + return "open-try" } func (msg MsgOpenTry) ValidateBasic() sdk.Error { @@ -82,11 +84,11 @@ type MsgOpenAck struct { var _ sdk.Msg = MsgOpenAck{} func (msg MsgOpenAck) Route() string { - return "ibc" + return Route } func (msg MsgOpenAck) Type() string { - return "open-init" + return "open-ack" } func (msg MsgOpenAck) ValidateBasic() sdk.Error { @@ -112,11 +114,11 @@ type MsgOpenConfirm struct { var _ sdk.Msg = MsgOpenConfirm{} func (msg MsgOpenConfirm) Route() string { - return "ibc" + return Route } func (msg MsgOpenConfirm) Type() string { - return "open-init" + return "open-confirm" } func (msg MsgOpenConfirm) ValidateBasic() sdk.Error { From 33d1760d5bab61a072f448594e7d2ddf6e98580b Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 19 Jul 2019 02:57:50 +0900 Subject: [PATCH 193/378] add MsgReceive --- x/ibc/04-channel/client/cli/tx.go | 51 ++++++++++++++++++++++++++ x/ibc/04-channel/handler.go | 11 ++++++ x/ibc/04-channel/manager.go | 16 ++++++-- x/ibc/04-channel/msgs.go | 30 +++++++++++++++ x/ibc/04-channel/router.go | 34 +++++++++++++++++ x/ibc/04-channel/tests/channel_test.go | 7 +++- x/ibc/04-channel/tests/types.go | 4 +- x/ibc/04-channel/types.go | 3 +- 8 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 x/ibc/04-channel/router.go diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index bad1375a08b8..4b314f523866 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -216,3 +216,54 @@ func GetCmdChannelHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return cmd } + +func GetCmdRelay(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} + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + ctx1 := context.NewCLIContext(). + WithCodec(cdc). + WithNodeURI(viper.GetString(FlagNode1)). + WithFrom(viper.GetString(FlagFrom1)) + + ctx2 := context.NewCLIContext(). + WithCodec(cdc). + WithNodeURI(viper.GetString(FlagNode2)). + WithFrom(viper.GetString(FlagFrom2)) + + conn1id, chan1id, conn2id, chan2id := args[0], args[1], args[2], args[3] + + obj1 := object(ctx1, cdc, storeKey, ibc.Version, conn1id, chan1id) + obj2 := object(ctx2, cdc, storeKey, ibc.Version, conn2id, chan2id) + }, + } + + return cmd +} + +func relay(ctxFrom, ctxTo context.CLIContext, objFrom, objTo channel.Object) error { + seq, _, err := objTo.SeqRecv(ctxTo) + if err != nil { + return err + } + + sent, _, err := objFrom.SeqSend(ctxFrom) + if err != nil { + return err + } + + if seq == sent { + return nil + } + + packet, proof, err := query(ctxFrom, objFrom.Packet(seq)) + if err != nil { + return err + } + + msg := channel.MsgReceive{} +} diff --git a/x/ibc/04-channel/handler.go b/x/ibc/04-channel/handler.go index 76d9ace3e6e4..02c2c334fb45 100644 --- a/x/ibc/04-channel/handler.go +++ b/x/ibc/04-channel/handler.go @@ -35,3 +35,14 @@ func HandleMsgOpenConfirm(ctx sdk.Context, msg MsgOpenConfirm, man Handshaker) s } 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/manager.go b/x/ibc/04-channel/manager.go index 3163d3c50455..f21115e3006c 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -18,6 +18,8 @@ type Manager struct { connection connection.Manager counterparty CounterpartyManager + + router Router } type CounterpartyManager struct { @@ -256,17 +258,22 @@ func (obj Object) Send(ctx sdk.Context, packet Packet) error { return errors.New("timeout height higher than the latest known") } - obj.packets.SetRaw(ctx, obj.seqsend.Incr(ctx), packet.Commit()) + obj.packets.Set(ctx, obj.seqsend.Incr(ctx), packet) return nil } -func (obj Object) Receive(ctx sdk.Context, proofs []commitment.Proof, packet Packet) error { +func (man Manager) Receive(ctx sdk.Context, proofs []commitment.Proof, connid, chanid string, packet Packet) error { + obj, err := man.Query(ctx, connid, chanid) + if err != nil { + return err + } + if !obj.Receivable(ctx) { return errors.New("cannot receive packets on this channel") } - ctx, err := obj.Context(ctx, proofs) + ctx, err = obj.Context(ctx, proofs) if err != nil { return err } @@ -277,7 +284,8 @@ func (obj Object) Receive(ctx sdk.Context, proofs []commitment.Proof, packet Pac } // XXX: increment should happen before verification, reflect on the spec - if !obj.counterparty.packets.Value(obj.seqrecv.Incr(ctx)).IsRaw(ctx, packet.Commit()) { + // TODO: packet should be custom marshalled + if !obj.counterparty.packets.Value(obj.seqrecv.Incr(ctx)).Is(ctx, packet) { return errors.New("verification failed") } diff --git a/x/ibc/04-channel/msgs.go b/x/ibc/04-channel/msgs.go index 9e4d5fe987a5..ba35f0bbc406 100644 --- a/x/ibc/04-channel/msgs.go +++ b/x/ibc/04-channel/msgs.go @@ -132,3 +132,33 @@ func (msg MsgOpenConfirm) GetSignBytes() []byte { 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 +} + +var _ sdk.Msg = MsgReceive{} + +func (msg MsgReceive) Route() string { + return Route +} + +func (msg MsgReceive) Type() string { + return "receive" +} + +func (msg MsgReceive) ValidateBasic() sdk.Error { + return nil // TODO +} + +func (msg MsgReceive) GetSignBytes() []byte { + return nil // TODO +} + +func (msg MsgReceive) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} diff --git a/x/ibc/04-channel/router.go b/x/ibc/04-channel/router.go new file mode 100644 index 000000000000..40c2c180fb31 --- /dev/null +++ b/x/ibc/04-channel/router.go @@ -0,0 +1,34 @@ +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 db2aac451268..6463d6db0c2d 100644 --- a/x/ibc/04-channel/tests/channel_test.go +++ b/x/ibc/04-channel/tests/channel_test.go @@ -36,14 +36,19 @@ 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 TestPacket(t *testing.T) { cdc := codec.New() registerCodec(cdc) diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index fae2418d4ee3..daa17e526bb3 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -159,7 +159,7 @@ func (node *Node) Send(t *testing.T, packet channel.Packet) { err = obj.Send(ctx, packet) require.NoError(t, err) require.Equal(t, seq+1, obj.SeqSend(ctx)) - require.Equal(t, packet.Commit(), obj.PacketCommit(ctx, seq+1)) + 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) { @@ -167,7 +167,7 @@ func (node *Node) Receive(t *testing.T, packet channel.Packet, proofs ...commitm obj, err := man.Query(ctx, node.Name, node.Name) require.NoError(t, err) seq := obj.SeqRecv(ctx) - err = obj.Receive(ctx, proofs, packet) + err = man.Receive(ctx, proofs, node.Name, node.Name, packet) require.NoError(t, err) require.Equal(t, seq+1, obj.SeqRecv(ctx)) } diff --git a/x/ibc/04-channel/types.go b/x/ibc/04-channel/types.go index 11c73fe834d4..891bea6f9985 100644 --- a/x/ibc/04-channel/types.go +++ b/x/ibc/04-channel/types.go @@ -16,7 +16,8 @@ type Packet struct { type Packet interface { Timeout() uint64 - Commit() []byte // Can be a commit message + // Commit() []byte // Can be a commit message + Route() string } type Channel struct { From bf762ba4dfe6d0684c2e53baf0883c115bc879bf Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 19 Jul 2019 13:43:42 +0900 Subject: [PATCH 194/378] fix relayer cli --- x/ibc/04-channel/cli.go | 2 +- x/ibc/04-channel/client/cli/tx.go | 51 +++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index f3d165ac7d4a..ffb0aeaa3f9e 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -88,7 +88,7 @@ func (obj CLIObject) SeqRecv(ctx context.CLIContext) (res uint64, proof merkle.P return } -func (obj CLIObject) PacketCommit(ctx context.CLIContext, index uint64) (res Packet, proof merkle.Proof, err error) { +func (obj CLIObject) Packet(ctx context.CLIContext, index uint64) (res Packet, proof merkle.Proof, err error) { proof, err = obj.query(ctx, obj.PacketCommitKey(index), &res) return } diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index 4b314f523866..7f67c9902cb2 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -3,6 +3,7 @@ package cli import ( "io/ioutil" "strconv" + "time" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -224,7 +225,6 @@ func GetCmdRelay(storeKey string, cdc *codec.Codec) *cobra.Command { Args: cobra.ExactArgs(4), // Args: []string{connid1, chanid1, chanfilepath1, connid2, chanid2, chanfilepath2} RunE: func(cmd *cobra.Command, args []string) error { - txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) ctx1 := context.NewCLIContext(). WithCodec(cdc). WithNodeURI(viper.GetString(FlagNode1)). @@ -239,13 +239,33 @@ func GetCmdRelay(storeKey string, cdc *codec.Codec) *cobra.Command { obj1 := object(ctx1, cdc, storeKey, ibc.Version, conn1id, chan1id) obj2 := object(ctx2, cdc, storeKey, ibc.Version, conn2id, chan2id) + + return relayLoop(cdc, ctx1, ctx2, obj1, obj2, conn1id, chan1id, conn2id, chan2id) }, } return cmd } -func relay(ctxFrom, ctxTo context.CLIContext, objFrom, objTo channel.Object) error { +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) + } +} + +func relay(cdc *codec.Codec, ctxFrom, ctxTo context.CLIContext, objFrom, objTo channel.CLIObject, connidTo, chanidTo string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + seq, _, err := objTo.SeqRecv(ctxTo) if err != nil { return err @@ -256,14 +276,25 @@ func relay(ctxFrom, ctxTo context.CLIContext, objFrom, objTo channel.Object) err return err } - if seq == sent { - return nil - } - - packet, proof, err := query(ctxFrom, objFrom.Packet(seq)) - if err != nil { - return err + 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 + } } - msg := channel.MsgReceive{} + return nil } From 1061a7888faafe37ce01806a7868e8e7cedd40a2 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 15 Aug 2019 20:12:00 +0900 Subject: [PATCH 195/378] finalize rebase, fix test --- store/state/indexer.go | 5 +- store/state/mapping_test.go | 2 +- x/ibc/03-connection/cli.go | 2 - x/ibc/04-channel/cli.go | 133 ++++++---------- x/ibc/04-channel/handshake.go | 148 +++++++++--------- x/ibc/04-channel/keys.go | 5 + x/ibc/04-channel/manager.go | 205 +++++++++++++------------ x/ibc/04-channel/tests/channel_test.go | 10 +- x/ibc/04-channel/tests/types.go | 78 +++++----- x/ibc/04-channel/types.go | 9 ++ x/ibc/23-commitment/store.go | 4 +- x/ibc/23-commitment/value.go | 3 +- 12 files changed, 286 insertions(+), 318 deletions(-) create mode 100644 x/ibc/04-channel/keys.go diff --git a/store/state/indexer.go b/store/state/indexer.go index 666d31b45667..c948937306da 100644 --- a/store/state/indexer.go +++ b/store/state/indexer.go @@ -31,8 +31,9 @@ type Indexer struct { enc IntEncoding } -// NewIndexer() constructs the Indexer with a predetermined prefix and IntEncoding -func NewIndexer(m Mapping, enc IntEncoding) Indexer { + +// Indexer() constructs the Indexer with an IntEncoding +func (m Mapping) Indexer(enc IntEncoding) Indexer { return Indexer{ m: m, enc: enc, diff --git a/store/state/mapping_test.go b/store/state/mapping_test.go index 0a29fead8a6e..2f44b9fcccc2 100644 --- a/store/state/mapping_test.go +++ b/store/state/mapping_test.go @@ -60,7 +60,7 @@ type indexerT struct { var _ mapping = indexerT{} func newIndexer(enc IntEncoding) indexerT { - return indexerT{NewIndexer(NewMapping(testkey, testcdc, nil), enc)} + return indexerT{NewMapping(testkey, testcdc, nil).Indexer(enc)} } func (m indexerT) Get(ctx Context, key interface{}, ptr interface{}) { diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index 769792c16358..2a6c65d7c824 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -14,8 +14,6 @@ func (man Manager) CLIObject(connid, clientid string) Object { return obj } - - func (obj Object) prefix() []byte { return bytes.Split(obj.Connection.KeyBytes(), LocalRoot())[0] } diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index ffb0aeaa3f9e..acfbb9bd8d0f 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -1,131 +1,88 @@ package channel import ( + "bytes" + "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -// CLIObject stores the key for each object fields -type CLIObject struct { - ChanID string - ChannelKey []byte - - AvailableKey []byte - SeqSendKey []byte - SeqRecvKey []byte - PacketCommitKey func(index uint64) []byte - - Connection connection.CLIObject - - Path merkle.Path - Cdc *codec.Codec -} - -func (man Manager) cliObject(path merkle.Path, chanid, connid string) CLIObject { - obj := man.object(connid, chanid) - return CLIObject{ - ChanID: chanid, - ChannelKey: obj.channel.Key(), - - AvailableKey: obj.available.Key(), - SeqSendKey: obj.seqsend.Key(), - SeqRecvKey: obj.seqrecv.Key(), - PacketCommitKey: func(index uint64) []byte { - return obj.packets.Value(index).Key() - }, - - Path: path, - Cdc: obj.channel.Cdc(), +func (man Manager) CLIObject(portid, chanid string, connids []string) Object { + obj := man.object(portid, chanid) + for _, connid := range connids { + obj.Connections = append(obj.Connections, man.connection.Object(connid)) } -} - -func (man Manager) CLIQuery(ctx context.CLIContext, path merkle.Path, chanid, connid string) CLIObject { - obj := man.cliObject(path, chanid, connid) - obj.Connection = man.connection.CLIQuery(ctx, path, connid) - return obj -} - -func (man Manager) CLIObject(path merkle.Path, chanid, connid, clientid string) CLIObject { - obj := man.cliObject(path, chanid, connid) - obj.Connection = man.connection.CLIObject(path, connid, clientid) return obj } -func (obj CLIObject) query(ctx context.CLIContext, key []byte, ptr interface{}) (merkle.Proof, error) { - resp, err := ctx.QueryABCI(obj.Path.RequestQuery(key)) +func (man Manager) CLIQuery(ctx context.CLIContext, portid, chanid string) (obj Object, err error) { + obj = man.object(portid, chanid) + channel, _, err := obj.ChannelCLI(ctx) if err != nil { - return merkle.Proof{}, err + return } - proof := merkle.Proof{ - Key: key, - Proof: resp.Proof, + for _, connid := range channel.ConnectionHops { + obj.Connections = append(obj.Connections, man.connection.Object(connid)) } - err = obj.Cdc.UnmarshalBinaryBare(resp.Value, ptr) - return proof, err - + return } -func (obj CLIObject) Channel(ctx context.CLIContext) (res Channel, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.ChannelKey, &res) - return +func (obj Object) prefix() []byte { + return bytes.Split(obj.Channel.KeyBytes(), LocalRoot())[0] } -func (obj CLIObject) Available(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.AvailableKey, &res) +func (obj Object) ChannelCLI(ctx context.CLIContext) (res Channel, proof merkle.Proof, err error) { + tmproof, err := obj.Channel.Query(ctx, &res) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Channel) return } -func (obj CLIObject) SeqSend(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.SeqSendKey, &res) +func (obj Object) AvailableCLI(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { + res, tmproof, err := obj.Available.Query(ctx) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.Available) return } -func (obj CLIObject) SeqRecv(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.SeqRecvKey, &res) +func (obj Object) SeqSendCLI(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { + res, tmproof, err := obj.SeqSend.Query(ctx) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.SeqSend) return } -func (obj CLIObject) Packet(ctx context.CLIContext, index uint64) (res Packet, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.PacketCommitKey(index), &res) +func (obj Object) SeqRecvCLI(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { + res, tmproof, err := obj.SeqRecv.Query(ctx) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.SeqRecv) return } -type CLIHandshakeObject struct { - CLIObject - - StateKey []byte - TimeoutKey []byte +func (obj Object) PacketCLI(ctx context.CLIContext, index uint64) (res Packet, proof merkle.Proof, err error) { + packet := obj.Packets.Value(index) + tmproof, err := packet.Query(ctx, &res) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), packet) + return } -func (man Handshaker) CLIQuery(ctx context.CLIContext, path merkle.Path, chanid, connid string) CLIHandshakeObject { - obj := man.object(man.man.object(connid, chanid)) - return CLIHandshakeObject{ - CLIObject: man.man.CLIQuery(ctx, path, chanid, connid), - - StateKey: obj.state.Key(), - TimeoutKey: obj.nextTimeout.Key(), +func (man Handshaker) CLIQuery(ctx context.CLIContext, portid, chanid string) (HandshakeObject, error) { + obj, err := man.man.CLIQuery(ctx, portid, chanid) + if err != nil { + return HandshakeObject{}, err } + return man.object(obj), nil } -func (man Handshaker) CLIObject(path merkle.Path, chanid, connid, clientid string) CLIHandshakeObject { - obj := man.object(man.man.object(connid, chanid)) - return CLIHandshakeObject{ - CLIObject: man.man.CLIObject(path, chanid, connid, clientid), - - StateKey: obj.state.Key(), - TimeoutKey: obj.nextTimeout.Key(), - } +func (man Handshaker) CLIObject(portid, chanid string, connids []string) HandshakeObject { + return man.object(man.man.CLIObject(portid, chanid, connids)) } -func (obj CLIHandshakeObject) State(ctx context.CLIContext) (res State, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.StateKey, &res) +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 (obj CLIHandshakeObject) NextTimeout(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { - proof, err = obj.query(ctx, obj.TimeoutKey, &res) +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/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index 96ceefe1cef9..48faa877b838 100644 --- a/x/ibc/04-channel/handshake.go +++ b/x/ibc/04-channel/handshake.go @@ -6,7 +6,7 @@ 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 @@ -48,8 +48,8 @@ type CounterpartyHandshaker struct { type HandshakeObject struct { Object - state state.Enum - nextTimeout state.Integer + State state.Enum + NextTimeout state.Integer counterparty CounterHandshakeObject } @@ -57,32 +57,32 @@ type HandshakeObject struct { type CounterHandshakeObject struct { CounterObject - state commitment.Enum - nextTimeout commitment.Integer + State commitment.Enum + NextTimeout commitment.Integer } // CONTRACT: client and remote must be filled by the caller func (man Handshaker) object(parent Object) HandshakeObject { - prefix := parent.connid + "/channels/" + parent.chanid + prefix := parent.portid + "/channels/" + parent.chanid return HandshakeObject{ Object: parent, - state: state.NewEnum(man.man.protocol.Value([]byte(prefix + "/state"))), - nextTimeout: state.NewInteger(man.man.protocol.Value([]byte(prefix+"/timeout")), state.Dec), + State: man.man.protocol.Value([]byte(prefix + "/state")).Enum(), + NextTimeout: man.man.protocol.Value([]byte(prefix + "/timeout")).Integer(state.Dec), - // CONTRACT: counterparty must be filled by the caller + counterparty: man.counterparty.object(parent.counterparty), } } -func (man CounterpartyHandshaker) object(connid, chanid string) CounterHandshakeObject { - prefix := connid + "/channels/" + chanid +func (man CounterpartyHandshaker) object(parent CounterObject) CounterHandshakeObject { + prefix := parent.portid + "/channels/" + parent.chanid return CounterHandshakeObject{ - CounterObject: man.man.object(connid, chanid), + CounterObject: man.man.object(parent.portid, parent.chanid), - state: commitment.NewEnum(man.man.protocol.Value([]byte(prefix + "/state"))), - nextTimeout: commitment.NewInteger(man.man.protocol.Value([]byte(prefix+"/timeout")), state.Dec), + State: man.man.protocol.Value([]byte(prefix + "/state")).Enum(), + NextTimeout: man.man.protocol.Value([]byte(prefix + "/timeout")).Integer(state.Dec), } } @@ -92,9 +92,6 @@ func (man Handshaker) create(ctx sdk.Context, connid, chanid string, channel Cha return } obj = man.object(cobj) - counterconnid := obj.connection.Connection(ctx).Counterparty - obj.counterparty = man.counterparty.object(counterconnid, channel.Counterparty) - obj.counterparty.connection = man.counterparty.man.connection.Object(counterconnid) return obj, nil } @@ -105,31 +102,16 @@ func (man Handshaker) query(ctx sdk.Context, connid, chanid string) (obj Handsha return } obj = man.object(cobj) - channel := obj.Channel(ctx) - counterconnid := obj.connection.Connection(ctx).Counterparty - obj.counterparty = man.counterparty.object(counterconnid, channel.Counterparty) - obj.counterparty.connection = man.counterparty.man.connection.Object(counterconnid) - return -} - -func (obj HandshakeObject) State(ctx sdk.Context) byte { - return obj.state.Get(ctx) -} - -func (obj HandshakeObject) Timeout(ctx sdk.Context) uint64 { - return obj.nextTimeout.Get(ctx) -} -func (obj HandshakeObject) NextTimeout(ctx sdk.Context) uint64 { - return obj.nextTimeout.Get(ctx) + return obj, nil } /* func (obj HandshakeObject) remove(ctx sdk.Context) { obj.Object.remove(ctx) - obj.state.Delete(ctx) + obj.State.Delete(ctx) obj.counterpartyClient.Delete(ctx) - obj.nextTimeout.Delete(ctx) + obj.NextTimeout.Delete(ctx) } */ @@ -146,15 +128,20 @@ func (man Handshaker) OpenInit(ctx sdk.Context, connid, chanid string, channel Channel, nextTimeoutHeight uint64, ) (HandshakeObject, 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") + } + obj, err := man.create(ctx, connid, chanid, channel) if err != nil { return HandshakeObject{}, err } - obj.nextTimeout.Set(ctx, nextTimeoutHeight) - obj.state.Set(ctx, Init) + obj.NextTimeout.Set(ctx, nextTimeoutHeight) + obj.State.Set(ctx, Init) return obj, nil } @@ -162,9 +149,12 @@ func (man Handshaker) OpenInit(ctx sdk.Context, // Using proofs: counterparty.{channel,state,nextTimeout} func (man Handshaker) OpenTry(ctx sdk.Context, proofs []commitment.Proof, - connid, chanid string, channel Channel, timeoutHeight, nextTimeoutHeight uint64, + portid, chanid string, channel Channel, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { - obj, err = man.create(ctx, connid, chanid, channel) + if len(channel.ConnectionHops) != 1 { + return HandshakeObject{}, errors.New("ConnectionHops length must be 1") + } + obj, err = man.create(ctx, portid, chanid, channel) if err != nil { return } @@ -179,21 +169,22 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - if !obj.counterparty.state.Is(ctx, Init) { + if !obj.counterparty.State.Is(ctx, Init) { err = errors.New("counterparty state not init") return } - if !obj.counterparty.channel.Is(ctx, Channel{ + if !obj.counterparty.Channel.Is(ctx, Channel{ Port: channel.CounterpartyPort, Counterparty: chanid, - CounterpartyPort: "", // TODO + CounterpartyPort: channel.Port, + ConnectionHops: []string{obj.Connections[0].GetConnection(ctx).Counterparty}, }) { err = errors.New("wrong counterparty connection") return } - if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { + if !obj.counterparty.NextTimeout.Is(ctx, timeoutHeight) { err = errors.New("unexpected counterparty timeout value") return } @@ -214,8 +205,8 @@ 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.State.Set(ctx, OpenTry) + obj.NextTimeout.Set(ctx, nextTimeoutHeight) return } @@ -235,7 +226,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.state.Transit(ctx, Init, Open) { + if !obj.State.Transit(ctx, Init, Open) { err = errors.New("ack on non-init connection") return } @@ -245,22 +236,23 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - channel := obj.Channel(ctx) - if !obj.counterparty.channel.Is(ctx, Channel{ + channel := obj.GetChannel(ctx) + if !obj.counterparty.Channel.Is(ctx, Channel{ Port: channel.CounterpartyPort, Counterparty: chanid, - CounterpartyPort: "", // TODO + CounterpartyPort: channel.Port, + ConnectionHops: []string{obj.Connections[0].GetConnection(ctx).Counterparty}, }) { err = errors.New("wrong counterparty") return } - if !obj.counterparty.state.Is(ctx, OpenTry) { + if !obj.counterparty.State.Is(ctx, OpenTry) { err = errors.New("counterparty state not opentry") return } - if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { + if !obj.counterparty.NextTimeout.Is(ctx, timeoutHeight) { err = errors.New("unexpected counterparty timeout value") return } @@ -274,8 +266,8 @@ func (man Handshaker) OpenAck(ctx sdk.Context, } */ - obj.nextTimeout.Set(ctx, nextTimeoutHeight) - obj.available.Set(ctx, true) + obj.NextTimeout.Set(ctx, nextTimeoutHeight) + obj.Available.Set(ctx, true) return } @@ -294,7 +286,7 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, return } - if !obj.state.Transit(ctx, OpenTry, Open) { + if !obj.State.Transit(ctx, OpenTry, Open) { err = errors.New("confirm on non-try connection") return } @@ -304,18 +296,18 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, return } - if !obj.counterparty.state.Is(ctx, Open) { + if !obj.counterparty.State.Is(ctx, Open) { err = errors.New("counterparty state not open") return } - if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { + if !obj.counterparty.NextTimeout.Is(ctx, timeoutHeight) { err = errors.New("unexpected counterparty timeout value") return } - obj.available.Set(ctx, true) - obj.nextTimeout.Set(ctx, 0) + obj.Available.Set(ctx, true) + obj.NextTimeout.Set(ctx, 0) return } @@ -323,23 +315,23 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, // TODO /* func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { - if !(obj.connection.Client().ConsensusState(ctx).GetHeight()) > obj.nextTimeout.Get(ctx)) { + if !(obj.connection.Client().ConsensusState(ctx).GetHeight()) > obj.NextTimeout.Get(ctx)) { return errors.New("timeout height not yet reached") } - switch obj.state.Get(ctx) { + 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) || + 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) { + if obj.counterparty.State.Is(ctx, OpenTry) { return errors.New("counterparty connection state not tryopen") } } @@ -351,17 +343,17 @@ func (obj HandshakeObject) OpenTimeout(ctx sdk.Context) error { func (obj HandshakeObject) CloseInit(ctx sdk.Context, nextTimeout uint64) error { - if !obj.state.Transit(ctx, Open, CloseTry) { + if !obj.State.Transit(ctx, Open, CloseTry) { return errors.New("closeinit on non-open connection") } - obj.nextTimeout.Set(ctx, nextTimeout) + 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) { + if !obj.State.Transit(ctx, Open, Closed) { return errors.New("closetry on non-open connection") } @@ -370,21 +362,21 @@ func (obj HandshakeObject) CloseTry(ctx sdk.Context, timeoutHeight, nextTimeoutH return err } - if !obj.counterparty.state.Is(ctx, CloseTry) { + if !obj.counterparty.State.Is(ctx, CloseTry) { return errors.New("unexpected counterparty state value") } - if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { + if !obj.counterparty.NextTimeout.Is(ctx, timeoutHeight) { return errors.New("unexpected counterparty timeout value") } - obj.nextTimeout.Set(ctx, nextTimeoutHeight) + obj.NextTimeout.Set(ctx, nextTimeoutHeight) return nil } func (obj HandshakeObject) CloseAck(ctx sdk.Context, timeoutHeight uint64) error { - if !obj.state.Transit(ctx, CloseTry, Closed) { + if !obj.State.Transit(ctx, CloseTry, Closed) { return errors.New("closeack on non-closetry connection") } @@ -393,38 +385,38 @@ func (obj HandshakeObject) CloseAck(ctx sdk.Context, timeoutHeight uint64) error return err } - if !obj.counterparty.state.Is(ctx, Closed) { + if !obj.counterparty.State.Is(ctx, Closed) { return errors.New("unexpected counterparty state value") } - if !obj.counterparty.nextTimeout.Is(ctx, timeoutHeight) { + if !obj.counterparty.NextTimeout.Is(ctx, timeoutHeight) { return errors.New("unexpected counterparty timeout value") } - obj.nextTimeout.Set(ctx, 0) + 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)) { + 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) { + switch obj.State.Get(ctx) { case CloseTry: - if !obj.counterparty.state.Is(ctx, Open) { + if !obj.counterparty.State.Is(ctx, Open) { return errors.New("counterparty connection state not open") } case Closed: - if !obj.counterparty.state.Is(ctx, CloseTry) { + 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) + obj.State.Set(ctx, Open) + obj.NextTimeout.Set(ctx, 0) return nil diff --git a/x/ibc/04-channel/keys.go b/x/ibc/04-channel/keys.go new file mode 100644 index 000000000000..383187d33c44 --- /dev/null +++ b/x/ibc/04-channel/keys.go @@ -0,0 +1,5 @@ +package channel + +func LocalRoot() []byte { + return []byte("ports/") +} diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index f21115e3006c..6b76f7cef4c4 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/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/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" ) // Manager is unrestricted @@ -28,97 +28,110 @@ type CounterpartyManager struct { connection connection.CounterpartyManager } -func NewManager(protocol state.Base, connection connection.Manager) Manager { +func NewManager(protocol state.Mapping, connection connection.Manager) Manager { return Manager{ - protocol: state.NewMapping(protocol, []byte("/connection/")), + protocol: protocol.Prefix(LocalRoot()), connection: connection, counterparty: NewCounterpartyManager(protocol.Cdc()), } } func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { - protocol := commitment.NewBase(cdc) + protocol := commitment.NewMapping(cdc, nil) return CounterpartyManager{ - protocol: commitment.NewMapping(protocol, []byte("/connection/")), + protocol: protocol.Prefix(LocalRoot()), connection: connection.NewCounterpartyManager(cdc), } } // CONTRACT: connection and counterparty must be filled by the caller -func (man Manager) object(connid, chanid string) Object { - key := connid + "/channels/" + chanid +func (man Manager) object(portid, chanid string) Object { + key := portid + "/channels/" + chanid return Object{ chanid: chanid, - connid: connid, - channel: man.protocol.Value([]byte(key)), + portid: portid, + Channel: man.protocol.Value([]byte(key)), - available: state.NewBoolean(man.protocol.Value([]byte(key + "/available"))), + Available: man.protocol.Value([]byte(key + "/available")).Boolean(), - seqsend: state.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), state.Dec), - seqrecv: state.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceRecv")), state.Dec), - packets: state.NewIndexer(man.protocol.Prefix([]byte(key+"/packets/")), 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(connid, chanid string) CounterObject { - key := connid + "/channels/" + chanid +func (man CounterpartyManager) object(portid, chanid string) CounterObject { + key := portid + "/channels/" + chanid return CounterObject{ chanid: chanid, - connid: connid, - channel: man.protocol.Value([]byte(key)), + portid: portid, + Channel: man.protocol.Value([]byte(key)), - available: commitment.NewBoolean(man.protocol.Value([]byte(key + "/available"))), + Available: man.protocol.Value([]byte(key + "/available")).Boolean(), - seqsend: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceSend")), state.Dec), - seqrecv: commitment.NewInteger(man.protocol.Value([]byte(key+"/nextSequenceRecv")), state.Dec), - packets: commitment.NewIndexer(man.protocol.Prefix([]byte(key+"/packets/")), 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, connid, chanid string, channel Channel) (obj Object, err error) { - obj = man.object(connid, chanid) +func (man Manager) create(ctx sdk.Context, portid, chanid string, channel Channel) (obj Object, err error) { + obj = man.object(portid, chanid) if obj.exists(ctx) { err = errors.New("channel already exists for the provided id") return } - obj.connection, err = man.connection.Query(ctx, connid) - if err != nil { - return + obj.Channel.Set(ctx, channel) + obj.counterparty = man.counterparty.object(channel.CounterpartyPort, channel.Counterparty) + + for _, hop := range channel.ConnectionHops { + connobj, err := man.connection.Query(ctx, hop) + if err != nil { + return obj, err + } + obj.Connections = append(obj.Connections, connobj) } - obj.channel.Set(ctx, channel) - counterconnid := obj.connection.Connection(ctx).Counterparty - obj.counterparty = man.counterparty.object(counterconnid, channel.Counterparty) - obj.counterparty.connection = man.counterparty.connection.Object(counterconnid) + for _, hop := range channel.CounterpartyHops() { + connobj := man.counterparty.connection.Object(hop) + obj.counterparty.Connections = append(obj.counterparty.Connections, connobj) + } return } // Does not check availability -func (man Manager) query(ctx sdk.Context, connid, chanid string) (obj Object, err error) { - obj = man.object(connid, chanid) +func (man Manager) query(ctx sdk.Context, portid, chanid string) (obj Object, err error) { + obj = man.object(portid, chanid) if !obj.exists(ctx) { err = errors.New("channel not exists for the provided id") return } - obj.connection, err = man.connection.Query(ctx, connid) - if err != nil { - return + + channel := obj.GetChannel(ctx) + obj.counterparty = man.counterparty.object(channel.CounterpartyPort, channel.Counterparty) + for _, hop := range channel.ConnectionHops { + connobj, err := man.connection.Query(ctx, hop) + if err != nil { + return obj, err + } + obj.Connections = append(obj.Connections, connobj) } - counterconnid := obj.connection.Connection(ctx).Counterparty - obj.counterparty = man.counterparty.object(counterconnid, obj.Channel(ctx).Counterparty) - obj.counterparty.connection = man.counterparty.connection.Object(counterconnid) + for _, hop := range channel.CounterpartyHops() { + connobj := man.counterparty.connection.Object(hop) + obj.counterparty.Connections = append(obj.counterparty.Connections, connobj) + } return } -func (man Manager) Query(ctx sdk.Context, connid, chanid string) (obj Object, err error) { - obj, err = man.query(ctx, connid, chanid) - if !obj.Available(ctx) { - err = errors.New("channel not available") +func (man Manager) Query(ctx sdk.Context, portid, chanid string) (obj Object, err error) { + obj, err = man.query(ctx, portid, chanid) + if !obj.Available.Get(ctx) { + err = errors.New("channel not Available") return } return @@ -141,7 +154,7 @@ type PortManager struct { chanid func(string) bool } -func (man PortManager) Create(ctx sdk.Context, connid, chanid string, channel Channel) (Object, error) { +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") } @@ -150,15 +163,15 @@ func (man PortManager) Create(ctx sdk.Context, connid, chanid string, channel Ch return Object{}, errors.New("invalid port") } - return man.man.Create(ctx, connid, chanid, channel) + return man.man.Create(ctx, portid, chanid, channel) } -func (man PortManager) Query(ctx sdk.Context, connid, chanid string) (Object, error) { +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, connid, chanid) + obj, err := man.man.Query(ctx, portid, chanid) if err != nil { return Object{}, err } @@ -173,105 +186,97 @@ func (man PortManager) Query(ctx sdk.Context, connid, chanid string) (Object, er type Object struct { chanid string - connid string + portid string - channel state.Value + Channel state.Value - seqsend state.Integer - seqrecv state.Integer - packets state.Indexer + SeqSend state.Integer + SeqRecv state.Integer + Packets state.Indexer - available state.Boolean + Available state.Boolean - connection connection.Object + Connections []connection.Object counterparty CounterObject } type CounterObject struct { - chanid string - connid string - channel commitment.Value + chanid string + portid string + + Channel commitment.Value - seqsend commitment.Integer - seqrecv commitment.Integer - packets commitment.Indexer + SeqSend commitment.Integer + SeqRecv commitment.Integer + Packets commitment.Indexer - available commitment.Boolean + Available commitment.Boolean + + Connections []connection.CounterObject +} - connection connection.CounterObject +func (obj Object) OriginConnection() connection.Object { + return obj.Connections[0] } func (obj Object) Context(ctx sdk.Context, proofs []commitment.Proof) (sdk.Context, error) { - return obj.connection.Context(ctx, nil, proofs) + return obj.OriginConnection().Context(ctx, nil, proofs) } func (obj Object) ChanID() string { return obj.chanid } -func (obj Object) Channel(ctx sdk.Context) (res Channel) { - obj.channel.Get(ctx, &res) - return -} - -func (obj Object) Value(ctx sdk.Context) (res Channel) { - obj.channel.Get(ctx, &res) +func (obj Object) GetChannel(ctx sdk.Context) (res Channel) { + obj.Channel.Get(ctx, &res) return } -func (obj Object) Available(ctx sdk.Context) bool { - return obj.available.Get(ctx) +func (obj Object) PacketCommit(ctx sdk.Context, index uint64) []byte { + return obj.Packets.Value(index).GetRaw(ctx) } +/* func (obj Object) Sendable(ctx sdk.Context) bool { - // TODO: sendable/receivable should be also defined for channels - return obj.connection.Sendable(ctx) + return obj.connection } func (obj Object) Receivable(ctx sdk.Context) bool { - return obj.connection.Receivable(ctx) -} - -func (obj Object) SeqSend(ctx sdk.Context) uint64 { - return obj.seqsend.Get(ctx) + return kinds[obj.kind.Get(ctx)].Receivable } - -func (obj Object) SeqRecv(ctx sdk.Context) uint64 { - return obj.seqrecv.Get(ctx) -} - -func (obj Object) PacketCommit(ctx sdk.Context, index uint64) []byte { - return obj.packets.Value(index).GetRaw(ctx) -} - +*/ func (obj Object) exists(ctx sdk.Context) bool { - return obj.channel.Exists(ctx) + return obj.Channel.Exists(ctx) } func (obj Object) Send(ctx sdk.Context, packet Packet) error { - if !obj.Sendable(ctx) { - return errors.New("cannot send packets on this channel") - } + /* + if !obj.Sendable(ctx) { + return errors.New("cannot send Packets on this channel") + } + */ - if obj.connection.Client().ConsensusState(ctx).GetHeight() >= packet.Timeout() { + if obj.OriginConnection().Client.GetConsensusState(ctx).GetHeight() >= packet.Timeout() { return errors.New("timeout height higher than the latest known") } - obj.packets.Set(ctx, obj.seqsend.Incr(ctx), packet) + obj.Packets.Set(ctx, obj.SeqSend.Incr(ctx), packet) return nil } -func (man Manager) Receive(ctx sdk.Context, proofs []commitment.Proof, connid, chanid string, packet Packet) error { - obj, err := man.Query(ctx, connid, chanid) +func (man Manager) Receive(ctx sdk.Context, proofs []commitment.Proof, portid, chanid string, packet Packet) error { + obj, err := man.Query(ctx, portid, chanid) if err != nil { return err } - if !obj.Receivable(ctx) { - return errors.New("cannot receive packets on this channel") - } + /* + if !obj.Receivable(ctx) { + return errors.New("cannot receive Packets on this channel") + } + */ ctx, err = obj.Context(ctx, proofs) if err != nil { @@ -285,7 +290,7 @@ func (man Manager) Receive(ctx sdk.Context, proofs []commitment.Proof, connid, c // XXX: increment should happen before verification, reflect on the spec // TODO: packet should be custom marshalled - if !obj.counterparty.packets.Value(obj.seqrecv.Incr(ctx)).Is(ctx, packet) { + if !obj.counterparty.Packets.Value(obj.SeqRecv.Incr(ctx)).Is(ctx, packet) { return errors.New("verification failed") } diff --git a/x/ibc/04-channel/tests/channel_test.go b/x/ibc/04-channel/tests/channel_test.go index 6463d6db0c2d..82d27dca8089 100644 --- a/x/ibc/04-channel/tests/channel_test.go +++ b/x/ibc/04-channel/tests/channel_test.go @@ -5,11 +5,11 @@ import ( "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" tmclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + tendermint "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" + 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/23-commitment/merkle" ) @@ -62,6 +62,6 @@ func TestPacket(t *testing.T) { node.Counterparty.UpdateClient(t, header) cliobj := node.CLIObject() - _, ppacket := node.Query(t, cliobj.PacketCommitKey(1)) + _, ppacket := node.QueryValue(t, cliobj.Packets.Value(1)) node.Counterparty.Receive(t, MyPacket{"ping"}, ppacket) } diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index daa17e526bb3..651a3665827a 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/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/tendermint/tests" - "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/tests" - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + tendermint "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/tests" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) type Node struct { @@ -39,15 +39,17 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { } res.Channel = channel.Channel{ - Port: "", // TODO + Port: res.Name, Counterparty: res.Counterparty.Name, - CounterpartyPort: "", //TODO + CounterpartyPort: res.Counterparty.Name, + ConnectionHops: []string{res.Name}, } res.Counterparty.Channel = channel.Channel{ - Port: "", // TODO + Port: res.Counterparty.Name, Counterparty: res.Name, - CounterpartyPort: "", // TODO + CounterpartyPort: res.Name, + ConnectionHops: []string{res.Counterparty.Name}, } return res @@ -55,21 +57,21 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Context, channel.Handshaker) { ctx := node.Context() - store, err := commitment.NewStore(node.Counterparty.Root(), node.Counterparty.Path, proofs) + store, err := commitment.NewStore(node.Counterparty.Root(), node.Counterparty.Path(), proofs) require.NoError(t, err) ctx = commitment.WithStore(ctx, store) man := node.Manager() return ctx, channel.NewHandshaker(man) } -func (node *Node) CLIObject() channel.CLIHandshakeObject { +func (node *Node) CLIObject() channel.HandshakeObject { man := node.Manager() - return channel.NewHandshaker(man).CLIObject(node.Path, node.Name, node.Name, node.Name) + return channel.NewHandshaker(man).CLIObject(node.Name, node.Name, []string{node.Counterparty.Name, node.Name}) } -func base(cdc *codec.Codec, key sdk.StoreKey) (state.Base, state.Base) { - protocol := state.NewBase(cdc, key, []byte("protocol")) - free := state.NewBase(cdc, key, []byte("free")) +func base(cdc *codec.Codec, key sdk.StoreKey) (state.Mapping, state.Mapping) { + protocol := state.NewMapping(key, cdc, []byte("protocol/")) + free := state.NewMapping(key, cdc, []byte("free")) return protocol, free } @@ -83,18 +85,18 @@ 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 require.NoError(t, err) - require.Equal(t, channel.Init, obj.State(ctx)) - require.Equal(t, node.Channel, obj.Channel(ctx)) - require.False(t, obj.Available(ctx)) + require.Equal(t, channel.Init, obj.State.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) { ctx, man := node.Handshaker(t, proofs) obj, err := man.OpenTry(ctx, proofs, node.Name, node.Name, node.Channel, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) - require.Equal(t, channel.OpenTry, obj.State(ctx)) - require.Equal(t, node.Channel, obj.Channel(ctx)) - require.False(t, obj.Available(ctx)) + require.Equal(t, channel.OpenTry, obj.State.Get(ctx)) + require.Equal(t, node.Channel, obj.GetChannel(ctx)) + require.False(t, obj.Available.Get(ctx)) node.SetState(channel.OpenTry) } @@ -102,9 +104,9 @@ func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) obj, err := man.OpenAck(ctx, proofs, node.Name, node.Name, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) - require.Equal(t, channel.Open, obj.State(ctx)) - require.Equal(t, node.Channel, obj.Channel(ctx)) - require.True(t, obj.Available(ctx)) + require.Equal(t, channel.Open, obj.State.Get(ctx)) + require.Equal(t, node.Channel, obj.GetChannel(ctx)) + require.True(t, obj.Available.Get(ctx)) node.SetState(channel.Open) } @@ -112,9 +114,9 @@ func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) obj, err := man.OpenConfirm(ctx, proofs, node.Name, node.Name, 100 /*TODO*/) require.NoError(t, err) - require.Equal(t, channel.Open, obj.State(ctx)) - require.Equal(t, node.Channel, obj.Channel(ctx)) - require.True(t, obj.Available(ctx)) + require.Equal(t, channel.Open, obj.State.Get(ctx)) + require.Equal(t, node.Channel, obj.GetChannel(ctx)) + require.True(t, obj.Available.Get(ctx)) node.SetState(channel.CloseTry) } @@ -128,26 +130,26 @@ func (node *Node) Handshake(t *testing.T) { // counterparty.OpenTry node.Counterparty.UpdateClient(t, header) cliobj := node.CLIObject() - _, pchan := node.Query(t, cliobj.ChannelKey) - _, pstate := node.Query(t, cliobj.StateKey) - _, ptimeout := node.Query(t, cliobj.TimeoutKey) + _, 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) header = node.Counterparty.Commit() // self.OpenAck node.UpdateClient(t, header) cliobj = node.Counterparty.CLIObject() - _, pchan = node.Counterparty.Query(t, cliobj.ChannelKey) - _, pstate = node.Counterparty.Query(t, cliobj.StateKey) - _, ptimeout = node.Counterparty.Query(t, cliobj.TimeoutKey) + _, 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) header = node.Commit() // counterparty.OpenConfirm node.Counterparty.UpdateClient(t, header) cliobj = node.CLIObject() - _, pstate = node.Query(t, cliobj.StateKey) - _, ptimeout = node.Query(t, cliobj.TimeoutKey) + _, pstate = node.QueryValue(t, cliobj.State) + _, ptimeout = node.QueryValue(t, cliobj.NextTimeout) node.Counterparty.OpenConfirm(t, pstate, ptimeout) } @@ -155,10 +157,10 @@ 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) require.NoError(t, err) - seq := obj.SeqSend(ctx) + seq := obj.SeqSend.Get(ctx) err = obj.Send(ctx, packet) require.NoError(t, err) - require.Equal(t, seq+1, obj.SeqSend(ctx)) + require.Equal(t, seq+1, obj.SeqSend.Get(ctx)) require.Equal(t, node.Cdc.MustMarshalBinaryBare(packet), obj.PacketCommit(ctx, seq+1)) } @@ -166,8 +168,8 @@ func (node *Node) Receive(t *testing.T, packet channel.Packet, proofs ...commitm ctx, man := node.Context(), node.Manager() obj, err := man.Query(ctx, node.Name, node.Name) require.NoError(t, err) - seq := obj.SeqRecv(ctx) + seq := obj.SeqRecv.Get(ctx) err = man.Receive(ctx, proofs, node.Name, node.Name, packet) require.NoError(t, err) - require.Equal(t, seq+1, obj.SeqRecv(ctx)) + 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 891bea6f9985..fe25a08dfc5f 100644 --- a/x/ibc/04-channel/types.go +++ b/x/ibc/04-channel/types.go @@ -24,4 +24,13 @@ type Channel struct { Port string Counterparty string CounterpartyPort string + ConnectionHops []string +} + +func (ch Channel) CounterpartyHops() (res []string) { + res = make([]string, len(ch.ConnectionHops)) + for i, hop := range ch.ConnectionHops { + res[len(res)-(i+1)] = hop + } + return } diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index cf76caac4b39..923a065334ea 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -3,6 +3,7 @@ package commitment import ( "bytes" "errors" + "fmt" ) // Store proves key-value pairs' inclusion or non-inclusion with @@ -25,7 +26,6 @@ func NewPrefix(store Store, pref []byte) prefix { } } - func (prefix prefix) Prove(key, value []byte) bool { return prefix.store.Prove(join(prefix.prefix, key), value) } @@ -80,6 +80,7 @@ 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) @@ -91,7 +92,6 @@ func (store *store) Prove(key, value []byte) bool { return true } - // Proven() returns true if the key-value pair is already proven func (store *store) Proven(key []byte) bool { _, ok := store.Get(key) diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 18e1a19c2a9e..947d322c06bd 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -1,7 +1,6 @@ package commitment import ( - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" @@ -40,7 +39,7 @@ type Indexer struct { enc state.IntEncoding } -func NewIndexer(m Mapping, enc state.IntEncoding) Indexer { +func (m Mapping) Indexer(enc state.IntEncoding) Indexer { return Indexer{ Mapping: m, enc: enc, From 7a863d7dcba04c445e17a0d6f133b644b358ba41 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 15 Aug 2019 20:22:47 +0900 Subject: [PATCH 196/378] comment out client --- x/ibc/04-channel/client/cli/query.go | 47 ++++++++------------------ x/ibc/04-channel/client/cli/tx.go | 50 ++++++++++------------------ 2 files changed, 31 insertions(+), 66 deletions(-) diff --git a/x/ibc/04-channel/client/cli/query.go b/x/ibc/04-channel/client/cli/query.go index 6f11957f7ab3..d50573cdc724 100644 --- a/x/ibc/04-channel/client/cli/query.go +++ b/x/ibc/04-channel/client/cli/query.go @@ -1,38 +1,17 @@ package cli -import ( - "fmt" - "strconv" - - "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" - - "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/04-channel" - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/client/utils" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" -) - const ( FlagProve = "prove" ) -func object(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, connid, chanid string) channel.CLIObject { - prefix := []byte(strconv.FormatInt(version, 10) + "/") - path := merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) - base := state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) +// TODO +/* +func object(cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid string, connids []string) channel.Object { + base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) climan := client.NewManager(base) connman := connection.NewManager(base, climan) man := channel.NewManager(base, connman) - return man.CLIQuery(ctx, path, connid, chanid) + return man.CLIObject(portid, chanid, connids) } func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { @@ -44,17 +23,17 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { } ibcQueryCmd.AddCommand(cli.GetCommands( - GetCmdQueryChannel(storeKey, cdc), + // GetCmdQueryChannel(storeKey, cdc), )...) return ibcQueryCmd } -func QueryChannel(ctx context.CLIContext, obj channel.CLIObject, prove bool) (res utils.JSONObject, err error) { - conn, connp, err := obj.Channel(ctx) +func QueryChannel(ctx context.CLIContext, obj channel.Object, prove bool) (res utils.JSONObject, err error) { + conn, connp, err := obj.ChannelCLI(ctx) if err != nil { return } - avail, availp, err := obj.Available(ctx) + avail, availp, err := obj.AvailableCLI(ctx) if err != nil { return } @@ -63,13 +42,13 @@ func QueryChannel(ctx context.CLIContext, obj channel.CLIObject, prove bool) (re if err != nil { return } - */ - seqsend, seqsendp, err := obj.SeqSend(ctx) + + seqsend, seqsendp, err := obj.SeqSendCLI(ctx) if err != nil { return } - seqrecv, seqrecvp, err := obj.SeqRecv(ctx) + seqrecv, seqrecvp, err := obj.SeqRecvCLI(ctx) if err != nil { return } @@ -92,6 +71,7 @@ func QueryChannel(ctx context.CLIContext, obj channel.CLIObject, prove bool) (re ), nil } + func GetCmdQueryChannel(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "connection", @@ -115,3 +95,4 @@ func GetCmdQueryChannel(storeKey string, cdc *codec.Codec) *cobra.Command { return cmd } +*/ diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index 7f67c9902cb2..c166bda866db 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -1,28 +1,5 @@ package cli -import ( - "io/ioutil" - "strconv" - "time" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "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" - - "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/04-channel" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" -) - /* func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { @@ -35,14 +12,14 @@ const ( FlagFrom2 = "from2" ) -func handshake(ctx context.CLIContext, cdc *codec.Codec, storeKey string, version int64, connid, chanid string) channel.CLIHandshakeObject { - prefix := []byte(strconv.FormatInt(version, 10) + "/") - path := merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) - base := state.NewBase(cdc, sdk.NewKVStoreKey(storeKey), prefix) +// TODO +/* +func handshake(ctx context.CLIContext, cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid string) (channel.HandshakeObject, 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, path, connid, chanid) + return man.CLIQuery(ctx, portid, chanid) } func lastheight(ctx context.CLIContext) (uint64, error) { @@ -88,7 +65,10 @@ func GetCmdChannelHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - obj1 := handshake(ctx1, cdc, storeKey, ibc.Version, conn1id, chan1id) + obj1, err := handshake(ctx1, cdc, storeKey, ibc.Version, conn1id, chan1id) + if err != nil { + return err + } conn2id := args[3] chan2id := args[4] @@ -101,7 +81,10 @@ func GetCmdChannelHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - obj2 := handshake(ctx2, cdc, storeKey, ibc.Version, conn1id, chan1id) + obj2, err := handshake(ctx2, cdc, storeKey, ibc.Version, conn1id, chan1id) + if err != nil { + return err + } // TODO: check state and if not Idle continue existing process height, err := lastheight(ctx2) @@ -128,15 +111,15 @@ func GetCmdChannelHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } nextTimeout = height + 1000 - _, pconn, err := obj1.Channel(ctx1) + _, pconn, err := obj1.ChannelCLI(ctx1) if err != nil { return err } - _, pstate, err := obj1.State(ctx1) + _, pstate, err := obj1.StateCLI(ctx1) if err != nil { return err } - _, ptimeout, err := obj1.NextTimeout(ctx1) + _, ptimeout, err := obj1.NextTimeoutCLI(ctx1) if err != nil { return err } @@ -298,3 +281,4 @@ func relay(cdc *codec.Codec, ctxFrom, ctxTo context.CLIContext, objFrom, objTo c return nil } +*/ From 7bf4d57d5e27e36074b719b8bd29ff98f2933420 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 15 Aug 2019 20:23:38 +0900 Subject: [PATCH 197/378] merge from ics04 branch --- store/state/indexer.go | 9 +++++++-- store/state/mapping.go | 5 +++++ store/state/mapping_test.go | 2 +- store/state/types.go | 2 ++ store/state/value.go | 8 ++++++++ 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/store/state/indexer.go b/store/state/indexer.go index 6b837c2021a3..c948937306da 100644 --- a/store/state/indexer.go +++ b/store/state/indexer.go @@ -31,8 +31,9 @@ type Indexer struct { enc IntEncoding } -// NewIndexer() constructs the Indexer with a predetermined prefix and IntEncoding -func NewIndexer(m Mapping, enc IntEncoding) Indexer { + +// Indexer() constructs the Indexer with an IntEncoding +func (m Mapping) Indexer(enc IntEncoding) Indexer { return Indexer{ m: m, enc: enc, @@ -94,6 +95,10 @@ func (ix Indexer) Set(ctx Context, index uint64, o interface{}) { ix.Value(index).Set(ctx, o) } +func (ix Indexer) SetRaw(ctx Context, index uint64, value []byte) { + ix.Value(index).SetRaw(ctx, value) +} + // Has() returns true if the stored value is not nil func (ix Indexer) Has(ctx Context, index uint64) bool { return ix.Value(index).Exists(ctx) diff --git a/store/state/mapping.go b/store/state/mapping.go index 95a96974416b..8cebbf97c1d7 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -49,6 +49,10 @@ func (m Mapping) Set(ctx Context, key []byte, o interface{}) { m.Value(key).Set(ctx, o) } +func (m Mapping) SetRaw(ctx Context, key []byte, value []byte) { + m.Value(key).SetRaw(ctx, value) +} + // Has() returns true if the stored value is not nil func (m Mapping) Has(ctx Context, key []byte) bool { return m.Value(key).Exists(ctx) @@ -92,3 +96,4 @@ func (m Mapping) Prefix(prefix []byte) Mapping { prefix: join(m.prefix, prefix), } } + diff --git a/store/state/mapping_test.go b/store/state/mapping_test.go index 0a29fead8a6e..2f44b9fcccc2 100644 --- a/store/state/mapping_test.go +++ b/store/state/mapping_test.go @@ -60,7 +60,7 @@ type indexerT struct { var _ mapping = indexerT{} func newIndexer(enc IntEncoding) indexerT { - return indexerT{NewIndexer(NewMapping(testkey, testcdc, nil), enc)} + return indexerT{NewMapping(testkey, testcdc, nil).Indexer(enc)} } func (m indexerT) Get(ctx Context, key interface{}, ptr interface{}) { diff --git a/store/state/types.go b/store/state/types.go index f5dbb4dc8648..a058cf6ddf0a 100644 --- a/store/state/types.go +++ b/store/state/types.go @@ -4,6 +4,7 @@ import ( "github.com/tendermint/tendermint/crypto/merkle" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -11,3 +12,4 @@ type KVStore = sdk.KVStore type Context = sdk.Context type CLIContext = context.CLIContext type Proof = merkle.Proof +type Codec = codec.Codec diff --git a/store/state/value.go b/store/state/value.go index c54445f59e9f..eb8cd12cf76a 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -95,6 +95,14 @@ func (v Value) Delete(ctx Context) { v.store(ctx).Delete(v.KeyBytes()) } +func (v Value) StoreName() string { + return v.m.StoreName() +} + +func (v Value) PrefixBytes() []byte { + return v.m.PrefixBytes() +} + // KeyBytes() returns the prefixed key that the Value is providing to the KVStore func (v Value) KeyBytes() []byte { return v.m.KeyBytes(v.key) From 32cb0ca7900ab12481534b5ef8172aa7be8f8d17 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 15 Aug 2019 20:29:45 +0900 Subject: [PATCH 198/378] merge from ics04 branch --- x/ibc/23-commitment/merkle/merkle.go | 15 +++- x/ibc/23-commitment/merkle/merkle_test.go | 43 +++++----- x/ibc/23-commitment/merkle/utils.go | 98 +++++++++++++++++------ x/ibc/23-commitment/store.go | 16 ++-- x/ibc/23-commitment/value.go | 43 +++++++++- 5 files changed, 159 insertions(+), 56 deletions(-) diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index a5acbdd43c3a..1606497ec4f8 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -1,13 +1,15 @@ package merkle import ( + "bytes" "errors" "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/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) const merkleKind = "merkle" @@ -91,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() @@ -101,3 +103,12 @@ func (proof Proof) Verify(croot commitment.Root, cpath commitment.Path, value [] } return runtime.VerifyAbsence(proof.Proof, root.Hash, keypath.String()) } + +type Value interface { + KeyBytes() []byte +} + +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/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index a407d17c1868..222a6bf5abd9 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -12,10 +12,11 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store" + "github.com/cosmos/cosmos-sdk/store/state" "github.com/cosmos/cosmos-sdk/store/types" 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" ) func defaultComponents() (sdk.StoreKey, sdk.Context, types.CommitMultiStore, *codec.Codec) { @@ -40,23 +41,25 @@ func commit(cms types.CommitMultiStore) Root { // TestStore tests Merkle proof on the commitment.Store // Sets/upates key-value pairs and prove with the query result proofs func TestStore(t *testing.T) { - k, ctx, cms, _ := defaultComponents() - kvstore := ctx.KVStore(k) - path := Path{KeyPath: [][]byte{[]byte("test")}, KeyPrefix: []byte{0x01, 0x03, 0x05}} + k, ctx, cms, cdc := defaultComponents() + storeName := k.Name() + prefix := []byte{0x01, 0x03, 0x05, 0xAA, 0xBB} + mapp := state.NewMapping(k, cdc, prefix) + path := NewPath([][]byte{[]byte(storeName)}, prefix) m := make(map[string][]byte) - kvpn := 1000 + kvpn := 10 - // Repeat 100 times to test on multiple commits + // Repeat to test on multiple commits for repeat := 0; repeat < 10; repeat++ { // Initializes random generated key-value pairs for i := 0; i < kvpn; i++ { - k, v := make([]byte, 64), make([]byte, 64) + k, v := make([]byte, 16), make([]byte, 16) rand.Read(k) rand.Read(v) m[string(k)] = v - kvstore.Set(path.Key(k), v) + mapp.Value(k).Set(ctx, v) } // Commit store @@ -65,18 +68,18 @@ func TestStore(t *testing.T) { // Test query, and accumulate proofs proofs := make([]commitment.Proof, 0, kvpn) for k, v := range m { - c, v0, p := path.Query(cms, []byte(k)) - require.Equal(t, uint32(0), c) - require.Equal(t, v, v0) + v0, p, err := QueryMultiStore(cms, storeName, prefix, []byte(k)) + require.NoError(t, err) + require.Equal(t, cdc.MustMarshalBinaryBare(v), v0, "Queried value different at %d", repeat) proofs = append(proofs, p) } // Add some exclusion proofs - for i := 0; i < 100; i++ { + for i := 0; i < 10; i++ { k := make([]byte, 64) rand.Read(k) - c, v, p := path.Query(cms, k) - require.Equal(t, uint32(0), c) + v, p, err := QueryMultiStore(cms, storeName, prefix, k) + require.NoError(t, err) require.Nil(t, v) proofs = append(proofs, p) m[string(k)] = []byte{} @@ -88,7 +91,7 @@ func TestStore(t *testing.T) { // Test commitment store for k, v := range m { if len(v) != 0 { - require.True(t, cstore.Prove([]byte(k), v)) + require.True(t, cstore.Prove([]byte(k), cdc.MustMarshalBinaryBare(v))) } else { require.True(t, cstore.Prove([]byte(k), nil)) } @@ -99,7 +102,7 @@ func TestStore(t *testing.T) { v := make([]byte, 64) rand.Read(v) m[k] = v - kvstore.Set(path.Key([]byte(k)), v) + mapp.Value([]byte(k)).Set(ctx, v) } root = commit(cms) @@ -107,9 +110,9 @@ func TestStore(t *testing.T) { // Test query, and accumulate proofs proofs = make([]commitment.Proof, 0, kvpn) for k, v := range m { - c, v0, p := path.Query(cms, []byte(k)) - require.Equal(t, uint32(0), c) - require.Equal(t, v, v0) + v0, p, err := QueryMultiStore(cms, storeName, prefix, []byte(k)) + require.NoError(t, err) + require.Equal(t, cdc.MustMarshalBinaryBare(v), v0) proofs = append(proofs, p) } @@ -119,7 +122,7 @@ func TestStore(t *testing.T) { // Test commitment store for k, v := range m { if len(v) != 0 { - require.True(t, cstore.Prove([]byte(k), v)) + require.True(t, cstore.Prove([]byte(k), cdc.MustMarshalBinaryBare(v))) } else { require.True(t, cstore.Prove([]byte(k), nil)) } diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index 1a0880a3659f..636fae569c28 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -1,41 +1,35 @@ package merkle import ( + "errors" + abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/store/types" ) -// RequestQuery() constructs the abci.RequestQuery. -// -// RequestQuery.Path is a slash separated key list, ending with "/key" -// -// RequestQuery.Data is the concatanation of path.KeyPrefix and key argument -// -// RequestQuery.Prove is set to true -func (path Path) RequestQuery(key []byte) abci.RequestQuery { - pathstr := "" - for _, inter := range path.KeyPath { - // The Queryable() stores uses slash-separated keypath format for querying - pathstr = pathstr + "/" + string(inter) +func QueryMultiStore(cms types.CommitMultiStore, storeName string, prefix []byte, key []byte) ([]byte, Proof, error) { + queryable, ok := cms.(types.Queryable) + if !ok { + panic("CommitMultiStore not queryable") + } + qres := queryable.Query(RequestQueryMultiStore(storeName, prefix, key)) + if !qres.IsOK() { + return nil, Proof{}, errors.New(qres.Log) } - // Suffixing pathstr with "/key". - // iavl.Store.Query() switches over the last path element, - // and performs key-value query only if it is "/key" - pathstr = pathstr + "/key" - - data := append(path.KeyPrefix, key...) - return abci.RequestQuery{Path: pathstr, Data: data, Prove: true} + return qres.Value, Proof{Key: key, Proof: qres.Proof}, nil } -func (path Path) Query(cms types.CommitMultiStore, key []byte) (uint32, []byte, Proof) { - queryable, ok := cms.(types.Queryable) - if !ok { - panic("CommitMultiStore not queryable") +func RequestQueryMultiStore(storeName string, prefix []byte, key []byte) abci.RequestQuery { + // Suffixing path with "/key". + // iavl.Store.Query() switches over the last path element, + // and performs key-value query only if it is "/key" + return abci.RequestQuery{ + Path: "/" + storeName + "/key", + Data: join(prefix, key), + Prove: true, } - qres := queryable.Query(path.RequestQuery(key)) - return qres.Code, qres.Value, Proof{Key: key, Proof: qres.Proof} } func (path Path) Key(key []byte) []byte { @@ -48,3 +42,57 @@ func join(a, b []byte) (res []byte) { copy(res[len(a):], b) return } + +/* + +// RequestQuery() constructs the abci.RequestQuery. +// +// RequestQuery.Path is a slash separated key list, ending with "/key" +// +// RequestQuery.Data is the concatanation of path.KeyPrefix and key argument +// +// RequestQuery.Prove is set to true +func (path Path) RequestQuery(key []byte) abci.RequestQuery { + req := path.RequestQueryMultiStore(key) + // BaseApp switches over the first path element, + // and performs KVStore query only if it is "/store" + req.Path = "/store" + req.Path + return req +} + + + +func (path Path) Query(ctx context.CLIContext, key []byte) (code uint32, value []byte, proof Proof, err error) { + resp, err := ctx.QueryABCI(path.RequestQuery(key)) + if err != nil { + return code, value, proof, err + } + if !resp.IsOK() { + return resp.Code, value, proof, errors.New(resp.Log) + } + return resp.Code, resp.Value, Proof{Key: key, Proof: resp.Proof}, nil +} + +func (path Path) QueryValue(ctx context.CLIContext, cdc *codec.Codec, key []byte, ptr interface{}) (Proof, error) { + _, value, proof, err := path.Query(ctx, key) + if err != nil { + return Proof{}, err + } + err = cdc.UnmarshalBinaryBare(value, ptr) // TODO + return proof, err +} + + + + + +func (path Path) Path() string { + pathstr := "" + for _, inter := range path.KeyPath { + // The Queryable() stores uses slash-separated keypath format for querying + pathstr = pathstr + "/" + string(inter) + } + + return pathstr +} +*/ diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index efb52a151a20..923a065334ea 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -3,6 +3,7 @@ package commitment import ( "bytes" "errors" + "fmt" ) // Store proves key-value pairs' inclusion or non-inclusion with @@ -11,7 +12,7 @@ type Store interface { Prove(key, value []byte) bool } -var _ Store = prefix{} +var _ Store = prefix{} // TODO: pointer type prefix struct { store Store @@ -29,7 +30,7 @@ func (prefix prefix) Prove(key, value []byte) bool { return prefix.store.Prove(join(prefix.prefix, key), value) } -var _ Store = store{} +var _ Store = (*store)(nil) type store struct { root Root @@ -41,13 +42,13 @@ type store struct { // NewStore constructs a new Store with the root, path, and proofs. // The proofs are not proven immediately because proofs require value bytes to verify. // If the kinds of the arguments don't match, returns error. -func NewStore(root Root, path Path, proofs []Proof) (res store, err error) { +func NewStore(root Root, path Path, proofs []Proof) (res *store, err error) { if root.CommitmentKind() != path.CommitmentKind() { err = errors.New("path type not matching with root's") return } - res = store{ + res = &store{ root: root, path: path, proofs: make(map[string]Proof), @@ -66,19 +67,20 @@ func NewStore(root Root, path Path, proofs []Proof) (res store, err error) { } // Get() returns the value only if it is already proven. -func (store store) Get(key []byte) ([]byte, bool) { +func (store *store) Get(key []byte) ([]byte, bool) { res, ok := store.verified[string(key)] return res, ok } // Prove() proves the key-value pair with the stored proof. -func (store store) Prove(key, value []byte) bool { +func (store *store) Prove(key, value []byte) bool { stored, ok := store.Get(key) if ok && bytes.Equal(stored, value) { return true } proof, ok := store.proofs[string(key)] if !ok { + fmt.Println(111, string(key)) return false } err := proof.Verify(store.root, store.path, value) @@ -91,7 +93,7 @@ func (store store) Prove(key, value []byte) bool { } // Proven() returns true if the key-value pair is already proven -func (store store) Proven(key []byte) bool { +func (store *store) Proven(key []byte) bool { _, ok := store.Get(key) return ok } diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 65297b91b361..947d322c06bd 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -34,8 +34,22 @@ func (m Mapping) Prefix(prefix []byte) Mapping { } } -// Value is for proving commitment proof on a speicifc key-value point in the other state -// using the already initialized commitment store. +type Indexer struct { + Mapping + enc state.IntEncoding +} + +func (m Mapping) Indexer(enc state.IntEncoding) Indexer { + return Indexer{ + Mapping: m, + enc: enc, + } +} + +func (ix Indexer) Value(index uint64) Value { + return ix.Mapping.Value(state.EncodeInt(index, ix.enc)) +} + type Value struct { m Mapping key []byte @@ -52,6 +66,7 @@ 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) } @@ -71,6 +86,30 @@ func (v Enum) Is(ctx sdk.Context, value byte) bool { return v.Value.IsRaw(ctx, []byte{value}) } +type String struct { + Value +} + +func (v Value) String() String { + return String{v} +} + +func (v String) Is(ctx sdk.Context, value string) bool { + return v.Value.IsRaw(ctx, []byte(value)) +} + +type Boolean struct { + Value +} + +func (v Value) Boolean() Boolean { + return Boolean{v} +} + +func (v Boolean) Is(ctx sdk.Context, value bool) bool { + return v.Value.Is(ctx, value) +} + // Integer is a uint64 types wrapper for Value. type Integer struct { Value From 17f18d735e10b733495c7fc2c495230a5ff4aae9 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 15 Aug 2019 20:42:09 +0900 Subject: [PATCH 199/378] merge from ics04 branch --- x/ibc/02-client/cli.go | 15 ++-- x/ibc/02-client/client/cli/query.go | 8 +-- x/ibc/02-client/keys.go | 5 ++ x/ibc/02-client/manager.go | 4 +- x/ibc/02-client/tendermint/codec.go | 1 - .../tendermint/tests/tendermint_test.go | 8 +-- x/ibc/02-client/tendermint/tests/types.go | 71 +++++++++++-------- x/ibc/02-client/tendermint/tests/utils.go | 8 +++ 8 files changed, 74 insertions(+), 46 deletions(-) create mode 100644 x/ibc/02-client/keys.go create mode 100644 x/ibc/02-client/tendermint/tests/utils.go diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index aa563f3c170b..db03c1441329 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -1,20 +1,25 @@ package client import ( + "bytes" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func (obj Object) ConsensusStateCLI(ctx context.CLIContext, path merkle.Path) (res ConsensusState, proof merkle.Proof, err error) { +func (obj Object) 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) - proof = merkle.NewProofFromValue(tmproof, path, obj.ConsensusState) + proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.ConsensusState) return } -func (obj Object) FrozenCLI(ctx context.CLIContext, path merkle.Path) (res bool, proof merkle.Proof, err error) { +func (obj Object) FrozenCLI(ctx context.CLIContext) (res bool, proof merkle.Proof, err error) { res, tmproof, err := obj.Frozen.Query(ctx) - proof = merkle.NewProofFromValue(tmproof, path, obj.Frozen) + 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 1cf445dae389..c4238dae8cdb 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -20,9 +20,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func mapping(cdc *codec.Codec, storeKey string, version int64) (state.Mapping, merkle.Path) { +func mapping(cdc *codec.Codec, storeKey string, version int64) state.Mapping { prefix := []byte(strconv.FormatInt(version, 10) + "/") - return state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix), merkle.NewPath([][]byte{[]byte(storeKey)}, prefix) + return state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) } func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { @@ -48,11 +48,11 @@ 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, path := mapping(cdc, storeKey, ibc.Version) + mapp := mapping(cdc, storeKey, ibc.Version) man := client.NewManager(mapp) id := args[0] - state, _, err := man.Object(id).ConsensusStateCLI(ctx, path) + state, _, err := man.Object(id).ConsensusStateCLI(ctx) if err != nil { return err } diff --git a/x/ibc/02-client/keys.go b/x/ibc/02-client/keys.go new file mode 100644 index 000000000000..a67761f20d36 --- /dev/null +++ b/x/ibc/02-client/keys.go @@ -0,0 +1,5 @@ +package client + +func LocalRoot() []byte { + return []byte("client/") +} diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index fe69a59caa05..eb9a83ff7d2e 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -17,7 +17,7 @@ type Manager struct { func NewManager(base state.Mapping) Manager { return Manager{ - protocol: base.Prefix([]byte("/client")), + protocol: base.Prefix(LocalRoot()), } } @@ -27,7 +27,7 @@ type CounterpartyManager struct { func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { return CounterpartyManager{ - protocol: commitment.NewMapping(cdc, []byte("/client")), + protocol: commitment.NewMapping(cdc, LocalRoot()), } } diff --git a/x/ibc/02-client/tendermint/codec.go b/x/ibc/02-client/tendermint/codec.go index eca3b38917fa..31a25031f9fc 100644 --- a/x/ibc/02-client/tendermint/codec.go +++ b/x/ibc/02-client/tendermint/codec.go @@ -2,7 +2,6 @@ package tendermint import ( "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client" ) diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/tendermint/tests/tendermint_test.go index 61a0944fbaa0..e7d09644126a 100644 --- a/x/ibc/02-client/tendermint/tests/tendermint_test.go +++ b/x/ibc/02-client/tendermint/tests/tendermint_test.go @@ -4,16 +4,14 @@ import ( "testing" "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) func testUpdate(t *testing.T, interval int, ok bool) { - node := NewNode(NewMockValidators(100, 10), newPath()) + node := NewNode(NewMockValidators(100, 10), "f8wib", []byte{0x98, 0x78}) - header := node.Commit() + _ = node.Commit() - verifier := node.LastStateVerifier(merkle.NewRoot(header.AppHash)) + verifier := node.LastStateVerifier() for i := 0; i < 100; i++ { header := node.Commit() diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 40caa5d6f041..027d3a28a5f5 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -3,6 +3,7 @@ package tendermint import ( "crypto/rand" "testing" + "bytes" "github.com/stretchr/testify/require" @@ -23,15 +24,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -// nolint: unused -func newPath() merkle.Path { - return merkle.NewPath([][]byte{[]byte("test")}, []byte{0x12, 0x34}) -} - const chainid = "testchain" -func defaultComponents() (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { - key := sdk.NewKVStoreKey("test") +func defaultComponents(storename string) (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { + key := sdk.NewKVStoreKey(storename) + db := dbm.NewMemDB() cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) @@ -54,21 +51,28 @@ type Node struct { Commits []tmtypes.SignedHeader - Path merkle.Path + StoreName string + Prefix []byte } -func NewNode(valset MockValidators, path merkle.Path) *Node { - key, ctx, cms, _ := defaultComponents() +func NewNode(valset MockValidators, storeName string, prefix []byte) *Node { + key, ctx, cms, _ := defaultComponents(storeName) + return &Node{ Valset: valset, Cms: cms, Key: key, Store: ctx.KVStore(key), Commits: nil, - Path: path, + StoreName: storeName, + Prefix: prefix, } } +func (node *Node) Path() merkle.Path { + return merkle.NewPath([][]byte{[]byte(node.StoreName)}, node.Prefix) +} + func (node *Node) Last() tmtypes.SignedHeader { if len(node.Commits) == 0 { return tmtypes.SignedHeader{} @@ -76,7 +80,7 @@ func (node *Node) Last() tmtypes.SignedHeader { return node.Commits[len(node.Commits)-1] } -func (node *Node) Commit() tmtypes.SignedHeader { +func (node *Node) Commit() tendermint.Header { valsethash := node.Valset.ValidatorSet().Hash() nextvalset := node.Valset.Mutate() nextvalsethash := nextvalset.ValidatorSet().Hash() @@ -100,11 +104,20 @@ func (node *Node) Commit() tmtypes.SignedHeader { node.Valset = nextvalset node.Commits = append(node.Commits, commit) - return commit + return tendermint.Header{ + SignedHeader: commit, + ValidatorSet: node.PrevValset.ValidatorSet(), + NextValidatorSet: node.Valset.ValidatorSet(), + } +} + +func (node *Node) LastStateVerifier() *Verifier { + return NewVerifier(node.Last(), node.Valset, node.Root()) } -func (node *Node) LastStateVerifier(root merkle.Root) *Verifier { - return NewVerifier(node.Last(), node.Valset, root) +func (node *Node) Root() merkle.Root { + return merkle.NewRoot(node.Last().AppHash) + } func (node *Node) Context() sdk.Context { @@ -126,14 +139,8 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root me } } -func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset MockValidators) error { - newcs, err := v.ConsensusState.Validate( - tendermint.Header{ - SignedHeader: header, - ValidatorSet: valset.ValidatorSet(), - NextValidatorSet: nextvalset.ValidatorSet(), - }, - ) +func (v *Verifier) Validate(header tendermint.Header, valset, nextvalset MockValidators) error { + newcs, err := v.ConsensusState.Validate(header) if err != nil { return err } @@ -142,19 +149,23 @@ func (v *Verifier) Validate(header tmtypes.SignedHeader, valset, nextvalset Mock return nil } -func (node *Node) Query(t *testing.T, path merkle.Path, k []byte) ([]byte, commitment.Proof) { - value, proof, err := merkle.QueryMultiStore(node.Cms, path, k) + +func (node *Node) Query(t *testing.T, k []byte) ([]byte, commitment.Proof) { + if bytes.HasPrefix(k, node.Prefix) { + k = bytes.TrimPrefix(k, node.Prefix) + } + value, proof, err := merkle.QueryMultiStore(node.Cms, node.StoreName, node.Prefix, k) require.NoError(t, err) return value, proof } func (node *Node) Set(k, value []byte) { - node.Store.Set(node.Path.Key(k), value) + node.Store.Set(join(node.Prefix, k), value) } // nolint:deadcode,unused func testProof(t *testing.T) { - node := NewNode(NewMockValidators(100, 10), newPath()) + node := NewNode(NewMockValidators(100, 10), "1", []byte{0x00, 0x01}) node.Commit() @@ -170,15 +181,17 @@ func testProof(t *testing.T) { kvps = append(kvps, cmn.KVPair{Key: k, Value: v}) node.Set(k, v) } + header := node.Commit() proofs := []commitment.Proof{} root := merkle.NewRoot(header.AppHash) for _, kvp := range kvps { - v, p := node.Query(t, node.Path, kvp.Key) + v, p := node.Query(t, kvp.Key) + require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } - cstore, err := commitment.NewStore(root, node.Path, proofs) + cstore, err := commitment.NewStore(root, node.Path(), proofs) require.NoError(t, err) for _, kvp := range kvps { diff --git a/x/ibc/02-client/tendermint/tests/utils.go b/x/ibc/02-client/tendermint/tests/utils.go new file mode 100644 index 000000000000..d5262a14a29b --- /dev/null +++ b/x/ibc/02-client/tendermint/tests/utils.go @@ -0,0 +1,8 @@ +package tendermint + +func join(a, b []byte) (res []byte) { + res = make([]byte, len(a)+len(b)) + copy(res, a) + copy(res[len(a):], b) + return +} From e1abf4950923de7ed47e37a2246cb6b12e152685 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 15 Aug 2019 20:47:07 +0900 Subject: [PATCH 200/378] merge from ics04 branch --- x/ibc/03-connection/cli.go | 2 - x/ibc/03-connection/manager.go | 4 +- x/ibc/03-connection/tests/connection_test.go | 39 +------------------ x/ibc/03-connection/tests/types.go | 41 ++++++++++++++++++++ 4 files changed, 45 insertions(+), 41 deletions(-) diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index 769792c16358..2a6c65d7c824 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -14,8 +14,6 @@ func (man Manager) CLIObject(connid, clientid string) Object { return obj } - - func (obj Object) prefix() []byte { return bytes.Split(obj.Connection.KeyBytes(), LocalRoot())[0] } diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index cc5da97a1386..f4e4d6432c29 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -133,7 +133,7 @@ func (obj Object) Sendable(ctx sdk.Context) bool { return kinds[obj.Kind.Get(ctx)].Sendable } -func (obj Object) Receivble(ctx sdk.Context) bool { +func (obj Object) Receivable(ctx sdk.Context) bool { return kinds[obj.Kind.Get(ctx)].Receivable } @@ -164,6 +164,7 @@ func (man Manager) create(ctx sdk.Context, id string, connection Connection, kin obj.Connection.Set(ctx, connection) obj.Kind.Set(ctx, kind) return + } // query() is used internally by the connection creators @@ -190,6 +191,7 @@ func (man Manager) Query(ctx sdk.Context, id string) (obj Object, err error) { if !obj.exists(ctx) { err = errors.New("Object not exists") return + } if !obj.Available.Get(ctx) { err = errors.New("Object not available") diff --git a/x/ibc/03-connection/tests/connection_test.go b/x/ibc/03-connection/tests/connection_test.go index 665f15b3142d..62a8e52fbf85 100644 --- a/x/ibc/03-connection/tests/connection_test.go +++ b/x/ibc/03-connection/tests/connection_test.go @@ -25,42 +25,5 @@ func TestHandshake(t *testing.T) { registerCodec(cdc) node := NewNode(tendermint.NewMockValidators(100, 10), tendermint.NewMockValidators(100, 10), cdc) - node.Commit() - node.Counterparty.Commit() - - node.CreateClient(t) - node.Counterparty.CreateClient(t) - - // self.OpenInit - node.OpenInit(t) - header := node.Commit() - - // counterparty.OpenTry - node.Counterparty.UpdateClient(t, header) - cliobj := node.CLIObject() - _, pconn := node.QueryValue(t, cliobj.Connection) - _, pstate := node.QueryValue(t, cliobj.State) - _, ptimeout := node.QueryValue(t, cliobj.NextTimeout) - _, 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) - header = node.Counterparty.Commit() - - // self.OpenAck - node.UpdateClient(t, header) - cliobj = node.Counterparty.CLIObject() - _, pconn = node.Counterparty.QueryValue(t, cliobj.Connection) - _, pstate = node.Counterparty.QueryValue(t, cliobj.State) - _, ptimeout = node.Counterparty.QueryValue(t, cliobj.NextTimeout) - _, pcounterclient = node.Counterparty.QueryValue(t, cliobj.CounterpartyClient) - node.OpenAck(t, pconn, pstate, ptimeout, 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) + node.Handshake(t) } diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index 29b7b0706721..9fbd375aa4b3 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -149,3 +149,44 @@ func (node *Node) OpenConfirm(t *testing.T, proofs ...commitment.Proof) { require.True(t, obj.Available.Get(ctx)) node.SetState(connection.CloseTry) } + +func (node *Node) Handshake(t *testing.T) { + node.Commit() + node.Counterparty.Commit() + + node.CreateClient(t) + node.Counterparty.CreateClient(t) + + // self.OpenInit + node.OpenInit(t) + header := node.Commit() + + // counterparty.OpenTry + node.Counterparty.UpdateClient(t, header) + cliobj := node.CLIObject() + _, pconn := node.QueryValue(t, cliobj.Connection) + _, pstate := node.QueryValue(t, cliobj.State) + _, ptimeout := node.QueryValue(t, cliobj.NextTimeout) + _, 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) + header = node.Counterparty.Commit() + + // self.OpenAck + node.UpdateClient(t, header) + cliobj = node.Counterparty.CLIObject() + _, pconn = node.Counterparty.QueryValue(t, cliobj.Connection) + _, pstate = node.Counterparty.QueryValue(t, cliobj.State) + _, ptimeout = node.Counterparty.QueryValue(t, cliobj.NextTimeout) + _, pcounterclient = node.Counterparty.QueryValue(t, cliobj.CounterpartyClient) + node.OpenAck(t, pconn, pstate, ptimeout, 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) +} From 71d2620c073342166c0b65c934cf29629859b68a Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 15 Aug 2019 20:50:54 +0900 Subject: [PATCH 201/378] fix lint --- x/ibc/23-commitment/codec.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ibc/23-commitment/codec.go b/x/ibc/23-commitment/codec.go index 5b6573497e86..e2639b78b4f9 100644 --- a/x/ibc/23-commitment/codec.go +++ b/x/ibc/23-commitment/codec.go @@ -4,7 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -// RegisterCodec registeres types declared in this package +// RegisterCodec registers types declared in this package func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*Root)(nil), nil) cdc.RegisterInterface((*Path)(nil), nil) From df2b7fe2d7502521b28b47df55686a26596f37b6 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 15 Aug 2019 21:15:38 +0900 Subject: [PATCH 202/378] add port --- x/ibc/04-channel/manager.go | 10 +++++++++- x/ibc/04-channel/port.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 x/ibc/04-channel/port.go diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index 6b76f7cef4c4..b5e2507ea9c9 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -20,6 +20,8 @@ type Manager struct { counterparty CounterpartyManager router Router + + ports map[string]struct{} } type CounterpartyManager struct { @@ -33,6 +35,8 @@ func NewManager(protocol state.Mapping, connection connection.Manager) Manager { protocol: protocol.Prefix(LocalRoot()), connection: connection, counterparty: NewCounterpartyManager(protocol.Cdc()), + + ports: make(map[string]struct{}), } } @@ -250,12 +254,16 @@ func (obj Object) exists(ctx sdk.Context) bool { return obj.Channel.Exists(ctx) } -func (obj Object) Send(ctx sdk.Context, packet Packet) error { +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) + if err != nil { + return err + } if obj.OriginConnection().Client.GetConsensusState(ctx).GetHeight() >= packet.Timeout() { return errors.New("timeout height higher than the latest known") diff --git a/x/ibc/04-channel/port.go b/x/ibc/04-channel/port.go new file mode 100644 index 000000000000..2b3505a50169 --- /dev/null +++ b/x/ibc/04-channel/port.go @@ -0,0 +1,37 @@ +package channel + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +type Port struct { + channel Manager + id string + valid *bool // once invalid forever invalid +} + +// bindPort, expected to be called only at init time +// TODO: is it safe to support runtime bindPort? +func (man Manager) Port(id string) Port { + if _, ok := man.ports[id]; ok { + panic("port already occupied") + } + man.ports[id] = struct{}{} + valid := true + return Port{man, id, &valid} +} + +// releasePort +func (port Port) Release() { + delete(port.channel.ports, port.id) + *port.valid = false +} + +func (port Port) Send(ctx sdk.Context, chanid string, packet Packet) error { + return port.channel.Send(ctx, port.id, 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) +} From 51303fd58454cfdc2e76cb518fafb0dda87756ed Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 15 Aug 2019 21:16:39 +0900 Subject: [PATCH 203/378] fix test --- x/ibc/04-channel/tests/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index 651a3665827a..22c8234fbabe 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -158,7 +158,7 @@ func (node *Node) Send(t *testing.T, packet channel.Packet) { obj, err := man.Query(ctx, node.Name, node.Name) require.NoError(t, err) seq := obj.SeqSend.Get(ctx) - err = obj.Send(ctx, packet) + err = man.Send(ctx, node.Name, 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)) From c60fd53096e6fd766f69e36e64fe1ac26c263390 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 21 Aug 2019 16:00:06 +0200 Subject: [PATCH 204/378] add mocks --- x/ibc/02-client/client/cli/query.go | 4 +- x/ibc/03-connection/client/cli/query.go | 9 ++-- x/ibc/03-connection/client/cli/tx.go | 12 ++--- x/ibc/04-channel/codec.go | 2 + x/ibc/04-channel/handler.go | 4 +- x/ibc/04-channel/msgs.go | 42 ++++++++-------- x/ibc/04-channel/tests/channel_test.go | 3 +- x/ibc/04-channel/types.go | 12 ++++- x/ibc/ante.go | 64 +++++++++++++++++++++++++ x/ibc/handler.go | 39 +++++++++++++++ x/ibc/mock/packets.go | 63 ++++++++++++++++++++++++ x/ibc/msg.go | 19 ++++++++ x/ibc/types.go | 7 +++ x/ibc/version.go | 9 ---- x/ibc/version/version.go | 13 +++++ 15 files changed, 253 insertions(+), 49 deletions(-) create mode 100644 x/ibc/ante.go create mode 100644 x/ibc/handler.go create mode 100644 x/ibc/mock/packets.go create mode 100644 x/ibc/msg.go create mode 100644 x/ibc/types.go delete mode 100644 x/ibc/version.go create mode 100644 x/ibc/version/version.go diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index c4238dae8cdb..6dd79d353a67 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -14,10 +14,10 @@ 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 { @@ -48,7 +48,7 @@ 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) + mapp := mapping(cdc, storeKey, version.Version) man := client.NewManager(mapp) id := args[0] diff --git a/x/ibc/03-connection/client/cli/query.go b/x/ibc/03-connection/client/cli/query.go index efc330969faa..c11c1f059a08 100644 --- a/x/ibc/03-connection/client/cli/query.go +++ b/x/ibc/03-connection/client/cli/query.go @@ -12,17 +12,16 @@ 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 { base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) climan := client.NewManager(base) @@ -80,7 +79,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..32df94715bd0 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -13,10 +13,10 @@ import ( "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" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + 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" ) /* @@ -80,7 +80,7 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } - obj1, err := handshake(ctx1, cdc, storeKey, ibc.VersionPrefix(ibc.Version), conn1id) + obj1, err := handshake(ctx1, cdc, storeKey, version.DefaultPrefix(), conn1id) if err != nil { return err } @@ -95,7 +95,7 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } - obj2, err := handshake(ctx2, cdc, storeKey, ibc.VersionPrefix(ibc.Version), conn1id) + obj2, err := handshake(ctx2, cdc, storeKey, version.DefaultPrefix(), conn1id) if err != nil { return err } diff --git a/x/ibc/04-channel/codec.go b/x/ibc/04-channel/codec.go index 4da636c4edc7..922009db6bd8 100644 --- a/x/ibc/04-channel/codec.go +++ b/x/ibc/04-channel/codec.go @@ -4,6 +4,8 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) +var msgCdc = codec.New() + func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*Packet)(nil), nil) } diff --git a/x/ibc/04-channel/handler.go b/x/ibc/04-channel/handler.go index 02c2c334fb45..078effaa433c 100644 --- a/x/ibc/04-channel/handler.go +++ b/x/ibc/04-channel/handler.go @@ -38,8 +38,8 @@ func HandleMsgOpenConfirm(ctx sdk.Context, msg MsgOpenConfirm, man Handshaker) s 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) +func HandleMsgPacket(ctx sdk.Context, msg MsgPacket, man Manager) sdk.Result { + err := man.Receive(ctx, msg.Proofs, msg.PortID, msg.ChannelID, msg.Packet) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), 500, "").Result() } diff --git a/x/ibc/04-channel/msgs.go b/x/ibc/04-channel/msgs.go index ba35f0bbc406..adb53c7e62c0 100644 --- a/x/ibc/04-channel/msgs.go +++ b/x/ibc/04-channel/msgs.go @@ -2,8 +2,7 @@ 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" @@ -133,32 +132,33 @@ 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 +type MsgPacket struct { + Packet `json:"packet" yaml:"packet"` + // PortID, ChannelID can be empty if batched & not first MsgPacket + PortID string `json:"port_id,omitempty" yaml:"port_id"` + ChannelID string `json:"channel_id,omitempty" yaml:"channel_id"` + // Height uint64 // height of the commitment root for the proofs + Proofs []commitment.Proof `json:"proofs" yaml:"proofs"` + 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 MsgReceive) Type() string { - return "receive" -} - -func (msg MsgReceive) ValidateBasic() sdk.Error { +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) GetSignBytes() []byte { - return nil // TODO +func (msg MsgPacket) GetSignBytes() []byte { + return msgCdc.MustMarshalJSON(msg) // TODO: Sort } -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/tests/channel_test.go b/x/ibc/04-channel/tests/channel_test.go index 82d27dca8089..366eaae8277d 100644 --- a/x/ibc/04-channel/tests/channel_test.go +++ b/x/ibc/04-channel/tests/channel_test.go @@ -36,11 +36,10 @@ type MyPacket struct { Message string } -/* func (packet MyPacket) Commit() []byte { return []byte(packet.Message) } -*/ + func (packet MyPacket) Timeout() uint64 { return 100 // TODO } diff --git a/x/ibc/04-channel/types.go b/x/ibc/04-channel/types.go index fe25a08dfc5f..0a95624cf39c 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,9 +19,13 @@ type Packet struct { */ type Packet interface { - Timeout() uint64 - // Commit() []byte // Can be a commit message Route() string + Type() string + ValidateBasic() sdk.Error + String() string + Timeout() uint64 + MarshalAmino() (string, error) + MarshalJSON() ([]byte, error) } type Channel struct { diff --git a/x/ibc/ante.go b/x/ibc/ante.go new file mode 100644 index 000000000000..916f4445ce8f --- /dev/null +++ b/x/ibc/ante.go @@ -0,0 +1,64 @@ +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.PortID) != 0 && msg.PortID != first.PortID { + return res, true + } + msg.PortID = first.PortID + 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.PortID, 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/handler.go b/x/ibc/handler.go new file mode 100644 index 000000000000..9614e00a1c30 --- /dev/null +++ b/x/ibc/handler.go @@ -0,0 +1,39 @@ +package ibc + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// IBC Handler should not return error. Returning error will make the channel +// not able to be proceed. Send receipt packet when the packet is non executable. +type Handler func(ctx sdk.Context, packet Packet) + +/* +type ReturnHandler func(ctx sdk.Context, packet sdk.Packet) sdk.Packet +*/ + +func WrapHandler(h Handler, sdkh sdk.Handler) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case MsgPacket: + h(ctx, msg.Packet) + return sdk.Result{Events:ctx.EventManager().Events()} + default: + return sdkh(ctx, msg) + } + } +} + +// TODO +/* +func WrapReturnHandler(h ReturnHandler) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + receipt := h(ctx, msg.Packet) + if receipt != nil { + // Send receipt packet to the receipt channel + } + + return sdk.Result{Events: ctx.EventManager().Events()} + } +} +*/ diff --git a/x/ibc/mock/packets.go b/x/ibc/mock/packets.go new file mode 100644 index 000000000000..5e649b1300e4 --- /dev/null +++ b/x/ibc/mock/packets.go @@ -0,0 +1,63 @@ +package mock + +import ( + "errors" + "fmt" + "strings" + "strconv" + "bytes" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc" +) + +var _ ibc.Packet = SequencePacket{} + +type SequencePacket struct { + Sequence uint64 +} + +func (packet SequencePacket) MarshalAmino() (string, error) { + return fmt.Sprintf("sequence-packet-%d", packet.Sequence), nil +} + +func (packet *SequencePacket) UnmarshalAmino(text string) (err error) { + if !strings.HasPrefix(text, "sequence-packet-") { + return errors.New("invalid SequencePacket string") + } + packet.Sequence, err = strconv.ParseUint(strings.TrimPrefix(text, "sequence-packet-"), 10, 64) + return +} + +func (packet SequencePacket) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf("\"sequence-packet-%d\"", packet.Sequence)), nil +} + +func (packet *SequencePacket) UnmarshalJSON(bz []byte) (err error) { + bz = bz[1:len(bz)-1] + if !bytes.HasPrefix(bz, []byte("sequence-packet-")) { + return errors.New("invalid SequencePacket string") + } + packet.Sequence, err = strconv.ParseUint(strings.TrimPrefix(string(bz), "sequence-packet-"), 10, 64) + return +} + +func (SequencePacket) Route() string { + return "ibc-mock" +} + +func (SequencePacket) String() string { + return "sequence-packet" +} + +func (SequencePacket) Timeout() uint64 { + return 0 +} + +func (SequencePacket) Type() string { + return "empty-packet" +} + +func (SequencePacket) ValidateBasic() sdk.Error { + return nil +} diff --git a/x/ibc/msg.go b/x/ibc/msg.go new file mode 100644 index 000000000000..fc05da83d817 --- /dev/null +++ b/x/ibc/msg.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..5ccf47815198 --- /dev/null +++ b/x/ibc/types.go @@ -0,0 +1,7 @@ +package ibc + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" +) + +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..5c80adf66a24 --- /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(strconv.FormatInt(version, 10) + "/") +} From ee9bad2ac9d0566741ae46212badfc73699384a5 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 21 Aug 2019 17:40:14 +0200 Subject: [PATCH 205/378] fix connid -> portid in handshake.go --- x/ibc/04-channel/handshake.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index 48faa877b838..76e372bb929f 100644 --- a/x/ibc/04-channel/handshake.go +++ b/x/ibc/04-channel/handshake.go @@ -86,8 +86,8 @@ func (man CounterpartyHandshaker) object(parent CounterObject) CounterHandshakeO } } -func (man Handshaker) create(ctx sdk.Context, connid, chanid string, channel Channel) (obj HandshakeObject, err error) { - cobj, err := man.man.create(ctx, connid, chanid, channel) +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) if err != nil { return } @@ -96,8 +96,8 @@ func (man Handshaker) create(ctx sdk.Context, connid, chanid string, channel Cha return obj, nil } -func (man Handshaker) query(ctx sdk.Context, connid, chanid string) (obj HandshakeObject, err error) { - cobj, err := man.man.query(ctx, connid, chanid) +func (man Handshaker) query(ctx sdk.Context, portid, chanid string) (obj HandshakeObject, err error) { + cobj, err := man.man.query(ctx, portid, chanid) if err != nil { return } @@ -125,7 +125,7 @@ func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { // Using proofs: none func (man Handshaker) OpenInit(ctx sdk.Context, - connid, chanid string, channel Channel, nextTimeoutHeight uint64, + portid, chanid string, channel Channel, nextTimeoutHeight uint64, ) (HandshakeObject, error) { // man.Create() will ensure // assert(connectionHops.length === 2) @@ -135,7 +135,7 @@ func (man Handshaker) OpenInit(ctx sdk.Context, return HandshakeObject{}, errors.New("ConnectionHops length must be 1") } - obj, err := man.create(ctx, connid, chanid, channel) + obj, err := man.create(ctx, portid, chanid, channel) if err != nil { return HandshakeObject{}, err } @@ -214,9 +214,9 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} func (man Handshaker) OpenAck(ctx sdk.Context, proofs []commitment.Proof, - connid, chanid string, timeoutHeight, nextTimeoutHeight uint64, + portid, chanid string, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { - obj, err = man.query(ctx, connid, chanid) + obj, err = man.query(ctx, portid, chanid) if err != nil { return } @@ -275,8 +275,8 @@ func (man Handshaker) OpenAck(ctx sdk.Context, // Using proofs: counterparty.{connection,state, nextTimeout} func (man Handshaker) OpenConfirm(ctx sdk.Context, proofs []commitment.Proof, - connid, chanid string, timeoutHeight uint64) (obj HandshakeObject, err error) { - obj, err = man.query(ctx, connid, chanid) + portid, chanid string, timeoutHeight uint64) (obj HandshakeObject, err error) { + obj, err = man.query(ctx, portid, chanid) if err != nil { return } From 649ea6e2c184c2279b8c457fcf60e55434be4048 Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 26 Aug 2019 16:14:01 +0200 Subject: [PATCH 206/378] add mock --- x/ibc/04-channel/events.go | 10 ++++++ x/ibc/04-channel/handler.go | 11 ------ x/ibc/04-channel/manager.go | 17 +++++++-- x/ibc/04-channel/msgs.go | 8 +++-- x/ibc/04-channel/port.go | 3 ++ x/ibc/04-channel/router.go | 34 ------------------ x/ibc/04-channel/tests/channel_test.go | 40 +++++++++++++++++++-- x/ibc/04-channel/types.go | 8 ++--- x/ibc/ante.go | 8 ++--- x/ibc/handler.go | 39 -------------------- x/ibc/mock/handler.go | 28 +++++++++++++++ x/ibc/mock/keeper.go | 49 ++++++++++++++++++++++++++ x/ibc/mock/packets.go | 12 ++++--- x/ibc/types.go | 4 ++- 14 files changed, 166 insertions(+), 105 deletions(-) create mode 100644 x/ibc/04-channel/events.go delete mode 100644 x/ibc/04-channel/router.go delete mode 100644 x/ibc/handler.go create mode 100644 x/ibc/mock/handler.go create mode 100644 x/ibc/mock/keeper.go 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 078effaa433c..76d9ace3e6e4 100644 --- a/x/ibc/04-channel/handler.go +++ b/x/ibc/04-channel/handler.go @@ -35,14 +35,3 @@ func HandleMsgOpenConfirm(ctx sdk.Context, msg MsgOpenConfirm, man Handshaker) s } return sdk.Result{} } - -type Handler func(sdk.Context, Packet) sdk.Result - -func HandleMsgPacket(ctx sdk.Context, msg MsgPacket, man Manager) sdk.Result { - err := man.Receive(ctx, msg.Proofs, msg.PortID, 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/manager.go b/x/ibc/04-channel/manager.go index b5e2507ea9c9..e7c2e1a2ee14 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" @@ -19,8 +20,6 @@ type Manager struct { counterparty CounterpartyManager - router Router - ports map[string]struct{} } @@ -260,6 +259,10 @@ func (man Manager) Send(ctx sdk.Context, portid, chanid string, packet Packet) e return errors.New("cannot send Packets on this channel") } */ + if portid != packet.SenderPort() { + return errors.New("Invalid portid") + } + obj, err := man.Query(ctx, portid, chanid) if err != nil { return err @@ -271,6 +274,16 @@ func (man Manager) Send(ctx sdk.Context, portid, chanid string, packet Packet) e obj.Packets.Set(ctx, obj.SeqSend.Incr(ctx), packet) + 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 } diff --git a/x/ibc/04-channel/msgs.go b/x/ibc/04-channel/msgs.go index adb53c7e62c0..c12f4a338b1a 100644 --- a/x/ibc/04-channel/msgs.go +++ b/x/ibc/04-channel/msgs.go @@ -134,8 +134,8 @@ func (msg MsgOpenConfirm) GetSigners() []sdk.AccAddress { type MsgPacket struct { Packet `json:"packet" yaml:"packet"` - // PortID, ChannelID can be empty if batched & not first MsgPacket - PortID string `json:"port_id,omitempty" yaml:"port_id"` + // PortID dependent on type + // ChannelID can be empty if batched & not first MsgPacket ChannelID string `json:"channel_id,omitempty" yaml:"channel_id"` // Height uint64 // height of the commitment root for the proofs Proofs []commitment.Proof `json:"proofs" yaml:"proofs"` @@ -152,6 +152,10 @@ func (msg MsgPacket) ValidateBasic() sdk.Error { return nil // TODO } +func (msg MsgPacket) Route() string { + return msg.ReceiverPort() +} + func (msg MsgPacket) GetSignBytes() []byte { return msgCdc.MustMarshalJSON(msg) // TODO: Sort } diff --git a/x/ibc/04-channel/port.go b/x/ibc/04-channel/port.go index 2b3505a50169..dfa8738655b2 100644 --- a/x/ibc/04-channel/port.go +++ b/x/ibc/04-channel/port.go @@ -29,6 +29,9 @@ func (port Port) Release() { } func (port Port) Send(ctx sdk.Context, chanid string, packet Packet) error { + if packet.SenderPort() != port.id { + panic("Packet sent on wrong port") + } return port.channel.Send(ctx, 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 366eaae8277d..b3c79ca70779 100644 --- a/x/ibc/04-channel/tests/channel_test.go +++ b/x/ibc/04-channel/tests/channel_test.go @@ -2,7 +2,9 @@ package channel import ( "testing" + "errors" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/codec" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" @@ -44,8 +46,42 @@ func (packet MyPacket) Timeout() uint64 { return 100 // TODO } -func (MyPacket) Route() string { - return "my" +func (MyPacket) SenderPort() string { + return "channel-test" +} + +func (MyPacket) ReceiverPort() string { + return "channel-test" +} + +func (MyPacket) Type() string { + return "my-packet" +} + +func (MyPacket) ValidateBasic() sdk.Error { + return nil +} + +func (packet MyPacket) MarshalAmino() (string, error) { + return "mp-"+packet.Message, nil +} + +func (packet *MyPacket) UnmarshalAmino(text string) error { + if text[:3] != "mp-" { + return errors.New("Invalid text for MyPacket") + } + packet.Message = text[3:] + return nil +} + +func (packet MyPacket) MarshalJSON() ([]byte, error) { + res, _ := packet.MarshalAmino() + return []byte("\""+res+"\""), nil +} + +func (packet *MyPacket) UnmarshalJSON(bz []byte) error { + bz = bz[1:len(bz)-1] + return packet.UnmarshalAmino(string(bz)) } func TestPacket(t *testing.T) { diff --git a/x/ibc/04-channel/types.go b/x/ibc/04-channel/types.go index 0a95624cf39c..d186a786bb2d 100644 --- a/x/ibc/04-channel/types.go +++ b/x/ibc/04-channel/types.go @@ -19,13 +19,13 @@ type Packet struct { */ type Packet interface { - Route() string + SenderPort() string + ReceiverPort() string // == Route() Type() string ValidateBasic() sdk.Error - String() string Timeout() uint64 - MarshalAmino() (string, error) - MarshalJSON() ([]byte, error) + MarshalAmino() (string, error) // Should exclude PortID/ChannelID info + MarshalJSON() ([]byte, error) // Should exclude PortID/ChannelID info } type Channel struct { diff --git a/x/ibc/ante.go b/x/ibc/ante.go index 916f4445ce8f..696275ea08a6 100644 --- a/x/ibc/ante.go +++ b/x/ibc/ante.go @@ -19,10 +19,6 @@ func ExtractMsgPackets(msgs []sdk.Msg) (res []MsgPacket, abort bool) { if len(res) >= 2 { first := res[0] for _, msg := range res[1:] { - if len(msg.PortID) != 0 && msg.PortID != first.PortID { - return res, true - } - msg.PortID = first.PortID if len(msg.ChannelID) != 0 && msg.ChannelID != first.ChannelID { return res, true } @@ -35,7 +31,7 @@ func ExtractMsgPackets(msgs []sdk.Msg) (res []MsgPacket, abort bool) { func VerifyMsgPackets(ctx sdk.Context, channel channel.Manager, msgs []MsgPacket) error { for _, msg := range msgs { - err := channel.Receive(ctx, msg.Proofs, msg.PortID, msg.ChannelID, msg.Packet) + err := channel.Receive(ctx, msg.Proofs, msg.ReceiverPort(), msg.ChannelID, msg.Packet) if err != nil { return err } @@ -59,6 +55,6 @@ func NewAnteHandler(channel channel.Manager) sdk.AnteHandler { return } - return ctx, res, false + return ctx, res, false } } diff --git a/x/ibc/handler.go b/x/ibc/handler.go deleted file mode 100644 index 9614e00a1c30..000000000000 --- a/x/ibc/handler.go +++ /dev/null @@ -1,39 +0,0 @@ -package ibc - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// IBC Handler should not return error. Returning error will make the channel -// not able to be proceed. Send receipt packet when the packet is non executable. -type Handler func(ctx sdk.Context, packet Packet) - -/* -type ReturnHandler func(ctx sdk.Context, packet sdk.Packet) sdk.Packet -*/ - -func WrapHandler(h Handler, sdkh sdk.Handler) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case MsgPacket: - h(ctx, msg.Packet) - return sdk.Result{Events:ctx.EventManager().Events()} - default: - return sdkh(ctx, msg) - } - } -} - -// TODO -/* -func WrapReturnHandler(h ReturnHandler) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - receipt := h(ctx, msg.Packet) - if receipt != nil { - // Send receipt packet to the receipt channel - } - - return sdk.Result{Events: ctx.EventManager().Events()} - } -} -*/ diff --git a/x/ibc/mock/handler.go b/x/ibc/mock/handler.go new file mode 100644 index 000000000000..659e84ea5c1f --- /dev/null +++ b/x/ibc/mock/handler.go @@ -0,0 +1,28 @@ +package mock + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/cosmos-sdk/x/ibc" +) + +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 SequencePacket: + return handleMyPacket(ctx, k, packet, msg.ChannelID) + } + } + return sdk.ErrUnknownRequest("21345").Result() + } +} + +func handleMyPacket(ctx sdk.Context, k Keeper, packet SequencePacket, chanid string) (res sdk.Result) { + err := k.CheckAndSetSequence(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/keeper.go b/x/ibc/mock/keeper.go new file mode 100644 index 000000000000..c1b27635e5ff --- /dev/null +++ b/x/ibc/mock/keeper.go @@ -0,0 +1,49 @@ +package mock + +import ( + "errors" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc" +) + +var sequence = []byte("sequence") + +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(sequence) { + k.cdc.MustUnmarshalBinaryBare(store.Get(sequence), &res) + } else { + res = 0 + } + + return +} + +func (k Keeper) SetSequence(ctx sdk.Context, chanid string, seq uint64) { + store := ctx.KVStore(k.key) + store.Set(sequence, k.cdc.MustMarshalBinaryBare(seq)) +} + +func (k Keeper) CheckAndSetSequence(ctx sdk.Context, chanid string, seq uint64) error { + if k.GetSequence(ctx, chanid)+1 != seq { + return errors.New("fjidow;af") + } + k.SetSequence(ctx, chanid, seq) + return nil +} diff --git a/x/ibc/mock/packets.go b/x/ibc/mock/packets.go index 5e649b1300e4..20f53f65d7e1 100644 --- a/x/ibc/mock/packets.go +++ b/x/ibc/mock/packets.go @@ -1,11 +1,11 @@ package mock import ( + "bytes" "errors" "fmt" - "strings" "strconv" - "bytes" + "strings" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc" @@ -34,7 +34,7 @@ func (packet SequencePacket) MarshalJSON() ([]byte, error) { } func (packet *SequencePacket) UnmarshalJSON(bz []byte) (err error) { - bz = bz[1:len(bz)-1] + bz = bz[1 : len(bz)-1] if !bytes.HasPrefix(bz, []byte("sequence-packet-")) { return errors.New("invalid SequencePacket string") } @@ -42,7 +42,11 @@ func (packet *SequencePacket) UnmarshalJSON(bz []byte) (err error) { return } -func (SequencePacket) Route() string { +func (SequencePacket) SenderPort() string { + return "ibc-mock" +} + +func (SequencePacket) ReceiverPort() string { return "ibc-mock" } diff --git a/x/ibc/types.go b/x/ibc/types.go index 5ccf47815198..be9303d07504 100644 --- a/x/ibc/types.go +++ b/x/ibc/types.go @@ -1,7 +1,9 @@ package ibc import ( - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" ) +type Port = channel.Port + type Packet = channel.Packet From 5ea508b3a73c3cd90964fb96b4f3eb988795b0da Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 2 Sep 2019 15:57:13 +0200 Subject: [PATCH 207/378] add ibc module.go, finalize mock --- x/ibc/02-client/client/cli/tx.go | 8 +- x/ibc/03-connection/client/cli/tx.go | 15 ++- x/ibc/04-channel/cli.go | 4 +- x/ibc/04-channel/handshake.go | 12 +- x/ibc/mock/client/cli/query.go | 53 +++++++++ x/ibc/mock/client/cli/tx.go | 53 +++++++++ x/ibc/mock/codec.go | 10 ++ x/ibc/mock/handler.go | 5 +- x/ibc/mock/keeper.go | 9 +- x/ibc/mock/module.go | 102 +++++++++++++++++ x/ibc/mock/types/keys.go | 3 + x/ibc/mock/types/msgs.go | 42 +++++++ x/ibc/mock/{ => types}/packets.go | 30 ++--- x/ibc/module.go | 164 +++++++++++++++++++++++++++ 14 files changed, 475 insertions(+), 35 deletions(-) create mode 100644 x/ibc/mock/client/cli/query.go create mode 100644 x/ibc/mock/client/cli/tx.go create mode 100644 x/ibc/mock/codec.go create mode 100644 x/ibc/mock/module.go create mode 100644 x/ibc/mock/types/keys.go create mode 100644 x/ibc/mock/types/msgs.go rename x/ibc/mock/{ => types}/packets.go (53%) create mode 100644 x/ibc/module.go 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/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index 32df94715bd0..c889015c8b2c 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -52,7 +52,20 @@ 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 +} + +func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "handshake", Short: "initiate connection handshake between two chains", diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index acfbb9bd8d0f..2462a11f4eda 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -64,7 +64,7 @@ func (obj Object) PacketCLI(ctx context.CLIContext, index uint64) (res Packet, p } func (man Handshaker) CLIQuery(ctx context.CLIContext, portid, chanid string) (HandshakeObject, error) { - obj, err := man.man.CLIQuery(ctx, portid, chanid) + obj, err := man.Manager.CLIQuery(ctx, portid, chanid) if err != nil { return HandshakeObject{}, err } @@ -72,7 +72,7 @@ func (man Handshaker) CLIQuery(ctx context.CLIContext, portid, chanid string) (H } func (man Handshaker) CLIObject(portid, chanid string, connids []string) HandshakeObject { - return man.object(man.man.CLIObject(portid, chanid, connids)) + return man.object(man.Manager.CLIObject(portid, chanid, connids)) } func (obj HandshakeObject) StateCLI(ctx context.CLIContext) (res State, proof merkle.Proof, err error) { diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index 48faa877b838..16dbcc0cb2ac 100644 --- a/x/ibc/04-channel/handshake.go +++ b/x/ibc/04-channel/handshake.go @@ -21,7 +21,7 @@ const ( ) type Handshaker struct { - man Manager + Manager counterparty CounterpartyHandshaker } @@ -35,7 +35,7 @@ func (man Handshaker) Kind() string { // or add Seal() method to Manager? func NewHandshaker(man Manager) Handshaker { return Handshaker{ - man: man, + Manager: man, counterparty: CounterpartyHandshaker{man.counterparty}, } @@ -68,8 +68,8 @@ func (man Handshaker) object(parent Object) HandshakeObject { return HandshakeObject{ Object: parent, - State: man.man.protocol.Value([]byte(prefix + "/state")).Enum(), - NextTimeout: man.man.protocol.Value([]byte(prefix + "/timeout")).Integer(state.Dec), + State: man.protocol.Value([]byte(prefix + "/state")).Enum(), + NextTimeout: man.protocol.Value([]byte(prefix + "/timeout")).Integer(state.Dec), counterparty: man.counterparty.object(parent.counterparty), } @@ -87,7 +87,7 @@ func (man CounterpartyHandshaker) object(parent CounterObject) CounterHandshakeO } func (man Handshaker) create(ctx sdk.Context, connid, chanid string, channel Channel) (obj HandshakeObject, err error) { - cobj, err := man.man.create(ctx, connid, chanid, channel) + cobj, err := man.Manager.create(ctx, connid, chanid, channel) if err != nil { return } @@ -97,7 +97,7 @@ func (man Handshaker) create(ctx sdk.Context, connid, chanid string, channel Cha } func (man Handshaker) query(ctx sdk.Context, connid, chanid string) (obj HandshakeObject, err error) { - cobj, err := man.man.query(ctx, connid, chanid) + cobj, err := man.Manager.query(ctx, connid, chanid) if err != nil { return } diff --git a/x/ibc/mock/client/cli/query.go b/x/ibc/mock/client/cli/query.go new file mode 100644 index 000000000000..a3817350902a --- /dev/null +++ b/x/ibc/mock/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: "ibcmock", + Short: "Querying commands for the ibcmock 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, 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/client/cli/tx.go b/x/ibc/mock/client/cli/tx.go new file mode 100644 index 000000000000..996baa46dc37 --- /dev/null +++ b/x/ibc/mock/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: "ibctypes", + Short: "IBC types module transaction subcommands", + RunE: client.ValidateCmd, + } + txCmd.AddCommand( + SequenceTxCmd(cdc), + ) + + return txCmd +} + +func SequenceTxCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "sequence [from-key-or-address] [channel-id] [sequence]", + Short: "Send SequencePacket", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + ctx := context.NewCLIContextWithFrom(args[0]).WithCodec(cdc) + + chanid := args[1] + seq, err := strconv.ParseUint(args[2], 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/codec.go b/x/ibc/mock/codec.go new file mode 100644 index 000000000000..20812bf738e8 --- /dev/null +++ b/x/ibc/mock/codec.go @@ -0,0 +1,10 @@ +package mock + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/types" +) + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(types.PacketSequence{}, "ibcmock/types.PacketSequence", nil) +} diff --git a/x/ibc/mock/handler.go b/x/ibc/mock/handler.go index 659e84ea5c1f..aa7b8168b62e 100644 --- a/x/ibc/mock/handler.go +++ b/x/ibc/mock/handler.go @@ -4,6 +4,7 @@ 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 { @@ -11,7 +12,7 @@ func NewHandler(k Keeper) sdk.Handler { switch msg := msg.(type) { case ibc.MsgPacket: switch packet := msg.Packet.(type) { - case SequencePacket: + case types.PacketSequence: return handleMyPacket(ctx, k, packet, msg.ChannelID) } } @@ -19,7 +20,7 @@ func NewHandler(k Keeper) sdk.Handler { } } -func handleMyPacket(ctx sdk.Context, k Keeper, packet SequencePacket, chanid string) (res sdk.Result) { +func handleMyPacket(ctx sdk.Context, k Keeper, packet types.PacketSequence, chanid string) (res sdk.Result) { err := k.CheckAndSetSequence(ctx, chanid, packet.Sequence) if err != nil { res.Log = "Invalid sequence" // should not return error, set only log diff --git a/x/ibc/mock/keeper.go b/x/ibc/mock/keeper.go index c1b27635e5ff..953dc889cf32 100644 --- a/x/ibc/mock/keeper.go +++ b/x/ibc/mock/keeper.go @@ -6,10 +6,9 @@ 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" ) -var sequence = []byte("sequence") - type Keeper struct { cdc *codec.Codec key sdk.StoreKey @@ -26,8 +25,8 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, port ibc.Port) Keeper { func (k Keeper) GetSequence(ctx sdk.Context, chanid string) (res uint64) { store := ctx.KVStore(k.key) - if store.Has(sequence) { - k.cdc.MustUnmarshalBinaryBare(store.Get(sequence), &res) + if store.Has(types.SequenceKey) { + k.cdc.MustUnmarshalBinaryBare(store.Get(types.SequenceKey), &res) } else { res = 0 } @@ -37,7 +36,7 @@ func (k Keeper) GetSequence(ctx sdk.Context, chanid string) (res uint64) { func (k Keeper) SetSequence(ctx sdk.Context, chanid string, seq uint64) { store := ctx.KVStore(k.key) - store.Set(sequence, k.cdc.MustMarshalBinaryBare(seq)) + store.Set(types.SequenceKey, k.cdc.MustMarshalBinaryBare(seq)) } func (k Keeper) CheckAndSetSequence(ctx sdk.Context, chanid string, seq uint64) error { diff --git a/x/ibc/mock/module.go b/x/ibc/mock/module.go new file mode 100644 index 000000000000..79aab119570d --- /dev/null +++ b/x/ibc/mock/module.go @@ -0,0 +1,102 @@ +package mock + +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/client/cli" +) + +const ( + ModuleName = "ibcmock" +) + +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) { + 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 (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/keys.go b/x/ibc/mock/types/keys.go new file mode 100644 index 000000000000..2e69fd34755e --- /dev/null +++ b/x/ibc/mock/types/keys.go @@ -0,0 +1,3 @@ +package types + +var SequenceKey = []byte("sequence") diff --git a/x/ibc/mock/types/msgs.go b/x/ibc/mock/types/msgs.go new file mode 100644 index 000000000000..1cd26b66a984 --- /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 cdc.MustMarshalJSON(msg) // TODO +} + +func (msg MsgSequence) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} diff --git a/x/ibc/mock/packets.go b/x/ibc/mock/types/packets.go similarity index 53% rename from x/ibc/mock/packets.go rename to x/ibc/mock/types/packets.go index 20f53f65d7e1..5daf0147756b 100644 --- a/x/ibc/mock/packets.go +++ b/x/ibc/mock/types/packets.go @@ -1,4 +1,4 @@ -package mock +package types import ( "bytes" @@ -11,57 +11,57 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc" ) -var _ ibc.Packet = SequencePacket{} +var _ ibc.Packet = PacketSequence{} -type SequencePacket struct { +type PacketSequence struct { Sequence uint64 } -func (packet SequencePacket) MarshalAmino() (string, error) { +func (packet PacketSequence) MarshalAmino() (string, error) { return fmt.Sprintf("sequence-packet-%d", packet.Sequence), nil } -func (packet *SequencePacket) UnmarshalAmino(text string) (err error) { +func (packet *PacketSequence) UnmarshalAmino(text string) (err error) { if !strings.HasPrefix(text, "sequence-packet-") { - return errors.New("invalid SequencePacket string") + return errors.New("invalid PacketSequence string") } packet.Sequence, err = strconv.ParseUint(strings.TrimPrefix(text, "sequence-packet-"), 10, 64) return } -func (packet SequencePacket) MarshalJSON() ([]byte, error) { +func (packet PacketSequence) MarshalJSON() ([]byte, error) { return []byte(fmt.Sprintf("\"sequence-packet-%d\"", packet.Sequence)), nil } -func (packet *SequencePacket) UnmarshalJSON(bz []byte) (err error) { +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 SequencePacket string") + return errors.New("invalid PacketSequence string") } packet.Sequence, err = strconv.ParseUint(strings.TrimPrefix(string(bz), "sequence-packet-"), 10, 64) return } -func (SequencePacket) SenderPort() string { +func (PacketSequence) SenderPort() string { return "ibc-mock" } -func (SequencePacket) ReceiverPort() string { +func (PacketSequence) ReceiverPort() string { return "ibc-mock" } -func (SequencePacket) String() string { +func (PacketSequence) String() string { return "sequence-packet" } -func (SequencePacket) Timeout() uint64 { +func (PacketSequence) Timeout() uint64 { return 0 } -func (SequencePacket) Type() string { +func (PacketSequence) Type() string { return "empty-packet" } -func (SequencePacket) ValidateBasic() sdk.Error { +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..ab21878de42b --- /dev/null +++ b/x/ibc/module.go @@ -0,0 +1,164 @@ +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" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +const ( + ModuleName = "ibc" +) + +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) + tendermint.RegisterCodec(cdc) + channel.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 { + 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 + client client.Manager + connection connection.Handshaker + channel channel.Handshaker +} + +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{} +} From 418ec863bbfa1aaac94f8ca762ffceccf5081212 Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 2 Sep 2019 20:06:29 +0200 Subject: [PATCH 208/378] add keeper --- x/ibc/keeper.go | 29 +++++++++++++++++++++++++++++ x/ibc/module.go | 10 +++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 x/ibc/keeper.go diff --git a/x/ibc/keeper.go b/x/ibc/keeper.go new file mode 100644 index 000000000000..859d909ad82a --- /dev/null +++ b/x/ibc/keeper.go @@ -0,0 +1,29 @@ +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()) + climan := client.NewManager(base) + connman := connection.NewManager(base, climan) + chanman := channel.NewManager(base, connman) + return Keeper{ + client: climan, + connection: connection.NewHandshaker(connman), + channel: channel.NewHandshaker(chanman), + } +} diff --git a/x/ibc/module.go b/x/ibc/module.go index ab21878de42b..20da38e8c00b 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -92,9 +92,13 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { type AppModule struct { AppModuleBasic - client client.Manager - connection connection.Handshaker - channel channel.Handshaker + Keeper +} + +func NewAppModule(k Keeper) AppModule { + return AppModule{ + Keeper: k, + } } func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { From 0570f84331ae232f16098f0bed8f3de46135b072 Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 2 Sep 2019 20:11:21 +0200 Subject: [PATCH 209/378] add StoreKey const --- x/ibc/module.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/ibc/module.go b/x/ibc/module.go index 20da38e8c00b..74c0edf946b8 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -25,6 +25,7 @@ import ( const ( ModuleName = "ibc" + StoreKey = ModuleName ) var ( From 075f7c996c0492b08a194db7ed243b2b7b212763 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 3 Sep 2019 16:31:55 +0200 Subject: [PATCH 210/378] fix test --- x/ibc/02-client/tendermint/tests/types.go | 23 +++++++++---------- x/ibc/04-channel/handshake.go | 14 ++---------- x/ibc/04-channel/tests/channel_test.go | 16 ++++++------- x/ibc/04-channel/tests/types.go | 28 ++++++++++++----------- x/ibc/23-commitment/merkle/merkle_test.go | 2 +- x/ibc/{msg.go => msgs.go} | 0 6 files changed, 37 insertions(+), 46 deletions(-) rename x/ibc/{msg.go => msgs.go} (100%) diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 027d3a28a5f5..26255358f483 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -1,26 +1,26 @@ package tendermint import ( + "bytes" "crypto/rand" "testing" - "bytes" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" cmn "github.com/tendermint/tendermint/libs/common" - dbm "github.com/tendermint/tendermint/libs/db" "github.com/tendermint/tendermint/libs/log" tmtypes "github.com/tendermint/tendermint/types" + dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store" stypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + 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" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) @@ -52,20 +52,20 @@ type Node struct { Commits []tmtypes.SignedHeader StoreName string - Prefix []byte + Prefix []byte } func NewNode(valset MockValidators, storeName string, prefix []byte) *Node { key, ctx, cms, _ := defaultComponents(storeName) return &Node{ - Valset: valset, - Cms: cms, - Key: key, - Store: ctx.KVStore(key), - Commits: nil, + Valset: valset, + Cms: cms, + Key: key, + Store: ctx.KVStore(key), + Commits: nil, StoreName: storeName, - Prefix: prefix, + Prefix: prefix, } } @@ -149,7 +149,6 @@ func (v *Verifier) Validate(header tendermint.Header, valset, nextvalset MockVal return nil } - func (node *Node) Query(t *testing.T, k []byte) ([]byte, commitment.Proof) { if bytes.HasPrefix(k, node.Prefix) { k = bytes.TrimPrefix(k, node.Prefix) diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index f31d459d545f..9b946ab4165e 100644 --- a/x/ibc/04-channel/handshake.go +++ b/x/ibc/04-channel/handshake.go @@ -86,13 +86,8 @@ func (man CounterpartyHandshaker) object(parent CounterObject) CounterHandshakeO } } -<<<<<<< HEAD -func (man Handshaker) create(ctx sdk.Context, connid, chanid string, channel Channel) (obj HandshakeObject, err error) { - cobj, err := man.Manager.create(ctx, connid, chanid, channel) -======= 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) ->>>>>>> joon/ics-04-implementation + cobj, err := man.Manager.create(ctx, portid, chanid, channel) if err != nil { return } @@ -101,13 +96,8 @@ func (man Handshaker) create(ctx sdk.Context, portid, chanid string, channel Cha return obj, nil } -<<<<<<< HEAD -func (man Handshaker) query(ctx sdk.Context, connid, chanid string) (obj HandshakeObject, err error) { - cobj, err := man.Manager.query(ctx, connid, chanid) -======= func (man Handshaker) query(ctx sdk.Context, portid, chanid string) (obj HandshakeObject, err error) { - cobj, err := man.man.query(ctx, portid, chanid) ->>>>>>> joon/ics-04-implementation + cobj, err := man.Manager.query(ctx, portid, chanid) if err != nil { return } diff --git a/x/ibc/04-channel/tests/channel_test.go b/x/ibc/04-channel/tests/channel_test.go index b3c79ca70779..fbc8b01a3a76 100644 --- a/x/ibc/04-channel/tests/channel_test.go +++ b/x/ibc/04-channel/tests/channel_test.go @@ -1,11 +1,11 @@ package channel import ( - "testing" "errors" + "testing" - sdk "github.com/cosmos/cosmos-sdk/types" "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" @@ -47,11 +47,11 @@ func (packet MyPacket) Timeout() uint64 { } func (MyPacket) SenderPort() string { - return "channel-test" + return PortName } func (MyPacket) ReceiverPort() string { - return "channel-test" + return PortName } func (MyPacket) Type() string { @@ -63,7 +63,7 @@ func (MyPacket) ValidateBasic() sdk.Error { } func (packet MyPacket) MarshalAmino() (string, error) { - return "mp-"+packet.Message, nil + return "mp-" + packet.Message, nil } func (packet *MyPacket) UnmarshalAmino(text string) error { @@ -74,13 +74,13 @@ func (packet *MyPacket) UnmarshalAmino(text string) error { return nil } -func (packet MyPacket) MarshalJSON() ([]byte, error) { +func (packet MyPacket) MarshalJSON() ([]byte, error) { res, _ := packet.MarshalAmino() - return []byte("\""+res+"\""), nil + return []byte("\"" + res + "\""), nil } func (packet *MyPacket) UnmarshalJSON(bz []byte) error { - bz = bz[1:len(bz)-1] + bz = bz[1 : len(bz)-1] return packet.UnmarshalAmino(string(bz)) } diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index 22c8234fbabe..d9ca7089241a 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 @@ -39,16 +41,16 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { } res.Channel = channel.Channel{ - Port: res.Name, + Port: PortName, Counterparty: res.Counterparty.Name, - CounterpartyPort: res.Counterparty.Name, + CounterpartyPort: PortName, ConnectionHops: []string{res.Name}, } res.Counterparty.Channel = channel.Channel{ - Port: res.Counterparty.Name, + Port: PortName, Counterparty: res.Name, - CounterpartyPort: res.Name, + CounterpartyPort: PortName, ConnectionHops: []string{res.Counterparty.Name}, } @@ -66,7 +68,7 @@ func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Conte func (node *Node) CLIObject() channel.HandshakeObject { man := node.Manager() - return channel.NewHandshaker(man).CLIObject(node.Name, node.Name, []string{node.Counterparty.Name, node.Name}) + return channel.NewHandshaker(man).CLIObject(PortName, node.Name, []string{node.Name}) } func base(cdc *codec.Codec, key sdk.StoreKey) (state.Mapping, state.Mapping) { @@ -83,7 +85,7 @@ 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, 100) // TODO: test timeout require.NoError(t, err) require.Equal(t, channel.Init, obj.State.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) @@ -92,7 +94,7 @@ func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenTry(t *testing.T, 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, PortName, node.Name, node.Channel, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, channel.OpenTry, obj.State.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) @@ -102,7 +104,7 @@ func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenAck(t *testing.T, 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, PortName, node.Name, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, channel.Open, obj.State.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) @@ -112,7 +114,7 @@ func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenConfirm(t *testing.T, 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, PortName, node.Name, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, channel.Open, obj.State.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) @@ -155,10 +157,10 @@ func (node *Node) Handshake(t *testing.T) { 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, PortName, 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)) @@ -166,10 +168,10 @@ func (node *Node) Send(t *testing.T, packet channel.Packet) { func (node *Node) Receive(t *testing.T, packet channel.Packet, 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, PortName, node.Name, packet) require.NoError(t, err) require.Equal(t, seq+1, obj.SeqRecv.Get(ctx)) } diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index 222a6bf5abd9..efa384a6c317 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -7,8 +7,8 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tendermint/libs/db" "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store" diff --git a/x/ibc/msg.go b/x/ibc/msgs.go similarity index 100% rename from x/ibc/msg.go rename to x/ibc/msgs.go From 10d1c46b52e44cc0a0f9bbbd276165093cfda3c6 Mon Sep 17 00:00:00 2001 From: Joon Date: Tue, 10 Sep 2019 23:06:52 +0200 Subject: [PATCH 211/378] Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> --- store/state/integer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/store/state/integer.go b/store/state/integer.go index 499fbe414ec2..b83b96abff60 100644 --- a/store/state/integer.go +++ b/store/state/integer.go @@ -45,8 +45,8 @@ func (v Integer) Set(ctx Context, value uint64) { v.Value.SetRaw(ctx, EncodeInt(value, v.enc)) } -// Incr() increments the stored value, and returns the updated value. -func (v Integer) Incr(ctx Context) (res uint64) { +// Increment increments the stored value and returns it. +func (v Integer) Increment(ctx Context) (res uint64) { res = v.Get(ctx) + 1 v.Set(ctx, res) return From 09e6600cc6a9d91697fc26a72db02b499846c53d Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 11 Sep 2019 16:21:38 +0200 Subject: [PATCH 212/378] applying review in progress --- store/state/enum.go | 7 ++++++- store/state/errors.go | 20 ++++++++++++++------ store/state/integer.go | 1 + store/state/string.go | 1 + 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/store/state/enum.go b/store/state/enum.go index a638b854f8f0..e61dfb3bb33b 100644 --- a/store/state/enum.go +++ b/store/state/enum.go @@ -1,5 +1,7 @@ package state +import "errors" + // Enum is a byte typed wrapper for Value. // x <-> []byte{x} type Enum struct { @@ -23,7 +25,10 @@ func (v Enum) GetSafe(ctx Context) (res byte, err error) { if bz == nil { return res, ErrEmptyValue() } - return bz[0], nil // TODO: check length + if len(bz) != 1 { + return res, ErrUnmarshal(errors.New("stored byte slice length is not 1")) + } + return bz[0], nil } // Set encodes and sets the byte argument to the state. diff --git a/store/state/errors.go b/store/state/errors.go index 936066b0ac29..303584c68bff 100644 --- a/store/state/errors.go +++ b/store/state/errors.go @@ -4,13 +4,17 @@ import ( "fmt" ) +// GetSafeErrorType is enum for indicating the type of error type GetSafeErrorType byte const ( + // ErrTypeEmptyValue is used for nil byteslice values ErrTypeEmptyValue GetSafeErrorType = iota + // ErrTypeUnmarshal is used for undeserializable values ErrTypeUnmarshal ) +// Implements Formatter func (ty GetSafeErrorType) Format(msg string) (res string) { switch ty { case ErrTypeEmptyValue: @@ -28,28 +32,32 @@ func (ty GetSafeErrorType) Format(msg string) (res string) { return } +// GetSafeError is error type for GetSafe method type GetSafeError struct { ty GetSafeErrorType inner error } -var _ error = (*GetSafeError)(nil) // TODO: sdk.Error +var _ error = GetSafeError{} -func (err *GetSafeError) Error() string { +// Implements error +func (err GetSafeError) Error() string { if err.inner == nil { return err.ty.Format("") } return err.ty.Format(err.inner.Error()) } -func ErrEmptyValue() *GetSafeError { - return &GetSafeError{ +// ErrEmptyValue constructs GetSafeError with ErrTypeEmptyValue +func ErrEmptyValue() GetSafeError { + return GetSafeError{ ty: ErrTypeEmptyValue, } } -func ErrUnmarshal(err error) *GetSafeError { - return &GetSafeError{ +// ErrUnmarshal constructs GetSafeError with ErrTypeUnmarshal +func ErrUnmarshal(err error) GetSafeError { + return GetSafeError{ ty: ErrTypeUnmarshal, inner: err, } diff --git a/store/state/integer.go b/store/state/integer.go index 499fbe414ec2..f76b199dfd51 100644 --- a/store/state/integer.go +++ b/store/state/integer.go @@ -52,6 +52,7 @@ func (v Integer) Incr(ctx Context) (res uint64) { return } +// Query() retrives state value and proof from a queryable reference func (v Integer) Query(ctx CLIContext) (res uint64, proof *Proof, err error) { value, proof, err := v.Value.QueryRaw(ctx) if err != nil { diff --git a/store/state/string.go b/store/state/string.go index 233a88adae6a..905ac38b0e41 100644 --- a/store/state/string.go +++ b/store/state/string.go @@ -31,6 +31,7 @@ func (v String) Set(ctx Context, value string) { v.Value.SetRaw(ctx, []byte(value)) } +// Query() retrives state value and proof from a queryable reference func (v String) Query(ctx CLIContext) (res string, proof *Proof, err error) { value, proof, err := v.Value.QueryRaw(ctx) return string(value), proof, err From 4116bb78e4307bfee66e88e8bc45154e5f03b183 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 11 Sep 2019 21:36:41 +0200 Subject: [PATCH 213/378] apply review - make querier interface --- store/state/boolean.go | 5 +++-- store/state/enum.go | 5 +++-- store/state/integer.go | 4 ++-- store/state/string.go | 4 ++-- store/state/types.go | 7 +++++-- store/state/value.go | 8 ++++---- 6 files changed, 19 insertions(+), 14 deletions(-) diff --git a/store/state/boolean.go b/store/state/boolean.go index 092d3dfb03e0..669b7ae85e8d 100644 --- a/store/state/boolean.go +++ b/store/state/boolean.go @@ -31,7 +31,8 @@ func (v Boolean) Set(ctx Context, value bool) { v.Value.Set(ctx, value) } -func (v Boolean) Query(ctx CLIContext) (res bool, proof *Proof, err error) { - proof, err = v.Value.Query(ctx, &res) +// Query() retrives state value and proof from a queryable reference +func (v Boolean) Query(q ABCIQuerier) (res bool, proof *Proof, err error) { + proof, err = v.Value.Query(q, &res) return } diff --git a/store/state/enum.go b/store/state/enum.go index e61dfb3bb33b..c580dca614aa 100644 --- a/store/state/enum.go +++ b/store/state/enum.go @@ -53,7 +53,8 @@ func (v Enum) Transit(ctx Context, from, to byte) bool { return true } -func (v Enum) Query(ctx CLIContext) (res byte, proof *Proof, err error) { - value, proof, err := v.Value.QueryRaw(ctx) +// 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) return value[0], proof, err } diff --git a/store/state/integer.go b/store/state/integer.go index 70121de033f4..6758d73cc479 100644 --- a/store/state/integer.go +++ b/store/state/integer.go @@ -53,8 +53,8 @@ func (v Integer) Increment(ctx Context) (res uint64) { } // Query() retrives state value and proof from a queryable reference -func (v Integer) Query(ctx CLIContext) (res uint64, proof *Proof, err error) { - value, proof, err := v.Value.QueryRaw(ctx) +func (v Integer) Query(q ABCIQuerier) (res uint64, proof *Proof, err error) { + value, proof, err := v.Value.QueryRaw(q) if err != nil { return } diff --git a/store/state/string.go b/store/state/string.go index 905ac38b0e41..a67b6b8939fb 100644 --- a/store/state/string.go +++ b/store/state/string.go @@ -32,7 +32,7 @@ func (v String) Set(ctx Context, value string) { } // Query() retrives state value and proof from a queryable reference -func (v String) Query(ctx CLIContext) (res string, proof *Proof, err error) { - value, proof, err := v.Value.QueryRaw(ctx) +func (v String) Query(q ABCIQuerier) (res string, proof *Proof, err error) { + value, proof, err := v.Value.QueryRaw(q) return string(value), proof, err } diff --git a/store/state/types.go b/store/state/types.go index a058cf6ddf0a..9251c808db88 100644 --- a/store/state/types.go +++ b/store/state/types.go @@ -1,15 +1,18 @@ package state 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" sdk "github.com/cosmos/cosmos-sdk/types" ) type KVStore = sdk.KVStore type Context = sdk.Context -type CLIContext = context.CLIContext type Proof = merkle.Proof type Codec = codec.Codec + +type ABCIQuerier interface { + QueryABCI(req abci.RequestQuery) (abci.ResponseQuery, error) +} diff --git a/store/state/value.go b/store/state/value.go index c4c1a29a217c..60df0c9718d6 100644 --- a/store/state/value.go +++ b/store/state/value.go @@ -107,14 +107,14 @@ func (v Value) KeyBytes() []byte { return v.m.KeyBytes(v.key) } -func (v Value) QueryRaw(ctx CLIContext) ([]byte, *Proof, error) { +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 := ctx.QueryABCI(req) + resp, err := q.QueryABCI(req) if err != nil { return nil, nil, err } @@ -126,8 +126,8 @@ func (v Value) QueryRaw(ctx CLIContext) ([]byte, *Proof, error) { return resp.Value, resp.Proof, nil } -func (v Value) Query(ctx CLIContext, ptr interface{}) (*Proof, error) { - value, proof, err := v.QueryRaw(ctx) +func (v Value) Query(q ABCIQuerier, ptr interface{}) (*Proof, error) { + value, proof, err := v.QueryRaw(q) if err != nil { return nil, err } From 08efad16a6d27dc9ef9656b3c42394700b32ad58 Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 16 Sep 2019 20:49:08 +0200 Subject: [PATCH 214/378] fix cli errors --- x/ibc/02-client/client/cli/query.go | 14 +++++ x/ibc/02-client/codec.go | 16 ++++-- x/ibc/02-client/tendermint/codec.go | 5 -- x/ibc/03-connection/client/cli/tx.go | 62 +++++++++++++++++------ x/ibc/03-connection/client/utils/types.go | 33 ++++++------ x/ibc/03-connection/handshake.go | 2 +- x/ibc/03-connection/manager.go | 6 +-- x/ibc/03-connection/types.go | 8 +-- x/ibc/04-channel/codec.go | 12 ++++- x/ibc/module.go | 3 ++ 10 files changed, 111 insertions(+), 50 deletions(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 6dd79d353a67..df4b21f962df 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -35,6 +35,7 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ibcQueryCmd.AddCommand(cli.GetCommands( GetCmdQueryConsensusState(storeKey, cdc), + GetCmdQueryPath(storeKey, cdc), GetCmdQueryHeader(cdc), GetCmdQueryClient(storeKey, cdc), )...) @@ -108,6 +109,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/codec.go b/x/ibc/02-client/codec.go index ece7e750dc98..d130e624f476 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,13 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgCreateClient{}, "ibc/client/MsgCreateClient", nil) cdc.RegisterConcrete(MsgUpdateClient{}, "ibc/client/MsgUpdateClient", 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/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/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index c889015c8b2c..edd44174089a 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -1,6 +1,7 @@ package cli import ( + "fmt" "io/ioutil" "github.com/spf13/cobra" @@ -69,9 +70,10 @@ 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), + // Args: []string{connid1, clientid1, path1, connid2, clientid2, connfilepath2} RunE: func(cmd *cobra.Command, args []string) error { + fmt.Println(0000) txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) ctx1 := context.NewCLIContext(). WithCodec(cdc). @@ -83,36 +85,53 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { WithNodeURI(viper.GetString(FlagNode2)). WithFrom(viper.GetString(FlagFrom2)) - conn1id := args[0] - conn1bz, err := ioutil.ReadFile(args[1]) + fmt.Println(3333) + connid1 := args[0] + clientid1 := args[1] + connid2 := args[3] + clientid2 := args[4] + + 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, version.DefaultPrefix(), conn1id) + fmt.Println(1111) + obj1, err := handshake(ctx1, 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, version.DefaultPrefix(), conn1id) + fmt.Println(2222) + obj2, err := handshake(ctx2, cdc, storeKey, version.DefaultPrefix(), connid2) if err != nil { return err } + fmt.Println(111) // TODO: check state and if not Idle continue existing process height, err := lastheight(ctx2) if err != nil { @@ -120,7 +139,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { } nextTimeout := height + 1000 // TODO: parameterize msginit := connection.MsgOpenInit{ - ConnectionID: conn1id, + ConnectionID: connid1, Connection: conn1, CounterpartyClient: conn2.Client, NextTimeout: nextTimeout, @@ -132,6 +151,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } + fmt.Println(222) timeout := nextTimeout height, err = lastheight(ctx1) if err != nil { @@ -146,6 +166,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { if err != nil { return err } + fmt.Println(333) _, ptimeout, err := obj1.NextTimeoutCLI(ctx1) if err != nil { return err @@ -156,7 +177,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { } msgtry := connection.MsgOpenTry{ - ConnectionID: conn2id, + ConnectionID: connid2, Connection: conn2, CounterpartyClient: conn1.Client, Timeout: timeout, @@ -165,6 +186,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { Signer: ctx2.GetFromAddress(), } + fmt.Println(444) err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgtry}) if err != nil { return err @@ -194,7 +216,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { } msgack := connection.MsgOpenAck{ - ConnectionID: conn1id, + ConnectionID: connid1, Timeout: timeout, NextTimeout: nextTimeout, Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, @@ -217,7 +239,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { } msgconfirm := connection.MsgOpenConfirm{ - ConnectionID: conn2id, + ConnectionID: connid2, Timeout: timeout, Proofs: []commitment.Proof{pstate, ptimeout}, Signer: ctx2.GetFromAddress(), @@ -232,5 +254,13 @@ func GetCmdHandshake(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 } diff --git a/x/ibc/03-connection/client/utils/types.go b/x/ibc/03-connection/client/utils/types.go index 33480a68291f..95989e93d650 100644 --- a/x/ibc/03-connection/client/utils/types.go +++ b/x/ibc/03-connection/client/utils/types.go @@ -1,8 +1,8 @@ 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 { @@ -12,6 +12,13 @@ type JSONObject struct { 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"` + NextTimeout uint64 `json:"next_timeout,omitempty"` + NextTimeoutProof commitment.Proof `json:"next_timeout_proof,omitempty"` } func NewJSONObject( @@ -29,16 +36,6 @@ 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( conn connection.Connection, connp commitment.Proof, avail bool, availp commitment.Proof, @@ -46,9 +43,15 @@ func NewHandshakeJSONObject( 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), +) JSONObject { + return JSONObject{ + Connection: conn, + ConnectionProof: connp, + Available: avail, + AvailableProof: availp, + Kind: kind, + KindProof: kindp, + State: state, StateProof: statep, CounterpartyClient: cpclient, diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index c5d9debba1a3..ab956b428d55 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -6,7 +6,7 @@ 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 diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index f4e4d6432c29..de1f7219200b 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()), diff --git a/x/ibc/03-connection/types.go b/x/ibc/03-connection/types.go index 358d6a451fb9..af5b1c987689 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/codec.go b/x/ibc/04-channel/codec.go index 922009db6bd8..ebf30115d09a 100644 --- a/x/ibc/04-channel/codec.go +++ b/x/ibc/04-channel/codec.go @@ -4,8 +4,18 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ) -var msgCdc = codec.New() +var msgCdc *codec.Codec func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*Packet)(nil), 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/module.go b/x/ibc/module.go index 74c0edf946b8..2be7ba8ed4d5 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -47,6 +47,9 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { client.RegisterCodec(cdc) tendermint.RegisterCodec(cdc) channel.RegisterCodec(cdc) + + client.SetMsgCodec(cdc) + channel.SetMsgCodec(cdc) } func (AppModuleBasic) DefaultGenesis() json.RawMessage { From 9b63a6b4a70c14d15b913b8267f6ce2b93c5d2c0 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 17 Sep 2019 17:32:48 +0200 Subject: [PATCH 215/378] fix dependency --- x/ibc/23-commitment/merkle/merkle_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index 222a6bf5abd9..efa384a6c317 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -7,8 +7,8 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tendermint/libs/db" "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store" From acaaaf299546fb8f1032e71229ec6e4da36ad4e4 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 17 Sep 2019 17:33:50 +0200 Subject: [PATCH 216/378] fix dependency --- x/ibc/02-client/tendermint/tests/types.go | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 027d3a28a5f5..26255358f483 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -1,26 +1,26 @@ package tendermint import ( + "bytes" "crypto/rand" "testing" - "bytes" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" cmn "github.com/tendermint/tendermint/libs/common" - dbm "github.com/tendermint/tendermint/libs/db" "github.com/tendermint/tendermint/libs/log" tmtypes "github.com/tendermint/tendermint/types" + dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store" stypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + 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" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) @@ -52,20 +52,20 @@ type Node struct { Commits []tmtypes.SignedHeader StoreName string - Prefix []byte + Prefix []byte } func NewNode(valset MockValidators, storeName string, prefix []byte) *Node { key, ctx, cms, _ := defaultComponents(storeName) return &Node{ - Valset: valset, - Cms: cms, - Key: key, - Store: ctx.KVStore(key), - Commits: nil, + Valset: valset, + Cms: cms, + Key: key, + Store: ctx.KVStore(key), + Commits: nil, StoreName: storeName, - Prefix: prefix, + Prefix: prefix, } } @@ -149,7 +149,6 @@ func (v *Verifier) Validate(header tendermint.Header, valset, nextvalset MockVal return nil } - func (node *Node) Query(t *testing.T, k []byte) ([]byte, commitment.Proof) { if bytes.HasPrefix(k, node.Prefix) { k = bytes.TrimPrefix(k, node.Prefix) From 4e53dcd35d7b0cc3580274d0d0f32ee000690886 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 17 Sep 2019 17:36:16 +0200 Subject: [PATCH 217/378] reflect method name change --- x/ibc/04-channel/manager.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index b5e2507ea9c9..8bcbbddedce5 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -269,7 +269,7 @@ 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.Incr(ctx), packet) + obj.Packets.Set(ctx, obj.SeqSend.Increment(ctx), packet) return nil } @@ -298,7 +298,7 @@ func (man Manager) Receive(ctx sdk.Context, proofs []commitment.Proof, portid, c // XXX: increment should happen before verification, reflect on the spec // TODO: packet should be custom marshalled - if !obj.counterparty.Packets.Value(obj.SeqRecv.Incr(ctx)).Is(ctx, packet) { + if !obj.counterparty.Packets.Value(obj.SeqRecv.Increment(ctx)).Is(ctx, packet) { return errors.New("verification failed") } From 828badd845c0afeceb929f3c9758e6ab40f3a7b5 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 18 Sep 2019 17:51:40 +0200 Subject: [PATCH 218/378] revise querier interface to work both on cli & store --- store/state/mapping_test.go | 2 +- store/state/types.go | 45 +++++++++++++++++++++++++++- store/state/value.go | 18 +++-------- store/state/value_test.go | 59 +++++++++++++++++++++++++++++++++++-- 4 files changed, 105 insertions(+), 19 deletions(-) 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))) } } From f88d8d3b1c639a2555c1a2430f2fab6b9e37c609 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 18 Sep 2019 17:51:40 +0200 Subject: [PATCH 219/378] revise querier interface to work both on cli & store --- store/state/mapping_test.go | 2 +- store/state/types.go | 45 +++++++++++++++++++++++++++- store/state/value.go | 18 +++-------- store/state/value_test.go | 59 +++++++++++++++++++++++++++++++++++-- 4 files changed, 105 insertions(+), 19 deletions(-) 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))) } } From 1e64e92e625029fbc7bd8e6de55cdfc3ef63e9f6 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 18 Sep 2019 17:51:40 +0200 Subject: [PATCH 220/378] revise querier interface to work both on cli & store --- store/state/mapping_test.go | 2 +- store/state/types.go | 45 +++++++++++++++++++++++++++- store/state/value.go | 18 +++-------- store/state/value_test.go | 59 +++++++++++++++++++++++++++++++++++-- 4 files changed, 105 insertions(+), 19 deletions(-) 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))) } } From b4d74913b49a3d1b5d81481df1ec4ad8a27b4228 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 18 Sep 2019 19:33:20 +0200 Subject: [PATCH 221/378] reflect downstream change --- x/ibc/02-client/cli.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index db03c1441329..67740d181748 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -3,7 +3,7 @@ package client 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" ) @@ -12,14 +12,14 @@ func (obj Object) 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 Object) 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 Object) 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 } From de1a0454c4ad97d06a05785a90628f5b1e598df8 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 18 Sep 2019 19:37:22 +0200 Subject: [PATCH 222/378] fix cli --- x/ibc/02-client/client/cli/query.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index c4238dae8cdb..624cfd7af9ff 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -48,11 +48,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) + q := state.NewCLIQuerier(ctx) mapp := mapping(cdc, storeKey, ibc.Version) man := client.NewManager(mapp) id := args[0] - state, _, err := man.Object(id).ConsensusStateCLI(ctx) + state, _, err := man.Object(id).ConsensusStateCLI(q) if err != nil { return err } From a60058963f193bb0217e1a2807902315b4648328 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 18 Sep 2019 19:44:42 +0200 Subject: [PATCH 223/378] reflect downstream changes --- x/ibc/03-connection/cli.go | 33 +++++++++++------------ x/ibc/03-connection/client/cli/query.go | 13 ++++----- x/ibc/03-connection/client/cli/tx.go | 36 +++++++++++++------------ 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index 2a6c65d7c824..c9450bd150db 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -3,8 +3,7 @@ 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" ) @@ -18,20 +17,20 @@ func (obj Object) 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 Object) 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 Object) 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 Object) 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 } @@ -40,9 +39,9 @@ func (man Handshaker) CLIObject(connid, clientid string) HandshakeObject { return man.Object(man.man.CLIObject(connid, clientid)) } -func (man Handshaker) CLIQuery(ctx context.CLIContext, connid string) (HandshakeObject, error) { +func (man Handshaker) CLIQuery(q state.ABCIQuerier, connid string) (HandshakeObject, error) { obj := man.man.Object(connid) - conn, _, err := obj.ConnectionCLI(ctx) + conn, _, err := obj.ConnectionCLI(q) if err != nil { return HandshakeObject{}, err } @@ -50,20 +49,20 @@ func (man Handshaker) CLIQuery(ctx context.CLIContext, connid string) (Handshake return man.Object(obj), nil } -func (obj HandshakeObject) StateCLI(ctx context.CLIContext) (res byte, proof merkle.Proof, err error){ - res, tmproof, err := obj.State.Query(ctx) +func (obj HandshakeObject) StateCLI(q state.ABCIQuerier) (res byte, proof merkle.Proof, err error) { + res, tmproof, err := obj.State.Query(q) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.State) return } -func (obj HandshakeObject) CounterpartyClientCLI(ctx context.CLIContext) (res string, proof merkle.Proof, err error) { - res, tmproof, err := obj.CounterpartyClient.Query(ctx) +func (obj HandshakeObject) 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 + return } -func (obj HandshakeObject) NextTimeoutCLI(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error){ - res, tmproof, err := obj.NextTimeout.Query(ctx) +func (obj HandshakeObject) NextTimeoutCLI(q state.ABCIQuerier) (res uint64, proof merkle.Proof, err error) { + res, tmproof, err := obj.NextTimeout.Query(q) 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..4c6c4a06f1e0 100644 --- a/x/ibc/03-connection/client/cli/query.go +++ b/x/ibc/03-connection/client/cli/query.go @@ -13,8 +13,8 @@ import ( 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" ) @@ -22,7 +22,6 @@ const ( FlagProve = "prove" ) - func object(cdc *codec.Codec, storeKey string, prefix []byte, connid, clientid string) connection.Object { base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) climan := client.NewManager(base) @@ -45,15 +44,17 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { } func QueryConnection(ctx context.CLIContext, obj connection.Object, prove bool) (res utils.JSONObject, err error) { - conn, connp, err := obj.ConnectionCLI(ctx) + 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 } diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index 68283021c36e..afac66e2f6a0 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -14,9 +14,9 @@ import ( "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" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) /* @@ -31,11 +31,11 @@ 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.HandshakeObject, 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) + return man.CLIQuery(q, connid) } func lastheight(ctx context.CLIContext) (uint64, error) { @@ -64,11 +64,13 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command WithCodec(cdc). WithNodeURI(viper.GetString(FlagNode1)). WithFrom(viper.GetString(FlagFrom1)) + q1 := state.NewCLIQuerier(ctx1) ctx2 := context.NewCLIContext(). WithCodec(cdc). WithNodeURI(viper.GetString(FlagNode2)). WithFrom(viper.GetString(FlagFrom2)) + q2 := state.NewCLIQuerier(ctx2) conn1id := args[0] conn1bz, err := ioutil.ReadFile(args[1]) @@ -80,7 +82,7 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } - obj1, err := handshake(ctx1, cdc, storeKey, ibc.VersionPrefix(ibc.Version), conn1id) + obj1, err := handshake(q1, cdc, storeKey, ibc.VersionPrefix(ibc.Version), conn1id) if err != nil { return err } @@ -95,7 +97,7 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } - obj2, err := handshake(ctx2, cdc, storeKey, ibc.VersionPrefix(ibc.Version), conn1id) + obj2, err := handshake(q2, cdc, storeKey, ibc.VersionPrefix(ibc.Version), conn1id) if err != nil { return err } @@ -125,19 +127,19 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } nextTimeout = height + 1000 - _, pconn, err := obj1.ConnectionCLI(ctx1) + _, pconn, err := obj1.ConnectionCLI(q1) if err != nil { return err } - _, pstate, err := obj1.StateCLI(ctx1) + _, pstate, err := obj1.StateCLI(q1) if err != nil { return err } - _, ptimeout, err := obj1.NextTimeoutCLI(ctx1) + _, ptimeout, err := obj1.NextTimeoutCLI(q1) if err != nil { return err } - _, pcounter, err := obj1.CounterpartyClientCLI(ctx1) + _, pcounter, err := obj1.CounterpartyClientCLI(q1) if err != nil { return err } @@ -163,19 +165,19 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } nextTimeout = height + 1000 - _, pconn, err = obj2.ConnectionCLI(ctx2) + _, pconn, err = obj2.ConnectionCLI(q2) if err != nil { return err } - _, pstate, err = obj2.StateCLI(ctx2) + _, pstate, err = obj2.StateCLI(q2) if err != nil { return err } - _, ptimeout, err = obj2.NextTimeoutCLI(ctx2) + _, ptimeout, err = obj2.NextTimeoutCLI(q2) if err != nil { return err } - _, pcounter, err = obj2.CounterpartyClientCLI(ctx2) + _, pcounter, err = obj2.CounterpartyClientCLI(q2) if err != nil { return err } @@ -194,11 +196,11 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command } timeout = nextTimeout - _, pstate, err = obj1.StateCLI(ctx1) + _, pstate, err = obj1.StateCLI(q1) if err != nil { return err } - _, ptimeout, err = obj1.NextTimeoutCLI(ctx1) + _, ptimeout, err = obj1.NextTimeoutCLI(q1) if err != nil { return err } From c90ed2d5c688d1886d36d9ff813901ce8ea793f2 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 18 Sep 2019 19:46:00 +0200 Subject: [PATCH 224/378] reflect downstream changes --- x/ibc/04-channel/cli.go | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index acfbb9bd8d0f..cfac26ab4090 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -3,8 +3,7 @@ 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" ) @@ -16,9 +15,9 @@ func (man Manager) CLIObject(portid, chanid string, connids []string) Object { 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 Object, err error) { obj = man.object(portid, chanid) - channel, _, err := obj.ChannelCLI(ctx) + channel, _, err := obj.ChannelCLI(q) if err != nil { return } @@ -32,39 +31,39 @@ func (obj Object) 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 Object) 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 Object) 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 Object) 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 Object) 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 Object) 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) (HandshakeObject, error) { + obj, err := man.man.CLIQuery(q, portid, chanid) if err != nil { return HandshakeObject{}, err } @@ -75,14 +74,14 @@ func (man Handshaker) CLIObject(portid, chanid string, connids []string) Handsha return man.object(man.man.CLIObject(portid, chanid, connids)) } -func (obj HandshakeObject) StateCLI(ctx context.CLIContext) (res State, proof merkle.Proof, err error) { - res, tmproof, err := obj.State.Query(ctx) +func (obj HandshakeObject) StateCLI(q state.ABCIQuerier) (res State, proof merkle.Proof, err error) { + res, tmproof, err := obj.State.Query(q) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.State) return } -func (obj HandshakeObject) NextTimeoutCLI(ctx context.CLIContext) (res uint64, proof merkle.Proof, err error) { - res, tmproof, err := obj.NextTimeout.Query(ctx) +func (obj HandshakeObject) NextTimeoutCLI(q state.ABCIQuerier) (res uint64, proof merkle.Proof, err error) { + res, tmproof, err := obj.NextTimeout.Query(q) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.NextTimeout) return } From cbfb04392de101b1cedf73dbc2728021664fed4d Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 18 Sep 2019 23:42:51 +0200 Subject: [PATCH 225/378] fix from address in tx cli --- x/ibc/03-connection/client/cli/tx.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index c9e7d9ac78e9..0983dc8012e7 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -76,16 +76,14 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { fmt.Println(0000) 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)) + WithNodeURI(viper.GetString(FlagNode1)) q1 := state.NewCLIQuerier(ctx1) - ctx2 := context.NewCLIContext(). + ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). WithCodec(cdc). - WithNodeURI(viper.GetString(FlagNode2)). - WithFrom(viper.GetString(FlagFrom2)) + WithNodeURI(viper.GetString(FlagNode2)) q2 := state.NewCLIQuerier(ctx2) fmt.Println(3333) From b15a44d5fe24912d2daa0e07188c371114071097 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 19 Sep 2019 14:08:06 +0200 Subject: [PATCH 226/378] fix cli in progress(squash later) --- x/ibc/03-connection/client/cli/tx.go | 7 ++-- x/ibc/03-connection/codec.go | 24 +++++++++++++ x/ibc/03-connection/handler.go | 8 ++--- x/ibc/03-connection/handshake.go | 12 +++---- x/ibc/03-connection/manager.go | 2 +- x/ibc/03-connection/msgs.go | 51 ++++++++++++++-------------- x/ibc/23-commitment/store.go | 2 ++ x/ibc/module.go | 2 ++ 8 files changed, 69 insertions(+), 39 deletions(-) create mode 100644 x/ibc/03-connection/codec.go diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index 0983dc8012e7..01f8daf5ffe2 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -8,6 +8,7 @@ import ( "github.com/spf13/viper" "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" @@ -78,12 +79,14 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) ctx1 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). WithCodec(cdc). - WithNodeURI(viper.GetString(FlagNode1)) + WithNodeURI(viper.GetString(FlagNode1)). + WithBroadcastMode(flags.BroadcastBlock) q1 := state.NewCLIQuerier(ctx1) ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). WithCodec(cdc). - WithNodeURI(viper.GetString(FlagNode2)) + WithNodeURI(viper.GetString(FlagNode2)). + WithBroadcastMode(flags.BroadcastBlock) q2 := state.NewCLIQuerier(ctx2) fmt.Println(3333) diff --git a/x/ibc/03-connection/codec.go b/x/ibc/03-connection/codec.go new file mode 100644 index 000000000000..49d5c7678fdd --- /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/client/MsgOpenInit", nil) + cdc.RegisterConcrete(MsgOpenTry{}, "ibc/client/MsgOpenTry", nil) + cdc.RegisterConcrete(MsgOpenAck{}, "ibc/client/MsgOpenAck", nil) + cdc.RegisterConcrete(MsgOpenConfirm{}, "ibc/client/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..ab306b90b25d 100644 --- a/x/ibc/03-connection/handler.go +++ b/x/ibc/03-connection/handler.go @@ -7,7 +7,7 @@ import ( func HandleMsgOpenInit(ctx sdk.Context, msg MsgOpenInit, man Handshaker) sdk.Result { _, err := man.OpenInit(ctx, msg.ConnectionID, msg.Connection, msg.CounterpartyClient, msg.NextTimeout) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), 100, "").Result() + return sdk.NewError(sdk.CodespaceType("ibc"), 100, err.Error()).Result() } return sdk.Result{} } @@ -15,7 +15,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.Connection, msg.CounterpartyClient, msg.Timeout, msg.NextTimeout) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), 200, "").Result() + return sdk.NewError(sdk.CodespaceType("ibc"), 200, err.Error()).Result() } return sdk.Result{} } @@ -23,7 +23,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.Timeout, msg.NextTimeout) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), 300, "").Result() + return sdk.NewError(sdk.CodespaceType("ibc"), 300, err.Error()).Result() } return sdk.Result{} } @@ -31,7 +31,7 @@ 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.Timeout) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), 400, "").Result() + 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 ab956b428d55..3a929094d53d 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -140,7 +140,7 @@ func (man Handshaker) OpenInit(ctx sdk.Context, // Using proofs: counterparty.{connection,state,nextTimeout,counterpartyClient, client} func (man Handshaker) OpenTry(ctx sdk.Context, - proofs []commitment.Proof, + proofs []commitment.Proof, height uint64, id string, connection Connection, counterpartyClient string, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { obj, err = man.create(ctx, id, connection, counterpartyClient) @@ -148,7 +148,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - ctx, err = obj.Context(ctx, connection.Path, proofs) + ctx, err = obj.Context(ctx, connection.Path, height, proofs) if err != nil { return } @@ -206,7 +206,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // Using proofs: counterparty.{connection, state, timeout, counterpartyClient, client} func (man Handshaker) OpenAck(ctx sdk.Context, - proofs []commitment.Proof, + proofs []commitment.Proof, height uint64, id string /*expheight uint64, */, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { obj, err = man.query(ctx, id) @@ -214,7 +214,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - ctx, err = obj.Context(ctx, nil, proofs) + ctx, err = obj.Context(ctx, obj.GetConnection(ctx).Path, height, proofs) if err != nil { return } @@ -269,7 +269,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, // Using proofs: counterparty.{connection,state, nextTimeout} func (man Handshaker) OpenConfirm(ctx sdk.Context, - proofs []commitment.Proof, + proofs []commitment.Proof, height uint64, id string, timeoutHeight uint64) (obj HandshakeObject, err error) { obj, err = man.query(ctx, id) @@ -277,7 +277,7 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, return } - ctx, err = obj.Context(ctx, nil, proofs) + ctx, err = obj.Context(ctx, obj.GetConnection(ctx).Path, height, proofs) if err != nil { return } diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index de1f7219200b..85c0152e5925 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -102,7 +102,7 @@ func (man CounterpartyManager) Object(id string) CounterObject { } } -func (obj Object) Context(ctx sdk.Context, optpath commitment.Path, proofs []commitment.Proof) (sdk.Context, error) { +func (obj Object) Context(ctx sdk.Context, optpath commitment.Path, height uint64, proofs []commitment.Proof) (sdk.Context, error) { if optpath == nil { optpath = obj.GetConnection(ctx).Path } diff --git a/x/ibc/03-connection/msgs.go b/x/ibc/03-connection/msgs.go index 3944599ff6a3..4f0ae1945825 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,13 @@ 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"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenTry{} @@ -63,7 +62,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 +70,11 @@ 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"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenAck{} @@ -93,7 +92,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 +100,10 @@ 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"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenConfirm{} diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 923a065334ea..2894561d316b 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -60,6 +60,7 @@ func NewStore(root Root, path Path, proofs []Proof) (res *store, err error) { err = errors.New("proof type not matching with root's") return } + fmt.Println("set", string(proof.GetKey())) res.proofs[string(proof.GetKey())] = proof } @@ -85,6 +86,7 @@ func (store *store) Prove(key, value []byte) bool { } err := proof.Verify(store.root, store.path, value) if err != nil { + fmt.Println(222, string(key), err) return false } store.verified[string(key)] = value diff --git a/x/ibc/module.go b/x/ibc/module.go index 2be7ba8ed4d5..602930a9525b 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -45,10 +45,12 @@ 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) } From 8820838f43bcd55f588a17b613d0127b4db9078f Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 19 Sep 2019 22:38:48 +0200 Subject: [PATCH 227/378] fix cli --- store/state/enum.go | 3 + x/ibc/02-client/cli.go | 8 ++ x/ibc/02-client/client/cli/query.go | 32 ++++++- x/ibc/02-client/manager.go | 9 ++ x/ibc/02-client/types.go | 2 +- x/ibc/03-connection/client/cli/tx.go | 113 +++++++++++++++++++++++-- x/ibc/03-connection/handler.go | 6 +- x/ibc/03-connection/handshake.go | 6 +- x/ibc/03-connection/manager.go | 12 +-- x/ibc/03-connection/msgs.go | 3 + x/ibc/03-connection/tests/types.go | 32 +++---- x/ibc/04-channel/handler.go | 6 +- x/ibc/04-channel/handshake.go | 12 +-- x/ibc/04-channel/manager.go | 8 +- x/ibc/04-channel/msgs.go | 78 +++++++++-------- x/ibc/04-channel/port.go | 4 +- x/ibc/04-channel/tests/channel_test.go | 2 +- x/ibc/04-channel/tests/types.go | 22 ++--- x/ibc/23-commitment/merkle/merkle.go | 14 +-- x/ibc/ante.go | 2 +- x/ibc/version/version.go | 2 +- 21 files changed, 267 insertions(+), 109 deletions(-) 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/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 67740d181748..29533883c76a 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -5,6 +5,7 @@ import ( "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" ) @@ -12,6 +13,13 @@ func (obj Object) prefix() []byte { return bytes.Split(obj.ConsensusState.KeyBytes(), LocalRoot())[0] } +func (obj Object) 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 Object) 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) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 79cff3198df4..49a5ac8b65dc 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -20,8 +20,8 @@ import ( "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) } @@ -38,6 +38,7 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { GetCmdQueryPath(storeKey, cdc), GetCmdQueryHeader(cdc), GetCmdQueryClient(storeKey, cdc), + GetCmdQueryRoot(storeKey, cdc), )...) return ibcQueryCmd } @@ -66,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.Object(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", diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index eb9a83ff7d2e..1a732c6dc824 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -43,6 +43,7 @@ func (man Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { func (man Manager) Object(id string) Object { return Object{ 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(), } @@ -53,6 +54,7 @@ func (man Manager) Create(ctx sdk.Context, id string, cs ConsensusState) (Object if obj.exists(ctx) { return Object{}, errors.New("Create client on already existing id") } + obj.Roots.Set(ctx, cs.GetHeight(), cs.GetRoot()) obj.ConsensusState.Set(ctx, cs) return obj, nil } @@ -79,6 +81,7 @@ func (man CounterpartyManager) Query(id string) CounterObject { // Any actor holding the Object can access on and modify that client information type Object struct { id string + Roots state.Indexer ConsensusState state.Value // ConsensusState Frozen state.Boolean } @@ -97,6 +100,11 @@ func (obj Object) GetConsensusState(ctx sdk.Context) (res ConsensusState) { return } +func (obj Object) GetRoot(ctx sdk.Context, height uint64) (res commitment.Root, err error) { + err = obj.Roots.GetSafe(ctx, height, &res) + return +} + func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { return obj.ConsensusState.Is(ctx, client) } @@ -121,6 +129,7 @@ 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 } 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/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index 01f8daf5ffe2..277a128cf7e2 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -3,10 +3,13 @@ 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" @@ -17,6 +20,7 @@ import ( "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" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/version" @@ -68,6 +72,45 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { 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", @@ -75,7 +118,6 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { Args: cobra.ExactArgs(6), // Args: []string{connid1, clientid1, path1, connid2, clientid2, connfilepath2} RunE: func(cmd *cobra.Command, args []string) error { - fmt.Println(0000) txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) ctx1 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). WithCodec(cdc). @@ -133,7 +175,6 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - fmt.Println(111) // TODO: check state and if not Idle continue existing process height, err := lastheight(ctx2) if err != nil { @@ -153,13 +194,35 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - fmt.Println(222) + // 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 + } + + msgupdate := client.MsgUpdateClient{ + ClientID: conn2.Client, + Header: header, + Signer: ctx2.GetFromAddress(), + } + + 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) + timeout := nextTimeout height, err = lastheight(ctx1) if err != nil { return err } nextTimeout = height + 1000 + _, pconn, err := obj1.ConnectionCLI(q1) if err != nil { return err @@ -184,16 +247,35 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { Timeout: timeout, NextTimeout: nextTimeout, Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, + Height: uint64(header.Height), Signer: ctx2.GetFromAddress(), } - fmt.Println(444) err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgtry}) if err != nil { return err } - timeout = nextTimeout + + // 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 + } + + msgupdate = client.MsgUpdateClient{ + ClientID: conn1.Client, + Header: header, + Signer: ctx2.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgupdate}) + + q2 = state.NewCLIQuerier(ctx2.WithHeight(header.Height - 1)) + height, err = lastheight(ctx2) if err != nil { return err @@ -221,6 +303,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { Timeout: timeout, NextTimeout: nextTimeout, Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, + Height: uint64(header.Height), Signer: ctx1.GetFromAddress(), } @@ -229,6 +312,25 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } + // 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 + } + + msgupdate = client.MsgUpdateClient{ + ClientID: conn2.Client, + Header: header, + Signer: ctx2.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgupdate}) + + q1 = state.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) + timeout = nextTimeout _, pstate, err = obj1.StateCLI(q1) if err != nil { @@ -243,6 +345,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { ConnectionID: connid2, Timeout: timeout, Proofs: []commitment.Proof{pstate, ptimeout}, + Height: uint64(header.Height), Signer: ctx2.GetFromAddress(), } diff --git a/x/ibc/03-connection/handler.go b/x/ibc/03-connection/handler.go index ab306b90b25d..8509e6b58c65 100644 --- a/x/ibc/03-connection/handler.go +++ b/x/ibc/03-connection/handler.go @@ -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.Connection, msg.CounterpartyClient, msg.Timeout, msg.NextTimeout) + _, err := man.OpenTry(ctx, msg.Proofs, msg.Height, msg.ConnectionID, msg.Connection, msg.CounterpartyClient, msg.Timeout, msg.NextTimeout) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), 200, err.Error()).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.Timeout, msg.NextTimeout) + _, err := man.OpenAck(ctx, msg.Proofs, msg.Height, msg.ConnectionID, msg.Timeout, msg.NextTimeout) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), 300, err.Error()).Result() } @@ -29,7 +29,7 @@ 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.Timeout) + _, err := man.OpenConfirm(ctx, msg.Proofs, msg.Height, msg.ConnectionID, msg.Timeout) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), 400, err.Error()).Result() } diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index 3a929094d53d..342d87d5cdd6 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -148,7 +148,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - ctx, err = obj.Context(ctx, connection.Path, height, proofs) + ctx, err = obj.Context(ctx, height, proofs) if err != nil { return } @@ -214,7 +214,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - ctx, err = obj.Context(ctx, obj.GetConnection(ctx).Path, height, proofs) + ctx, err = obj.Context(ctx, height, proofs) if err != nil { return } @@ -277,7 +277,7 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, return } - ctx, err = obj.Context(ctx, obj.GetConnection(ctx).Path, height, proofs) + ctx, err = obj.Context(ctx, height, proofs) if err != nil { return } diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 85c0152e5925..57e5a3456fea 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -102,15 +102,15 @@ func (man CounterpartyManager) Object(id string) CounterObject { } } -func (obj Object) Context(ctx sdk.Context, optpath commitment.Path, height uint64, proofs []commitment.Proof) (sdk.Context, error) { - if optpath == nil { - optpath = obj.GetConnection(ctx).Path +func (obj Object) 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 { diff --git a/x/ibc/03-connection/msgs.go b/x/ibc/03-connection/msgs.go index 4f0ae1945825..5848558554b0 100644 --- a/x/ibc/03-connection/msgs.go +++ b/x/ibc/03-connection/msgs.go @@ -44,6 +44,7 @@ type MsgOpenTry struct { Timeout uint64 `json:"timeout"` NextTimeout uint64 `json:"next_timeout"` Proofs []commitment.Proof `json:"proofs"` + Height uint64 `json:"height"` Signer sdk.AccAddress `json:"signer"` } @@ -74,6 +75,7 @@ type MsgOpenAck struct { Timeout uint64 `json:"timeout"` NextTimeout uint64 `json:"next_timeout"` Proofs []commitment.Proof `json:"proofs"` + Height uint64 `json:"height"` Signer sdk.AccAddress `json:"signer"` } @@ -103,6 +105,7 @@ type MsgOpenConfirm struct { ConnectionID string `json:"connection_id"` Timeout uint64 `json:"timeout"` Proofs []commitment.Proof `json:"proofs"` + Height uint64 `json:"height"` Signer sdk.AccAddress `json:"signer"` } diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index 9fbd375aa4b3..a0c27dd3e768 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 { @@ -29,8 +29,8 @@ type Node struct { 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()) } @@ -119,9 +119,9 @@ func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { 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, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.OpenTry, obj.State.Get(ctx)) require.Equal(t, node.Connection, obj.GetConnection(ctx)) @@ -130,9 +130,9 @@ func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { 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, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.Open, obj.State.Get(ctx)) require.Equal(t, node.Connection, obj.GetConnection(ctx)) @@ -140,9 +140,9 @@ func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { 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, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, connection.Open, obj.State.Get(ctx)) require.Equal(t, node.Connection, obj.GetConnection(ctx)) @@ -170,7 +170,7 @@ func (node *Node) Handshake(t *testing.T) { _, 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, ptimeout, pcounterclient) header = node.Counterparty.Commit() // self.OpenAck @@ -180,7 +180,7 @@ func (node *Node) Handshake(t *testing.T) { _, pstate = node.Counterparty.QueryValue(t, cliobj.State) _, ptimeout = node.Counterparty.QueryValue(t, cliobj.NextTimeout) _, pcounterclient = node.Counterparty.QueryValue(t, cliobj.CounterpartyClient) - node.OpenAck(t, pconn, pstate, ptimeout, pcounterclient) + node.OpenAck(t, uint64(header.Height), pconn, pstate, ptimeout, pcounterclient) header = node.Commit() // counterparty.OpenConfirm @@ -188,5 +188,5 @@ func (node *Node) Handshake(t *testing.T) { cliobj = node.CLIObject() _, pstate = node.QueryValue(t, cliobj.State) _, ptimeout = node.QueryValue(t, cliobj.NextTimeout) - node.Counterparty.OpenConfirm(t, pstate, ptimeout) + node.Counterparty.OpenConfirm(t, uint64(header.Height), pstate, ptimeout) } diff --git a/x/ibc/04-channel/handler.go b/x/ibc/04-channel/handler.go index 76d9ace3e6e4..bb18de6e17e8 100644 --- a/x/ibc/04-channel/handler.go +++ b/x/ibc/04-channel/handler.go @@ -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.ConnectionID, msg.ChannelID, msg.Channel, msg.Timeout, msg.NextTimeout) 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.ConnectionID, msg.ChannelID, msg.Timeout, msg.NextTimeout) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), 300, "").Result() } @@ -29,7 +29,7 @@ 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.ConnectionID, msg.ChannelID, msg.Timeout) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), 400, "").Result() } diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index 9b946ab4165e..d0cb14574c47 100644 --- a/x/ibc/04-channel/handshake.go +++ b/x/ibc/04-channel/handshake.go @@ -148,7 +148,7 @@ func (man Handshaker) OpenInit(ctx sdk.Context, // Using proofs: counterparty.{channel,state,nextTimeout} func (man Handshaker) OpenTry(ctx sdk.Context, - proofs []commitment.Proof, + proofs []commitment.Proof, height uint64, portid, chanid string, channel Channel, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { if len(channel.ConnectionHops) != 1 { @@ -159,7 +159,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - ctx, err = obj.Context(ctx, proofs) + ctx, err = obj.Context(ctx, proofs, height) if err != nil { return } @@ -213,7 +213,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} func (man Handshaker) OpenAck(ctx sdk.Context, - proofs []commitment.Proof, + proofs []commitment.Proof, height uint64, portid, chanid string, timeoutHeight, nextTimeoutHeight uint64, ) (obj HandshakeObject, err error) { obj, err = man.query(ctx, portid, chanid) @@ -221,7 +221,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - ctx, err = obj.Context(ctx, proofs) + ctx, err = obj.Context(ctx, proofs, height) if err != nil { return } @@ -274,14 +274,14 @@ func (man Handshaker) OpenAck(ctx sdk.Context, // Using proofs: counterparty.{connection,state, nextTimeout} func (man Handshaker) OpenConfirm(ctx sdk.Context, - proofs []commitment.Proof, + proofs []commitment.Proof, height uint64, portid, chanid string, timeoutHeight uint64) (obj HandshakeObject, 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 } diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index ad33e6453d4f..0920e9119e65 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -223,8 +223,8 @@ func (obj Object) OriginConnection() connection.Object { 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 Object) Context(ctx sdk.Context, proofs []commitment.Proof, height uint64) (sdk.Context, error) { + return obj.OriginConnection().Context(ctx, height, proofs) } func (obj Object) ChanID() string { @@ -287,7 +287,7 @@ func (man Manager) Send(ctx sdk.Context, portid, chanid string, packet Packet) e 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 @@ -299,7 +299,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 } diff --git a/x/ibc/04-channel/msgs.go b/x/ibc/04-channel/msgs.go index c12f4a338b1a..adb764900798 100644 --- a/x/ibc/04-channel/msgs.go +++ b/x/ibc/04-channel/msgs.go @@ -8,12 +8,12 @@ import ( const Route = "ibc" type MsgOpenInit struct { - ConnectionID string - ChannelID string - Channel Channel - CounterpartyClient string - NextTimeout uint64 - Signer sdk.AccAddress + ConnectionID string `json:"connection_id"` + ChannelID string `json:"channel_id"` + Channel Channel `json:"channel"` + CounterpartyClient string `json:"counterparty_client"` + NextTimeout uint64 `json:"next_timeout"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenInit{} @@ -31,7 +31,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,14 +39,15 @@ 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 + ConnectionID string `json:"connection_id"` + ChannelID string `json:"channel_id"` + Channel Channel `json:"channel"` + 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{} @@ -64,7 +65,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 { @@ -72,12 +73,13 @@ func (msg MsgOpenTry) GetSigners() []sdk.AccAddress { } type MsgOpenAck struct { - ConnectionID string - ChannelID string - Timeout uint64 - NextTimeout uint64 - Proofs []commitment.Proof - Signer sdk.AccAddress + ConnectionID string `json:"connection_id"` + ChannelID string `json:"channel_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{} @@ -95,7 +97,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 { @@ -103,11 +105,12 @@ func (msg MsgOpenAck) GetSigners() []sdk.AccAddress { } type MsgOpenConfirm struct { - ConnectionID string - ChannelID string - Timeout uint64 - Proofs []commitment.Proof - Signer sdk.AccAddress + ConnectionID string `json:"connection_id"` + ChannelID string `json:"channel_id"` + Timeout uint64 `json:"timeout"` + Proofs []commitment.Proof `json:"proofs"` + Height uint64 `json:"height"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenConfirm{} @@ -125,21 +128,22 @@ 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} } +// 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"` - // PortID dependent on type - // ChannelID can be empty if batched & not first MsgPacket - ChannelID string `json:"channel_id,omitempty" yaml:"channel_id"` - // Height uint64 // height of the commitment root for the proofs - Proofs []commitment.Proof `json:"proofs" yaml:"proofs"` - Signer sdk.AccAddress `json:"signer,omitempty" yaml:"signer"` + 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 = MsgPacket{} @@ -157,7 +161,7 @@ func (msg MsgPacket) Route() string { } func (msg MsgPacket) GetSignBytes() []byte { - return msgCdc.MustMarshalJSON(msg) // TODO: Sort + return sdk.MustSortJSON(msgCdc.MustMarshalJSON(msg)) } func (msg MsgPacket) GetSigners() []sdk.AccAddress { diff --git a/x/ibc/04-channel/port.go b/x/ibc/04-channel/port.go index dfa8738655b2..8c06a1e6f12f 100644 --- a/x/ibc/04-channel/port.go +++ b/x/ibc/04-channel/port.go @@ -35,6 +35,6 @@ func (port Port) Send(ctx sdk.Context, chanid string, packet Packet) error { return port.channel.Send(ctx, port.id, 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/tests/channel_test.go b/x/ibc/04-channel/tests/channel_test.go index fbc8b01a3a76..432709585414 100644 --- a/x/ibc/04-channel/tests/channel_test.go +++ b/x/ibc/04-channel/tests/channel_test.go @@ -98,5 +98,5 @@ func TestPacket(t *testing.T) { node.Counterparty.UpdateClient(t, header) cliobj := node.CLIObject() _, 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 d9ca7089241a..1079fccfc8c0 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -92,9 +92,9 @@ func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { 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, PortName, node.Name, node.Channel, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenTry(ctx, proofs, height, PortName, node.Name, node.Channel, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, channel.OpenTry, obj.State.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) @@ -102,9 +102,9 @@ func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { 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, PortName, node.Name, 100 /*TODO*/, 100 /*TODO*/) + obj, err := man.OpenAck(ctx, proofs, height, PortName, node.Name, 100 /*TODO*/, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, channel.Open, obj.State.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) @@ -112,9 +112,9 @@ func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { 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, PortName, node.Name, 100 /*TODO*/) + obj, err := man.OpenConfirm(ctx, proofs, height, PortName, node.Name, 100 /*TODO*/) require.NoError(t, err) require.Equal(t, channel.Open, obj.State.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) @@ -135,7 +135,7 @@ func (node *Node) Handshake(t *testing.T) { _, 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) + node.Counterparty.OpenTry(t, uint64(header.Height), pchan, pstate, ptimeout) header = node.Counterparty.Commit() // self.OpenAck @@ -144,7 +144,7 @@ func (node *Node) Handshake(t *testing.T) { _, 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) + node.OpenAck(t, uint64(header.Height), pchan, pstate, ptimeout) header = node.Commit() // counterparty.OpenConfirm @@ -152,7 +152,7 @@ func (node *Node) Handshake(t *testing.T) { cliobj = node.CLIObject() _, pstate = node.QueryValue(t, cliobj.State) _, ptimeout = node.QueryValue(t, cliobj.NextTimeout) - node.Counterparty.OpenConfirm(t, pstate, ptimeout) + node.Counterparty.OpenConfirm(t, uint64(header.Height), pstate, ptimeout) } func (node *Node) Send(t *testing.T, packet channel.Packet) { @@ -166,12 +166,12 @@ func (node *Node) Send(t *testing.T, packet channel.Packet) { 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, PortName, node.Name) require.NoError(t, err) seq := obj.SeqRecv.Get(ctx) - err = man.Receive(ctx, proofs, PortName, 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/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index 1606497ec4f8..7ca7579d9eb8 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() diff --git a/x/ibc/ante.go b/x/ibc/ante.go index 696275ea08a6..ae0a00315a05 100644 --- a/x/ibc/ante.go +++ b/x/ibc/ante.go @@ -31,7 +31,7 @@ func ExtractMsgPackets(msgs []sdk.Msg) (res []MsgPacket, abort bool) { func VerifyMsgPackets(ctx sdk.Context, channel channel.Manager, msgs []MsgPacket) error { for _, msg := range msgs { - err := channel.Receive(ctx, msg.Proofs, msg.ReceiverPort(), msg.ChannelID, msg.Packet) + err := channel.Receive(ctx, msg.Proofs, msg.Height, msg.ReceiverPort(), msg.ChannelID, msg.Packet) if err != nil { return err } diff --git a/x/ibc/version/version.go b/x/ibc/version/version.go index 5c80adf66a24..a7d3275fae5b 100644 --- a/x/ibc/version/version.go +++ b/x/ibc/version/version.go @@ -9,5 +9,5 @@ func DefaultPrefix() []byte { } func Prefix(version int64) []byte { - return []byte(strconv.FormatInt(version, 10) + "/") + return []byte("v" + strconv.FormatInt(version, 10) + "/") } From a72f6c59135bb36a84f4672a3e74220666708276 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 20 Sep 2019 18:11:21 +0200 Subject: [PATCH 228/378] remove timeout, add channel cli --- x/ibc/03-connection/cli.go | 6 - x/ibc/03-connection/client/cli/tx.go | 46 +-- x/ibc/03-connection/client/utils/types.go | 5 - x/ibc/03-connection/handler.go | 8 +- x/ibc/03-connection/handshake.go | 162 +------- x/ibc/03-connection/tests/types.go | 17 +- x/ibc/04-channel/cli.go | 6 - x/ibc/04-channel/client/cli/query.go | 79 +++- x/ibc/04-channel/client/cli/tx.go | 440 ++++++++++++++-------- x/ibc/04-channel/handler.go | 8 +- x/ibc/04-channel/handshake.go | 76 +--- x/ibc/04-channel/msgs.go | 48 +-- x/ibc/04-channel/tests/types.go | 19 +- x/ibc/04-channel/types.go | 3 +- x/ibc/module.go | 5 +- 15 files changed, 408 insertions(+), 520 deletions(-) diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index c9450bd150db..7fa3986465d7 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -60,9 +60,3 @@ func (obj HandshakeObject) CounterpartyClientCLI(q state.ABCIQuerier) (res strin proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.CounterpartyClient) return } - -func (obj HandshakeObject) NextTimeoutCLI(q state.ABCIQuerier) (res uint64, proof merkle.Proof, err error) { - res, tmproof, err := obj.NextTimeout.Query(q) - proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.NextTimeout) - return -} diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index 277a128cf7e2..0ecb6c97cf61 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -131,7 +131,6 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { WithBroadcastMode(flags.BroadcastBlock) q2 := state.NewCLIQuerier(ctx2) - fmt.Println(3333) connid1 := args[0] clientid1 := args[1] connid2 := args[3] @@ -176,16 +175,10 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { } // 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: connid1, Connection: conn1, CounterpartyClient: conn2.Client, - NextTimeout: nextTimeout, Signer: ctx1.GetFromAddress(), } @@ -216,13 +209,6 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { q1 = state.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) fmt.Printf("querying from %d\n", header.Height-1) - timeout := nextTimeout - height, err = lastheight(ctx1) - if err != nil { - return err - } - nextTimeout = height + 1000 - _, pconn, err := obj1.ConnectionCLI(q1) if err != nil { return err @@ -231,10 +217,6 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { if err != nil { return err } - _, ptimeout, err := obj1.NextTimeoutCLI(q1) - if err != nil { - return err - } _, pcounter, err := obj1.CounterpartyClientCLI(q1) if err != nil { return err @@ -244,9 +226,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { 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(), } @@ -255,7 +235,6 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { if err != nil { return err } - timeout = nextTimeout // Another block has to be passed after msginit is commited // to retrieve the correct proofs @@ -269,18 +248,13 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { msgupdate = client.MsgUpdateClient{ ClientID: conn1.Client, Header: header, - Signer: ctx2.GetFromAddress(), + Signer: ctx1.GetFromAddress(), } err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgupdate}) q2 = state.NewCLIQuerier(ctx2.WithHeight(header.Height - 1)) - height, err = lastheight(ctx2) - if err != nil { - return err - } - nextTimeout = height + 1000 _, pconn, err = obj2.ConnectionCLI(q2) if err != nil { return err @@ -289,10 +263,6 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { if err != nil { return err } - _, ptimeout, err = obj2.NextTimeoutCLI(q2) - if err != nil { - return err - } _, pcounter, err = obj2.CounterpartyClientCLI(q2) if err != nil { return err @@ -300,9 +270,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { msgack := connection.MsgOpenAck{ ConnectionID: connid1, - Timeout: timeout, - NextTimeout: nextTimeout, - Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, + Proofs: []commitment.Proof{pconn, pstate, pcounter}, Height: uint64(header.Height), Signer: ctx1.GetFromAddress(), } @@ -331,20 +299,14 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { q1 = state.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) - timeout = nextTimeout _, pstate, err = obj1.StateCLI(q1) if err != nil { return err } - _, ptimeout, err = obj1.NextTimeoutCLI(q1) - if err != nil { - return err - } msgconfirm := connection.MsgOpenConfirm{ ConnectionID: connid2, - Timeout: timeout, - Proofs: []commitment.Proof{pstate, ptimeout}, + Proofs: []commitment.Proof{pstate}, Height: uint64(header.Height), Signer: ctx2.GetFromAddress(), } diff --git a/x/ibc/03-connection/client/utils/types.go b/x/ibc/03-connection/client/utils/types.go index 95989e93d650..9ef404879a4b 100644 --- a/x/ibc/03-connection/client/utils/types.go +++ b/x/ibc/03-connection/client/utils/types.go @@ -17,8 +17,6 @@ type JSONObject struct { StateProof commitment.Proof `json:"state_proof,omitempty"` CounterpartyClient string `json:"counterparty_client,omitempty"` CounterpartyClientProof commitment.Proof `json:"counterparty_client_proof,omitempty"` - NextTimeout uint64 `json:"next_timeout,omitempty"` - NextTimeoutProof commitment.Proof `json:"next_timeout_proof,omitempty"` } func NewJSONObject( @@ -42,7 +40,6 @@ func NewHandshakeJSONObject( kind string, kindp commitment.Proof, state byte, statep commitment.Proof, cpclient string, cpclientp commitment.Proof, - timeout uint64, timeoutp commitment.Proof, ) JSONObject { return JSONObject{ Connection: conn, @@ -56,7 +53,5 @@ func NewHandshakeJSONObject( StateProof: statep, CounterpartyClient: cpclient, CounterpartyClientProof: cpclientp, - NextTimeout: timeout, - NextTimeoutProof: timeoutp, } } diff --git a/x/ibc/03-connection/handler.go b/x/ibc/03-connection/handler.go index 8509e6b58c65..8395579663d2 100644 --- a/x/ibc/03-connection/handler.go +++ b/x/ibc/03-connection/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.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, err.Error()).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.Height, 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, err.Error()).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.Height, 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, err.Error()).Result() } @@ -29,7 +29,7 @@ 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.Height, msg.ConnectionID, msg.Timeout) + _, err := man.OpenConfirm(ctx, msg.Proofs, msg.Height, msg.ConnectionID) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), 400, err.Error()).Result() } diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index 342d87d5cdd6..04eb96fc298f 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -48,7 +48,6 @@ type HandshakeObject struct { State state.Enum CounterpartyClient state.String - NextTimeout state.Integer Counterparty CounterHandshakeObject } @@ -58,7 +57,6 @@ type CounterHandshakeObject struct { State commitment.Enum CounterpartyClient commitment.String - NextTimeout commitment.Integer } // CONTRACT: client and remote must be filled by the caller @@ -68,7 +66,6 @@ func (man Handshaker) Object(parent Object) HandshakeObject { State: 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 } @@ -80,7 +77,6 @@ func (man CounterpartyHandshaker) Object(id string) CounterHandshakeObject { State: 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), } } @@ -109,20 +105,11 @@ func (obj HandshakeObject) remove(ctx sdk.Context) { obj.Object.remove(ctx) obj.State.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, + id string, connection Connection, counterpartyClient string, ) (HandshakeObject, error) { // man.Create() will ensure // assert(get("connections/{identifier}") === null) and @@ -132,7 +119,6 @@ func (man Handshaker) OpenInit(ctx sdk.Context, return HandshakeObject{}, err } - obj.NextTimeout.Set(ctx, nextTimeoutHeight) obj.State.Set(ctx, Init) return obj, nil @@ -141,7 +127,7 @@ func (man Handshaker) OpenInit(ctx sdk.Context, // Using proofs: counterparty.{connection,state,nextTimeout,counterpartyClient, client} func (man Handshaker) OpenTry(ctx sdk.Context, proofs []commitment.Proof, height uint64, - id string, connection Connection, counterpartyClient string, timeoutHeight, nextTimeoutHeight uint64, + id string, connection Connection, counterpartyClient string, ) (obj HandshakeObject, err error) { obj, err = man.create(ctx, id, connection, counterpartyClient) if err != nil { @@ -153,11 +139,6 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - err = assertTimeout(ctx, timeoutHeight) - if err != nil { - return - } - if !obj.Counterparty.State.Is(ctx, Init) { err = errors.New("counterparty state not init") return @@ -177,11 +158,6 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { - err = errors.New("unexpected counterparty timeout value") - 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 @@ -199,7 +175,6 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // set("connections{identifier}", connection) obj.State.Set(ctx, OpenTry) - obj.NextTimeout.Set(ctx, nextTimeoutHeight) return } @@ -207,7 +182,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // Using proofs: counterparty.{connection, state, timeout, counterpartyClient, client} func (man Handshaker) OpenAck(ctx sdk.Context, proofs []commitment.Proof, height uint64, - id string /*expheight uint64, */, timeoutHeight, nextTimeoutHeight uint64, + id string, ) (obj HandshakeObject, err error) { obj, err = man.query(ctx, id) if err != nil { @@ -224,11 +199,6 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - err = assertTimeout(ctx, timeoutHeight) - if err != nil { - return - } - if !obj.Counterparty.Connection.Is(ctx, Connection{ Client: obj.CounterpartyClient.Get(ctx), Counterparty: obj.ID(), @@ -248,11 +218,6 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { - err = errors.New("unexpected counterparty timeout value") - return - } - // TODO: implement in v1 /* var expected client.ConsensusState @@ -262,7 +227,6 @@ func (man Handshaker) OpenAck(ctx sdk.Context, } */ obj.Available.Set(ctx, true) - obj.NextTimeout.Set(ctx, nextTimeoutHeight) return } @@ -270,7 +234,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, // Using proofs: counterparty.{connection,state, nextTimeout} func (man Handshaker) OpenConfirm(ctx sdk.Context, proofs []commitment.Proof, height uint64, - id string, timeoutHeight uint64) (obj HandshakeObject, err error) { + id string) (obj HandshakeObject, err error) { obj, err = man.query(ctx, id) if err != nil { @@ -287,130 +251,12 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, 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") - 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/tests/types.go b/x/ibc/03-connection/tests/types.go index a0c27dd3e768..0162b392b494 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -110,7 +110,7 @@ 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, node.Connection, obj.GetConnection(ctx)) @@ -121,7 +121,7 @@ func (node *Node) OpenInit(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, height, 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, node.Connection, obj.GetConnection(ctx)) @@ -132,7 +132,7 @@ func (node *Node) OpenTry(t *testing.T, height uint64, proofs ...commitment.Proo func (node *Node) OpenAck(t *testing.T, height uint64, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenAck(ctx, proofs, height, 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, node.Connection, obj.GetConnection(ctx)) @@ -142,7 +142,7 @@ func (node *Node) OpenAck(t *testing.T, height uint64, proofs ...commitment.Proo func (node *Node) OpenConfirm(t *testing.T, height uint64, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenConfirm(ctx, proofs, height, 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, node.Connection, obj.GetConnection(ctx)) @@ -166,11 +166,10 @@ func (node *Node) Handshake(t *testing.T) { cliobj := node.CLIObject() _, pconn := node.QueryValue(t, cliobj.Connection) _, pstate := node.QueryValue(t, cliobj.State) - _, ptimeout := node.QueryValue(t, cliobj.NextTimeout) _, pcounterclient := node.QueryValue(t, cliobj.CounterpartyClient) // TODO: implement consensus state checking // _, pclient := node.Query(t, cliobj.Client.ConsensusStateKey) - node.Counterparty.OpenTry(t, uint64(header.Height), pconn, pstate, ptimeout, pcounterclient) + node.Counterparty.OpenTry(t, uint64(header.Height), pconn, pstate, pcounterclient) header = node.Counterparty.Commit() // self.OpenAck @@ -178,15 +177,13 @@ func (node *Node) Handshake(t *testing.T) { cliobj = node.Counterparty.CLIObject() _, pconn = node.Counterparty.QueryValue(t, cliobj.Connection) _, pstate = node.Counterparty.QueryValue(t, cliobj.State) - _, ptimeout = node.Counterparty.QueryValue(t, cliobj.NextTimeout) _, pcounterclient = node.Counterparty.QueryValue(t, cliobj.CounterpartyClient) - node.OpenAck(t, uint64(header.Height), 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, uint64(header.Height), pstate, ptimeout) + node.Counterparty.OpenConfirm(t, uint64(header.Height), pstate) } diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index 5f624b7af02b..ebf0f1755890 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -79,9 +79,3 @@ func (obj HandshakeObject) StateCLI(q state.ABCIQuerier) (res State, proof merkl proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.State) return } - -func (obj HandshakeObject) NextTimeoutCLI(q state.ABCIQuerier) (res uint64, proof merkle.Proof, err error) { - res, tmproof, err := obj.NextTimeout.Query(q) - proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.NextTimeout) - return -} diff --git a/x/ibc/04-channel/client/cli/query.go b/x/ibc/04-channel/client/cli/query.go index d50573cdc724..9a5c7d4fb9b7 100644 --- a/x/ibc/04-channel/client/cli/query.go +++ b/x/ibc/04-channel/client/cli/query.go @@ -1,11 +1,28 @@ 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 { base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) climan := client.NewManager(base) @@ -16,39 +33,36 @@ func object(cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid str 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) + 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 } @@ -71,15 +85,14 @@ 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", Short: "Query stored connection", - Args: cobra.ExactArgs(1), + Args: cobra.ExactArgs(3), 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 := object(cdc, storeKey, version.DefaultPrefix(), args[0], args[1], []string{args[2]}) jsonobj, err := QueryChannel(ctx, obj, viper.GetBool(FlagProve)) if err != nil { return err @@ -95,4 +108,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.Object { + 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) +} +*/ +/* +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..90696ee9ab6d 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -1,5 +1,129 @@ +/* + + +func lastheight(ctx context.CLIContext) (uint64, error) { + node, err := ctx.GetNode() + if err != nil { + return 0, err + } + + info, err := node.ABCIInfo() + if err != nil { + return 0, err + } + + return uint64(info.Response.LastBlockHeight), nil +} + +func GetCmdRelay(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} + RunE: func(cmd *cobra.Command, args []string) error { + ctx1 := context.NewCLIContext(). + WithCodec(cdc). + WithNodeURI(viper.GetString(FlagNode1)). + WithFrom(viper.GetString(FlagFrom1)) + + ctx2 := context.NewCLIContext(). + WithCodec(cdc). + WithNodeURI(viper.GetString(FlagNode2)). + WithFrom(viper.GetString(FlagFrom2)) + + conn1id, chan1id, conn2id, chan2id := args[0], args[1], args[2], args[3] + + obj1 := object(ctx1, cdc, storeKey, ibc.Version, conn1id, chan1id) + obj2 := object(ctx2, cdc, storeKey, ibc.Version, conn2id, chan2id) + + return relayLoop(cdc, ctx1, ctx2, obj1, obj2, conn1id, chan1id, conn2id, chan2id) + }, + } + + return cmd +} + +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) + } +} + +func relay(cdc *codec.Codec, ctxFrom, ctxTo context.CLIContext, objFrom, objTo channel.CLIObject, connidTo, chanidTo string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + + seq, _, err := objTo.SeqRecv(ctxTo) + if err != nil { + return err + } + + sent, _, err := objFrom.SeqSend(ctxFrom) + if err != nil { + return err + } + + 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 + } + } + + return nil +} +*/ package cli +import ( + "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" +) + /* func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { @@ -12,92 +136,133 @@ const ( FlagFrom2 = "from2" ) -// TODO -/* -func handshake(ctx context.CLIContext, cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid string) (channel.HandshakeObject, error) { +func handshake(q state.ABCIQuerier, cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid string) (channel.HandshakeObject, 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) { +func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "channel", + Short: "IBC channel 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 0, err + return } info, err := node.ABCIInfo() if err != nil { - return 0, err + return } - return uint64(info.Response.LastBlockHeight), nil + 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 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 + 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}, } - var conn1 channel.Channel - if err := cdc.UnmarshalJSON(conn1bz, &conn1); err != nil { - return err + + chan2 := channel.Channel{ + Counterparty: chanid1, + CounterpartyPort: portid1, + ConnectionHops: []string{connid2}, } - obj1, err := handshake(ctx1, cdc, storeKey, ibc.Version, conn1id, chan1id) + obj1, err := handshake(q1, cdc, storeKey, version.DefaultPrefix(), portid1, chanid1) if err != nil { return err } - conn2id := args[3] - chan2id := args[4] - conn2bz, err := ioutil.ReadFile(args[5]) + obj2, err := handshake(q2, cdc, storeKey, version.DefaultPrefix(), portid2, chanid2) if err != nil { return err } - var conn2 channel.Channel - if err := cdc.UnmarshalJSON(conn2bz, &conn2); err != nil { - return err - } - obj2, err := handshake(ctx2, cdc, storeKey, ibc.Version, conn1id, chan1id) + conn1, _, err := obj1.OriginConnection().ConnectionCLI(q1) if err != nil { return err } + clientid1 := conn1.Client - // TODO: check state and if not Idle continue existing process - height, err := lastheight(ctx2) + conn2, _, err := obj2.OriginConnection().ConnectionCLI(q2) if err != nil { return err } - nextTimeout := height + 1000 // TODO: parameterize + clientid2 := conn2.Client + + // TODO: check state and if not Idle continue existing process 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 +270,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.StateCLI(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 +315,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.StateCLI(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,21 +356,34 @@ 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.StateCLI(q1) if err != nil { return err } - msgconfirm := channel.MsgOpenConfirm{ - ConnectionID: conn2id, - ChannelID: chan2id, - Timeout: timeout, - Proofs: []commitment.Proof{pstate, ptimeout}, + msgconfirm := connection.MsgOpenConfirm{ + ConnectionID: connid2, + Proofs: []commitment.Proof{pstate}, + Height: uint64(header.Height), Signer: ctx2.GetFromAddress(), } @@ -198,87 +396,13 @@ func GetCmdChannelHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { }, } - return cmd -} - -func GetCmdRelay(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} - RunE: func(cmd *cobra.Command, args []string) error { - ctx1 := context.NewCLIContext(). - WithCodec(cdc). - WithNodeURI(viper.GetString(FlagNode1)). - WithFrom(viper.GetString(FlagFrom1)) - - ctx2 := context.NewCLIContext(). - WithCodec(cdc). - WithNodeURI(viper.GetString(FlagNode2)). - WithFrom(viper.GetString(FlagFrom2)) - - conn1id, chan1id, conn2id, chan2id := args[0], args[1], args[2], args[3] - - obj1 := object(ctx1, cdc, storeKey, ibc.Version, conn1id, chan1id) - obj2 := object(ctx2, cdc, storeKey, ibc.Version, conn2id, chan2id) + cmd.Flags().String(FlagNode1, "tcp://localhost:26657", "") + cmd.Flags().String(FlagNode2, "tcp://localhost:26657", "") + cmd.Flags().String(FlagFrom1, "", "") + cmd.Flags().String(FlagFrom2, "", "") - return relayLoop(cdc, ctx1, ctx2, obj1, obj2, conn1id, chan1id, conn2id, chan2id) - }, - } + cmd.MarkFlagRequired(FlagFrom1) + cmd.MarkFlagRequired(FlagFrom2) return cmd } - -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) - } -} - -func relay(cdc *codec.Codec, ctxFrom, ctxTo context.CLIContext, objFrom, objTo channel.CLIObject, connidTo, chanidTo string) error { - txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - - seq, _, err := objTo.SeqRecv(ctxTo) - if err != nil { - return err - } - - sent, _, err := objFrom.SeqSend(ctxFrom) - if err != nil { - return err - } - - 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 - } - } - - return nil -} -*/ diff --git a/x/ibc/04-channel/handler.go b/x/ibc/04-channel/handler.go index bb18de6e17e8..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.Height, 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.Height, 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,7 +29,7 @@ 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.Height, 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() } diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index d0cb14574c47..fd50dfa64476 100644 --- a/x/ibc/04-channel/handshake.go +++ b/x/ibc/04-channel/handshake.go @@ -48,8 +48,7 @@ type CounterpartyHandshaker struct { type HandshakeObject struct { Object - State state.Enum - NextTimeout state.Integer + State state.Enum counterparty CounterHandshakeObject } @@ -57,8 +56,7 @@ type HandshakeObject struct { type CounterHandshakeObject struct { CounterObject - State commitment.Enum - NextTimeout commitment.Integer + State commitment.Enum } // CONTRACT: client and remote must be filled by the caller @@ -68,8 +66,7 @@ func (man Handshaker) object(parent Object) HandshakeObject { return HandshakeObject{ Object: parent, - State: man.protocol.Value([]byte(prefix + "/state")).Enum(), - NextTimeout: man.protocol.Value([]byte(prefix + "/timeout")).Integer(state.Dec), + State: man.protocol.Value([]byte(prefix + "/state")).Enum(), counterparty: man.counterparty.object(parent.counterparty), } @@ -81,8 +78,7 @@ func (man CounterpartyHandshaker) object(parent CounterObject) CounterHandshakeO 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), + State: man.man.protocol.Value([]byte(prefix + "/state")).Enum(), } } @@ -125,7 +121,7 @@ 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, + portid, chanid string, channel Channel, ) (HandshakeObject, error) { // man.Create() will ensure // assert(connectionHops.length === 2) @@ -140,16 +136,15 @@ func (man Handshaker) OpenInit(ctx sdk.Context, return HandshakeObject{}, err } - obj.NextTimeout.Set(ctx, nextTimeoutHeight) obj.State.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, height uint64, - portid, chanid string, channel Channel, timeoutHeight, nextTimeoutHeight uint64, + portid, chanid string, channel Channel, ) (obj HandshakeObject, err error) { if len(channel.ConnectionHops) != 1 { return HandshakeObject{}, errors.New("ConnectionHops length must be 1") @@ -164,49 +159,26 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - err = assertTimeout(ctx, timeoutHeight) - if err != nil { - return - } - if !obj.counterparty.State.Is(ctx, Init) { err = errors.New("counterparty state not init") return } if !obj.counterparty.Channel.Is(ctx, Channel{ - Port: channel.CounterpartyPort, 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") - 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) return } @@ -214,7 +186,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // Using proofs: counterparty.{handshake,state,nextTimeout,clientid,client} func (man Handshaker) OpenAck(ctx sdk.Context, proofs []commitment.Proof, height uint64, - portid, chanid string, timeoutHeight, nextTimeoutHeight uint64, + portid, chanid string, ) (obj HandshakeObject, err error) { obj, err = man.query(ctx, portid, chanid) if err != nil { @@ -231,16 +203,9 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - err = assertTimeout(ctx, timeoutHeight) - if err != nil { - return - } - - channel := obj.GetChannel(ctx) if !obj.counterparty.Channel.Is(ctx, Channel{ - Port: channel.CounterpartyPort, Counterparty: chanid, - CounterpartyPort: channel.Port, + CounterpartyPort: portid, ConnectionHops: []string{obj.Connections[0].GetConnection(ctx).Counterparty}, }) { err = errors.New("wrong counterparty") @@ -252,11 +217,6 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.counterparty.NextTimeout.Is(ctx, timeoutHeight) { - err = errors.New("unexpected counterparty timeout value") - return - } - // TODO: commented out, implement in v1 /* var expected client.ConsensusState @@ -266,7 +226,6 @@ func (man Handshaker) OpenAck(ctx sdk.Context, } */ - obj.NextTimeout.Set(ctx, nextTimeoutHeight) obj.Available.Set(ctx, true) return @@ -275,7 +234,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, // Using proofs: counterparty.{connection,state, nextTimeout} func (man Handshaker) OpenConfirm(ctx sdk.Context, proofs []commitment.Proof, height uint64, - portid, chanid string, timeoutHeight uint64) (obj HandshakeObject, err error) { + portid, chanid string) (obj HandshakeObject, err error) { obj, err = man.query(ctx, portid, chanid) if err != nil { return @@ -291,23 +250,12 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, 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") - return - } - obj.Available.Set(ctx, true) - obj.NextTimeout.Set(ctx, 0) return } @@ -352,7 +300,7 @@ func (obj HandshakeObject) CloseInit(ctx sdk.Context, nextTimeout uint64) error return nil } -func (obj HandshakeObject) CloseTry(ctx sdk.Context, timeoutHeight, nextTimeoutHeight uint64) error { +func (obj HandshakeObject) CloseTry(ctx sdk.Context, nextTimeoutHeight uint64) error { if !obj.State.Transit(ctx, Open, Closed) { return errors.New("closetry on non-open connection") } diff --git a/x/ibc/04-channel/msgs.go b/x/ibc/04-channel/msgs.go index adb764900798..3fba21f320b4 100644 --- a/x/ibc/04-channel/msgs.go +++ b/x/ibc/04-channel/msgs.go @@ -8,12 +8,10 @@ import ( const Route = "ibc" type MsgOpenInit struct { - ConnectionID string `json:"connection_id"` - ChannelID string `json:"channel_id"` - Channel Channel `json:"channel"` - CounterpartyClient string `json:"counterparty_client"` - NextTimeout uint64 `json:"next_timeout"` - Signer sdk.AccAddress `json:"signer"` + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Channel Channel `json:"channel"` + Signer sdk.AccAddress `json:"signer"` } var _ sdk.Msg = MsgOpenInit{} @@ -39,15 +37,12 @@ func (msg MsgOpenInit) GetSigners() []sdk.AccAddress { } type MsgOpenTry struct { - ConnectionID string `json:"connection_id"` - ChannelID string `json:"channel_id"` - Channel Channel `json:"channel"` - 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"` + 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{} @@ -73,13 +68,11 @@ func (msg MsgOpenTry) GetSigners() []sdk.AccAddress { } type MsgOpenAck struct { - ConnectionID string `json:"connection_id"` - ChannelID string `json:"channel_id"` - Timeout uint64 `json:"timeout"` - NextTimeout uint64 `json:"next_timeout"` - Proofs []commitment.Proof `json:"proofs"` - Height uint64 `json:"height"` - Signer sdk.AccAddress `json:"signer"` + 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{} @@ -105,12 +98,11 @@ func (msg MsgOpenAck) GetSigners() []sdk.AccAddress { } type MsgOpenConfirm struct { - ConnectionID string `json:"connection_id"` - ChannelID string `json:"channel_id"` - Timeout uint64 `json:"timeout"` - Proofs []commitment.Proof `json:"proofs"` - Height uint64 `json:"height"` - Signer sdk.AccAddress `json:"signer"` + 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{} diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index 1079fccfc8c0..9d159960653b 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -41,14 +41,12 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { } res.Channel = channel.Channel{ - Port: PortName, Counterparty: res.Counterparty.Name, CounterpartyPort: PortName, ConnectionHops: []string{res.Name}, } res.Counterparty.Channel = channel.Channel{ - Port: PortName, Counterparty: res.Name, CounterpartyPort: PortName, ConnectionHops: []string{res.Counterparty.Name}, @@ -85,7 +83,7 @@ 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, PortName, 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, node.Channel, obj.GetChannel(ctx)) @@ -94,7 +92,7 @@ func (node *Node) OpenInit(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, height, PortName, 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, node.Channel, obj.GetChannel(ctx)) @@ -104,7 +102,7 @@ func (node *Node) OpenTry(t *testing.T, height uint64, proofs ...commitment.Proo func (node *Node) OpenAck(t *testing.T, height uint64, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenAck(ctx, proofs, height, PortName, 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, node.Channel, obj.GetChannel(ctx)) @@ -114,7 +112,7 @@ func (node *Node) OpenAck(t *testing.T, height uint64, proofs ...commitment.Proo func (node *Node) OpenConfirm(t *testing.T, height uint64, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenConfirm(ctx, proofs, height, PortName, 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, node.Channel, obj.GetChannel(ctx)) @@ -134,8 +132,7 @@ func (node *Node) Handshake(t *testing.T) { cliobj := node.CLIObject() _, pchan := node.QueryValue(t, cliobj.Channel) _, pstate := node.QueryValue(t, cliobj.State) - _, ptimeout := node.QueryValue(t, cliobj.NextTimeout) - node.Counterparty.OpenTry(t, uint64(header.Height), pchan, pstate, ptimeout) + node.Counterparty.OpenTry(t, uint64(header.Height), pchan, pstate) header = node.Counterparty.Commit() // self.OpenAck @@ -143,16 +140,14 @@ func (node *Node) Handshake(t *testing.T) { cliobj = node.Counterparty.CLIObject() _, pchan = node.Counterparty.QueryValue(t, cliobj.Channel) _, pstate = node.Counterparty.QueryValue(t, cliobj.State) - _, ptimeout = node.Counterparty.QueryValue(t, cliobj.NextTimeout) - node.OpenAck(t, uint64(header.Height), pchan, pstate, ptimeout) + 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, uint64(header.Height), pstate, ptimeout) + node.Counterparty.OpenConfirm(t, uint64(header.Height), pstate) } func (node *Node) Send(t *testing.T, packet channel.Packet) { diff --git a/x/ibc/04-channel/types.go b/x/ibc/04-channel/types.go index d186a786bb2d..7714dfe5e24c 100644 --- a/x/ibc/04-channel/types.go +++ b/x/ibc/04-channel/types.go @@ -25,11 +25,10 @@ type Packet interface { ValidateBasic() sdk.Error Timeout() uint64 MarshalAmino() (string, error) // Should exclude PortID/ChannelID info - MarshalJSON() ([]byte, error) // Should exclude PortID/ChannelID info + MarshalJSON() ([]byte, error) // Should exclude PortID/ChannelID info } type Channel struct { - Port string Counterparty string CounterpartyPort string ConnectionHops []string diff --git a/x/ibc/module.go b/x/ibc/module.go index 602930a9525b..4990660b33f4 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -19,6 +19,7 @@ import ( 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" ) @@ -75,7 +76,7 @@ func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { cmd.AddCommand( clicli.GetTxCmd(ModuleName, cdc), conncli.GetTxCmd(ModuleName, cdc), - // chancli.GetTxCmd(ModuleName, cdc), + chancli.GetTxCmd(ModuleName, cdc), ) return cmd @@ -90,7 +91,7 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { cmd.AddCommand( clicli.GetQueryCmd(ModuleName, cdc), conncli.GetQueryCmd(ModuleName, cdc), - // chancli.GetQueryCmd(ModuleName, cdc), + chancli.GetQueryCmd(ModuleName, cdc), ) return cmd From 4b81cb5431d409ef5b23fddfe31e90108ca2b083 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 20 Sep 2019 18:18:33 +0200 Subject: [PATCH 229/378] fix golangci --- x/ibc/03-connection/client/cli/tx.go | 15 ++++++++++++--- x/ibc/mock/handler.go | 5 ++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index 0ecb6c97cf61..f1550c85a5a5 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -187,7 +187,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - // Another block has to be passed after msginit is commited + // Another block has to be passed after msginit is committed // to retrieve the correct proofs time.Sleep(8 * time.Second) @@ -203,6 +203,9 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { } err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgupdate}) + if err != nil { + return err + } fmt.Printf("updated apphash to %X\n", header.AppHash) @@ -236,7 +239,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - // Another block has to be passed after msginit is commited + // Another block has to be passed after msginit is committed // to retrieve the correct proofs time.Sleep(8 * time.Second) @@ -252,6 +255,9 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { } err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgupdate}) + if err != nil { + return err + } q2 = state.NewCLIQuerier(ctx2.WithHeight(header.Height - 1)) @@ -280,7 +286,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - // Another block has to be passed after msginit is commited + // Another block has to be passed after msginit is committed // to retrieve the correct proofs time.Sleep(8 * time.Second) @@ -296,6 +302,9 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { } err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgupdate}) + if err != nil { + return err + } q1 = state.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) diff --git a/x/ibc/mock/handler.go b/x/ibc/mock/handler.go index aa7b8168b62e..4706c58a4ec7 100644 --- a/x/ibc/mock/handler.go +++ b/x/ibc/mock/handler.go @@ -14,9 +14,12 @@ func NewHandler(k Keeper) sdk.Handler { 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() } - return sdk.ErrUnknownRequest("21345").Result() } } From 3866942f3343db83097fc51b881b3241e991cec4 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 20 Sep 2019 18:56:39 +0200 Subject: [PATCH 230/378] fix cli --- store/state/integer.go | 4 + x/ibc/03-connection/codec.go | 8 +- x/ibc/04-channel/client/cli/query.go | 13 +-- x/ibc/04-channel/client/cli/tx.go | 129 +++------------------------ x/ibc/04-channel/codec.go | 5 ++ 5 files changed, 31 insertions(+), 128 deletions(-) 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/x/ibc/03-connection/codec.go b/x/ibc/03-connection/codec.go index 49d5c7678fdd..a3e2284b38a8 100644 --- a/x/ibc/03-connection/codec.go +++ b/x/ibc/03-connection/codec.go @@ -7,10 +7,10 @@ import ( var MsgCdc *codec.Codec func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(MsgOpenInit{}, "ibc/client/MsgOpenInit", nil) - cdc.RegisterConcrete(MsgOpenTry{}, "ibc/client/MsgOpenTry", nil) - cdc.RegisterConcrete(MsgOpenAck{}, "ibc/client/MsgOpenAck", nil) - cdc.RegisterConcrete(MsgOpenConfirm{}, "ibc/client/MsgOpenConfirm", nil) + 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) { diff --git a/x/ibc/04-channel/client/cli/query.go b/x/ibc/04-channel/client/cli/query.go index 9a5c7d4fb9b7..fcf28355d303 100644 --- a/x/ibc/04-channel/client/cli/query.go +++ b/x/ibc/04-channel/client/cli/query.go @@ -23,12 +23,12 @@ const ( FlagProve = "prove" ) -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.Object, 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 { @@ -87,12 +87,15 @@ func QueryChannel(ctx context.CLIContext, obj channel.Object, prove bool) (res u func GetCmdQueryChannel(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "connection", + Use: "channel", Short: "Query stored connection", - Args: cobra.ExactArgs(3), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) - obj := object(cdc, storeKey, version.DefaultPrefix(), args[0], args[1], []string{args[2]}) + 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 diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index 90696ee9ab6d..476ed72f9313 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -1,101 +1,3 @@ -/* - - -func lastheight(ctx context.CLIContext) (uint64, error) { - node, err := ctx.GetNode() - if err != nil { - return 0, err - } - - info, err := node.ABCIInfo() - if err != nil { - return 0, err - } - - return uint64(info.Response.LastBlockHeight), nil -} - -func GetCmdRelay(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} - RunE: func(cmd *cobra.Command, args []string) error { - ctx1 := context.NewCLIContext(). - WithCodec(cdc). - WithNodeURI(viper.GetString(FlagNode1)). - WithFrom(viper.GetString(FlagFrom1)) - - ctx2 := context.NewCLIContext(). - WithCodec(cdc). - WithNodeURI(viper.GetString(FlagNode2)). - WithFrom(viper.GetString(FlagFrom2)) - - conn1id, chan1id, conn2id, chan2id := args[0], args[1], args[2], args[3] - - obj1 := object(ctx1, cdc, storeKey, ibc.Version, conn1id, chan1id) - obj2 := object(ctx2, cdc, storeKey, ibc.Version, conn2id, chan2id) - - return relayLoop(cdc, ctx1, ctx2, obj1, obj2, conn1id, chan1id, conn2id, chan2id) - }, - } - - return cmd -} - -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) - } -} - -func relay(cdc *codec.Codec, ctxFrom, ctxTo context.CLIContext, objFrom, objTo channel.CLIObject, connidTo, chanidTo string) error { - txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - - seq, _, err := objTo.SeqRecv(ctxTo) - if err != nil { - return err - } - - sent, _, err := objFrom.SeqSend(ctxFrom) - if err != nil { - return err - } - - 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 - } - } - - return nil -} -*/ package cli import ( @@ -124,11 +26,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/version" ) -/* -func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - -} -*/ const ( FlagNode1 = "node1" FlagNode2 = "node2" @@ -136,12 +33,12 @@ const ( FlagFrom2 = "from2" ) -func handshake(q state.ABCIQuerier, 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.HandshakeObject { 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(q, portid, chanid) + return man.CLIObject(portid, chanid, []string{connid}) } func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { @@ -235,15 +132,8 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { ConnectionHops: []string{connid2}, } - obj1, err := handshake(q1, cdc, storeKey, version.DefaultPrefix(), portid1, chanid1) - if err != nil { - return err - } - - obj2, err := handshake(q2, cdc, storeKey, version.DefaultPrefix(), portid2, chanid2) - if err != nil { - return err - } + 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 { @@ -380,11 +270,12 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgconfirm := connection.MsgOpenConfirm{ - ConnectionID: connid2, - Proofs: []commitment.Proof{pstate}, - Height: uint64(header.Height), - Signer: ctx2.GetFromAddress(), + msgconfirm := channel.MsgOpenConfirm{ + PortID: portid2, + ChannelID: chanid2, + Proofs: []commitment.Proof{pstate}, + Height: uint64(header.Height), + Signer: ctx2.GetFromAddress(), } err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgconfirm}) diff --git a/x/ibc/04-channel/codec.go b/x/ibc/04-channel/codec.go index ebf30115d09a..112aedc4c40c 100644 --- a/x/ibc/04-channel/codec.go +++ b/x/ibc/04-channel/codec.go @@ -8,6 +8,11 @@ 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) { From 6e6c186342266a14e16ef3990beeb8c719cf0417 Mon Sep 17 00:00:00 2001 From: Timothy Chen Date: Tue, 24 Sep 2019 22:21:16 -0700 Subject: [PATCH 231/378] Clean up --- x/ibc/02-client/README.md | 2 +- x/ibc/02-client/codec.go | 6 - x/ibc/02-client/manager.go | 2 +- x/ibc/03-connection/cli.go | 24 +-- x/ibc/03-connection/client/cli/query.go | 4 +- x/ibc/03-connection/client/cli/tx.go | 85 +++++---- x/ibc/03-connection/handler.go | 4 + x/ibc/03-connection/handshake.go | 116 ++++++------- x/ibc/03-connection/manager.go | 40 ++--- x/ibc/03-connection/tests/types.go | 6 +- x/ibc/03-connection/types.go | 2 +- x/ibc/04-channel/cli.go | 28 +-- x/ibc/04-channel/client/cli/query.go | 6 +- x/ibc/04-channel/client/cli/tx.go | 70 ++++---- x/ibc/04-channel/codec.go | 6 - x/ibc/04-channel/handshake.go | 219 ++++++------------------ x/ibc/04-channel/manager.go | 169 ++++++------------ x/ibc/04-channel/port.go | 14 +- x/ibc/04-channel/tests/types.go | 6 +- x/ibc/23-commitment/merkle/merkle.go | 1 - x/ibc/23-commitment/store.go | 6 +- x/ibc/23-commitment/value.go | 1 - x/ibc/keeper.go | 6 +- x/ibc/mock/types/msgs.go | 2 +- 24 files changed, 323 insertions(+), 502 deletions(-) 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/codec.go b/x/ibc/02-client/codec.go index d130e624f476..18dd6da686e8 100644 --- a/x/ibc/02-client/codec.go +++ b/x/ibc/02-client/codec.go @@ -15,11 +15,5 @@ func RegisterCodec(cdc *codec.Codec) { } func SetMsgCodec(cdc *codec.Codec) { - // TODO - /* - if MsgCdc != nil && MsgCdc != cdc { - panic("MsgCdc set more than once") - } - */ MsgCdc = cdc } diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 1a732c6dc824..06927c33d1eb 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -78,7 +78,7 @@ func (man CounterpartyManager) Query(id string) CounterObject { return man.Object(id) } -// Any actor holding the Object can access on and modify that client information +// Any actor holding the Stage can access on and modify that client information type Object struct { id string Roots state.Indexer diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index 7fa3986465d7..ca114e8e2e8c 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -7,55 +7,55 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func (man Manager) CLIObject(connid, clientid string) Object { +func (man Manager) CLIObject(connid, clientid string) State { obj := man.Object(connid) obj.Client = man.client.Object(clientid) return obj } -func (obj Object) prefix() []byte { +func (obj State) prefix() []byte { return bytes.Split(obj.Connection.KeyBytes(), LocalRoot())[0] } -func (obj Object) ConnectionCLI(q state.ABCIQuerier) (res Connection, proof merkle.Proof, err error) { +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(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { +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(q state.ABCIQuerier) (res string, proof merkle.Proof, err error) { +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) CLIObject(connid, clientid string) HandshakeState { + return man.CreateState(man.man.CLIObject(connid, clientid)) } -func (man Handshaker) CLIQuery(q state.ABCIQuerier, connid string) (HandshakeObject, error) { +func (man Handshaker) CLIQuery(q state.ABCIQuerier, connid string) (HandshakeState, error) { obj := man.man.Object(connid) conn, _, err := obj.ConnectionCLI(q) 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(obj), nil } -func (obj HandshakeObject) StateCLI(q state.ABCIQuerier) (res byte, proof merkle.Proof, err error) { +func (obj HandshakeState) StateCLI(q state.ABCIQuerier) (res byte, proof merkle.Proof, err error) { res, tmproof, err := obj.State.Query(q) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.State) return } -func (obj HandshakeObject) CounterpartyClientCLI(q state.ABCIQuerier) (res string, proof merkle.Proof, err error) { +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 diff --git a/x/ibc/03-connection/client/cli/query.go b/x/ibc/03-connection/client/cli/query.go index b01280c2fa33..63b563c5d44b 100644 --- a/x/ibc/03-connection/client/cli/query.go +++ b/x/ibc/03-connection/client/cli/query.go @@ -22,7 +22,7 @@ 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) @@ -43,7 +43,7 @@ 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) { +func QueryConnection(ctx context.CLIContext, obj connection.State, prove bool) (res utils.JSONObject, err error) { q := state.NewCLIQuerier(ctx) conn, connp, err := obj.ConnectionCLI(q) diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index f1550c85a5a5..50e1f0ddf661 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -26,11 +26,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/version" ) -/* -func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - -} -*/ const ( FlagNode1 = "node1" FlagNode2 = "node2" @@ -38,14 +33,14 @@ const ( FlagFrom2 = "from2" ) -func handshake(q state.ABCIQuerier, 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)) + 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 @@ -116,7 +111,6 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { Use: "handshake", Short: "initiate connection handshake between two chains", Args: cobra.ExactArgs(6), - // Args: []string{connid1, clientid1, path1, connid2, clientid2, connfilepath2} RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) ctx1 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). @@ -131,10 +125,10 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { WithBroadcastMode(flags.BroadcastBlock) q2 := state.NewCLIQuerier(ctx2) - connid1 := args[0] - clientid1 := args[1] - connid2 := args[3] - clientid2 := args[4] + connId1 := args[0] + clientId1 := args[1] + connId2 := args[3] + clientId2 := args[4] var path1 commitment.Path path1bz, err := ioutil.ReadFile(args[2]) @@ -145,12 +139,12 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } conn1 := connection.Connection{ - Client: clientid1, - Counterparty: connid2, + Client: clientId1, + Counterparty: connId2, Path: path1, } - obj1, err := handshake(q1, cdc, storeKey, version.DefaultPrefix(), connid1) + obj1, err := handshake(q1, cdc, storeKey, version.DefaultPrefix(), connId1) if err != nil { return err } @@ -164,31 +158,33 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } conn2 := connection.Connection{ - Client: clientid2, - Counterparty: connid1, + Client: clientId2, + Counterparty: connId1, Path: path2, } - obj2, err := handshake(q2, cdc, storeKey, version.DefaultPrefix(), connid2) + obj2, err := handshake(q2, cdc, storeKey, version.DefaultPrefix(), connId2) if err != nil { return err } // TODO: check state and if not Idle continue existing process - msginit := connection.MsgOpenInit{ - ConnectionID: connid1, + msgInit := connection.MsgOpenInit{ + ConnectionID: connId1, Connection: conn1, CounterpartyClient: conn2.Client, Signer: ctx1.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msginit}) + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgInit}) if err != nil { return err } - // Another block has to be passed after msginit is committed + // 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) @@ -196,19 +192,17 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgupdate := client.MsgUpdateClient{ + msgUpdate := client.MsgUpdateClient{ ClientID: conn2.Client, Header: header, Signer: ctx2.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgupdate}) + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) if err != nil { return err } - 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) @@ -225,8 +219,8 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgtry := connection.MsgOpenTry{ - ConnectionID: connid2, + msgTry := connection.MsgOpenTry{ + ConnectionID: connId2, Connection: conn2, CounterpartyClient: conn1.Client, Proofs: []commitment.Proof{pconn, pstate, pcounter}, @@ -234,13 +228,15 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { Signer: ctx2.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgtry}) + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgTry}) if err != nil { return err } - // Another block has to be passed after msginit is committed + // 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) @@ -248,13 +244,13 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgupdate = client.MsgUpdateClient{ + msgUpdate = client.MsgUpdateClient{ ClientID: conn1.Client, Header: header, Signer: ctx1.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgupdate}) + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgUpdate}) if err != nil { return err } @@ -274,20 +270,22 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgack := connection.MsgOpenAck{ - ConnectionID: connid1, + 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 + // 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) @@ -295,13 +293,13 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgupdate = client.MsgUpdateClient{ + msgUpdate = client.MsgUpdateClient{ ClientID: conn2.Client, Header: header, Signer: ctx2.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgupdate}) + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) if err != nil { return err } @@ -313,14 +311,14 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgconfirm := connection.MsgOpenConfirm{ - ConnectionID: connid2, + 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 } @@ -329,6 +327,7 @@ func GetCmdHandshake(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, "", "") diff --git a/x/ibc/03-connection/handler.go b/x/ibc/03-connection/handler.go index 8395579663d2..f516c0a5d6df 100644 --- a/x/ibc/03-connection/handler.go +++ b/x/ibc/03-connection/handler.go @@ -7,6 +7,7 @@ import ( func HandleMsgOpenInit(ctx sdk.Context, msg MsgOpenInit, man Handshaker) sdk.Result { _, err := man.OpenInit(ctx, msg.ConnectionID, msg.Connection, msg.CounterpartyClient) if err != nil { + // TODO: Define the error code in errors return sdk.NewError(sdk.CodespaceType("ibc"), 100, err.Error()).Result() } return sdk.Result{} @@ -15,6 +16,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.Height, msg.ConnectionID, msg.Connection, msg.CounterpartyClient) if err != nil { + // TODO: Define the error code in errors return sdk.NewError(sdk.CodespaceType("ibc"), 200, err.Error()).Result() } return sdk.Result{} @@ -23,6 +25,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.Height, msg.ConnectionID) if err != nil { + // TODO: Define the error code in errors return sdk.NewError(sdk.CodespaceType("ibc"), 300, err.Error()).Result() } return sdk.Result{} @@ -31,6 +34,7 @@ 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.Height, msg.ConnectionID) if err != nil { + // 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 04eb96fc298f..e4c59386d2f6 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -9,10 +9,10 @@ import ( 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,92 +39,90 @@ type CounterpartyHandshaker struct { man CounterpartyManager } -type HandshakeObject struct { - Object +type HandshakeState struct { + State - State state.Enum + Stage state.Enum CounterpartyClient state.String - Counterparty CounterHandshakeObject + Counterparty CounterHandshakeState } -type CounterHandshakeObject struct { - CounterObject +type CounterHandshakeState struct { + CounterState - State commitment.Enum + Stage commitment.Enum CounterpartyClient commitment.String } // 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(), - // 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(), } } -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) } // Using proofs: none func (man Handshaker) OpenInit(ctx sdk.Context, id string, connection Connection, counterpartyClient string, -) (HandshakeObject, error) { +) (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.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, height uint64, id string, connection Connection, counterpartyClient string, -) (obj HandshakeObject, err error) { +) (obj HandshakeState, err error) { obj, err = man.create(ctx, id, connection, counterpartyClient) if err != nil { return @@ -139,8 +133,8 @@ func (man Handshaker) OpenTry(ctx sdk.Context, 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 } @@ -149,12 +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") + err = errors.New("counterParty client not match") return } @@ -164,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") } */ @@ -174,16 +168,16 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // assert(get("connections/{desiredIdentifier}") === null) and // set("connections{identifier}", connection) - obj.State.Set(ctx, OpenTry) + 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, height uint64, id string, -) (obj HandshakeObject, err error) { +) (obj HandshakeState, err error) { obj, err = man.query(ctx, id) if err != nil { return @@ -194,7 +188,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.State.Transit(ctx, Init, Open) { + if !obj.Stage.Transit(ctx, Init, Open) { err = errors.New("ack on non-init connection") return } @@ -204,17 +198,17 @@ func (man Handshaker) OpenAck(ctx sdk.Context, 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") + err = errors.New("counterParty client not match") return } @@ -222,8 +216,8 @@ 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) @@ -231,10 +225,10 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } -// Using proofs: counterparty.{connection,state, nextTimeout} +// Using proofs: counterParty.{connection,state, nextTimeout} func (man Handshaker) OpenConfirm(ctx sdk.Context, proofs []commitment.Proof, height uint64, - id string) (obj HandshakeObject, err error) { + id string) (obj HandshakeState, err error) { obj, err = man.query(ctx, id) if err != nil { @@ -246,13 +240,13 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, return } - if !obj.State.Transit(ctx, OpenTry, Open) { + if !obj.Stage.Transit(ctx, OpenTry, Open) { err = errors.New("confirm on non-try connection") return } - if !obj.Counterparty.State.Is(ctx, Open) { - err = errors.New("counterparty state not open") + if !obj.Counterparty.Stage.Is(ctx, Open) { + err = errors.New("counterParty state not open") return } diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index 57e5a3456fea..a1c500af415a 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -47,7 +47,7 @@ func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { } } -type Object struct { +type State struct { id string protocol state.Mapping @@ -61,8 +61,8 @@ type Object struct { path merkle.Path } -func (man Manager) Object(id string) Object { - return Object{ +func (man Manager) Object(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 @@ -89,8 +89,8 @@ type CounterObject struct { Client client.CounterObject // 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,7 +102,7 @@ func (man CounterpartyManager) Object(id string) CounterObject { } } -func (obj Object) Context(ctx sdk.Context, height uint64, proofs []commitment.Proof) (sdk.Context, error) { +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 @@ -120,30 +120,30 @@ func (obj Object) Context(ctx sdk.Context, height uint64, proofs []commitment.Pr 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) { +func (man Manager) create(ctx sdk.Context, id string, connection Connection, kind string) (obj State, err error) { obj = man.Object(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) { +func (man Manager) query(ctx sdk.Context, id string, kind string) (obj State, err error) { obj = man.Object(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) { +func (man Manager) Query(ctx sdk.Context, id string) (obj State, err error) { obj = man.Object(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/tests/types.go b/x/ibc/03-connection/tests/types.go index 0162b392b494..83ee9543ea56 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -22,7 +22,7 @@ type Node struct { CounterpartyClient string Connection connection.Connection - State connection.State + State connection.HandshakeStage Cdc *codec.Codec } @@ -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,7 +92,7 @@ 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) CLIObject() connection.HandshakeState { _, man := node.Manager() return connection.NewHandshaker(man).CLIObject(node.Name, node.Name) } diff --git a/x/ibc/03-connection/types.go b/x/ibc/03-connection/types.go index af5b1c987689..81c1eca05ae4 100644 --- a/x/ibc/03-connection/types.go +++ b/x/ibc/03-connection/types.go @@ -10,7 +10,7 @@ import ( type Connection struct { Client string `json:"client"` - Counterparty string `json:"counterparty"` + 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 ebf0f1755890..9dae276d567f 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -7,7 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func (man Manager) CLIObject(portid, chanid string, connids []string) Object { +func (man Manager) CLIObject(portid, chanid string, connids []string) State { obj := man.object(portid, chanid) for _, connid := range connids { obj.Connections = append(obj.Connections, man.connection.Object(connid)) @@ -15,7 +15,7 @@ func (man Manager) CLIObject(portid, chanid string, connids []string) Object { return obj } -func (man Manager) CLIQuery(q state.ABCIQuerier, 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(q) if err != nil { @@ -27,54 +27,54 @@ func (man Manager) CLIQuery(q state.ABCIQuerier, portid, chanid string) (obj Obj return } -func (obj Object) prefix() []byte { +func (obj State) prefix() []byte { return bytes.Split(obj.Channel.KeyBytes(), LocalRoot())[0] } -func (obj Object) ChannelCLI(q state.ABCIQuerier) (res Channel, proof merkle.Proof, err error) { +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(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { +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(q state.ABCIQuerier) (res uint64, proof merkle.Proof, err error) { +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(q state.ABCIQuerier) (res uint64, proof merkle.Proof, err error) { +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(q state.ABCIQuerier, 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(q, &res) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), packet) return } -func (man Handshaker) CLIQuery(q state.ABCIQuerier, portid, chanid string) (HandshakeObject, error) { +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 + return man.createState(obj), nil } -func (man Handshaker) CLIObject(portid, chanid string, connids []string) HandshakeObject { - return man.object(man.Manager.CLIObject(portid, chanid, connids)) +func (man Handshaker) CLIObject(portid, chanid string, connids []string) HandshakeState { + return man.createState(man.Manager.CLIObject(portid, chanid, connids)) } -func (obj HandshakeObject) StateCLI(q state.ABCIQuerier) (res State, proof merkle.Proof, err error) { +func (obj HandshakeState) StateCLI(q state.ABCIQuerier) (res HandshakeStage, proof merkle.Proof, err error) { res, tmproof, err := obj.State.Query(q) proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.State) return diff --git a/x/ibc/04-channel/client/cli/query.go b/x/ibc/04-channel/client/cli/query.go index fcf28355d303..04e3ca0b19be 100644 --- a/x/ibc/04-channel/client/cli/query.go +++ b/x/ibc/04-channel/client/cli/query.go @@ -23,7 +23,7 @@ const ( FlagProve = "prove" ) -func object(ctx context.CLIContext, cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid string) (channel.Object, error) { +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) @@ -45,7 +45,7 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { return ibcQueryCmd } -func QueryChannel(ctx context.CLIContext, obj channel.Object, prove bool) (res utils.JSONObject, err error) { +func QueryChannel(ctx context.CLIContext, obj channel.State, prove bool) (res utils.JSONObject, err error) { q := state.NewCLIQuerier(ctx) conn, connp, err := obj.ChannelCLI(q) @@ -113,7 +113,7 @@ func GetCmdQueryChannel(storeKey string, cdc *codec.Codec) *cobra.Command { } /* -func object(cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid string, connids []string) channel.Object { +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) diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index 476ed72f9313..81c0cc8022f5 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -33,12 +33,12 @@ const ( FlagFrom2 = "from2" ) -func handshake(cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid, connid string) channel.HandshakeObject { +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.CLIObject(portid, chanid, []string{connid}) + clientManager := client.NewManager(base) + connectionManager := connection.NewManager(base, clientManager) + man := channel.NewHandshaker(channel.NewManager(base, connectionManager)) + return man.CLIObject(portId, chanId, []string{connId}) } func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { @@ -67,19 +67,19 @@ func getHeader(ctx context.CLIContext) (res tendermint.Header, err error) { } height := info.Response.LastBlockHeight - prevheight := height - 1 + prevHeight := height - 1 commit, err := node.Commit(&height) if err != nil { return } - validators, err := node.Validators(&prevheight) + validators, err := node.Validators(&prevHeight) if err != nil { return } - nextvalidators, err := node.Validators(&height) + nextValidators, err := node.Validators(&height) if err != nil { return } @@ -87,7 +87,7 @@ func getHeader(ctx context.CLIContext) (res tendermint.Header, err error) { res = tendermint.Header{ SignedHeader: commit.SignedHeader, ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), + NextValidatorSet: tmtypes.NewValidatorSet(nextValidators.Validators), } return @@ -98,7 +98,6 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { Use: "handshake", 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.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). @@ -139,29 +138,31 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { if err != nil { return err } - clientid1 := conn1.Client + clientId1 := conn1.Client conn2, _, err := obj2.OriginConnection().ConnectionCLI(q2) if err != nil { return err } - clientid2 := conn2.Client + clientId2 := conn2.Client // TODO: check state and if not Idle continue existing process - msginit := channel.MsgOpenInit{ + msgInit := channel.MsgOpenInit{ PortID: portid1, ChannelID: chanid1, Channel: chan1, Signer: ctx1.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msginit}) + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgInit}) if err != nil { return err } - // Another block has to be passed after msginit is commited + // Another block has to be passed after msgInit is commited // 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) @@ -169,13 +170,13 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgupdate := client.MsgUpdateClient{ - ClientID: clientid2, + msgUpdate := client.MsgUpdateClient{ + ClientID: clientId2, Header: header, Signer: ctx2.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgupdate}) + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) fmt.Printf("updated apphash to %X\n", header.AppHash) @@ -191,7 +192,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgtry := channel.MsgOpenTry{ + msgTry := channel.MsgOpenTry{ PortID: portid2, ChannelID: chanid2, Channel: chan2, @@ -200,13 +201,15 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { Signer: ctx2.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgtry}) + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgTry}) if err != nil { return err } - // Another block has to be passed after msginit is commited + // Another block has to be passed after msgInit is commited // 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) @@ -214,13 +217,13 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgupdate = client.MsgUpdateClient{ - ClientID: clientid1, + msgUpdate = client.MsgUpdateClient{ + ClientID: clientId1, Header: header, Signer: ctx1.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgupdate}) + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgUpdate}) q2 = state.NewCLIQuerier(ctx2.WithHeight(header.Height - 1)) @@ -233,7 +236,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgack := channel.MsgOpenAck{ + msgAck := channel.MsgOpenAck{ PortID: portid1, ChannelID: chanid1, Proofs: []commitment.Proof{pchan, pstate}, @@ -241,13 +244,15 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { 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 commited + // Another block has to be passed after msgInit is commited // 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) @@ -255,13 +260,13 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgupdate = client.MsgUpdateClient{ - ClientID: clientid2, + msgUpdate = client.MsgUpdateClient{ + ClientID: clientId2, Header: header, Signer: ctx2.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgupdate}) + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) q1 = state.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) @@ -270,7 +275,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgconfirm := channel.MsgOpenConfirm{ + msgConfirm := channel.MsgOpenConfirm{ PortID: portid2, ChannelID: chanid2, Proofs: []commitment.Proof{pstate}, @@ -278,7 +283,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { Signer: ctx2.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgconfirm}) + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgConfirm}) if err != nil { return err } @@ -287,6 +292,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { }, } + // TODO: Create flag description cmd.Flags().String(FlagNode1, "tcp://localhost:26657", "") cmd.Flags().String(FlagNode2, "tcp://localhost:26657", "") cmd.Flags().String(FlagFrom1, "", "") diff --git a/x/ibc/04-channel/codec.go b/x/ibc/04-channel/codec.go index 112aedc4c40c..38654da4e6a9 100644 --- a/x/ibc/04-channel/codec.go +++ b/x/ibc/04-channel/codec.go @@ -16,11 +16,5 @@ func RegisterCodec(cdc *codec.Codec) { } func SetMsgCodec(cdc *codec.Codec) { - // TODO - /* - if msgCdc != nil && msgCdc != cdc { - panic("MsgCdc set more than once") - } - */ msgCdc = cdc } diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go index fd50dfa64476..850d97546e9e 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 HandshakeStage = byte const ( - Idle State = iota + Idle HandshakeStage = iota Init OpenTry Open @@ -23,21 +23,17 @@ const ( type Handshaker struct { 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{ - Manager: man, - - counterparty: CounterpartyHandshaker{man.counterparty}, + Manager: man, + counterParty: CounterpartyHandshaker{man.counterParty}, } } @@ -45,67 +41,64 @@ type CounterpartyHandshaker struct { man CounterpartyManager } -type HandshakeObject struct { - Object +type HandshakeState struct { + State - State state.Enum + HandshakeStage state.Enum - counterparty CounterHandshakeObject + counterParty CounterHandshakeState } -type CounterHandshakeObject struct { - CounterObject +type CounterHandshakeState struct { + CounterState - State commitment.Enum + 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, +func (man Handshaker) createState(parent State) HandshakeState { + prefix := parent.portId + "/channels/" + parent.chanId - State: man.protocol.Value([]byte(prefix + "/state")).Enum(), - - counterparty: man.counterparty.object(parent.counterparty), + return HandshakeState{ + State: parent, + HandshakeStage: 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 - - return CounterHandshakeObject{ - CounterObject: man.man.object(parent.portid, parent.chanid), +func (man CounterpartyHandshaker) createState(parent CounterState) CounterHandshakeState { + prefix := parent.portId + "/channels/" + parent.chanId - State: man.man.protocol.Value([]byte(prefix + "/state")).Enum(), + 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) { +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) { +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.HandshakeStage.Delete(ctx) obj.counterpartyClient.Delete(ctx) obj.NextTimeout.Delete(ctx) } @@ -122,32 +115,32 @@ func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { // Using proofs: none func (man Handshaker) OpenInit(ctx sdk.Context, portid, chanid string, channel Channel, -) (HandshakeObject, error) { +) (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.State.Set(ctx, Init) + obj.HandshakeStage.Set(ctx, Init) return obj, nil } -// Using proofs: counterparty.{channel,state} +// Using proofs: counterParty.{channel,state} func (man Handshaker) OpenTry(ctx sdk.Context, proofs []commitment.Proof, height uint64, portid, chanid string, channel Channel, -) (obj HandshakeObject, err error) { +) (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 { @@ -159,17 +152,17 @@ func (man Handshaker) OpenTry(ctx sdk.Context, 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{ + if !obj.counterParty.Channel.Is(ctx, Channel{ Counterparty: chanid, CounterpartyPort: portid, ConnectionHops: []string{obj.Connections[0].GetConnection(ctx).Counterparty}, }) { - err = errors.New("wrong counterparty connection") + err = errors.New("wrong counterParty connection") return } @@ -178,16 +171,16 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // assert(get("connections/{desiredIdentifier}") === null) and // set("connections{identifier}", connection) - obj.State.Set(ctx, OpenTry) + obj.HandshakeStage.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, height uint64, portid, chanid string, -) (obj HandshakeObject, err error) { +) (obj HandshakeState, err error) { obj, err = man.query(ctx, portid, chanid) if err != nil { return @@ -198,22 +191,22 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.State.Transit(ctx, Init, Open) { + if !obj.HandshakeStage.Transit(ctx, Init, Open) { err = errors.New("ack on non-init connection") return } - if !obj.counterparty.Channel.Is(ctx, Channel{ + if !obj.counterParty.Channel.Is(ctx, Channel{ Counterparty: chanid, 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") + if !obj.counterParty.Stage.Is(ctx, OpenTry) { + err = errors.New("counterParty state not opentry") return } @@ -221,8 +214,8 @@ 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") } */ @@ -231,10 +224,10 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } -// Using proofs: counterparty.{connection,state, nextTimeout} +// Using proofs: counterParty.{connection,state, nextTimeout} func (man Handshaker) OpenConfirm(ctx sdk.Context, proofs []commitment.Proof, height uint64, - portid, chanid string) (obj HandshakeObject, err error) { + portid, chanid string) (obj HandshakeState, err error) { obj, err = man.query(ctx, portid, chanid) if err != nil { return @@ -250,8 +243,8 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, return } - if !obj.counterparty.State.Is(ctx, Open) { - err = errors.New("counterparty state not open") + if !obj.counterParty.Stage.Is(ctx, Open) { + err = errors.New("counterParty state not open") return } @@ -262,36 +255,8 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, // 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.HandshakeStage.Transit(ctx, Open, CloseTry) { return errors.New("closeinit on non-open connection") } @@ -299,74 +264,4 @@ func (obj HandshakeObject) CloseInit(ctx sdk.Context, nextTimeout uint64) error return nil } - -func (obj HandshakeObject) CloseTry(ctx sdk.Context, 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 0920e9119e65..88baa957777f 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -18,7 +18,7 @@ type Manager struct { connection connection.Manager - counterparty CounterpartyManager + counterParty CounterpartyManager ports map[string]struct{} } @@ -33,8 +33,7 @@ func NewManager(protocol state.Mapping, connection connection.Manager) Manager { return Manager{ protocol: protocol.Prefix(LocalRoot()), connection: connection, - counterparty: NewCounterpartyManager(protocol.Cdc()), - + counterParty: NewCounterpartyManager(protocol.Cdc()), ports: make(map[string]struct{}), } } @@ -48,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) @@ -97,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") @@ -113,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 { @@ -123,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 @@ -199,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 @@ -216,54 +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, height uint64) (sdk.Context, error) { +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") - } - */ - if portid != packet.SenderPort() { - return errors.New("Invalid portid") - } - - 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 } @@ -279,7 +218,7 @@ func (man Manager) Send(ctx sdk.Context, portid, chanid string, packet Packet) e EventTypeSendPacket, sdk.NewAttribute(AttributeKeySenderPort, packet.SenderPort()), sdk.NewAttribute(AttributeKeyReceiverPort, packet.ReceiverPort()), - sdk.NewAttribute(AttributeKeyChannelID, chanid), + sdk.NewAttribute(AttributeKeyChannelID, chanId), sdk.NewAttribute(AttributeKeySequence, strconv.FormatUint(obj.SeqSend.Get(ctx), 10)), ), }) @@ -308,10 +247,8 @@ func (man Manager) Receive(ctx sdk.Context, proofs []commitment.Proof, height ui if err != nil { 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)).Is(ctx, packet) { return errors.New("verification failed") } diff --git a/x/ibc/04-channel/port.go b/x/ibc/04-channel/port.go index 8c06a1e6f12f..8547d2819163 100644 --- a/x/ibc/04-channel/port.go +++ b/x/ibc/04-channel/port.go @@ -8,7 +8,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,17 +17,24 @@ 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 { + 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") } diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index 9d159960653b..5ed8456bcdd4 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -28,15 +28,13 @@ 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 - + Node: connection.NewNode(self, counter, cdc), Cdc: cdc, } res.Counterparty = &Node{ Node: res.Node.Counterparty, Counterparty: res, - Cdc: cdc, } @@ -64,7 +62,7 @@ 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) CLIObject() channel.HandshakeState { man := node.Manager() return channel.NewHandshaker(man).CLIObject(PortName, node.Name, []string{node.Name}) } diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index 7ca7579d9eb8..681c8bd56985 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -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 2894561d316b..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 @@ -60,7 +59,6 @@ func NewStore(root Root, path Path, proofs []Proof) (res *store, err error) { err = errors.New("proof type not matching with root's") return } - fmt.Println("set", string(proof.GetKey())) res.proofs[string(proof.GetKey())] = proof } @@ -81,12 +79,10 @@ 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) if err != nil { - fmt.Println(222, string(key), err) return false } store.verified[string(key)] = 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/keeper.go b/x/ibc/keeper.go index 859d909ad82a..dbf8a4b4766f 100644 --- a/x/ibc/keeper.go +++ b/x/ibc/keeper.go @@ -18,11 +18,11 @@ type Keeper struct { func NewKeeper(cdc *codec.Codec, key sdk.StoreKey) Keeper { base := state.NewMapping(key, cdc, version.DefaultPrefix()) - climan := client.NewManager(base) - connman := connection.NewManager(base, climan) + client := client.NewManager(base) + connman := connection.NewManager(base, client) chanman := channel.NewManager(base, connman) return Keeper{ - client: climan, + client: client, connection: connection.NewHandshaker(connman), channel: channel.NewHandshaker(chanman), } diff --git a/x/ibc/mock/types/msgs.go b/x/ibc/mock/types/msgs.go index 1cd26b66a984..09a226b41e63 100644 --- a/x/ibc/mock/types/msgs.go +++ b/x/ibc/mock/types/msgs.go @@ -34,7 +34,7 @@ func (msg MsgSequence) ValidateBasic() sdk.Error { } func (msg MsgSequence) GetSignBytes() []byte { - return cdc.MustMarshalJSON(msg) // TODO + return sdk.MustSortJSON(cdc.MustMarshalJSON(msg)) } func (msg MsgSequence) GetSigners() []sdk.AccAddress { From 025caf1fbb328a66373ac9c98601494512292fa5 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 25 Sep 2019 10:08:35 -0700 Subject: [PATCH 232/378] fix mock cli in progress --- x/ibc/04-channel/client/cli/tx.go | 120 ++++++++++++++++++++++++++++++ x/ibc/04-channel/manager.go | 2 +- x/ibc/mock/client/cli/tx.go | 10 +-- x/ibc/mock/handler.go | 9 +++ x/ibc/mock/types/packets.go | 4 +- 5 files changed, 137 insertions(+), 8 deletions(-) diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index 476ed72f9313..9003300df07d 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -1,6 +1,7 @@ package cli import ( + "errors" "fmt" "time" @@ -41,6 +42,14 @@ func handshake(cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid, return man.CLIObject(portid, chanid, []string{connid}) } +func flush(q state.ABCIQuerier, cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid string) (channel.HandshakeObject, 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(q, portid, chanid) +} + func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "channel", @@ -297,3 +306,114 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return cmd } + +func GetCmdFlushPackets(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "flush", + Short: "flush packets on queue", + Args: cobra.ExactArgs(2), + // Args: []string{portid, chanid} + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + ctx1 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). + WithCodec(cdc). + WithNodeURI(viper.GetString(FlagNode1)). + WithBroadcastMode(flags.BroadcastBlock) + q1 := state.NewCLIQuerier(ctx1) + + ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). + WithCodec(cdc). + WithNodeURI(viper.GetString(FlagNode2)). + WithBroadcastMode(flags.BroadcastBlock) + q2 := state.NewCLIQuerier(ctx2) + + portid1, chanid1 := args[0], args[1] + + obj1, err := flush(q1, cdc, storeKey, version.DefaultPrefix(), portid1, chanid1) + if err != nil { + return err + } + + chan1, _, err := obj1.ChannelCLI(q1) + if err != nil { + return err + } + + portid2, chanid2 := chan1.CounterpartyPort, chan1.Counterparty + + obj2, err := flush(q2, cdc, storeKey, version.DefaultPrefix(), portid2, chanid2) + if err != nil { + return err + } + + chan2, _, err := obj2.ChannelCLI(q2) + if err != nil { + return err + } + + conn2, _, err := chan2.ConnectionCLI(q2) + if err != nil { + return err + } + + client2 := conn2.Client + + portid2, chanid2 := chan1.CounterpartyPort, chan1.Counterparty + + obj2, err := flush(q2, cdc, storeKey, version.DefaultPrefix(), portid2, chanid2) + 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 + } + + 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() + } + }, + } + + 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/manager.go b/x/ibc/04-channel/manager.go index 0920e9119e65..ca8596a6a6a4 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -272,7 +272,7 @@ 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.Commitment()) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( diff --git a/x/ibc/mock/client/cli/tx.go b/x/ibc/mock/client/cli/tx.go index 996baa46dc37..4db71904ba3d 100644 --- a/x/ibc/mock/client/cli/tx.go +++ b/x/ibc/mock/client/cli/tx.go @@ -29,15 +29,15 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command { func SequenceTxCmd(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "sequence [from-key-or-address] [channel-id] [sequence]", + Use: "sequence [channel-id] [sequence]", Short: "Send SequencePacket", - Args: cobra.ExactArgs(3), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - ctx := context.NewCLIContextWithFrom(args[0]).WithCodec(cdc) + ctx := context.NewCLIContext().WithCodec(cdc) - chanid := args[1] - seq, err := strconv.ParseUint(args[2], 10, 64) + chanid := args[0] + seq, err := strconv.ParseUint(args[1], 10, 64) if err != nil { return err } diff --git a/x/ibc/mock/handler.go b/x/ibc/mock/handler.go index 4706c58a4ec7..90a459fd3c59 100644 --- a/x/ibc/mock/handler.go +++ b/x/ibc/mock/handler.go @@ -10,6 +10,8 @@ import ( func NewHandler(k Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { + case MsgSequence: + return handleMsgSequence(ctx, k, msg) case ibc.MsgPacket: switch packet := msg.Packet.(type) { case types.PacketSequence: @@ -23,6 +25,13 @@ func NewHandler(k Keeper) sdk.Handler { } } +func handleMsgSequence(ctx sdk.Context, k Keeper, msg MsgSequence) (res sdk.Result) { + err := k.ibcPort.SendPacket(ctx, msg.ChannelID, types.PacketSequence{msg.Sequence}) + if err != nil { + + } +} + func handleMyPacket(ctx sdk.Context, k Keeper, packet types.PacketSequence, chanid string) (res sdk.Result) { err := k.CheckAndSetSequence(ctx, chanid, packet.Sequence) if err != nil { diff --git a/x/ibc/mock/types/packets.go b/x/ibc/mock/types/packets.go index 5daf0147756b..914454e9e5e9 100644 --- a/x/ibc/mock/types/packets.go +++ b/x/ibc/mock/types/packets.go @@ -43,11 +43,11 @@ func (packet *PacketSequence) UnmarshalJSON(bz []byte) (err error) { } func (PacketSequence) SenderPort() string { - return "ibc-mock" + return "ibcmock" } func (PacketSequence) ReceiverPort() string { - return "ibc-mock" + return "ibcmock" } func (PacketSequence) String() string { From 1cea7e387b6e021636e4fd62508deed2428698dc Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 27 Sep 2019 18:59:16 -0700 Subject: [PATCH 233/378] finalize cleanup, mock cli wip --- x/ibc/02-client/cli.go | 8 +- x/ibc/02-client/client/cli/query.go | 4 +- x/ibc/02-client/manager.go | 44 ++++---- x/ibc/03-connection/cli.go | 32 +++--- x/ibc/03-connection/client/cli/query.go | 8 +- x/ibc/03-connection/client/cli/tx.go | 6 +- x/ibc/03-connection/client/utils/types.go | 14 +-- x/ibc/03-connection/manager.go | 12 +-- x/ibc/03-connection/tests/types.go | 24 ++--- x/ibc/04-channel/cli.go | 16 +-- x/ibc/04-channel/client/cli/query.go | 8 +- x/ibc/04-channel/client/cli/tx.go | 116 +++++++++++++--------- x/ibc/04-channel/client/utils/types.go | 24 ++--- x/ibc/04-channel/handshake.go | 24 ++--- x/ibc/04-channel/manager.go | 8 +- x/ibc/04-channel/port.go | 5 +- x/ibc/04-channel/tests/channel_test.go | 27 +---- x/ibc/04-channel/tests/types.go | 30 +++--- x/ibc/04-channel/types.go | 3 +- x/ibc/mock/client/cli/tx.go | 53 ---------- x/ibc/mock/codec.go | 10 -- x/ibc/mock/{ => recv}/client/cli/query.go | 6 +- x/ibc/mock/{ => recv}/handler.go | 11 +- x/ibc/mock/{ => recv}/keeper.go | 13 ++- x/ibc/mock/recv/module.go | 103 +++++++++++++++++++ x/ibc/mock/send/handler.go | 26 +++++ x/ibc/mock/send/keeper.go | 49 +++++++++ x/ibc/mock/{ => send}/module.go | 7 +- x/ibc/mock/types/codec.go | 9 ++ x/ibc/mock/types/keys.go | 4 +- x/ibc/mock/types/packets.go | 7 ++ 31 files changed, 423 insertions(+), 288 deletions(-) delete mode 100644 x/ibc/mock/client/cli/tx.go delete mode 100644 x/ibc/mock/codec.go rename x/ibc/mock/{ => recv}/client/cli/query.go (86%) rename x/ibc/mock/{ => recv}/handler.go (71%) rename x/ibc/mock/{ => recv}/keeper.go (67%) create mode 100644 x/ibc/mock/recv/module.go create mode 100644 x/ibc/mock/send/handler.go create mode 100644 x/ibc/mock/send/keeper.go rename x/ibc/mock/{ => send}/module.go (92%) create mode 100644 x/ibc/mock/types/codec.go diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go index 29533883c76a..0895bbcc2c38 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -9,24 +9,24 @@ import ( "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) RootCLI(q state.ABCIQuerier, height uint64) (res commitment.Root, proof merkle.Proof, err error) { +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 Object) ConsensusStateCLI(q state.ABCIQuerier) (res ConsensusState, proof merkle.Proof, err error) { +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(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { +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 49a5ac8b65dc..ff0010c82ded 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -55,7 +55,7 @@ func GetCmdQueryClient(storeKey string, cdc *codec.Codec) *cobra.Command { man := client.NewManager(mapp) id := args[0] - state, _, err := man.Object(id).ConsensusStateCLI(q) + state, _, err := man.State(id).ConsensusStateCLI(q) if err != nil { return err } @@ -83,7 +83,7 @@ func GetCmdQueryRoot(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - root, _, err := man.Object(id).RootCLI(q, height) + root, _, err := man.State(id).RootCLI(q, height) if err != nil { return err } diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index 06927c33d1eb..b5efd7bd94c1 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -40,8 +40,8 @@ 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)), @@ -49,71 +49,71 @@ func (man Manager) Object(id string) Object { } } -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 Stage can access on and modify that client information -type Object struct { +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 Object) GetRoot(ctx sdk.Context, height uint64) (res commitment.Root, err error) { +func (obj State) GetRoot(ctx sdk.Context, height uint64) (res commitment.Root, err error) { err = obj.Roots.GetSafe(ctx, height, &res) return } -func (obj CounterObject) Is(ctx sdk.Context, client ConsensusState) bool { +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") } @@ -134,7 +134,7 @@ func (obj Object) Update(ctx sdk.Context, header Header) error { 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") } @@ -148,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/03-connection/cli.go b/x/ibc/03-connection/cli.go index ca114e8e2e8c..f4222722332f 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -7,12 +7,22 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func (man Manager) CLIObject(connid, clientid string) State { - 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 (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] } @@ -35,23 +45,21 @@ func (obj State) KindCLI(q state.ABCIQuerier) (res string, proof merkle.Proof, e return } -func (man Handshaker) CLIObject(connid, clientid string) HandshakeState { - return man.CreateState(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(q state.ABCIQuerier, connid string) (HandshakeState, error) { - obj := man.man.Object(connid) - conn, _, err := obj.ConnectionCLI(q) + state, err := man.man.CLIQuery(q, connid) if err != nil { return HandshakeState{}, err } - obj.Client = man.man.client.Object(conn.Client) - return man.CreateState(obj), nil + return man.CreateState(state), nil } -func (obj HandshakeState) StateCLI(q state.ABCIQuerier) (res byte, proof merkle.Proof, err error) { - res, tmproof, err := obj.State.Query(q) - 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 } diff --git a/x/ibc/03-connection/client/cli/query.go b/x/ibc/03-connection/client/cli/query.go index 63b563c5d44b..74c982e9cb52 100644 --- a/x/ibc/03-connection/client/cli/query.go +++ b/x/ibc/03-connection/client/cli/query.go @@ -26,7 +26,7 @@ func object(cdc *codec.Codec, storeKey string, prefix []byte, connid, clientid s 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 { @@ -43,7 +43,7 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { return ibcQueryCmd } -func QueryConnection(ctx context.CLIContext, obj connection.State, prove bool) (res utils.JSONObject, err error) { +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) @@ -60,14 +60,14 @@ func QueryConnection(ctx context.CLIContext, obj connection.State, prove bool) ( } 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, diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index 50e1f0ddf661..43ce9ae810e1 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -210,7 +210,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { if err != nil { return err } - _, pstate, err := obj1.StateCLI(q1) + _, pstate, err := obj1.StageCLI(q1) if err != nil { return err } @@ -261,7 +261,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { if err != nil { return err } - _, pstate, err = obj2.StateCLI(q2) + _, pstate, err = obj2.StageCLI(q2) if err != nil { return err } @@ -306,7 +306,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { q1 = state.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) - _, pstate, err = obj1.StateCLI(q1) + _, pstate, err = obj1.StageCLI(q1) if err != nil { return err } diff --git a/x/ibc/03-connection/client/utils/types.go b/x/ibc/03-connection/client/utils/types.go index 9ef404879a4b..9e7e2c807b20 100644 --- a/x/ibc/03-connection/client/utils/types.go +++ b/x/ibc/03-connection/client/utils/types.go @@ -5,7 +5,7 @@ import ( 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"` @@ -19,12 +19,12 @@ type JSONObject struct { 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, @@ -34,14 +34,14 @@ func NewJSONObject( } } -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, -) JSONObject { - return JSONObject{ +) JSONState { + return JSONState{ Connection: conn, ConnectionProof: connp, Available: avail, diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index a1c500af415a..ffeaaeef6d5f 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -56,12 +56,12 @@ type State struct { Kind state.String - Client client.Object + Client client.State path merkle.Path } -func (man Manager) Object(id string) State { +func (man Manager) State(id string) State { return State{ id: id, @@ -86,7 +86,7 @@ type CounterState struct { Kind commitment.String - Client client.CounterObject // nolint: unused + Client client.CounterState // nolint: unused } func (man CounterpartyManager) CreateState(id string) CounterState { @@ -152,7 +152,7 @@ func (man Manager) Cdc() *codec.Codec { } func (man Manager) create(ctx sdk.Context, id string, connection Connection, kind string) (obj State, err error) { - obj = man.Object(id) + obj = man.State(id) if obj.exists(ctx) { err = errors.New("Stage already exists") return @@ -170,7 +170,7 @@ 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 State, err error) { - obj = man.Object(id) + obj = man.State(id) if !obj.exists(ctx) { err = errors.New("Stage not exists") return @@ -187,7 +187,7 @@ func (man Manager) query(ctx sdk.Context, id string, kind string) (obj State, er } func (man Manager) Query(ctx sdk.Context, id string) (obj State, err error) { - obj = man.Object(id) + obj = man.State(id) if !obj.exists(ctx) { err = errors.New("Stage not exists") return diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index 83ee9543ea56..df188acdabf9 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -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.HandshakeState { +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 { @@ -112,7 +112,7 @@ 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) 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)) @@ -123,7 +123,7 @@ func (node *Node) OpenTry(t *testing.T, height uint64, proofs ...commitment.Proo ctx, man := node.Handshaker(t, proofs) 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)) @@ -134,7 +134,7 @@ func (node *Node) OpenAck(t *testing.T, height uint64, proofs ...commitment.Proo ctx, man := node.Handshaker(t, proofs) 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) @@ -144,7 +144,7 @@ func (node *Node) OpenConfirm(t *testing.T, height uint64, proofs ...commitment. ctx, man := node.Handshaker(t, proofs) 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,9 +163,9 @@ 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) + _, pstate := node.QueryValue(t, cliobj.Stage) _, pcounterclient := node.QueryValue(t, cliobj.CounterpartyClient) // TODO: implement consensus state checking // _, pclient := node.Query(t, cliobj.Client.ConsensusStateKey) @@ -174,16 +174,16 @@ func (node *Node) Handshake(t *testing.T) { // 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) + _, pstate = node.Counterparty.QueryValue(t, cliobj.Stage) _, pcounterclient = node.Counterparty.QueryValue(t, cliobj.CounterpartyClient) 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) + cliobj = node.CLIState() + _, pstate = node.QueryValue(t, cliobj.Stage) node.Counterparty.OpenConfirm(t, uint64(header.Height), pstate) } diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index 9dae276d567f..9e5d803d2fea 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -7,10 +7,10 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -func (man Manager) CLIObject(portid, chanid string, connids []string) State { +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 } @@ -22,7 +22,7 @@ func (man Manager) CLIQuery(q state.ABCIQuerier, portid, chanid string) (obj Sta 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 } @@ -70,12 +70,12 @@ func (man Handshaker) CLIQuery(q state.ABCIQuerier, portid, chanid string) (Hand return man.createState(obj), nil } -func (man Handshaker) CLIObject(portid, chanid string, connids []string) HandshakeState { - return man.createState(man.Manager.CLIObject(portid, chanid, connids)) +func (man Handshaker) CLIState(portid, chanid string, connids []string) HandshakeState { + return man.createState(man.Manager.CLIState(portid, chanid, connids)) } -func (obj HandshakeState) StateCLI(q state.ABCIQuerier) (res HandshakeStage, proof merkle.Proof, err error) { - res, tmproof, err := obj.State.Query(q) - proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.State) +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 04e3ca0b19be..aad646c24047 100644 --- a/x/ibc/04-channel/client/cli/query.go +++ b/x/ibc/04-channel/client/cli/query.go @@ -45,7 +45,7 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { return ibcQueryCmd } -func QueryChannel(ctx context.CLIContext, obj channel.State, prove bool) (res utils.JSONObject, err error) { +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) @@ -68,7 +68,7 @@ func QueryChannel(ctx context.CLIContext, obj channel.State, prove bool) (res ut } if prove { - return utils.NewJSONObject( + return utils.NewJSONState( conn, connp, avail, availp, // kind, kindp, @@ -77,7 +77,7 @@ func QueryChannel(ctx context.CLIContext, obj channel.State, prove bool) (res ut ), nil } - return utils.NewJSONObject( + return utils.NewJSONState( conn, nil, avail, nil, seqsend, nil, @@ -118,7 +118,7 @@ func object(cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid str climan := client.NewManager(base) connman := connection.NewManager(base, climan) man := channel.NewManager(base, connman) - return man.CLIObject(portid, chanid, connids) + return man.CLIState(portid, chanid, connids) } */ /* diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index f85851c11579..7a8dfc792d57 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -34,15 +34,15 @@ const ( FlagFrom2 = "from2" ) -func handshake(cdc *codec.Codec, storeKey string, prefix []byte, portId, chanId, connId string) channel.HandshakeState { +func handshake(cdc *codec.Codec, storeKey string, prefix []byte, portid, chanid, connid string) channel.HandshakeState { base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) - clientManager := client.NewManager(base) - connectionManager := connection.NewManager(base, clientManager) - man := channel.NewHandshaker(channel.NewManager(base, connectionManager)) - return man.CLIObject(portId, chanId, []string{connId}) + 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.HandshakeObject, error) { +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) @@ -50,6 +50,14 @@ func flush(q state.ABCIQuerier, cdc *codec.Codec, storeKey string, prefix []byte return man.CLIQuery(q, portid, chanid) } +// 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", @@ -58,6 +66,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { cmd.AddCommand( GetCmdHandshake(storeKey, cdc), + GetCmdFlushPackets(storeKey, cdc), ) return cmd @@ -76,19 +85,19 @@ func getHeader(ctx context.CLIContext) (res tendermint.Header, err error) { } height := info.Response.LastBlockHeight - prevHeight := height - 1 + prevheight := height - 1 commit, err := node.Commit(&height) if err != nil { return } - validators, err := node.Validators(&prevHeight) + validators, err := node.Validators(&prevheight) if err != nil { return } - nextValidators, err := node.Validators(&height) + nextvalidators, err := node.Validators(&height) if err != nil { return } @@ -96,7 +105,7 @@ func getHeader(ctx context.CLIContext) (res tendermint.Header, err error) { res = tendermint.Header{ SignedHeader: commit.SignedHeader, ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - NextValidatorSet: tmtypes.NewValidatorSet(nextValidators.Validators), + NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), } return @@ -107,6 +116,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { Use: "handshake", 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.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). @@ -147,31 +157,29 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { if err != nil { return err } + clientid1 := conn1.Client - clientId1 := conn1.Client conn2, _, err := obj2.OriginConnection().ConnectionCLI(q2) if err != nil { return err } - clientId2 := conn2.Client + clientid2 := conn2.Client // TODO: check state and if not Idle continue existing process - msgInit := channel.MsgOpenInit{ + msginit := channel.MsgOpenInit{ PortID: portid1, ChannelID: chanid1, Channel: chan1, Signer: ctx1.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgInit}) + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msginit}) if err != nil { return err } - // Another block has to be passed after msgInit is commited + // Another block has to be passed after msginit is commited // 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) @@ -179,13 +187,13 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgUpdate := client.MsgUpdateClient{ - ClientID: clientId2, + msgupdate := client.MsgUpdateClient{ + ClientID: clientid2, Header: header, Signer: ctx2.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgupdate}) fmt.Printf("updated apphash to %X\n", header.AppHash) @@ -196,12 +204,12 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { if err != nil { return err } - _, pstate, err := obj1.StateCLI(q1) + _, pstate, err := obj1.StageCLI(q1) if err != nil { return err } - msgTry := channel.MsgOpenTry{ + msgtry := channel.MsgOpenTry{ PortID: portid2, ChannelID: chanid2, Channel: chan2, @@ -210,15 +218,13 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { Signer: ctx2.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgTry}) + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgtry}) if err != nil { return err } - // Another block has to be passed after msgInit is commited + // Another block has to be passed after msginit is commited // 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) @@ -226,13 +232,13 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgUpdate = client.MsgUpdateClient{ - ClientID: clientId1, + msgupdate = client.MsgUpdateClient{ + ClientID: clientid1, Header: header, Signer: ctx1.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgUpdate}) + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgupdate}) q2 = state.NewCLIQuerier(ctx2.WithHeight(header.Height - 1)) @@ -240,12 +246,12 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { if err != nil { return err } - _, pstate, err = obj2.StateCLI(q2) + _, pstate, err = obj2.StageCLI(q2) if err != nil { return err } - msgAck := channel.MsgOpenAck{ + msgack := channel.MsgOpenAck{ PortID: portid1, ChannelID: chanid1, Proofs: []commitment.Proof{pchan, pstate}, @@ -253,15 +259,13 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { 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 commited + // Another block has to be passed after msginit is commited // 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) @@ -269,22 +273,22 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msgUpdate = client.MsgUpdateClient{ - ClientID: clientId2, + msgupdate = client.MsgUpdateClient{ + ClientID: clientid2, Header: header, Signer: ctx2.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgupdate}) q1 = state.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) - _, pstate, err = obj1.StateCLI(q1) + _, pstate, err = obj1.StageCLI(q1) if err != nil { return err } - msgConfirm := channel.MsgOpenConfirm{ + msgconfirm := channel.MsgOpenConfirm{ PortID: portid2, ChannelID: chanid2, Proofs: []commitment.Proof{pstate}, @@ -292,7 +296,7 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { Signer: ctx2.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgConfirm}) + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgconfirm}) if err != nil { return err } @@ -301,7 +305,6 @@ func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { }, } - // TODO: Create flag description cmd.Flags().String(FlagNode1, "tcp://localhost:26657", "") cmd.Flags().String(FlagNode2, "tcp://localhost:26657", "") cmd.Flags().String(FlagFrom1, "", "") @@ -357,20 +360,18 @@ func GetCmdFlushPackets(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - conn2, _, err := chan2.ConnectionCLI(q2) + connobj2, err := conn(q2, cdc, storeKey, version.DefaultPrefix(), chan2.ConnectionHops[0]) if err != nil { return err } - client2 := conn2.Client - - portid2, chanid2 := chan1.CounterpartyPort, chan1.Counterparty - - obj2, err := flush(q2, cdc, storeKey, version.DefaultPrefix(), portid2, chanid2) + conn2, _, err := connobj2.ConnectionCLI(q2) if err != nil { return err } + client2 := conn2.Client + seqrecv, _, err := obj2.SeqRecvCLI(q2) if err != nil { return err @@ -393,6 +394,8 @@ func GetCmdFlushPackets(storeKey string, cdc *codec.Codec) *cobra.Command { return err } + q1 = state.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) + msgupdate := client.MsgUpdateClient{ ClientID: client2, Header: header, @@ -407,8 +410,23 @@ func GetCmdFlushPackets(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msg := channel.MsgPacket() + 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 }, } 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/handshake.go b/x/ibc/04-channel/handshake.go index 850d97546e9e..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 HandshakeStage = byte +type Stage = byte const ( - Idle HandshakeStage = iota + Idle Stage = iota Init OpenTry Open @@ -44,7 +44,7 @@ type CounterpartyHandshaker struct { type HandshakeState struct { State - HandshakeStage state.Enum + Stage state.Enum counterParty CounterHandshakeState } @@ -60,9 +60,9 @@ func (man Handshaker) createState(parent State) HandshakeState { prefix := parent.portId + "/channels/" + parent.chanId return HandshakeState{ - State: parent, - HandshakeStage: man.protocol.Value([]byte(prefix + "/state")).Enum(), - counterParty: man.counterParty.createState(parent.counterParty), + State: parent, + Stage: man.protocol.Value([]byte(prefix + "/state")).Enum(), + counterParty: man.counterParty.createState(parent.counterParty), } } @@ -98,7 +98,7 @@ func (man Handshaker) query(ctx sdk.Context, portid, chanid string) (obj Handsha /* func (obj HandshakeState) remove(ctx sdk.Context) { obj.Stage.remove(ctx) - obj.HandshakeStage.Delete(ctx) + obj.Stage.Delete(ctx) obj.counterpartyClient.Delete(ctx) obj.NextTimeout.Delete(ctx) } @@ -129,7 +129,7 @@ func (man Handshaker) OpenInit(ctx sdk.Context, return HandshakeState{}, err } - obj.HandshakeStage.Set(ctx, Init) + obj.Stage.Set(ctx, Init) return obj, nil } @@ -171,7 +171,7 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // assert(get("connections/{desiredIdentifier}") === null) and // set("connections{identifier}", connection) - obj.HandshakeStage.Set(ctx, OpenTry) + obj.Stage.Set(ctx, OpenTry) return } @@ -191,7 +191,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.HandshakeStage.Transit(ctx, Init, Open) { + if !obj.Stage.Transit(ctx, Init, Open) { err = errors.New("ack on non-init connection") return } @@ -238,7 +238,7 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, return } - if !obj.State.Transit(ctx, OpenTry, Open) { + if !obj.Stage.Transit(ctx, OpenTry, Open) { err = errors.New("confirm on non-try connection") return } @@ -256,7 +256,7 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, // TODO /* func (obj HandshakeState) CloseInit(ctx sdk.Context, nextTimeout uint64) error { - if !obj.HandshakeStage.Transit(ctx, Open, CloseTry) { + if !obj.Stage.Transit(ctx, Open, CloseTry) { return errors.New("closeinit on non-open connection") } diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go index dd0e077c8501..7bd358152303 100644 --- a/x/ibc/04-channel/manager.go +++ b/x/ibc/04-channel/manager.go @@ -34,7 +34,7 @@ func NewManager(protocol state.Mapping, connection connection.Manager) Manager { protocol: protocol.Prefix(LocalRoot()), connection: connection, counterParty: NewCounterpartyManager(protocol.Cdc()), - ports: make(map[string]struct{}), + ports: make(map[string]struct{}), } } @@ -211,7 +211,7 @@ func (man Manager) Send(ctx sdk.Context, chanId string, packet Packet) error { return errors.New("timeout height higher than the latest known") } - obj.Packets.SetRaw(ctx, obj.SeqSend.Increment(ctx), packet.Commitment()) + obj.Packets.SetRaw(ctx, obj.SeqSend.Increment(ctx), packet.Marshal()) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( @@ -247,8 +247,8 @@ func (man Manager) Receive(ctx sdk.Context, proofs []commitment.Proof, height ui if err != nil { return err } - - 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/port.go b/x/ibc/04-channel/port.go index 8547d2819163..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" ) @@ -38,7 +40,8 @@ func (port Port) Send(ctx sdk.Context, chanid string, packet Packet) error { if packet.SenderPort() != port.id { panic("Packet sent on wrong port") } - return port.channel.Send(ctx, port.id, chanid, packet) + + return port.channel.Send(ctx, chanid, packet) } func (port Port) Receive(ctx sdk.Context, proof []commitment.Proof, height uint64, chanid string, packet Packet) error { diff --git a/x/ibc/04-channel/tests/channel_test.go b/x/ibc/04-channel/tests/channel_test.go index 432709585414..1bd8edb8d443 100644 --- a/x/ibc/04-channel/tests/channel_test.go +++ b/x/ibc/04-channel/tests/channel_test.go @@ -1,7 +1,6 @@ package channel import ( - "errors" "testing" "github.com/cosmos/cosmos-sdk/codec" @@ -62,26 +61,10 @@ func (MyPacket) ValidateBasic() sdk.Error { return nil } -func (packet MyPacket) MarshalAmino() (string, error) { - return "mp-" + packet.Message, nil -} - -func (packet *MyPacket) UnmarshalAmino(text string) error { - if text[:3] != "mp-" { - return errors.New("Invalid text for MyPacket") - } - packet.Message = text[3:] - return nil -} - -func (packet MyPacket) MarshalJSON() ([]byte, error) { - res, _ := packet.MarshalAmino() - return []byte("\"" + res + "\""), nil -} - -func (packet *MyPacket) UnmarshalJSON(bz []byte) error { - bz = bz[1 : len(bz)-1] - return packet.UnmarshalAmino(string(bz)) +func (packet MyPacket) Marshal() []byte { + cdc := codec.New() + registerCodec(cdc) + return cdc.MustMarshalBinaryBare(packet) } func TestPacket(t *testing.T) { @@ -96,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"}, uint64(header.Height), ppacket) } diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index 5ed8456bcdd4..32221079fb3d 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -29,13 +29,13 @@ type Node struct { func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { res := &Node{ Node: connection.NewNode(self, counter, cdc), - Cdc: cdc, + Cdc: cdc, } res.Counterparty = &Node{ Node: res.Node.Counterparty, Counterparty: res, - Cdc: cdc, + Cdc: cdc, } res.Channel = channel.Channel{ @@ -62,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.HandshakeState { +func (node *Node) CLIState() channel.HandshakeState { man := node.Manager() - return channel.NewHandshaker(man).CLIObject(PortName, node.Name, []string{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,7 +83,7 @@ func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) 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)) } @@ -92,7 +92,7 @@ func (node *Node) OpenTry(t *testing.T, height uint64, proofs ...commitment.Proo ctx, man := node.Handshaker(t, proofs) 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) @@ -102,7 +102,7 @@ func (node *Node) OpenAck(t *testing.T, height uint64, proofs ...commitment.Proo ctx, man := node.Handshaker(t, proofs) 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) @@ -112,7 +112,7 @@ func (node *Node) OpenConfirm(t *testing.T, height uint64, proofs ...commitment. ctx, man := node.Handshaker(t, proofs) 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) @@ -127,24 +127,24 @@ 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) + _, 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) + _, 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) + cliobj = node.CLIState() + _, pstate = node.QueryValue(t, cliobj.Stage) node.Counterparty.OpenConfirm(t, uint64(header.Height), pstate) } @@ -153,7 +153,7 @@ func (node *Node) Send(t *testing.T, packet channel.Packet) { obj, err := man.Query(ctx, PortName, node.Name) require.NoError(t, err) seq := obj.SeqSend.Get(ctx) - err = man.Send(ctx, PortName, 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)) diff --git a/x/ibc/04-channel/types.go b/x/ibc/04-channel/types.go index 7714dfe5e24c..43688edaa92f 100644 --- a/x/ibc/04-channel/types.go +++ b/x/ibc/04-channel/types.go @@ -24,8 +24,7 @@ type Packet interface { Type() string ValidateBasic() sdk.Error Timeout() uint64 - MarshalAmino() (string, error) // Should exclude PortID/ChannelID info - MarshalJSON() ([]byte, error) // Should exclude PortID/ChannelID info + Marshal() []byte // Should exclude PortID/ChannelID info } type Channel struct { diff --git a/x/ibc/mock/client/cli/tx.go b/x/ibc/mock/client/cli/tx.go deleted file mode 100644 index 4db71904ba3d..000000000000 --- a/x/ibc/mock/client/cli/tx.go +++ /dev/null @@ -1,53 +0,0 @@ -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: "ibctypes", - Short: "IBC types 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/codec.go b/x/ibc/mock/codec.go deleted file mode 100644 index 20812bf738e8..000000000000 --- a/x/ibc/mock/codec.go +++ /dev/null @@ -1,10 +0,0 @@ -package mock - -import ( - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/ibc/mock/types" -) - -func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(types.PacketSequence{}, "ibcmock/types.PacketSequence", nil) -} diff --git a/x/ibc/mock/client/cli/query.go b/x/ibc/mock/recv/client/cli/query.go similarity index 86% rename from x/ibc/mock/client/cli/query.go rename to x/ibc/mock/recv/client/cli/query.go index a3817350902a..627027ddea54 100644 --- a/x/ibc/mock/client/cli/query.go +++ b/x/ibc/mock/recv/client/cli/query.go @@ -14,8 +14,8 @@ import ( func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { queryCmd := &cobra.Command{ - Use: "ibcmock", - Short: "Querying commands for the ibcmock module", + Use: "ibcmockrecv", + Short: "Querying commands for the ibcmockrecv module", RunE: client.ValidateCmd, } @@ -34,7 +34,7 @@ func GetCmdQuerySequence(storeName string, cdc *codec.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) - val, _, err := ctx.QueryStore(types.SequenceKey, storeName) + val, _, err := ctx.QueryStore(types.SequenceKey(args[0]), storeName) if err != nil { return err } diff --git a/x/ibc/mock/handler.go b/x/ibc/mock/recv/handler.go similarity index 71% rename from x/ibc/mock/handler.go rename to x/ibc/mock/recv/handler.go index 90a459fd3c59..e095d1ad6987 100644 --- a/x/ibc/mock/handler.go +++ b/x/ibc/mock/recv/handler.go @@ -10,8 +10,6 @@ import ( func NewHandler(k Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { - case MsgSequence: - return handleMsgSequence(ctx, k, msg) case ibc.MsgPacket: switch packet := msg.Packet.(type) { case types.PacketSequence: @@ -25,15 +23,8 @@ func NewHandler(k Keeper) sdk.Handler { } } -func handleMsgSequence(ctx sdk.Context, k Keeper, msg MsgSequence) (res sdk.Result) { - err := k.ibcPort.SendPacket(ctx, msg.ChannelID, types.PacketSequence{msg.Sequence}) - if err != nil { - - } -} - func handleMyPacket(ctx sdk.Context, k Keeper, packet types.PacketSequence, chanid string) (res sdk.Result) { - err := k.CheckAndSetSequence(ctx, chanid, packet.Sequence) + err := k.UpdateSequence(ctx, chanid, packet.Sequence) if err != nil { res.Log = "Invalid sequence" // should not return error, set only log } diff --git a/x/ibc/mock/keeper.go b/x/ibc/mock/recv/keeper.go similarity index 67% rename from x/ibc/mock/keeper.go rename to x/ibc/mock/recv/keeper.go index 953dc889cf32..7fcb5ad544da 100644 --- a/x/ibc/mock/keeper.go +++ b/x/ibc/mock/recv/keeper.go @@ -1,8 +1,6 @@ package mock import ( - "errors" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc" @@ -25,8 +23,8 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, port ibc.Port) Keeper { func (k Keeper) GetSequence(ctx sdk.Context, chanid string) (res uint64) { store := ctx.KVStore(k.key) - if store.Has(types.SequenceKey) { - k.cdc.MustUnmarshalBinaryBare(store.Get(types.SequenceKey), &res) + if store.Has(types.SequenceKey(chanid)) { + k.cdc.MustUnmarshalBinaryBare(store.Get(types.SequenceKey(chanid)), &res) } else { res = 0 } @@ -36,12 +34,13 @@ func (k Keeper) GetSequence(ctx sdk.Context, chanid string) (res uint64) { func (k Keeper) SetSequence(ctx sdk.Context, chanid string, seq uint64) { store := ctx.KVStore(k.key) - store.Set(types.SequenceKey, k.cdc.MustMarshalBinaryBare(seq)) + store.Set(types.SequenceKey(chanid), k.cdc.MustMarshalBinaryBare(seq)) } -func (k Keeper) CheckAndSetSequence(ctx sdk.Context, chanid string, seq uint64) error { +func (k Keeper) UpdateSequence(ctx sdk.Context, chanid string, seq uint64) sdk.Error { if k.GetSequence(ctx, chanid)+1 != seq { - return errors.New("fjidow;af") + // 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..9e142a855baf --- /dev/null +++ b/x/ibc/mock/recv/module.go @@ -0,0 +1,103 @@ +package mock + +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 (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/handler.go b/x/ibc/mock/send/handler.go new file mode 100644 index 000000000000..e78e97714675 --- /dev/null +++ b/x/ibc/mock/send/handler.go @@ -0,0 +1,26 @@ +package mock + +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..150e1a5f7ee5 --- /dev/null +++ b/x/ibc/mock/send/keeper.go @@ -0,0 +1,49 @@ +package mock + +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/module.go b/x/ibc/mock/send/module.go similarity index 92% rename from x/ibc/mock/module.go rename to x/ibc/mock/send/module.go index 79aab119570d..19309e13bd69 100644 --- a/x/ibc/mock/module.go +++ b/x/ibc/mock/send/module.go @@ -12,11 +12,12 @@ import ( "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/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/send/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/types" ) const ( - ModuleName = "ibcmock" + ModuleName = "ibcmocksend" ) var ( @@ -33,7 +34,7 @@ func (AppModuleBasic) Name() string { } func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { - RegisterCodec(cdc) + types.RegisterCodec(cdc) } func (AppModuleBasic) DefaultGenesis() json.RawMessage { 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 index 2e69fd34755e..3134a5ad511a 100644 --- a/x/ibc/mock/types/keys.go +++ b/x/ibc/mock/types/keys.go @@ -1,3 +1,5 @@ package types -var SequenceKey = []byte("sequence") +func SequenceKey(chanid string) []byte { + return []byte("sequence/" + chanid) +} diff --git a/x/ibc/mock/types/packets.go b/x/ibc/mock/types/packets.go index 914454e9e5e9..11fdfc88c370 100644 --- a/x/ibc/mock/types/packets.go +++ b/x/ibc/mock/types/packets.go @@ -7,6 +7,7 @@ import ( "strconv" "strings" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc" ) @@ -29,6 +30,12 @@ func (packet *PacketSequence) UnmarshalAmino(text string) (err error) { 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 } From 45dcdb324958d81dd92c5a9d17f3b16ba5859eb1 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 27 Sep 2019 19:02:25 -0700 Subject: [PATCH 234/378] add cli for mocksend --- x/ibc/mock/send/client/cli/query.go | 53 +++++++++++++++++++++++++++++ x/ibc/mock/send/client/cli/tx.go | 53 +++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 x/ibc/mock/send/client/cli/query.go create mode 100644 x/ibc/mock/send/client/cli/tx.go 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 +} From 56be11e4ed0352b1e1ab55d8aef5bb9478f1ece2 Mon Sep 17 00:00:00 2001 From: mossid Date: Sat, 28 Sep 2019 10:38:13 -0700 Subject: [PATCH 235/378] fix handler --- x/ibc/mock/send/handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ibc/mock/send/handler.go b/x/ibc/mock/send/handler.go index e78e97714675..dfc92719bc61 100644 --- a/x/ibc/mock/send/handler.go +++ b/x/ibc/mock/send/handler.go @@ -1,4 +1,4 @@ -package mock +package mocksend import ( sdk "github.com/cosmos/cosmos-sdk/types" From 9f636291508ee2eab0e04265deeca04941a026f3 Mon Sep 17 00:00:00 2001 From: mossid Date: Sat, 28 Sep 2019 10:39:16 -0700 Subject: [PATCH 236/378] rm commented lines --- x/ibc/23-commitment/merkle/utils.go | 42 ----------------------------- 1 file changed, 42 deletions(-) diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index 636fae569c28..954085e3a88d 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -43,48 +43,6 @@ func join(a, b []byte) (res []byte) { return } -/* - -// RequestQuery() constructs the abci.RequestQuery. -// -// RequestQuery.Path is a slash separated key list, ending with "/key" -// -// RequestQuery.Data is the concatanation of path.KeyPrefix and key argument -// -// RequestQuery.Prove is set to true -func (path Path) RequestQuery(key []byte) abci.RequestQuery { - req := path.RequestQueryMultiStore(key) - // BaseApp switches over the first path element, - // and performs KVStore query only if it is "/store" - req.Path = "/store" + req.Path - return req -} - - - -func (path Path) Query(ctx context.CLIContext, key []byte) (code uint32, value []byte, proof Proof, err error) { - resp, err := ctx.QueryABCI(path.RequestQuery(key)) - if err != nil { - return code, value, proof, err - } - if !resp.IsOK() { - return resp.Code, value, proof, errors.New(resp.Log) - } - return resp.Code, resp.Value, Proof{Key: key, Proof: resp.Proof}, nil -} - -func (path Path) QueryValue(ctx context.CLIContext, cdc *codec.Codec, key []byte, ptr interface{}) (Proof, error) { - _, value, proof, err := path.Query(ctx, key) - if err != nil { - return Proof{}, err - } - err = cdc.UnmarshalBinaryBare(value, ptr) // TODO - return proof, err -} - - - - func (path Path) Path() string { pathstr := "" From b4e71e1b80014fea1d099f84c9565c58909a21ac Mon Sep 17 00:00:00 2001 From: mossid Date: Sat, 28 Sep 2019 10:59:02 -0700 Subject: [PATCH 237/378] address review in progress --- x/ibc/02-client/manager.go | 31 +---------------------- x/ibc/02-client/tendermint/tests/types.go | 2 +- x/ibc/02-client/tendermint/types.go | 12 ++++----- x/ibc/02-client/types.go | 22 ++++++++-------- 4 files changed, 18 insertions(+), 49 deletions(-) diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go index eb9a83ff7d2e..5c14323cb633 100644 --- a/x/ibc/02-client/manager.go +++ b/x/ibc/02-client/manager.go @@ -115,7 +115,7 @@ func (obj Object) Update(ctx sdk.Context, header Header) error { } stored := obj.GetConsensusState(ctx) - updated, err := stored.Validate(header) + updated, err := stored.CheckValidityAndUpdateState(header) if err != nil { return err } @@ -124,32 +124,3 @@ func (obj Object) Update(ctx sdk.Context, header Header) error { return nil } - -func (obj Object) Freeze(ctx sdk.Context) error { - if !obj.exists(ctx) { - panic("should not freeze nonexisting client") - } - - if obj.Frozen.Get(ctx) { - return errors.New("client is already Frozen") - } - - obj.Frozen.Set(ctx, true) - - return nil -} - -func (obj Object) Delete(ctx sdk.Context) error { - if !obj.exists(ctx) { - panic("should not delete nonexisting client") - } - - if !obj.Frozen.Get(ctx) { - return errors.New("client is not Frozen") - } - - obj.ConsensusState.Delete(ctx) - obj.Frozen.Delete(ctx) - - return nil -} diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 26255358f483..51f56a50fbb1 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -140,7 +140,7 @@ func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root me } func (v *Verifier) Validate(header tendermint.Header, valset, nextvalset MockValidators) error { - newcs, err := v.ConsensusState.Validate(header) + newcs, err := v.ConsensusState.CheckValidityAndUpdateState(header) if err != nil { return err } diff --git a/x/ibc/02-client/tendermint/types.go b/x/ibc/02-client/tendermint/types.go index ca5da8c1cae5..8d2f23509175 100644 --- a/x/ibc/02-client/tendermint/types.go +++ b/x/ibc/02-client/tendermint/types.go @@ -7,8 +7,8 @@ import ( lerr "github.com/tendermint/tendermint/lite/errors" "github.com/tendermint/tendermint/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" ) @@ -43,7 +43,7 @@ func (cs ConsensusState) update(header Header) ConsensusState { } } -func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, error) { +func (cs ConsensusState) CheckValidityAndUpdateState(cheader client.Header) (client.ConsensusState, error) { header, ok := cheader.(Header) if !ok { return nil, errors.New("invalid type") @@ -73,14 +73,14 @@ func (cs ConsensusState) Validate(cheader client.Header) (client.ConsensusState, return cs.update(header), nil } -func (cs ConsensusState) Equivocation(header1, header2 client.Header) bool { - return false // XXX +func (cs ConsensusState) CheckMisbehaviourAndUpdateState(mb client.Misbehaviour) bool { + return false // TODO: implement } var _ client.Header = Header{} type Header struct { - // XXX: don't take the entire struct + // TODO: define Tendermint header type manually, don't use tmtypes types.SignedHeader ValidatorSet *types.ValidatorSet NextValidatorSet *types.ValidatorSet diff --git a/x/ibc/02-client/types.go b/x/ibc/02-client/types.go index 134837a43aa8..fa18c5095b9b 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 @@ -17,20 +17,20 @@ type ConsensusState interface { // which is used for key-value pair verification. GetRoot() commitment.Root - // Validate() returns the updated consensus state + // CheckValidityAndUpdateState() returns the updated consensus state // only if the header is a descendent of this consensus state. - Validate(Header) (ConsensusState, error) // ValidityPredicate + CheckValidityAndUpdateState(Header) (ConsensusState, error) - // Equivocation checks two headers' confliction. - Equivocation(Header, Header) bool // EquivocationPredicate + // CheckMisbehaviourAndUpdateState() checks any misbehaviour evidence + // depending on the state type. + CheckMisbehaviourAndUpdateState(Misbehaviour) bool } -/* -func Equal(client1, client2 ConsensusState) bool { - return client1.Kind() == client2.Kind() && - client1.GetBase().Equal(client2.GetBase()) +type Misbehaviour interface { + Kind() Kind + // TODO: embed Evidence interface + // evidence.Evidence } -*/ // Header is the consensus state update information. type Header interface { @@ -40,8 +40,6 @@ type Header interface { GetHeight() uint64 } -// XXX: Kind should be enum? - type Kind byte const ( From 3f509ee73de15d51432798e49ca9d4160c07adde Mon Sep 17 00:00:00 2001 From: mossid Date: Sat, 28 Sep 2019 11:14:38 -0700 Subject: [PATCH 238/378] address review, rm cleanup/closing --- x/ibc/03-connection/cli.go | 6 - x/ibc/03-connection/client/cli/tx.go | 42 +------ x/ibc/03-connection/handler.go | 8 +- x/ibc/03-connection/handshake.go | 174 +-------------------------- x/ibc/03-connection/msgs.go | 9 +- x/ibc/03-connection/tests/types.go | 31 +++-- 6 files changed, 28 insertions(+), 242 deletions(-) diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index c9450bd150db..7fa3986465d7 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -60,9 +60,3 @@ func (obj HandshakeObject) CounterpartyClientCLI(q state.ABCIQuerier) (res strin proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.CounterpartyClient) return } - -func (obj HandshakeObject) NextTimeoutCLI(q state.ABCIQuerier) (res uint64, proof merkle.Proof, err error) { - res, tmproof, err := obj.NextTimeout.Query(q) - proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.NextTimeout) - return -} diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index afac66e2f6a0..c1910960a5f5 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -103,16 +103,10 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command } // 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, Connection: conn1, CounterpartyClient: conn2.Client, - NextTimeout: nextTimeout, Signer: ctx1.GetFromAddress(), } @@ -121,12 +115,6 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } - timeout := nextTimeout - height, err = lastheight(ctx1) - if err != nil { - return err - } - nextTimeout = height + 1000 _, pconn, err := obj1.ConnectionCLI(q1) if err != nil { return err @@ -135,10 +123,6 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command if err != nil { return err } - _, ptimeout, err := obj1.NextTimeoutCLI(q1) - if err != nil { - return err - } _, pcounter, err := obj1.CounterpartyClientCLI(q1) if err != nil { return err @@ -148,9 +132,7 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command ConnectionID: conn2id, Connection: conn2, CounterpartyClient: conn1.Client, - Timeout: timeout, - NextTimeout: nextTimeout, - Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, + Proofs: []commitment.Proof{pconn, pstate, pcounter}, Signer: ctx2.GetFromAddress(), } @@ -159,12 +141,6 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } - timeout = nextTimeout - height, err = lastheight(ctx2) - if err != nil { - return err - } - nextTimeout = height + 1000 _, pconn, err = obj2.ConnectionCLI(q2) if err != nil { return err @@ -173,10 +149,6 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command if err != nil { return err } - _, ptimeout, err = obj2.NextTimeoutCLI(q2) - if err != nil { - return err - } _, pcounter, err = obj2.CounterpartyClientCLI(q2) if err != nil { return err @@ -184,9 +156,7 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command msgack := connection.MsgOpenAck{ ConnectionID: conn1id, - Timeout: timeout, - NextTimeout: nextTimeout, - Proofs: []commitment.Proof{pconn, pstate, ptimeout, pcounter}, + Proofs: []commitment.Proof{pconn, pstate, pcounter}, Signer: ctx1.GetFromAddress(), } @@ -195,20 +165,14 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } - timeout = nextTimeout _, pstate, err = obj1.StateCLI(q1) if err != nil { return err } - _, ptimeout, err = obj1.NextTimeoutCLI(q1) - if err != nil { - return err - } msgconfirm := connection.MsgOpenConfirm{ ConnectionID: conn2id, - Timeout: timeout, - Proofs: []commitment.Proof{pstate, ptimeout}, + Proofs: []commitment.Proof{pstate}, Signer: ctx2.GetFromAddress(), } diff --git a/x/ibc/03-connection/handler.go b/x/ibc/03-connection/handler.go index 738ba38da7e0..b9f53de71602 100644 --- a/x/ibc/03-connection/handler.go +++ b/x/ibc/03-connection/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.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() } @@ -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.Connection, msg.CounterpartyClient, msg.Timeout, msg.NextTimeout) + _, err := man.OpenTry(ctx, msg.Proofs, msg.ConnectionID, msg.Connection, msg.CounterpartyClient) 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.Timeout, msg.NextTimeout) + _, err := man.OpenAck(ctx, msg.Proofs, msg.ConnectionID) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), 300, "").Result() } @@ -29,7 +29,7 @@ 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.Timeout) + _, err := man.OpenConfirm(ctx, msg.Proofs, msg.ConnectionID) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), 400, "").Result() } diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/handshake.go index c5d9debba1a3..e4d25965b3ca 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -6,7 +6,7 @@ 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 @@ -16,8 +16,6 @@ const ( Init OpenTry Open - CloseTry - Closed ) const HandshakeKind = "handshake" @@ -48,7 +46,6 @@ type HandshakeObject struct { State state.Enum CounterpartyClient state.String - NextTimeout state.Integer Counterparty CounterHandshakeObject } @@ -58,7 +55,6 @@ type CounterHandshakeObject struct { State commitment.Enum CounterpartyClient commitment.String - NextTimeout commitment.Integer } // CONTRACT: client and remote must be filled by the caller @@ -68,7 +64,6 @@ func (man Handshaker) Object(parent Object) HandshakeObject { State: 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 } @@ -80,7 +75,6 @@ func (man CounterpartyHandshaker) Object(id string) CounterHandshakeObject { State: 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), } } @@ -105,24 +99,9 @@ func (man Handshaker) query(ctx sdk.Context, id string) (obj HandshakeObject, er return } -func (obj HandshakeObject) remove(ctx sdk.Context) { - obj.Object.remove(ctx) - obj.State.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, + id string, connection Connection, counterpartyClient string, ) (HandshakeObject, error) { // man.Create() will ensure // assert(get("connections/{identifier}") === null) and @@ -132,7 +111,6 @@ func (man Handshaker) OpenInit(ctx sdk.Context, return HandshakeObject{}, err } - obj.NextTimeout.Set(ctx, nextTimeoutHeight) obj.State.Set(ctx, Init) return obj, nil @@ -141,7 +119,7 @@ func (man Handshaker) OpenInit(ctx sdk.Context, // 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, + id string, connection Connection, counterpartyClient string, ) (obj HandshakeObject, err error) { obj, err = man.create(ctx, id, connection, counterpartyClient) if err != nil { @@ -153,11 +131,6 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - err = assertTimeout(ctx, timeoutHeight) - if err != nil { - return - } - if !obj.Counterparty.State.Is(ctx, Init) { err = errors.New("counterparty state not init") return @@ -177,11 +150,6 @@ func (man Handshaker) OpenTry(ctx sdk.Context, return } - if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { - err = errors.New("unexpected counterparty timeout value") - 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 @@ -199,15 +167,14 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // set("connections{identifier}", connection) obj.State.Set(ctx, OpenTry) - obj.NextTimeout.Set(ctx, nextTimeoutHeight) return } -// Using proofs: counterparty.{connection, state, timeout, counterpartyClient, client} +// Using proofs: counterparty.{connection, state, counterpartyClient, client} func (man Handshaker) OpenAck(ctx sdk.Context, proofs []commitment.Proof, - id string /*expheight uint64, */, timeoutHeight, nextTimeoutHeight uint64, + id string, /*expheight uint64, */ ) (obj HandshakeObject, err error) { obj, err = man.query(ctx, id) if err != nil { @@ -224,11 +191,6 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - err = assertTimeout(ctx, timeoutHeight) - if err != nil { - return - } - if !obj.Counterparty.Connection.Is(ctx, Connection{ Client: obj.CounterpartyClient.Get(ctx), Counterparty: obj.ID(), @@ -248,11 +210,6 @@ func (man Handshaker) OpenAck(ctx sdk.Context, return } - if !obj.Counterparty.NextTimeout.Is(ctx, timeoutHeight) { - err = errors.New("unexpected counterparty timeout value") - return - } - // TODO: implement in v1 /* var expected client.ConsensusState @@ -262,7 +219,6 @@ func (man Handshaker) OpenAck(ctx sdk.Context, } */ obj.Available.Set(ctx, true) - obj.NextTimeout.Set(ctx, nextTimeoutHeight) return } @@ -270,7 +226,7 @@ func (man Handshaker) OpenAck(ctx sdk.Context, // Using proofs: counterparty.{connection,state, nextTimeout} func (man Handshaker) OpenConfirm(ctx sdk.Context, proofs []commitment.Proof, - id string, timeoutHeight uint64) (obj HandshakeObject, err error) { + id string) (obj HandshakeObject, err error) { obj, err = man.query(ctx, id) if err != nil { @@ -287,130 +243,12 @@ func (man Handshaker) OpenConfirm(ctx sdk.Context, 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") - 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/msgs.go b/x/ibc/03-connection/msgs.go index 3944599ff6a3..f528bd145f5d 100644 --- a/x/ibc/03-connection/msgs.go +++ b/x/ibc/03-connection/msgs.go @@ -2,8 +2,7 @@ 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" @@ -12,7 +11,6 @@ type MsgOpenInit struct { ConnectionID string Connection Connection CounterpartyClient string - NextTimeout uint64 Signer sdk.AccAddress } @@ -42,8 +40,6 @@ type MsgOpenTry struct { ConnectionID string Connection Connection CounterpartyClient string - Timeout uint64 - NextTimeout uint64 Proofs []commitment.Proof Signer sdk.AccAddress } @@ -72,8 +68,6 @@ func (msg MsgOpenTry) GetSigners() []sdk.AccAddress { type MsgOpenAck struct { ConnectionID string - Timeout uint64 - NextTimeout uint64 Proofs []commitment.Proof Signer sdk.AccAddress } @@ -102,7 +96,6 @@ func (msg MsgOpenAck) GetSigners() []sdk.AccAddress { type MsgOpenConfirm struct { ConnectionID string - Timeout uint64 Proofs []commitment.Proof Signer sdk.AccAddress } diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/tests/types.go index 9fbd375aa4b3..54321c28ac9e 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 { @@ -29,7 +29,7 @@ type Node struct { func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { res := &Node{ - Name: "self", // hard coded, doesnt matter + Name: "self", // hard coded, doesnt matter Node: tendermint.NewNode(self, "teststoreself", []byte("protocol/")), // TODO: test with key prefix State: connection.Idle, @@ -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()) } @@ -110,7 +110,7 @@ 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, node.Connection, obj.GetConnection(ctx)) @@ -121,7 +121,7 @@ func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenTry(t *testing.T, 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, node.Name, node.Connection, node.CounterpartyClient) require.NoError(t, err) require.Equal(t, connection.OpenTry, obj.State.Get(ctx)) require.Equal(t, node.Connection, obj.GetConnection(ctx)) @@ -132,7 +132,7 @@ func (node *Node) OpenTry(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenAck(t *testing.T, 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, node.Name) require.NoError(t, err) require.Equal(t, connection.Open, obj.State.Get(ctx)) require.Equal(t, node.Connection, obj.GetConnection(ctx)) @@ -142,12 +142,12 @@ func (node *Node) OpenAck(t *testing.T, proofs ...commitment.Proof) { func (node *Node) OpenConfirm(t *testing.T, 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, node.Name) require.NoError(t, err) require.Equal(t, connection.Open, obj.State.Get(ctx)) require.Equal(t, node.Connection, obj.GetConnection(ctx)) require.True(t, obj.Available.Get(ctx)) - node.SetState(connection.CloseTry) + node.SetState(connection.Open) } func (node *Node) Handshake(t *testing.T) { @@ -166,11 +166,10 @@ func (node *Node) Handshake(t *testing.T) { cliobj := node.CLIObject() _, pconn := node.QueryValue(t, cliobj.Connection) _, pstate := node.QueryValue(t, cliobj.State) - _, ptimeout := node.QueryValue(t, cliobj.NextTimeout) _, 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, pconn, pstate, pcounterclient) header = node.Counterparty.Commit() // self.OpenAck @@ -178,15 +177,13 @@ func (node *Node) Handshake(t *testing.T) { cliobj = node.Counterparty.CLIObject() _, pconn = node.Counterparty.QueryValue(t, cliobj.Connection) _, pstate = node.Counterparty.QueryValue(t, cliobj.State) - _, ptimeout = node.Counterparty.QueryValue(t, cliobj.NextTimeout) _, pcounterclient = node.Counterparty.QueryValue(t, cliobj.CounterpartyClient) - node.OpenAck(t, pconn, pstate, ptimeout, pcounterclient) + node.OpenAck(t, 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) + node.Counterparty.OpenConfirm(t, pstate) } From 10bf523fd7e0015d836a73bfe014ada9ab551201 Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 30 Sep 2019 21:28:00 -0700 Subject: [PATCH 239/378] rename mock packages --- x/ibc/mock/recv/handler.go | 2 +- x/ibc/mock/recv/keeper.go | 2 +- x/ibc/mock/recv/module.go | 2 +- x/ibc/mock/send/keeper.go | 2 +- x/ibc/mock/send/module.go | 2 +- x/ibc/mock/types/packets.go | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/x/ibc/mock/recv/handler.go b/x/ibc/mock/recv/handler.go index e095d1ad6987..d992f799fcb1 100644 --- a/x/ibc/mock/recv/handler.go +++ b/x/ibc/mock/recv/handler.go @@ -1,4 +1,4 @@ -package mock +package mockrecv import ( sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/ibc/mock/recv/keeper.go b/x/ibc/mock/recv/keeper.go index 7fcb5ad544da..99ce5d2e9746 100644 --- a/x/ibc/mock/recv/keeper.go +++ b/x/ibc/mock/recv/keeper.go @@ -1,4 +1,4 @@ -package mock +package mockrecv import ( "github.com/cosmos/cosmos-sdk/codec" diff --git a/x/ibc/mock/recv/module.go b/x/ibc/mock/recv/module.go index 9e142a855baf..e4dcb5f7d2d6 100644 --- a/x/ibc/mock/recv/module.go +++ b/x/ibc/mock/recv/module.go @@ -1,4 +1,4 @@ -package mock +package mockrecv import ( "encoding/json" diff --git a/x/ibc/mock/send/keeper.go b/x/ibc/mock/send/keeper.go index 150e1a5f7ee5..ce88988093e3 100644 --- a/x/ibc/mock/send/keeper.go +++ b/x/ibc/mock/send/keeper.go @@ -1,4 +1,4 @@ -package mock +package mocksend import ( "github.com/cosmos/cosmos-sdk/codec" diff --git a/x/ibc/mock/send/module.go b/x/ibc/mock/send/module.go index 19309e13bd69..1749d57ed1d9 100644 --- a/x/ibc/mock/send/module.go +++ b/x/ibc/mock/send/module.go @@ -1,4 +1,4 @@ -package mock +package mocksend import ( "encoding/json" diff --git a/x/ibc/mock/types/packets.go b/x/ibc/mock/types/packets.go index 11fdfc88c370..745adef2188c 100644 --- a/x/ibc/mock/types/packets.go +++ b/x/ibc/mock/types/packets.go @@ -50,11 +50,11 @@ func (packet *PacketSequence) UnmarshalJSON(bz []byte) (err error) { } func (PacketSequence) SenderPort() string { - return "ibcmock" + return "ibcmocksend" } func (PacketSequence) ReceiverPort() string { - return "ibcmock" + return "ibcmockrecv" } func (PacketSequence) String() string { From fea2ba628ccd4a374cf7a33b0a10a5099f19bfc6 Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 30 Sep 2019 22:47:05 -0700 Subject: [PATCH 240/378] fix interface for gaia --- x/ibc/keeper.go | 4 ++++ x/ibc/mock/recv/module.go | 8 ++++++++ x/ibc/mock/send/module.go | 8 ++++++++ 3 files changed, 20 insertions(+) diff --git a/x/ibc/keeper.go b/x/ibc/keeper.go index dbf8a4b4766f..df1d2bde063e 100644 --- a/x/ibc/keeper.go +++ b/x/ibc/keeper.go @@ -27,3 +27,7 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey) Keeper { channel: channel.NewHandshaker(chanman), } } + +func (k Keeper) Port(id string) channel.Port { + return k.channel.Port(id) +} diff --git a/x/ibc/mock/recv/module.go b/x/ibc/mock/recv/module.go index e4dcb5f7d2d6..89c8ce099a0a 100644 --- a/x/ibc/mock/recv/module.go +++ b/x/ibc/mock/recv/module.go @@ -62,6 +62,14 @@ type AppModule struct { k Keeper } +func NewAppModule(k Keeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{}, + + k: k, + } +} + func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { } diff --git a/x/ibc/mock/send/module.go b/x/ibc/mock/send/module.go index 1749d57ed1d9..8e45118fe495 100644 --- a/x/ibc/mock/send/module.go +++ b/x/ibc/mock/send/module.go @@ -62,6 +62,14 @@ type AppModule struct { k Keeper } +func NewAppModule(k Keeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{}, + + k: k, + } +} + func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { } From 6b966a37d5bfaffb047bcfd41f3483fd9b67420a Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 30 Sep 2019 23:19:36 -0700 Subject: [PATCH 241/378] rename Path -> Prefix --- x/ibc/23-commitment/codec.go | 2 +- x/ibc/23-commitment/merkle/codec.go | 2 +- x/ibc/23-commitment/merkle/merkle.go | 24 +++++++++++----------- x/ibc/23-commitment/merkle/utils.go | 10 ++++------ x/ibc/23-commitment/store.go | 28 +++++++++++--------------- x/ibc/23-commitment/types.go | 8 ++++---- x/ibc/23-commitment/value.go | 30 ++++++++++++++-------------- 7 files changed, 49 insertions(+), 55 deletions(-) diff --git a/x/ibc/23-commitment/codec.go b/x/ibc/23-commitment/codec.go index e2639b78b4f9..943f8ede8b7e 100644 --- a/x/ibc/23-commitment/codec.go +++ b/x/ibc/23-commitment/codec.go @@ -7,6 +7,6 @@ import ( // RegisterCodec registers types declared in this package func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*Root)(nil), nil) - cdc.RegisterInterface((*Path)(nil), nil) + cdc.RegisterInterface((*Prefix)(nil), nil) cdc.RegisterInterface((*Proof)(nil), nil) } diff --git a/x/ibc/23-commitment/merkle/codec.go b/x/ibc/23-commitment/merkle/codec.go index 993c46603a3e..bbb83afa87a4 100644 --- a/x/ibc/23-commitment/merkle/codec.go +++ b/x/ibc/23-commitment/merkle/codec.go @@ -6,6 +6,6 @@ import ( func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(Root{}, "ibc/commitment/merkle/Root", nil) - cdc.RegisterConcrete(Path{}, "ibc/commitment/merkle/Path", nil) + cdc.RegisterConcrete(Prefix{}, "ibc/commitment/merkle/Prefix", nil) cdc.RegisterConcrete(Proof{}, "ibc/commitment/merkle/Proof", nil) } diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index 1606497ec4f8..190f73cbd2fe 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" ) @@ -35,27 +35,27 @@ func (Root) CommitmentKind() string { return merkleKind } -var _ commitment.Path = Path{} +var _ commitment.Prefix = Prefix{} -// Path is merkle path prefixed to the key. +// Prefix is merkle path prefixed to the key. // The constructed key from the Path and the key will be append(Path.KeyPath, append(Path.KeyPrefix, key...)) -type Path struct { +type Prefix struct { // KeyPath is the list of keys prepended before the prefixed key KeyPath [][]byte // KeyPrefix is a byte slice prefixed before the key KeyPrefix []byte } -// NewPath() constructs new Path -func NewPath(keypath [][]byte, keyprefix []byte) Path { - return Path{ +// NewPath() constructs new Prefix +func NewPath(keypath [][]byte, keyprefix []byte) Prefix { + return Prefix{ KeyPath: keypath, KeyPrefix: keyprefix, } } -// Implements commitment.Path -func (Path) CommitmentKind() string { +// Implements commitment.Prefix +func (Prefix) CommitmentKind() string { return merkleKind } @@ -78,13 +78,13 @@ func (proof Proof) GetKey() []byte { } // Verify() proves the proof against the given root, path, and value. -func (proof Proof) Verify(croot commitment.Root, cpath commitment.Path, value []byte) error { +func (proof Proof) Verify(croot commitment.Root, cpath commitment.Prefix, value []byte) error { root, ok := croot.(Root) if !ok { return errors.New("invalid commitment root type") } - path, ok := cpath.(Path) + path, ok := cpath.(Prefix) if !ok { return errors.New("invalid commitment path type") } @@ -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() diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index 954085e3a88d..2f8fea5ca026 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -32,8 +32,8 @@ func RequestQueryMultiStore(storeName string, prefix []byte, key []byte) abci.Re } } -func (path Path) Key(key []byte) []byte { - return join(path.KeyPrefix, key) +func (prefix Prefix) Key(key []byte) []byte { + return join(prefix.KeyPrefix, key) } func join(a, b []byte) (res []byte) { @@ -43,14 +43,12 @@ func join(a, b []byte) (res []byte) { return } - -func (path Path) Path() string { +func (prefix Prefix) Path() string { pathstr := "" - for _, inter := range path.KeyPath { + for _, inter := range prefix.KeyPath { // The Queryable() stores uses slash-separated keypath format for querying pathstr = pathstr + "/" + string(inter) } return pathstr } -*/ diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 923a065334ea..fab1564eccde 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,15 +11,15 @@ type Store interface { Prove(key, value []byte) bool } -var _ Store = prefix{} // TODO: pointer +var _ Store = (*prefix)(nil) // TODO: pointer type prefix struct { store Store prefix []byte } -func NewPrefix(store Store, pref []byte) prefix { - return prefix{ +func NewPrefix(store Store, pref []byte) Store { + return &prefix{ store: store, prefix: pref, } @@ -34,7 +33,7 @@ var _ Store = (*store)(nil) type store struct { root Root - path Path + prefix Prefix proofs map[string]Proof verified map[string][]byte } @@ -42,28 +41,26 @@ type store struct { // NewStore constructs a new Store with the root, path, and proofs. // The proofs are not proven immediately because proofs require value bytes to verify. // If the kinds of the arguments don't match, returns error. -func NewStore(root Root, path Path, proofs []Proof) (res *store, err error) { - if root.CommitmentKind() != path.CommitmentKind() { - err = errors.New("path type not matching with root's") - return +func NewStore(root Root, prefix Prefix, proofs []Proof) (Store, error) { + if root.CommitmentKind() != prefix.CommitmentKind() { + return nil, errors.New("prefix type not matching with root's") } - res = &store{ + res := &store{ root: root, - path: path, + prefix: prefix, proofs: make(map[string]Proof), verified: make(map[string][]byte), } for _, proof := range proofs { if proof.CommitmentKind() != root.CommitmentKind() { - err = errors.New("proof type not matching with root's") - return + return nil, errors.New("proof type not matching with root's") } res.proofs[string(proof.GetKey())] = proof } - return + return res, nil } // Get() returns the value only if it is already proven. @@ -80,10 +77,9 @@ 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) + err := proof.Verify(store.root, store.prefix, value) if err != nil { return false } diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go index 006e2b08c69e..6d09c7c6a404 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/types.go @@ -8,9 +8,9 @@ type Root interface { CommitmentKind() string } -// Path is the additional information provided to the verification function. -// Path represents the common "prefix" that a set of keys shares. -type Path interface { +// Prefix is the additional information provided to the verification function. +// Prefix represents the common "prefix" that a set of keys shares. +type Prefix interface { CommitmentKind() string } @@ -20,5 +20,5 @@ type Path interface { type Proof interface { CommitmentKind() string GetKey() []byte - Verify(Root, Path, []byte) error + Verify(Root, Prefix, []byte) error } diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 947d322c06bd..1c05a8b9e1b1 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -26,7 +26,7 @@ func (m Mapping) store(ctx sdk.Context) Store { return NewPrefix(GetStore(ctx), m.prefix) } -// Prefix() returns a new Mapping with the updated prefix +// Prefix() returns a new Mapping with the updated key prefix func (m Mapping) Prefix(prefix []byte) Mapping { return Mapping{ cdc: m.cdc, @@ -59,13 +59,13 @@ func (m Mapping) Value(key []byte) Value { return Value{m, key} } -// Is() proves the proof with the Value's key and the provided value. -func (v Value) Is(ctx sdk.Context, value interface{}) bool { +// Verify() proves the proof with the Value's key and the provided value. +func (v Value) Verify(ctx sdk.Context, value interface{}) bool { return v.m.store(ctx).Prove(v.key, v.m.cdc.MustMarshalBinaryBare(value)) } -// 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 { +// VerifyRaw() proves the proof with the Value's key and the provided raw value bytes. +func (v Value) VerifyRaw(ctx sdk.Context, value []byte) bool { return v.m.store(ctx).Prove(v.key, value) } @@ -81,9 +81,9 @@ func (v Value) Enum() Enum { return Enum{v} } -// Is() proves the proof with the Enum's key and the provided value -func (v Enum) Is(ctx sdk.Context, value byte) bool { - return v.Value.IsRaw(ctx, []byte{value}) +// Verify() proves the proof with the Enum's key and the provided value +func (v Enum) Verify(ctx sdk.Context, value byte) bool { + return v.Value.VerifyRaw(ctx, []byte{value}) } type String struct { @@ -94,8 +94,8 @@ func (v Value) String() String { return String{v} } -func (v String) Is(ctx sdk.Context, value string) bool { - return v.Value.IsRaw(ctx, []byte(value)) +func (v String) Verify(ctx sdk.Context, value string) bool { + return v.Value.VerifyRaw(ctx, []byte(value)) } type Boolean struct { @@ -106,8 +106,8 @@ func (v Value) Boolean() Boolean { return Boolean{v} } -func (v Boolean) Is(ctx sdk.Context, value bool) bool { - return v.Value.Is(ctx, value) +func (v Boolean) Verify(ctx sdk.Context, value bool) bool { + return v.Value.Verify(ctx, value) } // Integer is a uint64 types wrapper for Value. @@ -122,7 +122,7 @@ func (v Value) Integer(enc state.IntEncoding) Integer { return Integer{v, enc} } -// Is() proves the proof with the Integer's key and the provided value -func (v Integer) Is(ctx sdk.Context, value uint64) bool { - return v.Value.IsRaw(ctx, state.EncodeInt(value, v.enc)) +// Verify() proves the proof with the Integer's key and the provided value +func (v Integer) Verify(ctx sdk.Context, value uint64) bool { + return v.Value.VerifyRaw(ctx, state.EncodeInt(value, v.enc)) } From 21bd8d0ce4334cbd03f4542ddd2c0f46d7f01561 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 1 Oct 2019 13:12:35 +0200 Subject: [PATCH 242/378] Store accessor upstream changes (#5119) * Store accessor upstream changes (#5119) --- store/state/enum.go | 3 +++ store/state/integer.go | 4 ++++ 2 files changed, 7 insertions(+) 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 } From df5b21ab5638a64ae998ccf5cc85fbd2333a1378 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 1 Oct 2019 20:16:54 +0900 Subject: [PATCH 243/378] add comments, reformat merkle querier --- x/ibc/23-commitment/README.md | 50 --------------------- x/ibc/23-commitment/merkle/merkle.go | 5 +++ x/ibc/23-commitment/merkle/merkle_test.go | 15 ++++--- x/ibc/23-commitment/merkle/utils.go | 33 +------------- x/ibc/23-commitment/store.go | 53 ++++++++++++----------- x/ibc/23-commitment/types.go | 13 +++++- x/ibc/23-commitment/value.go | 48 ++++++++++++++++---- 7 files changed, 94 insertions(+), 123 deletions(-) delete mode 100644 x/ibc/23-commitment/README.md diff --git a/x/ibc/23-commitment/README.md b/x/ibc/23-commitment/README.md deleted file mode 100644 index 256e77f0b95d..000000000000 --- a/x/ibc/23-commitment/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# ICS 23: Commitment - -Package `commitment` defines types and methods to verify other chain's state. The main type is `Store`, containing -proofs that can be verified when the correct value is provided. The spec functions those are directly related to -verification are: - -## Spec - -```typescript -type verifyMembership = (root: CommitmentRoot, proof: CommitmentProof, key: Key, value: Value) => bool -type verifyNonMembership = (root: CommitmentRoot, proof: CommitmentProof, key: Key) => bool -``` - -## Implementation - -### types.go - -`type Proof` implements `spec: type CommitmentProof`. CommitmentProof is an arbitrary object which can be used as -an argument for `spec: verifyMembership` / `spec: verifyNonMembership`, constructed with `spec: createMembershipProof` / -`spec: createNonMembershipProof`. The implementation type `Proof` defines `spec: verify(Non)Membership` as its method -`Verify(Root, []byte) error`, which takes the commitment root and the value bytes as arguments. The method acts as -`spec: verifyMembership` when the value bytes is not nil, and `spec: verifyNonMembership` if it is nil. - -`type Root` implements `spec: type CommitmentRoot`. - -In Cosmos-SDK implementation, `Root` will be the `AppHash []byte`, and `Proof` will be `merkle.Proof`, which consists -of `SimpleProof` and `IAVLValueProof`. Defined in `merkle/` - -### store.go - -`Store` assumes that the keys are already known at the time when the transaction is included, so the type `Proof` has -the method `Key() []byte`. The values should also have to be provided in order to verify the proof, but to reduce the -size of the transaction, they are excluded from `Proof` and provided by the application on runtime. - -`NewStore` takes `[]Proof` as its argument, without verifying, since the values are yet unknown. They are stored in -`store.proofs`. - -Proofs can be verified with `store.Prove()` method which takes the key of the proof it will verify and the value -that will be given to the `proof.Verify()`. Verified proofs are stored in `store.verified`. - -### context.go - -All of the ICS internals that requires verification on other chains' state are expected to take `ctx sdk.Context` -argument initialized by `WithStore()`. `WithStore()` sets the `Store` that contains the proofs for the other chain -in the context. Any attept to verify other chain's state without setting `Store` will lead to panic. - -### value.go - -Types in `value.go` is a replication of `store/mapping/*.go`, but only with a single method -`Is(ctx sdk.Context, value T) bool`, which access on the underlying `Store` and performs verification. diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index 190f73cbd2fe..36563f8f3344 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -12,6 +12,10 @@ import ( commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) +// ICS 023 Merkle Types Implementation +// +// This file defines Merkle commitment types that implements ICS 023. + const merkleKind = "merkle" // merkle.Proof implementation of Proof @@ -19,6 +23,7 @@ const merkleKind = "merkle" var _ commitment.Root = Root{} // Root is Merkle root hash +// In Cosmos-SDK, the AppHash of the Header becomes Root. type Root struct { Hash []byte } diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index efa384a6c317..c652289caf34 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -68,20 +68,22 @@ func TestStore(t *testing.T) { // Test query, and accumulate proofs proofs := make([]commitment.Proof, 0, kvpn) for k, v := range m { - v0, p, err := QueryMultiStore(cms, storeName, prefix, []byte(k)) + q := state.NewStoreQuerier(cms.(types.Queryable)) + v0, p, err := mapp.Value([]byte(k)).QueryRaw(q) require.NoError(t, err) require.Equal(t, cdc.MustMarshalBinaryBare(v), v0, "Queried value different at %d", repeat) - proofs = append(proofs, p) + proofs = append(proofs, Proof{Key: []byte(k), Proof: p}) } // Add some exclusion proofs for i := 0; i < 10; i++ { k := make([]byte, 64) rand.Read(k) - v, p, err := QueryMultiStore(cms, storeName, prefix, k) + q := state.NewStoreQuerier(cms.(types.Queryable)) + v, p, err := mapp.Value([]byte(k)).QueryRaw(q) require.NoError(t, err) require.Nil(t, v) - proofs = append(proofs, p) + proofs = append(proofs, Proof{Key: []byte(k), Proof: p}) m[string(k)] = []byte{} } @@ -110,10 +112,11 @@ func TestStore(t *testing.T) { // Test query, and accumulate proofs proofs = make([]commitment.Proof, 0, kvpn) for k, v := range m { - v0, p, err := QueryMultiStore(cms, storeName, prefix, []byte(k)) + q := state.NewStoreQuerier(cms.(types.Queryable)) + v0, p, err := mapp.Value([]byte(k)).QueryRaw(q) require.NoError(t, err) require.Equal(t, cdc.MustMarshalBinaryBare(v), v0) - proofs = append(proofs, p) + proofs = append(proofs, Proof{Key: []byte(k), Proof: p}) } cstore, err = commitment.NewStore(root, path, proofs) diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index 2f8fea5ca026..5e908af9783c 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -1,36 +1,6 @@ package merkle -import ( - "errors" - - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/store/types" -) - -func QueryMultiStore(cms types.CommitMultiStore, storeName string, prefix []byte, key []byte) ([]byte, Proof, error) { - queryable, ok := cms.(types.Queryable) - if !ok { - panic("CommitMultiStore not queryable") - } - qres := queryable.Query(RequestQueryMultiStore(storeName, prefix, key)) - if !qres.IsOK() { - return nil, Proof{}, errors.New(qres.Log) - } - - return qres.Value, Proof{Key: key, Proof: qres.Proof}, nil -} - -func RequestQueryMultiStore(storeName string, prefix []byte, key []byte) abci.RequestQuery { - // Suffixing path with "/key". - // iavl.Store.Query() switches over the last path element, - // and performs key-value query only if it is "/key" - return abci.RequestQuery{ - Path: "/" + storeName + "/key", - Data: join(prefix, key), - Prove: true, - } -} +/* func (prefix Prefix) Key(key []byte) []byte { return join(prefix.KeyPrefix, key) @@ -52,3 +22,4 @@ func (prefix Prefix) Path() string { return pathstr } +*/ diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index fab1564eccde..4c4ae37ab167 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -5,19 +5,28 @@ import ( "errors" ) -// Store proves key-value pairs' inclusion or non-inclusion with -// the stored commitment proofs against the commitment root. +// ICS 023 Function Implementation +// +// This file includes functions defined under +// https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments + +// Store partially implements spec:verifyMembership and spec:verifyNonMembership. +// Store holds Root, Prefix, and list of Proofs that will be verified. +// Proofs incldues their respective Paths. Values are provided at the verification time. type Store interface { - Prove(key, value []byte) bool + Prove(path, value []byte) bool } -var _ Store = (*prefix)(nil) // TODO: pointer +var _ Store = (*prefix)(nil) type prefix struct { store Store prefix []byte } +// NewPrefix returns a prefixed store given base store and prefix. +// Prefix store for commitment proofs is used for similar path bytestring +// prefixing UX with local KVStore. func NewPrefix(store Store, pref []byte) Store { return &prefix{ store: store, @@ -25,8 +34,9 @@ func NewPrefix(store Store, pref []byte) Store { } } -func (prefix prefix) Prove(key, value []byte) bool { - return prefix.store.Prove(join(prefix.prefix, key), value) +// Prove implements Store. +func (prefix prefix) Prove(path, value []byte) bool { + return prefix.store.Prove(join(prefix.prefix, path), value) } var _ Store = (*store)(nil) @@ -39,8 +49,8 @@ type store struct { } // NewStore constructs a new Store with the root, path, and proofs. -// The proofs are not proven immediately because proofs require value bytes to verify. -// If the kinds of the arguments don't match, returns error. +// The result store will be stored in the context and used by the +// commitment.Value types. func NewStore(root Root, prefix Prefix, proofs []Proof) (Store, error) { if root.CommitmentKind() != prefix.CommitmentKind() { return nil, errors.New("prefix type not matching with root's") @@ -63,19 +73,18 @@ func NewStore(root Root, prefix Prefix, proofs []Proof) (Store, error) { return res, nil } -// Get() returns the value only if it is already proven. -func (store *store) Get(key []byte) ([]byte, bool) { - res, ok := store.verified[string(key)] - return res, ok -} - -// Prove() proves the key-value pair with the stored proof. -func (store *store) Prove(key, value []byte) bool { - stored, ok := store.Get(key) +// Prove implements spec:verifyMembership and spec:verifyNonMembership. +// The path should be one of the path format defined under +// https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements +// Prove retrieves the matching proof with the provided path from the internal map +// and call Verify method on it with internal Root and Prefix. +// Prove acts as verifyMembership if value is not nil, and verifyNonMembership if nil. +func (store *store) Prove(path, value []byte) bool { + stored, ok := store.verified[string(path)] if ok && bytes.Equal(stored, value) { return true } - proof, ok := store.proofs[string(key)] + proof, ok := store.proofs[string(path)] if !ok { return false } @@ -83,13 +92,7 @@ func (store *store) Prove(key, value []byte) bool { if err != nil { return false } - store.verified[string(key)] = value + store.verified[string(path)] = value return true } - -// Proven() returns true if the key-value pair is already proven -func (store *store) Proven(key []byte) bool { - _, ok := store.Get(key) - return ok -} diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go index 6d09c7c6a404..0e8a5db04d07 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/types.go @@ -1,6 +1,13 @@ package commitment -// Root is the interface for commitment root. +// ICS 023 Types Implementation +// +// This file includes types defined under +// https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments + +// spec:Path and spec:Value are defined as bytestring + +// Root implements spec:CommitmentRoot. // A root is constructed from a set of key-value pairs, // and the inclusion or non-inclusion of an arbitrary key-value pair // can be proven with the proof. @@ -8,15 +15,17 @@ type Root interface { CommitmentKind() string } +// Prefix implements spec:CommitmentPrefix. // Prefix is the additional information provided to the verification function. // Prefix represents the common "prefix" that a set of keys shares. type Prefix interface { CommitmentKind() string } +// Proof implements spec:CommitmentProof. // Proof can prove whether the key-value pair is a part of the Root or not. // Each proof has designated key-value pair it is able to prove. -// Proofs stores key but value is provided dynamically at the verification time. +// Proofs includes key but value is provided dynamically at the verification time. type Proof interface { CommitmentKind() string GetKey() []byte diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 1c05a8b9e1b1..4ea74ae9e8ed 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -6,6 +6,27 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// Remote State Accessors +// +// This file defines the state accessor type for remote chains. +// The accessors defined here, unlike normal accessors, cannot +// mutate the state. The accessors are for storing the state +// struct, which means, given correct proofs, the remote state +// accessors reflects the behaviour of the normal state accessors. +// +// Exmaple +// +// On chain A, the following state mutation has happened +// v := state.NewMapping(sdk.NewStoreKey(name), cdc, preprefix+prefix).Value(key) +// v.Set(ctx, value) +// +// Given a correct membership proof, the following function returns true +// v := commitment.NewMapping(cdc, prefix).Value(key) +// v.Verify(ctx, value) +// +// The storeKey name and preprefix information is embedded in the store as +// merkle.Prefix{[][]byte{name}, preprefix} + // Mapping is key []byte -> value []byte mapping, possibly prefixed. // Proof verification should be done over Value constructed from the Mapping. type Mapping struct { @@ -13,7 +34,7 @@ type Mapping struct { prefix []byte } -// NewMapping() constructs a new Mapping. +// NewMapping constructs a new Mapping. // The KVStore accessor is fixed to the commitment store. func NewMapping(cdc *codec.Codec, prefix []byte) Mapping { return Mapping{ @@ -26,7 +47,7 @@ func (m Mapping) store(ctx sdk.Context) Store { return NewPrefix(GetStore(ctx), m.prefix) } -// Prefix() returns a new Mapping with the updated key prefix +// Prefix returns a new Mapping with the updated key prefix func (m Mapping) Prefix(prefix []byte) Mapping { return Mapping{ cdc: m.cdc, @@ -50,23 +71,26 @@ func (ix Indexer) Value(index uint64) Value { return ix.Mapping.Value(state.EncodeInt(index, ix.enc)) } +// Value is a reference for a key-value point on a remote state. +// Value only contains the information of the key string information +// which is used by the commitment proof verification type Value struct { m Mapping key []byte } +// Value constructs a Value with the provided key func (m Mapping) Value(key []byte) Value { return Value{m, key} } -// Verify() proves the proof with the Value's key and the provided value. +// Verify proves the proof with the Value's key and the provided value. func (v Value) Verify(ctx sdk.Context, value interface{}) bool { return v.m.store(ctx).Prove(v.key, v.m.cdc.MustMarshalBinaryBare(value)) } -// VerifyRaw() proves the proof with the Value's key and the provided raw value bytes. +// VerifyRaw proves the proof with the Value's key and the provided raw value bytes. func (v Value) VerifyRaw(ctx sdk.Context, value []byte) bool { - return v.m.store(ctx).Prove(v.key, value) } @@ -76,36 +100,42 @@ type Enum struct { Value } -// Enum() wraps the argument Value as Enum +// Enum wraps the argument Value as Enum func (v Value) Enum() Enum { return Enum{v} } -// Verify() proves the proof with the Enum's key and the provided value +// Verify proves the proof with the Enum's key and the provided value func (v Enum) Verify(ctx sdk.Context, value byte) bool { return v.Value.VerifyRaw(ctx, []byte{value}) } +// String is a string types wrapper for Value. type String struct { Value } +// String wraps the argument Value as String func (v Value) String() String { return String{v} } +// Verify proves the proof with the String's key and the provided value func (v String) Verify(ctx sdk.Context, value string) bool { return v.Value.VerifyRaw(ctx, []byte(value)) } +// Boolean is a bool types wrapper for Value. type Boolean struct { Value } +// Boolean wraps the argument Value as Boolean func (v Value) Boolean() Boolean { return Boolean{v} } +// Verify proves the proof with the Boolean's key and the provided value func (v Boolean) Verify(ctx sdk.Context, value bool) bool { return v.Value.Verify(ctx, value) } @@ -117,12 +147,12 @@ type Integer struct { enc state.IntEncoding } -// Integer() wraps the argument Value as Integer +// Integer wraps the argument Value as Integer func (v Value) Integer(enc state.IntEncoding) Integer { return Integer{v, enc} } -// Verify() proves the proof with the Integer's key and the provided value +// Verify proves the proof with the Integer's key and the provided value func (v Integer) Verify(ctx sdk.Context, value uint64) bool { return v.Value.VerifyRaw(ctx, state.EncodeInt(value, v.enc)) } From 1ac982c602a178e7c109726291b52b90434a7ec5 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 1 Oct 2019 20:21:34 +0900 Subject: [PATCH 244/378] rm merkle/utils --- x/ibc/23-commitment/merkle/utils.go | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 x/ibc/23-commitment/merkle/utils.go diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go deleted file mode 100644 index 5e908af9783c..000000000000 --- a/x/ibc/23-commitment/merkle/utils.go +++ /dev/null @@ -1,25 +0,0 @@ -package merkle - -/* - -func (prefix Prefix) Key(key []byte) []byte { - return join(prefix.KeyPrefix, key) -} - -func join(a, b []byte) (res []byte) { - res = make([]byte, len(a)+len(b)) - copy(res, a) - copy(res[len(a):], b) - return -} - -func (prefix Prefix) Path() string { - pathstr := "" - for _, inter := range prefix.KeyPath { - // The Queryable() stores uses slash-separated keypath format for querying - pathstr = pathstr + "/" + string(inter) - } - - return pathstr -} -*/ From fa0441997b15e05950b54c09b3ba5b8b83004976 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 1 Oct 2019 14:02:42 +0200 Subject: [PATCH 245/378] ICS 23 upstream changes (#5120) * ICS 23 upstream changes (#5120) --- x/ibc/23-commitment/merkle/merkle.go | 19 ++++++----- x/ibc/23-commitment/merkle/merkle_test.go | 2 +- x/ibc/23-commitment/merkle/utils.go | 40 +++++++++++++++++++++++ x/ibc/23-commitment/store.go | 2 +- 4 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 x/ibc/23-commitment/merkle/utils.go diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index 36563f8f3344..f310ac948151 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -25,7 +25,7 @@ var _ commitment.Root = Root{} // Root is Merkle root hash // In Cosmos-SDK, the AppHash of the Header becomes Root. type Root struct { - Hash []byte + Hash []byte `json:"hash"` } // NewRoot constructs a new Root @@ -46,13 +46,13 @@ var _ commitment.Prefix = Prefix{} // The constructed key from the Path and the key will be append(Path.KeyPath, append(Path.KeyPrefix, key...)) type Prefix 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 Prefix -func NewPath(keypath [][]byte, keyprefix []byte) Prefix { +// NewPrefix constructs new Prefix instance +func NewPrefix(keypath [][]byte, keyprefix []byte) Prefix { return Prefix{ KeyPath: keypath, KeyPrefix: keyprefix, @@ -64,12 +64,16 @@ func (Prefix) CommitmentKind() string { return merkleKind } +func (prefix Prefix) Key(key []byte) []byte { + return join(prefix.KeyPrefix, key) +} + 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 @@ -114,6 +118,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/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index c652289caf34..fd550d43da53 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -45,7 +45,7 @@ func TestStore(t *testing.T) { storeName := k.Name() prefix := []byte{0x01, 0x03, 0x05, 0xAA, 0xBB} mapp := state.NewMapping(k, cdc, prefix) - path := NewPath([][]byte{[]byte(storeName)}, prefix) + path := NewPrefix([][]byte{[]byte(storeName)}, prefix) m := make(map[string][]byte) kvpn := 10 diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go new file mode 100644 index 000000000000..ec933af09748 --- /dev/null +++ b/x/ibc/23-commitment/merkle/utils.go @@ -0,0 +1,40 @@ +package merkle + +import ( + "errors" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/store/types" +) + +func QueryMultiStore(cms types.CommitMultiStore, storeName string, prefix []byte, key []byte) ([]byte, Proof, error) { + queryable, ok := cms.(types.Queryable) + if !ok { + panic("CommitMultiStore not queryable") + } + qres := queryable.Query(RequestQueryMultiStore(storeName, prefix, key)) + if !qres.IsOK() { + return nil, Proof{}, errors.New(qres.Log) + } + + return qres.Value, Proof{Key: key, Proof: qres.Proof}, nil +} + +func RequestQueryMultiStore(storeName string, prefix []byte, key []byte) abci.RequestQuery { + // Suffixing path with "/key". + // iavl.Store.Query() switches over the last path element, + // and performs key-value query only if it is "/key" + return abci.RequestQuery{ + Path: "/" + storeName + "/key", + Data: join(prefix, key), + Prove: true, + } +} + +func join(a, b []byte) (res []byte) { + res = make([]byte, len(a)+len(b)) + copy(res, a) + copy(res[len(a):], b) + return +} diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 4c4ae37ab167..1ced699258fd 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -17,7 +17,7 @@ type Store interface { Prove(path, value []byte) bool } -var _ Store = (*prefix)(nil) +var _ Store = prefix{} type prefix struct { store Store From db8d3820916f4ce754e1af7ac1c0c565f992f104 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Oct 2019 15:54:09 +0200 Subject: [PATCH 246/378] update Value --- x/ibc/23-commitment/value.go | 69 ++++++++++-------------------------- 1 file changed, 19 insertions(+), 50 deletions(-) diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 4ea74ae9e8ed..5797e1cd13c9 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -6,27 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// Remote State Accessors -// -// This file defines the state accessor type for remote chains. -// The accessors defined here, unlike normal accessors, cannot -// mutate the state. The accessors are for storing the state -// struct, which means, given correct proofs, the remote state -// accessors reflects the behaviour of the normal state accessors. -// -// Exmaple -// -// On chain A, the following state mutation has happened -// v := state.NewMapping(sdk.NewStoreKey(name), cdc, preprefix+prefix).Value(key) -// v.Set(ctx, value) -// -// Given a correct membership proof, the following function returns true -// v := commitment.NewMapping(cdc, prefix).Value(key) -// v.Verify(ctx, value) -// -// The storeKey name and preprefix information is embedded in the store as -// merkle.Prefix{[][]byte{name}, preprefix} - // Mapping is key []byte -> value []byte mapping, possibly prefixed. // Proof verification should be done over Value constructed from the Mapping. type Mapping struct { @@ -34,7 +13,7 @@ type Mapping struct { prefix []byte } -// NewMapping constructs a new Mapping. +// NewMapping() constructs a new Mapping. // The KVStore accessor is fixed to the commitment store. func NewMapping(cdc *codec.Codec, prefix []byte) Mapping { return Mapping{ @@ -47,7 +26,7 @@ func (m Mapping) store(ctx sdk.Context) Store { return NewPrefix(GetStore(ctx), m.prefix) } -// Prefix returns a new Mapping with the updated key prefix +// Prefix() returns a new Mapping with the updated prefix func (m Mapping) Prefix(prefix []byte) Mapping { return Mapping{ cdc: m.cdc, @@ -71,26 +50,22 @@ func (ix Indexer) Value(index uint64) Value { return ix.Mapping.Value(state.EncodeInt(index, ix.enc)) } -// Value is a reference for a key-value point on a remote state. -// Value only contains the information of the key string information -// which is used by the commitment proof verification type Value struct { m Mapping key []byte } -// Value constructs a Value with the provided key func (m Mapping) Value(key []byte) Value { return Value{m, key} } -// Verify proves the proof with the Value's key and the provided value. -func (v Value) Verify(ctx sdk.Context, value interface{}) bool { +// Is() proves the proof with the Value's key and the provided value. +func (v Value) Is(ctx sdk.Context, value interface{}) bool { return v.m.store(ctx).Prove(v.key, v.m.cdc.MustMarshalBinaryBare(value)) } -// VerifyRaw proves the proof with the Value's key and the provided raw value bytes. -func (v Value) VerifyRaw(ctx sdk.Context, value []byte) 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) } @@ -100,44 +75,38 @@ type Enum struct { Value } -// Enum wraps the argument Value as Enum +// Enum() wraps the argument Value as Enum func (v Value) Enum() Enum { return Enum{v} } -// Verify proves the proof with the Enum's key and the provided value -func (v Enum) Verify(ctx sdk.Context, value byte) bool { - return v.Value.VerifyRaw(ctx, []byte{value}) +// Is() proves the proof with the Enum's key and the provided value +func (v Enum) Is(ctx sdk.Context, value byte) bool { + return v.Value.IsRaw(ctx, []byte{value}) } -// String is a string types wrapper for Value. type String struct { Value } -// String wraps the argument Value as String func (v Value) String() String { return String{v} } -// Verify proves the proof with the String's key and the provided value -func (v String) Verify(ctx sdk.Context, value string) bool { - return v.Value.VerifyRaw(ctx, []byte(value)) +func (v String) Is(ctx sdk.Context, value string) bool { + return v.Value.IsRaw(ctx, []byte(value)) } -// Boolean is a bool types wrapper for Value. type Boolean struct { Value } -// Boolean wraps the argument Value as Boolean func (v Value) Boolean() Boolean { return Boolean{v} } -// Verify proves the proof with the Boolean's key and the provided value -func (v Boolean) Verify(ctx sdk.Context, value bool) bool { - return v.Value.Verify(ctx, value) +func (v Boolean) Is(ctx sdk.Context, value bool) bool { + return v.Value.Is(ctx, value) } // Integer is a uint64 types wrapper for Value. @@ -147,12 +116,12 @@ type Integer struct { enc state.IntEncoding } -// Integer wraps the argument Value as Integer +// Integer() wraps the argument Value as Integer func (v Value) Integer(enc state.IntEncoding) Integer { return Integer{v, enc} } -// Verify proves the proof with the Integer's key and the provided value -func (v Integer) Verify(ctx sdk.Context, value uint64) bool { - return v.Value.VerifyRaw(ctx, state.EncodeInt(value, v.enc)) -} +// Is() proves the proof with the Integer's key and the provided value +func (v Integer) Is(ctx sdk.Context, value uint64) bool { + return v.Value.IsRaw(ctx, state.EncodeInt(value, v.enc)) +} \ No newline at end of file From 4d518f2ed06e5ee4c6a1054350b099d9330da8c6 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Oct 2019 16:03:29 +0200 Subject: [PATCH 247/378] update test --- x/ibc/02-client/tendermint/tests/types.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 51f56a50fbb1..20cb6ddfdd19 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -52,7 +52,7 @@ type Node struct { Commits []tmtypes.SignedHeader StoreName string - Prefix []byte + KeyPrefix []byte } func NewNode(valset MockValidators, storeName string, prefix []byte) *Node { @@ -65,12 +65,12 @@ func NewNode(valset MockValidators, storeName string, prefix []byte) *Node { Store: ctx.KVStore(key), Commits: nil, StoreName: storeName, - Prefix: prefix, + KeyPrefix: prefix, } } -func (node *Node) Path() merkle.Path { - return merkle.NewPath([][]byte{[]byte(node.StoreName)}, node.Prefix) +func (node *Node) Prefix() merkle.Prefix { + return merkle.NewPrefix([][]byte{[]byte(node.StoreName)}, node.KeyPrefix) } func (node *Node) Last() tmtypes.SignedHeader { From 8a3e5ea57ce19c420e45204f188b466b99f02f2e Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Oct 2019 16:06:13 +0200 Subject: [PATCH 248/378] fix --- x/ibc/02-client/tendermint/tests/types.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/tendermint/tests/types.go index 20cb6ddfdd19..b9b238c74126 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/tendermint/tests/types.go @@ -150,16 +150,16 @@ func (v *Verifier) Validate(header tendermint.Header, valset, nextvalset MockVal } func (node *Node) Query(t *testing.T, k []byte) ([]byte, commitment.Proof) { - if bytes.HasPrefix(k, node.Prefix) { - k = bytes.TrimPrefix(k, node.Prefix) + if bytes.HasPrefix(k, node.KeyPrefix) { + k = bytes.TrimPrefix(k, node.KeyPrefix) } - value, proof, err := merkle.QueryMultiStore(node.Cms, node.StoreName, node.Prefix, k) + value, proof, err := merkle.QueryMultiStore(node.Cms, node.StoreName, node.KeyPrefix, k) require.NoError(t, err) return value, proof } func (node *Node) Set(k, value []byte) { - node.Store.Set(join(node.Prefix, k), value) + node.Store.Set(join(node.KeyPrefix, k), value) } // nolint:deadcode,unused @@ -190,7 +190,7 @@ func testProof(t *testing.T) { require.Equal(t, kvp.Value, v) proofs = append(proofs, p) } - cstore, err := commitment.NewStore(root, node.Path(), proofs) + cstore, err := commitment.NewStore(root, node.Prefix(), proofs) require.NoError(t, err) for _, kvp := range kvps { From 9975a1d2a84dac1ac3274113e5543ef829446e79 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 1 Oct 2019 16:45:02 +0200 Subject: [PATCH 249/378] ICS 02 upstream changes (#5122) * ICS 02 upstream changes (#5122) --- x/ibc/02-client/README.md | 2 +- x/ibc/02-client/cli.go | 14 ++++-- x/ibc/02-client/client/cli/query.go | 52 +++++++++++++++++-- x/ibc/02-client/client/cli/tx.go | 8 +-- x/ibc/02-client/codec.go | 10 ++-- x/ibc/02-client/manager.go | 78 +++++++++++++++++++++-------- x/ibc/02-client/tendermint/codec.go | 5 -- x/ibc/version.go | 3 -- x/ibc/version/version.go | 13 +++++ 9 files changed, 139 insertions(+), 46 deletions(-) delete mode 100644 x/ibc/version.go create mode 100644 x/ibc/version/version.go 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 67740d181748..0895bbcc2c38 100644 --- a/x/ibc/02-client/cli.go +++ b/x/ibc/02-client/cli.go @@ -5,20 +5,28 @@ import ( "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(q state.ABCIQuerier) (res ConsensusState, proof merkle.Proof, err error) { +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(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { +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 624cfd7af9ff..ca3382814356 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 } @@ -49,11 +51,11 @@ func GetCmdQueryClient(storeKey string, cdc *codec.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) q := state.NewCLIQuerier(ctx) - mapp := mapping(cdc, storeKey, ibc.Version) + mapp := mapping(cdc, storeKey, version.Version) man := client.NewManager(mapp) id := args[0] - state, _, err := man.Object(id).ConsensusStateCLI(q) + state, _, err := man.State(id).ConsensusStateCLI(q) if err != nil { return err } @@ -65,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", @@ -109,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.NewPrefix([][]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 5c14323cb633..8fc389420558 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,6 +129,36 @@ 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 State) Freeze(ctx sdk.Context) error { + if !obj.exists(ctx) { + panic("should not freeze nonexisting client") + } + + if obj.Frozen.Get(ctx) { + return errors.New("client is already Frozen") + } + + obj.Frozen.Set(ctx, true) + + return nil +} + +func (obj State) Delete(ctx sdk.Context) error { + if !obj.exists(ctx) { + panic("should not delete nonexisting client") + } + + if !obj.Frozen.Get(ctx) { + return errors.New("client is not Frozen") + } + + obj.ConsensusState.Delete(ctx) + obj.Frozen.Delete(ctx) return nil } 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/version.go b/x/ibc/version.go deleted file mode 100644 index 11bd8ee5b3d3..000000000000 --- a/x/ibc/version.go +++ /dev/null @@ -1,3 +0,0 @@ -package ibc - -const Version int64 = 1 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) + "/") +} From 11bdbd75cd56f8e38b00ffe732ca1aeb04a5b75f Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 1 Oct 2019 17:36:26 +0200 Subject: [PATCH 250/378] ICS 03 upstream changes (#5123) * ICS 03 upstream changes (#5123) --- store/state/mapping.go | 1 - x/ibc/03-connection/cli.go | 66 +++--- x/ibc/03-connection/client/cli/query.go | 24 +-- x/ibc/03-connection/client/cli/tx.go | 243 ++++++++++++++++++---- x/ibc/03-connection/client/utils/types.go | 44 ++-- x/ibc/03-connection/codec.go | 24 +++ x/ibc/03-connection/handler.go | 18 +- x/ibc/03-connection/handshake.go | 132 ++++++------ x/ibc/03-connection/manager.go | 147 +++++++------ x/ibc/03-connection/msgs.go | 45 ++-- x/ibc/03-connection/tests/types.go | 56 ++--- x/ibc/03-connection/types.go | 8 +- x/ibc/23-commitment/store.go | 4 +- x/ibc/23-commitment/value.go | 1 - 14 files changed, 499 insertions(+), 314 deletions(-) create mode 100644 x/ibc/03-connection/codec.go diff --git a/store/state/mapping.go b/store/state/mapping.go index 5ff4cb1ee563..3b81d2323efe 100644 --- a/store/state/mapping.go +++ b/store/state/mapping.go @@ -101,4 +101,3 @@ func (m Mapping) Prefix(prefix []byte) Mapping { prefix: join(m.prefix, prefix), } } - diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index 7fa3986465d7..7f54a598b6a9 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -7,56 +7,64 @@ import ( "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) - return obj +func (man Manager) CLIState(connid, clientid string) State { + state := man.State(connid) + state.Client = man.client.State(clientid) + return state } -func (obj Object) prefix() []byte { - return bytes.Split(obj.Connection.KeyBytes(), LocalRoot())[0] +func (man Manager) CLIQuery(q state.ABCIQuerier, connid string) (State, error) { + state := man.State(connid) + conn, _, err := state.ConnectionCLI(q) + if err != nil { + return State{}, err + } + state.Client = man.client.State(conn.Client) + return state, nil +} + +func (state State) prefix() []byte { + return bytes.Split(state.Connection.KeyBytes(), LocalRoot())[0] } -func (obj Object) 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) +func (state State) ConnectionCLI(q state.ABCIQuerier) (res Connection, proof merkle.Proof, err error) { + tmproof, err := state.Connection.Query(q, &res) + proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Connection) return } -func (obj Object) 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) +func (state State) AvailableCLI(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { + res, tmproof, err := state.Available.Query(q) + proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Available) return } -func (obj Object) 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) +func (state State) KindCLI(q state.ABCIQuerier) (res string, proof merkle.Proof, err error) { + res, tmproof, err := state.Kind.Query(q) + proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.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(q state.ABCIQuerier, connid string) (HandshakeObject, error) { - obj := man.man.Object(connid) - conn, _, err := obj.ConnectionCLI(q) +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(q state.ABCIQuerier) (res byte, proof merkle.Proof, err error) { - res, tmproof, err := obj.State.Query(q) - proof = merkle.NewProofFromValue(tmproof, obj.prefix(), obj.State) +func (state HandshakeState) StageCLI(q state.ABCIQuerier) (res byte, proof merkle.Proof, err error) { + res, tmproof, err := state.Stage.Query(q) + proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Stage) return } -func (obj HandshakeObject) 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) +func (state HandshakeState) CounterpartyClientCLI(q state.ABCIQuerier) (res string, proof merkle.Proof, err error) { + res, tmproof, err := state.CounterpartyClient.Query(q) + proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.CounterpartyClient) return } diff --git a/x/ibc/03-connection/client/cli/query.go b/x/ibc/03-connection/client/cli/query.go index 4c6c4a06f1e0..96d4c24d92c7 100644 --- a/x/ibc/03-connection/client/cli/query.go +++ b/x/ibc/03-connection/client/cli/query.go @@ -9,24 +9,24 @@ import ( 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" + storestate "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" 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 { - base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) +func state(cdc *codec.Codec, storeKey string, prefix []byte, connid, clientid string) connection.State { + base := storestate.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 { @@ -43,8 +43,8 @@ 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) { - q := state.NewCLIQuerier(ctx) +func QueryConnection(ctx context.CLIContext, obj connection.State, prove bool) (res utils.JSONState, err error) { + q := storestate.NewCLIQuerier(ctx) conn, connp, err := obj.ConnectionCLI(q) if err != nil { @@ -60,14 +60,14 @@ func QueryConnection(ctx context.CLIContext, obj connection.Object, prove bool) } 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, @@ -81,13 +81,13 @@ 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], "") - jsonobj, err := QueryConnection(ctx, obj, viper.GetBool(FlagProve)) + state := state(cdc, storeKey, version.Prefix(version.Version), args[0], "") + jsonObj, err := QueryConnection(ctx, state, viper.GetBool(FlagProve)) if err != nil { return err } - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, jsonobj)) + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, jsonObj)) return nil }, diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index c1910960a5f5..67c97d1172cd 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" + storestate "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" + 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" ) -/* -func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - -} -*/ const ( FlagNode1 = "node1" FlagNode2 = "node2" @@ -31,14 +33,14 @@ const ( FlagFrom2 = "from2" ) -func handshake(q state.ABCIQuerier, cdc *codec.Codec, storeKey string, prefix []byte, connid string) (connection.HandshakeObject, error) { - base := state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) - climan := client.NewManager(base) - man := connection.NewHandshaker(connection.NewManager(base, climan)) +func handshake(q storestate.ABCIQuerier, cdc *codec.Codec, storeKey string, prefix []byte, connid string) (connection.HandshakeState, error) { + base := storestate.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) + 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,74 +54,163 @@ 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)) - q1 := state.NewCLIQuerier(ctx1) + WithBroadcastMode(flags.BroadcastBlock) + q1 := storestate.NewCLIQuerier(ctx1) - ctx2 := context.NewCLIContext(). + ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). WithCodec(cdc). WithNodeURI(viper.GetString(FlagNode2)). - WithFrom(viper.GetString(FlagFrom2)) - q2 := state.NewCLIQuerier(ctx2) + WithBroadcastMode(flags.BroadcastBlock) + q2 := storestate.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.Prefix + 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(q1, 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.Prefix + 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(q2, 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 - msginit := connection.MsgOpenInit{ - ConnectionID: conn1id, + msgInit := connection.MsgOpenInit{ + ConnectionID: connId1, Connection: conn1, CounterpartyClient: conn2.Client, Signer: ctx1.GetFromAddress(), } - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msginit}) + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgInit}) 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 + } + + msgUpdate := client.MsgUpdateClient{ + ClientID: conn2.Client, + Header: header, + Signer: ctx2.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) + if err != nil { + return err + } + + q1 = storestate.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 } - _, pstate, err := obj1.StateCLI(q1) + _, pstate, err := obj1.StageCLI(q1) if err != nil { return err } @@ -128,24 +219,49 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } - msgtry := connection.MsgOpenTry{ - ConnectionID: conn2id, + msgTry := connection.MsgOpenTry{ + ConnectionID: connId2, Connection: conn2, CounterpartyClient: conn1.Client, 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 + } + + // 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 + } + + msgUpdate = client.MsgUpdateClient{ + ClientID: conn1.Client, + Header: header, + Signer: ctx1.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgUpdate}) if err != nil { return err } + q2 = storestate.NewCLIQuerier(ctx2.WithHeight(header.Height - 1)) + _, pconn, err = obj2.ConnectionCLI(q2) if err != nil { return err } - _, pstate, err = obj2.StateCLI(q2) + _, pstate, err = obj2.StageCLI(q2) if err != nil { return err } @@ -154,29 +270,55 @@ func GetCmdConnectionHandshake(storeKey string, cdc *codec.Codec) *cobra.Command return err } - msgack := connection.MsgOpenAck{ - ConnectionID: conn1id, + 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 } - _, pstate, err = obj1.StateCLI(q1) + // 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 } - msgconfirm := connection.MsgOpenConfirm{ - ConnectionID: conn2id, + msgUpdate = client.MsgUpdateClient{ + ClientID: conn2.Client, + Header: header, + Signer: ctx2.GetFromAddress(), + } + + err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) + if err != nil { + return err + } + + q1 = storestate.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) + + _, pstate, err = obj1.StageCLI(q1) + if err != nil { + return err + } + + 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 } @@ -185,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 b9f53de71602..f516c0a5d6df 100644 --- a/x/ibc/03-connection/handler.go +++ b/x/ibc/03-connection/handler.go @@ -7,31 +7,35 @@ import ( func HandleMsgOpenInit(ctx sdk.Context, msg MsgOpenInit, man Handshaker) sdk.Result { _, 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) + _, 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) + _, 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) + _, 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 e4d25965b3ca..1abc0d03f434 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/handshake.go @@ -9,10 +9,10 @@ import ( 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 @@ -23,17 +23,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}, + man: man, + counterParty: CounterpartyHandshaker{man.counterparty}, } } @@ -41,98 +37,102 @@ type CounterpartyHandshaker struct { man CounterpartyManager } -type HandshakeObject struct { - Object +type HandshakeState struct { + State - State state.Enum + Stage state.Enum CounterpartyClient state.String - Counterparty CounterHandshakeObject + Counterparty CounterHandshakeState } -type CounterHandshakeObject struct { - CounterObject +type CounterHandshakeState struct { + CounterState - State commitment.Enum + Stage commitment.Enum CounterpartyClient commitment.String } // 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(), - // 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(), } } -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 HandshakeState) remove(ctx sdk.Context) { + obj.State.remove(ctx) + obj.Stage.Delete(ctx) + obj.CounterpartyClient.Delete(ctx) +} + // Using proofs: none func (man Handshaker) OpenInit(ctx sdk.Context, id string, connection Connection, counterpartyClient string, -) (HandshakeObject, error) { +) (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.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, + proofs []commitment.Proof, height uint64, id string, connection Connection, counterpartyClient string, -) (obj HandshakeObject, err error) { +) (obj HandshakeState, err error) { obj, err = man.create(ctx, id, connection, counterpartyClient) if err != nil { return } - ctx, err = obj.Context(ctx, connection.Path, proofs) + 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 } @@ -141,12 +141,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") + err = errors.New("counterParty client not match") return } @@ -156,8 +156,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") } */ @@ -166,27 +166,27 @@ func (man Handshaker) OpenTry(ctx sdk.Context, // assert(get("connections/{desiredIdentifier}") === null) and // set("connections{identifier}", connection) - obj.State.Set(ctx, OpenTry) + obj.Stage.Set(ctx, OpenTry) return } -// Using proofs: counterparty.{connection, state, counterpartyClient, client} +// Using proofs: counterParty.{connection, state, timeout, counterpartyClient, client} func (man Handshaker) OpenAck(ctx sdk.Context, - proofs []commitment.Proof, - id string, /*expheight 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 } @@ -196,17 +196,17 @@ func (man Handshaker) OpenAck(ctx sdk.Context, 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") + err = errors.New("counterParty client not match") return } @@ -214,8 +214,8 @@ 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) @@ -223,28 +223,28 @@ func (man Handshaker) OpenAck(ctx sdk.Context, 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) (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 } - if !obj.Counterparty.State.Is(ctx, Open) { - err = errors.New("counterparty state not open") + if !obj.Counterparty.Stage.Is(ctx, Open) { + err = errors.New("counterParty state not open") return } diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/manager.go index f4e4d6432c29..d8d5fdb41bbf 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/manager.go @@ -7,27 +7,24 @@ 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" ) type Manager struct { - protocol state.Mapping - - client client.Manager - + protocol state.Mapping + client client.Manager counterparty CounterpartyManager - - path merkle.Path + path merkle.Prefix } 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()), + path: merkle.NewPrefix([][]byte{[]byte(protocol.StoreName())}, protocol.PrefixBytes()), } } @@ -47,7 +44,7 @@ func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { } } -type Object struct { +type State struct { id string protocol state.Mapping @@ -56,61 +53,53 @@ type Object struct { Kind state.String - Client client.Object + Client client.State - path merkle.Path + path merkle.Prefix } -func (man Manager) Object(id string) Object { - return Object{ - id: id, - +// CONTRACT: client must be filled by the caller +func (man Manager) State(id string) State { + return State{ + id: id, protocol: man.protocol.Prefix([]byte(id + "/")), Connection: man.protocol.Value([]byte(id)), Available: man.protocol.Value([]byte(id + "/available")).Boolean(), - - Kind: man.protocol.Value([]byte(id + "/kind")).String(), - - // CONTRACT: client must be filled by the caller - - path: man.path, + Kind: man.protocol.Value([]byte(id + "/kind")).String(), + path: man.path, } } -type CounterObject struct { - id string - +type CounterState struct { + id string protocol commitment.Mapping Connection commitment.Value Available commitment.Boolean - - Kind commitment.String - - Client client.CounterObject // nolint: unused + Kind commitment.String + Client client.CounterState // nolint: unused } -func (man CounterpartyManager) Object(id string) CounterObject { - return CounterObject{ +// CreateState creates a new CounterState instance. +// CONTRACT: client should be filled by the caller +func (man CounterpartyManager) CreateState(id string) CounterState { + return CounterState{ id: id, protocol: man.protocol.Prefix([]byte(id + "/")), Connection: man.protocol.Value([]byte(id)), Available: man.protocol.Value([]byte(id + "/available")).Boolean(), - - Kind: man.protocol.Value([]byte(id + "/kind")).String(), - - // CONTRACT: client should be filled by the caller + Kind: man.protocol.Value([]byte(id + "/kind")).String(), } } -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 (state State) Context(ctx sdk.Context, height uint64, proofs []commitment.Proof) (sdk.Context, error) { + root, err := state.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, + state.GetConnection(ctx).Path, proofs, ) if err != nil { @@ -120,83 +109,87 @@ func (obj Object) Context(ctx sdk.Context, optpath commitment.Path, proofs []com return commitment.WithStore(ctx, store), nil } -func (obj Object) ID() string { - return obj.id +func (state State) ID() string { + return state.id } -func (obj Object) GetConnection(ctx sdk.Context) (res Connection) { - obj.Connection.Get(ctx, &res) +func (state State) GetConnection(ctx sdk.Context) (res Connection) { + state.Connection.Get(ctx, &res) return } -func (obj Object) Sendable(ctx sdk.Context) bool { - return kinds[obj.Kind.Get(ctx)].Sendable +func (state State) Sendable(ctx sdk.Context) bool { + return kinds[state.Kind.Get(ctx)].Sendable } -func (obj Object) Receivable(ctx sdk.Context) bool { - return kinds[obj.Kind.Get(ctx)].Receivable +func (state State) Receivable(ctx sdk.Context) bool { + return kinds[state.Kind.Get(ctx)].Receivable } -func (obj Object) remove(ctx sdk.Context) { - obj.Connection.Delete(ctx) - obj.Available.Delete(ctx) - obj.Kind.Delete(ctx) +func (state State) remove(ctx sdk.Context) { + state.Connection.Delete(ctx) + state.Available.Delete(ctx) + state.Kind.Delete(ctx) } -func (obj Object) exists(ctx sdk.Context) bool { - return obj.Connection.Exists(ctx) +func (state State) exists(ctx sdk.Context) bool { + return state.Connection.Exists(ctx) } 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) - if obj.exists(ctx) { - err = errors.New("Object already exists") +func (man Manager) create(ctx sdk.Context, id string, connection Connection, kind string) (state State, err error) { + state = man.State(id) + if state.exists(ctx) { + err = errors.New("Stage already exists") return } - obj.Client, err = man.client.Query(ctx, connection.Client) + state.Client, err = man.client.Query(ctx, connection.Client) if err != nil { return } - obj.Connection.Set(ctx, connection) - obj.Kind.Set(ctx, kind) + state.Connection.Set(ctx, connection) + state.Kind.Set(ctx, kind) return } // 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) - if !obj.exists(ctx) { - err = errors.New("Object not exists") +func (man Manager) query(ctx sdk.Context, id string, kind string) (state State, err error) { + state = man.State(id) + if !state.exists(ctx) { + err = errors.New("Stage not exists") return } - obj.Client, err = man.client.Query(ctx, obj.GetConnection(ctx).Client) + + state.Client, err = man.client.Query(ctx, state.GetConnection(ctx).Client) if err != nil { return } - if obj.Kind.Get(ctx) != kind { + + if state.Kind.Get(ctx) != kind { err = errors.New("kind mismatch") return } + return } -func (man Manager) Query(ctx sdk.Context, id string) (obj Object, err error) { - obj = man.Object(id) - if !obj.exists(ctx) { - err = errors.New("Object not exists") +func (man Manager) Query(ctx sdk.Context, id string) (state State, err error) { + state = man.State(id) + if !state.exists(ctx) { + err = errors.New("Stage not exists") return - } - if !obj.Available.Get(ctx) { - err = errors.New("Object not available") + + if !state.Available.Get(ctx) { + err = errors.New("Stage not available") return } - obj.Client, err = man.client.Query(ctx, obj.GetConnection(ctx).Client) + + state.Client, err = man.client.Query(ctx, state.GetConnection(ctx).Client) return } diff --git a/x/ibc/03-connection/msgs.go b/x/ibc/03-connection/msgs.go index f528bd145f5d..5848558554b0 100644 --- a/x/ibc/03-connection/msgs.go +++ b/x/ibc/03-connection/msgs.go @@ -8,10 +8,11 @@ import ( const Route = "ibc" type MsgOpenInit struct { - ConnectionID string - Connection Connection - CounterpartyClient string - 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{} @@ -29,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 { @@ -37,11 +38,14 @@ func (msg MsgOpenInit) GetSigners() []sdk.AccAddress { } type MsgOpenTry struct { - ConnectionID string - Connection Connection - CounterpartyClient string - 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{} @@ -59,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 { @@ -67,9 +71,12 @@ func (msg MsgOpenTry) GetSigners() []sdk.AccAddress { } type MsgOpenAck struct { - ConnectionID string - 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{} @@ -87,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 { @@ -95,9 +102,11 @@ func (msg MsgOpenAck) GetSigners() []sdk.AccAddress { } type MsgOpenConfirm struct { - ConnectionID string - 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 54321c28ac9e..e17508ef1266 100644 --- a/x/ibc/03-connection/tests/types.go +++ b/x/ibc/03-connection/tests/types.go @@ -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, @@ -47,12 +47,12 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { res.Connection = connection.Connection{ Counterparty: res.Counterparty.Name, - Path: res.Counterparty.Path(), + Path: res.Counterparty.Prefix(), } res.Counterparty.Connection = connection.Connection{ Counterparty: res.Name, - Path: res.Path(), + Path: res.Prefix(), } return res @@ -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,13 +92,13 @@ 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 { - protocol := state.NewMapping(node.Key, node.Cdc, node.Prefix) + protocol := state.NewMapping(node.Key, node.Cdc, node.KeyPrefix) return protocol } @@ -112,39 +112,39 @@ 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) 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) + 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) + 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) + 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.Open) @@ -163,27 +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) + _, 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, 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) + _, pstate = node.Counterparty.QueryValue(t, cliobj.Stage) _, pcounterclient = node.Counterparty.QueryValue(t, cliobj.CounterpartyClient) - node.OpenAck(t, pconn, pstate, 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) - node.Counterparty.OpenConfirm(t, pstate) + 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..199bee022ade 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.Prefix `json:"path"` } /* diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 1ced699258fd..ae7fde1a21a2 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -35,8 +35,8 @@ func NewPrefix(store Store, pref []byte) Store { } // Prove implements Store. -func (prefix prefix) Prove(path, value []byte) bool { - return prefix.store.Prove(join(prefix.prefix, path), value) +func (prefix prefix) Prove(key, value []byte) bool { + return prefix.store.Prove(join(prefix.prefix, key), value) } var _ Store = (*store)(nil) diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go index 9a2f4380f8b0..5797e1cd13c9 100644 --- a/x/ibc/23-commitment/value.go +++ b/x/ibc/23-commitment/value.go @@ -1,7 +1,6 @@ package commitment import ( - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" From 7428e5bd5a07a666aebba17975c2ba55afd62a92 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Oct 2019 17:51:27 +0200 Subject: [PATCH 251/378] update test --- x/ibc/04-channel/tests/types.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/tests/types.go index 32221079fb3d..add562813d5e 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/tests/types.go @@ -20,10 +20,8 @@ const PortName = "port-test" type Node struct { *connection.Node Counterparty *Node - - Channel channel.Channel - - Cdc *codec.Codec + Channel channel.Channel + Cdc *codec.Codec } func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { @@ -55,7 +53,7 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Context, channel.Handshaker) { ctx := node.Context() - store, err := commitment.NewStore(node.Counterparty.Root(), node.Counterparty.Path(), proofs) + store, err := commitment.NewStore(node.Counterparty.Root(), node.Counterparty.Prefix(), proofs) require.NoError(t, err) ctx = commitment.WithStore(ctx, store) man := node.Manager() From cc404a03f769205d36f4b9855d3f43dc39a4a874 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 2 Oct 2019 12:37:17 +0200 Subject: [PATCH 252/378] cleanup types and submodule --- x/ibc/02-client/cli.go | 33 --- x/ibc/02-client/client/cli/query.go | 12 +- x/ibc/02-client/client/cli/tx.go | 44 ++-- x/ibc/02-client/codec.go | 19 -- x/ibc/02-client/{README.md => doc.go} | 29 ++- x/ibc/02-client/exported/exported.go | 53 +++++ x/ibc/02-client/handler.go | 33 ++- x/ibc/02-client/manager.go | 164 --------------- x/ibc/02-client/tendermint/codec.go | 10 - x/ibc/02-client/tendermint/types.go | 95 --------- x/ibc/02-client/types.go | 47 ----- x/ibc/02-client/types/codec.go | 23 +++ x/ibc/02-client/{ => types}/keys.go | 3 +- x/ibc/02-client/types/manager.go | 192 ++++++++++++++++++ x/ibc/02-client/{ => types}/msgs.go | 42 ++-- .../02-client/types/tendermint/tendermint.go | 101 +++++++++ .../tendermint/tests/tendermint_test.go | 0 .../{ => types}/tendermint/tests/types.go | 6 +- .../{ => types}/tendermint/tests/utils.go | 0 .../{ => types}/tendermint/tests/valset.go | 0 x/ibc/types/types.go | 15 ++ 21 files changed, 493 insertions(+), 428 deletions(-) delete mode 100644 x/ibc/02-client/cli.go delete mode 100644 x/ibc/02-client/codec.go rename x/ibc/02-client/{README.md => doc.go} (64%) create mode 100644 x/ibc/02-client/exported/exported.go delete mode 100644 x/ibc/02-client/manager.go delete mode 100644 x/ibc/02-client/tendermint/codec.go delete mode 100644 x/ibc/02-client/tendermint/types.go delete mode 100644 x/ibc/02-client/types.go create mode 100644 x/ibc/02-client/types/codec.go rename x/ibc/02-client/{ => types}/keys.go (57%) create mode 100644 x/ibc/02-client/types/manager.go rename x/ibc/02-client/{ => types}/msgs.go (55%) create mode 100644 x/ibc/02-client/types/tendermint/tendermint.go rename x/ibc/02-client/{ => types}/tendermint/tests/tendermint_test.go (100%) rename x/ibc/02-client/{ => types}/tendermint/tests/types.go (97%) rename x/ibc/02-client/{ => types}/tendermint/tests/utils.go (100%) rename x/ibc/02-client/{ => types}/tendermint/tests/valset.go (100%) create mode 100644 x/ibc/types/types.go diff --git a/x/ibc/02-client/cli.go b/x/ibc/02-client/cli.go deleted file mode 100644 index 0895bbcc2c38..000000000000 --- a/x/ibc/02-client/cli.go +++ /dev/null @@ -1,33 +0,0 @@ -package client - -import ( - "bytes" - - "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 State) prefix() []byte { - return bytes.Split(obj.ConsensusState.KeyBytes(), LocalRoot())[0] -} - -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 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 ca3382814356..73baefcfcd5a 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -14,8 +14,8 @@ import ( "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" - 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/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" "github.com/cosmos/cosmos-sdk/x/ibc/version" ) @@ -52,10 +52,10 @@ func GetCmdQueryClient(storeKey string, cdc *codec.Codec) *cobra.Command { ctx := context.NewCLIContext().WithCodec(cdc) q := state.NewCLIQuerier(ctx) mapp := mapping(cdc, storeKey, version.Version) - man := client.NewManager(mapp) + manager := types.NewManager(mapp) id := args[0] - state, _, err := man.State(id).ConsensusStateCLI(q) + state, _, err := manager.State(id).ConsensusStateCLI(q) if err != nil { return err } @@ -76,14 +76,14 @@ func GetCmdQueryRoot(storeKey string, cdc *codec.Codec) *cobra.Command { ctx := context.NewCLIContext().WithCodec(cdc) q := state.NewCLIQuerier(ctx) mapp := mapping(cdc, storeKey, version.Version) - man := client.NewManager(mapp) + manager := types.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) + root, _, err := manager.State(id).RootCLI(q, height) if err != nil { return err } diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index d79bbbcf70e2..34e7c79683cc 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -2,24 +2,21 @@ package cli import ( "io/ioutil" - // "os" + "strings" "github.com/spf13/cobra" - // "github.com/tendermint/tendermint/libs/log" - 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/x/auth/client/utils" - // "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/ibc/02-client" - // "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" ) +// ICS02 Client CLI flags const ( FlagStatePath = "state" FlagClientID = "client-id" @@ -30,6 +27,7 @@ const ( FlagSourceNode = "source-node" ) +// GetTxCmd returns the transaction commands for IBC Clients func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ibcTxCmd := &cobra.Command{ Use: "client", @@ -46,27 +44,32 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { return ibcTxCmd } +// GetCmdCreateClient defines the command to create a new IBC Client as defined +// in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "create", Short: "create new client with a consensus state", - Args: cobra.ExactArgs(2), + Long: strings.TrimSpace(`create new client with a specified identifier and consensus state: + + $ tx ibc client create $CLIENTID ./state.json --from node0 --home ../node0/cli --chain-id $CID + `), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContext(). - WithCodec(cdc) + cliCtx := context.NewCLIContext().WithCodec(cdc) contents, err := ioutil.ReadFile(args[1]) if err != nil { return err } - var state client.ConsensusState + var state exported.ConsensusState if err := cdc.UnmarshalJSON(contents, &state); err != nil { return err } - msg := client.MsgCreateClient{ + msg := types.MsgCreateClient{ ClientID: args[0], ConsensusState: state, Signer: cliCtx.GetFromAddress(), @@ -75,10 +78,11 @@ func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command { return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } - return cmd } +// GetCmdUpdateClient defines the command to update a client as defined in +// https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#update func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "update", @@ -86,20 +90,23 @@ func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContext(). - WithCodec(cdc) + cliCtx := context.NewCLIContext().WithCodec(cdc) contents, err := ioutil.ReadFile(args[1]) if err != nil { return err } - var header client.Header + var header exported.Header if err := cdc.UnmarshalJSON(contents, &header); err != nil { return err } - msg := client.MsgUpdateClient{ + if err := header.ValidateBasic(txBldr.ChainID()); err != nil { + return sdk.ErrInternal(err.Error()) // TODO: create error on types + } + + msg := types.MsgUpdateClient{ ClientID: args[0], Header: header, Signer: cliCtx.GetFromAddress(), @@ -108,6 +115,5 @@ func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } - return cmd } diff --git a/x/ibc/02-client/codec.go b/x/ibc/02-client/codec.go deleted file mode 100644 index 18dd6da686e8..000000000000 --- a/x/ibc/02-client/codec.go +++ /dev/null @@ -1,19 +0,0 @@ -package client - -import ( - "github.com/cosmos/cosmos-sdk/codec" -) - -var MsgCdc *codec.Codec - -func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterInterface((*ConsensusState)(nil), nil) - cdc.RegisterInterface((*Header)(nil), nil) - - 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/README.md b/x/ibc/02-client/doc.go similarity index 64% rename from x/ibc/02-client/README.md rename to x/ibc/02-client/doc.go index f8b3fc98d086..40c1e138d3d9 100644 --- a/x/ibc/02-client/README.md +++ b/x/ibc/02-client/doc.go @@ -1,10 +1,13 @@ -# ICS 02: Client +/* +Package ics02 implements the ICS 02 - Client Semenatics specification +https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics. This +concrete implementations defines types and method to store and update light +clients which tracks on other chain's state. -Package `client` defines types and method to store and update light clients which tracks on other chain's state. -The main type is `Client`, which provides `commitment.Root` to verify state proofs and `ConsensusState` to +The main type is `Client`, which provides `commitment.Root` to verify state proofs and `ConsensusState` to verify header proofs. -## Spec +Specification ```typescript interface ConsensusState { @@ -32,18 +35,22 @@ type ValidityPredicate = (ConsensusState, Header) => Error | ConsensusState type EquivocationPredicate = (ConsensusState, Header, Header) => bool ``` -## Impl +Implementation -### types.go +1. Types `spec: interface ConsensusState` is implemented by `type ConsensusState`. `ConsensusState.{GetHeight(), GetRoot(), -Validate(), Equivocation()}` each corresponds to `spec: ConsensusState.{height, root, validityPredicate, -equivocationPredicate}`. `ConsensusState.Kind()` returns `Kind`, which is an enum indicating the type of the +Validate(), Equivocation()}` each corresponds to `spec: ConsensusState.{height, root, validityPredicate, +equivocationPredicate}`. `ConsensusState.Kind()` returns `Kind`, which is an enum indicating the type of the consensus algorithm. -`spec: interface Header` is implemented by `type Header`. `Header{GetHeight(), Proof(), State(), GetRoot()}` +`spec: interface Header` is implemented by `type Header`. `Header{GetHeight(), Proof(), State(), GetRoot()}` each corresponds to `spec: Header.{height, proof, state, root}`. -### manager.go +2. Manager -`spec: interface ClientState` is implemented by `type State`. // TODO +`spec: interface ClientState` is implemented by `type State`. + + +*/ +package ics02 diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go new file mode 100644 index 000000000000..6ddab9625be8 --- /dev/null +++ b/x/ibc/02-client/exported/exported.go @@ -0,0 +1,53 @@ +package exported + +import ( + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +// Blockchain is consensus algorithm which generates valid Headers. It generates +// a unique list of headers starting from a genesis ConsensusState with arbitrary messages. +// This interface is implemented as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#blockchain. +type Blockchain interface { + Genesis() ConsensusState // Consensus state defined in the genesis + Consensus() Header // Header generating funciton +} + +// ConsensusState is the state of the consensus process +type ConsensusState interface { + Kind() Kind // Consensus kind + GetHeight() uint64 + + // GetRoot returns the commitment root of the consensus state, + // which is used for key-value pair verification. + GetRoot() ics23.Root + + // CheckValidityAndUpdateState returns the updated consensus state + // only if the header is a descendent of this consensus state. + CheckValidityAndUpdateState(Header) (ConsensusState, error) + + // CheckMisbehaviourAndUpdateState checks any misbehaviour evidence + // depending on the state type. + CheckMisbehaviourAndUpdateState(Misbehaviour) bool +} + +// Misbehaviour defines the evidence +type Misbehaviour interface { + Kind() Kind + // TODO: embed Evidence interface + // evidence.Evidence +} + +// Header is the consensus state update information +type Header interface { + Kind() Kind + GetHeight() uint64 + ValidateBasic(chainID string) error // NOTE: added for msg validation +} + +// Kind defines the type of the consensus algorithm +type Kind byte + +// Registered consensus types +const ( + Tendermint Kind = iota +) diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go index dfab0725b8c4..3ed9a8bde551 100644 --- a/x/ibc/02-client/handler.go +++ b/x/ibc/02-client/handler.go @@ -1,11 +1,34 @@ -package client +package ics02 import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" ) -func HandleMsgCreateClient(ctx sdk.Context, msg MsgCreateClient, man Manager) sdk.Result { - _, err := man.Create(ctx, msg.ClientID, msg.ConsensusState) +// NewHandler creates a new Handler instance for IBC client +// transactions +func NewHandler(manager types.Manager) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + switch msg := msg.(type) { + case types.MsgCreateClient: + return handleMsgCreateClient(ctx, manager, msg) + + case types.MsgUpdateClient: + return handleMsgUpdateClient(ctx, manager, msg) + + default: + errMsg := fmt.Sprintf("unrecognized IBC Client message type: %T", msg) + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +func handleMsgCreateClient(ctx sdk.Context, manager types.Manager, msg types.MsgCreateClient) sdk.Result { + _, err := manager.Create(ctx, msg.ClientID, msg.ConsensusState) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(100), err.Error()).Result() } @@ -14,8 +37,8 @@ func HandleMsgCreateClient(ctx sdk.Context, msg MsgCreateClient, man Manager) sd return sdk.Result{} } -func HandleMsgUpdateClient(ctx sdk.Context, msg MsgUpdateClient, man Manager) sdk.Result { - obj, err := man.Query(ctx, msg.ClientID) +func handleMsgUpdateClient(ctx sdk.Context, manager types.Manager, msg types.MsgUpdateClient) sdk.Result { + obj, err := manager.Query(ctx, msg.ClientID) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(200), err.Error()).Result() } diff --git a/x/ibc/02-client/manager.go b/x/ibc/02-client/manager.go deleted file mode 100644 index 8fc389420558..000000000000 --- a/x/ibc/02-client/manager.go +++ /dev/null @@ -1,164 +0,0 @@ -package client - -import ( - "errors" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/state" - sdk "github.com/cosmos/cosmos-sdk/types" - - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -// Any actor holding the Manager can access on and modify any client information -type Manager struct { - protocol state.Mapping -} - -func NewManager(base state.Mapping) Manager { - return Manager{ - protocol: base.Prefix(LocalRoot()), - } -} - -type CounterpartyManager struct { - protocol commitment.Mapping -} - -func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { - return CounterpartyManager{ - protocol: commitment.NewMapping(cdc, LocalRoot()), - } -} - -/* -func (man Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { - if _, ok := man.pred[kind]; ok { - panic("Kind already registered") - } - man.pred[kind] = pred - return man -} -*/ -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) (State, error) { - obj := man.State(id) - if obj.exists(ctx) { - 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) (State, error) { - res := man.State(id) - if !res.exists(ctx) { - return State{}, errors.New("client not exists") - } - return res, nil -} - -func (man CounterpartyManager) State(id string) CounterState { - return CounterState{ - id: id, - ConsensusState: man.protocol.Value([]byte(id)), - } -} - -func (man CounterpartyManager) Query(id string) CounterState { - return man.State(id) -} - -// 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 CounterState struct { - id string - ConsensusState commitment.Value -} - -func (obj State) ID() string { - return obj.id -} - -func (obj State) GetConsensusState(ctx sdk.Context) (res ConsensusState) { - obj.ConsensusState.Get(ctx, &res) - return -} - -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 State) exists(ctx sdk.Context) bool { - return obj.ConsensusState.Exists(ctx) -} - -func (obj State) Update(ctx sdk.Context, header Header) error { - if !obj.exists(ctx) { - panic("should not update nonexisting client") - } - - if obj.Frozen.Get(ctx) { - return errors.New("client is Frozen") - } - - stored := obj.GetConsensusState(ctx) - updated, err := stored.CheckValidityAndUpdateState(header) - if err != nil { - return err - } - - obj.ConsensusState.Set(ctx, updated) - obj.Roots.Set(ctx, updated.GetHeight(), updated.GetRoot()) - - return nil -} - -func (obj State) Freeze(ctx sdk.Context) error { - if !obj.exists(ctx) { - panic("should not freeze nonexisting client") - } - - if obj.Frozen.Get(ctx) { - return errors.New("client is already Frozen") - } - - obj.Frozen.Set(ctx, true) - - return nil -} - -func (obj State) Delete(ctx sdk.Context) error { - if !obj.exists(ctx) { - panic("should not delete nonexisting client") - } - - if !obj.Frozen.Get(ctx) { - return errors.New("client is not Frozen") - } - - obj.ConsensusState.Delete(ctx) - obj.Frozen.Delete(ctx) - - return nil -} diff --git a/x/ibc/02-client/tendermint/codec.go b/x/ibc/02-client/tendermint/codec.go deleted file mode 100644 index 1c149c0a3fe3..000000000000 --- a/x/ibc/02-client/tendermint/codec.go +++ /dev/null @@ -1,10 +0,0 @@ -package tendermint - -import ( - "github.com/cosmos/cosmos-sdk/codec" -) - -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/tendermint/types.go b/x/ibc/02-client/tendermint/types.go deleted file mode 100644 index 8d2f23509175..000000000000 --- a/x/ibc/02-client/tendermint/types.go +++ /dev/null @@ -1,95 +0,0 @@ -package tendermint - -import ( - "bytes" - "errors" - - lerr "github.com/tendermint/tendermint/lite/errors" - "github.com/tendermint/tendermint/types" - - 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" -) - -var _ client.ConsensusState = ConsensusState{} - -// Ref tendermint/lite/base_verifier.go -type ConsensusState struct { - ChainID string - Height uint64 - Root commitment.Root - NextValidatorSet *types.ValidatorSet -} - -func (ConsensusState) Kind() client.Kind { - return client.Tendermint -} - -func (cs ConsensusState) GetHeight() uint64 { - return cs.Height -} - -func (cs ConsensusState) GetRoot() commitment.Root { - return cs.Root -} - -func (cs ConsensusState) update(header Header) ConsensusState { - return ConsensusState{ - ChainID: cs.ChainID, - Height: uint64(header.Height), - Root: merkle.NewRoot(header.AppHash), - NextValidatorSet: header.NextValidatorSet, - } -} - -func (cs ConsensusState) CheckValidityAndUpdateState(cheader client.Header) (client.ConsensusState, error) { - header, ok := cheader.(Header) - if !ok { - return nil, errors.New("invalid type") - } - - if cs.Height == uint64(header.Height-1) { - nexthash := cs.NextValidatorSet.Hash() - if !bytes.Equal(header.ValidatorsHash, nexthash) { - return nil, lerr.ErrUnexpectedValidators(header.ValidatorsHash, nexthash) - } - } - - if !bytes.Equal(header.NextValidatorsHash, header.NextValidatorSet.Hash()) { - return nil, lerr.ErrUnexpectedValidators(header.NextValidatorsHash, header.NextValidatorSet.Hash()) - } - - err := header.ValidateBasic(cs.ChainID) - if err != nil { - return nil, err - } - - err = cs.NextValidatorSet.VerifyFutureCommit(header.ValidatorSet, cs.ChainID, header.Commit.BlockID, header.Height, header.Commit) - if err != nil { - return nil, err - } - - return cs.update(header), nil -} - -func (cs ConsensusState) CheckMisbehaviourAndUpdateState(mb client.Misbehaviour) bool { - return false // TODO: implement -} - -var _ client.Header = Header{} - -type Header struct { - // TODO: define Tendermint header type manually, don't use tmtypes - types.SignedHeader - ValidatorSet *types.ValidatorSet - NextValidatorSet *types.ValidatorSet -} - -func (header Header) Kind() client.Kind { - return client.Tendermint -} - -func (header Header) GetHeight() uint64 { - return uint64(header.Height) -} diff --git a/x/ibc/02-client/types.go b/x/ibc/02-client/types.go deleted file mode 100644 index fa18c5095b9b..000000000000 --- a/x/ibc/02-client/types.go +++ /dev/null @@ -1,47 +0,0 @@ -package client - -import ( - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -// TODO: types in this file should be (de/)serialized with proto in the future -// currently amino codec handles it - -// ConsensusState is the state of the consensus process. -type ConsensusState interface { - // Kind() is the kind of the consensus algorithm. - Kind() Kind - GetHeight() uint64 - - // GetRoot() returns the commitment root of the consensus state, - // which is used for key-value pair verification. - GetRoot() commitment.Root - - // CheckValidityAndUpdateState() returns the updated consensus state - // only if the header is a descendent of this consensus state. - CheckValidityAndUpdateState(Header) (ConsensusState, error) - - // CheckMisbehaviourAndUpdateState() checks any misbehaviour evidence - // depending on the state type. - CheckMisbehaviourAndUpdateState(Misbehaviour) bool -} - -type Misbehaviour interface { - Kind() Kind - // TODO: embed Evidence interface - // evidence.Evidence -} - -// Header is the consensus state update information. -type Header interface { - // Kind() is the kind of the consensus algorithm. - Kind() Kind - - GetHeight() uint64 -} - -type Kind byte - -const ( - Tendermint Kind = iota -) diff --git a/x/ibc/02-client/types/codec.go b/x/ibc/02-client/types/codec.go new file mode 100644 index 000000000000..c556850a0ca2 --- /dev/null +++ b/x/ibc/02-client/types/codec.go @@ -0,0 +1,23 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" +) + +var SubModuleCdc *codec.Codec + +// RegisterCodec registers the IBC client interfaces and types +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*exported.Blockchain)(nil), nil) + cdc.RegisterInterface((*exported.ConsensusState)(nil), nil) + cdc.RegisterInterface((*exported.Header)(nil), nil) + cdc.RegisterInterface((*exported.Misbehaviour)(nil), nil) + + cdc.RegisterConcrete(MsgCreateClient{}, "ibc/client/MsgCreateClient", nil) + cdc.RegisterConcrete(MsgUpdateClient{}, "ibc/client/MsgUpdateClient", nil) + + cdc.RegisterConcrete(tendermint.ConsensusState{}, "ibc/client/tendermint/ConsensusState", nil) + cdc.RegisterConcrete(tendermint.Header{}, "ibc/client/tendermint/Header", nil) +} diff --git a/x/ibc/02-client/keys.go b/x/ibc/02-client/types/keys.go similarity index 57% rename from x/ibc/02-client/keys.go rename to x/ibc/02-client/types/keys.go index a67761f20d36..c3d97c364a16 100644 --- a/x/ibc/02-client/keys.go +++ b/x/ibc/02-client/types/keys.go @@ -1,5 +1,6 @@ -package client +package types +// IDK what is this for... func LocalRoot() []byte { return []byte("client/") } diff --git a/x/ibc/02-client/types/manager.go b/x/ibc/02-client/types/manager.go new file mode 100644 index 000000000000..7aae2fe6827d --- /dev/null +++ b/x/ibc/02-client/types/manager.go @@ -0,0 +1,192 @@ +package types + +import ( + "bytes" + "errors" + + "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/ibc/02-client/exported" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +// Any actor holding the Manager can access on and modify any client information +type Manager struct { + protocol state.Mapping +} + +// NewManager creates a new Manager instance +func NewManager(base state.Mapping) Manager { + return Manager{ + protocol: base.Prefix(LocalRoot()), + } +} + +type CounterpartyManager struct { + protocol ics23.Mapping +} + +// NewCounterpartyManager creates a new CounterpartyManager instance +func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { + return CounterpartyManager{ + protocol: ics23.NewMapping(cdc, LocalRoot()), + } +} + +/* +func (m Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { + if _, ok := m.pred[kind]; ok { + panic("Kind already registered") + } + m.pred[kind] = pred + return m +} +*/ + +func (m Manager) State(id string) State { + return State{ + id: id, + Roots: m.protocol.Prefix([]byte(id + "/roots/")).Indexer(state.Dec), + ConsensusState: m.protocol.Value([]byte(id)), + Frozen: m.protocol.Value([]byte(id + "/freeze")).Boolean(), + } +} + +func (m Manager) Create(ctx sdk.Context, id string, cs exported.ConsensusState) (State, error) { + state := m.State(id) + if state.exists(ctx) { + return State{}, errors.New("cannot create client on an existing id") + } + state.Roots.Set(ctx, cs.GetHeight(), cs.GetRoot()) + state.ConsensusState.Set(ctx, cs) + return state, nil +} + +func (m Manager) Query(ctx sdk.Context, id string) (State, error) { + res := m.State(id) + if !res.exists(ctx) { + return State{}, errors.New("client doesn't exist") + } + return res, nil +} + +func (m CounterpartyManager) State(id string) CounterState { + return CounterState{ + id: id, + ConsensusState: m.protocol.Value([]byte(id)), + } +} + +func (m CounterpartyManager) Query(id string) CounterState { + return m.State(id) +} + +// 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 CounterState struct { + id string + ConsensusState ics23.Value +} + +func (state State) ID() string { + return state.id +} + +func (state State) GetConsensusState(ctx sdk.Context) (res exported.ConsensusState) { + state.ConsensusState.Get(ctx, &res) + return +} + +func (state State) GetRoot(ctx sdk.Context, height uint64) (res ics23.Root, err error) { + err = state.Roots.GetSafe(ctx, height, &res) + return +} + +func (state CounterState) Is(ctx sdk.Context, client exported.ConsensusState) bool { + return state.ConsensusState.Is(ctx, client) +} + +func (state State) exists(ctx sdk.Context) bool { + return state.ConsensusState.Exists(ctx) +} + +func (state State) Update(ctx sdk.Context, header exported.Header) error { + if !state.exists(ctx) { + panic("should not update nonexisting client") + } + + if state.Frozen.Get(ctx) { + return errors.New("client is Frozen") + } + + stored := state.GetConsensusState(ctx) + updated, err := stored.CheckValidityAndUpdateState(header) + if err != nil { + return err + } + + state.ConsensusState.Set(ctx, updated) + state.Roots.Set(ctx, updated.GetHeight(), updated.GetRoot()) + + return nil +} + +func (state State) Freeze(ctx sdk.Context) error { + if !state.exists(ctx) { + panic("should not freeze nonexisting client") + } + + if state.Frozen.Get(ctx) { + return errors.New("client is already Frozen") + } + + state.Frozen.Set(ctx, true) + + return nil +} + +func (state State) Delete(ctx sdk.Context) error { + if !state.exists(ctx) { + panic("should not delete nonexisting client") + } + + if !state.Frozen.Get(ctx) { + return errors.New("client is not Frozen") + } + + state.ConsensusState.Delete(ctx) + state.Frozen.Delete(ctx) + + return nil +} + +func (state State) prefix() []byte { + return bytes.Split(state.ConsensusState.KeyBytes(), LocalRoot())[0] +} + +func (state State) RootCLI(q state.ABCIQuerier, height uint64) (res ics23.Root, proof merkle.Proof, err error) { + root := state.Roots.Value(height) + tmproof, err := root.Query(q, &res) + proof = merkle.NewProofFromValue(tmproof, state.prefix(), root) + return +} + +func (state State) ConsensusStateCLI(q state.ABCIQuerier) (res exported.ConsensusState, proof merkle.Proof, err error) { + tmproof, err := state.ConsensusState.Query(q, &res) + proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.ConsensusState) + return +} + +func (state State) FrozenCLI(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { + res, tmproof, err := state.Frozen.Query(q) + proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Frozen) + return +} diff --git a/x/ibc/02-client/msgs.go b/x/ibc/02-client/types/msgs.go similarity index 55% rename from x/ibc/02-client/msgs.go rename to x/ibc/02-client/types/msgs.go index 7f515c388c8f..ec9a7f122284 100644 --- a/x/ibc/02-client/msgs.go +++ b/x/ibc/02-client/types/msgs.go @@ -1,25 +1,31 @@ -package client +package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) +var _ sdk.Msg = MsgCreateClient{} + +// MsgCreateClient defines a message to create an IBC client type MsgCreateClient struct { ClientID string - ConsensusState ConsensusState + ConsensusState exported.ConsensusState Signer sdk.AccAddress } -var _ sdk.Msg = MsgCreateClient{} - +// Route implements sdk.Msg func (msg MsgCreateClient) Route() string { - return "ibc" + return ibctypes.RouterKey } +// Type implements sdk.Msg func (msg MsgCreateClient) Type() string { - return "create-client" + return "create_client" } +// ValidateBasic implements sdk.Msg func (msg MsgCreateClient) ValidateBasic() sdk.Error { if msg.Signer.Empty() { return sdk.ErrInvalidAddress("empty address") @@ -27,31 +33,36 @@ func (msg MsgCreateClient) ValidateBasic() sdk.Error { return nil } +// GetSignBytes implements sdk.Msg func (msg MsgCreateClient) GetSignBytes() []byte { - bz := MsgCdc.MustMarshalJSON(msg) - return sdk.MustSortJSON(bz) + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) } +// GetSigners implements sdk.Msg func (msg MsgCreateClient) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } +var _ sdk.Msg = MsgUpdateClient{} + +// MsgUpdateClient defines a message to update an IBC client type MsgUpdateClient struct { ClientID string - Header Header + Header exported.Header Signer sdk.AccAddress } -var _ sdk.Msg = MsgUpdateClient{} - +// Route implements sdk.Msg func (msg MsgUpdateClient) Route() string { - return "ibc" + return ibctypes.RouterKey } +// Type implements sdk.Msg func (msg MsgUpdateClient) Type() string { - return "update-client" + return "update_client" } +// ValidateBasic implements sdk.Msg func (msg MsgUpdateClient) ValidateBasic() sdk.Error { if msg.Signer.Empty() { return sdk.ErrInvalidAddress("empty address") @@ -59,11 +70,12 @@ func (msg MsgUpdateClient) ValidateBasic() sdk.Error { return nil } +// GetSignBytes implements sdk.Msg func (msg MsgUpdateClient) GetSignBytes() []byte { - bz := MsgCdc.MustMarshalJSON(msg) - return sdk.MustSortJSON(bz) + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) } +// GetSigners implements sdk.Msg func (msg MsgUpdateClient) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } diff --git a/x/ibc/02-client/types/tendermint/tendermint.go b/x/ibc/02-client/types/tendermint/tendermint.go new file mode 100644 index 000000000000..bff49e738f7b --- /dev/null +++ b/x/ibc/02-client/types/tendermint/tendermint.go @@ -0,0 +1,101 @@ +package tendermint + +import ( + "bytes" + "errors" + + lerr "github.com/tendermint/tendermint/lite/errors" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +var _ exported.ConsensusState = ConsensusState{} + +// ConsensusState defines a Tendermint consensus state +type ConsensusState struct { + ChainID string + Height uint64 + Root ics23.Root + NextValidatorSet *tmtypes.ValidatorSet +} + +func (ConsensusState) Kind() exported.Kind { + return exported.Tendermint +} + +func (cs ConsensusState) GetHeight() uint64 { + return cs.Height +} + +func (cs ConsensusState) GetRoot() ics23.Root { + return cs.Root +} + +func (cs ConsensusState) update(header Header) ConsensusState { + return ConsensusState{ + ChainID: cs.ChainID, + Height: uint64(header.Height), + Root: merkle.NewRoot(header.AppHash), + NextValidatorSet: header.NextValidatorSet, + } +} + +// CheckValidityAndUpdateState +func (cs ConsensusState) CheckValidityAndUpdateState(header exported.Header) (exported.ConsensusState, error) { + tmHeader, ok := header.(Header) + if !ok { + return nil, errors.New("header is not from a tendermint consensus") // TODO: create concrete error + } + + if cs.Height == uint64(tmHeader.Height-1) { + nexthash := cs.NextValidatorSet.Hash() + if !bytes.Equal(tmHeader.ValidatorsHash, nexthash) { + return nil, lerr.ErrUnexpectedValidators(tmHeader.ValidatorsHash, nexthash) + } + } + + if !bytes.Equal(tmHeader.NextValidatorsHash, tmHeader.NextValidatorSet.Hash()) { + return nil, lerr.ErrUnexpectedValidators(tmHeader.NextValidatorsHash, tmHeader.NextValidatorSet.Hash()) + } + + err := tmHeader.ValidateBasic(cs.ChainID) + if err != nil { + return nil, err + } + + err = cs.NextValidatorSet.VerifyFutureCommit(tmHeader.ValidatorSet, cs.ChainID, tmHeader.Commit.BlockID, tmHeader.Height, tmHeader.Commit) + if err != nil { + return nil, err + } + + return cs.update(tmHeader), nil +} + +// CheckMisbehaviourAndUpdateState - not implemented +func (cs ConsensusState) CheckMisbehaviourAndUpdateState(mb exported.Misbehaviour) bool { + // TODO: implement + return false +} + +var _ exported.Header = Header{} + +// Header defines the Tendermint consensus Header +type Header struct { + // TODO: define Tendermint header type manually, don't use tmtypes + tmtypes.SignedHeader + ValidatorSet *tmtypes.ValidatorSet + NextValidatorSet *tmtypes.ValidatorSet +} + +// Kind defines that the Header is a Tendermint consensus algorithm +func (header Header) Kind() exported.Kind { + return exported.Tendermint +} + +// GetHeight returns the current height +func (header Header) GetHeight() uint64 { + return uint64(header.Height) +} diff --git a/x/ibc/02-client/tendermint/tests/tendermint_test.go b/x/ibc/02-client/types/tendermint/tests/tendermint_test.go similarity index 100% rename from x/ibc/02-client/tendermint/tests/tendermint_test.go rename to x/ibc/02-client/types/tendermint/tests/tendermint_test.go diff --git a/x/ibc/02-client/tendermint/tests/types.go b/x/ibc/02-client/types/tendermint/tests/types.go similarity index 97% rename from x/ibc/02-client/tendermint/tests/types.go rename to x/ibc/02-client/types/tendermint/tests/types.go index b9b238c74126..2094de08abc6 100644 --- a/x/ibc/02-client/tendermint/tests/types.go +++ b/x/ibc/02-client/types/tendermint/tests/types.go @@ -18,8 +18,8 @@ import ( stypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - 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/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) @@ -125,7 +125,7 @@ func (node *Node) Context() sdk.Context { } type Verifier struct { - client.ConsensusState + exported.ConsensusState } func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root merkle.Root) *Verifier { diff --git a/x/ibc/02-client/tendermint/tests/utils.go b/x/ibc/02-client/types/tendermint/tests/utils.go similarity index 100% rename from x/ibc/02-client/tendermint/tests/utils.go rename to x/ibc/02-client/types/tendermint/tests/utils.go diff --git a/x/ibc/02-client/tendermint/tests/valset.go b/x/ibc/02-client/types/tendermint/tests/valset.go similarity index 100% rename from x/ibc/02-client/tendermint/tests/valset.go rename to x/ibc/02-client/types/tendermint/tests/valset.go diff --git a/x/ibc/types/types.go b/x/ibc/types/types.go new file mode 100644 index 000000000000..535a8f2461e5 --- /dev/null +++ b/x/ibc/types/types.go @@ -0,0 +1,15 @@ +package types + +const ( + // ModuleName is the name of the IBC module + ModuleName = "ibc" + + // StoreKey is the string store representation + StoreKey = ModuleName + + // QuerierRoute is the querier route for the IBC module + QuerierRoute = ModuleName + + // RouterKey is the msg router key for the IBC module + RouterKey = ModuleName +) From d93a0ae027cfdb7764c768197084925dcfdb84d3 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 2 Oct 2019 13:56:34 +0200 Subject: [PATCH 253/378] more cleanup and godocs --- x/ibc/02-client/client/cli/query.go | 50 ++++-- x/ibc/02-client/doc.go | 2 - x/ibc/02-client/exported/exported.go | 2 +- x/ibc/02-client/handler.go | 7 +- x/ibc/02-client/types/errors.go | 3 + x/ibc/02-client/types/manager.go | 164 ++++-------------- x/ibc/02-client/types/state.go | 118 +++++++++++++ .../02-client/types/tendermint/tests/types.go | 4 +- 8 files changed, 195 insertions(+), 155 deletions(-) create mode 100644 x/ibc/02-client/types/errors.go create mode 100644 x/ibc/02-client/types/state.go diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 73baefcfcd5a..ddcd2d73e30b 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -3,6 +3,7 @@ package cli import ( "fmt" "strconv" + "strings" "github.com/spf13/cobra" @@ -25,6 +26,7 @@ func mapping(cdc *codec.Codec, storeKey string, v int64) state.Mapping { return state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) } +// GetQueryCmd returns the query commands for IBC clients func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ibcQueryCmd := &cobra.Command{ Use: "client", @@ -37,17 +39,23 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { GetCmdQueryConsensusState(storeKey, cdc), GetCmdQueryPath(storeKey, cdc), GetCmdQueryHeader(cdc), - GetCmdQueryClient(storeKey, cdc), + GetCmdQueryClientState(storeKey, cdc), GetCmdQueryRoot(storeKey, cdc), )...) return ibcQueryCmd } -func GetCmdQueryClient(storeKey string, cdc *codec.Codec) *cobra.Command { +// GetCmdQueryClientState defines the command to query the state of a client with +// a given id as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#query +func GetCmdQueryClientState(storeKey string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ - Use: "client", - Short: "Query stored client", - Args: cobra.ExactArgs(1), + Use: "state", + Short: "Query a client state", + Long: strings.TrimSpace(`Query stored client + +$ cli query ibc client state [id] + `), + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) q := state.NewCLIQuerier(ctx) @@ -61,17 +69,21 @@ func GetCmdQueryClient(storeKey string, cdc *codec.Codec) *cobra.Command { } fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) - return nil }, } } +// GetCmdQueryRoot defines the command to query func GetCmdQueryRoot(storeKey string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "root", Short: "Query stored root", - Args: cobra.ExactArgs(2), + Long: strings.TrimSpace(`Query stored client + +$ cli query ibc client root [id] [height] + `), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) q := state.NewCLIQuerier(ctx) @@ -89,15 +101,21 @@ func GetCmdQueryRoot(storeKey string, cdc *codec.Codec) *cobra.Command { } fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, root)) - return nil }, } } + +// GetCmdQueryConsensusState defines the command to query the consensus state of +// the chain as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#query func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "consensus-state", Short: "Query the latest consensus state of the running chain", + Long: strings.TrimSpace(`Query consensus state + +$ cli query ibc client consensus-state + `), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) @@ -132,16 +150,20 @@ func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command } fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) - return nil }, } } +// GetCmdQueryPath defines the command to query the commitment path func GetCmdQueryPath(storeName string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "path", Short: "Query the commitment path of the running chain", + Long: strings.TrimSpace(`Query the commitment path + +$ cli query ibc client path + `), RunE: func(cmd *cobra.Command, args []string) error { mapp := mapping(cdc, storeName, version.Version) path := merkle.NewPrefix([][]byte{[]byte(storeName)}, mapp.PrefixBytes()) @@ -151,10 +173,15 @@ func GetCmdQueryPath(storeName string, cdc *codec.Codec) *cobra.Command { } } +// GetCmdQueryHeader defines the command to query the latest header on the chain func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "header", Short: "Query the latest header of the running chain", + Long: strings.TrimSpace(`Query the latest header + +$ cli query ibc client header + `), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) @@ -181,7 +208,7 @@ func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { return err } - nextvalidators, err := node.Validators(&height) + nextValidators, err := node.Validators(&height) if err != nil { return err } @@ -189,11 +216,10 @@ func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { header := tendermint.Header{ SignedHeader: commit.SignedHeader, ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), + NextValidatorSet: tmtypes.NewValidatorSet(nextValidators.Validators), } fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) - return nil }, } diff --git a/x/ibc/02-client/doc.go b/x/ibc/02-client/doc.go index 40c1e138d3d9..c2ce8f7729e6 100644 --- a/x/ibc/02-client/doc.go +++ b/x/ibc/02-client/doc.go @@ -50,7 +50,5 @@ each corresponds to `spec: Header.{height, proof, state, root}`. 2. Manager `spec: interface ClientState` is implemented by `type State`. - - */ package ics02 diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index 6ddab9625be8..3fbad3b79e9f 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -9,7 +9,7 @@ import ( // This interface is implemented as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#blockchain. type Blockchain interface { Genesis() ConsensusState // Consensus state defined in the genesis - Consensus() Header // Header generating funciton + Consensus() Header // Header generating function } // ConsensusState is the state of the consensus process diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go index 3ed9a8bde551..a367ce36d6ca 100644 --- a/x/ibc/02-client/handler.go +++ b/x/ibc/02-client/handler.go @@ -28,7 +28,7 @@ func NewHandler(manager types.Manager) sdk.Handler { } func handleMsgCreateClient(ctx sdk.Context, manager types.Manager, msg types.MsgCreateClient) sdk.Result { - _, err := manager.Create(ctx, msg.ClientID, msg.ConsensusState) + _, err := manager.CreateClient(ctx, msg.ClientID, msg.ConsensusState) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(100), err.Error()).Result() } @@ -38,11 +38,12 @@ func handleMsgCreateClient(ctx sdk.Context, manager types.Manager, msg types.Msg } func handleMsgUpdateClient(ctx sdk.Context, manager types.Manager, msg types.MsgUpdateClient) sdk.Result { - obj, err := manager.Query(ctx, msg.ClientID) + state, err := manager.Query(ctx, msg.ClientID) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(200), err.Error()).Result() } - err = obj.Update(ctx, msg.Header) + + err = state.Update(ctx, msg.Header) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(300), err.Error()).Result() } diff --git a/x/ibc/02-client/types/errors.go b/x/ibc/02-client/types/errors.go new file mode 100644 index 000000000000..d8fa0171da5d --- /dev/null +++ b/x/ibc/02-client/types/errors.go @@ -0,0 +1,3 @@ +package types + +// TODO: diff --git a/x/ibc/02-client/types/manager.go b/x/ibc/02-client/types/manager.go index 7aae2fe6827d..039774fc44b7 100644 --- a/x/ibc/02-client/types/manager.go +++ b/x/ibc/02-client/types/manager.go @@ -1,7 +1,6 @@ package types import ( - "bytes" "errors" "github.com/cosmos/cosmos-sdk/codec" @@ -9,29 +8,18 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -// Any actor holding the Manager can access on and modify any client information +// Manager represents a type that grants read and write permissions to any client +// state information type Manager struct { protocol state.Mapping } // NewManager creates a new Manager instance -func NewManager(base state.Mapping) Manager { +func NewManager(mapping state.Mapping) Manager { return Manager{ - protocol: base.Prefix(LocalRoot()), - } -} - -type CounterpartyManager struct { - protocol ics23.Mapping -} - -// NewCounterpartyManager creates a new CounterpartyManager instance -func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { - return CounterpartyManager{ - protocol: ics23.NewMapping(cdc, LocalRoot()), + protocol: mapping.Prefix(LocalRoot()), } } @@ -45,25 +33,30 @@ func (m Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { } */ -func (m Manager) State(id string) State { - return State{ - id: id, - Roots: m.protocol.Prefix([]byte(id + "/roots/")).Indexer(state.Dec), - ConsensusState: m.protocol.Value([]byte(id)), - Frozen: m.protocol.Value([]byte(id + "/freeze")).Boolean(), - } -} - -func (m Manager) Create(ctx sdk.Context, id string, cs exported.ConsensusState) (State, error) { +// CreateClient creates a new client state and populates it with a given consensus state +func (m Manager) CreateClient(ctx sdk.Context, id string, cs exported.ConsensusState) (State, error) { state := m.State(id) if state.exists(ctx) { return State{}, errors.New("cannot create client on an existing id") } + + // set the most recent state root and consensus state state.Roots.Set(ctx, cs.GetHeight(), cs.GetRoot()) state.ConsensusState.Set(ctx, cs) return state, nil } +// State returnts a new client state with a given id +func (m Manager) State(id string) State { + return State{ + id: id, + Roots: m.protocol.Prefix([]byte(id + "/roots/")).Indexer(state.Dec), + ConsensusState: m.protocol.Value([]byte(id)), + Frozen: m.protocol.Value([]byte(id + "/freeze")).Boolean(), + } +} + +// Query returns a client state that matches a given ID func (m Manager) Query(ctx sdk.Context, id string) (State, error) { res := m.State(id) if !res.exists(ctx) { @@ -72,6 +65,17 @@ func (m Manager) Query(ctx sdk.Context, id string) (State, error) { return res, nil } +type CounterpartyManager struct { + protocol ics23.Mapping +} + +// NewCounterpartyManager creates a new CounterpartyManager instance +func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { + return CounterpartyManager{ + protocol: ics23.NewMapping(cdc, LocalRoot()), + } +} + func (m CounterpartyManager) State(id string) CounterState { return CounterState{ id: id, @@ -82,111 +86,3 @@ func (m CounterpartyManager) State(id string) CounterState { func (m CounterpartyManager) Query(id string) CounterState { return m.State(id) } - -// 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 CounterState struct { - id string - ConsensusState ics23.Value -} - -func (state State) ID() string { - return state.id -} - -func (state State) GetConsensusState(ctx sdk.Context) (res exported.ConsensusState) { - state.ConsensusState.Get(ctx, &res) - return -} - -func (state State) GetRoot(ctx sdk.Context, height uint64) (res ics23.Root, err error) { - err = state.Roots.GetSafe(ctx, height, &res) - return -} - -func (state CounterState) Is(ctx sdk.Context, client exported.ConsensusState) bool { - return state.ConsensusState.Is(ctx, client) -} - -func (state State) exists(ctx sdk.Context) bool { - return state.ConsensusState.Exists(ctx) -} - -func (state State) Update(ctx sdk.Context, header exported.Header) error { - if !state.exists(ctx) { - panic("should not update nonexisting client") - } - - if state.Frozen.Get(ctx) { - return errors.New("client is Frozen") - } - - stored := state.GetConsensusState(ctx) - updated, err := stored.CheckValidityAndUpdateState(header) - if err != nil { - return err - } - - state.ConsensusState.Set(ctx, updated) - state.Roots.Set(ctx, updated.GetHeight(), updated.GetRoot()) - - return nil -} - -func (state State) Freeze(ctx sdk.Context) error { - if !state.exists(ctx) { - panic("should not freeze nonexisting client") - } - - if state.Frozen.Get(ctx) { - return errors.New("client is already Frozen") - } - - state.Frozen.Set(ctx, true) - - return nil -} - -func (state State) Delete(ctx sdk.Context) error { - if !state.exists(ctx) { - panic("should not delete nonexisting client") - } - - if !state.Frozen.Get(ctx) { - return errors.New("client is not Frozen") - } - - state.ConsensusState.Delete(ctx) - state.Frozen.Delete(ctx) - - return nil -} - -func (state State) prefix() []byte { - return bytes.Split(state.ConsensusState.KeyBytes(), LocalRoot())[0] -} - -func (state State) RootCLI(q state.ABCIQuerier, height uint64) (res ics23.Root, proof merkle.Proof, err error) { - root := state.Roots.Value(height) - tmproof, err := root.Query(q, &res) - proof = merkle.NewProofFromValue(tmproof, state.prefix(), root) - return -} - -func (state State) ConsensusStateCLI(q state.ABCIQuerier) (res exported.ConsensusState, proof merkle.Proof, err error) { - tmproof, err := state.ConsensusState.Query(q, &res) - proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.ConsensusState) - return -} - -func (state State) FrozenCLI(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { - res, tmproof, err := state.Frozen.Query(q) - proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Frozen) - return -} diff --git a/x/ibc/02-client/types/state.go b/x/ibc/02-client/types/state.go new file mode 100644 index 000000000000..0abbd74da179 --- /dev/null +++ b/x/ibc/02-client/types/state.go @@ -0,0 +1,118 @@ +package types + +import ( + "bytes" + "errors" + + "github.com/cosmos/cosmos-sdk/store/state" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +// State is a type that represents the state of a client. +// Any actor holding the Stage can access on and modify that client information. +type State struct { + // Client ID + id string + // Past state roots required to avoid race conditions between client updates + // and proof-carrying transactions as defined in + // https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#utilising-past-roots + Roots state.Indexer + // Consensus state bytes + ConsensusState state.Value + // Boolean that states if the client is frozen when a misbehaviour proof is + // submitted in the event of an equivocation. + Frozen state.Boolean +} + +// ID returns the client identifier +func (state State) ID() string { + return state.id +} + +// GetConsensusState returns the consensus state +func (state State) GetConsensusState(ctx sdk.Context) (cs exported.ConsensusState) { + state.ConsensusState.Get(ctx, &cs) + return +} + +// GetRoot returns the commitment root of the client at a given height +func (state State) GetRoot(ctx sdk.Context, height uint64) (root ics23.Root, err error) { + err = state.Roots.GetSafe(ctx, height, &root) + return +} + +// Update updates the consensus state and the state root from a provided header +func (state State) Update(ctx sdk.Context, header exported.Header) error { + if !state.exists(ctx) { + panic("should not update nonexisting client") + } + + if state.Frozen.Get(ctx) { + return errors.New("client is frozen due to misbehaviour") + } + + stored := state.GetConsensusState(ctx) + updated, err := stored.CheckValidityAndUpdateState(header) + if err != nil { + return err + } + + state.ConsensusState.Set(ctx, updated) + state.Roots.Set(ctx, updated.GetHeight(), updated.GetRoot()) + + return nil +} + +// Freeze updates the state of the client in the event of a misbehaviour +func (state State) Freeze(ctx sdk.Context) error { + if !state.exists(ctx) { + panic("should not freeze nonexisting client") + } + + if state.Frozen.Get(ctx) { + return errors.New("cannot freeze an already frozen client") + } + + state.Frozen.Set(ctx, true) + return nil +} + +func (state State) RootCLI(q state.ABCIQuerier, height uint64) (res ics23.Root, proof merkle.Proof, err error) { + root := state.Roots.Value(height) + tmProof, err := root.Query(q, &res) + proof = merkle.NewProofFromValue(tmProof, state.prefix(), root) + return +} + +func (state State) ConsensusStateCLI(q state.ABCIQuerier) (res exported.ConsensusState, proof merkle.Proof, err error) { + tmproof, err := state.ConsensusState.Query(q, &res) + proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.ConsensusState) + return +} + +func (state State) FrozenCLI(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { + res, tmproof, err := state.Frozen.Query(q) + proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Frozen) + return +} + +// exists verifies if the client exists or not +func (state State) exists(ctx sdk.Context) bool { + return state.ConsensusState.Exists(ctx) +} + +func (state State) prefix() []byte { + return bytes.Split(state.ConsensusState.KeyBytes(), LocalRoot())[0] +} + +type CounterState struct { + id string + ConsensusState ics23.Value +} + +func (counterState CounterState) Is(ctx sdk.Context, client exported.ConsensusState) bool { + return counterState.ConsensusState.Is(ctx, client) +} diff --git a/x/ibc/02-client/types/tendermint/tests/types.go b/x/ibc/02-client/types/tendermint/tests/types.go index 2094de08abc6..532b01c635ee 100644 --- a/x/ibc/02-client/types/tendermint/tests/types.go +++ b/x/ibc/02-client/types/tendermint/tests/types.go @@ -150,9 +150,7 @@ func (v *Verifier) Validate(header tendermint.Header, valset, nextvalset MockVal } func (node *Node) Query(t *testing.T, k []byte) ([]byte, commitment.Proof) { - if bytes.HasPrefix(k, node.KeyPrefix) { - k = bytes.TrimPrefix(k, node.KeyPrefix) - } + k = bytes.TrimPrefix(k, node.KeyPrefix) value, proof, err := merkle.QueryMultiStore(node.Cms, node.StoreName, node.KeyPrefix, k) require.NoError(t, err) return value, proof From 9b6afe920da2e1fabaeedf55680ec72d584c7eaf Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 2 Oct 2019 14:13:45 +0200 Subject: [PATCH 254/378] remove counterPartyManager/State and cleanup --- x/ibc/02-client/client/cli/tx.go | 4 --- x/ibc/02-client/exported/exported.go | 1 - x/ibc/02-client/types/manager.go | 34 ------------------- x/ibc/02-client/types/msgs.go | 21 ++++++++---- x/ibc/02-client/types/state.go | 15 ++------ .../02-client/types/tendermint/tendermint.go | 34 +++++++++++-------- 6 files changed, 37 insertions(+), 72 deletions(-) diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index 34e7c79683cc..f02ac62c496b 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -102,10 +102,6 @@ func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { return err } - if err := header.ValidateBasic(txBldr.ChainID()); err != nil { - return sdk.ErrInternal(err.Error()) // TODO: create error on types - } - msg := types.MsgUpdateClient{ ClientID: args[0], Header: header, diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index 3fbad3b79e9f..576e06440386 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -41,7 +41,6 @@ type Misbehaviour interface { type Header interface { Kind() Kind GetHeight() uint64 - ValidateBasic(chainID string) error // NOTE: added for msg validation } // Kind defines the type of the consensus algorithm diff --git a/x/ibc/02-client/types/manager.go b/x/ibc/02-client/types/manager.go index 039774fc44b7..8af23d87c895 100644 --- a/x/ibc/02-client/types/manager.go +++ b/x/ibc/02-client/types/manager.go @@ -3,11 +3,9 @@ package types import ( "errors" - "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/ibc/02-client/exported" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // Manager represents a type that grants read and write permissions to any client @@ -23,16 +21,6 @@ func NewManager(mapping state.Mapping) Manager { } } -/* -func (m Manager) RegisterKind(kind Kind, pred ValidityPredicate) Manager { - if _, ok := m.pred[kind]; ok { - panic("Kind already registered") - } - m.pred[kind] = pred - return m -} -*/ - // CreateClient creates a new client state and populates it with a given consensus state func (m Manager) CreateClient(ctx sdk.Context, id string, cs exported.ConsensusState) (State, error) { state := m.State(id) @@ -64,25 +52,3 @@ func (m Manager) Query(ctx sdk.Context, id string) (State, error) { } return res, nil } - -type CounterpartyManager struct { - protocol ics23.Mapping -} - -// NewCounterpartyManager creates a new CounterpartyManager instance -func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { - return CounterpartyManager{ - protocol: ics23.NewMapping(cdc, LocalRoot()), - } -} - -func (m CounterpartyManager) State(id string) CounterState { - return CounterState{ - id: id, - ConsensusState: m.protocol.Value([]byte(id)), - } -} - -func (m CounterpartyManager) Query(id string) CounterState { - return m.State(id) -} diff --git a/x/ibc/02-client/types/msgs.go b/x/ibc/02-client/types/msgs.go index ec9a7f122284..e1f983f0368b 100644 --- a/x/ibc/02-client/types/msgs.go +++ b/x/ibc/02-client/types/msgs.go @@ -10,9 +10,18 @@ var _ sdk.Msg = MsgCreateClient{} // MsgCreateClient defines a message to create an IBC client type MsgCreateClient struct { - ClientID string - ConsensusState exported.ConsensusState - Signer sdk.AccAddress + ClientID string `json:"id" yaml:"id"` + ConsensusState exported.ConsensusState `json:"consensus_state" yaml:"consensus_address"` + Signer sdk.AccAddress `json:"address" yaml:"address"` +} + +// NewMsgCreateClient creates a new MsgCreateClient instance +func NewMsgCreateClient(ID string, consensusState exported.ConsensusState, signer sdk.AccAddress) MsgCreateClient { + return MsgCreateClient{ + ClientID: ID, + ConsensusState: consensusState, + Signer: signer, + } } // Route implements sdk.Msg @@ -47,9 +56,9 @@ var _ sdk.Msg = MsgUpdateClient{} // MsgUpdateClient defines a message to update an IBC client type MsgUpdateClient struct { - ClientID string - Header exported.Header - Signer sdk.AccAddress + ClientID string `json:"id" yaml:"id"` + Header exported.Header `json:"header" yaml:"header"` + Signer sdk.AccAddress `json:"address" yaml:"address"` } // Route implements sdk.Msg diff --git a/x/ibc/02-client/types/state.go b/x/ibc/02-client/types/state.go index 0abbd74da179..5e968b969583 100644 --- a/x/ibc/02-client/types/state.go +++ b/x/ibc/02-client/types/state.go @@ -19,12 +19,12 @@ type State struct { // Past state roots required to avoid race conditions between client updates // and proof-carrying transactions as defined in // https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#utilising-past-roots - Roots state.Indexer + Roots state.Indexer `json:"roots" yaml:"roots"` // Consensus state bytes - ConsensusState state.Value + ConsensusState state.Value `json:"consensus_state" yaml:"consensus_state"` // Boolean that states if the client is frozen when a misbehaviour proof is // submitted in the event of an equivocation. - Frozen state.Boolean + Frozen state.Boolean `json:"frozen" yaml:"frozen"` } // ID returns the client identifier @@ -107,12 +107,3 @@ func (state State) exists(ctx sdk.Context) bool { func (state State) prefix() []byte { return bytes.Split(state.ConsensusState.KeyBytes(), LocalRoot())[0] } - -type CounterState struct { - id string - ConsensusState ics23.Value -} - -func (counterState CounterState) Is(ctx sdk.Context, client exported.ConsensusState) bool { - return counterState.ConsensusState.Is(ctx, client) -} diff --git a/x/ibc/02-client/types/tendermint/tendermint.go b/x/ibc/02-client/types/tendermint/tendermint.go index bff49e738f7b..5ae497307d73 100644 --- a/x/ibc/02-client/types/tendermint/tendermint.go +++ b/x/ibc/02-client/types/tendermint/tendermint.go @@ -16,33 +16,27 @@ var _ exported.ConsensusState = ConsensusState{} // ConsensusState defines a Tendermint consensus state type ConsensusState struct { - ChainID string - Height uint64 - Root ics23.Root - NextValidatorSet *tmtypes.ValidatorSet + ChainID string `json:"chain_id" yaml:"chain_id"` + Height uint64 `json:"height" yaml:"height"` + Root ics23.Root `json:"root" yaml:"root"` + NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` } +// Kind returns Tendermint func (ConsensusState) Kind() exported.Kind { return exported.Tendermint } +// GetHeight returns the ConsensusState height func (cs ConsensusState) GetHeight() uint64 { return cs.Height } +// GetRoot returns the commitment Root func (cs ConsensusState) GetRoot() ics23.Root { return cs.Root } -func (cs ConsensusState) update(header Header) ConsensusState { - return ConsensusState{ - ChainID: cs.ChainID, - Height: uint64(header.Height), - Root: merkle.NewRoot(header.AppHash), - NextValidatorSet: header.NextValidatorSet, - } -} - // CheckValidityAndUpdateState func (cs ConsensusState) CheckValidityAndUpdateState(header exported.Header) (exported.ConsensusState, error) { tmHeader, ok := header.(Header) @@ -80,14 +74,24 @@ func (cs ConsensusState) CheckMisbehaviourAndUpdateState(mb exported.Misbehaviou return false } +// update updates the consensus state from a new header +func (cs ConsensusState) update(header Header) ConsensusState { + return ConsensusState{ + ChainID: cs.ChainID, + Height: uint64(header.Height), + Root: merkle.NewRoot(header.AppHash), + NextValidatorSet: header.NextValidatorSet, + } +} + var _ exported.Header = Header{} // Header defines the Tendermint consensus Header type Header struct { // TODO: define Tendermint header type manually, don't use tmtypes tmtypes.SignedHeader - ValidatorSet *tmtypes.ValidatorSet - NextValidatorSet *tmtypes.ValidatorSet + ValidatorSet *tmtypes.ValidatorSet `json:"validator_set" yaml:"validator_set"` + NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` } // Kind defines that the Header is a Tendermint consensus algorithm From c8a0ab41c16ffb19b546b7abc63e07a8b36b95d3 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 2 Oct 2019 19:11:07 +0200 Subject: [PATCH 255/378] implement SubmitMisbehaviour and refactor --- x/ibc/02-client/client/cli/query.go | 2 + x/ibc/02-client/client/cli/tx.go | 50 ++++++++++- x/ibc/02-client/exported/exported.go | 14 ++-- x/ibc/02-client/handler.go | 33 ++++++-- x/ibc/02-client/keeper/keeper.go | 84 +++++++++++++++++++ x/ibc/02-client/types/keys.go | 8 +- x/ibc/02-client/types/manager.go | 54 ------------ x/ibc/02-client/types/msgs.go | 57 ++++++++++++- x/ibc/02-client/types/state.go | 26 ++++-- .../{tendermint.go => consensus_state.go} | 59 ++++--------- x/ibc/02-client/types/tendermint/doc.go | 5 ++ x/ibc/02-client/types/tendermint/header.go | 46 ++++++++++ .../types/tendermint/misbehaviour.go | 18 ++++ 13 files changed, 330 insertions(+), 126 deletions(-) create mode 100644 x/ibc/02-client/keeper/keeper.go delete mode 100644 x/ibc/02-client/types/manager.go rename x/ibc/02-client/types/tendermint/{tendermint.go => consensus_state.go} (54%) create mode 100644 x/ibc/02-client/types/tendermint/doc.go create mode 100644 x/ibc/02-client/types/tendermint/header.go create mode 100644 x/ibc/02-client/types/tendermint/misbehaviour.go diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index ddcd2d73e30b..d65559d5ac9f 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -21,6 +21,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/version" ) +// TODO: use Queriers + func mapping(cdc *codec.Codec, storeKey string, v int64) state.Mapping { prefix := version.Prefix(v) return state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index f02ac62c496b..56fa776098f6 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -52,7 +52,7 @@ func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command { Short: "create new client with a consensus state", Long: strings.TrimSpace(`create new client with a specified identifier and consensus state: - $ tx ibc client create $CLIENTID ./state.json --from node0 --home ../node0/cli --chain-id $CID +$ tx ibc client create [client-id] [path/to/consensus_state.json] --from node0 --home ../node0/cli --chain-id $CID `), Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { @@ -87,18 +87,22 @@ func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "update", Short: "update existing client with a header", - Args: cobra.ExactArgs(2), + Long: strings.TrimSpace(`update existing client with a header: + +$ tx ibc client create [client-id] [path/to/header.json] --from node0 --home ../node0/cli --chain-id $CID + `), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) - contents, err := ioutil.ReadFile(args[1]) + bz, err := ioutil.ReadFile(args[1]) if err != nil { return err } var header exported.Header - if err := cdc.UnmarshalJSON(contents, &header); err != nil { + if err := cdc.UnmarshalJSON(bz, &header); err != nil { return err } @@ -113,3 +117,41 @@ func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { } return cmd } + +// GetCmdSubmitMisbehaviour defines the command to submit a misbehaviour to invalidate +// previous state roots and prevent future updates as defined in +// https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#misbehaviour +func GetCmdSubmitMisbehaviour(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "misbehaviour", + Short: "submit a client misbehaviour", + Long: strings.TrimSpace(`submit a client misbehaviour to invalidate to invalidate previous state roots and prevent future updates: + +$ tx ibc client misbehaviour [client-id] [path/to/evidence.json] --from node0 --home ../node0/cli --chain-id $CID + `), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + bz, err := ioutil.ReadFile(args[1]) + if err != nil { + return err + } + + var evidence exported.Evidence + if err := cdc.UnmarshalJSON(bz, &evidence); err != nil { + return err + } + + msg := types.MsgSubmitMisbehaviour{ + ClientID: args[0], + Evidence: evidence, + Signer: cliCtx.GetFromAddress(), + } + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index 576e06440386..636a99a94361 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -24,17 +24,19 @@ type ConsensusState interface { // CheckValidityAndUpdateState returns the updated consensus state // only if the header is a descendent of this consensus state. CheckValidityAndUpdateState(Header) (ConsensusState, error) +} - // CheckMisbehaviourAndUpdateState checks any misbehaviour evidence - // depending on the state type. - CheckMisbehaviourAndUpdateState(Misbehaviour) bool +// Evidence contains two disctict headers used to submit client equivocation +// TODO: use evidence module type +type Evidence interface { + H1() Header + H2() Header } -// Misbehaviour defines the evidence +// Misbehaviour defines a specific consensus kind and an evidence type Misbehaviour interface { Kind() Kind - // TODO: embed Evidence interface - // evidence.Evidence + Evidence() Evidence } // Header is the consensus state update information diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go index a367ce36d6ca..56a664657c1e 100644 --- a/x/ibc/02-client/handler.go +++ b/x/ibc/02-client/handler.go @@ -4,21 +4,25 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" ) // NewHandler creates a new Handler instance for IBC client // transactions -func NewHandler(manager types.Manager) sdk.Handler { +func NewHandler(k keeper.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { case types.MsgCreateClient: - return handleMsgCreateClient(ctx, manager, msg) + return handleMsgCreateClient(ctx, k, msg) case types.MsgUpdateClient: - return handleMsgUpdateClient(ctx, manager, msg) + return handleMsgUpdateClient(ctx, k, msg) + + case types.MsgSubmitMisbehaviour: + return handleMsgSubmitMisbehaviour(ctx, k, msg) default: errMsg := fmt.Sprintf("unrecognized IBC Client message type: %T", msg) @@ -27,8 +31,8 @@ func NewHandler(manager types.Manager) sdk.Handler { } } -func handleMsgCreateClient(ctx sdk.Context, manager types.Manager, msg types.MsgCreateClient) sdk.Result { - _, err := manager.CreateClient(ctx, msg.ClientID, msg.ConsensusState) +func handleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgCreateClient) sdk.Result { + _, err := k.CreateClient(ctx, msg.ClientID, msg.ConsensusState) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(100), err.Error()).Result() } @@ -37,8 +41,8 @@ func handleMsgCreateClient(ctx sdk.Context, manager types.Manager, msg types.Msg return sdk.Result{} } -func handleMsgUpdateClient(ctx sdk.Context, manager types.Manager, msg types.MsgUpdateClient) sdk.Result { - state, err := manager.Query(ctx, msg.ClientID) +func handleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgUpdateClient) sdk.Result { + state, err := k.Query(ctx, msg.ClientID) if err != nil { return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(200), err.Error()).Result() } @@ -51,3 +55,18 @@ func handleMsgUpdateClient(ctx sdk.Context, manager types.Manager, msg types.Msg // TODO: events return sdk.Result{} } + +func handleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg types.MsgSubmitMisbehaviour) sdk.Result { + state, err := k.Query(ctx, msg.ClientID) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(200), err.Error()).Result() + } + + err = k.CheckMisbehaviourAndUpdateState(ctx, state, msg.Evidence) + if err != nil { + return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(200), err.Error()).Result() + } + + // TODO: events + return sdk.Result{} +} diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go new file mode 100644 index 000000000000..1c0f86f35b95 --- /dev/null +++ b/x/ibc/02-client/keeper/keeper.go @@ -0,0 +1,84 @@ +package keeper + +import ( + "errors" + "fmt" + + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/store/state" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// Keeper represents a type that grants read and write permissions to any client +// state information +type Keeper struct { + mapping state.Mapping + codespace sdk.CodespaceType +} + +// NewKeeper creates a new NewKeeper instance +func NewKeeper(mapping state.Mapping) Keeper { + return Keeper{ + mapping: mapping.Prefix([]byte(types.SubModuleName + "/")), + } +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName)) +} + +// CreateClient creates a new client state and populates it with a given consensus state +func (k Keeper) CreateClient(ctx sdk.Context, id string, cs exported.ConsensusState) (types.State, error) { + state, err := k.Query(ctx, id) + if err == nil { + return types.State{}, errors.New("cannot create client on an existing id") + } + + // set the most recent state root and consensus state + state.Roots.Set(ctx, cs.GetHeight(), cs.GetRoot()) + state.ConsensusState.Set(ctx, cs) + return state, nil +} + +// State returnts a new client state with a given id +func (k Keeper) State(id string) types.State { + return types.NewState( + id, // client ID + k.mapping.Prefix([]byte(id+"/roots/")).Indexer(state.Dec), // commitment roots + k.mapping.Value([]byte(id)), // consensus state + k.mapping.Value([]byte(id+"/freeze")).Boolean(), // client frozen + ) +} + +// Query returns a client state that matches a given ID +func (k Keeper) Query(ctx sdk.Context, id string) (types.State, error) { + state := k.State(id) + if !state.Exists(ctx) { + return types.State{}, errors.New("client doesn't exist") + } + return state, nil +} + +// CheckMisbehaviourAndUpdateState checks for client misbehaviour and freezes the +// client if so. +func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, state types.State, evidence exported.Evidence) error { + var err error + switch evidence.H1().Kind() { + case exported.Tendermint: + err = tendermint.CheckMisbehaviour(evidence) + default: + panic("unregistered consensus type") + } + + if err != nil { + return err + } + + return state.Freeze(ctx) +} diff --git a/x/ibc/02-client/types/keys.go b/x/ibc/02-client/types/keys.go index c3d97c364a16..bef9f661d8ad 100644 --- a/x/ibc/02-client/types/keys.go +++ b/x/ibc/02-client/types/keys.go @@ -1,6 +1,6 @@ package types -// IDK what is this for... -func LocalRoot() []byte { - return []byte("client/") -} +const ( + // SubModuleName defines the IBC client name + SubModuleName string = "client" +) diff --git a/x/ibc/02-client/types/manager.go b/x/ibc/02-client/types/manager.go deleted file mode 100644 index 8af23d87c895..000000000000 --- a/x/ibc/02-client/types/manager.go +++ /dev/null @@ -1,54 +0,0 @@ -package types - -import ( - "errors" - - "github.com/cosmos/cosmos-sdk/store/state" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" -) - -// Manager represents a type that grants read and write permissions to any client -// state information -type Manager struct { - protocol state.Mapping -} - -// NewManager creates a new Manager instance -func NewManager(mapping state.Mapping) Manager { - return Manager{ - protocol: mapping.Prefix(LocalRoot()), - } -} - -// CreateClient creates a new client state and populates it with a given consensus state -func (m Manager) CreateClient(ctx sdk.Context, id string, cs exported.ConsensusState) (State, error) { - state := m.State(id) - if state.exists(ctx) { - return State{}, errors.New("cannot create client on an existing id") - } - - // set the most recent state root and consensus state - state.Roots.Set(ctx, cs.GetHeight(), cs.GetRoot()) - state.ConsensusState.Set(ctx, cs) - return state, nil -} - -// State returnts a new client state with a given id -func (m Manager) State(id string) State { - return State{ - id: id, - Roots: m.protocol.Prefix([]byte(id + "/roots/")).Indexer(state.Dec), - ConsensusState: m.protocol.Value([]byte(id)), - Frozen: m.protocol.Value([]byte(id + "/freeze")).Boolean(), - } -} - -// Query returns a client state that matches a given ID -func (m Manager) Query(ctx sdk.Context, id string) (State, error) { - res := m.State(id) - if !res.exists(ctx) { - return State{}, errors.New("client doesn't exist") - } - return res, nil -} diff --git a/x/ibc/02-client/types/msgs.go b/x/ibc/02-client/types/msgs.go index e1f983f0368b..5f9c7286b153 100644 --- a/x/ibc/02-client/types/msgs.go +++ b/x/ibc/02-client/types/msgs.go @@ -16,9 +16,9 @@ type MsgCreateClient struct { } // NewMsgCreateClient creates a new MsgCreateClient instance -func NewMsgCreateClient(ID string, consensusState exported.ConsensusState, signer sdk.AccAddress) MsgCreateClient { +func NewMsgCreateClient(id string, consensusState exported.ConsensusState, signer sdk.AccAddress) MsgCreateClient { return MsgCreateClient{ - ClientID: ID, + ClientID: id, ConsensusState: consensusState, Signer: signer, } @@ -61,6 +61,15 @@ type MsgUpdateClient struct { Signer sdk.AccAddress `json:"address" yaml:"address"` } +// NewMsgUpdateClient creates a new MsgUpdateClient instance +func NewMsgUpdateClient(id string, header exported.Header, signer sdk.AccAddress) MsgUpdateClient { + return MsgUpdateClient{ + ClientID: id, + Header: header, + Signer: signer, + } +} + // Route implements sdk.Msg func (msg MsgUpdateClient) Route() string { return ibctypes.RouterKey @@ -88,3 +97,47 @@ func (msg MsgUpdateClient) GetSignBytes() []byte { func (msg MsgUpdateClient) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } + +// MsgSubmitMisbehaviour defines a message to update an IBC client +type MsgSubmitMisbehaviour struct { + ClientID string `json:"id" yaml:"id"` + Evidence exported.Evidence `json:"evidence" yaml:"evidence"` + Signer sdk.AccAddress `json:"address" yaml:"address"` +} + +// NewMsgSubmitMisbehaviour creates a new MsgSubmitMisbehaviour instance +func NewMsgSubmitMisbehaviour(id string, evidence exported.Evidence, signer sdk.AccAddress) MsgSubmitMisbehaviour { + return MsgSubmitMisbehaviour{ + ClientID: id, + Evidence: evidence, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgSubmitMisbehaviour) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgSubmitMisbehaviour) Type() string { + return "submit_misbehaviour" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgSubmitMisbehaviour) ValidateBasic() sdk.Error { + if msg.Signer.Empty() { + return sdk.ErrInvalidAddress("empty address") + } + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgSubmitMisbehaviour) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgSubmitMisbehaviour) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} diff --git a/x/ibc/02-client/types/state.go b/x/ibc/02-client/types/state.go index 5e968b969583..85c0d934de80 100644 --- a/x/ibc/02-client/types/state.go +++ b/x/ibc/02-client/types/state.go @@ -27,6 +27,16 @@ type State struct { Frozen state.Boolean `json:"frozen" yaml:"frozen"` } +// NewState creates a new State instance +func NewState(id string, roots state.Indexer, consensusState state.Value, frozen state.Boolean) State { + return State{ + id: id, + Roots: roots, + ConsensusState: consensusState, + Frozen: frozen, + } +} + // ID returns the client identifier func (state State) ID() string { return state.id @@ -44,9 +54,14 @@ func (state State) GetRoot(ctx sdk.Context, height uint64) (root ics23.Root, err return } +// Exists verifies if the client exists or not +func (state State) Exists(ctx sdk.Context) bool { + return state.ConsensusState.Exists(ctx) +} + // Update updates the consensus state and the state root from a provided header func (state State) Update(ctx sdk.Context, header exported.Header) error { - if !state.exists(ctx) { + if !state.Exists(ctx) { panic("should not update nonexisting client") } @@ -68,7 +83,7 @@ func (state State) Update(ctx sdk.Context, header exported.Header) error { // Freeze updates the state of the client in the event of a misbehaviour func (state State) Freeze(ctx sdk.Context) error { - if !state.exists(ctx) { + if !state.Exists(ctx) { panic("should not freeze nonexisting client") } @@ -99,11 +114,6 @@ func (state State) FrozenCLI(q state.ABCIQuerier) (res bool, proof merkle.Proof, return } -// exists verifies if the client exists or not -func (state State) exists(ctx sdk.Context) bool { - return state.ConsensusState.Exists(ctx) -} - func (state State) prefix() []byte { - return bytes.Split(state.ConsensusState.KeyBytes(), LocalRoot())[0] + return bytes.Split(state.ConsensusState.KeyBytes(), []byte(SubModuleName+"/"))[0] } diff --git a/x/ibc/02-client/types/tendermint/tendermint.go b/x/ibc/02-client/types/tendermint/consensus_state.go similarity index 54% rename from x/ibc/02-client/types/tendermint/tendermint.go rename to x/ibc/02-client/types/tendermint/consensus_state.go index 5ae497307d73..65a51f9b4e4f 100644 --- a/x/ibc/02-client/types/tendermint/tendermint.go +++ b/x/ibc/02-client/types/tendermint/consensus_state.go @@ -37,41 +37,38 @@ func (cs ConsensusState) GetRoot() ics23.Root { return cs.Root } -// CheckValidityAndUpdateState +// CheckValidityAndUpdateState checks if the provided header is valid and updates +// the consensus state if appropiate func (cs ConsensusState) CheckValidityAndUpdateState(header exported.Header) (exported.ConsensusState, error) { tmHeader, ok := header.(Header) if !ok { return nil, errors.New("header is not from a tendermint consensus") // TODO: create concrete error } - if cs.Height == uint64(tmHeader.Height-1) { - nexthash := cs.NextValidatorSet.Hash() - if !bytes.Equal(tmHeader.ValidatorsHash, nexthash) { - return nil, lerr.ErrUnexpectedValidators(tmHeader.ValidatorsHash, nexthash) - } + if err := cs.checkValidity(tmHeader); err != nil { + return nil, err } - if !bytes.Equal(tmHeader.NextValidatorsHash, tmHeader.NextValidatorSet.Hash()) { - return nil, lerr.ErrUnexpectedValidators(tmHeader.NextValidatorsHash, tmHeader.NextValidatorSet.Hash()) - } + return cs.update(tmHeader), nil +} - err := tmHeader.ValidateBasic(cs.ChainID) - if err != nil { - return nil, err +// checkValidity checks if the Tendermint header is valid +func (cs ConsensusState) checkValidity(header Header) error { + nextHash := cs.NextValidatorSet.Hash() + if cs.Height == uint64(header.Height-1) && + !bytes.Equal(header.ValidatorsHash, nextHash) { + return lerr.ErrUnexpectedValidators(header.ValidatorsHash, nextHash) } - err = cs.NextValidatorSet.VerifyFutureCommit(tmHeader.ValidatorSet, cs.ChainID, tmHeader.Commit.BlockID, tmHeader.Height, tmHeader.Commit) - if err != nil { - return nil, err + if !bytes.Equal(header.NextValidatorsHash, nextHash) { + return lerr.ErrUnexpectedValidators(header.NextValidatorsHash, nextHash) } - return cs.update(tmHeader), nil -} + if err := header.ValidateBasic(cs.ChainID); err != nil { + return err + } -// CheckMisbehaviourAndUpdateState - not implemented -func (cs ConsensusState) CheckMisbehaviourAndUpdateState(mb exported.Misbehaviour) bool { - // TODO: implement - return false + return cs.NextValidatorSet.VerifyFutureCommit(header.ValidatorSet, cs.ChainID, header.Commit.BlockID, header.Height, header.Commit) } // update updates the consensus state from a new header @@ -83,23 +80,3 @@ func (cs ConsensusState) update(header Header) ConsensusState { NextValidatorSet: header.NextValidatorSet, } } - -var _ exported.Header = Header{} - -// Header defines the Tendermint consensus Header -type Header struct { - // TODO: define Tendermint header type manually, don't use tmtypes - tmtypes.SignedHeader - ValidatorSet *tmtypes.ValidatorSet `json:"validator_set" yaml:"validator_set"` - NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` -} - -// Kind defines that the Header is a Tendermint consensus algorithm -func (header Header) Kind() exported.Kind { - return exported.Tendermint -} - -// GetHeight returns the current height -func (header Header) GetHeight() uint64 { - return uint64(header.Height) -} diff --git a/x/ibc/02-client/types/tendermint/doc.go b/x/ibc/02-client/types/tendermint/doc.go new file mode 100644 index 000000000000..f0e27c7696a7 --- /dev/null +++ b/x/ibc/02-client/types/tendermint/doc.go @@ -0,0 +1,5 @@ +/* +Package tendermint implements a concrete `ConsensusState`, `Header` and `Equivocation` +for the Tendermint consensus algorithm. +*/ +package tendermint diff --git a/x/ibc/02-client/types/tendermint/header.go b/x/ibc/02-client/types/tendermint/header.go new file mode 100644 index 000000000000..fe790ac5da73 --- /dev/null +++ b/x/ibc/02-client/types/tendermint/header.go @@ -0,0 +1,46 @@ +package tendermint + +import ( + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" +) + +var _ exported.Header = Header{} + +// Header defines the Tendermint consensus Header +type Header struct { + // TODO: define Tendermint header type manually, don't use tmtypes + tmtypes.SignedHeader + ValidatorSet *tmtypes.ValidatorSet `json:"validator_set" yaml:"validator_set"` + NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` +} + +// Kind defines that the Header is a Tendermint consensus algorithm +func (header Header) Kind() exported.Kind { + return exported.Tendermint +} + +// GetHeight returns the current height +func (header Header) GetHeight() uint64 { + return uint64(header.Height) +} + +var _ exported.Evidence = Evidence{} + +// Evidence defines two disctinct Tendermint headers used to submit a client misbehaviour +// TODO: use evidence module's types +type Evidence struct { + Header1 Header `json:"header_one" yaml:"header_one"` + Header2 Header `json:"header_two" yaml:"header_two"` +} + +// H1 returns the first header +func (e Evidence) H1() exported.Header { + return e.Header1 +} + +// H2 returns the second header +func (e Evidence) H2() exported.Header { + return e.Header2 +} diff --git a/x/ibc/02-client/types/tendermint/misbehaviour.go b/x/ibc/02-client/types/tendermint/misbehaviour.go new file mode 100644 index 000000000000..86bc198dd9c3 --- /dev/null +++ b/x/ibc/02-client/types/tendermint/misbehaviour.go @@ -0,0 +1,18 @@ +package tendermint + +import ( + "errors" + + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" +) + +// CheckMisbehaviour checks if the evidence provided is a misbehaviour +func CheckMisbehaviour(evidence exported.Evidence) error { + _, ok := evidence.(Evidence) + if !ok { + return errors.New("header is not from a tendermint consensus") // TODO: create concrete error + } + + // TODO: check evidence + return nil +} From 4483182b33c4deccac5f8691dfb1df8348675eeb Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 4 Oct 2019 13:50:09 +0200 Subject: [PATCH 256/378] errors --- x/ibc/02-client/handler.go | 12 ++-- x/ibc/02-client/keeper/keeper.go | 57 ++++++++++++++++--- x/ibc/02-client/types/errors.go | 35 +++++++++++- x/ibc/02-client/types/keys.go | 2 +- x/ibc/02-client/types/state.go | 37 ------------ .../types/tendermint/consensus_state.go | 13 +++-- .../types/tendermint/misbehaviour.go | 9 +-- 7 files changed, 100 insertions(+), 65 deletions(-) diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go index 56a664657c1e..e25aca6f1ca2 100644 --- a/x/ibc/02-client/handler.go +++ b/x/ibc/02-client/handler.go @@ -34,7 +34,7 @@ func NewHandler(k keeper.Keeper) sdk.Handler { func handleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgCreateClient) sdk.Result { _, err := k.CreateClient(ctx, msg.ClientID, msg.ConsensusState) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(100), err.Error()).Result() + return sdk.ResultFromError(err) } // TODO: events @@ -44,12 +44,12 @@ func handleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgCreate func handleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgUpdateClient) sdk.Result { state, err := k.Query(ctx, msg.ClientID) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(200), err.Error()).Result() + return sdk.ResultFromError(err) } - err = state.Update(ctx, msg.Header) + err = k.Update(ctx, state, msg.Header) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(300), err.Error()).Result() + return sdk.ResultFromError(err) } // TODO: events @@ -59,12 +59,12 @@ func handleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgUpdate func handleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg types.MsgSubmitMisbehaviour) sdk.Result { state, err := k.Query(ctx, msg.ClientID) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(200), err.Error()).Result() + return sdk.ResultFromError(err) } err = k.CheckMisbehaviourAndUpdateState(ctx, state, msg.Evidence) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), sdk.CodeType(200), err.Error()).Result() + return sdk.ResultFromError(err) } // TODO: events diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index 1c0f86f35b95..7257427eeb4c 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -1,13 +1,13 @@ package keeper import ( - "errors" "fmt" "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" @@ -22,9 +22,10 @@ type Keeper struct { } // NewKeeper creates a new NewKeeper instance -func NewKeeper(mapping state.Mapping) Keeper { +func NewKeeper(mapping state.Mapping, codespace sdk.CodespaceType) Keeper { return Keeper{ - mapping: mapping.Prefix([]byte(types.SubModuleName + "/")), + mapping: mapping.Prefix([]byte(types.SubModuleName + "/")), // "client/" + codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/client" } } @@ -37,7 +38,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { func (k Keeper) CreateClient(ctx sdk.Context, id string, cs exported.ConsensusState) (types.State, error) { state, err := k.Query(ctx, id) if err == nil { - return types.State{}, errors.New("cannot create client on an existing id") + return types.State{}, sdkerrors.Wrap(err, "cannot create client") } // set the most recent state root and consensus state @@ -46,7 +47,7 @@ func (k Keeper) CreateClient(ctx sdk.Context, id string, cs exported.ConsensusSt return state, nil } -// State returnts a new client state with a given id +// State returns a new client state with a given id func (k Keeper) State(id string) types.State { return types.NewState( id, // client ID @@ -60,7 +61,7 @@ func (k Keeper) State(id string) types.State { func (k Keeper) Query(ctx sdk.Context, id string) (types.State, error) { state := k.State(id) if !state.Exists(ctx) { - return types.State{}, errors.New("client doesn't exist") + return types.State{}, types.ErrClientExists(k.codespace) } return state, nil } @@ -71,7 +72,12 @@ func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, state types.Sta var err error switch evidence.H1().Kind() { case exported.Tendermint: - err = tendermint.CheckMisbehaviour(evidence) + var tmEvidence tendermint.Evidence + _, ok := evidence.(tendermint.Evidence) + if !ok { + return sdkerrors.Wrap(types.ErrInvalidConsensus(k.codespace), "consensus is not Tendermint") + } + err = tendermint.CheckMisbehaviour(tmEvidence) default: panic("unregistered consensus type") } @@ -80,5 +86,40 @@ func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, state types.Sta return err } - return state.Freeze(ctx) + return k.Freeze(ctx, state) +} + +// Update updates the consensus state and the state root from a provided header +func (k Keeper) Update(ctx sdk.Context, state types.State, header exported.Header) error { + if !state.Exists(ctx) { + panic("should not update nonexisting client") + } + + if state.Frozen.Get(ctx) { + return sdkerrors.Wrap(types.ErrClientFrozen(k.codespace), "cannot update client") + } + + consensusState := state.GetConsensusState(ctx) + consensusState, err := consensusState.CheckValidityAndUpdateState(header) + if err != nil { + return sdkerrors.Wrap(err, "cannot update client") + } + + state.ConsensusState.Set(ctx, consensusState) + state.Roots.Set(ctx, consensusState.GetHeight(), consensusState.GetRoot()) + return nil +} + +// Freeze updates the state of the client in the event of a misbehaviour +func (k Keeper) Freeze(ctx sdk.Context, state types.State) error { + if !state.Exists(ctx) { + panic("should not freeze nonexisting client") + } + + if state.Frozen.Get(ctx) { + return sdkerrors.Wrap(types.ErrClientFrozen(k.codespace), "already frozen") + } + + state.Frozen.Set(ctx, true) + return nil } diff --git a/x/ibc/02-client/types/errors.go b/x/ibc/02-client/types/errors.go index d8fa0171da5d..4c77d2dffe0a 100644 --- a/x/ibc/02-client/types/errors.go +++ b/x/ibc/02-client/types/errors.go @@ -1,3 +1,36 @@ package types -// TODO: +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// client error codes +const ( + DefaultCodespace sdk.CodespaceType = SubModuleName + + CodeClientExists sdk.CodeType = 101 + CodeClientNotFound sdk.CodeType = 102 + CodeClientFrozen sdk.CodeType = 103 + CodeInvalidConsensus sdk.CodeType = 104 + CodeValidatorJailed sdk.CodeType = 104 +) + +// ErrClientExists implements sdk.Error +func ErrClientExists(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeClientExists, "client already exists") +} + +// ErrClientNotFound implements sdk.Error +func ErrClientNotFound(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeClientNotFound, "client not found") +} + +// ErrClientFrozen implements sdk.Error +func ErrClientFrozen(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeClientFrozen, "client is frozen due to misbehaviour") +} + +// ErrInvalidConsensus implements sdk.Error +func ErrInvalidConsensus(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidConsensus, "invalid consensus algorithm type") +} diff --git a/x/ibc/02-client/types/keys.go b/x/ibc/02-client/types/keys.go index bef9f661d8ad..2e1f26ae3a26 100644 --- a/x/ibc/02-client/types/keys.go +++ b/x/ibc/02-client/types/keys.go @@ -2,5 +2,5 @@ package types const ( // SubModuleName defines the IBC client name - SubModuleName string = "client" + SubModuleName = "client" ) diff --git a/x/ibc/02-client/types/state.go b/x/ibc/02-client/types/state.go index 85c0d934de80..1141c3f281b0 100644 --- a/x/ibc/02-client/types/state.go +++ b/x/ibc/02-client/types/state.go @@ -2,7 +2,6 @@ package types import ( "bytes" - "errors" "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" @@ -59,42 +58,6 @@ func (state State) Exists(ctx sdk.Context) bool { return state.ConsensusState.Exists(ctx) } -// Update updates the consensus state and the state root from a provided header -func (state State) Update(ctx sdk.Context, header exported.Header) error { - if !state.Exists(ctx) { - panic("should not update nonexisting client") - } - - if state.Frozen.Get(ctx) { - return errors.New("client is frozen due to misbehaviour") - } - - stored := state.GetConsensusState(ctx) - updated, err := stored.CheckValidityAndUpdateState(header) - if err != nil { - return err - } - - state.ConsensusState.Set(ctx, updated) - state.Roots.Set(ctx, updated.GetHeight(), updated.GetRoot()) - - return nil -} - -// Freeze updates the state of the client in the event of a misbehaviour -func (state State) Freeze(ctx sdk.Context) error { - if !state.Exists(ctx) { - panic("should not freeze nonexisting client") - } - - if state.Frozen.Get(ctx) { - return errors.New("cannot freeze an already frozen client") - } - - state.Frozen.Set(ctx, true) - return nil -} - func (state State) RootCLI(q state.ABCIQuerier, height uint64) (res ics23.Root, proof merkle.Proof, err error) { root := state.Roots.Value(height) tmProof, err := root.Query(q, &res) diff --git a/x/ibc/02-client/types/tendermint/consensus_state.go b/x/ibc/02-client/types/tendermint/consensus_state.go index 65a51f9b4e4f..ed166d581142 100644 --- a/x/ibc/02-client/types/tendermint/consensus_state.go +++ b/x/ibc/02-client/types/tendermint/consensus_state.go @@ -17,9 +17,9 @@ var _ exported.ConsensusState = ConsensusState{} // ConsensusState defines a Tendermint consensus state type ConsensusState struct { ChainID string `json:"chain_id" yaml:"chain_id"` - Height uint64 `json:"height" yaml:"height"` + Height uint64 `json:"height" yaml:"height"` // NOTE: defined as 'sequence' in the spec Root ics23.Root `json:"root" yaml:"root"` - NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` + NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` // contains the PublicKey } // Kind returns Tendermint @@ -42,7 +42,7 @@ func (cs ConsensusState) GetRoot() ics23.Root { func (cs ConsensusState) CheckValidityAndUpdateState(header exported.Header) (exported.ConsensusState, error) { tmHeader, ok := header.(Header) if !ok { - return nil, errors.New("header is not from a tendermint consensus") // TODO: create concrete error + return nil, errors.New("header is not from a tendermint consensus") } if err := cs.checkValidity(tmHeader); err != nil { @@ -54,6 +54,7 @@ func (cs ConsensusState) CheckValidityAndUpdateState(header exported.Header) (ex // checkValidity checks if the Tendermint header is valid func (cs ConsensusState) checkValidity(header Header) error { + // TODO: shouldn't we check that header.Height > cs.Height? nextHash := cs.NextValidatorSet.Hash() if cs.Height == uint64(header.Height-1) && !bytes.Equal(header.ValidatorsHash, nextHash) { @@ -68,10 +69,12 @@ func (cs ConsensusState) checkValidity(header Header) error { return err } - return cs.NextValidatorSet.VerifyFutureCommit(header.ValidatorSet, cs.ChainID, header.Commit.BlockID, header.Height, header.Commit) + return cs.NextValidatorSet.VerifyFutureCommit( + header.ValidatorSet, cs.ChainID, header.Commit.BlockID, header.Height, header.Commit, + ) } -// update updates the consensus state from a new header +// update the consensus state from a new header func (cs ConsensusState) update(header Header) ConsensusState { return ConsensusState{ ChainID: cs.ChainID, diff --git a/x/ibc/02-client/types/tendermint/misbehaviour.go b/x/ibc/02-client/types/tendermint/misbehaviour.go index 86bc198dd9c3..53fcbcca6bd0 100644 --- a/x/ibc/02-client/types/tendermint/misbehaviour.go +++ b/x/ibc/02-client/types/tendermint/misbehaviour.go @@ -1,17 +1,12 @@ package tendermint import ( - "errors" - + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ) // CheckMisbehaviour checks if the evidence provided is a misbehaviour -func CheckMisbehaviour(evidence exported.Evidence) error { - _, ok := evidence.(Evidence) - if !ok { - return errors.New("header is not from a tendermint consensus") // TODO: create concrete error - } +func CheckMisbehaviour(evidence exported.Evidence) sdk.Error { // TODO: check evidence return nil From 23fbb5d56a0ffc31499e39739718600cdd84e9f6 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 4 Oct 2019 14:08:40 +0200 Subject: [PATCH 257/378] events --- x/ibc/02-client/client/cli/query.go | 202 ++++++++++++++-------------- x/ibc/02-client/handler.go | 44 +++++- x/ibc/02-client/types/events.go | 21 +++ 3 files changed, 158 insertions(+), 109 deletions(-) create mode 100644 x/ibc/02-client/types/events.go diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index d65559d5ac9f..b5a4d6ffbe73 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -2,21 +2,15 @@ package cli import ( "fmt" - "strconv" "strings" "github.com/spf13/cobra" - tmtypes "github.com/tendermint/tendermint/types" - 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" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" "github.com/cosmos/cosmos-sdk/x/ibc/version" ) @@ -59,18 +53,18 @@ $ cli query ibc client state [id] `), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - q := state.NewCLIQuerier(ctx) - mapp := mapping(cdc, storeKey, version.Version) - manager := types.NewManager(mapp) - id := args[0] - - state, _, err := manager.State(id).ConsensusStateCLI(q) - if err != nil { - return err - } - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + // ctx := context.NewCLIContext().WithCodec(cdc) + // q := state.NewCLIQuerier(ctx) + // mapp := mapping(cdc, storeKey, version.Version) + // manager := types.NewManager(mapp) + // id := args[0] + + // state, _, err := manager.State(id).ConsensusStateCLI(q) + // if err != nil { + // return err + // } + + // fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) return nil }, } @@ -87,22 +81,22 @@ $ cli query ibc client root [id] [height] `), 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) - manager := types.NewManager(mapp) - id := args[0] - height, err := strconv.ParseUint(args[1], 10, 64) - if err != nil { - return err - } - - root, _, err := manager.State(id).RootCLI(q, height) - if err != nil { - return err - } - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, root)) + // ctx := context.NewCLIContext().WithCodec(cdc) + // q := state.NewCLIQuerier(ctx) + // mapp := mapping(cdc, storeKey, version.Version) + // manager := types.NewManager(mapp) + // id := args[0] + // height, err := strconv.ParseUint(args[1], 10, 64) + // if err != nil { + // return err + // } + + // root, _, err := manager.State(id).RootCLI(q, height) + // if err != nil { + // return err + // } + + // fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, root)) return nil }, } @@ -119,39 +113,39 @@ func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command $ cli query ibc client consensus-state `), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - node, err := ctx.GetNode() - if err != nil { - return err - } - - info, err := node.ABCIInfo() - if err != nil { - return err - } - - height := info.Response.LastBlockHeight - prevheight := height - 1 - - commit, err := node.Commit(&height) - if err != nil { - return err - } - - validators, err := node.Validators(&prevheight) - if err != nil { - return err - } - - state := tendermint.ConsensusState{ - ChainID: commit.ChainID, - Height: uint64(commit.Height), - Root: merkle.NewRoot(commit.AppHash), - NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - } - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + // ctx := context.NewCLIContext().WithCodec(cdc) + + // node, err := ctx.GetNode() + // if err != nil { + // return err + // } + + // info, err := node.ABCIInfo() + // if err != nil { + // return err + // } + + // height := info.Response.LastBlockHeight + // prevheight := height - 1 + + // commit, err := node.Commit(&height) + // if err != nil { + // return err + // } + + // validators, err := node.Validators(&prevheight) + // if err != nil { + // return err + // } + + // state := tendermint.ConsensusState{ + // ChainID: commit.ChainID, + // Height: uint64(commit.Height), + // Root: merkle.NewRoot(commit.AppHash), + // NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + // } + + // fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) return nil }, } @@ -185,43 +179,43 @@ func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { $ cli query ibc client header `), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - - node, err := ctx.GetNode() - if err != nil { - return err - } - - info, err := node.ABCIInfo() - if err != nil { - return err - } - - height := info.Response.LastBlockHeight - prevheight := height - 1 - - commit, err := node.Commit(&height) - if err != nil { - return err - } - - validators, err := node.Validators(&prevheight) - if err != nil { - return err - } - - nextValidators, err := node.Validators(&height) - if err != nil { - return err - } - - header := tendermint.Header{ - SignedHeader: commit.SignedHeader, - ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - NextValidatorSet: tmtypes.NewValidatorSet(nextValidators.Validators), - } - - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) + // ctx := context.NewCLIContext().WithCodec(cdc) + + // node, err := ctx.GetNode() + // if err != nil { + // return err + // } + + // info, err := node.ABCIInfo() + // if err != nil { + // return err + // } + + // height := info.Response.LastBlockHeight + // prevheight := height - 1 + + // commit, err := node.Commit(&height) + // if err != nil { + // return err + // } + + // validators, err := node.Validators(&prevheight) + // if err != nil { + // return err + // } + + // nextValidators, err := node.Validators(&height) + // if err != nil { + // return err + // } + + // header := tendermint.Header{ + // SignedHeader: commit.SignedHeader, + // ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + // NextValidatorSet: tmtypes.NewValidatorSet(nextValidators.Validators), + // } + + // fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) return nil }, } diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go index e25aca6f1ca2..dfc2f0eabb67 100644 --- a/x/ibc/02-client/handler.go +++ b/x/ibc/02-client/handler.go @@ -37,8 +37,19 @@ func handleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgCreate return sdk.ResultFromError(err) } - // TODO: events - return sdk.Result{} + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeCreateClient, + sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} } func handleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgUpdateClient) sdk.Result { @@ -52,8 +63,20 @@ func handleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgUpdate return sdk.ResultFromError(err) } + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeUpdateClient, + sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + // TODO: events - return sdk.Result{} + return sdk.Result{Events: ctx.EventManager().Events()} } func handleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg types.MsgSubmitMisbehaviour) sdk.Result { @@ -67,6 +90,17 @@ func handleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg types.Msg return sdk.ResultFromError(err) } - // TODO: events - return sdk.Result{} + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeSubmitMisbehaviour, + sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} } diff --git a/x/ibc/02-client/types/events.go b/x/ibc/02-client/types/events.go new file mode 100644 index 000000000000..6258a7e328d9 --- /dev/null +++ b/x/ibc/02-client/types/events.go @@ -0,0 +1,21 @@ +package types + +import ( + "fmt" + + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// IBC client events +const ( + EventTypeCreateClient = "create_client" + EventTypeUpdateClient = "update_client" + EventTypeSubmitMisbehaviour = "submit_misbehaviour" + + AttributeKeyClientID = "client_id" +) + +// IBC client events vars +var ( + AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, SubModuleName) +) From ebecbce1ee843e07ba86cd04ca6436d7502e1535 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 4 Oct 2019 14:13:48 +0200 Subject: [PATCH 258/378] fix test --- x/ibc/02-client/types/tendermint/consensus_state.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/ibc/02-client/types/tendermint/consensus_state.go b/x/ibc/02-client/types/tendermint/consensus_state.go index ed166d581142..0fd3966fa65d 100644 --- a/x/ibc/02-client/types/tendermint/consensus_state.go +++ b/x/ibc/02-client/types/tendermint/consensus_state.go @@ -32,7 +32,7 @@ func (cs ConsensusState) GetHeight() uint64 { return cs.Height } -// GetRoot returns the commitment Root +// GetRoot returns the commitment Rootgit func (cs ConsensusState) GetRoot() ics23.Root { return cs.Root } @@ -61,6 +61,7 @@ func (cs ConsensusState) checkValidity(header Header) error { return lerr.ErrUnexpectedValidators(header.ValidatorsHash, nextHash) } + nextHash = header.NextValidatorSet.Hash() if !bytes.Equal(header.NextValidatorsHash, nextHash) { return lerr.ErrUnexpectedValidators(header.NextValidatorsHash, nextHash) } From 0e85ed041893aa201dfaadc3c68c88430c7a70ba Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 4 Oct 2019 16:28:06 +0200 Subject: [PATCH 259/378] refactors --- x/ibc/02-client/client/cli/query.go | 229 +++++++----------- x/ibc/02-client/exported/exported.go | 12 +- x/ibc/02-client/keeper/keeper.go | 4 +- x/ibc/02-client/keeper/querier.go | 134 ++++++++++ x/ibc/02-client/types/querier.go | 38 +++ .../types/tendermint/consensus_state.go | 4 +- x/ibc/02-client/types/tendermint/header.go | 4 +- 7 files changed, 277 insertions(+), 148 deletions(-) create mode 100644 x/ibc/02-client/keeper/querier.go create mode 100644 x/ibc/02-client/types/querier.go diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index b5a4d6ffbe73..b092f224f31a 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -2,26 +2,18 @@ package cli import ( "fmt" + "strconv" "strings" "github.com/spf13/cobra" 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" - - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" - "github.com/cosmos/cosmos-sdk/x/ibc/version" + "github.com/cosmos/cosmos-sdk/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/version" ) -// TODO: use Queriers - -func mapping(cdc *codec.Codec, storeKey string, v int64) state.Mapping { - prefix := version.Prefix(v) - return state.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) -} - // GetQueryCmd returns the query commands for IBC clients func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ibcQueryCmd := &cobra.Command{ @@ -47,25 +39,30 @@ func GetCmdQueryClientState(storeKey string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "state", Short: "Query a client state", - Long: strings.TrimSpace(`Query stored client - -$ cli query ibc client state [id] - `), + Long: strings.TrimSpace( + fmt.Sprintf(`Query stored client + +Example: +$ %s query ibc client state [id] + `, version.ClientName), + ), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - // ctx := context.NewCLIContext().WithCodec(cdc) - // q := state.NewCLIQuerier(ctx) - // mapp := mapping(cdc, storeKey, version.Version) - // manager := types.NewManager(mapp) - // id := args[0] - - // state, _, err := manager.State(id).ConsensusStateCLI(q) - // if err != nil { - // return err - // } - - // fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) - return nil + cliCtx := context.NewCLIContext().WithCodec(cdc) + id := args[0] + + bz, err := cdc.MarshalJSON(types.NewQueryClientStateParams(id)) + if err != nil { + return err + } + + req := abci.RequestQuery{ + Path: "/store/" + storeKey + "/key", + Data: bz, + Prove: true, + } + + return cliCtx.PrintOutput() }, } } @@ -75,29 +72,28 @@ func GetCmdQueryRoot(storeKey string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "root", Short: "Query stored root", - Long: strings.TrimSpace(`Query stored client - -$ cli query ibc client root [id] [height] - `), + Long: strings.TrimSpace( + fmt.Sprintf(`Query stored client + +Example: +$ %s query ibc client root [id] [height] +`, version.ClientName), + ), 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) - // manager := types.NewManager(mapp) - // id := args[0] - // height, err := strconv.ParseUint(args[1], 10, 64) - // if err != nil { - // return err - // } - - // root, _, err := manager.State(id).RootCLI(q, height) - // if err != nil { - // return err - // } - - // fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, root)) - return nil + cliCtx := context.NewCLIContext().WithCodec(cdc) + id := args[0] + height, err := strconv.ParseUint(args[1], 10, 64) + if err != nil { + return err + } + + bz, err := cdc.MarshalJSON(types.NewQueryCommitmentRootParams(id, height)) + if err != nil { + return err + } + + return cliCtx.PrintOutput() }, } } @@ -108,45 +104,38 @@ func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command return &cobra.Command{ Use: "consensus-state", Short: "Query the latest consensus state of the running chain", - Long: strings.TrimSpace(`Query consensus state - -$ cli query ibc client consensus-state - `), + Long: strings.TrimSpace( + fmt.Sprintf(`Query consensus state + +Example: +$ %s query ibc client consensus-state + `, version.ClientName), + ), RunE: func(cmd *cobra.Command, args []string) error { - // ctx := context.NewCLIContext().WithCodec(cdc) - - // node, err := ctx.GetNode() - // if err != nil { - // return err - // } - - // info, err := node.ABCIInfo() - // if err != nil { - // return err - // } - - // height := info.Response.LastBlockHeight - // prevheight := height - 1 - - // commit, err := node.Commit(&height) - // if err != nil { - // return err - // } - - // validators, err := node.Validators(&prevheight) - // if err != nil { - // return err - // } - - // state := tendermint.ConsensusState{ - // ChainID: commit.ChainID, - // Height: uint64(commit.Height), - // Root: merkle.NewRoot(commit.AppHash), - // NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - // } - - // fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) - return nil + cliCtx := context.NewCLIContext().WithCodec(cdc) + node, err := cliCtx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return err + } + + return cliCtx.PrintOutput() }, } } @@ -156,15 +145,16 @@ func GetCmdQueryPath(storeName string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "path", Short: "Query the commitment path of the running chain", - Long: strings.TrimSpace(`Query the commitment path + Long: strings.TrimSpace(fmt.Sprintf(`Query the commitment path -$ cli query ibc client path - `), +Example: +$ %s query ibc client path + `, version.ClientName), + ), RunE: func(cmd *cobra.Command, args []string) error { - mapp := mapping(cdc, storeName, version.Version) - path := merkle.NewPrefix([][]byte{[]byte(storeName)}, mapp.PrefixBytes()) - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, path)) - return nil + cliCtx := context.NewCLIContext().WithCodec(cdc) + + return cliCtx.PrintOutput() }, } } @@ -174,49 +164,16 @@ func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "header", Short: "Query the latest header of the running chain", - Long: strings.TrimSpace(`Query the latest header + Long: strings.TrimSpace(fmt.Sprintf(`Query the latest header -$ cli query ibc client header - `), +Example: +$ %s query ibc client header + `, version.ClientName), + ), RunE: func(cmd *cobra.Command, args []string) error { - // ctx := context.NewCLIContext().WithCodec(cdc) - - // node, err := ctx.GetNode() - // if err != nil { - // return err - // } - - // info, err := node.ABCIInfo() - // if err != nil { - // return err - // } - - // height := info.Response.LastBlockHeight - // prevheight := height - 1 - - // commit, err := node.Commit(&height) - // if err != nil { - // return err - // } - - // validators, err := node.Validators(&prevheight) - // if err != nil { - // return err - // } - - // nextValidators, err := node.Validators(&height) - // if err != nil { - // return err - // } - - // header := tendermint.Header{ - // SignedHeader: commit.SignedHeader, - // ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - // NextValidatorSet: tmtypes.NewValidatorSet(nextValidators.Validators), - // } - - // fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, header)) - return nil + cliCtx := context.NewCLIContext().WithCodec(cdc) + + return cliCtx.PrintOutput() }, } } diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index 636a99a94361..54d42f15bd9a 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -14,7 +14,7 @@ type Blockchain interface { // ConsensusState is the state of the consensus process type ConsensusState interface { - Kind() Kind // Consensus kind + ClientType() ClientType // Consensus kind GetHeight() uint64 // GetRoot returns the commitment root of the consensus state, @@ -35,20 +35,20 @@ type Evidence interface { // Misbehaviour defines a specific consensus kind and an evidence type Misbehaviour interface { - Kind() Kind + ClientType() ClientType Evidence() Evidence } // Header is the consensus state update information type Header interface { - Kind() Kind + ClientType() ClientType GetHeight() uint64 } -// Kind defines the type of the consensus algorithm -type Kind byte +// ClientType defines the type of the consensus algorithm +type ClientType byte // Registered consensus types const ( - Tendermint Kind = iota + Tendermint ClientType = iota ) diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index 7257427eeb4c..b1fb846eb672 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -48,7 +48,7 @@ func (k Keeper) CreateClient(ctx sdk.Context, id string, cs exported.ConsensusSt } // State returns a new client state with a given id -func (k Keeper) State(id string) types.State { +func (k Keeper) ClientState(id string) types.State { return types.NewState( id, // client ID k.mapping.Prefix([]byte(id+"/roots/")).Indexer(state.Dec), // commitment roots @@ -59,7 +59,7 @@ func (k Keeper) State(id string) types.State { // Query returns a client state that matches a given ID func (k Keeper) Query(ctx sdk.Context, id string) (types.State, error) { - state := k.State(id) + state := k.ClientState(id) if !state.Exists(ctx) { return types.State{}, types.ErrClientExists(k.codespace) } diff --git a/x/ibc/02-client/keeper/querier.go b/x/ibc/02-client/keeper/querier.go new file mode 100644 index 000000000000..260cfc63bc7e --- /dev/null +++ b/x/ibc/02-client/keeper/querier.go @@ -0,0 +1,134 @@ +package keeper + +import ( + "fmt" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +) + +// NewQuerier creates a querier for the IBC client +func NewQuerier(k Keeper) sdk.Querier { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + switch path[0] { + case types.QueryClientState: + return queryClientState(ctx, req, k) + case types.QueryConsensusState: + return queryConsensusState(ctx) + case types.QueryCommitmentPath: + return queryCommitmentPath(ctx, req, k) + case types.QueryCommitmentRoot: + return queryCommitmentRoot(ctx, req, k) + case types.QueryHeader: + return queryHeader(ctx, req, k) + default: + return nil, sdk.ErrUnknownRequest("unknown IBC client query endpoint") + } + } +} + +func queryClientState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { + var params types.QueryClientStateParams + + err := types.SubModuleCdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + } + + + // mapp := mapping(cdc, storeKey, version.Version) + // state, _, err := k.State(id).ConsensusStateCLI(q) + // if err != nil { + // return err + // } + + return res, nil +} + +func queryConsensusState(ctx sdk.Context) ([]byte, sdk.Error) { + + state := tendermint.ConsensusState{ + ChainID: commit.ChainID, + Height: uint64(commit.Height), + Root: merkle.NewRoot(commit.AppHash), + NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + } + + return res, nil +} + +func queryCommitmentPath(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { + + path := merkle.NewPrefix([][]byte{[]byte(k.mapping.storeName)}, k.mapping.PrefixBytes()) + + return res, nil +} + +func queryCommitmentRoot(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { + var params types.QueryCommitmentRoot + + err := types.SubModuleCdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + } + + root, _, err := k.ClientState(params.ID).RootCLI(q, params.Height) + if err != nil { + return nil, err + } + + res, err := codec.MarshalJSONIndent(types.SubModuleCdc, root) + if err != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + } + + return res, nil +} + +func queryHeader(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { + // node, err := ctx.GetNode() + // if err != nil { + // return err + // } + + // info, err := node.ABCIInfo() + // if err != nil { + // return err + // } + + // height := info.Response.LastBlockHeight + // prevheight := height - 1 + + // commit, err := node.Commit(&height) + // if err != nil { + // return err + // } + + // validators, err := node.Validators(&prevheight) + // if err != nil { + // return err + // } + + // nextValidators, err := node.Validators(&height) + // if err != nil { + // return err + // } + + // header := tendermint.Header{ + // SignedHeader: commit.SignedHeader, + // ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + // NextValidatorSet: tmtypes.NewValidatorSet(nextValidators.Validators), + // } + + res, err := codec.MarshalJSONIndent(types.SubModuleCdc, header) + if err != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", err.Error())) + } + + return res, nil +} diff --git a/x/ibc/02-client/types/querier.go b/x/ibc/02-client/types/querier.go new file mode 100644 index 000000000000..3e10883481c4 --- /dev/null +++ b/x/ibc/02-client/types/querier.go @@ -0,0 +1,38 @@ +package types + +// query routes supported by the IBC client Querier +const ( + QueryClientState = "clientState" + QueryConsensusState = "consensusState" + QueryCommitmentPath = "commitmentPath" + QueryCommitmentRoot = "commitmentRoot" + QueryHeader = "header" +) + +// QueryClientStateParams defines the params for the following queries: +// - 'custom/ibc/client/clientState' +type QueryClientStateParams struct { + ID string +} + +// NewQueryClientStateParams creates a new QueryClientStateParams instance +func NewQueryClientStateParams(id string) QueryClientStateParams { + return QueryClientStateParams{ + ID: id, + } +} + +// QueryCommitmentRootParams defines the params for the following queries: +// - 'custom/ibc/client/commitmentRoot' +type QueryCommitmentRootParams struct { + ID string + Height uint64 +} + +// NewQueryCommitmentRootParams creates a new QueryCommitmentRootParams instance +func NewQueryCommitmentRootParams(id string, height uint64) QueryCommitmentRootParams { + return QueryCommitmentRootParams{ + ID: id, + Height: height, + } +} diff --git a/x/ibc/02-client/types/tendermint/consensus_state.go b/x/ibc/02-client/types/tendermint/consensus_state.go index 0fd3966fa65d..5ebb973719bc 100644 --- a/x/ibc/02-client/types/tendermint/consensus_state.go +++ b/x/ibc/02-client/types/tendermint/consensus_state.go @@ -22,8 +22,8 @@ type ConsensusState struct { NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` // contains the PublicKey } -// Kind returns Tendermint -func (ConsensusState) Kind() exported.Kind { +// ClientType returns Tendermint +func (ConsensusState) ClientType() exported.ClientType { return exported.Tendermint } diff --git a/x/ibc/02-client/types/tendermint/header.go b/x/ibc/02-client/types/tendermint/header.go index fe790ac5da73..408aaed40d28 100644 --- a/x/ibc/02-client/types/tendermint/header.go +++ b/x/ibc/02-client/types/tendermint/header.go @@ -16,8 +16,8 @@ type Header struct { NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` } -// Kind defines that the Header is a Tendermint consensus algorithm -func (header Header) Kind() exported.Kind { +// ClientType defines that the Header is a Tendermint consensus algorithm +func (header Header) ClientType() exported.ClientType { return exported.Tendermint } From f16d6e9e1cde59da01de98773fad86f309edf847 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 7 Oct 2019 17:38:08 +0200 Subject: [PATCH 260/378] WIP refactor ICS03 --- x/ibc/03-connection/client/utils/types.go | 32 ++-- x/ibc/03-connection/codec.go | 24 --- x/ibc/03-connection/handler.go | 120 ++++++++++--- x/ibc/03-connection/{ => keeper}/handshake.go | 107 ++++-------- .../{manager.go => keeper/keeper.go} | 93 +++++----- x/ibc/03-connection/keys.go | 5 - x/ibc/03-connection/msgs.go | 132 --------------- x/ibc/03-connection/types.go | 39 ----- x/ibc/03-connection/types/codec.go | 18 ++ x/ibc/03-connection/types/connection.go | 60 +++++++ x/ibc/03-connection/types/errors.go | 36 ++++ x/ibc/03-connection/types/events.go | 23 +++ x/ibc/03-connection/types/expected_keepers.go | 5 + x/ibc/03-connection/types/handshake.go | 7 + x/ibc/03-connection/types/keys.go | 6 + x/ibc/03-connection/types/msgs.go | 159 ++++++++++++++++++ .../{ => types}/tests/connection_test.go | 0 .../03-connection/{ => types}/tests/types.go | 0 18 files changed, 510 insertions(+), 356 deletions(-) delete mode 100644 x/ibc/03-connection/codec.go rename x/ibc/03-connection/{ => keeper}/handshake.go (59%) rename x/ibc/03-connection/{manager.go => keeper/keeper.go} (52%) delete mode 100644 x/ibc/03-connection/keys.go delete mode 100644 x/ibc/03-connection/msgs.go delete mode 100644 x/ibc/03-connection/types.go create mode 100644 x/ibc/03-connection/types/codec.go create mode 100644 x/ibc/03-connection/types/connection.go create mode 100644 x/ibc/03-connection/types/errors.go create mode 100644 x/ibc/03-connection/types/events.go create mode 100644 x/ibc/03-connection/types/expected_keepers.go create mode 100644 x/ibc/03-connection/types/handshake.go create mode 100644 x/ibc/03-connection/types/keys.go create mode 100644 x/ibc/03-connection/types/msgs.go rename x/ibc/03-connection/{ => types}/tests/connection_test.go (100%) rename x/ibc/03-connection/{ => types}/tests/types.go (100%) diff --git a/x/ibc/03-connection/client/utils/types.go b/x/ibc/03-connection/client/utils/types.go index 9e7e2c807b20..24eff8ae5e7c 100644 --- a/x/ibc/03-connection/client/utils/types.go +++ b/x/ibc/03-connection/client/utils/types.go @@ -2,27 +2,27 @@ package utils import ( connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) type JSONState struct { Connection connection.Connection `json:"connection"` - ConnectionProof commitment.Proof `json:"connection_proof,omitempty"` + ConnectionProof ics23.Proof `json:"connection_proof,omitempty"` Available bool `json:"available"` - AvailableProof commitment.Proof `json:"available_proof,omitempty"` + AvailableProof ics23.Proof `json:"available_proof,omitempty"` Kind string `json:"kind"` - KindProof commitment.Proof `json:"kind_proof,omitempty"` + KindProof ics23.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"` + State byte `json:"state,omitempty"` + StateProof ics23.Proof `json:"state_proof,omitempty"` + CounterpartyClient string `json:"counterparty_client,omitempty"` + CounterpartyClientProof ics23.Proof `json:"counterparty_client_proof,omitempty"` } func NewJSONState( - conn connection.Connection, connp commitment.Proof, - avail bool, availp commitment.Proof, - kind string, kindp commitment.Proof, + conn connection.Connection, connp ics23.Proof, + avail bool, availp ics23.Proof, + kind string, kindp ics23.Proof, ) JSONState { return JSONState{ Connection: conn, @@ -35,11 +35,11 @@ func NewJSONState( } 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, + conn connection.Connection, connp ics23.Proof, + avail bool, availp ics23.Proof, + kind string, kindp ics23.Proof, + state byte, statep ics23.Proof, + cpclient string, cpclientp ics23.Proof, ) JSONState { return JSONState{ Connection: conn, diff --git a/x/ibc/03-connection/codec.go b/x/ibc/03-connection/codec.go deleted file mode 100644 index a3e2284b38a8..000000000000 --- a/x/ibc/03-connection/codec.go +++ /dev/null @@ -1,24 +0,0 @@ -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 f516c0a5d6df..2085ca10403b 100644 --- a/x/ibc/03-connection/handler.go +++ b/x/ibc/03-connection/handler.go @@ -1,41 +1,121 @@ package connection import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" ) -func HandleMsgOpenInit(ctx sdk.Context, msg MsgOpenInit, man Handshaker) sdk.Result { - _, err := man.OpenInit(ctx, msg.ConnectionID, msg.Connection, msg.CounterpartyClient) +// NewHandler creates a new Handler instance for IBC connection +// transactions +func NewHandler(k keeper.Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + switch msg := msg.(type) { + case types.MsgConnectionOpenInit: + return handleMsgConnectionOpenInit(ctx, k, msg) + + case types.MsgConnectionOpenTry: + return handleMsgConnectionOpenTry(ctx, k, msg) + + case types.MsgConnectionOpenAck: + return handleMsgConnectionOpenAck(ctx, k, msg) + + case types.MsgConnectionOpenConfirm: + return handleMsgConnectionOpenConfirm(ctx, k, msg) + + default: + errMsg := fmt.Sprintf("unrecognized IBC connection message type: %T", msg) + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +func handleMsgConnectionOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenInit) sdk.Result { + _, err := k.ConnOpenInit(ctx, msg.ConnectionID, msg.ClientID, msg.Counterparty) if err != nil { - // TODO: Define the error code in errors - return sdk.NewError(sdk.CodespaceType("ibc"), 100, err.Error()).Result() + return sdk.ResultFromError(err) } - return sdk.Result{} + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeConnectionOpenInit, + sdk.NewAttribute(types.AttributeKeyConnectionID, msg.ConnectionID), + sdk.NewAttribute(types.AttributeKeyCounterpartyClientID, msg.Counterparty.ClientID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} } -func HandleMsgOpenTry(ctx sdk.Context, msg MsgOpenTry, man Handshaker) sdk.Result { - _, err := man.OpenTry(ctx, msg.Proofs, msg.Height, msg.ConnectionID, msg.Connection, msg.CounterpartyClient) +func handleMsgConnectionOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenTry) sdk.Result { + _, err := k.ConnOpenTry(ctx, msg.ConnectionID, msg.ClientID, msg.Counterparty, msg.Proofs, msg.Height) if err != nil { - // TODO: Define the error code in errors - return sdk.NewError(sdk.CodespaceType("ibc"), 200, err.Error()).Result() + return sdk.ResultFromError(err) } - return sdk.Result{} + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeConnectionOpenTry, + sdk.NewAttribute(types.AttributeKeyConnectionID, msg.ConnectionID), + sdk.NewAttribute(types.AttributeKeyCounterpartyClientID, msg.Counterparty.ClientID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} } -func HandleMsgOpenAck(ctx sdk.Context, msg MsgOpenAck, man Handshaker) sdk.Result { - _, err := man.OpenAck(ctx, msg.Proofs, msg.Height, msg.ConnectionID) +func handleMsgConnectionOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenAck) sdk.Result { + _, err := k.OpenAck(ctx, msg.Proofs, msg.Height, msg.ConnectionID) if err != nil { - // TODO: Define the error code in errors - return sdk.NewError(sdk.CodespaceType("ibc"), 300, err.Error()).Result() + return sdk.ResultFromError(err) } - return sdk.Result{} + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeConnectionOpenAck, + sdk.NewAttribute(types.AttributeKeyConnectionID, msg.ConnectionID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} } -func HandleMsgOpenConfirm(ctx sdk.Context, msg MsgOpenConfirm, man Handshaker) sdk.Result { - _, err := man.OpenConfirm(ctx, msg.Proofs, msg.Height, msg.ConnectionID) +func handleMsgConnectionOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenConfirm) sdk.Result { + _, err := k.OpenConfirm(ctx, msg.Proofs, msg.Height, msg.ConnectionID) if err != nil { - // TODO: Define the error code in errors - return sdk.NewError(sdk.CodespaceType("ibc"), 400, err.Error()).Result() + return sdk.ResultFromError(err) } - return sdk.Result{} + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeConnectionOpenConfirm, + sdk.NewAttribute(types.AttributeKeyConnectionID, msg.ConnectionID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} } diff --git a/x/ibc/03-connection/handshake.go b/x/ibc/03-connection/keeper/handshake.go similarity index 59% rename from x/ibc/03-connection/handshake.go rename to x/ibc/03-connection/keeper/handshake.go index 1abc0d03f434..8741e2b7b08d 100644 --- a/x/ibc/03-connection/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -1,4 +1,4 @@ -package connection +package tyoes import ( "errors" @@ -6,127 +6,90 @@ import ( "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -type HandshakeStage = byte - -const ( - Idle HandshakeStage = iota - Init - OpenTry - Open -) - -const HandshakeKind = "handshake" - -type Handshaker struct { - man Manager - - counterParty CounterpartyHandshaker -} - -func NewHandshaker(man Manager) Handshaker { - return Handshaker{ - man: man, - counterParty: CounterpartyHandshaker{man.counterparty}, - } -} - -type CounterpartyHandshaker struct { - man CounterpartyManager -} - type HandshakeState struct { State Stage state.Enum CounterpartyClient state.String - - Counterparty CounterHandshakeState + Counterparty CounterHandshakeState } type CounterHandshakeState struct { CounterState - Stage commitment.Enum - CounterpartyClient commitment.String + Stage ics23.Enum + CounterpartyClient ics23.String } // CONTRACT: client and remote must be filled by the caller -func (man Handshaker) CreateState(parent State) HandshakeState { +func (k Keeper) 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(), - - // CONTRACT: counterParty must be filled by the caller + Stage: k.man.protocol.Value([]byte(parent.id + "/state")).Enum(), + CounterpartyClient: k.man.protocol.Value([]byte(parent.id + "/counterpartyClient")).String(), } } 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(), + CounterState: k.man.CreateState(id), + Stage: k.man.protocol.Value([]byte(id + "/state")).Enum(), + CounterpartyClient: k.man.protocol.Value([]byte(id + "/counterpartyClient")).String(), } } -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) +func (k Keeper) create(ctx sdk.Context, id string, connection Connection, counterpartyClient string) (obj HandshakeState, err error) { + cobj, err := k.man.create(ctx, id, connection, HandshakeKind) if err != nil { return } - obj = man.CreateState(cobj) + obj = k.CreateState(cobj) obj.CounterpartyClient.Set(ctx, counterpartyClient) - obj.Counterparty = man.counterParty.CreateState(connection.Counterparty) + obj.Counterparty = k.CounterParty.CreateState(connection.Counterparty) return obj, nil } -func (man Handshaker) query(ctx sdk.Context, id string) (obj HandshakeState, err error) { - cobj, err := man.man.query(ctx, id, HandshakeKind) +func (k Keeper) query(ctx sdk.Context, id string) (obj HandshakeState, err error) { + cobj, err := k.man.query(ctx, id, HandshakeKind) if err != nil { return } - obj = man.CreateState(cobj) - obj.Counterparty = man.counterParty.CreateState(obj.GetConnection(ctx).Counterparty) + obj = k.CreateState(cobj) + obj.Counterparty = k.counterParty.CreateState(obj.GetConnection(ctx).Counterparty) return } -func (obj HandshakeState) remove(ctx sdk.Context) { - obj.State.remove(ctx) - obj.Stage.Delete(ctx) - obj.CounterpartyClient.Delete(ctx) -} - -// Using proofs: none -func (man Handshaker) OpenInit(ctx sdk.Context, - id string, connection Connection, counterpartyClient string, -) (HandshakeState, error) { +func (k Keeper) ConnOpenInit( + ctx sdk.Context, connectionID, clientID string, counterparty types.Counterparty, +) (HandshakeState, sdk.Error) { // man.Create() will ensure // assert(get("connections/{identifier}") === null) and // set("connections{identifier}", connection) - obj, err := man.create(ctx, id, connection, counterpartyClient) + + // connection := types.NewConnectionEnd(types.INIT, clientID, counterparty, []string{}) // TODO: getCompatibleVersions() + + obj, err := k.create(ctx, id, connection, counterpartyClient) if err != nil { return HandshakeState{}, err } - obj.Stage.Set(ctx, Init) - return obj, nil } // Using proofs: counterParty.{connection,state,nextTimeout,counterpartyClient, client} -func (man Handshaker) OpenTry(ctx sdk.Context, - proofs []commitment.Proof, height uint64, - id string, connection Connection, counterpartyClient string, +func (k Keeper) ConnOpenTry(ctx sdk.Context, connectionID, clientID string, counterparty types.Counterparty, ) (obj HandshakeState, err error) { - obj, err = man.create(ctx, id, connection, counterpartyClient) + + obj, err = k.create(ctx, id, connection, counterpartyClient) if err != nil { return } - ctx, err = obj.Context(ctx, height, proofs) + ctx, err = k.Context(ctx, height, proofs) if err != nil { return } @@ -172,8 +135,8 @@ func (man Handshaker) OpenTry(ctx sdk.Context, } // Using proofs: counterParty.{connection, state, timeout, counterpartyClient, client} -func (man Handshaker) OpenAck(ctx sdk.Context, - proofs []commitment.Proof, height uint64, +func (k Keeper) OpenAck(ctx sdk.Context, + proofs []ics23.Proof, height uint64, id string, ) (obj HandshakeState, err error) { obj, err = man.query(ctx, id) @@ -224,8 +187,8 @@ func (man Handshaker) OpenAck(ctx sdk.Context, } // Using proofs: counterParty.{connection,state, nextTimeout} -func (man Handshaker) OpenConfirm(ctx sdk.Context, - proofs []commitment.Proof, height uint64, +func (k Keeper) OpenConfirm(ctx sdk.Context, + proofs []ics23.Proof, height uint64, id string) (obj HandshakeState, err error) { obj, err = man.query(ctx, id) diff --git a/x/ibc/03-connection/manager.go b/x/ibc/03-connection/keeper/keeper.go similarity index 52% rename from x/ibc/03-connection/manager.go rename to x/ibc/03-connection/keeper/keeper.go index d8d5fdb41bbf..d5551222ed37 100644 --- a/x/ibc/03-connection/manager.go +++ b/x/ibc/03-connection/keeper/keeper.go @@ -7,87 +7,90 @@ import ( "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" - client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -type Manager struct { - protocol state.Mapping - client client.Manager +// Keeper defines the IBC connection keeper +type Keeper struct { + mapping state.Mapping + clientKeeper types.ClientKeeper + counterparty CounterpartyManager path merkle.Prefix } -func NewManager(protocol state.Mapping, client client.Manager) Manager { - return Manager{ - protocol: protocol.Prefix(LocalRoot()), - client: client, - counterparty: NewCounterpartyManager(protocol.Cdc()), - path: merkle.NewPrefix([][]byte{[]byte(protocol.StoreName())}, protocol.PrefixBytes()), +// NewKeeper creates a new IBC connection Keeper instance +func NewKeeper(mapping state.Mapping, ck types.ClientKeeper) Keeper { + return Keeper{ + mapping: mapping.Prefix([]byte(types.SubModuleName + "/")), + clientKeeper: ck, + counterparty: NewCounterpartyManager(mapping.Cdc()), + path: merkle.NewPrefix([][]byte{[]byte(mapping.StoreName())}, mapping.PrefixBytes()), } } type CounterpartyManager struct { - protocol commitment.Mapping + mapping commitment.Mapping - client client.CounterpartyManager + client ics02.CounterpartyManager } func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { - protocol := commitment.NewMapping(cdc, nil) + mapping := commitment.NewMapping(cdc, nil) return CounterpartyManager{ - protocol: protocol.Prefix(LocalRoot()), + mapping: mapping.Prefix([]byte(types.SubModuleName + "/")), - client: client.NewCounterpartyManager(cdc), + client: ics02.NewCounterpartyManager(cdc), } } type State struct { id string - protocol state.Mapping + mapping state.Mapping Connection state.Value Available state.Boolean Kind state.String - Client client.State + Client ics02.State path merkle.Prefix } // CONTRACT: client must be filled by the caller -func (man Manager) State(id string) State { +func (k Keeper) State(id string) State { return State{ id: id, - protocol: man.protocol.Prefix([]byte(id + "/")), - Connection: man.protocol.Value([]byte(id)), - Available: man.protocol.Value([]byte(id + "/available")).Boolean(), - Kind: man.protocol.Value([]byte(id + "/kind")).String(), - path: man.path, + mapping: k.mapping.Prefix([]byte(id + "/")), + Connection: k.mapping.Value([]byte(id)), + Available: k.mapping.Value([]byte(id + "/available")).Boolean(), + Kind: k.mapping.Value([]byte(id + "/kind")).String(), + path: k.path, } } type CounterState struct { id string - protocol commitment.Mapping + mapping commitment.Mapping Connection commitment.Value Available commitment.Boolean Kind commitment.String - Client client.CounterState // nolint: unused + Client ics02.CounterState // nolint: unused } // CreateState creates a new CounterState instance. // CONTRACT: client should be filled by the caller -func (man CounterpartyManager) CreateState(id string) CounterState { +func (k CounterpartyManager) CreateState(id string) CounterState { return CounterState{ id: id, - protocol: man.protocol.Prefix([]byte(id + "/")), - Connection: man.protocol.Value([]byte(id)), - Available: man.protocol.Value([]byte(id + "/available")).Boolean(), - Kind: man.protocol.Value([]byte(id + "/kind")).String(), + mapping: k.mapping.Prefix([]byte(id + "/")), + Connection: k.mapping.Value([]byte(id)), + Available: k.mapping.Value([]byte(id + "/available")).Boolean(), + Kind: k.mapping.Value([]byte(id + "/kind")).String(), } } @@ -113,7 +116,7 @@ func (state State) ID() string { return state.id } -func (state State) GetConnection(ctx sdk.Context) (res Connection) { +func (state State) GetConnection(ctx sdk.Context) (res types.ConnectionEnd) { state.Connection.Get(ctx, &res) return } @@ -126,27 +129,21 @@ func (state State) Receivable(ctx sdk.Context) bool { return kinds[state.Kind.Get(ctx)].Receivable } -func (state State) remove(ctx sdk.Context) { - state.Connection.Delete(ctx) - state.Available.Delete(ctx) - state.Kind.Delete(ctx) -} - func (state State) exists(ctx sdk.Context) bool { return state.Connection.Exists(ctx) } -func (man Manager) Cdc() *codec.Codec { - return man.protocol.Cdc() +func (k Keeper) Cdc() *codec.Codec { + return k.mapping.Cdc() } -func (man Manager) create(ctx sdk.Context, id string, connection Connection, kind string) (state State, err error) { - state = man.State(id) +func (k Keeper) create(ctx sdk.Context, id string, connection Connection, kind string) (state State, err error) { + state = k.State(id) if state.exists(ctx) { err = errors.New("Stage already exists") return } - state.Client, err = man.client.Query(ctx, connection.Client) + state.Client, err = k.client.Query(ctx, connection.Client) if err != nil { return } @@ -158,14 +155,14 @@ 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) (state State, err error) { - state = man.State(id) +func (k Keeper) query(ctx sdk.Context, id string, kind string) (state State, err error) { + state = k.State(id) if !state.exists(ctx) { err = errors.New("Stage not exists") return } - state.Client, err = man.client.Query(ctx, state.GetConnection(ctx).Client) + state.Client, err = k.client.Query(ctx, state.GetConnection(ctx).Client) if err != nil { return } @@ -178,8 +175,8 @@ func (man Manager) query(ctx sdk.Context, id string, kind string) (state State, return } -func (man Manager) Query(ctx sdk.Context, id string) (state State, err error) { - state = man.State(id) +func (k Keeper) Query(ctx sdk.Context, id string) (state State, err error) { + state = k.State(id) if !state.exists(ctx) { err = errors.New("Stage not exists") return @@ -190,6 +187,6 @@ func (man Manager) Query(ctx sdk.Context, id string) (state State, err error) { return } - state.Client, err = man.client.Query(ctx, state.GetConnection(ctx).Client) + state.Client, err = k.client.Query(ctx, state.GetConnection(ctx).Client) return } diff --git a/x/ibc/03-connection/keys.go b/x/ibc/03-connection/keys.go deleted file mode 100644 index 3ce706ab0bc7..000000000000 --- a/x/ibc/03-connection/keys.go +++ /dev/null @@ -1,5 +0,0 @@ -package connection - -func LocalRoot() []byte { - return []byte("connection/") -} diff --git a/x/ibc/03-connection/msgs.go b/x/ibc/03-connection/msgs.go deleted file mode 100644 index 5848558554b0..000000000000 --- a/x/ibc/03-connection/msgs.go +++ /dev/null @@ -1,132 +0,0 @@ -package connection - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -const Route = "ibc" - -type MsgOpenInit struct { - 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{} - -func (msg MsgOpenInit) Route() string { - return Route -} - -func (msg MsgOpenInit) Type() string { - return "open-init" -} - -func (msg MsgOpenInit) ValidateBasic() sdk.Error { - return nil // TODO -} - -func (msg MsgOpenInit) GetSignBytes() []byte { - return sdk.MustSortJSON(MsgCdc.MustMarshalJSON(msg)) -} - -func (msg MsgOpenInit) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} - -type MsgOpenTry struct { - 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{} - -func (msg MsgOpenTry) Route() string { - return Route -} - -func (msg MsgOpenTry) Type() string { - return "open-try" -} - -func (msg MsgOpenTry) ValidateBasic() sdk.Error { - return nil // TODO -} - -func (msg MsgOpenTry) GetSignBytes() []byte { - return sdk.MustSortJSON(MsgCdc.MustMarshalJSON(msg)) -} - -func (msg MsgOpenTry) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} - -type MsgOpenAck struct { - 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{} - -func (msg MsgOpenAck) Route() string { - return Route -} - -func (msg MsgOpenAck) Type() string { - return "open-ack" -} - -func (msg MsgOpenAck) ValidateBasic() sdk.Error { - return nil // TODO -} - -func (msg MsgOpenAck) GetSignBytes() []byte { - return sdk.MustSortJSON(MsgCdc.MustMarshalJSON(msg)) -} - -func (msg MsgOpenAck) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} - -type MsgOpenConfirm struct { - 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{} - -func (msg MsgOpenConfirm) Route() string { - return Route -} - -func (msg MsgOpenConfirm) Type() string { - return "open-confirm" -} - -func (msg MsgOpenConfirm) ValidateBasic() sdk.Error { - return nil // TODO -} - -func (msg MsgOpenConfirm) GetSignBytes() []byte { - return nil // TODO -} - -func (msg MsgOpenConfirm) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} diff --git a/x/ibc/03-connection/types.go b/x/ibc/03-connection/types.go deleted file mode 100644 index 199bee022ade..000000000000 --- a/x/ibc/03-connection/types.go +++ /dev/null @@ -1,39 +0,0 @@ -package connection - -import ( - /* - "errors" - "strings" - */ - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -type Connection struct { - Client string `json:"client"` - Counterparty string `json:"counterParty"` - Path commitment.Prefix `json:"path"` -} - -/* -func (conn Connection) MarshalAmino() (string, error) { - return strings.Join([]string{conn.Client, conn.Counterparty}, "/"), nil -} - -func (conn *Connection) UnmarshalAmino(text string) (err error) { - fields := strings.Split(text, "/") - if len(fields) < 2 { - return errors.New("not enough number of fields") - } - conn.Client = fields[0] - conn.Counterparty = fields[1] - return nil -} -*/ -var kinds = map[string]Kind{ - "handshake": Kind{true, true}, -} - -type Kind struct { - Sendable bool - Receivable bool -} diff --git a/x/ibc/03-connection/types/codec.go b/x/ibc/03-connection/types/codec.go new file mode 100644 index 000000000000..81758fa41f3c --- /dev/null +++ b/x/ibc/03-connection/types/codec.go @@ -0,0 +1,18 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +var SubModuleCdc *codec.Codec + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(MsgConnectionOpenInit{}, "ibc/connection/MsgConnectionOpenInit", nil) + cdc.RegisterConcrete(MsgConnectionOpenTry{}, "ibc/connection/MsgConnectionOpenTry", nil) + cdc.RegisterConcrete(MsgConnectionOpenAck{}, "ibc/connection/MsgConnectionOpenAck", nil) + cdc.RegisterConcrete(MsgConnectionOpenConfirm{}, "ibc/connection/MsgConnectionOpenConfirm", nil) +} + +func SetMsgConnectionCodec(cdc *codec.Codec) { + SubModuleCdc = cdc +} diff --git a/x/ibc/03-connection/types/connection.go b/x/ibc/03-connection/types/connection.go new file mode 100644 index 000000000000..7284a55a4331 --- /dev/null +++ b/x/ibc/03-connection/types/connection.go @@ -0,0 +1,60 @@ +package types + +import ( + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +// ICS03 - Connection Data Structures as defined in https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#data-structures + +// ConnectionState defines the state of a connection between two disctinct +// chains +type ConnectionState = byte + +// available ConnectionStates +const ( + NONE ConnectionState = iota // default State + INIT + TRYOPEN + OPEN +) + +// ConnectionEnd defines a stateful object on a chain connected to another separate +// one. +// NOTE: there must only be 2 defined ConnectionEnds to stablish a connection +// between two chains. +type ConnectionEnd struct { + State ConnectionState `json:"state" yaml:"state"` + ClientID string `json:"client" yaml:"client"` + + // Counterparty chain associated with this connection. + Counterparty Counterparty `json:"counterparty" yaml:"counterparty"` + // Version is utilised to determine encodings or protocols for channels or + // packets utilising this connection. + Versions []string `json:"versions" yaml:"versions"` +} + +// NewConnectionEnd creates a new ConnectionEnd instance. +func NewConnectionEnd(state ConnectionState, clientID string, counterparty Counterparty, versions []string) ConnectionEnd { + return ConnectionEnd{ + State: state, + ClientID: clientID, + Counterparty: counterparty, + Versions: versions, + } +} + +// Counterparty defines the counterparty chain associated with a connection end. +type Counterparty struct { + ClientID string `json:"client_id" yaml:"client_id"` + ConnectionID string `json:"connection_id" yaml:"connection_id"` + Prefix ics23.Prefix `json:"prefix" yaml:"prefix` +} + +// NewCounterparty creates a new Counterparty instance. +func NewCounterparty(clientID, connectionID string, prefix ics23.Prefix) Counterparty { + return Counterparty{ + ClientID: clientID, + ConnectionID: connectionID, + Prefix: prefix, + } +} diff --git a/x/ibc/03-connection/types/errors.go b/x/ibc/03-connection/types/errors.go new file mode 100644 index 000000000000..4c77d2dffe0a --- /dev/null +++ b/x/ibc/03-connection/types/errors.go @@ -0,0 +1,36 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// client error codes +const ( + DefaultCodespace sdk.CodespaceType = SubModuleName + + CodeClientExists sdk.CodeType = 101 + CodeClientNotFound sdk.CodeType = 102 + CodeClientFrozen sdk.CodeType = 103 + CodeInvalidConsensus sdk.CodeType = 104 + CodeValidatorJailed sdk.CodeType = 104 +) + +// ErrClientExists implements sdk.Error +func ErrClientExists(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeClientExists, "client already exists") +} + +// ErrClientNotFound implements sdk.Error +func ErrClientNotFound(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeClientNotFound, "client not found") +} + +// ErrClientFrozen implements sdk.Error +func ErrClientFrozen(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeClientFrozen, "client is frozen due to misbehaviour") +} + +// ErrInvalidConsensus implements sdk.Error +func ErrInvalidConsensus(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidConsensus, "invalid consensus algorithm type") +} diff --git a/x/ibc/03-connection/types/events.go b/x/ibc/03-connection/types/events.go new file mode 100644 index 000000000000..5dece7400bdb --- /dev/null +++ b/x/ibc/03-connection/types/events.go @@ -0,0 +1,23 @@ +package types + +import ( + "fmt" + + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// IBC connection events +const ( + EventTypeConnectionOpenInit = "connection_open_init" + EventTypeConnectionOpenTry = "connection_open_try" + EventTypeConnectionOpenAck = "connection_open_ack" + EventTypeConnectionOpenConfirm = "connection_open_confirm" + + AttributeKeyConnectionID = "connection_id" + AttributeKeyCounterpartyClientID = "counterparty_client_id" +) + +// IBC connection events vars +var ( + AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, SubModuleName) +) diff --git a/x/ibc/03-connection/types/expected_keepers.go b/x/ibc/03-connection/types/expected_keepers.go new file mode 100644 index 000000000000..98c5e40430a2 --- /dev/null +++ b/x/ibc/03-connection/types/expected_keepers.go @@ -0,0 +1,5 @@ +package types + +// ClientKeeper expected account IBC client keeper +type ClientKeeper interface { +} diff --git a/x/ibc/03-connection/types/handshake.go b/x/ibc/03-connection/types/handshake.go new file mode 100644 index 000000000000..2717f7cfe60e --- /dev/null +++ b/x/ibc/03-connection/types/handshake.go @@ -0,0 +1,7 @@ +package types + +// Handshake defines a connection between two chains A and B +type Handshake struct { + ConnA ConnectionEnd + ConnB ConnectionEnd +} diff --git a/x/ibc/03-connection/types/keys.go b/x/ibc/03-connection/types/keys.go new file mode 100644 index 000000000000..4631e8cc7966 --- /dev/null +++ b/x/ibc/03-connection/types/keys.go @@ -0,0 +1,6 @@ +package types + +const ( + // SubModuleName defines the IBC connection name + SubModuleName = "connection" +) diff --git a/x/ibc/03-connection/types/msgs.go b/x/ibc/03-connection/types/msgs.go new file mode 100644 index 000000000000..f6d19317a9af --- /dev/null +++ b/x/ibc/03-connection/types/msgs.go @@ -0,0 +1,159 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +var _ sdk.Msg = MsgConnectionOpenInit{} + +// MsgConnectionOpenInit defines the msg sent by an account on Chain A to +// initialize a connection with Chain B. +type MsgConnectionOpenInit struct { + ConnectionID string `json:"connection_id"` + ClientID string `json:"client_id"` + Counterparty Counterparty `json:"counterparty"` + NextTimeout uint64 `json:"next_timeout"` // TODO: Where is this defined? + Signer sdk.AccAddress `json:"signer"` +} + +// Route implements sdk.Msg +func (msg MsgConnectionOpenInit) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgConnectionOpenInit) Type() string { + return "connection_open_init" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgConnectionOpenInit) ValidateBasic() sdk.Error { + return nil // TODO +} + +// GetSignBytes implements sdk.Msg +func (msg MsgConnectionOpenInit) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgConnectionOpenInit) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgConnectionOpenTry{} + +// MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a connection +// on Chain B. +type MsgConnectionOpenTry struct { + ConnectionID string `json:"connection_id"` + ClientID string `json:"client_id"` + Counterparty Counterparty `json:"counterparty"` + CounterpartyVersions []string `json:"counterparty_versions"` // TODO: why wasn't this defined previously? + Proofs []ics23.Proof `json:"proofs"` // Contains a Proof of the initialization the connection on Chain A + Height uint64 `json:"height"` // TODO: Rename to ProofHeight? Is this supposed to be the same as ConsensusHeight? + // ConsensusHeight uint64 `json:"consensus_height"` + Signer sdk.AccAddress `json:"signer"` +} + +// Route implements sdk.Msg +func (msg MsgConnectionOpenTry) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgConnectionOpenTry) Type() string { + return "connection_open_try" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgConnectionOpenTry) ValidateBasic() sdk.Error { + return nil // TODO +} + +// GetSignBytes implements sdk.Msg +func (msg MsgConnectionOpenTry) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgConnectionOpenTry) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgConnectionOpenAck{} + +// MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to acknowledge +// the change of connection state to TRYOPEN on Chain B. +type MsgConnectionOpenAck struct { + ConnectionID string `json:"connection_id"` + Timeout uint64 `json:"timeout"` // TODO: Where's this defined ? + NextTimeout uint64 `json:"next_timeout"` // TODO: Where's this defined ? + Proofs []ics23.Proof `json:"proofs"` // Contains a Proof for the change of the connection state on Chain B: `none -> TRYOPEN` + ConsensusHeight uint64 `json:"consensus_height"` + Signer sdk.AccAddress `json:"signer"` +} + +// Route implements sdk.Msg +func (msg MsgConnectionOpenAck) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgConnectionOpenAck) Type() string { + return "connection_open_ack" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgConnectionOpenAck) ValidateBasic() sdk.Error { + return nil // TODO +} + +// GetSignBytes implements sdk.Msg +func (msg MsgConnectionOpenAck) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgConnectionOpenAck) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgConnectionOpenConfirm{} + +// MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to acknowledge +// the change of connection state to OPEN on Chain A. +type MsgConnectionOpenConfirm struct { + ConnectionID string `json:"connection_id"` + Timeout uint64 `json:"timeout"` // TODO: Where's this defined ? + Proofs []ics23.Proof `json:"proofs"` // Contains a Proof for the change of the connection state on Chain A: `INIT -> OPEN` + Height uint64 `json:"height"` // TODO: Rename to ProofHeight? + Signer sdk.AccAddress `json:"signer"` +} + +// Route implements sdk.Msg +func (msg MsgConnectionOpenConfirm) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgConnectionOpenConfirm) Type() string { + return "connection_open_confirm" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgConnectionOpenConfirm) ValidateBasic() sdk.Error { + return nil // TODO +} + +// GetSignBytes implements sdk.Msg +func (msg MsgConnectionOpenConfirm) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgConnectionOpenConfirm) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} diff --git a/x/ibc/03-connection/tests/connection_test.go b/x/ibc/03-connection/types/tests/connection_test.go similarity index 100% rename from x/ibc/03-connection/tests/connection_test.go rename to x/ibc/03-connection/types/tests/connection_test.go diff --git a/x/ibc/03-connection/tests/types.go b/x/ibc/03-connection/types/tests/types.go similarity index 100% rename from x/ibc/03-connection/tests/types.go rename to x/ibc/03-connection/types/tests/types.go From a7d2d987f74ab570ddf4ac7251db6cad84670ef9 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 7 Oct 2019 18:13:20 +0200 Subject: [PATCH 261/378] remove Mapping --- x/ibc/23-commitment/codec.go | 2 +- x/ibc/23-commitment/context.go | 2 +- x/ibc/23-commitment/merkle/merkle.go | 28 ++--- x/ibc/23-commitment/merkle/merkle_test.go | 12 +- x/ibc/23-commitment/merkle/utils.go | 2 +- x/ibc/23-commitment/store.go | 2 +- x/ibc/23-commitment/types.go | 2 +- x/ibc/23-commitment/utils.go | 8 -- x/ibc/23-commitment/value.go | 127 ---------------------- 9 files changed, 20 insertions(+), 165 deletions(-) delete mode 100644 x/ibc/23-commitment/utils.go delete mode 100644 x/ibc/23-commitment/value.go diff --git a/x/ibc/23-commitment/codec.go b/x/ibc/23-commitment/codec.go index 943f8ede8b7e..7312c5942d85 100644 --- a/x/ibc/23-commitment/codec.go +++ b/x/ibc/23-commitment/codec.go @@ -1,4 +1,4 @@ -package commitment +package ics23 import ( "github.com/cosmos/cosmos-sdk/codec" diff --git a/x/ibc/23-commitment/context.go b/x/ibc/23-commitment/context.go index a0404e2a8927..af3f300ef9f2 100644 --- a/x/ibc/23-commitment/context.go +++ b/x/ibc/23-commitment/context.go @@ -1,4 +1,4 @@ -package commitment +package ics23 import ( sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index f310ac948151..bef5e7c6951b 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -1,15 +1,13 @@ package merkle import ( - "bytes" "errors" "github.com/tendermint/tendermint/crypto/merkle" "github.com/cosmos/cosmos-sdk/store/rootmulti" - // "github.com/cosmos/cosmos-sdk/store/state" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // ICS 023 Merkle Types Implementation @@ -20,7 +18,7 @@ const merkleKind = "merkle" // merkle.Proof implementation of Proof // Applied on SDK-based IBC implementation -var _ commitment.Root = Root{} +var _ ics23.Root = Root{} // Root is Merkle root hash // In Cosmos-SDK, the AppHash of the Header becomes Root. @@ -35,12 +33,12 @@ func NewRoot(hash []byte) Root { } } -// Implements commitment.Root +// Implements ics23.Root func (Root) CommitmentKind() string { return merkleKind } -var _ commitment.Prefix = Prefix{} +var _ ics23.Prefix = Prefix{} // Prefix is merkle path prefixed to the key. // The constructed key from the Path and the key will be append(Path.KeyPath, append(Path.KeyPrefix, key...)) @@ -59,7 +57,7 @@ func NewPrefix(keypath [][]byte, keyprefix []byte) Prefix { } } -// Implements commitment.Prefix +// Implements ics23.Prefix func (Prefix) CommitmentKind() string { return merkleKind } @@ -68,7 +66,7 @@ func (prefix Prefix) Key(key []byte) []byte { return join(prefix.KeyPrefix, key) } -var _ commitment.Proof = Proof{} +var _ ics23.Proof = Proof{} // Proof is Merkle proof with the key information. type Proof struct { @@ -76,7 +74,7 @@ type Proof struct { Key []byte `json:"key"` } -// Implements commitment.Proof +// Implements ics23.Proof func (Proof) CommitmentKind() string { return merkleKind } @@ -86,8 +84,8 @@ func (proof Proof) GetKey() []byte { return proof.Key } -// Verify() proves the proof against the given root, path, and value. -func (proof Proof) Verify(croot commitment.Root, cpath commitment.Prefix, value []byte) error { +// Verify proves the proof against the given root, path, and value. +func (proof Proof) Verify(croot ics23.Root, cpath ics23.Prefix, value []byte) error { root, ok := croot.(Root) if !ok { return errors.New("invalid commitment root type") @@ -112,11 +110,3 @@ func (proof Proof) Verify(croot commitment.Root, cpath commitment.Prefix, value } return runtime.VerifyAbsence(proof.Proof, root.Hash, keypath.String()) } - -type Value interface { - KeyBytes() []byte -} - -func NewProofFromValue(proof *merkle.Proof, prefix []byte, value Value) Proof { - return Proof{proof, bytes.TrimPrefix(value.KeyBytes(), prefix)} -} diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index fd550d43da53..0c73e7676ce8 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -16,7 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) func defaultComponents() (sdk.StoreKey, sdk.Context, types.CommitMultiStore, *codec.Codec) { @@ -38,7 +38,7 @@ func commit(cms types.CommitMultiStore) Root { return NewRoot(cid.Hash) } -// TestStore tests Merkle proof on the commitment.Store +// TestStore tests Merkle proof on the ics23.Store // Sets/upates key-value pairs and prove with the query result proofs func TestStore(t *testing.T) { k, ctx, cms, cdc := defaultComponents() @@ -66,7 +66,7 @@ func TestStore(t *testing.T) { root := commit(cms) // Test query, and accumulate proofs - proofs := make([]commitment.Proof, 0, kvpn) + proofs := make([]ics23.Proof, 0, kvpn) for k, v := range m { q := state.NewStoreQuerier(cms.(types.Queryable)) v0, p, err := mapp.Value([]byte(k)).QueryRaw(q) @@ -87,7 +87,7 @@ func TestStore(t *testing.T) { m[string(k)] = []byte{} } - cstore, err := commitment.NewStore(root, path, proofs) + cstore, err := ics23.NewStore(root, path, proofs) require.NoError(t, err) // Test commitment store @@ -110,7 +110,7 @@ func TestStore(t *testing.T) { root = commit(cms) // Test query, and accumulate proofs - proofs = make([]commitment.Proof, 0, kvpn) + proofs = make([]ics23.Proof, 0, kvpn) for k, v := range m { q := state.NewStoreQuerier(cms.(types.Queryable)) v0, p, err := mapp.Value([]byte(k)).QueryRaw(q) @@ -119,7 +119,7 @@ func TestStore(t *testing.T) { proofs = append(proofs, Proof{Key: []byte(k), Proof: p}) } - cstore, err = commitment.NewStore(root, path, proofs) + cstore, err = ics23.NewStore(root, path, proofs) require.NoError(t, err) // Test commitment store diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index ec933af09748..64baf2d7c67c 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -11,7 +11,7 @@ import ( func QueryMultiStore(cms types.CommitMultiStore, storeName string, prefix []byte, key []byte) ([]byte, Proof, error) { queryable, ok := cms.(types.Queryable) if !ok { - panic("CommitMultiStore not queryable") + panic("commitMultiStore not queryable") } qres := queryable.Query(RequestQueryMultiStore(storeName, prefix, key)) if !qres.IsOK() { diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 1ced699258fd..633ded2cbc20 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -1,4 +1,4 @@ -package commitment +package ics23 import ( "bytes" diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go index 0e8a5db04d07..bba7711bb32f 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/types.go @@ -1,4 +1,4 @@ -package commitment +package ics23 // ICS 023 Types Implementation // diff --git a/x/ibc/23-commitment/utils.go b/x/ibc/23-commitment/utils.go deleted file mode 100644 index e49dc15319a0..000000000000 --- a/x/ibc/23-commitment/utils.go +++ /dev/null @@ -1,8 +0,0 @@ -package commitment - -func join(a, b []byte) (res []byte) { - res = make([]byte, len(a)+len(b)) - copy(res, a) - copy(res[len(a):], b) - return -} diff --git a/x/ibc/23-commitment/value.go b/x/ibc/23-commitment/value.go deleted file mode 100644 index 5797e1cd13c9..000000000000 --- a/x/ibc/23-commitment/value.go +++ /dev/null @@ -1,127 +0,0 @@ -package commitment - -import ( - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/state" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// Mapping is key []byte -> value []byte mapping, possibly prefixed. -// Proof verification should be done over Value constructed from the Mapping. -type Mapping struct { - cdc *codec.Codec - prefix []byte -} - -// NewMapping() constructs a new Mapping. -// The KVStore accessor is fixed to the commitment store. -func NewMapping(cdc *codec.Codec, prefix []byte) Mapping { - return Mapping{ - cdc: cdc, - prefix: prefix, - } -} - -func (m Mapping) store(ctx sdk.Context) Store { - return NewPrefix(GetStore(ctx), m.prefix) -} - -// Prefix() returns a new Mapping with the updated prefix -func (m Mapping) Prefix(prefix []byte) Mapping { - return Mapping{ - cdc: m.cdc, - prefix: join(m.prefix, prefix), - } -} - -type Indexer struct { - Mapping - enc state.IntEncoding -} - -func (m Mapping) Indexer(enc state.IntEncoding) Indexer { - return Indexer{ - Mapping: m, - enc: enc, - } -} - -func (ix Indexer) Value(index uint64) Value { - return ix.Mapping.Value(state.EncodeInt(index, ix.enc)) -} - -type Value struct { - m Mapping - key []byte -} - -func (m Mapping) Value(key []byte) Value { - return Value{m, key} -} - -// Is() proves the proof with the Value's key and the provided value. -func (v Value) Is(ctx sdk.Context, value interface{}) bool { - return v.m.store(ctx).Prove(v.key, v.m.cdc.MustMarshalBinaryBare(value)) -} - -// 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) -} - -// Enum is a byte typed wrapper for Value. -// Except for the type checking, it does not alter the behaviour. -type Enum struct { - Value -} - -// Enum() wraps the argument Value as Enum -func (v Value) Enum() Enum { - return Enum{v} -} - -// Is() proves the proof with the Enum's key and the provided value -func (v Enum) Is(ctx sdk.Context, value byte) bool { - return v.Value.IsRaw(ctx, []byte{value}) -} - -type String struct { - Value -} - -func (v Value) String() String { - return String{v} -} - -func (v String) Is(ctx sdk.Context, value string) bool { - return v.Value.IsRaw(ctx, []byte(value)) -} - -type Boolean struct { - Value -} - -func (v Value) Boolean() Boolean { - return Boolean{v} -} - -func (v Boolean) Is(ctx sdk.Context, value bool) bool { - return v.Value.Is(ctx, value) -} - -// Integer is a uint64 types wrapper for Value. -type Integer struct { - Value - - enc state.IntEncoding -} - -// Integer() wraps the argument Value as Integer -func (v Value) Integer(enc state.IntEncoding) Integer { - return Integer{v, enc} -} - -// Is() proves the proof with the Integer's key and the provided value -func (v Integer) Is(ctx sdk.Context, value uint64) bool { - return v.Value.IsRaw(ctx, state.EncodeInt(value, v.enc)) -} \ No newline at end of file From 1b7e4660b8f7bbaa4d8441bfaacbbd702f88cb9d Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 7 Oct 2019 18:15:15 +0200 Subject: [PATCH 262/378] remove store accessors --- store/state/boolean.go | 38 --- store/state/enum.go | 63 ----- store/state/errors.go | 64 ----- store/state/indexer.go | 125 ---------- store/state/integer.go | 67 ----- store/state/mapping.go | 103 -------- store/state/mapping_test.go | 123 ---------- store/state/string.go | 38 --- store/state/types.go | 61 ----- store/state/value.go | 126 ---------- store/state/value_test.go | 353 --------------------------- x/ibc/23-commitment/merkle/merkle.go | 2 +- x/ibc/23-commitment/merkle/utils.go | 10 +- x/ibc/23-commitment/store.go | 9 +- 14 files changed, 11 insertions(+), 1171 deletions(-) delete mode 100644 store/state/boolean.go delete mode 100644 store/state/enum.go delete mode 100644 store/state/errors.go delete mode 100644 store/state/indexer.go delete mode 100644 store/state/integer.go delete mode 100644 store/state/mapping.go delete mode 100644 store/state/mapping_test.go delete mode 100644 store/state/string.go delete mode 100644 store/state/types.go delete mode 100644 store/state/value.go delete mode 100644 store/state/value_test.go diff --git a/store/state/boolean.go b/store/state/boolean.go deleted file mode 100644 index 669b7ae85e8d..000000000000 --- a/store/state/boolean.go +++ /dev/null @@ -1,38 +0,0 @@ -package state - -// Boolean is a bool typed wrapper for Value. -// -// false <-> []byte{0x00} -// true <-> []byte{0x01} -type Boolean struct { - Value -} - -func (v Value) Boolean() Boolean { - return Boolean{v} -} - -// Get decodes and returns the stored boolean value if it exists. It will panic -// if the value exists but is not boolean type. -func (v Boolean) Get(ctx Context) (res bool) { - v.Value.Get(ctx, &res) - return -} - -// GetSafe decodes and returns the stored boolean value. It will return an error -// if the value does not exist or not boolean. -func (v Boolean) GetSafe(ctx Context) (res bool, err error) { - err = v.Value.GetSafe(ctx, &res) - return -} - -// Set encodes and sets the boolean argument to the state. -func (v Boolean) Set(ctx Context, value bool) { - v.Value.Set(ctx, value) -} - -// Query() retrives state value and proof from a queryable reference -func (v Boolean) Query(q ABCIQuerier) (res bool, proof *Proof, err error) { - proof, err = v.Value.Query(q, &res) - return -} diff --git a/store/state/enum.go b/store/state/enum.go deleted file mode 100644 index 18937ce18bf7..000000000000 --- a/store/state/enum.go +++ /dev/null @@ -1,63 +0,0 @@ -package state - -import "errors" - -// Enum is a byte typed wrapper for Value. -// x <-> []byte{x} -type Enum struct { - Value -} - -func (v Value) Enum() Enum { - return Enum{v} -} - -// Get decodes and returns the stored byte value if it exists. It will panic if -// the value exists but is not byte type. -func (v Enum) Get(ctx Context) (res byte) { - return v.Value.GetRaw(ctx)[0] -} - -// GetSafe decodes and returns the stored byte value. It will returns an error -// if the value does not exists or not byte. -func (v Enum) GetSafe(ctx Context) (res byte, err error) { - bz := v.Value.GetRaw(ctx) - if bz == nil { - return res, ErrEmptyValue() - } - if len(bz) != 1 { - return res, ErrUnmarshal(errors.New("stored byte slice length is not 1")) - } - return bz[0], nil -} - -// Set encodes and sets the byte argument to the state. -func (v Enum) Set(ctx Context, value byte) { - v.Value.SetRaw(ctx, []byte{value}) -} - -// Incr increments the stored value, and returns the updated value. -func (v Enum) Incr(ctx Context) (res byte) { - res = v.Get(ctx) + 1 - v.Set(ctx, res) - return -} - -// Transit checks whether the stored value matching with the "from" argument. -// If it matches, it stores the "to" argument to the state and returns true. -func (v Enum) Transit(ctx Context, from, to byte) bool { - if v.Get(ctx) != from { - return false - } - v.Set(ctx, to) - return true -} - -// 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/errors.go b/store/state/errors.go deleted file mode 100644 index 303584c68bff..000000000000 --- a/store/state/errors.go +++ /dev/null @@ -1,64 +0,0 @@ -package state - -import ( - "fmt" -) - -// GetSafeErrorType is enum for indicating the type of error -type GetSafeErrorType byte - -const ( - // ErrTypeEmptyValue is used for nil byteslice values - ErrTypeEmptyValue GetSafeErrorType = iota - // ErrTypeUnmarshal is used for undeserializable values - ErrTypeUnmarshal -) - -// Implements Formatter -func (ty GetSafeErrorType) Format(msg string) (res string) { - switch ty { - case ErrTypeEmptyValue: - res = fmt.Sprintf("Empty Value found") - case ErrTypeUnmarshal: - res = fmt.Sprintf("Error while unmarshal") - default: - panic("Unknown error type") - } - - if msg != "" { - res = fmt.Sprintf("%s: %s", res, msg) - } - - return -} - -// GetSafeError is error type for GetSafe method -type GetSafeError struct { - ty GetSafeErrorType - inner error -} - -var _ error = GetSafeError{} - -// Implements error -func (err GetSafeError) Error() string { - if err.inner == nil { - return err.ty.Format("") - } - return err.ty.Format(err.inner.Error()) -} - -// ErrEmptyValue constructs GetSafeError with ErrTypeEmptyValue -func ErrEmptyValue() GetSafeError { - return GetSafeError{ - ty: ErrTypeEmptyValue, - } -} - -// ErrUnmarshal constructs GetSafeError with ErrTypeUnmarshal -func ErrUnmarshal(err error) GetSafeError { - return GetSafeError{ - ty: ErrTypeUnmarshal, - inner: err, - } -} diff --git a/store/state/indexer.go b/store/state/indexer.go deleted file mode 100644 index 3988e9503fe0..000000000000 --- a/store/state/indexer.go +++ /dev/null @@ -1,125 +0,0 @@ -package state - -import ( - "encoding/binary" - "fmt" - "strconv" -) - -// IntEncoding is an enum type defining the integer serialization scheme. -// All encoding schemes preserves order. -type IntEncoding byte - -const ( - // Dec is human readable decimal encoding scheme. - // Has fixed length of 20 bytes. - Dec IntEncoding = iota - // Hex is human readable hexadecimal encoding scheme - // Has fixed length of 16 bytes. - Hex - // Bin is machine readable big endian encoding scheme - // Has fixed length of 8 bytes - Bin -) - -// Indexer is a integer typed key wrapper for Mapping. Except for the type -// checking, it does not alter the behaviour. All keys are encoded depending on -// the IntEncoding. -type Indexer struct { - m Mapping - - enc IntEncoding -} - -// Indexer() constructs the Indexer with an IntEncoding -func (m Mapping) Indexer(enc IntEncoding) Indexer { - return Indexer{ - m: m, - enc: enc, - } -} - -// EncodeInt provides order preserving integer encoding function. -func EncodeInt(index uint64, enc IntEncoding) (res []byte) { - switch enc { - case Dec: - // return decimal number index, 20-length 0 padded - return []byte(fmt.Sprintf("%020d", index)) - - case Hex: - // return hexadecimal number index, 20-length 0 padded - return []byte(fmt.Sprintf("%016x", index)) - - case Bin: - // return bigendian encoded number index, 8-length - res = make([]byte, 8) - binary.BigEndian.PutUint64(res, index) - return - - default: - panic("invalid IntEncoding") - } -} - -// DecodeInt provides integer decoding function, inversion of EncodeInt. -func DecodeInt(bz []byte, enc IntEncoding) (res uint64, err error) { - switch enc { - case Dec: - return strconv.ParseUint(string(bz), 10, 64) - - case Hex: - return strconv.ParseUint(string(bz), 16, 64) - - case Bin: - return binary.BigEndian.Uint64(bz), nil - - default: - panic("invalid IntEncoding") - } -} - -// Value returns the Value corresponding to the provided index. -func (ix Indexer) Value(index uint64) Value { - return ix.m.Value(EncodeInt(index, ix.enc)) -} - -// Get decodes and sets the stored value to the pointer if it exists. It will -// panic if the value exists but not unmarshalable. -func (ix Indexer) Get(ctx Context, index uint64, ptr interface{}) { - ix.Value(index).Get(ctx, ptr) -} - -// GetSafe decodes and sets the stored value to the pointer. It will return an -// error if the value does not exist or unmarshalable. -func (ix Indexer) GetSafe(ctx Context, index uint64, ptr interface{}) error { - return ix.Value(index).GetSafe(ctx, ptr) -} - -// Set encodes and sets the argument to the state. -func (ix Indexer) Set(ctx Context, index uint64, o interface{}) { - ix.Value(index).Set(ctx, o) -} - -// SetRaw sets the raw bytestring argument to the state -func (ix Indexer) SetRaw(ctx Context, index uint64, value []byte) { - ix.Value(index).SetRaw(ctx, value) -} - -// Has returns true if the stored value is not nil. -func (ix Indexer) Has(ctx Context, index uint64) bool { - return ix.Value(index).Exists(ctx) -} - -// Delete removes the stored value. -func (ix Indexer) Delete(ctx Context, index uint64) { - ix.Value(index).Delete(ctx) -} - -// Prefix returns a new Indexer with the updated prefix -func (ix Indexer) Prefix(prefix []byte) Indexer { - return Indexer{ - m: ix.m.Prefix(prefix), - - enc: ix.enc, - } -} diff --git a/store/state/integer.go b/store/state/integer.go deleted file mode 100644 index 938b83fd1f46..000000000000 --- a/store/state/integer.go +++ /dev/null @@ -1,67 +0,0 @@ -package state - -// Integer is a uint64 types wrapper for Value. -// The serialization follows the @IntEncoding@ format provided to the NewInteger. -type Integer struct { - Value - - enc IntEncoding -} - -func (v Value) Integer(enc IntEncoding) Integer { - return Integer{v, enc} -} - -// Get() unmarshales and returns the stored uint64 value if it exists. -// If will panic if the value exists but not decodable. -func (v Integer) Get(ctx Context) uint64 { - bz := v.Value.GetRaw(ctx) - if bz == nil { - return 0 - } - res, err := DecodeInt(bz, v.enc) - if err != nil { - panic(err) - } - return res -} - -// GetSafe() unmarshales and returns the stored uint64 value. -// It will return an error if the value does not exist or not uint64. -func (v Integer) GetSafe(ctx Context) (res uint64, err error) { - bz := v.Value.GetRaw(ctx) - if bz == nil { - return 0, ErrEmptyValue() - } - res, err = DecodeInt(bz, v.enc) - if err != nil { - err = ErrUnmarshal(err) - } - return -} - -// Set() marshales and sets the uint64 argument to the state. -func (v Integer) Set(ctx Context, value uint64) { - v.Value.SetRaw(ctx, EncodeInt(value, v.enc)) -} - -// Increment increments the stored value and returns it. -func (v Integer) Increment(ctx Context) (res uint64) { - res = v.Get(ctx) + 1 - v.Set(ctx, res) - return -} - -// Query() retrives state value and proof from a queryable reference -func (v Integer) Query(q ABCIQuerier) (res uint64, proof *Proof, err error) { - value, proof, err := v.Value.QueryRaw(q) - if err != nil { - return - } - if value == nil { - res = 0 - return - } - res, err = DecodeInt(value, v.enc) - return -} diff --git a/store/state/mapping.go b/store/state/mapping.go deleted file mode 100644 index 3b81d2323efe..000000000000 --- a/store/state/mapping.go +++ /dev/null @@ -1,103 +0,0 @@ -package state - -import ( - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// Mapping is key []byte -> value []byte mapping using a base(possibly prefixed). -// All store accessing operations are redirected to the Value corresponding to -// the key argument. -type Mapping struct { - storeKey sdk.StoreKey - cdc *codec.Codec - prefix []byte -} - -// NewMapping constructs a Mapping with a provided prefix. -func NewMapping(storeKey sdk.StoreKey, cdc *codec.Codec, prefix []byte) Mapping { - return Mapping{ - storeKey: storeKey, - cdc: cdc, - prefix: prefix, - } -} - -// Value returns the Value corresponding to the provided key. -func (m Mapping) Value(key []byte) Value { - return NewValue(m, key) -} - -// Get decodes and sets the stored value to the pointer if it exists. It will -// panic if the value exists but not unmarshalable. -func (m Mapping) Get(ctx Context, key []byte, ptr interface{}) { - m.Value(key).Get(ctx, ptr) -} - -// GetSafe decodes and sets the stored value to the pointer. It will return an -// error if the value does not exist or unmarshalable. -func (m Mapping) GetSafe(ctx Context, key []byte, ptr interface{}) error { - return m.Value(key).GetSafe(ctx, ptr) -} - -// Set encodes and sets the argument to the state. It calls Delete if the -// argument is nil. -func (m Mapping) Set(ctx Context, key []byte, o interface{}) { - if o == nil { - m.Delete(ctx, key) - return - } - m.Value(key).Set(ctx, o) -} - -// SetRaw sets the raw bytestring argument to the state. -func (m Mapping) SetRaw(ctx Context, key []byte, value []byte) { - m.Value(key).SetRaw(ctx, value) -} - -// Has returns true if the stored value is not nil. -func (m Mapping) Has(ctx Context, key []byte) bool { - return m.Value(key).Exists(ctx) -} - -// Delete removes the stored value. -func (m Mapping) Delete(ctx Context, key []byte) { - m.Value(key).Delete(ctx) -} - -func (m Mapping) Cdc() *codec.Codec { - return m.cdc -} - -// StoreName returns the mapping's store name. -func (m Mapping) StoreName() string { - return m.storeKey.Name() -} - -// PrefixBytes returns the mapping's prefix bytes. -func (m Mapping) PrefixBytes() (res []byte) { - res = make([]byte, len(m.prefix)) - copy(res, m.prefix) - return -} - -// KeyBytes returns the mapping's key bytes. -func (m Mapping) KeyBytes(key []byte) (res []byte) { - return join(m.prefix, key) -} - -func join(a, b []byte) (res []byte) { - res = make([]byte, len(a)+len(b)) - copy(res, a) - copy(res[len(a):], b) - return -} - -// Prefix returns a new mapping with an updated prefix. -func (m Mapping) Prefix(prefix []byte) Mapping { - return Mapping{ - storeKey: m.storeKey, - cdc: m.cdc, - prefix: join(m.prefix, prefix), - } -} diff --git a/store/state/mapping_test.go b/store/state/mapping_test.go deleted file mode 100644 index 3d4110fdf672..000000000000 --- a/store/state/mapping_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package state - -import ( - "math/rand" - "reflect" - "testing" - - "github.com/stretchr/testify/require" -) - -type mapping interface { - Get(Context, interface{}, interface{}) - GetSafe(Context, interface{}, interface{}) error - Set(Context, interface{}, interface{}) - Has(Context, interface{}) bool - Delete(Context, interface{}) - RandomKey() interface{} -} - -type mappingT struct { - Mapping -} - -var _ mapping = mappingT{} - -func newMapping() mappingT { - return mappingT{NewMapping(testkey, testcdc, nil)} -} - -func (m mappingT) Get(ctx Context, key interface{}, ptr interface{}) { - m.Mapping.Get(ctx, []byte(key.(string)), ptr) -} - -func (m mappingT) GetSafe(ctx Context, key interface{}, ptr interface{}) error { - return m.Mapping.GetSafe(ctx, []byte(key.(string)), ptr) -} - -func (m mappingT) Set(ctx Context, key interface{}, o interface{}) { - m.Mapping.Set(ctx, []byte(key.(string)), o) -} - -func (m mappingT) Has(ctx Context, key interface{}) bool { - return m.Mapping.Has(ctx, []byte(key.(string))) -} - -func (m mappingT) Delete(ctx Context, key interface{}) { - m.Mapping.Delete(ctx, []byte(key.(string))) -} - -func (m mappingT) RandomKey() interface{} { - bz := make([]byte, 64) - rand.Read(bz) - return string(bz) -} - -type indexerT struct { - Indexer -} - -var _ mapping = indexerT{} - -func newIndexer(enc IntEncoding) indexerT { - return indexerT{NewMapping(testkey, testcdc, nil).Indexer(enc)} -} - -func (m indexerT) Get(ctx Context, key interface{}, ptr interface{}) { - m.Indexer.Get(ctx, key.(uint64), ptr) -} - -func (m indexerT) GetSafe(ctx Context, key interface{}, ptr interface{}) error { - return m.Indexer.GetSafe(ctx, key.(uint64), ptr) -} - -func (m indexerT) Set(ctx Context, key interface{}, o interface{}) { - m.Indexer.Set(ctx, key.(uint64), o) -} - -func (m indexerT) Has(ctx Context, key interface{}) bool { - return m.Indexer.Has(ctx, key.(uint64)) -} - -func (m indexerT) Delete(ctx Context, key interface{}) { - m.Indexer.Delete(ctx, key.(uint64)) -} - -func (m indexerT) RandomKey() interface{} { - return rand.Uint64() -} - -func TestMapping(t *testing.T) { - ctx, _ := defaultComponents() - table := []mapping{newMapping(), newIndexer(Dec), newIndexer(Hex), newIndexer(Bin)} - - for _, m := range table { - exp := make(map[interface{}]uint64) - for n := 0; n < 10e4; n++ { - k, v := m.RandomKey(), rand.Uint64() - require.False(t, m.Has(ctx, k)) - exp[k] = v - m.Set(ctx, k, v) - } - - for k, v := range exp { - ptr := new(uint64) - m.Get(ctx, k, ptr) - require.Equal(t, v, indirect(ptr)) - - ptr = new(uint64) - err := m.GetSafe(ctx, k, ptr) - require.NoError(t, err) - require.Equal(t, v, indirect(ptr)) - - require.True(t, m.Has(ctx, k)) - - m.Delete(ctx, k) - require.False(t, m.Has(ctx, k)) - ptr = new(uint64) - err = m.GetSafe(ctx, k, ptr) - require.Error(t, err) - require.Equal(t, reflect.Zero(reflect.TypeOf(ptr).Elem()).Interface(), indirect(ptr)) - } - } -} diff --git a/store/state/string.go b/store/state/string.go deleted file mode 100644 index a67b6b8939fb..000000000000 --- a/store/state/string.go +++ /dev/null @@ -1,38 +0,0 @@ -package state - -// String is a string types wrapper for Value. -// x <-> []byte(x) -type String struct { - Value -} - -func (v Value) String() String { - return String{v} -} - -// Get decodes and returns the stored string value if it exists. It will panic -// if the value exists but is not string type. -func (v String) Get(ctx Context) (res string) { - return string(v.Value.GetRaw(ctx)) -} - -// GetSafe decodes and returns the stored string value. It will return an error -// if the value does not exist or not string. -func (v String) GetSafe(ctx Context) (res string, err error) { - bz := v.Value.GetRaw(ctx) - if bz == nil { - return res, ErrEmptyValue() - } - return string(bz), nil -} - -// Set encodes and sets the string argument to the state. -func (v String) Set(ctx Context, value string) { - v.Value.SetRaw(ctx, []byte(value)) -} - -// Query() retrives state value and proof from a queryable reference -func (v String) Query(q ABCIQuerier) (res string, proof *Proof, err error) { - value, proof, err := v.Value.QueryRaw(q) - return string(value), proof, err -} diff --git a/store/state/types.go b/store/state/types.go deleted file mode 100644 index 66ffb1f5255f..000000000000 --- a/store/state/types.go +++ /dev/null @@ -1,61 +0,0 @@ -package state - -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" -) - -type KVStore = sdk.KVStore -type Context = sdk.Context -type Proof = merkle.Proof -type Codec = codec.Codec - -type ABCIQuerier interface { - 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 deleted file mode 100644 index 1d467b0ab380..000000000000 --- a/store/state/value.go +++ /dev/null @@ -1,126 +0,0 @@ -package state - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// Value is a capability for reading and writing on a specific key-value point -// in the state. Value consists of Base and key []byte. An actor holding a Value -// has a full access right on that state point. -type Value struct { - m Mapping - key []byte -} - -// NewValue constructs a Value. -func NewValue(m Mapping, key []byte) Value { - return Value{ - m: m, - key: key, - } -} - -func (v Value) store(ctx Context) KVStore { - return ctx.KVStore(v.m.storeKey) -} - -// Cdc() returns the codec that the value is using to marshal/unmarshal -func (v Value) Cdc() *Codec { - return v.m.Cdc() -} - -func (v Value) Marshal(value interface{}) []byte { - return v.m.cdc.MustMarshalBinaryBare(value) -} - -func (v Value) Unmarshal(bz []byte, ptr interface{}) error { - return v.m.cdc.UnmarshalBinaryBare(bz, ptr) -} - -func (v Value) mustUnmarshal(bz []byte, ptr interface{}) { - v.m.cdc.MustUnmarshalBinaryBare(bz, ptr) -} - -// Get decodes and sets the stored value to the pointer if it exists. It will -// panic if the value exists but not unmarshalable. -func (v Value) Get(ctx Context, ptr interface{}) { - bz := v.store(ctx).Get(v.KeyBytes()) - if bz != nil { - v.mustUnmarshal(bz, ptr) - } -} - -// GetSafe decodes and sets the stored value to the pointer. It will return an -// error if the value does not exist or unmarshalable. -func (v Value) GetSafe(ctx Context, ptr interface{}) error { - bz := v.store(ctx).Get(v.KeyBytes()) - if bz == nil { - return ErrEmptyValue() - } - err := v.Unmarshal(bz, ptr) - if err != nil { - return ErrUnmarshal(err) - } - return nil -} - -// GetRaw returns the raw bytes that is stored in the state. -func (v Value) GetRaw(ctx Context) []byte { - return v.store(ctx).Get(v.KeyBytes()) -} - -// Set encodes and sets the argument to the state. -func (v Value) Set(ctx Context, o interface{}) { - v.store(ctx).Set(v.KeyBytes(), v.Marshal(o)) -} - -// SetRaw sets the raw bytes to the state. -func (v Value) SetRaw(ctx Context, bz []byte) { - v.store(ctx).Set(v.KeyBytes(), bz) -} - -// Exists returns true if the stored value is not nil. It calls KVStore.Has() -// internally. -func (v Value) Exists(ctx Context) bool { - return v.store(ctx).Has(v.KeyBytes()) -} - -// Delete removes the stored value. It calls KVStore.Delete() internally. -func (v Value) Delete(ctx Context) { - v.store(ctx).Delete(v.KeyBytes()) -} - -func (v Value) StoreName() string { - return v.m.StoreName() -} - -func (v Value) PrefixBytes() []byte { - return v.m.PrefixBytes() -} - -// KeyBytes returns the prefixed key that the Value is providing to the KVStore. -func (v Value) KeyBytes() []byte { - return v.m.KeyBytes(v.key) -} - -func (v Value) QueryRaw(q ABCIQuerier) ([]byte, *Proof, error) { - resp, err := q.Query(v.m.StoreName(), v.KeyBytes()) - if err != nil { - return nil, nil, err - } - - if !resp.IsOK() { - return nil, nil, sdk.NewError(sdk.CodespaceRoot, sdk.CodeType(resp.Code), resp.Log) - } - - return resp.Value, resp.Proof, nil -} - -func (v Value) Query(q ABCIQuerier, ptr interface{}) (*Proof, error) { - value, proof, err := v.QueryRaw(q) - if err != nil { - return nil, err - } - err = v.Cdc().UnmarshalBinaryBare(value, ptr) - return proof, err -} diff --git a/store/state/value_test.go b/store/state/value_test.go deleted file mode 100644 index 38888890bbdf..000000000000 --- a/store/state/value_test.go +++ /dev/null @@ -1,353 +0,0 @@ -package state - -import ( - "crypto/rand" - "reflect" - "testing" - - "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" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/rootmulti" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -var testcdc = codec.New() -var testkey = sdk.NewKVStoreKey("test") - -func init() { - // register -} - -func key() (res []byte) { - res = make([]byte, 64) - rand.Read(res) - return -} - -type value interface { - KeyBytes() []byte - Get(Context, interface{}) - GetSafe(Context, interface{}) error - GetRaw(Context) []byte - Set(Context, interface{}) - SetRaw(Context, []byte) - Exists(Context) bool - Delete(Context) - Query(ABCIQuerier, interface{}) (*Proof, error) - Marshal(interface{}) []byte - Unmarshal([]byte, interface{}) -} - -type typeValue interface { - value - Proto() interface{} -} - -type valueT struct { - Value -} - -var _ value = valueT{} - -func (v valueT) Marshal(o interface{}) []byte { - return v.m.cdc.MustMarshalBinaryBare(o) -} - -func (v valueT) Unmarshal(bz []byte, ptr interface{}) { - v.m.cdc.MustUnmarshalBinaryBare(bz, ptr) -} - -type booleanT struct { - Boolean -} - -var _ typeValue = booleanT{} - -func newBoolean() booleanT { - return booleanT{NewMapping(testkey, testcdc, nil).Value(key()).Boolean()} -} - -func (booleanT) Proto() interface{} { - return new(bool) -} - -func (v booleanT) Get(ctx Context, ptr interface{}) { - reflect.ValueOf(ptr).Elem().SetBool(v.Boolean.Get(ctx)) -} - -func (v booleanT) GetSafe(ctx Context, ptr interface{}) error { - res, err := v.Boolean.GetSafe(ctx) - if err != nil { - return err - } - reflect.ValueOf(ptr).Elem().SetBool(res) - return nil -} - -func (v booleanT) Set(ctx Context, o interface{}) { - v.Boolean.Set(ctx, o.(bool)) -} - -func (v booleanT) Marshal(o interface{}) []byte { - switch o.(bool) { - case false: - return []byte{0x00} - case true: - return []byte{0x01} - } - panic("invalid boolean type") -} - -func (v booleanT) Unmarshal(bz []byte, ptr interface{}) { - switch bz[0] { - case 0x00: - reflect.ValueOf(ptr).Elem().SetBool(false) - case 0x01: - reflect.ValueOf(ptr).Elem().SetBool(true) - } -} - -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 -} - -var _ typeValue = integerT{} - -func newInteger(enc IntEncoding) integerT { - return integerT{NewMapping(testkey, testcdc, nil).Value(key()).Integer(enc)} -} - -func (integerT) Proto() interface{} { - return new(uint64) -} - -func (v integerT) Get(ctx Context, ptr interface{}) { - reflect.ValueOf(ptr).Elem().SetUint(v.Integer.Get(ctx)) -} - -func (v integerT) GetSafe(ctx Context, ptr interface{}) error { - res, err := v.Integer.GetSafe(ctx) - if err != nil { - return err - } - reflect.ValueOf(ptr).Elem().SetUint(res) - return nil -} - -func (v integerT) Set(ctx Context, o interface{}) { - v.Integer.Set(ctx, o.(uint64)) -} - -func (v integerT) Marshal(o interface{}) []byte { - return EncodeInt(o.(uint64), v.enc) -} - -func (v integerT) Unmarshal(bz []byte, ptr interface{}) { - res, err := DecodeInt(bz, v.enc) - if err != nil { - panic(err) - } - 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 -} - -var _ typeValue = enumT{} - -func newEnum() enumT { - return enumT{NewMapping(testkey, testcdc, nil).Value(key()).Enum()} -} - -func (enumT) Proto() interface{} { - return new(byte) -} - -func (v enumT) Get(ctx Context, ptr interface{}) { - reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v.Enum.Get(ctx))) -} - -func (v enumT) GetSafe(ctx Context, ptr interface{}) error { - res, err := v.Enum.GetSafe(ctx) - if err != nil { - return err - } - reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(res)) - return nil -} - -func (v enumT) Set(ctx Context, o interface{}) { - v.Enum.Set(ctx, o.(byte)) -} - -func (v enumT) Marshal(o interface{}) []byte { - return []byte{o.(byte)} -} - -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 -} - -var _ typeValue = stringT{} - -func newString() stringT { - return stringT{NewMapping(testkey, testcdc, nil).Value(key()).String()} -} - -func (stringT) Proto() interface{} { - return new(string) -} - -func (v stringT) Get(ctx Context, ptr interface{}) { - reflect.ValueOf(ptr).Elem().SetString(v.String.Get(ctx)) -} - -func (v stringT) GetSafe(ctx Context, ptr interface{}) error { - res, err := v.String.GetSafe(ctx) - if err != nil { - return err - } - reflect.ValueOf(ptr).Elem().SetString(res) - return nil -} - -func (v stringT) Set(ctx Context, o interface{}) { - v.String.Set(ctx, o.(string)) -} - -func (v stringT) Marshal(o interface{}) []byte { - return []byte(o.(string)) -} - -func (v stringT) Unmarshal(bz []byte, ptr interface{}) { - reflect.ValueOf(ptr).Elem().SetString(string(bz)) -} - -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, cms -} - -func indirect(ptr interface{}) interface{} { - return reflect.ValueOf(ptr).Elem().Interface() -} - -func TestTypeValue(t *testing.T) { - ctx, cms := defaultComponents() - - var table = []struct { - ty typeValue - orig interface{} - }{ - {newBoolean(), false}, - {newBoolean(), true}, - {newInteger(Dec), uint64(1024000)}, - {newInteger(Dec), uint64(2048000)}, - {newInteger(Bin), uint64(4096000)}, - {newInteger(Bin), uint64(8192000)}, - {newInteger(Hex), uint64(16384000)}, - {newInteger(Hex), uint64(32768000)}, - {newEnum(), byte(0x00)}, - {newEnum(), byte(0x78)}, - {newEnum(), byte(0xA0)}, - {newString(), "1234567890"}, - {newString(), "asdfghjkl"}, - {newString(), "qwertyuiop"}, - } - - for i, tc := range table { - v := tc.ty - // Exists expected false - require.False(t, v.Exists(ctx)) - - // Simple get-set - v.Set(ctx, tc.orig) - ptr := v.Proto() - v.Get(ctx, ptr) - require.Equal(t, tc.orig, indirect(ptr), "Expected equal on tc %d", i) - ptr = v.Proto() - err := v.GetSafe(ctx, ptr) - require.NoError(t, err) - require.Equal(t, tc.orig, indirect(ptr), "Expected equal on tc %d", i) - - // Raw get - require.Equal(t, v.Marshal(tc.orig), v.GetRaw(ctx), "Expected equal on tc %d", i) - - // Exists expected true - require.True(t, v.Exists(ctx)) - - // After delete - v.Delete(ctx) - require.False(t, v.Exists(ctx)) - ptr = v.Proto() - err = v.GetSafe(ctx, ptr) - 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/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go index bef5e7c6951b..798b41d840ad 100644 --- a/x/ibc/23-commitment/merkle/merkle.go +++ b/x/ibc/23-commitment/merkle/merkle.go @@ -63,7 +63,7 @@ func (Prefix) CommitmentKind() string { } func (prefix Prefix) Key(key []byte) []byte { - return join(prefix.KeyPrefix, key) + return ics23.Join(prefix.KeyPrefix, key) } var _ ics23.Proof = Proof{} diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go index 64baf2d7c67c..a2813762b7b6 100644 --- a/x/ibc/23-commitment/merkle/utils.go +++ b/x/ibc/23-commitment/merkle/utils.go @@ -6,6 +6,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/store/types" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) func QueryMultiStore(cms types.CommitMultiStore, storeName string, prefix []byte, key []byte) ([]byte, Proof, error) { @@ -27,14 +28,7 @@ func RequestQueryMultiStore(storeName string, prefix []byte, key []byte) abci.Re // and performs key-value query only if it is "/key" return abci.RequestQuery{ Path: "/" + storeName + "/key", - Data: join(prefix, key), + Data: ics23.Join(prefix, key), Prove: true, } } - -func join(a, b []byte) (res []byte) { - res = make([]byte, len(a)+len(b)) - copy(res, a) - copy(res[len(a):], b) - return -} diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go index 633ded2cbc20..941adaf230a0 100644 --- a/x/ibc/23-commitment/store.go +++ b/x/ibc/23-commitment/store.go @@ -36,7 +36,7 @@ func NewPrefix(store Store, pref []byte) Store { // Prove implements Store. func (prefix prefix) Prove(path, value []byte) bool { - return prefix.store.Prove(join(prefix.prefix, path), value) + return prefix.store.Prove(Join(prefix.prefix, path), value) } var _ Store = (*store)(nil) @@ -96,3 +96,10 @@ func (store *store) Prove(path, value []byte) bool { return true } + +func Join(a, b []byte) (res []byte) { + res = make([]byte, len(a)+len(b)) + copy(res, a) + copy(res[len(a):], b) + return +} From 02bd6f78e684d0007dc2df4175a884634f48a010 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 7 Oct 2019 18:46:12 +0200 Subject: [PATCH 263/378] proposed refactor --- x/ibc/02-client/keeper/keeper.go | 38 ++++++++++++++++++++++++++------ x/ibc/02-client/types/state.go | 6 ++--- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index b1fb846eb672..b23969926763 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -5,6 +5,8 @@ import ( "github.com/tendermint/tendermint/libs/log" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -17,15 +19,19 @@ import ( // Keeper represents a type that grants read and write permissions to any client // state information type Keeper struct { - mapping state.Mapping + storeKey sdk.StoreKey + cdc *codec.Codec codespace sdk.CodespaceType + prefix []byte // prefix bytes for accessing the store } // NewKeeper creates a new NewKeeper instance -func NewKeeper(mapping state.Mapping, codespace sdk.CodespaceType) Keeper { +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) Keeper { return Keeper{ - mapping: mapping.Prefix([]byte(types.SubModuleName + "/")), // "client/" - codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/client" + storeKey: key, + cdc: cdc, + codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/client", + prefix: []byte(types.SubModuleName + "/"), // "client/" } } @@ -34,11 +40,29 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName)) } +// GetClient creates a new client state and populates it with a given consensus state +func (k Keeper) GetClient(ctx sdk.Context, id string) (state types.State, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(KeyClientState(id)) + if bz == nil { + return types.State{}, false + } + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &state) + return state, true +} + +// SetClient creates a new client state and populates it with a given consensus state +func (k Keeper) SetClient(ctx sdk.Context, clientState types.State) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(clientState) + store.Set(KeyClientState(id), bz) +} + // CreateClient creates a new client state and populates it with a given consensus state func (k Keeper) CreateClient(ctx sdk.Context, id string, cs exported.ConsensusState) (types.State, error) { - state, err := k.Query(ctx, id) - if err == nil { - return types.State{}, sdkerrors.Wrap(err, "cannot create client") + state, found := k.GetClient(ctx, id) + if found { + return types.State{}, types.ErrClientExists(k.codespace) } // set the most recent state root and consensus state diff --git a/x/ibc/02-client/types/state.go b/x/ibc/02-client/types/state.go index 1141c3f281b0..aa17a79863a6 100644 --- a/x/ibc/02-client/types/state.go +++ b/x/ibc/02-client/types/state.go @@ -23,16 +23,16 @@ type State struct { ConsensusState state.Value `json:"consensus_state" yaml:"consensus_state"` // Boolean that states if the client is frozen when a misbehaviour proof is // submitted in the event of an equivocation. - Frozen state.Boolean `json:"frozen" yaml:"frozen"` + Frozen bool `json:"frozen" yaml:"frozen"` } // NewState creates a new State instance -func NewState(id string, roots state.Indexer, consensusState state.Value, frozen state.Boolean) State { +func NewState(id string, roots state.Indexer, consensusState state.Value) State { return State{ id: id, Roots: roots, ConsensusState: consensusState, - Frozen: frozen, + Frozen: false, } } From 0e37d757fbdbe9204f093d7100590f8460b3099a Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 7 Oct 2019 22:45:19 +0200 Subject: [PATCH 264/378] remove store accessors from ICS02 --- x/ibc/02-client/exported/exported.go | 2 +- x/ibc/02-client/keeper/keeper.go | 186 +++++++++++++++++++-------- x/ibc/02-client/types/errors.go | 29 ++++- x/ibc/02-client/types/keys.go | 54 +++++++- x/ibc/02-client/types/state.go | 94 +++++--------- 5 files changed, 243 insertions(+), 122 deletions(-) diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index 54d42f15bd9a..72fbe579200e 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -50,5 +50,5 @@ type ClientType byte // Registered consensus types const ( - Tendermint ClientType = iota + Tendermint ClientType = iota + 1 // 1 ) diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index b23969926763..fa712c1b9165 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -7,12 +7,12 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" - "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -40,66 +40,124 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName)) } -// GetClient creates a new client state and populates it with a given consensus state -func (k Keeper) GetClient(ctx sdk.Context, id string) (state types.State, found bool) { +// GetClientState gets a particular client from the +func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (types.ClientState, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) - bz := store.Get(KeyClientState(id)) + bz := store.Get(types.KeyClientState(clientID)) if bz == nil { - return types.State{}, false + return types.ClientState{}, false } - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &state) - return state, true + + var clientState types.ClientState + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &clientState) + return clientState, true } -// SetClient creates a new client state and populates it with a given consensus state -func (k Keeper) SetClient(ctx sdk.Context, clientState types.State) { +// SetClient sets a particular Client to the store +func (k Keeper) SetClient(ctx sdk.Context, clientState types.ClientState) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := k.cdc.MustMarshalBinaryLengthPrefixed(clientState) - store.Set(KeyClientState(id), bz) + store.Set(types.KeyClientState(clientState.ID()), bz) } -// CreateClient creates a new client state and populates it with a given consensus state -func (k Keeper) CreateClient(ctx sdk.Context, id string, cs exported.ConsensusState) (types.State, error) { - state, found := k.GetClient(ctx, id) - if found { - return types.State{}, types.ErrClientExists(k.codespace) +// GetClientType gets the consensus type for a specific client +func (k Keeper) GetClientType(ctx sdk.Context, clientID string) (exported.ClientType, bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(types.KeyClientType(clientID)) + if bz == nil { + return 0, false + } + + return exported.ClientType(bz[0]), true +} + +// SetClientType sets the specific client consensus type to the provable store +func (k Keeper) SetClientType(ctx sdk.Context, clientID string, clientType exported.ClientType) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + store.Set(types.KeyClientType(clientID), []byte{byte(clientType)}) +} + +// GetConsensusState creates a new client state and populates it with a given consensus state +func (k Keeper) GetConsensusState(ctx sdk.Context, clientID string) (exported.ConsensusState, bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(types.KeyClientState(clientID)) + if bz == nil { + return nil, false + } + + var consensusState exported.ConsensusState + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &consensusState) + return consensusState, true +} + +// SetConsensusState sets a ConsensusState to a particular Client +func (k Keeper) SetConsensusState(ctx sdk.Context, clientID string, consensusState exported.ConsensusState) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(consensusState) + store.Set(types.KeyClientState(clientID), bz) +} + +// GetCommitmentRoot gets a commitment Root from a particular height to a client +func (k Keeper) GetCommitmentRoot(ctx sdk.Context, clientID string, height uint64) (ics23.Root, bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(types.KeyRoot(clientID, height)) + if bz == nil { + return nil, false } - // set the most recent state root and consensus state - state.Roots.Set(ctx, cs.GetHeight(), cs.GetRoot()) - state.ConsensusState.Set(ctx, cs) - return state, nil + var root ics23.Root + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &root) + return root, true } -// State returns a new client state with a given id -func (k Keeper) ClientState(id string) types.State { - return types.NewState( - id, // client ID - k.mapping.Prefix([]byte(id+"/roots/")).Indexer(state.Dec), // commitment roots - k.mapping.Value([]byte(id)), // consensus state - k.mapping.Value([]byte(id+"/freeze")).Boolean(), // client frozen - ) +// SetCommitmentRoot sets a commitment Root from a particular height to a client +func (k Keeper) SetCommitmentRoot(ctx sdk.Context, clientID string, height uint64, root ics23.Root) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(root) + store.Set(types.KeyRoot(clientID, height), bz) } -// Query returns a client state that matches a given ID -func (k Keeper) Query(ctx sdk.Context, id string) (types.State, error) { - state := k.ClientState(id) - if !state.Exists(ctx) { - return types.State{}, types.ErrClientExists(k.codespace) +// CreateClient creates a new client state and populates it with a given consensus +// state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create +func (k Keeper) CreateClient( + ctx sdk.Context, clientID string, + clientType exported.ClientType, consensusState exported.ConsensusState, +) (types.ClientState, error) { + clientState, found := k.GetClientState(ctx, clientID) + if found { + return types.ClientState{}, types.ErrClientExists(k.codespace) + } + + clientType, found = k.GetClientType(ctx, clientID) + if found { + panic(fmt.Sprintf("consensus type is already defined for client %s", clientID)) } - return state, nil + + clientState = k.initialize(ctx, clientID, consensusState) + k.SetCommitmentRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) + k.SetClient(ctx, clientState) + k.SetClientType(ctx, clientID, clientType) + return clientState, nil +} + +// ClientState returns a new client state with a given id as defined in +// https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#example-implementation +func (k Keeper) initialize(ctx sdk.Context, clientID string, consensusState exported.ConsensusState) types.ClientState { + clientState := types.NewClientState(clientID) + k.SetConsensusState(ctx, clientID, consensusState) + return clientState } // CheckMisbehaviourAndUpdateState checks for client misbehaviour and freezes the // client if so. -func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, state types.State, evidence exported.Evidence) error { +func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, clientState types.ClientState, evidence exported.Evidence) error { var err error - switch evidence.H1().Kind() { + switch evidence.H1().ClientType() { case exported.Tendermint: var tmEvidence tendermint.Evidence _, ok := evidence.(tendermint.Evidence) if !ok { - return sdkerrors.Wrap(types.ErrInvalidConsensus(k.codespace), "consensus is not Tendermint") + return sdkerrors.Wrap(types.ErrInvalidClientType(k.codespace), "consensus type is not Tendermint") } err = tendermint.CheckMisbehaviour(tmEvidence) default: @@ -110,40 +168,58 @@ func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, state types.Sta return err } - return k.Freeze(ctx, state) + clientState, err = k.freeze(ctx, clientState) + if err != nil { + return err + } + + k.SetClient(ctx, clientState) + return nil } -// Update updates the consensus state and the state root from a provided header -func (k Keeper) Update(ctx sdk.Context, state types.State, header exported.Header) error { - if !state.Exists(ctx) { - panic("should not update nonexisting client") +// UpdateClient updates the consensus state and the state root from a provided header +func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.Header) error { + clientType, found := k.GetClientType(ctx, clientID) + if !found { + return sdkerrors.Wrap(types.ErrClientTypeNotFound(k.codespace), "cannot update client") + } + + // check that the header consensus matches the client one + if header.ClientType() != clientType { + return sdkerrors.Wrap(types.ErrInvalidConsensus(k.codespace), "cannot update client") + } + + clientState, found := k.GetClientState(ctx, clientID) + if !found { + return sdkerrors.Wrap(types.ErrClientNotFound(k.codespace), "cannot update client") } - if state.Frozen.Get(ctx) { + if clientState.Frozen { return sdkerrors.Wrap(types.ErrClientFrozen(k.codespace), "cannot update client") } - consensusState := state.GetConsensusState(ctx) + consensusState, found := k.GetConsensusState(ctx, clientID) + if !found { + return sdkerrors.Wrap(types.ErrConsensusStateNotFound(k.codespace), "cannot update client") + panic(fmt.Sprintf("consensus state not found for client %s", clientID)) + } + consensusState, err := consensusState.CheckValidityAndUpdateState(header) if err != nil { return sdkerrors.Wrap(err, "cannot update client") } - state.ConsensusState.Set(ctx, consensusState) - state.Roots.Set(ctx, consensusState.GetHeight(), consensusState.GetRoot()) + k.SetConsensusState(ctx, clientID, consensusState) + k.SetCommitmentRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) return nil } -// Freeze updates the state of the client in the event of a misbehaviour -func (k Keeper) Freeze(ctx sdk.Context, state types.State) error { - if !state.Exists(ctx) { - panic("should not freeze nonexisting client") +// freeze updates the state of the client in the event of a misbehaviour +func (k Keeper) freeze(ctx sdk.Context, clientState types.ClientState) (types.ClientState, error) { + if clientState.Frozen { + return types.ClientState{}, sdkerrors.Wrap(types.ErrClientFrozen(k.codespace), "already frozen") } - if state.Frozen.Get(ctx) { - return sdkerrors.Wrap(types.ErrClientFrozen(k.codespace), "already frozen") - } - - state.Frozen.Set(ctx, true) - return nil + clientState.Frozen = true + return clientState, nil } diff --git a/x/ibc/02-client/types/errors.go b/x/ibc/02-client/types/errors.go index 4c77d2dffe0a..2657ff7ea56c 100644 --- a/x/ibc/02-client/types/errors.go +++ b/x/ibc/02-client/types/errors.go @@ -8,11 +8,13 @@ import ( const ( DefaultCodespace sdk.CodespaceType = SubModuleName - CodeClientExists sdk.CodeType = 101 - CodeClientNotFound sdk.CodeType = 102 - CodeClientFrozen sdk.CodeType = 103 - CodeInvalidConsensus sdk.CodeType = 104 - CodeValidatorJailed sdk.CodeType = 104 + CodeClientExists sdk.CodeType = 101 + CodeClientNotFound sdk.CodeType = 102 + CodeClientFrozen sdk.CodeType = 103 + CodeConsensusStateNotFound sdk.CodeType = 104 + CodeInvalidConsensusState sdk.CodeType = 105 + CodeClientTypeNotFound sdk.CodeType = 106 + CodeInvalidClientType sdk.CodeType = 107 ) // ErrClientExists implements sdk.Error @@ -30,7 +32,22 @@ func ErrClientFrozen(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeClientFrozen, "client is frozen due to misbehaviour") } +// ErrConsensusStateNotFound implements sdk.Error +func ErrConsensusStateNotFound(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeConsensusStateNotFound, "consensus state not found") +} + // ErrInvalidConsensus implements sdk.Error func ErrInvalidConsensus(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidConsensus, "invalid consensus algorithm type") + return sdk.NewError(codespace, CodeInvalidConsensusState, "invalid consensus state") +} + +// ErrClientTypeNotFound implements sdk.Error +func ErrClientTypeNotFound(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeClientTypeNotFound, "client type not found") +} + +// ErrInvalidClientType implements sdk.Error +func ErrInvalidClientType(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidClientType, "client type mismatch") } diff --git a/x/ibc/02-client/types/keys.go b/x/ibc/02-client/types/keys.go index 2e1f26ae3a26..5869852a741f 100644 --- a/x/ibc/02-client/types/keys.go +++ b/x/ibc/02-client/types/keys.go @@ -1,6 +1,58 @@ package types +import ( + "fmt" +) + const ( // SubModuleName defines the IBC client name - SubModuleName = "client" + SubModuleName = "clients" ) + +// The following paths are the keys to the store as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#path-space + +// clientStatePath takes an Identifier and returns a Path under which to store a +// particular client state +func clientStatePath(clientID string) string { + return fmt.Sprintf("clients/%s/state", clientID) +} + +// clientTypePath takes an Identifier and returns Path under which to store the +// type of a particular client. +func clientTypePath(clientID string) string { + return fmt.Sprintf("clients/%s/type", clientID) +} + +// consensusStatePath takes an Identifier and returns a Path under which to +// store the consensus state of a client. +func consensusStatePath(clientID string) string { + return fmt.Sprintf("clients/%s/consensusState", clientID) +} + +// consensusStatePath takes an Identifier and returns a Path under which to +// store the consensus state of a client. +func rootPath(clientID string, height uint64) string { + return fmt.Sprintf("clients/%s/roots/%d", clientID, height) +} + +// KeyClientState returns the store key for a particular client state +func KeyClientState(clientID string) []byte { + return []byte(clientStatePath(clientID)) +} + +// KeyClientType returns the store key for type of a particular client +func KeyClientType(clientID string) []byte { + return []byte(clientTypePath(clientID)) +} + +// KeyConsensusState returns the store key for the consensus state of a particular +// client +func KeyConsensusState(clientID string) []byte { + return []byte(consensusStatePath(clientID)) +} + +// KeyRoot returns the store key for a commitment root of a particular +// client at a given height +func KeyRoot(clientID string, height uint64) []byte { + return []byte(rootPath(clientID, height)) +} diff --git a/x/ibc/02-client/types/state.go b/x/ibc/02-client/types/state.go index aa17a79863a6..873b3d9ab8aa 100644 --- a/x/ibc/02-client/types/state.go +++ b/x/ibc/02-client/types/state.go @@ -1,82 +1,58 @@ package types import ( - "bytes" - - "github.com/cosmos/cosmos-sdk/store/state" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) -// State is a type that represents the state of a client. +// ClientState is a type that represents the state of a client. // Any actor holding the Stage can access on and modify that client information. -type State struct { +type ClientState struct { // Client ID id string // Past state roots required to avoid race conditions between client updates // and proof-carrying transactions as defined in // https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#utilising-past-roots - Roots state.Indexer `json:"roots" yaml:"roots"` + Roots []ics23.Root `json:"roots" yaml:"roots"` // Consensus state bytes - ConsensusState state.Value `json:"consensus_state" yaml:"consensus_state"` + ConsensusState exported.ConsensusState `json:"consensus_state" yaml:"consensus_state"` // Boolean that states if the client is frozen when a misbehaviour proof is // submitted in the event of an equivocation. Frozen bool `json:"frozen" yaml:"frozen"` } -// NewState creates a new State instance -func NewState(id string, roots state.Indexer, consensusState state.Value) State { - return State{ - id: id, - Roots: roots, - ConsensusState: consensusState, - Frozen: false, +// NewClientState creates a new ClientState instance +func NewClientState(id string) ClientState { + return ClientState{ + id: id, + Frozen: false, } } // ID returns the client identifier -func (state State) ID() string { - return state.id -} - -// GetConsensusState returns the consensus state -func (state State) GetConsensusState(ctx sdk.Context) (cs exported.ConsensusState) { - state.ConsensusState.Get(ctx, &cs) - return -} - -// GetRoot returns the commitment root of the client at a given height -func (state State) GetRoot(ctx sdk.Context, height uint64) (root ics23.Root, err error) { - err = state.Roots.GetSafe(ctx, height, &root) - return -} - -// Exists verifies if the client exists or not -func (state State) Exists(ctx sdk.Context) bool { - return state.ConsensusState.Exists(ctx) -} - -func (state State) RootCLI(q state.ABCIQuerier, height uint64) (res ics23.Root, proof merkle.Proof, err error) { - root := state.Roots.Value(height) - tmProof, err := root.Query(q, &res) - proof = merkle.NewProofFromValue(tmProof, state.prefix(), root) - return -} - -func (state State) ConsensusStateCLI(q state.ABCIQuerier) (res exported.ConsensusState, proof merkle.Proof, err error) { - tmproof, err := state.ConsensusState.Query(q, &res) - proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.ConsensusState) - return -} - -func (state State) FrozenCLI(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { - res, tmproof, err := state.Frozen.Query(q) - proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Frozen) - return -} - -func (state State) prefix() []byte { - return bytes.Split(state.ConsensusState.KeyBytes(), []byte(SubModuleName+"/"))[0] -} +func (cs ClientState) ID() string { + return cs.id +} + +// func (state State) RootCLI(q cs.ABCIQuerier, height uint64) (res ics23.Root, proof merkle.Proof, err error) { +// root := cs.Roots.Value(height) +// tmProof, err := root.Query(q, &res) +// proof = merkle.NewProofFromValue(tmProof, cs.prefix(), root) +// return +// } + +// func (state State) ConsensusStateCLI(q cs.ABCIQuerier) (res exported.ConsensusState, proof merkle.Proof, err error) { +// tmproof, err := cs.ConsensusState.Query(q, &res) +// proof = merkle.NewProofFromValue(tmproof, cs.prefix(), cs.ConsensusState) +// return +// } + +// func (state State) FrozenCLI(q cs.ABCIQuerier) (res bool, proof merkle.Proof, err error) { +// res, tmproof, err := cs.Frozen.Query(q) +// proof = merkle.NewProofFromValue(tmproof, cs.prefix(), cs.Frozen) +// return +// } + +// func (state State) prefix() []byte { +// return bytes.Split(cs.ConsensusState.KeyBytes(), []byte(SubModuleName+"/"))[0] +// } From 8dec96f40186e81cec99955bcf43c5c9d0960809 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 8 Oct 2019 13:37:08 +0200 Subject: [PATCH 265/378] refactor queriers, handler and clean keeper --- x/ibc/02-client/client/cli/query.go | 108 +++++++++++---- x/ibc/02-client/exported/exported.go | 33 +++++ x/ibc/02-client/handler.go | 16 +-- x/ibc/02-client/keeper/keeper.go | 107 +++++++++------ x/ibc/02-client/keeper/querier.go | 129 ++++++++---------- x/ibc/02-client/types/errors.go | 6 + x/ibc/02-client/types/keys.go | 33 +++-- x/ibc/02-client/types/msgs.go | 11 +- x/ibc/02-client/types/querier.go | 20 +-- x/ibc/02-client/types/state.go | 34 ----- .../types/tendermint/consensus_state.go | 26 ++-- x/ibc/02-client/types/tendermint/header.go | 8 +- .../types/tendermint/misbehaviour.go | 4 +- 13 files changed, 311 insertions(+), 224 deletions(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index b092f224f31a..8d873f29df9d 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -7,11 +7,17 @@ import ( "github.com/spf13/cobra" + tmtypes "github.com/tendermint/tendermint/types" + 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/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) // GetQueryCmd returns the query commands for IBC clients @@ -43,7 +49,7 @@ func GetCmdQueryClientState(storeKey string, cdc *codec.Codec) *cobra.Command { fmt.Sprintf(`Query stored client Example: -$ %s query ibc client state [id] +$ %s query ibc client state [client-id] `, version.ClientName), ), Args: cobra.ExactArgs(1), @@ -56,13 +62,17 @@ $ %s query ibc client state [id] return err } - req := abci.RequestQuery{ - Path: "/store/" + storeKey + "/key", - Data: bz, - Prove: true, + res, _, err := cliCtx.QueryWithData(types.ClientStatePath(id), bz) + if err != nil { + return err + } + + var clientState types.ClientState + if err := cdc.UnmarshalJSON(res, &clientState); err != nil { + return err } - return cliCtx.PrintOutput() + return cliCtx.PrintOutput(clientState) }, } } @@ -76,7 +86,7 @@ func GetCmdQueryRoot(storeKey string, cdc *codec.Codec) *cobra.Command { fmt.Sprintf(`Query stored client Example: -$ %s query ibc client root [id] [height] +$ %s query ibc client root [client-id] [height] `, version.ClientName), ), Args: cobra.ExactArgs(2), @@ -93,7 +103,17 @@ $ %s query ibc client root [id] [height] return err } - return cliCtx.PrintOutput() + res, _, err := cliCtx.QueryWithData(types.RootPath(id, height), bz) + if err != nil { + return err + } + + var root ics23.Root + if err := cdc.UnmarshalJSON(res, &root); err != nil { + return err + } + + return cliCtx.PrintOutput(root) }, } } @@ -108,34 +128,30 @@ func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command fmt.Sprintf(`Query consensus state Example: -$ %s query ibc client consensus-state +$ %s query ibc client consensus-state [client-id] `, version.ClientName), ), + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - node, err := cliCtx.GetNode() - if err != nil { - return err - } + id := args[0] - info, err := node.ABCIInfo() + bz, err := cdc.MarshalJSON(types.NewQueryClientStateParams(id)) if err != nil { return err } - height := info.Response.LastBlockHeight - prevheight := height - 1 - commit, err := node.Commit(&height) + res, _, err := cliCtx.QueryWithData(types.ConsensusStatePath(id), bz) if err != nil { return err } - validators, err := node.Validators(&prevheight) - if err != nil { + var consensusState exported.ConsensusState + if err := cdc.UnmarshalJSON(res, &consensusState); err != nil { return err } - return cliCtx.PrintOutput() + return cliCtx.PrintOutput(consensusState) }, } } @@ -154,12 +170,24 @@ $ %s query ibc client path RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - return cliCtx.PrintOutput() + // TODO: + res, _, err := cliCtx.Query("") + if err != nil { + return err + } + + var path merkle.Prefix + if err := cdc.UnmarshalJSON(res, &path); err != nil { + return err + } + + return cliCtx.PrintOutput(path) }, } } // GetCmdQueryHeader defines the command to query the latest header on the chain +// TODO: do we really need this cmd ?? func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "header", @@ -173,7 +201,41 @@ $ %s query ibc client header RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - return cliCtx.PrintOutput() + node, err := cliCtx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevHeight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevHeight) + if err != nil { + return err + } + + nextValidators, err := node.Validators(&height) + if err != nil { + return err + } + + header := tendermint.Header{ + SignedHeader: commit.SignedHeader, + ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + NextValidatorSet: tmtypes.NewValidatorSet(nextValidators.Validators), + } + + return cliCtx.PrintOutput(header) }, } } diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index 72fbe579200e..8e97b68b6f6f 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -1,6 +1,8 @@ package exported import ( + "fmt" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -45,6 +47,11 @@ type Header interface { GetHeight() uint64 } +// Client types +const ( + ClientTypeTendermint string = "Tendermint" +) + // ClientType defines the type of the consensus algorithm type ClientType byte @@ -52,3 +59,29 @@ type ClientType byte const ( Tendermint ClientType = iota + 1 // 1 ) + +var validClientTypes = map[string]struct{}{ + ClientTypeTendermint: {}, +} + +// RegisterClientType registers a client type. It will panic if the type is +// already registered. +func RegisterClientType(ty string) { + if _, ok := validClientTypes[ty]; ok { + panic(fmt.Sprintf("already registered client type: %s", ty)) + } + + validClientTypes[ty] = struct{}{} +} + +// ClientTypeFromStr returns a byte that corresponds to the registered client +// type. It returns 0 if the type is not found/registered. +func ClientTypeFromStr(ty string) ClientType { + switch ty { + case ClientTypeTendermint: + return Tendermint + + default: + return 0 + } +} diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go index dfc2f0eabb67..6dab4bc41ba9 100644 --- a/x/ibc/02-client/handler.go +++ b/x/ibc/02-client/handler.go @@ -32,7 +32,7 @@ func NewHandler(k keeper.Keeper) sdk.Handler { } func handleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgCreateClient) sdk.Result { - _, err := k.CreateClient(ctx, msg.ClientID, msg.ConsensusState) + _, err := k.CreateClient(ctx, msg.ClientID, msg.ClientType, msg.ConsensusState) if err != nil { return sdk.ResultFromError(err) } @@ -53,12 +53,7 @@ func handleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgCreate } func handleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgUpdateClient) sdk.Result { - state, err := k.Query(ctx, msg.ClientID) - if err != nil { - return sdk.ResultFromError(err) - } - - err = k.Update(ctx, state, msg.Header) + err := k.UpdateClient(ctx, msg.ClientID, msg.Header) if err != nil { return sdk.ResultFromError(err) } @@ -80,12 +75,7 @@ func handleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgUpdate } func handleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg types.MsgSubmitMisbehaviour) sdk.Result { - state, err := k.Query(ctx, msg.ClientID) - if err != nil { - return sdk.ResultFromError(err) - } - - err = k.CheckMisbehaviourAndUpdateState(ctx, state, msg.Evidence) + err := k.CheckMisbehaviourAndUpdateState(ctx, msg.ClientID, msg.Evidence) if err != nil { return sdk.ResultFromError(err) } diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index fa712c1b9165..cc6c24ac3702 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -40,6 +41,11 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName)) } +// GetCommitmentPath returns the commitment path of the client +func (k Keeper) GetCommitmentPath() merkle.Prefix { + return merkle.NewPrefix([][]byte{[]byte(k.storeKey.Name())}, k.prefix) +} + // GetClientState gets a particular client from the func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (types.ClientState, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) @@ -121,18 +127,23 @@ func (k Keeper) SetCommitmentRoot(ctx sdk.Context, clientID string, height uint6 // state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create func (k Keeper) CreateClient( ctx sdk.Context, clientID string, - clientType exported.ClientType, consensusState exported.ConsensusState, + clientTypeStr string, consensusState exported.ConsensusState, ) (types.ClientState, error) { clientState, found := k.GetClientState(ctx, clientID) if found { return types.ClientState{}, types.ErrClientExists(k.codespace) } - clientType, found = k.GetClientType(ctx, clientID) + _, found = k.GetClientType(ctx, clientID) if found { panic(fmt.Sprintf("consensus type is already defined for client %s", clientID)) } + clientType := exported.ClientTypeFromStr(clientTypeStr) + if clientType == 0 { + return types.ClientState{}, types.ErrInvalidClientType(k.codespace) + } + clientState = k.initialize(ctx, clientID, consensusState) k.SetCommitmentRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) k.SetClient(ctx, clientState) @@ -140,43 +151,6 @@ func (k Keeper) CreateClient( return clientState, nil } -// ClientState returns a new client state with a given id as defined in -// https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#example-implementation -func (k Keeper) initialize(ctx sdk.Context, clientID string, consensusState exported.ConsensusState) types.ClientState { - clientState := types.NewClientState(clientID) - k.SetConsensusState(ctx, clientID, consensusState) - return clientState -} - -// CheckMisbehaviourAndUpdateState checks for client misbehaviour and freezes the -// client if so. -func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, clientState types.ClientState, evidence exported.Evidence) error { - var err error - switch evidence.H1().ClientType() { - case exported.Tendermint: - var tmEvidence tendermint.Evidence - _, ok := evidence.(tendermint.Evidence) - if !ok { - return sdkerrors.Wrap(types.ErrInvalidClientType(k.codespace), "consensus type is not Tendermint") - } - err = tendermint.CheckMisbehaviour(tmEvidence) - default: - panic("unregistered consensus type") - } - - if err != nil { - return err - } - - clientState, err = k.freeze(ctx, clientState) - if err != nil { - return err - } - - k.SetClient(ctx, clientState) - return nil -} - // UpdateClient updates the consensus state and the state root from a provided header func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.Header) error { clientType, found := k.GetClientType(ctx, clientID) @@ -201,7 +175,15 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H consensusState, found := k.GetConsensusState(ctx, clientID) if !found { return sdkerrors.Wrap(types.ErrConsensusStateNotFound(k.codespace), "cannot update client") - panic(fmt.Sprintf("consensus state not found for client %s", clientID)) + } + + if header.GetHeight() < consensusState.GetHeight() { + return sdkerrors.Wrap( + sdk.ErrInvalidSequence( + fmt.Sprintf("header height < consensus height (%d < %d)", header.GetHeight(), consensusState.GetHeight()), + ), + "cannot update client", + ) } consensusState, err := consensusState.CheckValidityAndUpdateState(header) @@ -214,6 +196,51 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H return nil } +// CheckMisbehaviourAndUpdateState checks for client misbehaviour and freezes the +// client if so. +func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, clientID string, evidence exported.Evidence) error { + clientState, found := k.GetClientState(ctx, clientID) + if !found { + sdk.ResultFromError(types.ErrClientNotFound(k.codespace)) + } + + err := k.checkMisbehaviour(ctx, evidence) + if err != nil { + return err + } + + clientState, err = k.freeze(ctx, clientState) + if err != nil { + return err + } + + k.SetClient(ctx, clientState) + return nil +} + +// ClientState returns a new client state with a given id as defined in +// https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#example-implementation +func (k Keeper) initialize(ctx sdk.Context, clientID string, consensusState exported.ConsensusState) types.ClientState { + clientState := types.NewClientState(clientID) + k.SetConsensusState(ctx, clientID, consensusState) + return clientState +} + +func (k Keeper) checkMisbehaviour(ctx sdk.Context, evidence exported.Evidence) error { + switch evidence.H1().ClientType() { + case exported.Tendermint: + var tmEvidence tendermint.Evidence + _, ok := evidence.(tendermint.Evidence) + if !ok { + return sdkerrors.Wrap(types.ErrInvalidClientType(k.codespace), "consensus type is not Tendermint") + } + // TODO: pass past consensus states + return tendermint.CheckMisbehaviour(tmEvidence) + default: + panic("unregistered consensus type") + } +} + // freeze updates the state of the client in the event of a misbehaviour func (k Keeper) freeze(ctx sdk.Context, clientState types.ClientState) (types.ClientState, error) { if clientState.Frozen { diff --git a/x/ibc/02-client/keeper/querier.go b/x/ibc/02-client/keeper/querier.go index 260cfc63bc7e..85ea53be9e4b 100644 --- a/x/ibc/02-client/keeper/querier.go +++ b/x/ibc/02-client/keeper/querier.go @@ -5,27 +5,26 @@ import ( abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) +// TODO: return proof + // NewQuerier creates a querier for the IBC client func NewQuerier(k Keeper) sdk.Querier { return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { switch path[0] { case types.QueryClientState: - return queryClientState(ctx, req, k) + return queryClientState(ctx, req, k) // TODO: return proof case types.QueryConsensusState: - return queryConsensusState(ctx) + return queryConsensusState(ctx, req, k) // TODO: return proof case types.QueryCommitmentPath: - return queryCommitmentPath(ctx, req, k) + return queryCommitmentPath(k) case types.QueryCommitmentRoot: - return queryCommitmentRoot(ctx, req, k) - case types.QueryHeader: - return queryHeader(ctx, req, k) + return queryCommitmentRoot(ctx, req, k) // TODO: return proof + // case types.QueryHeader: + // return queryHeader(ctx, req, k) default: return nil, sdk.ErrUnknownRequest("unknown IBC client query endpoint") } @@ -40,95 +39,81 @@ func queryClientState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } + // NOTE: clientID won't be exported as it's declared as private + // TODO: should we create a custom ExportedClientState to make it public ? + clientState, found := k.GetClientState(ctx, params.ClientID) + if !found { + return nil, types.ErrClientTypeNotFound(k.codespace) + } - // mapp := mapping(cdc, storeKey, version.Version) - // state, _, err := k.State(id).ConsensusStateCLI(q) - // if err != nil { - // return err - // } + bz, err := types.SubModuleCdc.MarshalJSON(clientState) + if err != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + } - return res, nil + return bz, nil } -func queryConsensusState(ctx sdk.Context) ([]byte, sdk.Error) { +func queryConsensusState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { + var params types.QueryClientStateParams + + err := types.SubModuleCdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + } - state := tendermint.ConsensusState{ - ChainID: commit.ChainID, - Height: uint64(commit.Height), - Root: merkle.NewRoot(commit.AppHash), - NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + consensusState, found := k.GetConsensusState(ctx, params.ClientID) + if !found { + return nil, types.ErrConsensusStateNotFound(k.codespace) } - return res, nil + bz, err := types.SubModuleCdc.MarshalJSON(consensusState) + if err != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + } + + return bz, nil } -func queryCommitmentPath(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryCommitmentPath(k Keeper) ([]byte, sdk.Error) { + path := k.GetCommitmentPath() - path := merkle.NewPrefix([][]byte{[]byte(k.mapping.storeName)}, k.mapping.PrefixBytes()) + bz, err := types.SubModuleCdc.MarshalJSON(path) + if err != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + } - return res, nil + return bz, nil } func queryCommitmentRoot(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { - var params types.QueryCommitmentRoot + var params types.QueryCommitmentRootParams err := types.SubModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } - root, _, err := k.ClientState(params.ID).RootCLI(q, params.Height) - if err != nil { - return nil, err + root, found := k.GetCommitmentRoot(ctx, params.ClientID, params.Height) + if !found { + return nil, types.ErrRootNotFound(k.codespace) } - res, err := codec.MarshalJSONIndent(types.SubModuleCdc, root) + bz, err := types.SubModuleCdc.MarshalJSON(root) if err != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) } - return res, nil + return bz, nil } -func queryHeader(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { - // node, err := ctx.GetNode() - // if err != nil { - // return err - // } - - // info, err := node.ABCIInfo() - // if err != nil { - // return err - // } - - // height := info.Response.LastBlockHeight - // prevheight := height - 1 - - // commit, err := node.Commit(&height) - // if err != nil { - // return err - // } - - // validators, err := node.Validators(&prevheight) - // if err != nil { - // return err - // } - - // nextValidators, err := node.Validators(&height) - // if err != nil { - // return err - // } - - // header := tendermint.Header{ - // SignedHeader: commit.SignedHeader, - // ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - // NextValidatorSet: tmtypes.NewValidatorSet(nextValidators.Validators), - // } - - res, err := codec.MarshalJSONIndent(types.SubModuleCdc, header) - if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", err.Error())) - } +// TODO: this is implented directly on the client +// func queryHeader(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { - return res, nil -} +// res, err := codec.MarshalJSONIndent(types.SubModuleCdc, header) +// if err != nil { +// return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", err.Error())) +// } + +// return res, nil +// } diff --git a/x/ibc/02-client/types/errors.go b/x/ibc/02-client/types/errors.go index 2657ff7ea56c..90707e84d815 100644 --- a/x/ibc/02-client/types/errors.go +++ b/x/ibc/02-client/types/errors.go @@ -15,6 +15,7 @@ const ( CodeInvalidConsensusState sdk.CodeType = 105 CodeClientTypeNotFound sdk.CodeType = 106 CodeInvalidClientType sdk.CodeType = 107 + CodeRootNotFound sdk.CodeType = 108 ) // ErrClientExists implements sdk.Error @@ -51,3 +52,8 @@ func ErrClientTypeNotFound(codespace sdk.CodespaceType) sdk.Error { func ErrInvalidClientType(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidClientType, "client type mismatch") } + +// ErrRootNotFound implements sdk.Error +func ErrRootNotFound(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeRootNotFound, "commitment root not found") +} diff --git a/x/ibc/02-client/types/keys.go b/x/ibc/02-client/types/keys.go index 5869852a741f..edc91fe2c4a3 100644 --- a/x/ibc/02-client/types/keys.go +++ b/x/ibc/02-client/types/keys.go @@ -7,52 +7,61 @@ import ( const ( // SubModuleName defines the IBC client name SubModuleName = "clients" + + // StoreKey is the store key string for IBC client + StoreKey = SubModuleName + + // RouterKey is the message route for IBC client + RouterKey = SubModuleName + + // QuerierRoute is the querier route for IBC client + QuerierRoute = SubModuleName ) // The following paths are the keys to the store as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#path-space -// clientStatePath takes an Identifier and returns a Path under which to store a +// ClientStatePath takes an Identifier and returns a Path under which to store a // particular client state -func clientStatePath(clientID string) string { +func ClientStatePath(clientID string) string { return fmt.Sprintf("clients/%s/state", clientID) } -// clientTypePath takes an Identifier and returns Path under which to store the +// ClientTypePath takes an Identifier and returns Path under which to store the // type of a particular client. -func clientTypePath(clientID string) string { +func ClientTypePath(clientID string) string { return fmt.Sprintf("clients/%s/type", clientID) } -// consensusStatePath takes an Identifier and returns a Path under which to +// ConsensusStatePath takes an Identifier and returns a Path under which to // store the consensus state of a client. -func consensusStatePath(clientID string) string { +func ConsensusStatePath(clientID string) string { return fmt.Sprintf("clients/%s/consensusState", clientID) } -// consensusStatePath takes an Identifier and returns a Path under which to +// RootPath takes an Identifier and returns a Path under which to // store the consensus state of a client. -func rootPath(clientID string, height uint64) string { +func RootPath(clientID string, height uint64) string { return fmt.Sprintf("clients/%s/roots/%d", clientID, height) } // KeyClientState returns the store key for a particular client state func KeyClientState(clientID string) []byte { - return []byte(clientStatePath(clientID)) + return []byte(ClientStatePath(clientID)) } // KeyClientType returns the store key for type of a particular client func KeyClientType(clientID string) []byte { - return []byte(clientTypePath(clientID)) + return []byte(ClientTypePath(clientID)) } // KeyConsensusState returns the store key for the consensus state of a particular // client func KeyConsensusState(clientID string) []byte { - return []byte(consensusStatePath(clientID)) + return []byte(ConsensusStatePath(clientID)) } // KeyRoot returns the store key for a commitment root of a particular // client at a given height func KeyRoot(clientID string, height uint64) []byte { - return []byte(rootPath(clientID, height)) + return []byte(RootPath(clientID, height)) } diff --git a/x/ibc/02-client/types/msgs.go b/x/ibc/02-client/types/msgs.go index 5f9c7286b153..17e1848cd577 100644 --- a/x/ibc/02-client/types/msgs.go +++ b/x/ibc/02-client/types/msgs.go @@ -10,15 +10,17 @@ var _ sdk.Msg = MsgCreateClient{} // MsgCreateClient defines a message to create an IBC client type MsgCreateClient struct { - ClientID string `json:"id" yaml:"id"` + ClientID string `json:"client_id" yaml:"client_id"` + ClientType string `json:"client_type" yaml:"client_type"` ConsensusState exported.ConsensusState `json:"consensus_state" yaml:"consensus_address"` Signer sdk.AccAddress `json:"address" yaml:"address"` } // NewMsgCreateClient creates a new MsgCreateClient instance -func NewMsgCreateClient(id string, consensusState exported.ConsensusState, signer sdk.AccAddress) MsgCreateClient { +func NewMsgCreateClient(id, clientType string, consensusState exported.ConsensusState, signer sdk.AccAddress) MsgCreateClient { return MsgCreateClient{ ClientID: id, + ClientType: clientType, ConsensusState: consensusState, Signer: signer, } @@ -39,6 +41,7 @@ func (msg MsgCreateClient) ValidateBasic() sdk.Error { if msg.Signer.Empty() { return sdk.ErrInvalidAddress("empty address") } + // TODO: validate client type and ID return nil } @@ -56,7 +59,7 @@ var _ sdk.Msg = MsgUpdateClient{} // MsgUpdateClient defines a message to update an IBC client type MsgUpdateClient struct { - ClientID string `json:"id" yaml:"id"` + ClientID string `json:"client_id" yaml:"client_id"` Header exported.Header `json:"header" yaml:"header"` Signer sdk.AccAddress `json:"address" yaml:"address"` } @@ -85,6 +88,7 @@ func (msg MsgUpdateClient) ValidateBasic() sdk.Error { if msg.Signer.Empty() { return sdk.ErrInvalidAddress("empty address") } + // TODO: validate client ID return nil } @@ -129,6 +133,7 @@ func (msg MsgSubmitMisbehaviour) ValidateBasic() sdk.Error { if msg.Signer.Empty() { return sdk.ErrInvalidAddress("empty address") } + // TODO: validate client ID return nil } diff --git a/x/ibc/02-client/types/querier.go b/x/ibc/02-client/types/querier.go index 3e10883481c4..17c41a01b40a 100644 --- a/x/ibc/02-client/types/querier.go +++ b/x/ibc/02-client/types/querier.go @@ -5,34 +5,34 @@ const ( QueryClientState = "clientState" QueryConsensusState = "consensusState" QueryCommitmentPath = "commitmentPath" - QueryCommitmentRoot = "commitmentRoot" - QueryHeader = "header" + QueryCommitmentRoot = "roots" ) // QueryClientStateParams defines the params for the following queries: -// - 'custom/ibc/client/clientState' +// - 'custom/ibc/clients//clientState' +// - 'custom/ibc/clients//consensusState' type QueryClientStateParams struct { - ID string + ClientID string } // NewQueryClientStateParams creates a new QueryClientStateParams instance func NewQueryClientStateParams(id string) QueryClientStateParams { return QueryClientStateParams{ - ID: id, + ClientID: id, } } // QueryCommitmentRootParams defines the params for the following queries: -// - 'custom/ibc/client/commitmentRoot' +// - 'custom/ibc/clients//roots/' type QueryCommitmentRootParams struct { - ID string - Height uint64 + ClientID string + Height uint64 } // NewQueryCommitmentRootParams creates a new QueryCommitmentRootParams instance func NewQueryCommitmentRootParams(id string, height uint64) QueryCommitmentRootParams { return QueryCommitmentRootParams{ - ID: id, - Height: height, + ClientID: id, + Height: height, } } diff --git a/x/ibc/02-client/types/state.go b/x/ibc/02-client/types/state.go index 873b3d9ab8aa..d900908b0018 100644 --- a/x/ibc/02-client/types/state.go +++ b/x/ibc/02-client/types/state.go @@ -1,21 +1,10 @@ package types -import ( - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - // ClientState is a type that represents the state of a client. // Any actor holding the Stage can access on and modify that client information. type ClientState struct { // Client ID id string - // Past state roots required to avoid race conditions between client updates - // and proof-carrying transactions as defined in - // https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#utilising-past-roots - Roots []ics23.Root `json:"roots" yaml:"roots"` - // Consensus state bytes - ConsensusState exported.ConsensusState `json:"consensus_state" yaml:"consensus_state"` // Boolean that states if the client is frozen when a misbehaviour proof is // submitted in the event of an equivocation. Frozen bool `json:"frozen" yaml:"frozen"` @@ -33,26 +22,3 @@ func NewClientState(id string) ClientState { func (cs ClientState) ID() string { return cs.id } - -// func (state State) RootCLI(q cs.ABCIQuerier, height uint64) (res ics23.Root, proof merkle.Proof, err error) { -// root := cs.Roots.Value(height) -// tmProof, err := root.Query(q, &res) -// proof = merkle.NewProofFromValue(tmProof, cs.prefix(), root) -// return -// } - -// func (state State) ConsensusStateCLI(q cs.ABCIQuerier) (res exported.ConsensusState, proof merkle.Proof, err error) { -// tmproof, err := cs.ConsensusState.Query(q, &res) -// proof = merkle.NewProofFromValue(tmproof, cs.prefix(), cs.ConsensusState) -// return -// } - -// func (state State) FrozenCLI(q cs.ABCIQuerier) (res bool, proof merkle.Proof, err error) { -// res, tmproof, err := cs.Frozen.Query(q) -// proof = merkle.NewProofFromValue(tmproof, cs.prefix(), cs.Frozen) -// return -// } - -// func (state State) prefix() []byte { -// return bytes.Split(cs.ConsensusState.KeyBytes(), []byte(SubModuleName+"/"))[0] -// } diff --git a/x/ibc/02-client/types/tendermint/consensus_state.go b/x/ibc/02-client/types/tendermint/consensus_state.go index 5ebb973719bc..dd9b2413a422 100644 --- a/x/ibc/02-client/types/tendermint/consensus_state.go +++ b/x/ibc/02-client/types/tendermint/consensus_state.go @@ -32,13 +32,13 @@ func (cs ConsensusState) GetHeight() uint64 { return cs.Height } -// GetRoot returns the commitment Rootgit +// GetRoot returns the commitment Root for the specific func (cs ConsensusState) GetRoot() ics23.Root { return cs.Root } // CheckValidityAndUpdateState checks if the provided header is valid and updates -// the consensus state if appropiate +// the consensus state if appropriate func (cs ConsensusState) CheckValidityAndUpdateState(header exported.Header) (exported.ConsensusState, error) { tmHeader, ok := header.(Header) if !ok { @@ -53,23 +53,29 @@ func (cs ConsensusState) CheckValidityAndUpdateState(header exported.Header) (ex } // checkValidity checks if the Tendermint header is valid +// +// CONTRACT: assumes header.Height > consensusState.Height func (cs ConsensusState) checkValidity(header Header) error { - // TODO: shouldn't we check that header.Height > cs.Height? + // check if the hash from the consensus set and header + // matches nextHash := cs.NextValidatorSet.Hash() if cs.Height == uint64(header.Height-1) && - !bytes.Equal(header.ValidatorsHash, nextHash) { - return lerr.ErrUnexpectedValidators(header.ValidatorsHash, nextHash) + !bytes.Equal(nextHash, header.ValidatorsHash) { + return lerr.ErrUnexpectedValidators(nextHash, header.ValidatorsHash) } + // validate the next validator set hash from the header nextHash = header.NextValidatorSet.Hash() if !bytes.Equal(header.NextValidatorsHash, nextHash) { return lerr.ErrUnexpectedValidators(header.NextValidatorsHash, nextHash) } + // basic consistency check if err := header.ValidateBasic(cs.ChainID); err != nil { return err } + // abortTransactionUnless(consensusState.publicKey.verify(header.signature)) return cs.NextValidatorSet.VerifyFutureCommit( header.ValidatorSet, cs.ChainID, header.Commit.BlockID, header.Height, header.Commit, ) @@ -77,10 +83,8 @@ func (cs ConsensusState) checkValidity(header Header) error { // update the consensus state from a new header func (cs ConsensusState) update(header Header) ConsensusState { - return ConsensusState{ - ChainID: cs.ChainID, - Height: uint64(header.Height), - Root: merkle.NewRoot(header.AppHash), - NextValidatorSet: header.NextValidatorSet, - } + cs.Height = header.GetHeight() + cs.Root = merkle.NewRoot(header.AppHash) + cs.NextValidatorSet = header.NextValidatorSet + return cs } diff --git a/x/ibc/02-client/types/tendermint/header.go b/x/ibc/02-client/types/tendermint/header.go index 408aaed40d28..9d6178cc2d7f 100644 --- a/x/ibc/02-client/types/tendermint/header.go +++ b/x/ibc/02-client/types/tendermint/header.go @@ -17,13 +17,15 @@ type Header struct { } // ClientType defines that the Header is a Tendermint consensus algorithm -func (header Header) ClientType() exported.ClientType { +func (h Header) ClientType() exported.ClientType { return exported.Tendermint } // GetHeight returns the current height -func (header Header) GetHeight() uint64 { - return uint64(header.Height) +// +// NOTE: also referred as `sequence` +func (h Header) GetHeight() uint64 { + return uint64(h.Height) } var _ exported.Evidence = Evidence{} diff --git a/x/ibc/02-client/types/tendermint/misbehaviour.go b/x/ibc/02-client/types/tendermint/misbehaviour.go index 53fcbcca6bd0..15787450e4ca 100644 --- a/x/ibc/02-client/types/tendermint/misbehaviour.go +++ b/x/ibc/02-client/types/tendermint/misbehaviour.go @@ -2,12 +2,10 @@ package tendermint import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ) // CheckMisbehaviour checks if the evidence provided is a misbehaviour -func CheckMisbehaviour(evidence exported.Evidence) sdk.Error { - +func CheckMisbehaviour(evidence Evidence) sdk.Error { // TODO: check evidence return nil } From 83f4c1bf7818bdc19470332715af07d48d942572 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 8 Oct 2019 16:41:27 +0200 Subject: [PATCH 266/378] logger and tx long description --- x/ibc/02-client/client/cli/query.go | 10 ++++----- x/ibc/02-client/client/cli/tx.go | 26 +++++++++++++++-------- x/ibc/02-client/keeper/keeper.go | 2 ++ x/ibc/02-client/keeper/querier.go | 21 +++--------------- x/ibc/23-commitment/merkle/merkle_test.go | 1 - 5 files changed, 27 insertions(+), 33 deletions(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 8d873f29df9d..862cfc25619e 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -46,7 +46,7 @@ func GetCmdQueryClientState(storeKey string, cdc *codec.Codec) *cobra.Command { Use: "state", Short: "Query a client state", Long: strings.TrimSpace( - fmt.Sprintf(`Query stored client + fmt.Sprintf(`Query stored client state Example: $ %s query ibc client state [client-id] @@ -83,7 +83,7 @@ func GetCmdQueryRoot(storeKey string, cdc *codec.Codec) *cobra.Command { Use: "root", Short: "Query stored root", Long: strings.TrimSpace( - fmt.Sprintf(`Query stored client + fmt.Sprintf(`Query a stored commitment root at a specific height for a particular client Example: $ %s query ibc client root [client-id] [height] @@ -123,9 +123,9 @@ $ %s query ibc client root [client-id] [height] func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "consensus-state", - Short: "Query the latest consensus state of the running chain", + Short: "Query the latest consensus state of the client", Long: strings.TrimSpace( - fmt.Sprintf(`Query consensus state + fmt.Sprintf(`Query the consensus state for a particular client Example: $ %s query ibc client consensus-state [client-id] @@ -192,7 +192,7 @@ func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "header", Short: "Query the latest header of the running chain", - Long: strings.TrimSpace(fmt.Sprintf(`Query the latest header + Long: strings.TrimSpace(fmt.Sprintf(`Query the latest Tendermint header Example: $ %s query ibc client header diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index 56fa776098f6..a7304166268d 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -1,6 +1,7 @@ package cli import ( + "fmt" "io/ioutil" "strings" @@ -10,6 +11,7 @@ import ( "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/version" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/client/utils" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" @@ -50,10 +52,12 @@ func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "create", Short: "create new client with a consensus state", - Long: strings.TrimSpace(`create new client with a specified identifier and consensus state: + Long: strings.TrimSpace(fmt.Sprintf(`create new client with a specified identifier and consensus state: -$ tx ibc client create [client-id] [path/to/consensus_state.json] --from node0 --home ../node0/cli --chain-id $CID - `), +Example: +$ %s tx ibc client create [client-id] [path/to/consensus_state.json] --from node0 --home ../node0/cli --chain-id $CID + `, version.ClientName), + ), Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) @@ -87,10 +91,12 @@ func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "update", Short: "update existing client with a header", - Long: strings.TrimSpace(`update existing client with a header: + Long: strings.TrimSpace(fmt.Sprintf(`update existing client with a header: -$ tx ibc client create [client-id] [path/to/header.json] --from node0 --home ../node0/cli --chain-id $CID - `), +Example: +$ %s tx ibc client create [client-id] [path/to/header.json] --from node0 --home ../node0/cli --chain-id $CID + `, version.ClientName), + ), Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) @@ -125,10 +131,12 @@ func GetCmdSubmitMisbehaviour(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "misbehaviour", Short: "submit a client misbehaviour", - Long: strings.TrimSpace(`submit a client misbehaviour to invalidate to invalidate previous state roots and prevent future updates: + Long: strings.TrimSpace(fmt.Sprintf(`submit a client misbehaviour to invalidate to invalidate previous state roots and prevent future updates: -$ tx ibc client misbehaviour [client-id] [path/to/evidence.json] --from node0 --home ../node0/cli --chain-id $CID - `), +Example: +$ %s tx ibc client misbehaviour [client-id] [path/to/evidence.json] --from node0 --home ../node0/cli --chain-id $CID + `, version.ClientName), + ), Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index cc6c24ac3702..37cf07b2db8e 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -193,6 +193,7 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H k.SetConsensusState(ctx, clientID, consensusState) k.SetCommitmentRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) + k.Logger(ctx).Info(fmt.Sprintf("client %s updated at height %d", clientID, consensusState.GetHeight())) return nil } @@ -215,6 +216,7 @@ func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, clientID string } k.SetClient(ctx, clientState) + k.Logger(ctx).Info(fmt.Sprintf("client %s frozen due to misbehaviour", clientID)) return nil } diff --git a/x/ibc/02-client/keeper/querier.go b/x/ibc/02-client/keeper/querier.go index 85ea53be9e4b..3b014d916ac3 100644 --- a/x/ibc/02-client/keeper/querier.go +++ b/x/ibc/02-client/keeper/querier.go @@ -9,22 +9,18 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" ) -// TODO: return proof - // NewQuerier creates a querier for the IBC client func NewQuerier(k Keeper) sdk.Querier { return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { switch path[0] { case types.QueryClientState: - return queryClientState(ctx, req, k) // TODO: return proof + return queryClientState(ctx, req, k) case types.QueryConsensusState: - return queryConsensusState(ctx, req, k) // TODO: return proof + return queryConsensusState(ctx, req, k) case types.QueryCommitmentPath: return queryCommitmentPath(k) case types.QueryCommitmentRoot: - return queryCommitmentRoot(ctx, req, k) // TODO: return proof - // case types.QueryHeader: - // return queryHeader(ctx, req, k) + return queryCommitmentRoot(ctx, req, k) default: return nil, sdk.ErrUnknownRequest("unknown IBC client query endpoint") } @@ -106,14 +102,3 @@ func queryCommitmentRoot(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]by return bz, nil } - -// TODO: this is implented directly on the client -// func queryHeader(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { - -// res, err := codec.MarshalJSONIndent(types.SubModuleCdc, header) -// if err != nil { -// return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", err.Error())) -// } - -// return res, nil -// } diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go index 0c73e7676ce8..0026ac0d0123 100644 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ b/x/ibc/23-commitment/merkle/merkle_test.go @@ -12,7 +12,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store" - "github.com/cosmos/cosmos-sdk/store/state" "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" From 178912f2fd4ae7c977defd2a7dadee1d8ac41d67 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 8 Oct 2019 16:49:42 +0200 Subject: [PATCH 267/378] ineffassign --- x/ibc/02-client/keeper/keeper.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index 37cf07b2db8e..d468e4de653d 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -129,7 +129,7 @@ func (k Keeper) CreateClient( ctx sdk.Context, clientID string, clientTypeStr string, consensusState exported.ConsensusState, ) (types.ClientState, error) { - clientState, found := k.GetClientState(ctx, clientID) + _, found := k.GetClientState(ctx, clientID) if found { return types.ClientState{}, types.ErrClientExists(k.codespace) } @@ -144,7 +144,7 @@ func (k Keeper) CreateClient( return types.ClientState{}, types.ErrInvalidClientType(k.codespace) } - clientState = k.initialize(ctx, clientID, consensusState) + clientState := k.initialize(ctx, clientID, consensusState) k.SetCommitmentRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) k.SetClient(ctx, clientState) k.SetClientType(ctx, clientID, clientType) From 9a225e9fce9c6d60ce13792a2fc93dfc57a78bd2 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 8 Oct 2019 17:17:04 +0200 Subject: [PATCH 268/378] Apply suggestions from code review Co-Authored-By: Jack Zampolin --- x/ibc/02-client/client/cli/query.go | 6 +++--- x/ibc/02-client/client/cli/tx.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 862cfc25619e..108d77233d55 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -43,7 +43,7 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { // a given id as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#query func GetCmdQueryClientState(storeKey string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ - Use: "state", + Use: "state [client-id]", Short: "Query a client state", Long: strings.TrimSpace( fmt.Sprintf(`Query stored client state @@ -80,7 +80,7 @@ $ %s query ibc client state [client-id] // GetCmdQueryRoot defines the command to query func GetCmdQueryRoot(storeKey string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ - Use: "root", + Use: "root [client-id] [height]", Short: "Query stored root", Long: strings.TrimSpace( fmt.Sprintf(`Query a stored commitment root at a specific height for a particular client @@ -122,7 +122,7 @@ $ %s query ibc client root [client-id] [height] // the chain as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#query func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ - Use: "consensus-state", + Use: "consensus-state [client-id]", Short: "Query the latest consensus state of the client", Long: strings.TrimSpace( fmt.Sprintf(`Query the consensus state for a particular client diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index a7304166268d..180a713d5615 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -50,7 +50,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { // in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "create", + Use: "create [client-id] [path/to/consensus_state.json]", Short: "create new client with a consensus state", Long: strings.TrimSpace(fmt.Sprintf(`create new client with a specified identifier and consensus state: From fe7da5f48f20a4e84843b273b8a25b2a5f3b572a Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 8 Oct 2019 17:17:36 +0200 Subject: [PATCH 269/378] Apply suggestions from code review Co-Authored-By: Jack Zampolin --- x/ibc/02-client/client/cli/tx.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index 180a713d5615..c9aacb3747fd 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -89,7 +89,7 @@ $ %s tx ibc client create [client-id] [path/to/consensus_state.json] --from node // https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#update func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "update", + Use: "update [client-id] [path/to/header.json]", Short: "update existing client with a header", Long: strings.TrimSpace(fmt.Sprintf(`update existing client with a header: @@ -129,7 +129,7 @@ $ %s tx ibc client create [client-id] [path/to/header.json] --from node0 --home // https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#misbehaviour func GetCmdSubmitMisbehaviour(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "misbehaviour", + Use: "misbehaviour [client-it] [path/to/evidence.json]", Short: "submit a client misbehaviour", Long: strings.TrimSpace(fmt.Sprintf(`submit a client misbehaviour to invalidate to invalidate previous state roots and prevent future updates: From c8ff483442efc904415d5aa081d3352e5293e1fb Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 8 Oct 2019 21:23:57 +0200 Subject: [PATCH 270/378] remove store accessors --- x/ibc/03-connection/keeper/handshake.go | 364 ++++++++++++------------ x/ibc/03-connection/keeper/keeper.go | 234 ++++++--------- x/ibc/03-connection/types/connection.go | 6 +- x/ibc/03-connection/types/errors.go | 35 ++- x/ibc/03-connection/types/keys.go | 37 ++- x/ibc/03-connection/types/msgs.go | 25 +- x/ibc/03-connection/types/querier.go | 41 +++ 7 files changed, 376 insertions(+), 366 deletions(-) create mode 100644 x/ibc/03-connection/types/querier.go diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index 8741e2b7b08d..9e0f5cb2030f 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -1,217 +1,213 @@ -package tyoes +package keeper import ( "errors" - "github.com/cosmos/cosmos-sdk/store/state" sdk "github.com/cosmos/cosmos-sdk/types" - + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -type HandshakeState struct { - State - - Stage state.Enum - CounterpartyClient state.String - Counterparty CounterHandshakeState -} - -type CounterHandshakeState struct { - CounterState - - Stage ics23.Enum - CounterpartyClient ics23.String -} - -// CONTRACT: client and remote must be filled by the caller -func (k Keeper) CreateState(parent State) HandshakeState { - return HandshakeState{ - State: parent, - Stage: k.man.protocol.Value([]byte(parent.id + "/state")).Enum(), - CounterpartyClient: k.man.protocol.Value([]byte(parent.id + "/counterpartyClient")).String(), - } -} - -func (man CounterpartyHandshaker) CreateState(id string) CounterHandshakeState { - return CounterHandshakeState{ - CounterState: k.man.CreateState(id), - Stage: k.man.protocol.Value([]byte(id + "/state")).Enum(), - CounterpartyClient: k.man.protocol.Value([]byte(id + "/counterpartyClient")).String(), - } -} - -func (k Keeper) create(ctx sdk.Context, id string, connection Connection, counterpartyClient string) (obj HandshakeState, err error) { - cobj, err := k.man.create(ctx, id, connection, HandshakeKind) - if err != nil { - return - } - obj = k.CreateState(cobj) - obj.CounterpartyClient.Set(ctx, counterpartyClient) - obj.Counterparty = k.CounterParty.CreateState(connection.Counterparty) - return obj, nil -} - -func (k Keeper) query(ctx sdk.Context, id string) (obj HandshakeState, err error) { - cobj, err := k.man.query(ctx, id, HandshakeKind) - if err != nil { - return - } - obj = k.CreateState(cobj) - obj.Counterparty = k.counterParty.CreateState(obj.GetConnection(ctx).Counterparty) - return -} - +// // CONTRACT: client and remote must be filled by the caller +// func (k Keeper) CreateState(parent State) HandshakeState { +// return HandshakeState{ +// State: parent, +// Stage: k.man.protocol.Value([]byte(parent.id + "/state")).Enum(), +// CounterpartyClient: k.man.protocol.Value([]byte(parent.id + "/counterpartyClient")).String(), +// } +// } + +// func (man CounterpartyHandshaker) CreateState(id string) CounterHandshakeState { +// return CounterHandshakeState{ +// CounterState: k.man.CreateState(id), +// Stage: k.man.protocol.Value([]byte(id + "/state")).Enum(), +// CounterpartyClient: k.man.protocol.Value([]byte(id + "/counterpartyClient")).String(), +// } +// } + +// func (k Keeper) create(ctx sdk.Context, id string, connection Connection, counterpartyClient string) (obj HandshakeState, err error) { +// cobj, err := k.man.create(ctx, id, connection, HandshakeKind) +// if err != nil { +// return +// } +// obj = k.CreateState(cobj) +// obj.CounterpartyClient.Set(ctx, counterpartyClient) +// obj.Counterparty = k.CounterParty.CreateState(connection.Counterparty) +// return obj, nil +// } + +// func (k Keeper) query(ctx sdk.Context, id string) (obj HandshakeState, err error) { +// cobj, err := k.man.query(ctx, id, HandshakeKind) +// if err != nil { +// return +// } +// obj = k.CreateState(cobj) +// obj.Counterparty = k.counterParty.CreateState(obj.GetConnection(ctx).Counterparty) +// return +// } + +// ConnOpenInit initialises a connection attempt on chain A. func (k Keeper) ConnOpenInit( ctx sdk.Context, connectionID, clientID string, counterparty types.Counterparty, -) (HandshakeState, sdk.Error) { - // man.Create() will ensure - // assert(get("connections/{identifier}") === null) and - // set("connections{identifier}", connection) +) error { + _, found := k.GetConnection(ctx, connectionID) + if found { + return sdkerrors.Wrap(types.ErrConnectionExists(k.codespace), "cannot initialize connection") + } - // connection := types.NewConnectionEnd(types.INIT, clientID, counterparty, []string{}) // TODO: getCompatibleVersions() + connection := types.NewConnectionEnd(clientID, counterparty, k.getCompatibleVersions()) + connection.State = types.INIT - obj, err := k.create(ctx, id, connection, counterpartyClient) + k.SetConnection(ctx, connectionID, connection) + err := k.addConnectionToClient(ctx, clientID, connectionID) if err != nil { - return HandshakeState{}, err + sdkerrors.Wrap(err, "cannot initialize connection") } - return obj, nil + return nil } -// Using proofs: counterParty.{connection,state,nextTimeout,counterpartyClient, client} +// ConnOpenTry relays notice of a connection attempt on chain A to chain B (this +// code is executed on chain B). func (k Keeper) ConnOpenTry(ctx sdk.Context, connectionID, clientID string, counterparty types.Counterparty, -) (obj HandshakeState, err error) { - - obj, err = k.create(ctx, id, connection, counterpartyClient) - if err != nil { - return - } - - ctx, err = k.Context(ctx, height, proofs) - if err != nil { - return - } - - if !obj.Counterparty.Stage.Is(ctx, Init) { - err = errors.New("counterParty state not init") - return - } - - if !obj.Counterparty.Connection.Is(ctx, Connection{ - Client: counterpartyClient, - Counterparty: id, - Path: obj.path, - }) { - err = errors.New("wrong counterParty connection") - return - } - - if !obj.Counterparty.CounterpartyClient.Is(ctx, connection.Client) { - err = errors.New("counterParty client not match") - 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.Stage.Set(ctx, OpenTry) - - return + counterpartyVersions []string, proofInit ics23.Proof, proofHeight uint64, consensusHeight uint64, +) error { + + if consensusHeight > uint64(ctx.BlockHeight()) { + return errors.New("invalid consensus height") + } + + // obj, err = k.create(ctx, id, connection, counterpartyClient) + // if err != nil { + // return + // } + + // ctx, err = k.Context(ctx, height, proofs) + // if err != nil { + // return + // } + + // if !obj.Counterparty.Stage.Is(ctx, Init) { + // err = errors.New("counterParty state not init") + // return + // } + + // if !obj.Counterparty.Connection.Is(ctx, Connection{ + // Client: counterpartyClient, + // Counterparty: id, + // Path: obj.path, + // }) { + // err = errors.New("wrong counterParty connection") + // return + // } + + // if !obj.Counterparty.CounterpartyClient.Is(ctx, connection.Client) { + // err = errors.New("counterParty client not match") + // 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.Stage.Set(ctx, OpenTry) + + return nil } -// Using proofs: counterParty.{connection, state, timeout, counterpartyClient, client} -func (k Keeper) OpenAck(ctx sdk.Context, +// ConnOpenAck relays acceptance of a connection open attempt from chain B back +// to chain A (this code is executed on chain A). +func (k Keeper) ConnOpenAck(ctx sdk.Context, proofs []ics23.Proof, height uint64, id string, -) (obj HandshakeState, err error) { - obj, err = man.query(ctx, id) - if err != nil { - return - } - - ctx, err = obj.Context(ctx, height, proofs) - if err != nil { - return - } - - if !obj.Stage.Transit(ctx, Init, Open) { - err = errors.New("ack on non-init connection") - return - } - - if !obj.Counterparty.Connection.Is(ctx, Connection{ - Client: obj.CounterpartyClient.Get(ctx), - Counterparty: obj.ID(), - Path: obj.path, - }) { - err = errors.New("wrong counterParty") - return - } - - 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 - } - - // TODO: implement in v1 - /* - var expected client.ConsensusState - // obj.self.Get(ctx, expheight, &expected) - if !obj.counterParty.client.Is(ctx, expected) { - // return errors.New("unexpected counterParty client value") - } - */ - obj.Available.Set(ctx, true) - - return +) error { + // obj, err = man.query(ctx, id) + // if err != nil { + // return + // } + + // ctx, err = obj.Context(ctx, height, proofs) + // if err != nil { + // return + // } + + // if !obj.Stage.Transit(ctx, Init, Open) { + // err = errors.New("ack on non-init connection") + // return + // } + + // if !obj.Counterparty.Connection.Is(ctx, Connection{ + // Client: obj.CounterpartyClient.Get(ctx), + // Counterparty: obj.ID(), + // Path: obj.path, + // }) { + // err = errors.New("wrong counterParty") + // return + // } + + // 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 + // } + + // // TODO: implement in v1 + // /* + // var expected client.ConsensusState + // // obj.self.Get(ctx, expheight, &expected) + // if !obj.counterParty.client.Is(ctx, expected) { + // // return errors.New("unexpected counterParty client value") + // } + // */ + // obj.Available.Set(ctx, true) + + return nil } -// Using proofs: counterParty.{connection,state, nextTimeout} -func (k Keeper) OpenConfirm(ctx sdk.Context, +// ConnOpenConfirm confirms opening of a connection on chain A to chain B, after +// which the connection is open on both chains (this code is executed on chain B). +func (k Keeper) ConnOpenConfirm(ctx sdk.Context, proofs []ics23.Proof, height uint64, - id string) (obj HandshakeState, err error) { + id string) error { - obj, err = man.query(ctx, id) - if err != nil { - return - } + // obj, err = man.query(ctx, id) + // if err != nil { + // return + // } - ctx, err = obj.Context(ctx, height, proofs) - if err != nil { - return - } + // ctx, err = obj.Context(ctx, height, proofs) + // if err != nil { + // return + // } - if !obj.Stage.Transit(ctx, OpenTry, Open) { - err = errors.New("confirm on non-try connection") - return - } + // if !obj.Stage.Transit(ctx, OpenTry, Open) { + // err = errors.New("confirm on non-try connection") + // return + // } - if !obj.Counterparty.Stage.Is(ctx, Open) { - err = errors.New("counterParty state not open") - return - } + // if !obj.Counterparty.Stage.Is(ctx, Open) { + // err = errors.New("counterParty state not open") + // return + // } - obj.Available.Set(ctx, true) + // obj.Available.Set(ctx, true) - return + return nil } diff --git a/x/ibc/03-connection/keeper/keeper.go b/x/ibc/03-connection/keeper/keeper.go index d5551222ed37..a3740d33336b 100644 --- a/x/ibc/03-connection/keeper/keeper.go +++ b/x/ibc/03-connection/keeper/keeper.go @@ -1,192 +1,136 @@ -package connection +package keeper import ( - "errors" + "fmt" + + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/state" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) // Keeper defines the IBC connection keeper type Keeper struct { - mapping state.Mapping + storeKey sdk.StoreKey + cdc *codec.Codec + codespace sdk.CodespaceType + prefix []byte // prefix bytes for accessing the store + clientKeeper types.ClientKeeper - - counterparty CounterpartyManager - path merkle.Prefix } // NewKeeper creates a new IBC connection Keeper instance -func NewKeeper(mapping state.Mapping, ck types.ClientKeeper) Keeper { +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType, ck types.ClientKeeper) Keeper { return Keeper{ - mapping: mapping.Prefix([]byte(types.SubModuleName + "/")), + storeKey: key, + cdc: cdc, + codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/connections", + prefix: []byte(types.SubModuleName + "/"), // "connections/" clientKeeper: ck, - counterparty: NewCounterpartyManager(mapping.Cdc()), - path: merkle.NewPrefix([][]byte{[]byte(mapping.StoreName())}, mapping.PrefixBytes()), - } -} - -type CounterpartyManager struct { - mapping commitment.Mapping - - client ics02.CounterpartyManager -} - -func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { - mapping := commitment.NewMapping(cdc, nil) - - return CounterpartyManager{ - mapping: mapping.Prefix([]byte(types.SubModuleName + "/")), - - client: ics02.NewCounterpartyManager(cdc), } } -type State struct { - id string - - mapping state.Mapping - Connection state.Value - Available state.Boolean - - Kind state.String - - Client ics02.State - - path merkle.Prefix +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName)) } -// CONTRACT: client must be filled by the caller -func (k Keeper) State(id string) State { - return State{ - id: id, - mapping: k.mapping.Prefix([]byte(id + "/")), - Connection: k.mapping.Value([]byte(id)), - Available: k.mapping.Value([]byte(id + "/available")).Boolean(), - Kind: k.mapping.Value([]byte(id + "/kind")).String(), - path: k.path, +// GetConnection returns a connection with a particular identifier +func (k Keeper) GetConnection(ctx sdk.Context, connectionID string) (types.ConnectionEnd, bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(types.KeyConnection(connectionID)) + if bz == nil { + return types.ConnectionEnd{}, false } -} -type CounterState struct { - id string - mapping commitment.Mapping - Connection commitment.Value - Available commitment.Boolean - Kind commitment.String - Client ics02.CounterState // nolint: unused + var connection types.ConnectionEnd + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &connection) + return connection, true } -// CreateState creates a new CounterState instance. -// CONTRACT: client should be filled by the caller -func (k CounterpartyManager) CreateState(id string) CounterState { - return CounterState{ - id: id, - mapping: k.mapping.Prefix([]byte(id + "/")), - Connection: k.mapping.Value([]byte(id)), - Available: k.mapping.Value([]byte(id + "/available")).Boolean(), - Kind: k.mapping.Value([]byte(id + "/kind")).String(), - } +// SetConnection sets a connection to the store +func (k Keeper) SetConnection(ctx sdk.Context, connectionID string, connection types.ConnectionEnd) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(connection) + store.Set(types.KeyConnection(connectionID), bz) } -func (state State) Context(ctx sdk.Context, height uint64, proofs []commitment.Proof) (sdk.Context, error) { - root, err := state.Client.GetRoot(ctx, height) - if err != nil { - return ctx, err +// GetClientConnectionPaths returns all the connection paths stored under a +// particular client +func (k Keeper) GetClientConnectionPaths(ctx sdk.Context, clientID string) ([]string, bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(types.KeyClientConnections(clientID)) + if bz == nil { + return nil, false } - store, err := commitment.NewStore( - root, - state.GetConnection(ctx).Path, - proofs, - ) - if err != nil { - return ctx, err - } - - return commitment.WithStore(ctx, store), nil -} - -func (state State) ID() string { - return state.id -} - -func (state State) GetConnection(ctx sdk.Context) (res types.ConnectionEnd) { - state.Connection.Get(ctx, &res) - return -} - -func (state State) Sendable(ctx sdk.Context) bool { - return kinds[state.Kind.Get(ctx)].Sendable -} - -func (state State) Receivable(ctx sdk.Context) bool { - return kinds[state.Kind.Get(ctx)].Receivable + var paths []string + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &paths) + return paths, true } -func (state State) exists(ctx sdk.Context) bool { - return state.Connection.Exists(ctx) +// SetClientConnectionPaths sets the connections paths for client +func (k Keeper) SetClientConnectionPaths(ctx sdk.Context, clientID string, paths []string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(paths) + store.Set(types.KeyClientConnections(clientID), bz) } -func (k Keeper) Cdc() *codec.Codec { - return k.mapping.Cdc() -} - -func (k Keeper) create(ctx sdk.Context, id string, connection Connection, kind string) (state State, err error) { - state = k.State(id) - if state.exists(ctx) { - err = errors.New("Stage already exists") - return +// addConnectionToClient is used to add a connection identifier to the set of +// connections associated with a client. +// +// CONTRACT: client must already exist +func (k Keeper) addConnectionToClient(ctx sdk.Context, clientID, connectionID string) sdk.Error { + conns, found := k.GetClientConnectionPaths(ctx, clientID) + if !found { + return types.ErrClientConnectionPathsNotFound(k.codespace) } - state.Client, err = k.client.Query(ctx, connection.Client) - if err != nil { - return - } - state.Connection.Set(ctx, connection) - state.Kind.Set(ctx, kind) - return + conns = append(conns, connectionID) + k.SetClientConnectionPaths(ctx, clientID, conns) + return nil } -// query() is used internally by the connection creators -// checks connection kind, doesn't check avilability -func (k Keeper) query(ctx sdk.Context, id string, kind string) (state State, err error) { - state = k.State(id) - if !state.exists(ctx) { - err = errors.New("Stage not exists") - return +// removeConnectionFromClient is used to remove a connection identifier from the +// set of connections associated with a client. +// +// CONTRACT: client must already exist +func (k Keeper) removeConnectionFromClient(ctx sdk.Context, clientID, connectionID string) sdk.Error { + conns, found := k.GetClientConnectionPaths(ctx, clientID) + if !found { + return types.ErrClientConnectionPathsNotFound(k.codespace) } - state.Client, err = k.client.Query(ctx, state.GetConnection(ctx).Client) - if err != nil { - return + conns, ok := removePath(conns, connectionID) + if !ok { + return types.ErrConnectionPath(k.codespace) } - if state.Kind.Get(ctx) != kind { - err = errors.New("kind mismatch") - return - } + k.SetClientConnectionPaths(ctx, clientID, conns) + return nil +} - return +func (k Keeper) getCompatibleVersions() []string { + // TODO: + return nil } -func (k Keeper) Query(ctx sdk.Context, id string) (state State, err error) { - state = k.State(id) - if !state.exists(ctx) { - err = errors.New("Stage not exists") - return - } +func (k Keeper) pickVersion(counterpartyVersions []string) string { + // TODO: + return "" +} - if !state.Available.Get(ctx) { - err = errors.New("Stage not available") - return +// removePath is an util function to remove a path from a set. +// +// TODO: move to ICS24 +func removePath(paths []string, path string) ([]string, bool) { + for i, p := range paths { + if p == path { + return append(paths[:i], paths[i+1:]...), true + } } - - state.Client, err = k.client.Query(ctx, state.GetConnection(ctx).Client) - return + return paths, false } diff --git a/x/ibc/03-connection/types/connection.go b/x/ibc/03-connection/types/connection.go index 7284a55a4331..9a36d8a0a3f4 100644 --- a/x/ibc/03-connection/types/connection.go +++ b/x/ibc/03-connection/types/connection.go @@ -24,7 +24,7 @@ const ( // between two chains. type ConnectionEnd struct { State ConnectionState `json:"state" yaml:"state"` - ClientID string `json:"client" yaml:"client"` + ClientID string `json:"client_id" yaml:"client_id"` // Counterparty chain associated with this connection. Counterparty Counterparty `json:"counterparty" yaml:"counterparty"` @@ -34,9 +34,9 @@ type ConnectionEnd struct { } // NewConnectionEnd creates a new ConnectionEnd instance. -func NewConnectionEnd(state ConnectionState, clientID string, counterparty Counterparty, versions []string) ConnectionEnd { +func NewConnectionEnd(clientID string, counterparty Counterparty, versions []string) ConnectionEnd { return ConnectionEnd{ - State: state, + State: NONE, ClientID: clientID, Counterparty: counterparty, Versions: versions, diff --git a/x/ibc/03-connection/types/errors.go b/x/ibc/03-connection/types/errors.go index 4c77d2dffe0a..9b38ec3c4f4c 100644 --- a/x/ibc/03-connection/types/errors.go +++ b/x/ibc/03-connection/types/errors.go @@ -4,33 +4,32 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// client error codes +// connection error codes const ( DefaultCodespace sdk.CodespaceType = SubModuleName - CodeClientExists sdk.CodeType = 101 - CodeClientNotFound sdk.CodeType = 102 - CodeClientFrozen sdk.CodeType = 103 - CodeInvalidConsensus sdk.CodeType = 104 - CodeValidatorJailed sdk.CodeType = 104 + CodeConnectionExists sdk.CodeType = 101 + CodeConnectionNotFound sdk.CodeType = 102 + CodeClientConnectionPathsNotFound sdk.CodeType = 103 + CodeConnectionPath sdk.CodeType = 104 ) -// ErrClientExists implements sdk.Error -func ErrClientExists(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeClientExists, "client already exists") +// ErrConnectionExists implements sdk.Error +func ErrConnectionExists(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeConnectionExists, "connection already exists") } -// ErrClientNotFound implements sdk.Error -func ErrClientNotFound(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeClientNotFound, "client not found") +// ErrConnectionNotFound implements sdk.Error +func ErrConnectionNotFound(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeConnectionNotFound, "connection not found") } -// ErrClientFrozen implements sdk.Error -func ErrClientFrozen(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeClientFrozen, "client is frozen due to misbehaviour") +// ErrClientConnectionPathsNotFound implements sdk.Error +func ErrClientConnectionPathsNotFound(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeClientConnectionPathsNotFound, "client connection paths not found") } -// ErrInvalidConsensus implements sdk.Error -func ErrInvalidConsensus(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidConsensus, "invalid consensus algorithm type") +// ErrConnectionPath implements sdk.Error +func ErrConnectionPath(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeConnectionPath, "connection path is not associated to the client") } diff --git a/x/ibc/03-connection/types/keys.go b/x/ibc/03-connection/types/keys.go index 4631e8cc7966..339c945a52b5 100644 --- a/x/ibc/03-connection/types/keys.go +++ b/x/ibc/03-connection/types/keys.go @@ -1,6 +1,41 @@ package types +import ( + "fmt" +) + const ( // SubModuleName defines the IBC connection name - SubModuleName = "connection" + SubModuleName = "connections" + + // StoreKey is the store key string for IBC connections + StoreKey = SubModuleName + + // RouterKey is the message route for IBC connections + RouterKey = SubModuleName + + // QuerierRoute is the querier route for IBC connections + QuerierRoute = SubModuleName ) + +// The following paths are the keys to the store as defined in https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#store-paths + +// ConnectionPath defines the path under which connection paths are stored +func ConnectionPath(connectionID string) string { + return fmt.Sprintf("connections/%s", connectionID) +} + +// ClientConnectionsPath defines a reverse mapping from clients to a set of connections +func ClientConnectionsPath(clientID string) string { + return fmt.Sprintf("clients/%s/connections", clientID) +} + +// KeyConnection returns the store key for a particular connection +func KeyConnection(connectionID string) []byte { + return []byte(ConnectionPath(connectionID)) +} + +// KeyClientConnections returns the store key for the connectios of a given client +func KeyClientConnections(clientID string) []byte { + return []byte(ClientConnectionsPath(clientID)) +} diff --git a/x/ibc/03-connection/types/msgs.go b/x/ibc/03-connection/types/msgs.go index f6d19317a9af..de920b76a694 100644 --- a/x/ibc/03-connection/types/msgs.go +++ b/x/ibc/03-connection/types/msgs.go @@ -14,7 +14,6 @@ type MsgConnectionOpenInit struct { ConnectionID string `json:"connection_id"` ClientID string `json:"client_id"` Counterparty Counterparty `json:"counterparty"` - NextTimeout uint64 `json:"next_timeout"` // TODO: Where is this defined? Signer sdk.AccAddress `json:"signer"` } @@ -48,14 +47,13 @@ var _ sdk.Msg = MsgConnectionOpenTry{} // MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a connection // on Chain B. type MsgConnectionOpenTry struct { - ConnectionID string `json:"connection_id"` - ClientID string `json:"client_id"` - Counterparty Counterparty `json:"counterparty"` - CounterpartyVersions []string `json:"counterparty_versions"` // TODO: why wasn't this defined previously? - Proofs []ics23.Proof `json:"proofs"` // Contains a Proof of the initialization the connection on Chain A - Height uint64 `json:"height"` // TODO: Rename to ProofHeight? Is this supposed to be the same as ConsensusHeight? - // ConsensusHeight uint64 `json:"consensus_height"` - Signer sdk.AccAddress `json:"signer"` + ConnectionID string `json:"connection_id"` + ClientID string `json:"client_id"` + Counterparty Counterparty `json:"counterparty"` + CounterpartyVersions []string `json:"counterparty_versions"` // TODO: why wasn't this defined previously? + Proofs []ics23.Proof `json:"proofs"` // Contains a Proof of the initialization the connection on Chain A + ConsensusHeight uint64 `json:"consensus_height"` + Signer sdk.AccAddress `json:"signer"` } // Route implements sdk.Msg @@ -89,9 +87,7 @@ var _ sdk.Msg = MsgConnectionOpenAck{} // the change of connection state to TRYOPEN on Chain B. type MsgConnectionOpenAck struct { ConnectionID string `json:"connection_id"` - Timeout uint64 `json:"timeout"` // TODO: Where's this defined ? - NextTimeout uint64 `json:"next_timeout"` // TODO: Where's this defined ? - Proofs []ics23.Proof `json:"proofs"` // Contains a Proof for the change of the connection state on Chain B: `none -> TRYOPEN` + Proofs []ics23.Proof `json:"proofs"` // Contains a Proof for the change of the connection state on Chain B: `none -> TRYOPEN` ConsensusHeight uint64 `json:"consensus_height"` Signer sdk.AccAddress `json:"signer"` } @@ -127,9 +123,8 @@ var _ sdk.Msg = MsgConnectionOpenConfirm{} // the change of connection state to OPEN on Chain A. type MsgConnectionOpenConfirm struct { ConnectionID string `json:"connection_id"` - Timeout uint64 `json:"timeout"` // TODO: Where's this defined ? - Proofs []ics23.Proof `json:"proofs"` // Contains a Proof for the change of the connection state on Chain A: `INIT -> OPEN` - Height uint64 `json:"height"` // TODO: Rename to ProofHeight? + Proofs []ics23.Proof `json:"proofs"` // Contains a Proof for the change of the connection state on Chain A: `INIT -> OPEN` + ProofHeight uint64 `json:"proof_height"` Signer sdk.AccAddress `json:"signer"` } diff --git a/x/ibc/03-connection/types/querier.go b/x/ibc/03-connection/types/querier.go new file mode 100644 index 000000000000..44f852664787 --- /dev/null +++ b/x/ibc/03-connection/types/querier.go @@ -0,0 +1,41 @@ +package types + + +// TODO: + +// // query routes supported by the IBC client Querier +// const ( +// QueryClientState = "clientState" +// QueryConsensusState = "consensusState" +// QueryCommitmentPath = "commitmentPath" +// QueryCommitmentRoot = "roots" +// ) + +// // QueryClientStateParams defines the params for the following queries: +// // - 'custom/ibc/clients//clientState' +// // - 'custom/ibc/clients//consensusState' +// type QueryClientStateParams struct { +// ClientID string +// } + +// // NewQueryClientStateParams creates a new QueryClientStateParams instance +// func NewQueryClientStateParams(id string) QueryClientStateParams { +// return QueryClientStateParams{ +// ClientID: id, +// } +// } + +// // QueryCommitmentRootParams defines the params for the following queries: +// // - 'custom/ibc/clients//roots/' +// type QueryCommitmentRootParams struct { +// ClientID string +// Height uint64 +// } + +// // NewQueryCommitmentRootParams creates a new QueryCommitmentRootParams instance +// func NewQueryCommitmentRootParams(id string, height uint64) QueryCommitmentRootParams { +// return QueryCommitmentRootParams{ +// ClientID: id, +// Height: height, +// } +// } From 8bcf17f8e41bfad12d3ca005aa6ca5cfccbed929 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 9 Oct 2019 14:50:30 +0200 Subject: [PATCH 271/378] refactor handshake to update it to the latest ICS03 spec --- x/ibc/03-connection/keeper/handshake.go | 320 +++++++++--------- x/ibc/03-connection/keeper/keeper.go | 39 +++ x/ibc/03-connection/types/expected_keepers.go | 9 + 3 files changed, 208 insertions(+), 160 deletions(-) diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index 9e0f5cb2030f..9680c6da6c74 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -5,57 +5,25 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + ics02types "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -// // CONTRACT: client and remote must be filled by the caller -// func (k Keeper) CreateState(parent State) HandshakeState { -// return HandshakeState{ -// State: parent, -// Stage: k.man.protocol.Value([]byte(parent.id + "/state")).Enum(), -// CounterpartyClient: k.man.protocol.Value([]byte(parent.id + "/counterpartyClient")).String(), -// } -// } - -// func (man CounterpartyHandshaker) CreateState(id string) CounterHandshakeState { -// return CounterHandshakeState{ -// CounterState: k.man.CreateState(id), -// Stage: k.man.protocol.Value([]byte(id + "/state")).Enum(), -// CounterpartyClient: k.man.protocol.Value([]byte(id + "/counterpartyClient")).String(), -// } -// } - -// func (k Keeper) create(ctx sdk.Context, id string, connection Connection, counterpartyClient string) (obj HandshakeState, err error) { -// cobj, err := k.man.create(ctx, id, connection, HandshakeKind) -// if err != nil { -// return -// } -// obj = k.CreateState(cobj) -// obj.CounterpartyClient.Set(ctx, counterpartyClient) -// obj.Counterparty = k.CounterParty.CreateState(connection.Counterparty) -// return obj, nil -// } - -// func (k Keeper) query(ctx sdk.Context, id string) (obj HandshakeState, err error) { -// cobj, err := k.man.query(ctx, id, HandshakeKind) -// if err != nil { -// return -// } -// obj = k.CreateState(cobj) -// obj.Counterparty = k.counterParty.CreateState(obj.GetConnection(ctx).Counterparty) -// return -// } - // ConnOpenInit initialises a connection attempt on chain A. func (k Keeper) ConnOpenInit( - ctx sdk.Context, connectionID, clientID string, counterparty types.Counterparty, + ctx sdk.Context, + connectionID, // identifier + clientID string, + counterparty types.Counterparty, // desiredCounterpartyConnectionIdentifier, counterpartyPrefix, counterpartyClientIdentifier ) error { + // TODO: validateConnectionIdentifier(identifier) _, found := k.GetConnection(ctx, connectionID) if found { return sdkerrors.Wrap(types.ErrConnectionExists(k.codespace), "cannot initialize connection") } + // connection defines chain A's ConnectionEnd connection := types.NewConnectionEnd(clientID, counterparty, k.getCompatibleVersions()) connection.State = types.INIT @@ -70,144 +38,176 @@ func (k Keeper) ConnOpenInit( // ConnOpenTry relays notice of a connection attempt on chain A to chain B (this // code is executed on chain B). -func (k Keeper) ConnOpenTry(ctx sdk.Context, connectionID, clientID string, counterparty types.Counterparty, - counterpartyVersions []string, proofInit ics23.Proof, proofHeight uint64, consensusHeight uint64, +// +// NOTE: here chain A acts as the counterparty +func (k Keeper) ConnOpenTry( + ctx sdk.Context, + connectionID string, // desiredIdentifier + counterparty types.Counterparty, // counterpartyConnectionIdentifier, counterpartyPrefix and counterpartyClientIdentifier + clientID string, + counterpartyVersions []string, + proofInit ics23.Proof, + proofHeight uint64, + consensusHeight uint64, ) error { - + // TODO: validateConnectionIdentifier(identifier) if consensusHeight > uint64(ctx.BlockHeight()) { - return errors.New("invalid consensus height") - } - - // obj, err = k.create(ctx, id, connection, counterpartyClient) - // if err != nil { - // return - // } - - // ctx, err = k.Context(ctx, height, proofs) - // if err != nil { - // return - // } - - // if !obj.Counterparty.Stage.Is(ctx, Init) { - // err = errors.New("counterParty state not init") - // return - // } - - // if !obj.Counterparty.Connection.Is(ctx, Connection{ - // Client: counterpartyClient, - // Counterparty: id, - // Path: obj.path, - // }) { - // err = errors.New("wrong counterParty connection") - // return - // } - - // if !obj.Counterparty.CounterpartyClient.Is(ctx, connection.Client) { - // err = errors.New("counterParty client not match") - // 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.Stage.Set(ctx, OpenTry) + return errors.New("invalid consensus height") // TODO: sdk.Error + } + + expectedConsensusState, found := k.clientKeeper.GetConsensusState(ctx, clientID) + if !found { + return errors.New("client consensus state not found") // TODO: use ICS02 error + } + + // expectedConn defines Chain A's ConnectionEnd + // NOTE: chain A's counterparty is chain B (i.e where this code is executed) + // TODO: prefix should be `getCommitmentPrefix()` + expectedCounterparty := types.NewCounterparty(counterparty.ClientID, connectionID, counterparty.Prefix) + expectedConn := types.NewConnectionEnd(clientID, expectedCounterparty, counterpartyVersions) + expectedConn.State = types.INIT + + // chain B picks a version from Chain A's available versions + version := k.pickVersion(counterpartyVersions) + + // connection defines chain B's ConnectionEnd + connection := types.NewConnectionEnd(clientID, counterparty, []string{version}) + + ok := k.verifyMembership( + ctx, connection, proofHeight, proofInit, + types.ConnectionPath(connectionID), expectedConn, + ) + if !ok { + return errors.New("couldn't verify connection membership on counterparty's client") // TODO: sdk.Error + } + + ok = k.verifyMembership( + ctx, connection, proofHeight, proofInit, + ics02types.ConsensusStatePath(counterparty.ClientID), expectedConsensusState, + ) + if !ok { + return errors.New("couldn't verify consensus state membership on counterparty's client") // TODO: sdk.Error + } + + _, found = k.GetConnection(ctx, connectionID) + if found { + return sdkerrors.Wrap(types.ErrConnectionExists(k.codespace), "cannot relay connection attempt") + } + if !checkVersion(version, counterpartyVersions[0]) { + return errors.New("versions don't match") // TODO: sdk.Error + } + + connection.State = types.TRYOPEN + err := k.addConnectionToClient(ctx, clientID, connectionID) + if err != nil { + return sdkerrors.Wrap(err, "cannot relay connection attempt") + } + + k.SetConnection(ctx, connectionID, connection) return nil } // ConnOpenAck relays acceptance of a connection open attempt from chain B back // to chain A (this code is executed on chain A). -func (k Keeper) ConnOpenAck(ctx sdk.Context, - proofs []ics23.Proof, height uint64, - id string, +func (k Keeper) ConnOpenAck( + ctx sdk.Context, + connectionID string, + version string, + proofTry ics23.Proof, + proofHeight uint64, + consensusHeight uint64, ) error { - // obj, err = man.query(ctx, id) - // if err != nil { - // return - // } - - // ctx, err = obj.Context(ctx, height, proofs) - // if err != nil { - // return - // } - - // if !obj.Stage.Transit(ctx, Init, Open) { - // err = errors.New("ack on non-init connection") - // return - // } - - // if !obj.Counterparty.Connection.Is(ctx, Connection{ - // Client: obj.CounterpartyClient.Get(ctx), - // Counterparty: obj.ID(), - // Path: obj.path, - // }) { - // err = errors.New("wrong counterParty") - // return - // } - - // 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 - // } - - // // TODO: implement in v1 - // /* - // var expected client.ConsensusState - // // obj.self.Get(ctx, expheight, &expected) - // if !obj.counterParty.client.Is(ctx, expected) { - // // return errors.New("unexpected counterParty client value") - // } - // */ - // obj.Available.Set(ctx, true) + // TODO: validateConnectionIdentifier(identifier) + if consensusHeight > uint64(ctx.BlockHeight()) { + return errors.New("invalid consensus height") // TODO: sdk.Error + } + + connection, found := k.GetConnection(ctx, connectionID) + if !found { + return sdkerrors.Wrap(types.ErrConnectionNotFound(k.codespace), "cannot relay ACK of open attempt") + } + if connection.State != types.INIT { + return errors.New("connection is in a non valid state") // TODO: sdk.Error + } + + if !checkVersion(connection.Versions[0], version) { + return errors.New("versions don't match") // TODO: sdk.Error + } + + expectedConsensusState, found := k.clientKeeper.GetConsensusState(ctx, connection.ClientID) + if !found { + return errors.New("client consensus state not found") // TODO: use ICS02 error + } + + prefix := getCommitmentPrefix() + expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, prefix) + expectedConn := types.NewConnectionEnd(connection.ClientID, expectedCounterparty, []string{version}) + expectedConn.State = types.TRYOPEN + + ok := k.verifyMembership( + ctx, connection, proofHeight, proofTry, + types.ConnectionPath(connection.Counterparty.ConnectionID), expectedConn, + ) + if !ok { + return errors.New("couldn't verify connection membership on counterparty's client") // TODO: sdk.Error + } + + ok = k.verifyMembership( + ctx, connection, proofHeight, proofTry, + ics02types.ConsensusStatePath(connection.Counterparty.ClientID), expectedConsensusState, + ) + if !ok { + return errors.New("couldn't verify consensus state membership on counterparty's client") // TODO: sdk.Error + } + + connection.State = types.OPEN + + // abort if version is the last one + // TODO: what does this suppose to mean ? + compatibleVersions := getCompatibleVersions() + if compatibleVersions[len(compatibleVersions)-1] == version { + return errors.New("versions don't match") // TODO: sdk.Error + } + + connection.Versions = []string{version} + k.SetConnection(ctx, connectionID, connection) return nil } // ConnOpenConfirm confirms opening of a connection on chain A to chain B, after // which the connection is open on both chains (this code is executed on chain B). -func (k Keeper) ConnOpenConfirm(ctx sdk.Context, - proofs []ics23.Proof, height uint64, - id string) error { - - // obj, err = man.query(ctx, id) - // if err != nil { - // return - // } - - // ctx, err = obj.Context(ctx, height, proofs) - // if err != nil { - // return - // } - - // if !obj.Stage.Transit(ctx, OpenTry, Open) { - // err = errors.New("confirm on non-try connection") - // return - // } +func (k Keeper) ConnOpenConfirm( + ctx sdk.Context, + connectionID string, + proofAck ics23.Proof, + proofHeight uint64, +) error { + // TODO: validateConnectionIdentifier(identifier) + connection, found := k.GetConnection(ctx, connectionID) + if !found { + return sdkerrors.Wrap(types.ErrConnectionNotFound(k.codespace), "cannot relay ACK of open attempt") + } - // if !obj.Counterparty.Stage.Is(ctx, Open) { - // err = errors.New("counterParty state not open") - // return - // } + if connection.State != types.TRYOPEN { + return errors.New("connection is in a non valid state") // TODO: sdk.Error + } - // obj.Available.Set(ctx, true) + prefix := getCommitmentPrefix() + expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, prefix) + expectedConn := types.NewConnectionEnd(connection.ClientID, expectedCounterparty, connection.Versions) + expectedConn.State = types.OPEN + + ok := k.verifyMembership( + ctx, connection, proofHeight, proofAck, + types.ConnectionPath(connection.Counterparty.ConnectionID), expectedConn, + ) + if !ok { + return errors.New("couldn't verify connection membership on counterparty's client") // TODO: sdk.Error + } + connection.State = types.OPEN + k.SetConnection(ctx, connectionID, connection) return nil } diff --git a/x/ibc/03-connection/keeper/keeper.go b/x/ibc/03-connection/keeper/keeper.go index a3740d33336b..968be1617ac3 100644 --- a/x/ibc/03-connection/keeper/keeper.go +++ b/x/ibc/03-connection/keeper/keeper.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -113,6 +114,37 @@ func (k Keeper) removeConnectionFromClient(ctx sdk.Context, clientID, connection return nil } +func (k Keeper) verifyMembership( + ctx sdk.Context, + connection types.ConnectionEnd, + height uint64, + proof ics23.Proof, + path string, + value interface{}, // value: Value +) bool { + _, found := k.clientKeeper.GetClientState(ctx, connection.ClientID) + if !found { + return false + } + // k.clientKeeper.VerifyMembership(ctx, clientState, height, proof, applyPrefix(connection.Counterparty.Prefix, path), value) + return true +} + +func (k Keeper) verifyNonMembership( + ctx sdk.Context, + connection types.ConnectionEnd, + height uint64, + proof ics23.Proof, + path string, +) bool { + _, found := k.clientKeeper.GetClientState(ctx, connection.ClientID) + if !found { + return false + } + // k.clientKeeper.VerifyNonMembership(ctx, clientState, height, proof, applyPrefix(connection.Counterparty.Prefix, path)) + return true +} + func (k Keeper) getCompatibleVersions() []string { // TODO: return nil @@ -123,6 +155,13 @@ func (k Keeper) pickVersion(counterpartyVersions []string) string { return "" } +// checkVersion is an opaque function defined by the host state machine which +// determines if two versions are compatible +func checkVersion(version, counterpartyVersion string) bool { + // TODO: + return true +} + // removePath is an util function to remove a path from a set. // // TODO: move to ICS24 diff --git a/x/ibc/03-connection/types/expected_keepers.go b/x/ibc/03-connection/types/expected_keepers.go index 98c5e40430a2..f69b5095d1d1 100644 --- a/x/ibc/03-connection/types/expected_keepers.go +++ b/x/ibc/03-connection/types/expected_keepers.go @@ -1,5 +1,14 @@ package types +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + ics02exported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + ics02types "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" +) + // ClientKeeper expected account IBC client keeper type ClientKeeper interface { + GetConsensusState(ctx sdk.Context, clientID string) (ics02exported.ConsensusState, bool) + GetClientState(ctx sdk.Context, clientID string) (ics02types.ClientState, bool) } + From 3df5378b4ffe2c69cf4fc991561a046c09470a7f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 9 Oct 2019 15:21:44 +0200 Subject: [PATCH 272/378] update handler and msgs --- x/ibc/03-connection/cli.go | 116 +++++++++++++-------------- x/ibc/03-connection/client/cli/tx.go | 42 ---------- x/ibc/03-connection/handler.go | 15 ++-- x/ibc/03-connection/types/msgs.go | 86 ++++++++++++++++++-- 4 files changed, 146 insertions(+), 113 deletions(-) diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go index 7f54a598b6a9..e514c301a8bf 100644 --- a/x/ibc/03-connection/cli.go +++ b/x/ibc/03-connection/cli.go @@ -1,70 +1,70 @@ -package connection +package ics03 -import ( - "bytes" +// import ( +// "bytes" - "github.com/cosmos/cosmos-sdk/store/state" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" -) +// "github.com/cosmos/cosmos-sdk/store/state" +// "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +// ) -func (man Manager) CLIState(connid, clientid string) State { - state := man.State(connid) - state.Client = man.client.State(clientid) - return state -} +// func (man Manager) CLIState(connid, clientid string) State { +// state := man.State(connid) +// state.Client = man.client.State(clientid) +// return state +// } -func (man Manager) CLIQuery(q state.ABCIQuerier, connid string) (State, error) { - state := man.State(connid) - conn, _, err := state.ConnectionCLI(q) - if err != nil { - return State{}, err - } - state.Client = man.client.State(conn.Client) - return state, nil -} +// func (man Manager) CLIQuery(q state.ABCIQuerier, connid string) (State, error) { +// state := man.State(connid) +// conn, _, err := state.ConnectionCLI(q) +// if err != nil { +// return State{}, err +// } +// state.Client = man.client.State(conn.Client) +// return state, nil +// } -func (state State) prefix() []byte { - return bytes.Split(state.Connection.KeyBytes(), LocalRoot())[0] -} +// func (state State) prefix() []byte { +// return bytes.Split(state.Connection.KeyBytes(), LocalRoot())[0] +// } -func (state State) ConnectionCLI(q state.ABCIQuerier) (res Connection, proof merkle.Proof, err error) { - tmproof, err := state.Connection.Query(q, &res) - proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Connection) - return -} +// func (state State) ConnectionCLI(q state.ABCIQuerier) (res Connection, proof merkle.Proof, err error) { +// tmproof, err := state.Connection.Query(q, &res) +// proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Connection) +// return +// } -func (state State) AvailableCLI(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { - res, tmproof, err := state.Available.Query(q) - proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Available) - return -} +// func (state State) AvailableCLI(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { +// res, tmproof, err := state.Available.Query(q) +// proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Available) +// return +// } -func (state State) KindCLI(q state.ABCIQuerier) (res string, proof merkle.Proof, err error) { - res, tmproof, err := state.Kind.Query(q) - proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Kind) - return -} +// func (state State) KindCLI(q state.ABCIQuerier) (res string, proof merkle.Proof, err error) { +// res, tmproof, err := state.Kind.Query(q) +// proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Kind) +// return +// } -func (man Handshaker) CLIState(connid, clientid string) HandshakeState { - return man.CreateState(man.man.CLIState(connid, clientid)) -} +// func (man Handshaker) CLIState(connid, clientid string) HandshakeState { +// return man.CreateState(man.man.CLIState(connid, clientid)) +// } -func (man Handshaker) CLIQuery(q state.ABCIQuerier, connid string) (HandshakeState, error) { - state, err := man.man.CLIQuery(q, connid) - if err != nil { - return HandshakeState{}, err - } - return man.CreateState(state), nil -} +// func (man Handshaker) CLIQuery(q state.ABCIQuerier, connid string) (HandshakeState, error) { +// state, err := man.man.CLIQuery(q, connid) +// if err != nil { +// return HandshakeState{}, err +// } +// return man.CreateState(state), nil +// } -func (state HandshakeState) StageCLI(q state.ABCIQuerier) (res byte, proof merkle.Proof, err error) { - res, tmproof, err := state.Stage.Query(q) - proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Stage) - return -} +// func (state HandshakeState) StageCLI(q state.ABCIQuerier) (res byte, proof merkle.Proof, err error) { +// res, tmproof, err := state.Stage.Query(q) +// proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Stage) +// return +// } -func (state HandshakeState) CounterpartyClientCLI(q state.ABCIQuerier) (res string, proof merkle.Proof, err error) { - res, tmproof, err := state.CounterpartyClient.Query(q) - proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.CounterpartyClient) - return -} +// func (state HandshakeState) CounterpartyClientCLI(q state.ABCIQuerier) (res string, proof merkle.Proof, err error) { +// res, tmproof, err := state.CounterpartyClient.Query(q) +// proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.CounterpartyClient) +// return +// } diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index 67c97d1172cd..84524013dd27 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -8,8 +8,6 @@ import ( "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" @@ -20,7 +18,6 @@ import ( "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" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/version" @@ -67,45 +64,6 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { 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", diff --git a/x/ibc/03-connection/handler.go b/x/ibc/03-connection/handler.go index 2085ca10403b..0f13f5eb088a 100644 --- a/x/ibc/03-connection/handler.go +++ b/x/ibc/03-connection/handler.go @@ -1,4 +1,4 @@ -package connection +package ics03 import ( "fmt" @@ -35,7 +35,7 @@ func NewHandler(k keeper.Keeper) sdk.Handler { } func handleMsgConnectionOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenInit) sdk.Result { - _, err := k.ConnOpenInit(ctx, msg.ConnectionID, msg.ClientID, msg.Counterparty) + err := k.ConnOpenInit(ctx, msg.ConnectionID, msg.ClientID, msg.Counterparty) if err != nil { return sdk.ResultFromError(err) } @@ -57,7 +57,9 @@ func handleMsgConnectionOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.Msg } func handleMsgConnectionOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenTry) sdk.Result { - _, err := k.ConnOpenTry(ctx, msg.ConnectionID, msg.ClientID, msg.Counterparty, msg.Proofs, msg.Height) + err := k.ConnOpenTry( + ctx, msg.ConnectionID, msg.Counterparty, msg.ClientID, + msg.CounterpartyVersions, msg.ProofInit, msg.ProofHeight, msg.ConsensusHeight) if err != nil { return sdk.ResultFromError(err) } @@ -79,7 +81,10 @@ func handleMsgConnectionOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgC } func handleMsgConnectionOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenAck) sdk.Result { - _, err := k.OpenAck(ctx, msg.Proofs, msg.Height, msg.ConnectionID) + err := k.ConnOpenAck( + ctx, msg.ConnectionID, msg.Version, msg.ProofTry, + msg.ProofHeight, msg.ConsensusHeight, + ) if err != nil { return sdk.ResultFromError(err) } @@ -100,7 +105,7 @@ func handleMsgConnectionOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgC } func handleMsgConnectionOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenConfirm) sdk.Result { - _, err := k.OpenConfirm(ctx, msg.Proofs, msg.Height, msg.ConnectionID) + err := k.ConnOpenConfirm(ctx, msg.ConnectionID, msg.ProofAck, msg.ProofHeight) if err != nil { return sdk.ResultFromError(err) } diff --git a/x/ibc/03-connection/types/msgs.go b/x/ibc/03-connection/types/msgs.go index de920b76a694..2984d4436f7b 100644 --- a/x/ibc/03-connection/types/msgs.go +++ b/x/ibc/03-connection/types/msgs.go @@ -17,6 +17,21 @@ type MsgConnectionOpenInit struct { Signer sdk.AccAddress `json:"signer"` } +// NewMsgConnectionOpenInit creates a new MsgConnectionOpenInit instance +func NewMsgConnectionOpenInit( + connectionID, clientID, counterpartyConnectionID, + counterpartyClientID string, counterpartyPrefix ics23.Prefix, + signer sdk.AccAddress, +) MsgConnectionOpenInit { + counterparty := NewCounterparty(counterpartyClientID, counterpartyConnectionID, counterpartyPrefix) + return MsgConnectionOpenInit{ + ConnectionID: connectionID, + ClientID: clientID, + Counterparty: counterparty, + Signer: signer, + } +} + // Route implements sdk.Msg func (msg MsgConnectionOpenInit) Route() string { return ibctypes.RouterKey @@ -29,7 +44,8 @@ func (msg MsgConnectionOpenInit) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgConnectionOpenInit) ValidateBasic() sdk.Error { - return nil // TODO + // TODO: + return nil } // GetSignBytes implements sdk.Msg @@ -50,12 +66,33 @@ type MsgConnectionOpenTry struct { ConnectionID string `json:"connection_id"` ClientID string `json:"client_id"` Counterparty Counterparty `json:"counterparty"` - CounterpartyVersions []string `json:"counterparty_versions"` // TODO: why wasn't this defined previously? - Proofs []ics23.Proof `json:"proofs"` // Contains a Proof of the initialization the connection on Chain A + CounterpartyVersions []string `json:"counterparty_versions"` + ProofInit ics23.Proof `json:"proof_init"` // proof of the initialization the connection on Chain A: `none -> INIT` + ProofHeight uint64 `json:"proof_height"` ConsensusHeight uint64 `json:"consensus_height"` Signer sdk.AccAddress `json:"signer"` } +// NewMsgConnectionOpenTry creates a new MsgConnectionOpenTry instance +func NewMsgConnectionOpenTry( + connectionID, clientID, counterpartyConnectionID, + counterpartyClientID string, counterpartyPrefix ics23.Prefix, + counterpartyVersions []string, proofInit ics23.Proof, + proofHeight, consensusHeight uint64, signer sdk.AccAddress, +) MsgConnectionOpenTry { + counterparty := NewCounterparty(counterpartyClientID, counterpartyConnectionID, counterpartyPrefix) + return MsgConnectionOpenTry{ + ConnectionID: connectionID, + ClientID: clientID, + Counterparty: counterparty, + CounterpartyVersions: counterpartyVersions, + ProofInit: proofInit, + ProofHeight: proofHeight, + ConsensusHeight: consensusHeight, + Signer: signer, + } +} + // Route implements sdk.Msg func (msg MsgConnectionOpenTry) Route() string { return ibctypes.RouterKey @@ -68,7 +105,8 @@ func (msg MsgConnectionOpenTry) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgConnectionOpenTry) ValidateBasic() sdk.Error { - return nil // TODO + // TODO: + return nil } // GetSignBytes implements sdk.Msg @@ -87,11 +125,29 @@ var _ sdk.Msg = MsgConnectionOpenAck{} // the change of connection state to TRYOPEN on Chain B. type MsgConnectionOpenAck struct { ConnectionID string `json:"connection_id"` - Proofs []ics23.Proof `json:"proofs"` // Contains a Proof for the change of the connection state on Chain B: `none -> TRYOPEN` + ProofTry ics23.Proof `json:"proof_try"` // proof for the change of the connection state on Chain B: `none -> TRYOPEN` + ProofHeight uint64 `json:"proof_height"` ConsensusHeight uint64 `json:"consensus_height"` + Version string `json:"version"` Signer sdk.AccAddress `json:"signer"` } +// NewMsgConnectionOpenAck creates a new MsgConnectionOpenAck instance +func NewMsgConnectionOpenAck( + connectionID string, proofTry ics23.Proof, + proofHeight, consensusHeight uint64, version string, + signer sdk.AccAddress, +) MsgConnectionOpenAck { + return MsgConnectionOpenAck{ + ConnectionID: connectionID, + ProofTry: proofTry, + ProofHeight: proofHeight, + ConsensusHeight: consensusHeight, + Version: version, + Signer: signer, + } +} + // Route implements sdk.Msg func (msg MsgConnectionOpenAck) Route() string { return ibctypes.RouterKey @@ -104,7 +160,8 @@ func (msg MsgConnectionOpenAck) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgConnectionOpenAck) ValidateBasic() sdk.Error { - return nil // TODO + // TODO: + return nil } // GetSignBytes implements sdk.Msg @@ -123,11 +180,23 @@ var _ sdk.Msg = MsgConnectionOpenConfirm{} // the change of connection state to OPEN on Chain A. type MsgConnectionOpenConfirm struct { ConnectionID string `json:"connection_id"` - Proofs []ics23.Proof `json:"proofs"` // Contains a Proof for the change of the connection state on Chain A: `INIT -> OPEN` + ProofAck ics23.Proof `json:"proof_ack"` // proof for the change of the connection state on Chain A: `INIT -> OPEN` ProofHeight uint64 `json:"proof_height"` Signer sdk.AccAddress `json:"signer"` } +// NewMsgConnectionOpenConfirm creates a new MsgConnectionOpenConfirm instance +func NewMsgConnectionOpenConfirm( + connectionID string, proofAck ics23.Proof, proofHeight uint64, signer sdk.AccAddress, +) MsgConnectionOpenConfirm { + return MsgConnectionOpenConfirm{ + ConnectionID: connectionID, + ProofAck: proofAck, + ProofHeight: proofHeight, + Signer: signer, + } +} + // Route implements sdk.Msg func (msg MsgConnectionOpenConfirm) Route() string { return ibctypes.RouterKey @@ -140,7 +209,8 @@ func (msg MsgConnectionOpenConfirm) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgConnectionOpenConfirm) ValidateBasic() sdk.Error { - return nil // TODO + // TODO: + return nil } // GetSignBytes implements sdk.Msg From 21f7d2cb92e830d36e440c9a89c5004ed7fcb094 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 9 Oct 2019 16:06:20 +0200 Subject: [PATCH 273/378] add verification functions --- x/ibc/02-client/keeper/client.go | 107 +++++++++++++++++++++ x/ibc/02-client/keeper/keeper.go | 156 +++++++++++-------------------- 2 files changed, 162 insertions(+), 101 deletions(-) create mode 100644 x/ibc/02-client/keeper/client.go diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go new file mode 100644 index 000000000000..f0645b49b5e4 --- /dev/null +++ b/x/ibc/02-client/keeper/client.go @@ -0,0 +1,107 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" +) + +// CreateClient creates a new client state and populates it with a given consensus +// state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create +func (k Keeper) CreateClient( + ctx sdk.Context, clientID string, + clientTypeStr string, consensusState exported.ConsensusState, +) (types.ClientState, error) { + _, found := k.GetClientState(ctx, clientID) + if found { + return types.ClientState{}, types.ErrClientExists(k.codespace) + } + + _, found = k.GetClientType(ctx, clientID) + if found { + panic(fmt.Sprintf("consensus type is already defined for client %s", clientID)) + } + + clientType := exported.ClientTypeFromStr(clientTypeStr) + if clientType == 0 { + return types.ClientState{}, types.ErrInvalidClientType(k.codespace) + } + + clientState := k.initialize(ctx, clientID, consensusState) + k.SetCommitmentRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) + k.SetClientState(ctx, clientState) + k.SetClientType(ctx, clientID, clientType) + return clientState, nil +} + +// UpdateClient updates the consensus state and the state root from a provided header +func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.Header) error { + clientType, found := k.GetClientType(ctx, clientID) + if !found { + return sdkerrors.Wrap(types.ErrClientTypeNotFound(k.codespace), "cannot update client") + } + + // check that the header consensus matches the client one + if header.ClientType() != clientType { + return sdkerrors.Wrap(types.ErrInvalidConsensus(k.codespace), "cannot update client") + } + + clientState, found := k.GetClientState(ctx, clientID) + if !found { + return sdkerrors.Wrap(types.ErrClientNotFound(k.codespace), "cannot update client") + } + + if clientState.Frozen { + return sdkerrors.Wrap(types.ErrClientFrozen(k.codespace), "cannot update client") + } + + consensusState, found := k.GetConsensusState(ctx, clientID) + if !found { + return sdkerrors.Wrap(types.ErrConsensusStateNotFound(k.codespace), "cannot update client") + } + + if header.GetHeight() < consensusState.GetHeight() { + return sdkerrors.Wrap( + sdk.ErrInvalidSequence( + fmt.Sprintf("header height < consensus height (%d < %d)", header.GetHeight(), consensusState.GetHeight()), + ), + "cannot update client", + ) + } + + consensusState, err := consensusState.CheckValidityAndUpdateState(header) + if err != nil { + return sdkerrors.Wrap(err, "cannot update client") + } + + k.SetConsensusState(ctx, clientID, consensusState) + k.SetCommitmentRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) + k.Logger(ctx).Info(fmt.Sprintf("client %s updated at height %d", clientID, consensusState.GetHeight())) + return nil +} + +// CheckMisbehaviourAndUpdateState checks for client misbehaviour and freezes the +// client if so. +func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, clientID string, evidence exported.Evidence) error { + clientState, found := k.GetClientState(ctx, clientID) + if !found { + sdk.ResultFromError(types.ErrClientNotFound(k.codespace)) + } + + err := k.checkMisbehaviour(ctx, evidence) + if err != nil { + return err + } + + clientState, err = k.freeze(ctx, clientState) + if err != nil { + return err + } + + k.SetClientState(ctx, clientState) + k.Logger(ctx).Info(fmt.Sprintf("client %s frozen due to misbehaviour", clientID)) + return nil +} diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index d468e4de653d..d0f83ce19d31 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -46,7 +46,7 @@ func (k Keeper) GetCommitmentPath() merkle.Prefix { return merkle.NewPrefix([][]byte{[]byte(k.storeKey.Name())}, k.prefix) } -// GetClientState gets a particular client from the +// GetClientState gets a particular client from the store func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (types.ClientState, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := store.Get(types.KeyClientState(clientID)) @@ -59,8 +59,8 @@ func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (types.ClientSt return clientState, true } -// SetClient sets a particular Client to the store -func (k Keeper) SetClient(ctx sdk.Context, clientState types.ClientState) { +// SetClientState sets a particular Client to the store +func (k Keeper) SetClientState(ctx sdk.Context, clientState types.ClientState) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := k.cdc.MustMarshalBinaryLengthPrefixed(clientState) store.Set(types.KeyClientState(clientState.ID()), bz) @@ -96,7 +96,7 @@ func (k Keeper) GetConsensusState(ctx sdk.Context, clientID string) (exported.Co return consensusState, true } -// SetConsensusState sets a ConsensusState to a particular Client +// SetConsensusState sets a ConsensusState to a particular client func (k Keeper) SetConsensusState(ctx sdk.Context, clientID string, consensusState exported.ConsensusState) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := k.cdc.MustMarshalBinaryLengthPrefixed(consensusState) @@ -123,103 +123,6 @@ func (k Keeper) SetCommitmentRoot(ctx sdk.Context, clientID string, height uint6 store.Set(types.KeyRoot(clientID, height), bz) } -// CreateClient creates a new client state and populates it with a given consensus -// state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create -func (k Keeper) CreateClient( - ctx sdk.Context, clientID string, - clientTypeStr string, consensusState exported.ConsensusState, -) (types.ClientState, error) { - _, found := k.GetClientState(ctx, clientID) - if found { - return types.ClientState{}, types.ErrClientExists(k.codespace) - } - - _, found = k.GetClientType(ctx, clientID) - if found { - panic(fmt.Sprintf("consensus type is already defined for client %s", clientID)) - } - - clientType := exported.ClientTypeFromStr(clientTypeStr) - if clientType == 0 { - return types.ClientState{}, types.ErrInvalidClientType(k.codespace) - } - - clientState := k.initialize(ctx, clientID, consensusState) - k.SetCommitmentRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) - k.SetClient(ctx, clientState) - k.SetClientType(ctx, clientID, clientType) - return clientState, nil -} - -// UpdateClient updates the consensus state and the state root from a provided header -func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.Header) error { - clientType, found := k.GetClientType(ctx, clientID) - if !found { - return sdkerrors.Wrap(types.ErrClientTypeNotFound(k.codespace), "cannot update client") - } - - // check that the header consensus matches the client one - if header.ClientType() != clientType { - return sdkerrors.Wrap(types.ErrInvalidConsensus(k.codespace), "cannot update client") - } - - clientState, found := k.GetClientState(ctx, clientID) - if !found { - return sdkerrors.Wrap(types.ErrClientNotFound(k.codespace), "cannot update client") - } - - if clientState.Frozen { - return sdkerrors.Wrap(types.ErrClientFrozen(k.codespace), "cannot update client") - } - - consensusState, found := k.GetConsensusState(ctx, clientID) - if !found { - return sdkerrors.Wrap(types.ErrConsensusStateNotFound(k.codespace), "cannot update client") - } - - if header.GetHeight() < consensusState.GetHeight() { - return sdkerrors.Wrap( - sdk.ErrInvalidSequence( - fmt.Sprintf("header height < consensus height (%d < %d)", header.GetHeight(), consensusState.GetHeight()), - ), - "cannot update client", - ) - } - - consensusState, err := consensusState.CheckValidityAndUpdateState(header) - if err != nil { - return sdkerrors.Wrap(err, "cannot update client") - } - - k.SetConsensusState(ctx, clientID, consensusState) - k.SetCommitmentRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) - k.Logger(ctx).Info(fmt.Sprintf("client %s updated at height %d", clientID, consensusState.GetHeight())) - return nil -} - -// CheckMisbehaviourAndUpdateState checks for client misbehaviour and freezes the -// client if so. -func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, clientID string, evidence exported.Evidence) error { - clientState, found := k.GetClientState(ctx, clientID) - if !found { - sdk.ResultFromError(types.ErrClientNotFound(k.codespace)) - } - - err := k.checkMisbehaviour(ctx, evidence) - if err != nil { - return err - } - - clientState, err = k.freeze(ctx, clientState) - if err != nil { - return err - } - - k.SetClient(ctx, clientState) - k.Logger(ctx).Info(fmt.Sprintf("client %s frozen due to misbehaviour", clientID)) - return nil -} - // ClientState returns a new client state with a given id as defined in // https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#example-implementation func (k Keeper) initialize(ctx sdk.Context, clientID string, consensusState exported.ConsensusState) types.ClientState { @@ -252,3 +155,54 @@ func (k Keeper) freeze(ctx sdk.Context, clientState types.ClientState) (types.Cl clientState.Frozen = true return clientState, nil } + +// VerifyMembership state membership verification function defined by the client type +func (k Keeper) VerifyMembership( + ctx sdk.Context, + clientState types.ClientState, + height uint64, // sequence + proof ics23.Proof, + path string, + value []byte, +) bool { + if clientState.Frozen { + return false + } + + root, found := k.GetCommitmentRoot(ctx, clientState.ID(), height) + if !found { + return false + } + + prefix := merkle.NewPrefix([][]byte{[]byte(path)}, nil) // TODO: keyprefix? + if err := proof.Verify(root, prefix, value); err != nil { + return false + } + + return true +} + +// VerifyNonMembership state non-membership function defined by the client type +func (k Keeper) VerifyNonMembership( + ctx sdk.Context, + clientState types.ClientState, + height uint64, // sequence + proof ics23.Proof, + path string, +) bool { + if clientState.Frozen { + return false + } + + root, found := k.GetCommitmentRoot(ctx, clientState.ID(), height) + if !found { + return false + } + + prefix := merkle.NewPrefix([][]byte{[]byte(path)}, nil) // TODO: keyprefix? + if err := proof.Verify(root, prefix, nil); err != nil { + return false + } + + return true +} From 604afd5808d28b50ed48189ed2d6d7829acd564d Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 9 Oct 2019 16:57:05 +0200 Subject: [PATCH 274/378] update verification --- x/ibc/03-connection/keeper/keeper.go | 20 ++++++++++++------- x/ibc/03-connection/types/connection.go | 4 ++-- x/ibc/03-connection/types/expected_keepers.go | 10 +++++++++- x/ibc/03-connection/types/handshake.go | 7 ------- 4 files changed, 24 insertions(+), 17 deletions(-) delete mode 100644 x/ibc/03-connection/types/handshake.go diff --git a/x/ibc/03-connection/keeper/keeper.go b/x/ibc/03-connection/keeper/keeper.go index 968be1617ac3..e63885b6727c 100644 --- a/x/ibc/03-connection/keeper/keeper.go +++ b/x/ibc/03-connection/keeper/keeper.go @@ -120,14 +120,14 @@ func (k Keeper) verifyMembership( height uint64, proof ics23.Proof, path string, - value interface{}, // value: Value + value []byte, ) bool { - _, found := k.clientKeeper.GetClientState(ctx, connection.ClientID) + clientState, found := k.clientKeeper.GetClientState(ctx, connection.ClientID) if !found { return false } - // k.clientKeeper.VerifyMembership(ctx, clientState, height, proof, applyPrefix(connection.Counterparty.Prefix, path), value) - return true + path = k.applyPrefix(connection.Counterparty.Prefix, path) + return k.clientKeeper.VerifyMembership(ctx, clientState, height, proof, path, value) } func (k Keeper) verifyNonMembership( @@ -137,12 +137,13 @@ func (k Keeper) verifyNonMembership( proof ics23.Proof, path string, ) bool { - _, found := k.clientKeeper.GetClientState(ctx, connection.ClientID) + clientState, found := k.clientKeeper.GetClientState(ctx, connection.ClientID) if !found { return false } - // k.clientKeeper.VerifyNonMembership(ctx, clientState, height, proof, applyPrefix(connection.Counterparty.Prefix, path)) - return true + + path = k.applyPrefix(connection.Counterparty.Prefix, path) + return k.clientKeeper.VerifyNonMembership(ctx, clientState, height, proof, path) } func (k Keeper) getCompatibleVersions() []string { @@ -155,6 +156,11 @@ func (k Keeper) pickVersion(counterpartyVersions []string) string { return "" } +func (k Keeper) applyPrefix(prefix ics23.Prefix, path string) string { + // TODO: + return path +} + // checkVersion is an opaque function defined by the host state machine which // determines if two versions are compatible func checkVersion(version, counterpartyVersion string) bool { diff --git a/x/ibc/03-connection/types/connection.go b/x/ibc/03-connection/types/connection.go index 9a36d8a0a3f4..ad744dddc004 100644 --- a/x/ibc/03-connection/types/connection.go +++ b/x/ibc/03-connection/types/connection.go @@ -10,9 +10,9 @@ import ( // chains type ConnectionState = byte -// available ConnectionStates +// available connection states const ( - NONE ConnectionState = iota // default State + NONE ConnectionState = iota // default ConnectionState INIT TRYOPEN OPEN diff --git a/x/ibc/03-connection/types/expected_keepers.go b/x/ibc/03-connection/types/expected_keepers.go index f69b5095d1d1..89f84de3188d 100644 --- a/x/ibc/03-connection/types/expected_keepers.go +++ b/x/ibc/03-connection/types/expected_keepers.go @@ -4,11 +4,19 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ics02exported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ics02types "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // ClientKeeper expected account IBC client keeper type ClientKeeper interface { GetConsensusState(ctx sdk.Context, clientID string) (ics02exported.ConsensusState, bool) GetClientState(ctx sdk.Context, clientID string) (ics02types.ClientState, bool) + VerifyMembership( + ctx sdk.Context, clientState ics02types.ClientState, height uint64, + proof ics23.Proof, path string, value []byte, + ) bool + VerifyNonMembership( + ctx sdk.Context, clientState ics02types.ClientState, height uint64, + proof ics23.Proof, path string, + ) bool } - diff --git a/x/ibc/03-connection/types/handshake.go b/x/ibc/03-connection/types/handshake.go deleted file mode 100644 index 2717f7cfe60e..000000000000 --- a/x/ibc/03-connection/types/handshake.go +++ /dev/null @@ -1,7 +0,0 @@ -package types - -// Handshake defines a connection between two chains A and B -type Handshake struct { - ConnA ConnectionEnd - ConnB ConnectionEnd -} From cf347bf00482031b02fa4dfc5d9cd4c7419f333b Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 9 Oct 2019 22:29:36 +0200 Subject: [PATCH 275/378] ICS02 module.go --- x/ibc/02-client/alias.go | 78 +++++++++++++++++++++++++++++ x/ibc/02-client/client/cli/query.go | 20 ++++---- x/ibc/02-client/client/cli/tx.go | 22 +++----- x/ibc/02-client/handler.go | 34 ++++++------- x/ibc/02-client/module.go | 33 ++++++++++++ 5 files changed, 143 insertions(+), 44 deletions(-) create mode 100644 x/ibc/02-client/alias.go create mode 100644 x/ibc/02-client/module.go diff --git a/x/ibc/02-client/alias.go b/x/ibc/02-client/alias.go new file mode 100644 index 000000000000..f66d835dfa0e --- /dev/null +++ b/x/ibc/02-client/alias.go @@ -0,0 +1,78 @@ +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/02-client/types +package ics02 + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" +) + +const ( + DefaultCodespace = types.DefaultCodespace + CodeClientExists = types.CodeClientExists + CodeClientNotFound = types.CodeClientNotFound + CodeClientFrozen = types.CodeClientFrozen + CodeConsensusStateNotFound = types.CodeConsensusStateNotFound + CodeInvalidConsensusState = types.CodeInvalidConsensusState + CodeClientTypeNotFound = types.CodeClientTypeNotFound + CodeInvalidClientType = types.CodeInvalidClientType + CodeRootNotFound = types.CodeRootNotFound + EventTypeCreateClient = types.EventTypeCreateClient + EventTypeUpdateClient = types.EventTypeUpdateClient + EventTypeSubmitMisbehaviour = types.EventTypeSubmitMisbehaviour + AttributeKeyClientID = types.AttributeKeyClientID + SubModuleName = types.SubModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute + QueryClientState = types.QueryClientState + QueryConsensusState = types.QueryConsensusState + QueryCommitmentPath = types.QueryCommitmentPath + QueryCommitmentRoot = types.QueryCommitmentRoot +) + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper + NewQuerier = keeper.NewQuerier + RegisterCodec = types.RegisterCodec + ErrClientExists = types.ErrClientExists + ErrClientNotFound = types.ErrClientNotFound + ErrClientFrozen = types.ErrClientFrozen + ErrConsensusStateNotFound = types.ErrConsensusStateNotFound + ErrInvalidConsensus = types.ErrInvalidConsensus + ErrClientTypeNotFound = types.ErrClientTypeNotFound + ErrInvalidClientType = types.ErrInvalidClientType + ErrRootNotFound = types.ErrRootNotFound + ClientStatePath = types.ClientStatePath + ClientTypePath = types.ClientTypePath + ConsensusStatePath = types.ConsensusStatePath + RootPath = types.RootPath + KeyClientState = types.KeyClientState + KeyClientType = types.KeyClientType + KeyConsensusState = types.KeyConsensusState + KeyRoot = types.KeyRoot + NewMsgCreateClient = types.NewMsgCreateClient + NewMsgUpdateClient = types.NewMsgUpdateClient + NewMsgSubmitMisbehaviour = types.NewMsgSubmitMisbehaviour + NewQueryClientStateParams = types.NewQueryClientStateParams + NewQueryCommitmentRootParams = types.NewQueryCommitmentRootParams + NewClientState = types.NewClientState + + // variable aliases + SubModuleCdc = types.SubModuleCdc + AttributeValueCategory = types.AttributeValueCategory +) + +type ( + Keeper = keeper.Keeper + MsgCreateClient = types.MsgCreateClient + MsgUpdateClient = types.MsgUpdateClient + MsgSubmitMisbehaviour = types.MsgSubmitMisbehaviour + QueryClientStateParams = types.QueryClientStateParams + QueryCommitmentRootParams = types.QueryCommitmentRootParams + ClientState = types.ClientState +) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 108d77233d55..a3ce9f401418 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -9,7 +9,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" - cli "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/version" @@ -21,22 +21,22 @@ import ( ) // GetQueryCmd returns the query commands for IBC clients -func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - ibcQueryCmd := &cobra.Command{ +func GetQueryCmd(queryRouter string, cdc *codec.Codec) *cobra.Command { + ics02ClientQueryCmd := &cobra.Command{ Use: "client", Short: "IBC client query subcommands", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, } - ibcQueryCmd.AddCommand(cli.GetCommands( - GetCmdQueryConsensusState(storeKey, cdc), - GetCmdQueryPath(storeKey, cdc), + ics02ClientQueryCmd.AddCommand(client.GetCommands( + GetCmdQueryConsensusState(queryRouter, cdc), + GetCmdQueryPath(queryRouter, cdc), GetCmdQueryHeader(cdc), - GetCmdQueryClientState(storeKey, cdc), - GetCmdQueryRoot(storeKey, cdc), + GetCmdQueryClientState(queryRouter, cdc), + GetCmdQueryRoot(queryRouter, cdc), )...) - return ibcQueryCmd + return ics02ClientQueryCmd } // GetCmdQueryClientState defines the command to query the state of a client with @@ -170,7 +170,7 @@ $ %s query ibc client path RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - // TODO: + // TODO: get right path res, _, err := cliCtx.Query("") if err != nil { return err diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index c9aacb3747fd..ef9b0674882c 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cobra" - cli "github.com/cosmos/cosmos-sdk/client" + "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" @@ -18,32 +18,21 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" ) -// ICS02 Client CLI flags -const ( - FlagStatePath = "state" - FlagClientID = "client-id" - FlagConnectionID = "connection-id" - FlagChannelID = "channel-id" - FlagCounterpartyID = "counterparty-id" - FlagCounterpartyClientID = "counterparty-client-id" - FlagSourceNode = "source-node" -) - // GetTxCmd returns the transaction commands for IBC Clients func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - ibcTxCmd := &cobra.Command{ + ics02ClientTxCmd := &cobra.Command{ Use: "client", Short: "Client transaction subcommands", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, } - ibcTxCmd.AddCommand(cli.PostCommands( + ics02ClientTxCmd.AddCommand(client.PostCommands( GetCmdCreateClient(cdc), GetCmdUpdateClient(cdc), )...) - return ibcTxCmd + return ics02ClientTxCmd } // GetCmdCreateClient defines the command to create a new IBC Client as defined @@ -74,7 +63,8 @@ $ %s tx ibc client create [client-id] [path/to/consensus_state.json] --from node } msg := types.MsgCreateClient{ - ClientID: args[0], + ClientID: args[0], + ConsensusState: state, Signer: cliCtx.GetFromAddress(), } diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go index 6dab4bc41ba9..f2da176b4771 100644 --- a/x/ibc/02-client/handler.go +++ b/x/ibc/02-client/handler.go @@ -4,24 +4,22 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" ) // NewHandler creates a new Handler instance for IBC client // transactions -func NewHandler(k keeper.Keeper) sdk.Handler { +func NewHandler(k Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { - case types.MsgCreateClient: + case MsgCreateClient: return handleMsgCreateClient(ctx, k, msg) - case types.MsgUpdateClient: + case MsgUpdateClient: return handleMsgUpdateClient(ctx, k, msg) - case types.MsgSubmitMisbehaviour: + case MsgSubmitMisbehaviour: return handleMsgSubmitMisbehaviour(ctx, k, msg) default: @@ -31,7 +29,7 @@ func NewHandler(k keeper.Keeper) sdk.Handler { } } -func handleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgCreateClient) sdk.Result { +func handleMsgCreateClient(ctx sdk.Context, k Keeper, msg MsgCreateClient) sdk.Result { _, err := k.CreateClient(ctx, msg.ClientID, msg.ClientType, msg.ConsensusState) if err != nil { return sdk.ResultFromError(err) @@ -39,12 +37,12 @@ func handleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgCreate ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( - types.EventTypeCreateClient, - sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientID), + EventTypeCreateClient, + sdk.NewAttribute(AttributeKeyClientID, msg.ClientID), ), sdk.NewEvent( sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory), sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), ), }) @@ -52,7 +50,7 @@ func handleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgCreate return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgUpdateClient) sdk.Result { +func handleMsgUpdateClient(ctx sdk.Context, k Keeper, msg MsgUpdateClient) sdk.Result { err := k.UpdateClient(ctx, msg.ClientID, msg.Header) if err != nil { return sdk.ResultFromError(err) @@ -60,12 +58,12 @@ func handleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgUpdate ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( - types.EventTypeUpdateClient, - sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientID), + EventTypeUpdateClient, + sdk.NewAttribute(AttributeKeyClientID, msg.ClientID), ), sdk.NewEvent( sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory), sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), ), }) @@ -74,7 +72,7 @@ func handleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg types.MsgUpdate return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg types.MsgSubmitMisbehaviour) sdk.Result { +func handleMsgSubmitMisbehaviour(ctx sdk.Context, k Keeper, msg MsgSubmitMisbehaviour) sdk.Result { err := k.CheckMisbehaviourAndUpdateState(ctx, msg.ClientID, msg.Evidence) if err != nil { return sdk.ResultFromError(err) @@ -82,12 +80,12 @@ func handleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg types.Msg ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( - types.EventTypeSubmitMisbehaviour, - sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientID), + EventTypeSubmitMisbehaviour, + sdk.NewAttribute(AttributeKeyClientID, msg.ClientID), ), sdk.NewEvent( sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory), sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), ), }) diff --git a/x/ibc/02-client/module.go b/x/ibc/02-client/module.go new file mode 100644 index 000000000000..c839e262a101 --- /dev/null +++ b/x/ibc/02-client/module.go @@ -0,0 +1,33 @@ +package ics02 + +import ( + "fmt" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/cli" +) + +// Name returns the staking module's name +func Name() string { + return SubModuleName +} + +// RegisterRESTRoutes registers the REST routes for the staking module. +func RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { + // TODO: + // rest.RegisterRoutes(ctx, rtr) +} + +// GetTxCmd returns the root tx command for the staking module. +func GetTxCmd(cdc *codec.Codec, storeKey string) *cobra.Command { + return cli.GetTxCmd(fmt.Sprintf("%s/%s", storeKey, SubModuleName), cdc) +} + +// GetQueryCmd returns no root query command for the staking module. +func GetQueryCmd(cdc *codec.Codec, queryRoute string) *cobra.Command { + return cli.GetQueryCmd(fmt.Sprintf("%s/%s", queryRoute, SubModuleName), cdc) +} From 5514e9e3cd8e96af7349c96ddc6172554bae3021 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 9 Oct 2019 22:30:40 +0200 Subject: [PATCH 276/378] top level x/ibc structure --- x/ibc/alias.go | 27 ++++++++ x/ibc/client/cli/cli.go | 43 +++++++++++++ x/ibc/handler.go | 13 ++++ x/ibc/keeper/keeper.go | 19 ++++++ x/ibc/module.go | 133 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 235 insertions(+) create mode 100644 x/ibc/alias.go create mode 100644 x/ibc/client/cli/cli.go create mode 100644 x/ibc/handler.go create mode 100644 x/ibc/keeper/keeper.go create mode 100644 x/ibc/module.go diff --git a/x/ibc/alias.go b/x/ibc/alias.go new file mode 100644 index 000000000000..34587f7580e8 --- /dev/null +++ b/x/ibc/alias.go @@ -0,0 +1,27 @@ +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/types +package ibc + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +const ( + ModuleName = types.ModuleName + StoreKey = types.StoreKey + QuerierRoute = types.QuerierRoute + RouterKey = types.RouterKey +) + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper +) + +type ( + Keeper = keeper.Keeper +) diff --git a/x/ibc/client/cli/cli.go b/x/ibc/client/cli/cli.go new file mode 100644 index 000000000000..640d4b3f580c --- /dev/null +++ b/x/ibc/client/cli/cli.go @@ -0,0 +1,43 @@ +package cli + +import ( + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + ics02 "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ibcTxCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "IBC transaction subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + ibcTxCmd.AddCommand( + ics02.GetTxCmd(cdc, storeKey), + ) + return ibcTxCmd +} + +// GetQueryCmd returns the cli query commands for this module +func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { + // Group ibc queries under a subcommand + ibcQueryCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the IBC module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + ibcQueryCmd.AddCommand( + ics02.GetQueryCmd(cdc, queryRoute), + ) + return ibcQueryCmd +} diff --git a/x/ibc/handler.go b/x/ibc/handler.go new file mode 100644 index 000000000000..5420e956fb4f --- /dev/null +++ b/x/ibc/handler.go @@ -0,0 +1,13 @@ +package ibc + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// NewHandler defines the IBC handler +func NewHandler(k Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + // TODO: + return sdk.Result{} + } +} diff --git a/x/ibc/keeper/keeper.go b/x/ibc/keeper/keeper.go new file mode 100644 index 000000000000..1dd8abef5596 --- /dev/null +++ b/x/ibc/keeper/keeper.go @@ -0,0 +1,19 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + ics02 "github.com/cosmos/cosmos-sdk/x/ibc/02-client" +) + +// Keeper defines each ICS keeper for IBC +type Keeper struct { + ClientKeeper ics02.Keeper +} + +// NewKeeper creates a new ibc Keeper +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) Keeper { + return Keeper{ + ClientKeeper: ics02.NewKeeper(cdc, key, codespace), + } +} diff --git a/x/ibc/module.go b/x/ibc/module.go new file mode 100644 index 000000000000..950ab8938c14 --- /dev/null +++ b/x/ibc/module.go @@ -0,0 +1,133 @@ +package ibc + +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" + ics02 "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// TODO: AppModuleSimulation +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// AppModuleBasic defines the basic application module used by the staking module. +type AppModuleBasic struct{} + +var _ module.AppModuleBasic = AppModuleBasic{} + +// Name returns the staking module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterCodec registers the staking module's types for the given codec. +func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { + ics02.RegisterCodec(cdc) + ics23.RegisterCodec(cdc) +} + +// DefaultGenesis returns default genesis state as raw bytes for the staking +// module. +func (AppModuleBasic) DefaultGenesis() json.RawMessage { + return nil +} + +// ValidateGenesis performs genesis state validation for the staking module. +func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { + return nil +} + +// RegisterRESTRoutes registers the REST routes for the staking module. +func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { + //noop +} + +// GetTxCmd returns the root tx command for the staking module. +func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetTxCmd(StoreKey, cdc) +} + +// GetQueryCmd returns no root query command for the staking module. +func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetQueryCmd(QuerierRoute, cdc) +} + +// AppModule implements an application module for the staking module. +type AppModule struct { + AppModuleBasic + keeper Keeper +} + +// NewAppModule creates a new AppModule object +func NewAppModule(k Keeper) AppModule { + return AppModule{ + keeper: k, + } +} + +// Name returns the staking module's name. +func (AppModule) Name() string { + return ModuleName +} + +// RegisterInvariants registers the staking module invariants. +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + // TODO: +} + +// Route returns the message routing key for the staking module. +func (AppModule) Route() string { + return RouterKey +} + +// NewHandler returns an sdk.Handler for the staking module. +func (am AppModule) NewHandler() sdk.Handler { + return NewHandler(am.keeper) +} + +// QuerierRoute returns the staking module's querier route name. +func (AppModule) QuerierRoute() string { + return QuerierRoute +} + +// NewQuerierHandler returns the staking module sdk.Querier. +func (am AppModule) NewQuerierHandler() sdk.Querier { + // return NewQuerier(am.keeper + return nil +} + +// InitGenesis performs genesis initialization for the staking module. It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the exported genesis state as raw bytes for the staking +// module. +func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { + return nil +} + +// BeginBlock returns the begin blocker for the staking module. +func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { +} + +// EndBlock returns the end blocker for the staking module. It returns no validator +// updates. +func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} From eefa08bda0d7fd0ec6f678a5bc17bd00ff1b7f73 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 9 Oct 2019 22:56:54 +0200 Subject: [PATCH 277/378] update connection queries --- x/ibc/03-connection/client/cli/query.go | 133 +++++++++++++----------- x/ibc/03-connection/types/querier.go | 64 ++++++------ 2 files changed, 100 insertions(+), 97 deletions(-) diff --git a/x/ibc/03-connection/client/cli/query.go b/x/ibc/03-connection/client/cli/query.go index 96d4c24d92c7..50f5ac6003f0 100644 --- a/x/ibc/03-connection/client/cli/query.go +++ b/x/ibc/03-connection/client/cli/query.go @@ -2,98 +2,107 @@ package cli import ( "fmt" + "strings" "github.com/spf13/cobra" - "github.com/spf13/viper" - cli "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" - storestate "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" - "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/utils" - "github.com/cosmos/cosmos-sdk/x/ibc/version" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" ) -const ( - FlagProve = "prove" -) - -func state(cdc *codec.Codec, storeKey string, prefix []byte, connid, clientid string) connection.State { - base := storestate.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) - climan := client.NewManager(base) - man := connection.NewManager(base, climan) - return man.CLIState(connid, clientid) -} +// const ( +// FlagProve = "prove" +// ) +// GetQueryCmd returns the query commands for IBC connections func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - ibcQueryCmd := &cobra.Command{ + ics03ConnectionQueryCmd := &cobra.Command{ Use: "connection", - Short: "Connection query subcommands", + Short: "IBC connection query subcommands", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, } - ibcQueryCmd.AddCommand(cli.GetCommands( + ics03ConnectionQueryCmd.AddCommand(client.GetCommands( GetCmdQueryConnection(storeKey, cdc), )...) - return ibcQueryCmd + return ics03ConnectionQueryCmd } -func QueryConnection(ctx context.CLIContext, obj connection.State, prove bool) (res utils.JSONState, err error) { - q := storestate.NewCLIQuerier(ctx) +// GetCmdQueryConnection defines the command to query a connection end +func GetCmdQueryConnection(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "end [connection-id]", + Short: "Query stored connection end", + Long: strings.TrimSpace(fmt.Sprintf(`Query stored connection end + +Example: +$ %s query ibc connection end [connection-id] + `, version.ClientName), + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + connectionID := args[0] - conn, connp, err := obj.ConnectionCLI(q) - if err != nil { - return - } - avail, availp, err := obj.AvailableCLI(q) - if err != nil { - return - } - kind, kindp, err := obj.KindCLI(q) - if err != nil { - return - } + bz, err := cdc.MarshalJSON(types.NewQueryConnectionParams(connectionID)) + if err != nil { + return err + } + + res, _, err := cliCtx.QueryWithData(types.ConnectionPath(connectionID), bz) + if err != nil { + return err + } - if prove { - return utils.NewJSONState( - conn, connp, - avail, availp, - kind, kindp, - ), nil + var connection types.ConnectionEnd + if err := cdc.UnmarshalJSON(res, &connection); err != nil { + return err + } + + return cliCtx.PrintOutput(connection) + }, } + // cmd.Flags().Bool(FlagProve, false, "(optional) show proofs for the query results") - return utils.NewJSONState( - conn, nil, - avail, nil, - kind, nil, - ), nil + return cmd } -func GetCmdQueryConnection(storeKey string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "connection", - Short: "Query stored connection", - Args: cobra.ExactArgs(1), +// GetCmdQueryClientConnections defines the command to query a client connections +func GetCmdQueryClientConnections(storeKey string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "client [client-id]", + Short: "Query stored client connection paths", + Long: strings.TrimSpace(fmt.Sprintf(`Query stored client connection paths + +Example: +$ %s query ibc connection client [client-id] + `, version.ClientName), + ), + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - state := state(cdc, storeKey, version.Prefix(version.Version), args[0], "") - jsonObj, err := QueryConnection(ctx, state, viper.GetBool(FlagProve)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + clientID := args[0] + + bz, err := cdc.MarshalJSON(types.NewQueryClientConnectionsParams(clientID)) if err != nil { return err } - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, jsonObj)) + res, _, err := cliCtx.QueryWithData(types.ClientConnectionsPath(clientID), bz) + if err != nil { + return err + } + + var connectionPaths []string + if err := cdc.UnmarshalJSON(res, &connectionPaths); err != nil { + return err + } - return nil + return cliCtx.PrintOutput(connectionPaths) }, } - - cmd.Flags().Bool(FlagProve, false, "(optional) show proofs for the query results") - - return cmd } diff --git a/x/ibc/03-connection/types/querier.go b/x/ibc/03-connection/types/querier.go index 44f852664787..7834f4370ab3 100644 --- a/x/ibc/03-connection/types/querier.go +++ b/x/ibc/03-connection/types/querier.go @@ -1,41 +1,35 @@ package types +// query routes supported by the IBC connection Querier +const ( + QueryClientState = "clientState" + QueryConsensusState = "consensusState" + QueryCommitmentPath = "commitmentPath" + QueryCommitmentRoot = "roots" +) -// TODO: +// QueryConnectionParams defines the params for the following queries: +// - 'custom/ibc/connections/' +type QueryConnectionParams struct { + ConnectionID string +} -// // query routes supported by the IBC client Querier -// const ( -// QueryClientState = "clientState" -// QueryConsensusState = "consensusState" -// QueryCommitmentPath = "commitmentPath" -// QueryCommitmentRoot = "roots" -// ) +// NewQueryConnectionParams creates a new QueryConnectionParams instance +func NewQueryConnectionParams(clientID string) QueryConnectionParams { + return QueryConnectionParams{ + ConnectionID: clientID, + } +} -// // QueryClientStateParams defines the params for the following queries: -// // - 'custom/ibc/clients//clientState' -// // - 'custom/ibc/clients//consensusState' -// type QueryClientStateParams struct { -// ClientID string -// } +// QueryClientConnectionsParams defines the params for the following queries: +// - 'custom/ibc/client//connections' +type QueryClientConnectionsParams struct { + ClientID string +} -// // NewQueryClientStateParams creates a new QueryClientStateParams instance -// func NewQueryClientStateParams(id string) QueryClientStateParams { -// return QueryClientStateParams{ -// ClientID: id, -// } -// } - -// // QueryCommitmentRootParams defines the params for the following queries: -// // - 'custom/ibc/clients//roots/' -// type QueryCommitmentRootParams struct { -// ClientID string -// Height uint64 -// } - -// // NewQueryCommitmentRootParams creates a new QueryCommitmentRootParams instance -// func NewQueryCommitmentRootParams(id string, height uint64) QueryCommitmentRootParams { -// return QueryCommitmentRootParams{ -// ClientID: id, -// Height: height, -// } -// } +// NewQueryClientConnectionsParams creates a new QueryClientConnectionsParams instance +func NewQueryClientConnectionsParams(clientID string) QueryClientConnectionsParams { + return QueryClientConnectionsParams{ + ClientID: clientID, + } +} From 482f24d10e10087f23d4068e53b8afe8c5b7152e Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 10 Oct 2019 17:58:35 +0200 Subject: [PATCH 278/378] update connection tx --- x/ibc/03-connection/client/cli/tx.go | 592 +++++++++++++++++---------- 1 file changed, 384 insertions(+), 208 deletions(-) diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index 84524013dd27..a45fbf2e8a38 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -1,298 +1,474 @@ package cli import ( - "fmt" "io/ioutil" - "time" + "strings" "github.com/spf13/cobra" "github.com/spf13/viper" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" - storestate "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" - 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" - FlagFrom1 = "from1" - FlagFrom2 = "from2" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -func handshake(q storestate.ABCIQuerier, cdc *codec.Codec, storeKey string, prefix []byte, connid string) (connection.HandshakeState, error) { - base := storestate.NewMapping(sdk.NewKVStoreKey(storeKey), cdc, prefix) - clientManager := client.NewManager(base) - man := connection.NewHandshaker(connection.NewManager(base, clientManager)) - return man.CLIQuery(q, connid) -} - -func lastHeight(ctx context.CLIContext) (uint64, error) { - node, err := ctx.GetNode() - if err != nil { - return 0, err - } - - info, err := node.ABCIInfo() - if err != nil { - return 0, err - } - - return uint64(info.Response.LastBlockHeight), nil -} +// const ( +// FlagNode2 = "node2" +// FlagFrom2 = "from2" +// ) +// GetTxCmd returns the transaction commands for IBC Connections func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + ics03ConnectionTxCmd := &cobra.Command{ Use: "connection", Short: "IBC connection transaction subcommands", } - cmd.AddCommand( - GetCmdHandshake(storeKey, cdc), - ) + ics03ConnectionTxCmd.AddCommand(client.PostCommands( + GetCmdConnectionOpenInit(storeKey, cdc), + GetCmdConnectionOpenTry(storeKey, cdc), + GetCmdConnectionOpenAck(storeKey, cdc), + GetCmdConnectionOpenConfirm(storeKey, cdc), + )...) - return cmd + return ics03ConnectionTxCmd } -func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { +// GetCmdConnectionOpenInit defines the command to initialize a connection on +// chain A with a given counterparty chain B +func GetCmdConnectionOpenInit(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "handshake", - Short: "initiate connection handshake between two chains", + Use: strings.TrimSpace(`open-init [connection-id] [client-id] [counterparty-connection-id] + [counterparty-client-id] [path/to/counterparty_prefix.json]`), + Short: "initialize connection on chain A", Args: cobra.ExactArgs(6), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - ctx1 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). - WithCodec(cdc). - WithNodeURI(viper.GetString(FlagNode1)). - WithBroadcastMode(flags.BroadcastBlock) - q1 := storestate.NewCLIQuerier(ctx1) - - ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). - WithCodec(cdc). - WithNodeURI(viper.GetString(FlagNode2)). - WithBroadcastMode(flags.BroadcastBlock) - q2 := storestate.NewCLIQuerier(ctx2) - - connId1 := args[0] - clientId1 := args[1] - connId2 := args[3] - clientId2 := args[4] - - var path1 commitment.Prefix - path1bz, err := ioutil.ReadFile(args[2]) - if err != nil { - return err - } - if err = cdc.UnmarshalJSON(path1bz, &path1); err != nil { - return err - } - conn1 := connection.Connection{ - Client: clientId1, - Counterparty: connId2, - Path: path1, - } - - obj1, err := handshake(q1, cdc, storeKey, version.DefaultPrefix(), connId1) + cliCtx := context.NewCLIContext().WithCodec(cdc) + // cliCtx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). + // WithCodec(cdc). + // WithNodeURI(viper.GetString(FlagNode2)). + // WithBroadcastMode(flags.BroadcastBlock) + + connectionID := args[0] + clientID := args[1] + counterpartyConnectionID := args[2] + counterpartyClientID := args[3] + + bz, err := ioutil.ReadFile(args[4]) if err != nil { return err } - var path2 commitment.Prefix - path2bz, err := ioutil.ReadFile(args[5]) - if err != nil { + var counterpartyPrefix ics23.Prefix + if err := cdc.UnmarshalJSON(bz, &counterpartyPrefix); err != nil { return err } - if err = cdc.UnmarshalJSON(path2bz, &path2); err != nil { - return err - } - conn2 := connection.Connection{ - Client: clientId2, - Counterparty: connId1, - Path: path2, - } - obj2, err := handshake(q2, cdc, storeKey, version.DefaultPrefix(), connId2) - if err != nil { - return err - } + msg := types.NewMsgConnectionOpenInit( + connectionID, clientID, counterpartyConnectionID, counterpartyClientID, + counterpartyPrefix, cliCtx.GetFromAddress(), + ) - // TODO: check state and if not Idle continue existing process - msgInit := connection.MsgOpenInit{ - ConnectionID: connId1, - Connection: conn1, - CounterpartyClient: conn2.Client, - Signer: ctx1.GetFromAddress(), - } + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgInit}) - if err != nil { - return err - } +// GetCmdConnectionOpenTry defines the command to initialize a connection on +// chain A with a given counterparty chain B +func GetCmdConnectionOpenTry(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: strings.TrimSpace(`open-try [connection-id] [client-id] +[counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json] +[counterparty-versions] [path/to/proof_init.json]`), + Short: "initiate connection handshake between two chains", + Args: cobra.ExactArgs(6), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithHeight(viper.GetInt64(flags.FlagHeight)) + // cliCtx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). + // WithCodec(cdc). + // WithNodeURI(viper.GetString(FlagNode2)). - // 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) + connectionID := args[0] + clientID := args[1] + counterpartyConnectionID := args[2] + counterpartyClientID := args[3] - header, err := getHeader(ctx1) + prefixBz, err := ioutil.ReadFile(args[4]) if err != nil { return err } - msgUpdate := client.MsgUpdateClient{ - ClientID: conn2.Client, - Header: header, - Signer: ctx2.GetFromAddress(), - } - - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) - if err != nil { + var counterpartyPrefix ics23.Prefix + if err := cdc.UnmarshalJSON(prefixBz, &counterpartyPrefix); err != nil { return err } - q1 = storestate.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) - fmt.Printf("querying from %d\n", header.Height-1) + // TODO: parse strings? + counterpartyVersions := args[5] - _, pconn, err := obj1.ConnectionCLI(q1) - if err != nil { - return err - } - _, pstate, err := obj1.StageCLI(q1) - if err != nil { - return err - } - _, pcounter, err := obj1.CounterpartyClientCLI(q1) + proofBz, err := ioutil.ReadFile(args[6]) if err != nil { return err } - msgTry := connection.MsgOpenTry{ - ConnectionID: connId2, - Connection: conn2, - CounterpartyClient: conn1.Client, - Proofs: []commitment.Proof{pconn, pstate, pcounter}, - Height: uint64(header.Height), - Signer: ctx2.GetFromAddress(), - } - - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgTry}) - if err != nil { + var proofInit ics23.Proof + if err := cdc.UnmarshalJSON(proofBz, &proofInit); 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(ctx2) + proofHeight := uint64(cliCtx.Height) + consensusHeight, err := lastHeight(cliCtx) if err != nil { return err } - msgUpdate = client.MsgUpdateClient{ - ClientID: conn1.Client, - Header: header, - Signer: ctx1.GetFromAddress(), - } + msg := types.NewMsgConnectionOpenTry( + connectionID, clientID, counterpartyConnectionID, counterpartyClientID, + counterpartyPrefix, []string{counterpartyVersions}, proofInit, proofHeight, + consensusHeight, cliCtx.GetFromAddress(), + ) - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgUpdate}) - if err != nil { - return err - } - - q2 = storestate.NewCLIQuerier(ctx2.WithHeight(header.Height - 1)) + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} - _, pconn, err = obj2.ConnectionCLI(q2) +// GetCmdConnectionOpenAck defines the command to initialize a connection on +// chain A with a given counterparty chain B +func GetCmdConnectionOpenAck(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "open-ack [connection-id] [path/to/proof_try.json] [version]", + Short: "relay the acceptance of a connection open attempt from chain B to chain A", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + // cliCtx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). + // WithCodec(cdc). + // WithNodeURI(viper.GetString(FlagNode2)). + // WithBroadcastMode(flags.BroadcastBlock) + + connectionID := args[0] + proofBz, err := ioutil.ReadFile(args[1]) if err != nil { return err } - _, pstate, err = obj2.StageCLI(q2) - if err != nil { + + var proofTry ics23.Proof + if err := cdc.UnmarshalJSON(proofBz, &proofTry); err != nil { return err } - _, pcounter, err = obj2.CounterpartyClientCLI(q2) + + proofHeight := uint64(cliCtx.Height) + consensusHeight, err := lastHeight(cliCtx) if err != nil { return err } - msgAck := connection.MsgOpenAck{ - ConnectionID: connId1, - Proofs: []commitment.Proof{pconn, pstate, pcounter}, - Height: uint64(header.Height), - Signer: ctx1.GetFromAddress(), - } + version := args[4] - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgAck}) - if err != nil { - return err - } + msg := types.NewMsgConnectionOpenAck( + connectionID, proofTry, proofHeight, + consensusHeight, version, cliCtx.GetFromAddress(), + ) - // 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) + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} - header, err = getHeader(ctx1) - if err != nil { - return err - } +// GetCmdConnectionOpenConfirm defines the command to initialize a connection on +// chain A with a given counterparty chain B +func GetCmdConnectionOpenConfirm(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "open-confirm [connection-id] [path/to/proof_ack.json]", + Short: "confirm to chain B that connection is open on chain A", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithHeight(viper.GetInt64(flags.FlagHeight)) + // cliCtx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). + // WithCodec(cdc). + // WithNodeURI(viper.GetString(FlagNode2)). + // WithBroadcastMode(flags.BroadcastBlock) - msgUpdate = client.MsgUpdateClient{ - ClientID: conn2.Client, - Header: header, - Signer: ctx2.GetFromAddress(), - } + connectionID := args[0] - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) + proofBz, err := ioutil.ReadFile(args[1]) if err != nil { return err } - q1 = storestate.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) - - _, pstate, err = obj1.StageCLI(q1) - if err != nil { + var proofAck ics23.Proof + if err := cdc.UnmarshalJSON(proofBz, &proofAck); err != nil { return err } - msgConfirm := connection.MsgOpenConfirm{ - ConnectionID: connId2, - Proofs: []commitment.Proof{pstate}, - Height: uint64(header.Height), - Signer: ctx2.GetFromAddress(), - } + proofHeight := uint64(cliCtx.Height) - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgConfirm}) - if err != nil { - return err - } + msg := types.NewMsgConnectionOpenConfirm( + connectionID, proofAck, proofHeight, cliCtx.GetFromAddress(), + ) - return nil + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } + return cmd +} - // 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, "", "") +// lastHeight util function to get the consensus height from the node +func lastHeight(cliCtx context.CLIContext) (uint64, error) { + node, err := cliCtx.GetNode() + if err != nil { + return 0, err + } - cmd.MarkFlagRequired(FlagFrom1) - cmd.MarkFlagRequired(FlagFrom2) + info, err := node.ABCIInfo() + if err != nil { + return 0, err + } - return cmd + return uint64(info.Response.LastBlockHeight), nil } + +// func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { +// cmd := &cobra.Command{ +// Use: "handshake", +// Short: "initiate connection handshake between two chains", +// Args: cobra.ExactArgs(6), +// RunE: func(cmd *cobra.Command, args []string) error { +// txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) +// ctx1 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). +// WithCodec(cdc). +// WithNodeURI(viper.GetString(FlagNode1)). +// WithBroadcastMode(flags.BroadcastBlock) +// q1 := storestate.NewCLIQuerier(ctx1) + +// ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). +// WithCodec(cdc). +// WithNodeURI(viper.GetString(FlagNode2)). +// WithBroadcastMode(flags.BroadcastBlock) +// q2 := storestate.NewCLIQuerier(ctx2) + +// connId1 := args[0] +// clientId1 := args[1] +// connId2 := args[3] +// clientId2 := args[4] + +// var path1 commitment.Prefix +// path1bz, err := ioutil.ReadFile(args[2]) +// if err != nil { +// return err +// } +// if err = cdc.UnmarshalJSON(path1bz, &path1); err != nil { +// return err +// } +// conn1 := connection.Connection{ +// Client: clientId1, +// Counterparty: connId2, +// Path: path1, +// } + +// obj1, err := handshake(q1, cdc, storeKey, version.DefaultPrefix(), connId1) +// if err != nil { +// return err +// } + +// var path2 commitment.Prefix +// path2bz, err := ioutil.ReadFile(args[5]) +// if err != nil { +// return err +// } +// if err = cdc.UnmarshalJSON(path2bz, &path2); err != nil { +// return err +// } +// conn2 := connection.Connection{ +// Client: clientId2, +// Counterparty: connId1, +// Path: path2, +// } + +// obj2, err := handshake(q2, cdc, storeKey, version.DefaultPrefix(), connId2) +// if err != nil { +// return err +// } + +// // TODO: check state and if not Idle continue existing process +// msgInit := connection.MsgOpenInit{ +// ConnectionID: connId1, +// Connection: conn1, +// CounterpartyClient: conn2.Client, +// Signer: ctx1.GetFromAddress(), +// } + +// err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgInit}) +// 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 +// } + +// msgUpdate := client.MsgUpdateClient{ +// ClientID: conn2.Client, +// Header: header, +// Signer: ctx2.GetFromAddress(), +// } + +// err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) +// if err != nil { +// return err +// } + +// q1 = storestate.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 +// } +// _, pstate, err := obj1.StageCLI(q1) +// if err != nil { +// return err +// } +// _, pcounter, err := obj1.CounterpartyClientCLI(q1) +// if err != nil { +// return err +// } + +// msgTry := connection.MsgOpenTry{ +// ConnectionID: connId2, +// Connection: conn2, +// CounterpartyClient: conn1.Client, +// Proofs: []commitment.Proof{pconn, pstate, pcounter}, +// Height: uint64(header.Height), +// Signer: ctx2.GetFromAddress(), +// } + +// err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgTry}) +// 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(ctx2) +// if err != nil { +// return err +// } + +// msgUpdate = client.MsgUpdateClient{ +// ClientID: conn1.Client, +// Header: header, +// Signer: ctx1.GetFromAddress(), +// } + +// err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgUpdate}) +// if err != nil { +// return err +// } + +// q2 = storestate.NewCLIQuerier(ctx2.WithHeight(header.Height - 1)) + +// _, pconn, err = obj2.ConnectionCLI(q2) +// if err != nil { +// return err +// } +// _, pstate, err = obj2.StageCLI(q2) +// if err != nil { +// return err +// } +// _, pcounter, err = obj2.CounterpartyClientCLI(q2) +// if err != nil { +// return err +// } + +// 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}) +// 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 +// } + +// msgUpdate = client.MsgUpdateClient{ +// ClientID: conn2.Client, +// Header: header, +// Signer: ctx2.GetFromAddress(), +// } + +// err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) +// if err != nil { +// return err +// } + +// q1 = storestate.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) + +// _, pstate, err = obj1.StageCLI(q1) +// if err != nil { +// return err +// } + +// msgConfirm := connection.MsgOpenConfirm{ +// ConnectionID: connId2, +// Proofs: []commitment.Proof{pstate}, +// Height: uint64(header.Height), +// Signer: ctx2.GetFromAddress(), +// } + +// err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgConfirm}) +// if err != nil { +// return err +// } + +// return nil +// }, +// } +// cmd.Flags().String(FlagNode2, "tcp://localhost:26657", "") +// cmd.Flags().String(FlagFrom2, "", "") + +// return cmd +// } From e4ffd8e20fafb5154c4928eb8eabdf6138876049 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 10 Oct 2019 19:32:22 +0200 Subject: [PATCH 279/378] remove extra files --- x/ibc/03-connection/cli.go | 70 ----------------------- x/ibc/03-connection/client/cli/query.go | 1 + x/ibc/03-connection/client/cli/tx.go | 49 +++++++++++++--- x/ibc/03-connection/client/utils/types.go | 57 ------------------ x/ibc/03-connection/keeper/handshake.go | 5 ++ 5 files changed, 47 insertions(+), 135 deletions(-) delete mode 100644 x/ibc/03-connection/cli.go delete mode 100644 x/ibc/03-connection/client/utils/types.go diff --git a/x/ibc/03-connection/cli.go b/x/ibc/03-connection/cli.go deleted file mode 100644 index e514c301a8bf..000000000000 --- a/x/ibc/03-connection/cli.go +++ /dev/null @@ -1,70 +0,0 @@ -package ics03 - -// import ( -// "bytes" - -// "github.com/cosmos/cosmos-sdk/store/state" -// "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" -// ) - -// func (man Manager) CLIState(connid, clientid string) State { -// state := man.State(connid) -// state.Client = man.client.State(clientid) -// return state -// } - -// func (man Manager) CLIQuery(q state.ABCIQuerier, connid string) (State, error) { -// state := man.State(connid) -// conn, _, err := state.ConnectionCLI(q) -// if err != nil { -// return State{}, err -// } -// state.Client = man.client.State(conn.Client) -// return state, nil -// } - -// func (state State) prefix() []byte { -// return bytes.Split(state.Connection.KeyBytes(), LocalRoot())[0] -// } - -// func (state State) ConnectionCLI(q state.ABCIQuerier) (res Connection, proof merkle.Proof, err error) { -// tmproof, err := state.Connection.Query(q, &res) -// proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Connection) -// return -// } - -// func (state State) AvailableCLI(q state.ABCIQuerier) (res bool, proof merkle.Proof, err error) { -// res, tmproof, err := state.Available.Query(q) -// proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Available) -// return -// } - -// func (state State) KindCLI(q state.ABCIQuerier) (res string, proof merkle.Proof, err error) { -// res, tmproof, err := state.Kind.Query(q) -// proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Kind) -// return -// } - -// func (man Handshaker) CLIState(connid, clientid string) HandshakeState { -// return man.CreateState(man.man.CLIState(connid, clientid)) -// } - -// func (man Handshaker) CLIQuery(q state.ABCIQuerier, connid string) (HandshakeState, error) { -// state, err := man.man.CLIQuery(q, connid) -// if err != nil { -// return HandshakeState{}, err -// } -// return man.CreateState(state), nil -// } - -// func (state HandshakeState) StageCLI(q state.ABCIQuerier) (res byte, proof merkle.Proof, err error) { -// res, tmproof, err := state.Stage.Query(q) -// proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.Stage) -// return -// } - -// func (state HandshakeState) CounterpartyClientCLI(q state.ABCIQuerier) (res string, proof merkle.Proof, err error) { -// res, tmproof, err := state.CounterpartyClient.Query(q) -// proof = merkle.NewProofFromValue(tmproof, state.prefix(), state.CounterpartyClient) -// return -// } diff --git a/x/ibc/03-connection/client/cli/query.go b/x/ibc/03-connection/client/cli/query.go index 50f5ac6003f0..53cd6297eafd 100644 --- a/x/ibc/03-connection/client/cli/query.go +++ b/x/ibc/03-connection/client/cli/query.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" ) +// TODO: get proofs // const ( // FlagProve = "prove" // ) diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index a45fbf2e8a38..a7376dfcdc81 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -1,6 +1,7 @@ package cli import ( + "fmt" "io/ioutil" "strings" @@ -12,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/client/utils" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" @@ -47,7 +49,15 @@ func GetCmdConnectionOpenInit(storeKey string, cdc *codec.Codec) *cobra.Command Use: strings.TrimSpace(`open-init [connection-id] [client-id] [counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json]`), Short: "initialize connection on chain A", - Args: cobra.ExactArgs(6), + Long: strings.TrimSpace( + fmt.Sprintf(`initialize a connection on chain A with a given counterparty chain B: + +Example: +$ %s tx ibc connection open-init [connection-id] [client-id] [counterparty-connection-id] +[counterparty-client-id] [path/to/counterparty_prefix.json] + `, version.ClientName), + ), + Args: cobra.ExactArgs(6), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) @@ -82,15 +92,24 @@ func GetCmdConnectionOpenInit(storeKey string, cdc *codec.Codec) *cobra.Command return cmd } -// GetCmdConnectionOpenTry defines the command to initialize a connection on -// chain A with a given counterparty chain B +// GetCmdConnectionOpenTry defines the command to relay a try open a connection on +// chain B func GetCmdConnectionOpenTry(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: strings.TrimSpace(`open-try [connection-id] [client-id] [counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json] [counterparty-versions] [path/to/proof_init.json]`), Short: "initiate connection handshake between two chains", - Args: cobra.ExactArgs(6), + Long: strings.TrimSpace( + fmt.Sprintf(`initialize a connection on chain A with a given counterparty chain B: + +Example: +$ %s tx ibc connection open-try connection-id] [client-id] +[counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json] +[counterparty-versions] [path/to/proof_init.json] + `, version.ClientName), + ), + Args: cobra.ExactArgs(6), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext(). @@ -146,13 +165,20 @@ func GetCmdConnectionOpenTry(storeKey string, cdc *codec.Codec) *cobra.Command { return cmd } -// GetCmdConnectionOpenAck defines the command to initialize a connection on -// chain A with a given counterparty chain B +// GetCmdConnectionOpenAck defines the command to relay the acceptance of a +// connection open attempt from chain B to chain A func GetCmdConnectionOpenAck(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "open-ack [connection-id] [path/to/proof_try.json] [version]", Short: "relay the acceptance of a connection open attempt from chain B to chain A", - Args: cobra.ExactArgs(3), + Long: strings.TrimSpace( + fmt.Sprintf(`relay the acceptance of a connection open attempt from chain B to chain A: + +Example: +$ %s tx ibc connection open-ack [connection-id] [path/to/proof_try.json] [version] + `, version.ClientName), + ), + Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) @@ -197,7 +223,14 @@ func GetCmdConnectionOpenConfirm(storeKey string, cdc *codec.Codec) *cobra.Comma cmd := &cobra.Command{ Use: "open-confirm [connection-id] [path/to/proof_ack.json]", Short: "confirm to chain B that connection is open on chain A", - Args: cobra.ExactArgs(3), + Long: strings.TrimSpace( + fmt.Sprintf(`confirm to chain B that connection is open on chain A: + +Example: +$ %s tx ibc connection open-confirm [connection-id] [path/to/proof_ack.json] + `, version.ClientName), + ), + Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext(). diff --git a/x/ibc/03-connection/client/utils/types.go b/x/ibc/03-connection/client/utils/types.go deleted file mode 100644 index 24eff8ae5e7c..000000000000 --- a/x/ibc/03-connection/client/utils/types.go +++ /dev/null @@ -1,57 +0,0 @@ -package utils - -import ( - connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -type JSONState struct { - Connection connection.Connection `json:"connection"` - ConnectionProof ics23.Proof `json:"connection_proof,omitempty"` - Available bool `json:"available"` - AvailableProof ics23.Proof `json:"available_proof,omitempty"` - Kind string `json:"kind"` - KindProof ics23.Proof `json:"kind_proof,omitempty"` - - State byte `json:"state,omitempty"` - StateProof ics23.Proof `json:"state_proof,omitempty"` - CounterpartyClient string `json:"counterparty_client,omitempty"` - CounterpartyClientProof ics23.Proof `json:"counterparty_client_proof,omitempty"` -} - -func NewJSONState( - conn connection.Connection, connp ics23.Proof, - avail bool, availp ics23.Proof, - kind string, kindp ics23.Proof, -) JSONState { - return JSONState{ - Connection: conn, - ConnectionProof: connp, - Available: avail, - AvailableProof: availp, - Kind: kind, - KindProof: kindp, - } -} - -func NewHandshakeJSONState( - conn connection.Connection, connp ics23.Proof, - avail bool, availp ics23.Proof, - kind string, kindp ics23.Proof, - state byte, statep ics23.Proof, - cpclient string, cpclientp ics23.Proof, -) JSONState { - return JSONState{ - Connection: conn, - ConnectionProof: connp, - Available: avail, - AvailableProof: availp, - Kind: kind, - KindProof: kindp, - - State: state, - StateProof: statep, - CounterpartyClient: cpclient, - CounterpartyClientProof: cpclientp, - } -} diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index 9680c6da6c74..ddfa8926e4e1 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -2,6 +2,7 @@ package keeper import ( "errors" + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -33,6 +34,7 @@ func (k Keeper) ConnOpenInit( sdkerrors.Wrap(err, "cannot initialize connection") } + k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: NONE -> INIT", connectionID)) return nil } @@ -105,6 +107,7 @@ func (k Keeper) ConnOpenTry( } k.SetConnection(ctx, connectionID, connection) + k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: NONE -> TRYOPEN ", connectionID)) return nil } @@ -173,6 +176,7 @@ func (k Keeper) ConnOpenAck( connection.Versions = []string{version} k.SetConnection(ctx, connectionID, connection) + k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: INIT -> OPEN ", connectionID)) return nil } @@ -209,5 +213,6 @@ func (k Keeper) ConnOpenConfirm( connection.State = types.OPEN k.SetConnection(ctx, connectionID, connection) + k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: TRYOPEN -> OPEN ", connectionID)) return nil } From e3349470691d09c9f6c07f3caccda5fc2a15e7e7 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 11 Oct 2019 22:36:55 +0200 Subject: [PATCH 280/378] refactor: remove store accessors, update keeper and types to match spec (WIP) --- x/ibc/04-channel/codec.go | 20 -- x/ibc/04-channel/exported/exported.go | 20 ++ x/ibc/04-channel/handshake.go | 267 ---------------- x/ibc/04-channel/keeper/handshake.go | 345 +++++++++++++++++++++ x/ibc/04-channel/keeper/keeper.go | 92 ++++++ x/ibc/04-channel/keeper/packet.go | 123 ++++++++ x/ibc/04-channel/keeper/port.go | 26 ++ x/ibc/04-channel/keys.go | 5 - x/ibc/04-channel/manager.go | 256 --------------- x/ibc/04-channel/msgs.go | 164 ---------- x/ibc/04-channel/port.go | 49 --- x/ibc/04-channel/types.go | 42 --- x/ibc/04-channel/types/channel.go | 67 ++++ x/ibc/04-channel/types/codec.go | 21 ++ x/ibc/04-channel/types/errors.go | 10 + x/ibc/04-channel/{ => types}/events.go | 2 +- x/ibc/04-channel/types/expected_keepers.go | 11 + x/ibc/04-channel/types/keys.go | 66 ++++ x/ibc/04-channel/types/msgs.go | 195 ++++++++++++ x/ibc/04-channel/types/packet.go | 14 + x/ibc/04-channel/types/port.go | 30 ++ 21 files changed, 1021 insertions(+), 804 deletions(-) delete mode 100644 x/ibc/04-channel/codec.go create mode 100644 x/ibc/04-channel/exported/exported.go delete mode 100644 x/ibc/04-channel/handshake.go create mode 100644 x/ibc/04-channel/keeper/handshake.go create mode 100644 x/ibc/04-channel/keeper/keeper.go create mode 100644 x/ibc/04-channel/keeper/packet.go create mode 100644 x/ibc/04-channel/keeper/port.go delete mode 100644 x/ibc/04-channel/keys.go delete mode 100644 x/ibc/04-channel/manager.go delete mode 100644 x/ibc/04-channel/msgs.go delete mode 100644 x/ibc/04-channel/port.go delete mode 100644 x/ibc/04-channel/types.go create mode 100644 x/ibc/04-channel/types/channel.go create mode 100644 x/ibc/04-channel/types/codec.go create mode 100644 x/ibc/04-channel/types/errors.go rename x/ibc/04-channel/{ => types}/events.go (93%) create mode 100644 x/ibc/04-channel/types/expected_keepers.go create mode 100644 x/ibc/04-channel/types/keys.go create mode 100644 x/ibc/04-channel/types/msgs.go create mode 100644 x/ibc/04-channel/types/packet.go create mode 100644 x/ibc/04-channel/types/port.go diff --git a/x/ibc/04-channel/codec.go b/x/ibc/04-channel/codec.go deleted file mode 100644 index 38654da4e6a9..000000000000 --- a/x/ibc/04-channel/codec.go +++ /dev/null @@ -1,20 +0,0 @@ -package channel - -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/exported/exported.go b/x/ibc/04-channel/exported/exported.go new file mode 100644 index 000000000000..0c691547da5f --- /dev/null +++ b/x/ibc/04-channel/exported/exported.go @@ -0,0 +1,20 @@ +package exported + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type PacketI interface { + Sequence() uint64 + TimeoutHeight() uint64 + SourcePort() string + SourceChannel() string + DestPort() string + DestChannel() string + Data() []byte + + // Non ICS04 interface functions + Type() string + ValidateBasic() sdk.Error + Marshal() []byte // Should exclude PortID/ChannelID info +} diff --git a/x/ibc/04-channel/handshake.go b/x/ibc/04-channel/handshake.go deleted file mode 100644 index 23f34d16eec5..000000000000 --- a/x/ibc/04-channel/handshake.go +++ /dev/null @@ -1,267 +0,0 @@ -package channel - -import ( - "errors" - - "github.com/cosmos/cosmos-sdk/store/state" - sdk "github.com/cosmos/cosmos-sdk/types" - - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -type Stage = byte - -const ( - Idle Stage = iota - Init - OpenTry - Open - CloseTry - Closed -) - -type Handshaker struct { - Manager - - counterParty CounterpartyHandshaker -} - -func (man Handshaker) Kind() string { - return "handshake" -} - -func NewHandshaker(man Manager) Handshaker { - return Handshaker{ - Manager: man, - counterParty: CounterpartyHandshaker{man.counterParty}, - } -} - -type CounterpartyHandshaker struct { - man CounterpartyManager -} - -type HandshakeState struct { - State - - Stage state.Enum - - counterParty CounterHandshakeState -} - -type CounterHandshakeState struct { - CounterState - - Stage commitment.Enum -} - -// CONTRACT: client and remote must be filled by the caller -func (man Handshaker) createState(parent State) HandshakeState { - prefix := parent.portId + "/channels/" + parent.chanId - - return HandshakeState{ - State: parent, - Stage: man.protocol.Value([]byte(prefix + "/state")).Enum(), - counterParty: man.counterParty.createState(parent.counterParty), - } -} - -func (man CounterpartyHandshaker) createState(parent CounterState) CounterHandshakeState { - prefix := parent.portId + "/channels/" + parent.chanId - - 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 HandshakeState, err error) { - cobj, err := man.Manager.create(ctx, portid, chanid, channel) - if err != nil { - return - } - obj = man.createState(cobj) - - return obj, nil -} - -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.createState(cobj) - - return obj, nil -} - -/* -func (obj HandshakeState) remove(ctx sdk.Context) { - obj.Stage.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, - 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 HandshakeState{}, errors.New("ConnectionHops length must be 1") - } - - obj, err := man.create(ctx, portid, chanid, channel) - if err != nil { - return HandshakeState{}, err - } - - obj.Stage.Set(ctx, Init) - - return obj, nil -} - -// Using proofs: counterParty.{channel,state} -func (man Handshaker) OpenTry(ctx sdk.Context, - proofs []commitment.Proof, height uint64, - portid, chanid string, channel Channel, -) (obj HandshakeState, err error) { - if len(channel.ConnectionHops) != 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, height) - if err != nil { - return - } - - if !obj.counterParty.Stage.Is(ctx, Init) { - err = errors.New("counterParty state not init") - return - } - - if !obj.counterParty.Channel.Is(ctx, Channel{ - Counterparty: chanid, - CounterpartyPort: portid, - ConnectionHops: []string{obj.Connections[0].GetConnection(ctx).Counterparty}, - }) { - err = errors.New("wrong counterParty connection") - return - } - - // 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.Stage.Set(ctx, OpenTry) - - return -} - -// Using proofs: counterParty.{handshake,state,nextTimeout,clientid,client} -func (man Handshaker) OpenAck(ctx sdk.Context, - 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, height) - if err != nil { - return - } - - if !obj.Stage.Transit(ctx, Init, Open) { - err = errors.New("ack on non-init connection") - return - } - - if !obj.counterParty.Channel.Is(ctx, Channel{ - Counterparty: chanid, - CounterpartyPort: portid, - ConnectionHops: []string{obj.Connections[0].GetConnection(ctx).Counterparty}, - }) { - err = errors.New("wrong counterParty") - return - } - - if !obj.counterParty.Stage.Is(ctx, OpenTry) { - err = errors.New("counterParty state not opentry") - return - } - - // TODO: commented out, implement in v1 - /* - var expected client.ConsensusState - obj.self.Get(ctx, expheight, &expected) - if !obj.counterParty.client.Is(ctx, expected) { - return errors.New("unexpected counterParty client value") - } - */ - - obj.Available.Set(ctx, true) - - return -} - -// Using proofs: counterParty.{connection,state, nextTimeout} -func (man Handshaker) OpenConfirm(ctx sdk.Context, - 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, height) - if err != nil { - return - } - - if !obj.Stage.Transit(ctx, OpenTry, Open) { - err = errors.New("confirm on non-try connection") - return - } - - if !obj.counterParty.Stage.Is(ctx, Open) { - err = errors.New("counterParty state not open") - return - } - - obj.Available.Set(ctx, true) - - return -} - -// TODO -/* -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") - } - - obj.NextTimeout.Set(ctx, nextTimeout) - - return nil -} -*/ diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go new file mode 100644 index 000000000000..000ce4bd5452 --- /dev/null +++ b/x/ibc/04-channel/keeper/handshake.go @@ -0,0 +1,345 @@ +package keeper + +import ( + "errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + ics03types "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +// ChanOpenInit is called by a module to initiate a channel opening handshake with +// a module on another chain. +func (k Keeper) ChanOpenInit( + ctx sdk.Context, + order types.ChannelOrder, + connectionHops []string, + portID, + channelID string, + counterparty types.Counterparty, + version string, +) (string, error) { + // TODO: abortTransactionUnless(validateChannelIdentifier(portIdentifier, channelIdentifier)) + if len(connectionHops) != 1 { + return "", errors.New("connection hops length must be 1") // TODO: sdk.Error + } + + _, found := k.GetChannel(ctx, portID, channelID) + if found { + return "", errors.New("channel already exists") // TODO: sdk.Error + } + + connection, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) + if !found { + return "", errors.New("connection not found") // TODO: ics03 sdk.Error + } + + // TODO: inconsistency on ICS03 (`none`) and ICS04 (`CLOSED`) + if connection.State == ics03types.NONE { + return "", errors.New("connection is closed") + } + + // TODO: Blocked - ICS05 Not implemented yet + // port, found := k.portKeeper.GetPort(ctx, portID) + // if !found { + // return errors.New("port not found") // TODO: ics05 sdk.Error + // } + + // if !k.portKeeper.AuthenticatePort(port.ID()) { + // return errors.New("port is not valid") // TODO: ics05 sdk.Error + // } + + channel := types.NewChannel(types.INIT, order, counterparty, connectionHops, version) + k.SetChannel(ctx, portID, channelID, channel) + + key := "" // TODO: generate key + k.SetChannelCapability(ctx, portID, channelID, key) + k.SetNextSequenceSend(ctx, portID, channelID, 1) + k.SetNextSequenceRecv(ctx, portID, channelID, 1) + + return key, nil +} + +// ChanOpenTry is called by a module to accept the first step of a channel opening +// handshake initiated by a module on another chain. +func (k Keeper) ChanOpenTry( + ctx sdk.Context, + order types.ChannelOrder, + connectionHops []string, + portID, + channelID string, + counterparty types.Counterparty, + version, + counterpartyVersion string, + proofInit ics23.Proof, + proofHeight uint64, +) (string, error) { + + if len(connectionHops) != 1 { + return "", errors.New("ConnectionHops length must be 1") + } + + _, found := k.GetChannel(ctx, portID, channelID) + if found { + return "", errors.New("channel already exists") // TODO: sdk.Error + } + + // TODO: Blocked - ICS05 Not implemented yet + // port, found := k.portKeeper.GetPort(ctx, portID) + // if !found { + // return errors.New("port not found") // TODO: ics05 sdk.Error + // } + + // if !k.portKeeper.AuthenticatePort(port.ID()) { + // return errors.New("port is not valid") // TODO: ics05 sdk.Error + // } + + connection, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) + if !found { + return "", errors.New("connection not found") // TODO: ics03 sdk.Error + } + + if connection.State != ics03types.OPEN { + return "", errors.New("connection is not open") + } + + // NOTE: this step has been switched with the one below to reverse the connection + // hops + channel := types.NewChannel(types.OPENTRY, order, counterparty, connectionHops, version) + + // TODO: + // if !connection.verifyMembership( + // proofHeight, + // proofInit, + // channelPath(counterpartyPortIdentifier, counterpartyChannelIdentifier), + // Channel{INIT, order, portIdentifier, + // channelIdentifier, channel.CounterpartyHops(), counterpartyVersion} + // ) { + // return err + // } + + k.SetChannel(ctx, portID, channelID, channel) + + key := "" // TODO: generate key + k.SetChannelCapability(ctx, portID, channelID, key) + k.SetNextSequenceSend(ctx, portID, channelID, 1) + k.SetNextSequenceRecv(ctx, portID, channelID, 1) + + return key, nil +} + +// ChanOpenAck is called by the handshake-originating module to acknowledge the +// acceptance of the initial request by the counterparty module on the other chain. +func (k Keeper) ChanOpenAck( + ctx sdk.Context, + portID, + channelID, + counterpartyVersion string, + proofTry ics23.Proof, + proofHeight uint64, +) error { + + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return errors.New("channel not found") // TODO: sdk.Error + } + + if channel.State != types.INIT { + return errors.New("invalid channel state") // TODO: sdk.Error + } + + _, found = k.GetChannelCapability(ctx, portID, channelID) + if !found { + return errors.New("channel capability key not found") // TODO: sdk.Error + } + + // if !AuthenticateCapabilityKey(capabilityKey) { + // return errors.New("invalid capability key") // TODO: sdk.Error + // } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return errors.New("connection not found") // TODO: ics03 sdk.Error + } + + if connection.State != ics03types.OPEN { + return errors.New("connection is not open") + } + + // TODO: + // if !connection.verifyMembership( + // proofHeight, + // proofInit, + // channelPath(counterpartyPortIdentifier, counterpartyChannelIdentifier), + // Channel{INIT, order, portIdentifier, + // channelIdentifier, channel.CounterpartyHops(), counterpartyVersion} + // ) { + // return err + // } + + channel.State = types.OPEN + channel.Version = counterpartyVersion + k.SetChannel(ctx, portID, channelID, channel) + + return nil +} + +// ChanOpenConfirm is called by the counterparty module to close their end of the +// channel, since the other end has been closed. +func (k Keeper) ChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, + proofAck ics23.Proof, + proofHeight uint64, +) error { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return errors.New("channel not found") // TODO: sdk.Error + } + + if channel.State != types.OPENTRY { + return errors.New("invalid channel state") // TODO: sdk.Error + } + + _, found = k.GetChannelCapability(ctx, portID, channelID) + if !found { + return errors.New("channel capability key not found") // TODO: sdk.Error + } + + // if !AuthenticateCapabilityKey(capabilityKey) { + // return errors.New("invalid capability key") // TODO: sdk.Error + // } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return errors.New("connection not found") // TODO: ics03 sdk.Error + } + + if connection.State != ics03types.OPEN { + return errors.New("connection is not open") + } + + // TODO: + // if !connection.verifyMembership( + // proofHeight, + // proofAck, + // channelPath(channel.counterpartyPortIdentifier, channel.counterpartyChannelIdentifier), + // Channel{OPEN, channel.order, portIdentifier, + // channelIdentifier, channel.CounterpartyHops(), channel.version} + // ) { + // return err + // } + + channel.State = types.OPEN + k.SetChannel(ctx, portID, channelID, channel) + + return nil +} + +// Closing Handshake +// +// This section defines the set of functions required to close a channel handshake +// as defined in https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#closing-handshake + +// ChanCloseInit is called by either module to close their end of the channel. Once +// closed, channels cannot be reopened. +func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error { + _, found := k.GetChannelCapability(ctx, portID, channelID) + if !found { + return errors.New("channel capability key not found") // TODO: sdk.Error + } + + // if !AuthenticateCapabilityKey(capabilityKey) { + // return errors.New("invalid capability key") // TODO: sdk.Error + // } + + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return errors.New("channel not found") // TODO: sdk.Error + } + + if channel.State == types.CLOSED { + return errors.New("channel already closed") // TODO: sdk.Error + } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return errors.New("connection not found") // TODO: ics03 sdk.Error + } + + if connection.State != ics03types.OPEN { + return errors.New("connection is not open") + } + + channel.State = types.CLOSED + k.SetChannel(ctx, portID, channelID, channel) + + return nil +} + +// ChanCloseConfirm is called by the counterparty module to close their end of the +// channel, since the other end has been closed. +func (k Keeper) ChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, + proofInit ics23.Proof, + proofHeight uint64, +) error { + _, found := k.GetChannelCapability(ctx, portID, channelID) + if !found { + return errors.New("channel capability key not found") // TODO: sdk.Error + } + + // if !AuthenticateCapabilityKey(capabilityKey) { + // return errors.New("invalid capability key") // TODO: sdk.Error + // } + + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return errors.New("channel not found") // TODO: sdk.Error + } + + if channel.State == types.CLOSED { + return errors.New("channel already closed") // TODO: sdk.Error + } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return errors.New("connection not found") // TODO: ics03 sdk.Error + } + + if connection.State != ics03types.OPEN { + return errors.New("connection is not open") + } + + // counterparty := types.NewCounterparty(portID, channelID) + // expectedChannel := types.NewChannel( + // types.CLOSED, channel.Ordering, counterparty, + // channel.CounterpartyHops(), channel.Version, + // ) + + // if !connection.verifyMembership( + // proofHeight, + // proofInit, + // channelPath(channel.counterpartyPortIdentifier, channel.counterpartyChannelIdentifier), + // expectedChannel + // ) { + + // } + + channel.State = types.CLOSED + k.SetChannel(ctx, portID, channelID, channel) + + return nil +} + +func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { + if uint64(ctx.BlockHeight()) > timeoutHeight { + return errors.New("timeout") + } + + return nil +} diff --git a/x/ibc/04-channel/keeper/keeper.go b/x/ibc/04-channel/keeper/keeper.go new file mode 100644 index 000000000000..a4a4f6c12c27 --- /dev/null +++ b/x/ibc/04-channel/keeper/keeper.go @@ -0,0 +1,92 @@ +package keeper + +import ( + "fmt" + + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// Keeper defines the IBC channel keeper +type Keeper struct { + storeKey sdk.StoreKey + cdc *codec.Codec + codespace sdk.CodespaceType + prefix []byte // prefix bytes for accessing the store + + connectionKeeper types.ConnectionKeeper + // TODO: portKeeper +} + +// NewKeeper creates a new IBC channel Keeper instance +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType, ck types.ConnectionKeeper) Keeper { + return Keeper{ + storeKey: key, + cdc: cdc, + codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/channel", + prefix: []byte(types.SubModuleName + "/"), // "channel/" + connectionKeeper: ck, + } +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName)) +} + +// GetChannel returns a channel with a particular identifier binded to a specific port +func (k Keeper) GetChannel(ctx sdk.Context, portID, channelID string) (types.Channel, bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(types.KeyChannel(portID, channelID)) + if bz == nil { + return types.Channel{}, false + } + + var channel types.Channel + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &channel) + return channel, true +} + +// SetChannel sets a channel to the store +func (k Keeper) SetChannel(ctx sdk.Context, portID, channelID string, channel types.Channel) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(channel) + store.Set(types.KeyChannel(portID, channelID), bz) +} + +// GetChannelCapability gets a channel's capability key from the store +func (k Keeper) GetChannelCapability(ctx sdk.Context, portID, channelID string) (string, bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(types.KeyChannelCapabilityPath(portID, channelID)) + if bz == nil { + return "", false + } + + return string(bz), true +} + +// SetChannelCapability sets a channel's capability key to the store +// TODO: is the key a string ? +func (k Keeper) SetChannelCapability(ctx sdk.Context, portID, channelID string, key string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + store.Set(types.KeyChannelCapabilityPath(portID, channelID), []byte(key)) +} + +// SetNextSequenceSend sets a channel's next send sequence to the store +func (k Keeper) SetNextSequenceSend(ctx sdk.Context, portID, channelID string, sequence uint64) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := sdk.Uint64ToBigEndian(sequence) + store.Set(types.KeyNextSequenceSend(portID, channelID), bz) +} + +// SetNextSequenceRecv sets a channel's next receive sequence to the store +func (k Keeper) SetNextSequenceRecv(ctx sdk.Context, portID, channelID string, sequence uint64) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := sdk.Uint64ToBigEndian(sequence) + store.Set(types.KeyNextSequenceRecv(portID, channelID), bz) +} diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go new file mode 100644 index 000000000000..92f94f05c823 --- /dev/null +++ b/x/ibc/04-channel/keeper/packet.go @@ -0,0 +1,123 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +// function sendPacket(packet: Packet) { +// channel = provableStore.get(channelPath(packet.sourcePort, packet.sourceChannel)) + +// // optimistic sends are permitted once the handshake has started +// abortTransactionUnless(channel !== null) +// abortTransactionUnless(channel.state !== CLOSED) +// abortTransactionUnless(authenticate(privateStore.get(channelCapabilityPath(packet.sourcePort, packet.sourceChannel)))) +// abortTransactionUnless(packet.destPort === channel.counterpartyPortIdentifier) +// abortTransactionUnless(packet.destChannel === channel.counterpartyChannelIdentifier) +// connection = provableStore.get(connectionPath(channel.connectionHops[0])) + +// abortTransactionUnless(connection !== null) +// abortTransactionUnless(connection.state !== CLOSED) + +// consensusState = provableStore.get(consensusStatePath(connection.clientIdentifier)) +// abortTransactionUnless(consensusState.getHeight() < packet.timeoutHeight) + +// nextSequenceSend = provableStore.get(nextSequenceSendPath(packet.sourcePort, packet.sourceChannel)) +// abortTransactionUnless(packet.sequence === nextSequenceSend) + +// // all assertions passed, we can alter state + +// nextSequenceSend = nextSequenceSend + 1 +// provableStore.set(nextSequenceSendPath(packet.sourcePort, packet.sourceChannel), nextSequenceSend) +// provableStore.set(packetCommitmentPath(packet.sourcePort, packet.sourceChannel, packet.sequence), hash(packet.data)) +// } + +// function recvPacket( +// packet: OpaquePacket, +// proof: CommitmentProof, +// proofHeight: uint64, +// acknowledgement: bytes): Packet { + +// channel = provableStore.get(channelPath(packet.destPort, packet.destChannel)) +// abortTransactionUnless(channel !== null) +// abortTransactionUnless(channel.state === OPEN) +// abortTransactionUnless(authenticate(privateStore.get(channelCapabilityPath(packet.destPort, packet.destChannel)))) +// abortTransactionUnless(packet.sourcePort === channel.counterpartyPortIdentifier) +// abortTransactionUnless(packet.sourceChannel === channel.counterpartyChannelIdentifier) + +// connection = provableStore.get(connectionPath(channel.connectionHops[0])) +// abortTransactionUnless(connection !== null) +// abortTransactionUnless(connection.state === OPEN) + +// abortTransactionUnless(getConsensusHeight() < packet.timeoutHeight) + +// abortTransactionUnless(connection.verifyMembership( +// proofHeight, +// proof, +// packetCommitmentPath(packet.sourcePort, packet.sourceChannel, packet.sequence), +// hash(packet.data) +// )) + +// // all assertions passed (except sequence check), we can alter state + +// if (acknowledgement.length > 0 || channel.order === UNORDERED) +// provableStore.set( +// packetAcknowledgementPath(packet.destPort, packet.destChannel, packet.sequence), +// hash(acknowledgement) +// ) + +// if (channel.order === ORDERED) { +// nextSequenceRecv = provableStore.get(nextSequenceRecvPath(packet.destPort, packet.destChannel)) +// abortTransactionUnless(packet.sequence === nextSequenceRecv) +// nextSequenceRecv = nextSequenceRecv + 1 +// provableStore.set(nextSequenceRecvPath(packet.destPort, packet.destChannel), nextSequenceRecv) +// } + +// // return transparent packet +// return packet +// } + +func (k Keeper) SendPacket(ctx sdk.Context, channelID string, packet exported.Packet) error { + // obj, err := man.Query(ctx, packet.SenderPort(), chanId) + // if err != nil { + // return err + // } + + // if obj.OriginConnection().Client.GetConsensusState(ctx).GetHeight() >= packet.Timeout() { + // return errors.New("timeout height higher than the latest known") + // } + + // obj.Packets.SetRaw(ctx, obj.SeqSend.Increment(ctx), packet.Marshal()) + + return nil +} + +func (k Keeper) RecvPacket(ctx sdk.Context, proofs []ics23.Proof, height uint64, portID, channelID string, packet exported.Packet) error { + // obj, err := man.Query(ctx, portid, chanid) + // if err != nil { + // return err + // } + + // /* + // if !obj.Receivable(ctx) { + // return errors.New("cannot receive Packets on this channel") + // } + // */ + + // ctx, err = obj.Context(ctx, proofs, height) + // if err != nil { + // return err + // } + + // err = assertTimeout(ctx, packet.Timeout()) + // if err != nil { + // return err + // } + + // if !obj.counterParty.Packets.Value(obj.SeqRecv.Increment(ctx)).IsRaw(ctx, packet.Marshal()) { + // return errors.New("verification failed") + // } + + return nil +} diff --git a/x/ibc/04-channel/keeper/port.go b/x/ibc/04-channel/keeper/port.go new file mode 100644 index 000000000000..ea99daf3af0a --- /dev/null +++ b/x/ibc/04-channel/keeper/port.go @@ -0,0 +1,26 @@ +package keeper + +import ( + "errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +func (k Keeper) Send(ctx sdk.Context, channelID string, packet exported.Packet, port types.Port) error { + 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, channelID, packet) +} + +func (k Keeper) Receive(ctx sdk.Context, proof []ics23.Proof, height uint64, channelID string, packet exported.Packet, port types.Port) error { + return port.channel.Receive(ctx, proof, height, port.ID(), channelID, packet) +} diff --git a/x/ibc/04-channel/keys.go b/x/ibc/04-channel/keys.go deleted file mode 100644 index 383187d33c44..000000000000 --- a/x/ibc/04-channel/keys.go +++ /dev/null @@ -1,5 +0,0 @@ -package channel - -func LocalRoot() []byte { - return []byte("ports/") -} diff --git a/x/ibc/04-channel/manager.go b/x/ibc/04-channel/manager.go deleted file mode 100644 index 7bd358152303..000000000000 --- a/x/ibc/04-channel/manager.go +++ /dev/null @@ -1,256 +0,0 @@ -package channel - -import ( - "errors" - "strconv" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/state" - sdk "github.com/cosmos/cosmos-sdk/types" - - connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -// Manager is unrestricted -type Manager struct { - protocol state.Mapping - - connection connection.Manager - - counterParty CounterpartyManager - - ports map[string]struct{} -} - -type CounterpartyManager struct { - protocol commitment.Mapping - - connection connection.CounterpartyManager -} - -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{}), - } -} - -func NewCounterpartyManager(cdc *codec.Codec) CounterpartyManager { - protocol := commitment.NewMapping(cdc, nil) - - return CounterpartyManager{ - protocol: protocol.Prefix(LocalRoot()), - connection: connection.NewCounterpartyManager(cdc), - } -} - -// 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), - } -} - -func (man CounterpartyManager) object(portid, chanid string) CounterState { - key := portid + "/channels/" + chanid - 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), - } -} - -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) - - for _, hop := range channel.ConnectionHops { - connobj, err := man.connection.Query(ctx, hop) - if err != nil { - return obj, err - } - obj.Connections = append(obj.Connections, connobj) - } - - for _, hop := range channel.CounterpartyHops() { - 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 State, err error) { - obj = man.object(portid, chanid) - if !obj.exists(ctx) { - err = errors.New("channel not exists for the provided id") - return - } - - channel := obj.GetChannel(ctx) - obj.counterParty = man.counterParty.object(channel.CounterpartyPort, channel.Counterparty) - for _, hop := range channel.ConnectionHops { - connobj, err := man.connection.Query(ctx, hop) - if err != nil { - return obj, err - } - obj.Connections = append(obj.Connections, connobj) - } - - for _, hop := range channel.CounterpartyHops() { - 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 State, err error) { - obj, err = man.query(ctx, portid, chanid) - if !obj.Available.Get(ctx) { - err = errors.New("channel not available") - return - } - return -} - -type State struct { - chanId string - portId string - - Channel state.Value - - SeqSend state.Integer - SeqRecv state.Integer - Packets state.Indexer - - Available state.Boolean - - Connections []connection.State - - counterParty CounterState -} - -type CounterState struct { - chanId string - portId string - - Channel commitment.Value - - SeqSend commitment.Integer - SeqRecv commitment.Integer - Packets commitment.Indexer - - Available commitment.Boolean - - Connections []connection.CounterState -} - -func (obj State) OriginConnection() connection.State { - return obj.Connections[0] -} - -func (obj State) Context(ctx sdk.Context, proofs []commitment.Proof, height uint64) (sdk.Context, error) { - return obj.OriginConnection().Context(ctx, height, proofs) -} - -func (obj State) ChanID() string { - return obj.chanId -} - -func (obj State) GetChannel(ctx sdk.Context) (res Channel) { - obj.Channel.Get(ctx, &res) - return -} - -func (obj State) PacketCommit(ctx sdk.Context, index uint64) []byte { - return obj.Packets.Value(index).GetRaw(ctx) -} - -/* -func (obj Stage) Sendable(ctx sdk.Context) bool { - return obj.connection -} - -func (obj Stage) Receivable(ctx sdk.Context) bool { - return kinds[obj.kind.Get(ctx)].Receivable -} -*/ -func (obj State) exists(ctx sdk.Context) bool { - return obj.Channel.Exists(ctx) -} - -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 - } - - if obj.OriginConnection().Client.GetConsensusState(ctx).GetHeight() >= packet.Timeout() { - return errors.New("timeout height higher than the latest known") - } - - 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, height uint64, portid, chanid string, packet Packet) error { - obj, err := man.Query(ctx, portid, chanid) - if err != nil { - return err - } - - /* - if !obj.Receivable(ctx) { - return errors.New("cannot receive Packets on this channel") - } - */ - - ctx, err = obj.Context(ctx, proofs, height) - if err != nil { - return err - } - - err = assertTimeout(ctx, packet.Timeout()) - if err != nil { - return err - } - - if !obj.counterParty.Packets.Value(obj.SeqRecv.Increment(ctx)).IsRaw(ctx, packet.Marshal()) { - return errors.New("verification failed") - } - - return nil -} diff --git a/x/ibc/04-channel/msgs.go b/x/ibc/04-channel/msgs.go deleted file mode 100644 index 3fba21f320b4..000000000000 --- a/x/ibc/04-channel/msgs.go +++ /dev/null @@ -1,164 +0,0 @@ -package channel - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -const Route = "ibc" - -type MsgOpenInit struct { - PortID string `json:"port_id"` - ChannelID string `json:"channel_id"` - Channel Channel `json:"channel"` - Signer sdk.AccAddress `json:"signer"` -} - -var _ sdk.Msg = MsgOpenInit{} - -func (msg MsgOpenInit) Route() string { - return Route -} - -func (msg MsgOpenInit) Type() string { - return "open-init" -} - -func (msg MsgOpenInit) ValidateBasic() sdk.Error { - return nil // TODO -} - -func (msg MsgOpenInit) GetSignBytes() []byte { - return sdk.MustSortJSON(msgCdc.MustMarshalJSON(msg)) -} - -func (msg MsgOpenInit) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} - -type MsgOpenTry struct { - 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{} - -func (msg MsgOpenTry) Route() string { - return Route -} - -func (msg MsgOpenTry) Type() string { - return "open-try" -} - -func (msg MsgOpenTry) ValidateBasic() sdk.Error { - return nil // TODO -} - -func (msg MsgOpenTry) GetSignBytes() []byte { - return sdk.MustSortJSON(msgCdc.MustMarshalJSON(msg)) -} - -func (msg MsgOpenTry) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} - -type MsgOpenAck struct { - 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{} - -func (msg MsgOpenAck) Route() string { - return Route -} - -func (msg MsgOpenAck) Type() string { - return "open-ack" -} - -func (msg MsgOpenAck) ValidateBasic() sdk.Error { - return nil // TODO -} - -func (msg MsgOpenAck) GetSignBytes() []byte { - return sdk.MustSortJSON(msgCdc.MustMarshalJSON(msg)) -} - -func (msg MsgOpenAck) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} - -type MsgOpenConfirm struct { - 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{} - -func (msg MsgOpenConfirm) Route() string { - return Route -} - -func (msg MsgOpenConfirm) Type() string { - return "open-confirm" -} - -func (msg MsgOpenConfirm) ValidateBasic() sdk.Error { - return nil // TODO -} - -func (msg MsgOpenConfirm) GetSignBytes() []byte { - return sdk.MustSortJSON(msgCdc.MustMarshalJSON(msg)) -} - -func (msg MsgOpenConfirm) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} - -// 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 = MsgPacket{} - -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 MsgPacket) Route() string { - return msg.ReceiverPort() -} - -func (msg MsgPacket) GetSignBytes() []byte { - return sdk.MustSortJSON(msgCdc.MustMarshalJSON(msg)) -} - -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 deleted file mode 100644 index 033b932e0e7a..000000000000 --- a/x/ibc/04-channel/port.go +++ /dev/null @@ -1,49 +0,0 @@ -package channel - -import ( - "errors" - - sdk "github.com/cosmos/cosmos-sdk/types" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -type Port struct { - channel Manager - id string -} - -// bindPort, expected to be called only at init time -// TODO: is it safe to support runtime bindPort? -func (man Manager) Port(id string) Port { - if _, ok := man.ports[id]; ok { - panic("port already occupied") - } - man.ports[id] = struct{}{} - return Port{man, id} -} - -// releasePort -func (port Port) Release() { - delete(port.channel.ports, port.id) -} - -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 { - 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, 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/types.go b/x/ibc/04-channel/types.go deleted file mode 100644 index 43688edaa92f..000000000000 --- a/x/ibc/04-channel/types.go +++ /dev/null @@ -1,42 +0,0 @@ -package channel - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -/* -type Packet struct { - Sequence uint64 - TimeoutHeight uint64 - - SourceConnection string - SourceChannel string - DestConnection string - DestChannel string - - Data []byte -} -*/ - -type Packet interface { - SenderPort() string - ReceiverPort() string // == Route() - Type() string - ValidateBasic() sdk.Error - Timeout() uint64 - Marshal() []byte // Should exclude PortID/ChannelID info -} - -type Channel struct { - Counterparty string - CounterpartyPort string - ConnectionHops []string -} - -func (ch Channel) CounterpartyHops() (res []string) { - res = make([]string, len(ch.ConnectionHops)) - for i, hop := range ch.ConnectionHops { - res[len(res)-(i+1)] = hop - } - return -} diff --git a/x/ibc/04-channel/types/channel.go b/x/ibc/04-channel/types/channel.go new file mode 100644 index 000000000000..3c56f6cecef6 --- /dev/null +++ b/x/ibc/04-channel/types/channel.go @@ -0,0 +1,67 @@ +package types + +// ChannelOrder defines if a channel is ORDERED or UNORDERED +type ChannelOrder byte + +// channel order types +const ( + UNORDERED ChannelOrder = iota // packets can be delivered in any order, which may differ from the order in which they were sent. + ORDERED // packets are delivered exactly in the order which they were sent +) + +// ChannelState defines if a channel is in one of the following states: +// CLOSED, INIT, OPENTRY or OPEN +type ChannelState byte + +// channel state types +const ( + CLOSED ChannelState = iota // A channel end has been closed and can no longer be used to send or receive packets. + INIT // A channel end has just started the opening handshake. + OPENTRY // A channel end has acknowledged the handshake step on the counterparty chain. + OPEN // A channel end has completed the handshake and is ready to send and receive packets. +) + +type Channel struct { + State ChannelState `json:"state" yaml:"state"` + Ordering ChannelOrder `json:"ordering" yaml:"ordering"` + Counterparty Counterparty `json:"counterparty" yaml:"counterparty"` + ConnectionHops []string `json:"connection_hops" yaml:"connection_hops"` + Version string `json:"version" yaml:"version "` +} + +// NewChannel creates a new Channel instance +func NewChannel( + state ChannelState, ordering ChannelOrder, counterparty Counterparty, + hops []string, version string, +) Channel { + return Channel{ + State: state, + Ordering: ordering, + Counterparty: counterparty, + ConnectionHops: hops, + Version: version, + } +} + +// CounterpartyHops returns the connection hops of the counterparty channel. +// The counterparty hops are stored in the inverse order as the channel's. +func (ch Channel) CounterpartyHops() []string { + counterPartyHops := make([]string, len(ch.ConnectionHops)) + for i, hop := range ch.ConnectionHops { + counterPartyHops[len(counterPartyHops)-1-i] = hop + } + return counterPartyHops +} + +type Counterparty struct { + PortID string `json:"port_id" yaml:"port_id"` + ChannelID string `json:"channel_id" yaml:"channel_id"` +} + +// NewCounterparty returns a new Counterparty instance +func NewCounterparty(portID, channelID string) Counterparty { + return Counterparty{ + PortID: portID, + ChannelID: channelID, + } +} diff --git a/x/ibc/04-channel/types/codec.go b/x/ibc/04-channel/types/codec.go new file mode 100644 index 000000000000..d0c98e2e71e4 --- /dev/null +++ b/x/ibc/04-channel/types/codec.go @@ -0,0 +1,21 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" +) + +var SubModuleCdc *codec.Codec + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*exported.PacketI)(nil), nil) + + cdc.RegisterConcrete(MsgChanOpenInit{}, "ibc/channel/MsgChanOpenInit", nil) + cdc.RegisterConcrete(MsgChanOpenTry{}, "ibc/channel/MsgChanOpenTry", nil) + cdc.RegisterConcrete(MsgChanOpenAck{}, "ibc/channel/MsgChanOpenAck", nil) + cdc.RegisterConcrete(MsgChanOpenConfirm{}, "ibc/channel/MsgChanOpenConfirm", nil) +} + +func SetMsgChanCodec(cdc *codec.Codec) { + SubModuleCdc = cdc +} diff --git a/x/ibc/04-channel/types/errors.go b/x/ibc/04-channel/types/errors.go new file mode 100644 index 000000000000..a1cefd783c40 --- /dev/null +++ b/x/ibc/04-channel/types/errors.go @@ -0,0 +1,10 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// connection error codes +const ( + DefaultCodespace sdk.CodespaceType = SubModuleName +) diff --git a/x/ibc/04-channel/events.go b/x/ibc/04-channel/types/events.go similarity index 93% rename from x/ibc/04-channel/events.go rename to x/ibc/04-channel/types/events.go index f9097af6a3b7..96de0272b2bc 100644 --- a/x/ibc/04-channel/events.go +++ b/x/ibc/04-channel/types/events.go @@ -1,4 +1,4 @@ -package channel +package types const ( EventTypeSendPacket = "send_packet" diff --git a/x/ibc/04-channel/types/expected_keepers.go b/x/ibc/04-channel/types/expected_keepers.go new file mode 100644 index 000000000000..0c35ba5d9f84 --- /dev/null +++ b/x/ibc/04-channel/types/expected_keepers.go @@ -0,0 +1,11 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + ics03types "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" +) + +// ConnectionKeeper expected account IBC connection keeper +type ConnectionKeeper interface { + GetConnection(ctx sdk.Context, connectionID string) (ics03types.ConnectionEnd, bool) +} diff --git a/x/ibc/04-channel/types/keys.go b/x/ibc/04-channel/types/keys.go new file mode 100644 index 000000000000..cef8e0364434 --- /dev/null +++ b/x/ibc/04-channel/types/keys.go @@ -0,0 +1,66 @@ +package types + +import ( + "fmt" +) + +const ( + // SubModuleName defines the IBC channels name + SubModuleName = "channels" // TODO: why was this "ports" beforehand + + // StoreKey is the store key string for IBC channels + StoreKey = SubModuleName + + // RouterKey is the message route for IBC channels + RouterKey = SubModuleName + + // QuerierRoute is the querier route for IBC channels + QuerierRoute = SubModuleName +) + +func channelPath(portID string, channelID string) string { + return fmt.Sprintf("ports/%s/channels/%s", portID, channelID) +} + +func channelCapabilityPath(portID string, channelID string) string { + return fmt.Sprintf("%s/key", channelPath(portID, channelID)) +} + +func nextSequenceSendPath(portID string, channelID string) string { + return fmt.Sprintf("%s/nextSequenceSend", channelPath(portID, channelID)) +} + +func nextSequenceRecvPath(portID string, channelID string) string { + return fmt.Sprintf("%s/nextSequenceRecv", channelPath(portID, channelID)) +} + +func packetCommitmentPath(portID string, channelID string, sequence uint64) string { + return fmt.Sprintf("%s/packets/%d", channelPath(portID, channelID), sequence) +} + +func packetAcknowledgementPath(portID string, channelID string, sequence uint64) string { + return fmt.Sprintf("%s/acknowledgements/%d", channelPath(portID, channelID), sequence) +} + +// KeyChannel returns the store key for a particular channel +func KeyChannel(portID, channelID string) []byte { + return []byte(channelPath(portID, channelID)) +} + +// KeyChannelCapabilityPath returns the store key for the capability key of a +// particular channel binded to a specific port +func KeyChannelCapabilityPath(portID, channelID string) []byte { + return []byte(channelCapabilityPath(portID, channelID)) +} + +// KeyNextSequenceSend returns the store key the send sequence of a particular +// channel binded to a specific port +func KeyNextSequenceSend(portID, channelID string) []byte { + return []byte(nextSequenceSendPath(portID, channelID)) +} + +// KeyNextSequenceRecv returns the store key the receive sequence of a particular +// channel binded to a specific port +func KeyNextSequenceRecv(portID, channelID string) []byte { + return []byte(nextSequenceRecvPath(portID, channelID)) +} diff --git a/x/ibc/04-channel/types/msgs.go b/x/ibc/04-channel/types/msgs.go new file mode 100644 index 000000000000..fe5f994b9d4e --- /dev/null +++ b/x/ibc/04-channel/types/msgs.go @@ -0,0 +1,195 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +var _ sdk.Msg = MsgChanOpenInit{} + +type MsgChanOpenInit struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Channel Channel `json:"channel"` + Signer sdk.AccAddress `json:"signer"` +} + +// Route implements sdk.Msg +func (msg MsgChanOpenInit) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgChanOpenInit) Type() string { + return "chan_open_init" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChanOpenInit) ValidateBasic() sdk.Error { + // TODO: + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgChanOpenInit) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgChanOpenInit) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgChanOpenTry{} + +type MsgChanOpenTry struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Channel Channel `json:"channel"` + Proofs []ics23.Proof `json:"proofs"` + Height uint64 `json:"height"` + Signer sdk.AccAddress `json:"signer"` +} + +// Route implements sdk.Msg +func (msg MsgChanOpenTry) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgChanOpenTry) Type() string { + return "chan_open_try" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChanOpenTry) ValidateBasic() sdk.Error { + // TODO: + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgChanOpenTry) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgChanOpenTry) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgChanOpenAck{} + +type MsgChanOpenAck struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Proofs []ics23.Proof `json:"proofs"` + Height uint64 `json:"height"` + Signer sdk.AccAddress `json:"signer"` +} + +// Route implements sdk.Msg +func (msg MsgChanOpenAck) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgChanOpenAck) Type() string { + return "chan_open_ack" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChanOpenAck) ValidateBasic() sdk.Error { + // TODO: + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgChanOpenAck) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgChanOpenAck) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgChanOpenConfirm{} + +type MsgChanOpenConfirm struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Proofs []ics23.Proof `json:"proofs"` + Height uint64 `json:"height"` + Signer sdk.AccAddress `json:"signer"` +} + +// Route implements sdk.Msg +func (msg MsgChanOpenConfirm) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgChanOpenConfirm) Type() string { + return "chan_open_confirm" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChanOpenConfirm) ValidateBasic() sdk.Error { + // TODO: + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgChanOpenConfirm) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgChanOpenConfirm) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgPacket{} + +// MsgPacket 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 exported.Packet `json:"packet" yaml:"packet"` + ChannelID string `json:"channel_id,omitempty" yaml:"channel_id"` + Proofs []ics23.Proof `json:"proofs" yaml:"proofs"` + Height uint64 `json:"height" yaml:"height"` + Signer sdk.AccAddress `json:"signer,omitempty" yaml:"signer"` +} + +// Route implements sdk.Msg +func (msg MsgPacket) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgPacket) Type() string { + return "packet" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgPacket) ValidateBasic() sdk.Error { + // TODO: + // Check PortID ChannelID len + // Check packet != nil + // Check proofs != nil + // Signer can be empty + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgPacket) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgPacket) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} diff --git a/x/ibc/04-channel/types/packet.go b/x/ibc/04-channel/types/packet.go new file mode 100644 index 000000000000..65c29ea7867f --- /dev/null +++ b/x/ibc/04-channel/types/packet.go @@ -0,0 +1,14 @@ +package types + +type Packet struct { + Seq uint64 // number corresponds to the order of sends and receives, where a packet with an earlier sequence number must be sent and received before a packet with a later sequence number. + Timeout uint64 // indicates a consensus height on the destination chain after which the packet will no longer be processed, and will instead count as having timed-out. + SourcePortID string // identifies the port on the sending chain. + SourceChannelID string // identifies the channel end on the sending chain. + DestinationPortID string // identifies the port on the receiving chain. + DestinationChannelID string // identifies the channel end on the receiving chain. + Data []byte // opaque value which can be defined by the application logic of the associated modules. +} + +// TODO: +type OpaquePacket Packet diff --git a/x/ibc/04-channel/types/port.go b/x/ibc/04-channel/types/port.go new file mode 100644 index 000000000000..a8183103fb75 --- /dev/null +++ b/x/ibc/04-channel/types/port.go @@ -0,0 +1,30 @@ +package types + +type Port struct { + id string +} + +// ID of the port +func (p Port) ID() string { + return p.id +} + +// // bindPort, expected to be called only at init time +// // TODO: is it safe to support runtime bindPort? +// func (man Manager) Port(id string) Port { +// if _, ok := man.ports[id]; ok { +// panic("port already occupied") +// } +// man.ports[id] = struct{}{} +// return Port{man, id} +// } + +// // releasePort +// func (port Port) Release() { +// delete(port.channel.ports, port.id) +// } + +// func (man Manager) IsValid(port Port) bool { +// _, ok := man.ports[port.id] +// return ok +// } From 0125276950a1de3021c50a8c4e00ccce3500944f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 14 Oct 2019 11:01:21 +0200 Subject: [PATCH 281/378] update handshake and packet --- x/ibc/04-channel/exported/exported.go | 12 +-- x/ibc/04-channel/keeper/handshake.go | 106 ++++++++++++++------- x/ibc/04-channel/keeper/packet.go | 4 +- x/ibc/04-channel/keeper/port.go | 4 +- x/ibc/04-channel/types/expected_keepers.go | 9 ++ x/ibc/04-channel/types/keys.go | 39 ++++---- x/ibc/04-channel/types/msgs.go | 10 +- x/ibc/04-channel/types/packet.go | 64 +++++++++++-- 8 files changed, 175 insertions(+), 73 deletions(-) diff --git a/x/ibc/04-channel/exported/exported.go b/x/ibc/04-channel/exported/exported.go index 0c691547da5f..7f1a537b28f1 100644 --- a/x/ibc/04-channel/exported/exported.go +++ b/x/ibc/04-channel/exported/exported.go @@ -1,9 +1,5 @@ package exported -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - type PacketI interface { Sequence() uint64 TimeoutHeight() uint64 @@ -13,8 +9,8 @@ type PacketI interface { DestChannel() string Data() []byte - // Non ICS04 interface functions - Type() string - ValidateBasic() sdk.Error - Marshal() []byte // Should exclude PortID/ChannelID info + // // Non ICS04 interface functions + // Type() string + // ValidateBasic() sdk.Error + // Marshal() []byte // Should exclude PortID/ChannelID info } diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go index 000ce4bd5452..ab0084f45dc5 100644 --- a/x/ibc/04-channel/keeper/handshake.go +++ b/x/ibc/04-channel/keeper/handshake.go @@ -108,6 +108,27 @@ func (k Keeper) ChanOpenTry( // hops channel := types.NewChannel(types.OPENTRY, order, counterparty, connectionHops, version) + // expectedCounterpaty is the counterparty of the counterparty's channel end + // (i.e self) + expectedCounterparty := types.NewCounterparty(portID, channelID) + expectedChannel := types.NewChannel( + types.INIT, channel.Ordering, expectedCounterparty, + channel.CounterpartyHops(), channel.Version, + ) + + bz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedChannel) + if err != nil { + return "", errors.New("failed to marshal expected channel") + } + + if !k.connectionKeeper.VerifyMembership( + ctx, connection, proofHeight, proofInit, + types.ChannelPath(counterparty.PortID, counterparty.ChannelID), + bz, + ) { + return "", errors.New("counterparty channel doesn't match the expected one") + } + // TODO: // if !connection.verifyMembership( // proofHeight, @@ -167,16 +188,25 @@ func (k Keeper) ChanOpenAck( return errors.New("connection is not open") } - // TODO: - // if !connection.verifyMembership( - // proofHeight, - // proofInit, - // channelPath(counterpartyPortIdentifier, counterpartyChannelIdentifier), - // Channel{INIT, order, portIdentifier, - // channelIdentifier, channel.CounterpartyHops(), counterpartyVersion} - // ) { - // return err - // } + // counterparty of the counterparty channel end (i.e self) + counterparty := types.NewCounterparty(portID, channelID) + expectedChannel := types.NewChannel( + types.INIT, channel.Ordering, counterparty, + channel.CounterpartyHops(), channel.Version, + ) + + bz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedChannel) + if err != nil { + return errors.New("failed to marshal expected channel") + } + + if !k.connectionKeeper.VerifyMembership( + ctx, connection, proofHeight, proofTry, + types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), + bz, + ) { + return errors.New("counterparty channel doesn't match the expected one") + } channel.State = types.OPEN channel.Version = counterpartyVersion @@ -221,16 +251,24 @@ func (k Keeper) ChanOpenConfirm( return errors.New("connection is not open") } - // TODO: - // if !connection.verifyMembership( - // proofHeight, - // proofAck, - // channelPath(channel.counterpartyPortIdentifier, channel.counterpartyChannelIdentifier), - // Channel{OPEN, channel.order, portIdentifier, - // channelIdentifier, channel.CounterpartyHops(), channel.version} - // ) { - // return err - // } + counterparty := types.NewCounterparty(portID, channelID) + expectedChannel := types.NewChannel( + types.OPEN, channel.Ordering, counterparty, + channel.CounterpartyHops(), channel.Version, + ) + + bz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedChannel) + if err != nil { + return errors.New("failed to marshal expected channel") + } + + if !k.connectionKeeper.VerifyMembership( + ctx, connection, proofHeight, proofAck, + types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), + bz, + ) { + return errors.New("counterparty channel doesn't match the expected one") + } channel.State = types.OPEN k.SetChannel(ctx, portID, channelID, channel) @@ -315,20 +353,24 @@ func (k Keeper) ChanCloseConfirm( return errors.New("connection is not open") } - // counterparty := types.NewCounterparty(portID, channelID) - // expectedChannel := types.NewChannel( - // types.CLOSED, channel.Ordering, counterparty, - // channel.CounterpartyHops(), channel.Version, - // ) + counterparty := types.NewCounterparty(portID, channelID) + expectedChannel := types.NewChannel( + types.CLOSED, channel.Ordering, counterparty, + channel.CounterpartyHops(), channel.Version, + ) - // if !connection.verifyMembership( - // proofHeight, - // proofInit, - // channelPath(channel.counterpartyPortIdentifier, channel.counterpartyChannelIdentifier), - // expectedChannel - // ) { + bz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedChannel) + if err != nil { + return errors.New("failed to marshal expected channel") + } - // } + if !k.connectionKeeper.VerifyMembership( + ctx, connection, proofHeight, proofInit, + types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), + bz, + ) { + return errors.New("counterparty channel doesn't match the expected one") + } channel.State = types.CLOSED k.SetChannel(ctx, portID, channelID, channel) diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go index 92f94f05c823..6a99cda0a943 100644 --- a/x/ibc/04-channel/keeper/packet.go +++ b/x/ibc/04-channel/keeper/packet.go @@ -78,7 +78,7 @@ import ( // return packet // } -func (k Keeper) SendPacket(ctx sdk.Context, channelID string, packet exported.Packet) error { +func (k Keeper) SendPacket(ctx sdk.Context, channelID string, packet exported.PacketI) error { // obj, err := man.Query(ctx, packet.SenderPort(), chanId) // if err != nil { // return err @@ -93,7 +93,7 @@ func (k Keeper) SendPacket(ctx sdk.Context, channelID string, packet exported.Pa return nil } -func (k Keeper) RecvPacket(ctx sdk.Context, proofs []ics23.Proof, height uint64, portID, channelID string, packet exported.Packet) error { +func (k Keeper) RecvPacket(ctx sdk.Context, proofs []ics23.Proof, height uint64, portID, channelID string, packet exported.PacketI) error { // obj, err := man.Query(ctx, portid, chanid) // if err != nil { // return err diff --git a/x/ibc/04-channel/keeper/port.go b/x/ibc/04-channel/keeper/port.go index ea99daf3af0a..fe42a34e6c5b 100644 --- a/x/ibc/04-channel/keeper/port.go +++ b/x/ibc/04-channel/keeper/port.go @@ -9,7 +9,7 @@ import ( ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -func (k Keeper) Send(ctx sdk.Context, channelID string, packet exported.Packet, port types.Port) error { +func (k Keeper) Send(ctx sdk.Context, channelID string, packet exported.PacketI, port types.Port) error { if !port.channel.IsValid(port) { return errors.New("Port is not in valid state") } @@ -21,6 +21,6 @@ func (k Keeper) Send(ctx sdk.Context, channelID string, packet exported.Packet, return port.channel.Send(ctx, channelID, packet) } -func (k Keeper) Receive(ctx sdk.Context, proof []ics23.Proof, height uint64, channelID string, packet exported.Packet, port types.Port) error { +func (k Keeper) Receive(ctx sdk.Context, proof []ics23.Proof, height uint64, channelID string, packet exported.PacketI, port types.Port) error { return port.channel.Receive(ctx, proof, height, port.ID(), channelID, packet) } diff --git a/x/ibc/04-channel/types/expected_keepers.go b/x/ibc/04-channel/types/expected_keepers.go index 0c35ba5d9f84..a1ae6f6dfe87 100644 --- a/x/ibc/04-channel/types/expected_keepers.go +++ b/x/ibc/04-channel/types/expected_keepers.go @@ -3,9 +3,18 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" ics03types "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // ConnectionKeeper expected account IBC connection keeper type ConnectionKeeper interface { GetConnection(ctx sdk.Context, connectionID string) (ics03types.ConnectionEnd, bool) + VerifyMembership( + ctx sdk.Context, connection ics03types.ConnectionEnd, height uint64, + proof ics23.Proof, path string, value []byte, + ) bool + VerifyNonMembership( + ctx sdk.Context, connection ics03types.ConnectionEnd, height uint64, + proof ics23.Proof, path string, + ) bool } diff --git a/x/ibc/04-channel/types/keys.go b/x/ibc/04-channel/types/keys.go index cef8e0364434..17f6b78d66d1 100644 --- a/x/ibc/04-channel/types/keys.go +++ b/x/ibc/04-channel/types/keys.go @@ -6,7 +6,7 @@ import ( const ( // SubModuleName defines the IBC channels name - SubModuleName = "channels" // TODO: why was this "ports" beforehand + SubModuleName = "channels" // StoreKey is the store key string for IBC channels StoreKey = SubModuleName @@ -18,49 +18,56 @@ const ( QuerierRoute = SubModuleName ) -func channelPath(portID string, channelID string) string { +// ChannelPath defines the path under which channels are stored +func ChannelPath(portID string, channelID string) string { return fmt.Sprintf("ports/%s/channels/%s", portID, channelID) } -func channelCapabilityPath(portID string, channelID string) string { - return fmt.Sprintf("%s/key", channelPath(portID, channelID)) +// ChannelCapabilityPath defines the path under which capability keys associated +// with a channel are stores +func ChannelCapabilityPath(portID string, channelID string) string { + return fmt.Sprintf("%s/key", ChannelPath(portID, channelID)) } -func nextSequenceSendPath(portID string, channelID string) string { - return fmt.Sprintf("%s/nextSequenceSend", channelPath(portID, channelID)) +// NextSequenceSendPath defines the next send sequence counter store path +func NextSequenceSendPath(portID string, channelID string) string { + return fmt.Sprintf("%s/nextSequenceSend", ChannelPath(portID, channelID)) } -func nextSequenceRecvPath(portID string, channelID string) string { - return fmt.Sprintf("%s/nextSequenceRecv", channelPath(portID, channelID)) +// NextSequenceRecvPath defines the next receive sequence counter store path +func NextSequenceRecvPath(portID string, channelID string) string { + return fmt.Sprintf("%s/nextSequenceRecv", ChannelPath(portID, channelID)) } -func packetCommitmentPath(portID string, channelID string, sequence uint64) string { - return fmt.Sprintf("%s/packets/%d", channelPath(portID, channelID), sequence) +// PacketCommitmentPath defines the commitments to packet data fields store path +func PacketCommitmentPath(portID string, channelID string, sequence uint64) string { + return fmt.Sprintf("%s/packets/%d", ChannelPath(portID, channelID), sequence) } -func packetAcknowledgementPath(portID string, channelID string, sequence uint64) string { - return fmt.Sprintf("%s/acknowledgements/%d", channelPath(portID, channelID), sequence) +// PacketAcknowledgementPath defines the packet acknowledgement store path +func PacketAcknowledgementPath(portID string, channelID string, sequence uint64) string { + return fmt.Sprintf("%s/acknowledgements/%d", ChannelPath(portID, channelID), sequence) } // KeyChannel returns the store key for a particular channel func KeyChannel(portID, channelID string) []byte { - return []byte(channelPath(portID, channelID)) + return []byte(ChannelPath(portID, channelID)) } // KeyChannelCapabilityPath returns the store key for the capability key of a // particular channel binded to a specific port func KeyChannelCapabilityPath(portID, channelID string) []byte { - return []byte(channelCapabilityPath(portID, channelID)) + return []byte(ChannelCapabilityPath(portID, channelID)) } // KeyNextSequenceSend returns the store key the send sequence of a particular // channel binded to a specific port func KeyNextSequenceSend(portID, channelID string) []byte { - return []byte(nextSequenceSendPath(portID, channelID)) + return []byte(NextSequenceSendPath(portID, channelID)) } // KeyNextSequenceRecv returns the store key the receive sequence of a particular // channel binded to a specific port func KeyNextSequenceRecv(portID, channelID string) []byte { - return []byte(nextSequenceRecvPath(portID, channelID)) + return []byte(NextSequenceRecvPath(portID, channelID)) } diff --git a/x/ibc/04-channel/types/msgs.go b/x/ibc/04-channel/types/msgs.go index fe5f994b9d4e..116e6ecc6cb3 100644 --- a/x/ibc/04-channel/types/msgs.go +++ b/x/ibc/04-channel/types/msgs.go @@ -157,11 +157,11 @@ var _ sdk.Msg = MsgPacket{} // ChannelID can be empty if batched & not first MsgPacket // Height uint64 // height of the commitment root for the proofs type MsgPacket struct { - Packet exported.Packet `json:"packet" yaml:"packet"` - ChannelID string `json:"channel_id,omitempty" yaml:"channel_id"` - Proofs []ics23.Proof `json:"proofs" yaml:"proofs"` - Height uint64 `json:"height" yaml:"height"` - Signer sdk.AccAddress `json:"signer,omitempty" yaml:"signer"` + Packet exported.PacketI `json:"packet" yaml:"packet"` + ChannelID string `json:"channel_id,omitempty" yaml:"channel_id"` + Proofs []ics23.Proof `json:"proofs" yaml:"proofs"` + Height uint64 `json:"height" yaml:"height"` + Signer sdk.AccAddress `json:"signer,omitempty" yaml:"signer"` } // Route implements sdk.Msg diff --git a/x/ibc/04-channel/types/packet.go b/x/ibc/04-channel/types/packet.go index 65c29ea7867f..ffde3410e96f 100644 --- a/x/ibc/04-channel/types/packet.go +++ b/x/ibc/04-channel/types/packet.go @@ -1,14 +1,62 @@ package types +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" +) + +var _ exported.PacketI = Packet{} + +// Packet defines a type that carries data across different chains through IBC type Packet struct { - Seq uint64 // number corresponds to the order of sends and receives, where a packet with an earlier sequence number must be sent and received before a packet with a later sequence number. - Timeout uint64 // indicates a consensus height on the destination chain after which the packet will no longer be processed, and will instead count as having timed-out. - SourcePortID string // identifies the port on the sending chain. - SourceChannelID string // identifies the channel end on the sending chain. - DestinationPortID string // identifies the port on the receiving chain. - DestinationChannelID string // identifies the channel end on the receiving chain. - Data []byte // opaque value which can be defined by the application logic of the associated modules. + sequence uint64 // number corresponds to the order of sends and receives, where a packet with an earlier sequence number must be sent and received before a packet with a later sequence number. + timeout uint64 // indicates a consensus height on the destination chain after which the packet will no longer be processed, and will instead count as having timed-out. + sourcePort string // identifies the port on the sending chain. + sourceChannel string // identifies the channel end on the sending chain. + destinationPort string // identifies the port on the receiving chain. + destinationChannel string // identifies the channel end on the receiving chain. + data []byte // opaque value which can be defined by the application logic of the associated modules. +} + +// NewPacket creates a new Packet instance +func NewPacket( + sequence, timeout uint64, sourcePort, sourceChannel, + destinationPort, destinationChannel string, data []byte, +) Packet { + return Packet{ + sequence, + timeout, + sourcePort, + sourceChannel, + destinationPort, + destinationChannel, + data, + } } -// TODO: +// Sequence implements PacketI interface +func (p Packet) Sequence() uint64 { return p.sequence } + +// TimeoutHeight implements PacketI interface +func (p Packet) TimeoutHeight() uint64 { return p.timeout } + +// SourcePort implements PacketI interface +func (p Packet) SourcePort() string { return p.sourcePort } + +// SourceChannel implements PacketI interface +func (p Packet) SourceChannel() string { return p.sourceChannel } + +// DestPort implements PacketI interface +func (p Packet) DestPort() string { return p.destinationPort } + +// DestChannel implements PacketI interface +func (p Packet) DestChannel() string { return p.destinationChannel } + +// Data implements PacketI interface +func (p Packet) Data() []byte { return p.data } + +// OpaquePacket is a packet, but cloaked in an obscuring data type by the host +// state machine, such that a module cannot act upon it other than to pass it to +// the IBC handler type OpaquePacket Packet + +// TODO: Obscure data type From 038d7cf4f7c32157884b7b0453ae5d0b6712719c Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 14 Oct 2019 11:48:17 +0200 Subject: [PATCH 282/378] implement packet timeouts --- x/ibc/04-channel/keeper/keeper.go | 12 +++ x/ibc/04-channel/keeper/packet.go | 151 ++++++++++++++++++++++++++++++ x/ibc/04-channel/types/keys.go | 22 +++-- 3 files changed, 177 insertions(+), 8 deletions(-) diff --git a/x/ibc/04-channel/keeper/keeper.go b/x/ibc/04-channel/keeper/keeper.go index a4a4f6c12c27..2d20a0d18895 100644 --- a/x/ibc/04-channel/keeper/keeper.go +++ b/x/ibc/04-channel/keeper/keeper.go @@ -90,3 +90,15 @@ func (k Keeper) SetNextSequenceRecv(ctx sdk.Context, portID, channelID string, s bz := sdk.Uint64ToBigEndian(sequence) store.Set(types.KeyNextSequenceRecv(portID, channelID), bz) } + +// GetPacketCommitment gets the packet commitment hash from the store +func (k Keeper) GetPacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64) []byte { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(types.KeyPacketCommitment(portID, channelID, sequence)) + return bz +} + +func (k Keeper) deletePacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + store.Delete(types.KeyPacketCommitment(portID, channelID, sequence)) +} diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go index 6a99cda0a943..2bc8b794c5eb 100644 --- a/x/ibc/04-channel/keeper/packet.go +++ b/x/ibc/04-channel/keeper/packet.go @@ -1,11 +1,162 @@ package keeper import ( + "bytes" + "errors" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) +// TimoutPacket is called by a module which originally attempted to send a +// packet to a counterparty module, where the timeout height has passed on the +// counterparty chain without the packet being committed, to prove that the +// packet can no longer be executed and to allow the calling module to safely +// perform appropriate state transitions. +func (k Keeper) TimoutPacket( + ctx sdk.Context, + packet exported.PacketI, + proof ics23.Proof, + proofHeight uint64, + nextSequenceRecv uint64, +) (exported.PacketI, error) { + channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) + if !found { + return nil, errors.New("channel not found") // TODO: sdk.Error + } + + if channel.State != types.OPEN { + return nil, errors.New("channel is not open") // TODO: sdk.Error + } + + _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) + if !found { + return nil, errors.New("channel capability key not found") // TODO: sdk.Error + } + + // if !AuthenticateCapabilityKey(capabilityKey) { + // return errors.New("invalid capability key") // TODO: sdk.Error + // } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return nil, errors.New("connection not found") // TODO: ics03 sdk.Error + } + + if proofHeight < packet.TimeoutHeight() { + return nil, errors.New("timeout on counterparty connection end") + } + + if nextSequenceRecv >= packet.Sequence() { + return nil, errors.New("packet already received") + } + + commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data + return nil, errors.New("packet hasn't been sent") + } + + var ok bool + switch channel.Ordering { + case types.ORDERED: + ok = k.connectionKeeper.VerifyMembership( + ctx, connection, proofHeight, proof, + types.NextSequenceRecvPath(packet.DestPort(), packet.DestChannel()), + sdk.Uint64ToBigEndian(nextSequenceRecv), + ) + case types.UNORDERED: + ok = k.connectionKeeper.VerifyNonMembership( + ctx, connection, proofHeight, proof, + types.PacketAcknowledgementPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), + ) + default: + panic("invalid channel ordering type") + } + + if !ok { + return nil, errors.New("failed packet verification") // TODO: sdk.Error + } + + k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + + if channel.Ordering == types.ORDERED { + channel.State = types.CLOSED + k.SetChannel(ctx, packet.SourcePort(), packet.SourceChannel(), channel) + } + + return packet, nil +} + +// TimeoutOnClose is called by a module in order to prove that the channel to +// which an unreceived packet was addressed has been closed, so the packet will +// never be received (even if the timeoutHeight has not yet been reached). +func (k Keeper) TimeoutOnClose( + ctx sdk.Context, + packet exported.PacketI, + proofNonMembership, + proofClosed ics23.Proof, + proofHeight uint64, +) (exported.PacketI, error) { + channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) + if !found { + return nil, errors.New("channel not found") // TODO: sdk.Error + } + + _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) + if !found { + return nil, errors.New("channel capability key not found") // TODO: sdk.Error + } + + // if !AuthenticateCapabilityKey(capabilityKey) { + // return errors.New("invalid capability key") // TODO: sdk.Error + // } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return nil, errors.New("connection not found") // TODO: ics03 sdk.Error + } + + if packet.DestPort() != channel.Counterparty.PortID { + return nil, errors.New("port id doesn't match with counterparty's") + } + + commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data + return nil, errors.New("packet hasn't been sent") + } + + counterparty := types.NewCounterparty(packet.SourcePort(), packet.SourceChannel()) + expectedChannel := types.NewChannel( + types.CLOSED, channel.Ordering, counterparty, channel.CounterpartyHops(), channel.Version, + ) + + bz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedChannel) + if err != nil { + return nil, errors.New("failed to marshal expected channel") + } + + if !k.connectionKeeper.VerifyMembership( + ctx, connection, proofHeight, proofClosed, + types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), + bz, + ) { + return nil, errors.New("counterparty channel doesn't match the expected one") + } + + if !k.connectionKeeper.VerifyNonMembership( + ctx, connection, proofHeight, proofNonMembership, + types.PacketAcknowledgementPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), + ) { + return nil, errors.New("cannot verify absence of acknowledgement at packet index") + } + + k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + + return packet, nil +} + // function sendPacket(packet: Packet) { // channel = provableStore.get(channelPath(packet.sourcePort, packet.sourceChannel)) diff --git a/x/ibc/04-channel/types/keys.go b/x/ibc/04-channel/types/keys.go index 17f6b78d66d1..839afc388d44 100644 --- a/x/ibc/04-channel/types/keys.go +++ b/x/ibc/04-channel/types/keys.go @@ -19,33 +19,33 @@ const ( ) // ChannelPath defines the path under which channels are stored -func ChannelPath(portID string, channelID string) string { +func ChannelPath(portID, channelID string) string { return fmt.Sprintf("ports/%s/channels/%s", portID, channelID) } // ChannelCapabilityPath defines the path under which capability keys associated // with a channel are stores -func ChannelCapabilityPath(portID string, channelID string) string { +func ChannelCapabilityPath(portID, channelID string) string { return fmt.Sprintf("%s/key", ChannelPath(portID, channelID)) } // NextSequenceSendPath defines the next send sequence counter store path -func NextSequenceSendPath(portID string, channelID string) string { +func NextSequenceSendPath(portID, channelID string) string { return fmt.Sprintf("%s/nextSequenceSend", ChannelPath(portID, channelID)) } // NextSequenceRecvPath defines the next receive sequence counter store path -func NextSequenceRecvPath(portID string, channelID string) string { +func NextSequenceRecvPath(portID, channelID string) string { return fmt.Sprintf("%s/nextSequenceRecv", ChannelPath(portID, channelID)) } // PacketCommitmentPath defines the commitments to packet data fields store path -func PacketCommitmentPath(portID string, channelID string, sequence uint64) string { +func PacketCommitmentPath(portID, channelID string, sequence uint64) string { return fmt.Sprintf("%s/packets/%d", ChannelPath(portID, channelID), sequence) } // PacketAcknowledgementPath defines the packet acknowledgement store path -func PacketAcknowledgementPath(portID string, channelID string, sequence uint64) string { +func PacketAcknowledgementPath(portID, channelID string, sequence uint64) string { return fmt.Sprintf("%s/acknowledgements/%d", ChannelPath(portID, channelID), sequence) } @@ -60,14 +60,20 @@ func KeyChannelCapabilityPath(portID, channelID string) []byte { return []byte(ChannelCapabilityPath(portID, channelID)) } -// KeyNextSequenceSend returns the store key the send sequence of a particular +// KeyNextSequenceSend returns the store key for the send sequence of a particular // channel binded to a specific port func KeyNextSequenceSend(portID, channelID string) []byte { return []byte(NextSequenceSendPath(portID, channelID)) } -// KeyNextSequenceRecv returns the store key the receive sequence of a particular +// KeyNextSequenceRecv returns the store key for the receive sequence of a particular // channel binded to a specific port func KeyNextSequenceRecv(portID, channelID string) []byte { return []byte(NextSequenceRecvPath(portID, channelID)) } + +// KeyPacketCommitment returns the store key of under which a packet commitment +// is stored +func KeyPacketCommitment(portID, channelID string, sequence uint64) []byte { + return []byte(PacketCommitmentPath(portID, channelID, sequence)) +} From 931ef763432ecd865570d13c8b2bda3ee1465117 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 14 Oct 2019 12:46:07 +0200 Subject: [PATCH 283/378] implement send and receive packet --- x/ibc/04-channel/keeper/keeper.go | 37 ++- x/ibc/04-channel/keeper/packet.go | 286 +++++++++------------ x/ibc/04-channel/keeper/port.go | 26 -- x/ibc/04-channel/keeper/timeout.go | 174 +++++++++++++ x/ibc/04-channel/types/expected_keepers.go | 6 + x/ibc/04-channel/types/keys.go | 6 + 6 files changed, 349 insertions(+), 186 deletions(-) delete mode 100644 x/ibc/04-channel/keeper/port.go create mode 100644 x/ibc/04-channel/keeper/timeout.go diff --git a/x/ibc/04-channel/keeper/keeper.go b/x/ibc/04-channel/keeper/keeper.go index 2d20a0d18895..73a6349f639f 100644 --- a/x/ibc/04-channel/keeper/keeper.go +++ b/x/ibc/04-channel/keeper/keeper.go @@ -1,6 +1,7 @@ package keeper import ( + "enconding/binary" "fmt" "github.com/tendermint/tendermint/libs/log" @@ -19,8 +20,8 @@ type Keeper struct { codespace sdk.CodespaceType prefix []byte // prefix bytes for accessing the store + clientKeeper types.ClientKeeper connectionKeeper types.ConnectionKeeper - // TODO: portKeeper } // NewKeeper creates a new IBC channel Keeper instance @@ -77,6 +78,17 @@ func (k Keeper) SetChannelCapability(ctx sdk.Context, portID, channelID string, store.Set(types.KeyChannelCapabilityPath(portID, channelID), []byte(key)) } +// GetNextSequenceSend gets a channel's next send sequence from the store +func (k Keeper) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(types.KeyNextSequenceSend(portID, channelID)) + if bz == nil { + return 0, false + } + + return binary.BigEndian(bz), true +} + // SetNextSequenceSend sets a channel's next send sequence to the store func (k Keeper) SetNextSequenceSend(ctx sdk.Context, portID, channelID string, sequence uint64) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) @@ -84,6 +96,17 @@ func (k Keeper) SetNextSequenceSend(ctx sdk.Context, portID, channelID string, s store.Set(types.KeyNextSequenceSend(portID, channelID), bz) } +// GetNextSequenceRecv gets a channel's next receive sequence from the store +func (k Keeper) GetNextSequenceRecv(ctx sdk.Context, portID, channelID string) (uint64, bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(types.KeyNextSequenceRecv(portID, channelID)) + if bz == nil { + return 0, false + } + + return binary.BigEndian(bz), true +} + // SetNextSequenceRecv sets a channel's next receive sequence to the store func (k Keeper) SetNextSequenceRecv(ctx sdk.Context, portID, channelID string, sequence uint64) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) @@ -98,7 +121,19 @@ func (k Keeper) GetPacketCommitment(ctx sdk.Context, portID, channelID string, s return bz } +// SetPacketCommitment sets the packet commitment hash to the store +func (k Keeper) SetPacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64, commitmentHash []byte) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + store.Set(types.KeyPacketCommitment(portID, channelID, sequence), commitmentHash) +} + func (k Keeper) deletePacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) store.Delete(types.KeyPacketCommitment(portID, channelID, sequence)) } + +// SetPacketAcknowledgement sets the packet ack hash to the store +func (k Keeper) SetPacketAcknowledgement(ctx sdk.Context, portID, channelID string, sequence uint64, ackHash []byte) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + store.Set(types.KeyPacketAcknowledgement(portID, channelID, sequence), ackHash) +} diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go index 2bc8b794c5eb..ca3e7b2c405a 100644 --- a/x/ibc/04-channel/keeper/packet.go +++ b/x/ibc/04-channel/keeper/packet.go @@ -5,22 +5,29 @@ import ( "errors" sdk "github.com/cosmos/cosmos-sdk/types" + ics03types "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -// TimoutPacket is called by a module which originally attempted to send a -// packet to a counterparty module, where the timeout height has passed on the -// counterparty chain without the packet being committed, to prove that the -// packet can no longer be executed and to allow the calling module to safely -// perform appropriate state transitions. -func (k Keeper) TimoutPacket( +// CleanupPacket is called by a module to remove a received packet commitment +// from storage. The receiving end must have already processed the packet +// (whether regularly or past timeout). +// +// In the ORDERED channel case, CleanupPacket cleans-up a packet on an ordered +// channel by proving that the packet has been received on the other end. +// +// In the UNORDERED channel case, CleanupPacket cleans-up a packet on an +// unordered channel by proving that the associated acknowledgement has been +//written. +func (k Keeper) CleanupPacket( ctx sdk.Context, packet exported.PacketI, proof ics23.Proof, - proofHeight uint64, + proofHeight, nextSequenceRecv uint64, + acknowledgement []byte, ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { @@ -40,13 +47,17 @@ func (k Keeper) TimoutPacket( // return errors.New("invalid capability key") // TODO: sdk.Error // } + if packet.DestChannel() != channel.Counterparty.ChannelID { + return nil, errors.New("invalid packet destination channel") + } + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { return nil, errors.New("connection not found") // TODO: ics03 sdk.Error } - if proofHeight < packet.TimeoutHeight() { - return nil, errors.New("timeout on counterparty connection end") + if packet.DestPort() != channel.Counterparty.PortID { + return nil, errors.New("invalid packet destination port") } if nextSequenceRecv >= packet.Sequence() { @@ -67,9 +78,10 @@ func (k Keeper) TimoutPacket( sdk.Uint64ToBigEndian(nextSequenceRecv), ) case types.UNORDERED: - ok = k.connectionKeeper.VerifyNonMembership( + ok = k.connectionKeeper.VerifyMembership( ctx, connection, proofHeight, proof, types.PacketAcknowledgementPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), + acknowledgement, ) default: panic("invalid channel ordering type") @@ -80,195 +92,151 @@ func (k Keeper) TimoutPacket( } k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) - - if channel.Ordering == types.ORDERED { - channel.State = types.CLOSED - k.SetChannel(ctx, packet.SourcePort(), packet.SourceChannel(), channel) - } - return packet, nil } -// TimeoutOnClose is called by a module in order to prove that the channel to -// which an unreceived packet was addressed has been closed, so the packet will -// never be received (even if the timeoutHeight has not yet been reached). -func (k Keeper) TimeoutOnClose( - ctx sdk.Context, - packet exported.PacketI, - proofNonMembership, - proofClosed ics23.Proof, - proofHeight uint64, -) (exported.PacketI, error) { +// SendPacket is called by a module in order to send an IBC packet on a channel +// end owned by the calling module to the corresponding module on the counterparty +// chain. +func (k Keeper) SendPacket(ctx sdk.Context, packet exported.PacketI) error { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, errors.New("channel not found") // TODO: sdk.Error + return errors.New("channel not found") // TODO: sdk.Error + } + + if channel.State == types.CLOSED { + return errors.New("channel is closed") // TODO: sdk.Error } _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, errors.New("channel capability key not found") // TODO: sdk.Error + return errors.New("channel capability key not found") // TODO: sdk.Error } // if !AuthenticateCapabilityKey(capabilityKey) { // return errors.New("invalid capability key") // TODO: sdk.Error // } + if packet.DestPort() != channel.Counterparty.PortID { + return errors.New("invalid packet destination port") + } + + if packet.DestChannel() != channel.Counterparty.ChannelID { + return errors.New("invalid packet destination channel") + } + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, errors.New("connection not found") // TODO: ics03 sdk.Error + return errors.New("connection not found") // TODO: ics03 sdk.Error } - if packet.DestPort() != channel.Counterparty.PortID { - return nil, errors.New("port id doesn't match with counterparty's") + if connection.State == ics03types.NONE { + return errors.New("connection is closed") // TODO: sdk.Error } - commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) - if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data - return nil, errors.New("packet hasn't been sent") + consensusState, found := k.clientKeeper.GetConsensusState(ctx, connection.ClientID) + if !found { + return errors.New("consensus state not found") // TODO: sdk.Error } - counterparty := types.NewCounterparty(packet.SourcePort(), packet.SourceChannel()) - expectedChannel := types.NewChannel( - types.CLOSED, channel.Ordering, counterparty, channel.CounterpartyHops(), channel.Version, - ) - - bz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedChannel) - if err != nil { - return nil, errors.New("failed to marshal expected channel") + if consensusState.GetHeight() >= packet.TimeoutHeight() { + return errors.New("invalid height") // TODO: sdk.Error } - if !k.connectionKeeper.VerifyMembership( - ctx, connection, proofHeight, proofClosed, - types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), - bz, - ) { - return nil, errors.New("counterparty channel doesn't match the expected one") + nextSequenceSend, found := k.GetNextSequenceSend(ctx, packet.SourcePort(), packet.SourceChannel()) + if !found { + return errors.New("next seq send counter not found") // TODO: sdk.Error } - if !k.connectionKeeper.VerifyNonMembership( - ctx, connection, proofHeight, proofNonMembership, - types.PacketAcknowledgementPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), - ) { - return nil, errors.New("cannot verify absence of acknowledgement at packet index") + if packet.Sequence() != nextSequenceSend { + return errors.New("invalid packet sequence") } - k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + nextSequenceSend++ + k.SetNextSequenceSend(ctx, packet.SourcePort(), packet.SourceChannel(), nextSequenceSend) + k.SetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence(), packet.Data()) // TODO: hash packet data - return packet, nil + return nil } -// function sendPacket(packet: Packet) { -// channel = provableStore.get(channelPath(packet.sourcePort, packet.sourceChannel)) - -// // optimistic sends are permitted once the handshake has started -// abortTransactionUnless(channel !== null) -// abortTransactionUnless(channel.state !== CLOSED) -// abortTransactionUnless(authenticate(privateStore.get(channelCapabilityPath(packet.sourcePort, packet.sourceChannel)))) -// abortTransactionUnless(packet.destPort === channel.counterpartyPortIdentifier) -// abortTransactionUnless(packet.destChannel === channel.counterpartyChannelIdentifier) -// connection = provableStore.get(connectionPath(channel.connectionHops[0])) - -// abortTransactionUnless(connection !== null) -// abortTransactionUnless(connection.state !== CLOSED) - -// consensusState = provableStore.get(consensusStatePath(connection.clientIdentifier)) -// abortTransactionUnless(consensusState.getHeight() < packet.timeoutHeight) - -// nextSequenceSend = provableStore.get(nextSequenceSendPath(packet.sourcePort, packet.sourceChannel)) -// abortTransactionUnless(packet.sequence === nextSequenceSend) - -// // all assertions passed, we can alter state - -// nextSequenceSend = nextSequenceSend + 1 -// provableStore.set(nextSequenceSendPath(packet.sourcePort, packet.sourceChannel), nextSequenceSend) -// provableStore.set(packetCommitmentPath(packet.sourcePort, packet.sourceChannel, packet.sequence), hash(packet.data)) -// } - -// function recvPacket( -// packet: OpaquePacket, -// proof: CommitmentProof, -// proofHeight: uint64, -// acknowledgement: bytes): Packet { - -// channel = provableStore.get(channelPath(packet.destPort, packet.destChannel)) -// abortTransactionUnless(channel !== null) -// abortTransactionUnless(channel.state === OPEN) -// abortTransactionUnless(authenticate(privateStore.get(channelCapabilityPath(packet.destPort, packet.destChannel)))) -// abortTransactionUnless(packet.sourcePort === channel.counterpartyPortIdentifier) -// abortTransactionUnless(packet.sourceChannel === channel.counterpartyChannelIdentifier) - -// connection = provableStore.get(connectionPath(channel.connectionHops[0])) -// abortTransactionUnless(connection !== null) -// abortTransactionUnless(connection.state === OPEN) - -// abortTransactionUnless(getConsensusHeight() < packet.timeoutHeight) - -// abortTransactionUnless(connection.verifyMembership( -// proofHeight, -// proof, -// packetCommitmentPath(packet.sourcePort, packet.sourceChannel, packet.sequence), -// hash(packet.data) -// )) - -// // all assertions passed (except sequence check), we can alter state - -// if (acknowledgement.length > 0 || channel.order === UNORDERED) -// provableStore.set( -// packetAcknowledgementPath(packet.destPort, packet.destChannel, packet.sequence), -// hash(acknowledgement) -// ) - -// if (channel.order === ORDERED) { -// nextSequenceRecv = provableStore.get(nextSequenceRecvPath(packet.destPort, packet.destChannel)) -// abortTransactionUnless(packet.sequence === nextSequenceRecv) -// nextSequenceRecv = nextSequenceRecv + 1 -// provableStore.set(nextSequenceRecvPath(packet.destPort, packet.destChannel), nextSequenceRecv) -// } - -// // return transparent packet -// return packet -// } - -func (k Keeper) SendPacket(ctx sdk.Context, channelID string, packet exported.PacketI) error { - // obj, err := man.Query(ctx, packet.SenderPort(), chanId) - // if err != nil { - // return err - // } +// RecvPacket is called by a module in order to receive & process an IBC packet +// sent on the corresponding channel end on the counterparty chain. +func (k Keeper) RecvPacket( + ctx sdk.Context, + packet exported.PacketI, + proof ics23.Proof, + proofHeight uint64, + acknowledgement []byte, +) (exported.PacketI, error) { - // if obj.OriginConnection().Client.GetConsensusState(ctx).GetHeight() >= packet.Timeout() { - // return errors.New("timeout height higher than the latest known") - // } + channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) + if !found { + return nil, errors.New("channel not found") // TODO: sdk.Error + } - // obj.Packets.SetRaw(ctx, obj.SeqSend.Increment(ctx), packet.Marshal()) + if channel.State != types.OPEN { + return nil, errors.New("channel not open") // TODO: sdk.Error + } - return nil -} + _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) + if !found { + return nil, errors.New("channel capability key not found") // TODO: sdk.Error + } -func (k Keeper) RecvPacket(ctx sdk.Context, proofs []ics23.Proof, height uint64, portID, channelID string, packet exported.PacketI) error { - // obj, err := man.Query(ctx, portid, chanid) - // if err != nil { - // return err + // if !AuthenticateCapabilityKey(capabilityKey) { + // return errors.New("invalid capability key") // TODO: sdk.Error // } - // /* - // if !obj.Receivable(ctx) { - // return errors.New("cannot receive Packets on this channel") - // } - // */ + // packet must come from the channel's counterparty + if packet.SourcePort() != channel.Counterparty.PortID { + return nil, errors.New("invalid packet source port") + } - // ctx, err = obj.Context(ctx, proofs, height) - // if err != nil { - // return err - // } + if packet.SourceChannel() != channel.Counterparty.ChannelID { + return nil, errors.New("invalid packet source channel") + } - // err = assertTimeout(ctx, packet.Timeout()) - // if err != nil { - // return err - // } + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return nil, errors.New("connection not found") // TODO: ics03 sdk.Error + } - // if !obj.counterParty.Packets.Value(obj.SeqRecv.Increment(ctx)).IsRaw(ctx, packet.Marshal()) { - // return errors.New("verification failed") - // } + if connection.State != ics03types.OPEN { + return nil, errors.New("connection is not open") // TODO: ics03 sdk.Error + } - return nil + if uint64(ctx.BlockHeight()) >= packet.TimeoutHeight() { + return nil, errors.New("packet receive timeout") + } + + if !k.connectionKeeper.VerifyMembership( + ctx, connection, proofHeight, proof, + types.ChannelPath(packet.SourcePort(), packet.SourceChannel()), + packet.Data(), // TODO: hash data + ) { + return nil, errors.New("counterparty channel doesn't match the expected one") + } + + if len(acknowledgement) > 0 || channel.Ordering == types.UNORDERED { + k.SetPacketAcknowledgement( + ctx, packet.DestPort(), packet.DestChannel(), packet.Sequence(), + acknowledgement, // TODO: hash ACK + ) + } + + if channel.Ordering == types.ORDERED { + nextSequenceRecv, found := k.GetNextSequenceRecv(ctx, packet.DestPort(), packet.DestChannel()) + if !found { + return nil, errors.New("next seq receive counter not found") // TODO: sdk.Error + } + + if packet.Sequence() != nextSequenceRecv { + return nil, errors.New("invalid packet sequence") + } + + nextSequenceRecv++ + k.SetNextSequenceRecv(ctx, packet.DestPort(), packet.DestChannel(), nextSequenceRecv) + } + + return packet, nil } diff --git a/x/ibc/04-channel/keeper/port.go b/x/ibc/04-channel/keeper/port.go deleted file mode 100644 index fe42a34e6c5b..000000000000 --- a/x/ibc/04-channel/keeper/port.go +++ /dev/null @@ -1,26 +0,0 @@ -package keeper - -import ( - "errors" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -func (k Keeper) Send(ctx sdk.Context, channelID string, packet exported.PacketI, port types.Port) error { - 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, channelID, packet) -} - -func (k Keeper) Receive(ctx sdk.Context, proof []ics23.Proof, height uint64, channelID string, packet exported.PacketI, port types.Port) error { - return port.channel.Receive(ctx, proof, height, port.ID(), channelID, packet) -} diff --git a/x/ibc/04-channel/keeper/timeout.go b/x/ibc/04-channel/keeper/timeout.go new file mode 100644 index 000000000000..54bec7120af9 --- /dev/null +++ b/x/ibc/04-channel/keeper/timeout.go @@ -0,0 +1,174 @@ +package keeper + +import ( + "bytes" + "errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +// TimoutPacket is called by a module which originally attempted to send a +// packet to a counterparty module, where the timeout height has passed on the +// counterparty chain without the packet being committed, to prove that the +// packet can no longer be executed and to allow the calling module to safely +// perform appropriate state transitions. +func (k Keeper) TimoutPacket( + ctx sdk.Context, + packet exported.PacketI, + proof ics23.Proof, + proofHeight uint64, + nextSequenceRecv uint64, +) (exported.PacketI, error) { + channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) + if !found { + return nil, errors.New("channel not found") // TODO: sdk.Error + } + + if channel.State != types.OPEN { + return nil, errors.New("channel is not open") // TODO: sdk.Error + } + + _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) + if !found { + return nil, errors.New("channel capability key not found") // TODO: sdk.Error + } + + // if !AuthenticateCapabilityKey(capabilityKey) { + // return errors.New("invalid capability key") // TODO: sdk.Error + // } + + if packet.DestChannel() != channel.Counterparty.ChannelID { + return nil, errors.New("invalid packet destination channel") + } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return nil, errors.New("connection not found") // TODO: ics03 sdk.Error + } + + if packet.DestPort() != channel.Counterparty.PortID { + return nil, errors.New("invalid packet destination port") + } + + if proofHeight < packet.TimeoutHeight() { + return nil, errors.New("timeout on counterparty connection end") + } + + if nextSequenceRecv >= packet.Sequence() { + return nil, errors.New("packet already received") + } + + commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data + return nil, errors.New("packet hasn't been sent") + } + + var ok bool + switch channel.Ordering { + case types.ORDERED: + ok = k.connectionKeeper.VerifyMembership( + ctx, connection, proofHeight, proof, + types.NextSequenceRecvPath(packet.DestPort(), packet.DestChannel()), + sdk.Uint64ToBigEndian(nextSequenceRecv), + ) + case types.UNORDERED: + ok = k.connectionKeeper.VerifyNonMembership( + ctx, connection, proofHeight, proof, + types.PacketAcknowledgementPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), + ) + default: + panic("invalid channel ordering type") + } + + if !ok { + return nil, errors.New("failed packet verification") // TODO: sdk.Error + } + + k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + + if channel.Ordering == types.ORDERED { + channel.State = types.CLOSED + k.SetChannel(ctx, packet.SourcePort(), packet.SourceChannel(), channel) + } + + return packet, nil +} + +// TimeoutOnClose is called by a module in order to prove that the channel to +// which an unreceived packet was addressed has been closed, so the packet will +// never be received (even if the timeoutHeight has not yet been reached). +func (k Keeper) TimeoutOnClose( + ctx sdk.Context, + packet exported.PacketI, + proofNonMembership, + proofClosed ics23.Proof, + proofHeight uint64, +) (exported.PacketI, error) { + channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) + if !found { + return nil, errors.New("channel not found") // TODO: sdk.Error + } + + _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) + if !found { + return nil, errors.New("channel capability key not found") // TODO: sdk.Error + } + + // if !AuthenticateCapabilityKey(capabilityKey) { + // return errors.New("invalid capability key") // TODO: sdk.Error + // } + + if packet.DestChannel() != channel.Counterparty.ChannelID { + return nil, errors.New("invalid packet destination channel") + } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return nil, errors.New("connection not found") // TODO: ics03 sdk.Error + } + + if packet.DestPort() != channel.Counterparty.PortID { + return nil, errors.New("invalid packet destination port") + } + + if packet.DestPort() != channel.Counterparty.PortID { + return nil, errors.New("port id doesn't match with counterparty's") + } + + commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data + return nil, errors.New("packet hasn't been sent") + } + + counterparty := types.NewCounterparty(packet.SourcePort(), packet.SourceChannel()) + expectedChannel := types.NewChannel( + types.CLOSED, channel.Ordering, counterparty, channel.CounterpartyHops(), channel.Version, + ) + + bz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedChannel) + if err != nil { + return nil, errors.New("failed to marshal expected channel") + } + + if !k.connectionKeeper.VerifyMembership( + ctx, connection, proofHeight, proofClosed, + types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), + bz, + ) { + return nil, errors.New("counterparty channel doesn't match the expected one") + } + + if !k.connectionKeeper.VerifyNonMembership( + ctx, connection, proofHeight, proofNonMembership, + types.PacketAcknowledgementPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), + ) { + return nil, errors.New("cannot verify absence of acknowledgement at packet index") + } + + k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + + return packet, nil +} diff --git a/x/ibc/04-channel/types/expected_keepers.go b/x/ibc/04-channel/types/expected_keepers.go index a1ae6f6dfe87..ff7c7b586370 100644 --- a/x/ibc/04-channel/types/expected_keepers.go +++ b/x/ibc/04-channel/types/expected_keepers.go @@ -2,10 +2,16 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + ics02exported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ics03types "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) +// ClientKeeper expected account IBC client keeper +type ClientKeeper interface { + GetConsensusState(ctx sdk.Context, clientID string) (ics02exported.ConsensusState, bool) +} + // ConnectionKeeper expected account IBC connection keeper type ConnectionKeeper interface { GetConnection(ctx sdk.Context, connectionID string) (ics03types.ConnectionEnd, bool) diff --git a/x/ibc/04-channel/types/keys.go b/x/ibc/04-channel/types/keys.go index 839afc388d44..26fb0b209770 100644 --- a/x/ibc/04-channel/types/keys.go +++ b/x/ibc/04-channel/types/keys.go @@ -77,3 +77,9 @@ func KeyNextSequenceRecv(portID, channelID string) []byte { func KeyPacketCommitment(portID, channelID string, sequence uint64) []byte { return []byte(PacketCommitmentPath(portID, channelID, sequence)) } + +// KeyPacketAcknowledgement returns the store key of under which a packet +// acknowledgement is stored +func KeyPacketAcknowledgement(portID, channelID string, sequence uint64) []byte { + return []byte(PacketAcknowledgementPath(portID, channelID, sequence)) +} From de156d3cdcf2372a41da21486adc01e67474fa4b Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 14 Oct 2019 13:32:17 +0200 Subject: [PATCH 284/378] implement packet ACK --- x/ibc/04-channel/keeper/keeper.go | 13 +++--- x/ibc/04-channel/keeper/packet.go | 69 ++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/x/ibc/04-channel/keeper/keeper.go b/x/ibc/04-channel/keeper/keeper.go index 73a6349f639f..c1411674442a 100644 --- a/x/ibc/04-channel/keeper/keeper.go +++ b/x/ibc/04-channel/keeper/keeper.go @@ -1,7 +1,7 @@ package keeper import ( - "enconding/binary" + "encoding/binary" "fmt" "github.com/tendermint/tendermint/libs/log" @@ -25,13 +25,16 @@ type Keeper struct { } // NewKeeper creates a new IBC channel Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType, ck types.ConnectionKeeper) Keeper { +func NewKeeper( + cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType, + clientKeeper types.ClientKeeper, connectionKeeper types.ConnectionKeeper) Keeper { return Keeper{ storeKey: key, cdc: cdc, codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/channel", prefix: []byte(types.SubModuleName + "/"), // "channel/" - connectionKeeper: ck, + clientKeeper: clientKeeper, + connectionKeeper: connectionKeeper, } } @@ -86,7 +89,7 @@ func (k Keeper) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) ( return 0, false } - return binary.BigEndian(bz), true + return binary.BigEndian.Uint64(bz), true } // SetNextSequenceSend sets a channel's next send sequence to the store @@ -104,7 +107,7 @@ func (k Keeper) GetNextSequenceRecv(ctx sdk.Context, portID, channelID string) ( return 0, false } - return binary.BigEndian(bz), true + return binary.BigEndian.Uint64(bz), true } // SetNextSequenceRecv sets a channel's next receive sequence to the store diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go index ca3e7b2c405a..73dde2984213 100644 --- a/x/ibc/04-channel/keeper/packet.go +++ b/x/ibc/04-channel/keeper/packet.go @@ -80,7 +80,7 @@ func (k Keeper) CleanupPacket( case types.UNORDERED: ok = k.connectionKeeper.VerifyMembership( ctx, connection, proofHeight, proof, - types.PacketAcknowledgementPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), + types.PacketAcknowledgementPath(packet.DestPort(), packet.DestChannel(), packet.Sequence()), acknowledgement, ) default: @@ -211,7 +211,7 @@ func (k Keeper) RecvPacket( if !k.connectionKeeper.VerifyMembership( ctx, connection, proofHeight, proof, - types.ChannelPath(packet.SourcePort(), packet.SourceChannel()), + types.PacketCommitmentPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), packet.Data(), // TODO: hash data ) { return nil, errors.New("counterparty channel doesn't match the expected one") @@ -240,3 +240,68 @@ func (k Keeper) RecvPacket( return packet, nil } + +// AcknowledgePacket is called by a module to process the acknowledgement of a +// packet previously sent by the calling module on a channel to a counterparty +// module on the counterparty chain. acknowledgePacket also cleans up the packet +// commitment, which is no longer necessary since the packet has been received +// and acted upon. +func (k Keeper) AcknowledgePacket( + ctx sdk.Context, + packet exported.PacketI, + acknowledgement []byte, + proof ics23.Proof, + proofHeight uint64, +) (exported.PacketI, error) { + channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) + if !found { + return nil, errors.New("channel not found") // TODO: sdk.Error + } + + if channel.State != types.OPEN { + return nil, errors.New("channel not open") // TODO: sdk.Error + } + + _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) + if !found { + return nil, errors.New("channel capability key not found") // TODO: sdk.Error + } + + // if !AuthenticateCapabilityKey(capabilityKey) { + // return errors.New("invalid capability key") // TODO: sdk.Error + // } + + // packet must come from the channel's counterparty + if packet.SourcePort() != channel.Counterparty.PortID { + return nil, errors.New("invalid packet source port") + } + + if packet.SourceChannel() != channel.Counterparty.ChannelID { + return nil, errors.New("invalid packet source channel") + } + + connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + if !found { + return nil, errors.New("connection not found") // TODO: ics03 sdk.Error + } + + if connection.State != ics03types.OPEN { + return nil, errors.New("connection is not open") // TODO: ics03 sdk.Error + } + + commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data + return nil, errors.New("packet hasn't been sent") + } + + if !k.connectionKeeper.VerifyMembership( + ctx, connection, proofHeight, proof, + types.PacketAcknowledgementPath(packet.DestPort(), packet.DestChannel(), packet.Sequence()), + acknowledgement, // TODO: hash ACK + ) { + return nil, errors.New("invalid acknowledgement on counterparty chain") // TODO: sdk.Error + } + + k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + return packet, nil +} From 9cc144738586a16e9759f8cba0fb6421c04ecb7f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 14 Oct 2019 14:58:08 +0200 Subject: [PATCH 285/378] update handler --- x/ibc/04-channel/cli.go | 136 ++++++------- x/ibc/04-channel/handler.go | 178 +++++++++++++++-- x/ibc/04-channel/types/codec.go | 8 +- x/ibc/04-channel/types/events.go | 20 +- x/ibc/04-channel/types/msgs.go | 186 ++++++++++++------ .../{ => types}/tests/channel_test.go | 6 +- x/ibc/04-channel/{ => types}/tests/types.go | 38 ++-- 7 files changed, 403 insertions(+), 169 deletions(-) rename x/ibc/04-channel/{ => types}/tests/channel_test.go (94%) rename x/ibc/04-channel/{ => types}/tests/types.go (82%) diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index 9e5d803d2fea..b03a9d8b2615 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -1,81 +1,81 @@ -package channel +package ics04 -import ( - "bytes" +// import ( +// "bytes" - "github.com/cosmos/cosmos-sdk/store/state" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" -) +// "github.com/cosmos/cosmos-sdk/store/state" +// "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" +// ) -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.State(connid)) - } - return obj -} +// 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.State(connid)) +// } +// return obj +// } -func (man Manager) CLIQuery(q state.ABCIQuerier, portid, chanid string) (obj State, err error) { - obj = man.object(portid, chanid) - channel, _, err := obj.ChannelCLI(q) - if err != nil { - return - } - for _, connid := range channel.ConnectionHops { - obj.Connections = append(obj.Connections, man.connection.State(connid)) - } - return -} +// func (man Manager) CLIQuery(q state.ABCIQuerier, portid, chanid string) (obj State, err error) { +// obj = man.object(portid, chanid) +// channel, _, err := obj.ChannelCLI(q) +// if err != nil { +// return +// } +// for _, connid := range channel.ConnectionHops { +// obj.Connections = append(obj.Connections, man.connection.State(connid)) +// } +// return +// } -func (obj State) prefix() []byte { - return bytes.Split(obj.Channel.KeyBytes(), LocalRoot())[0] -} +// func (obj State) prefix() []byte { +// return bytes.Split(obj.Channel.KeyBytes(), LocalRoot())[0] +// } -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 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 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 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 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 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 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 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 State) PacketCLI(q state.ABCIQuerier, index uint64) (res Packet, proof merkle.Proof, err error) { - packet := obj.Packets.Value(index) - tmproof, err := packet.Query(q, &res) - proof = merkle.NewProofFromValue(tmproof, obj.prefix(), packet) - return -} +// 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(q, &res) +// proof = merkle.NewProofFromValue(tmproof, obj.prefix(), packet) +// return +// } -func (man Handshaker) CLIQuery(q state.ABCIQuerier, portid, chanid string) (HandshakeState, error) { - obj, err := man.Manager.CLIQuery(q, portid, chanid) - if err != nil { - return HandshakeState{}, err - } - return man.createState(obj), nil -} +// func (man Handshaker) CLIQuery(q state.ABCIQuerier, portid, chanid string) (HandshakeState, error) { +// obj, err := man.Manager.CLIQuery(q, portid, chanid) +// if err != nil { +// return HandshakeState{}, err +// } +// return man.createState(obj), nil +// } -func (man Handshaker) CLIState(portid, chanid string, connids []string) HandshakeState { - return man.createState(man.Manager.CLIState(portid, chanid, connids)) -} +// func (man Handshaker) CLIState(portid, chanid string, connids []string) HandshakeState { +// return man.createState(man.Manager.CLIState(portid, chanid, connids)) +// } -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 -} +// 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/handler.go b/x/ibc/04-channel/handler.go index 0ef8f76a1bfd..2b324a955ae3 100644 --- a/x/ibc/04-channel/handler.go +++ b/x/ibc/04-channel/handler.go @@ -1,37 +1,181 @@ -package channel +package ics04 import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ) -func HandleMsgOpenInit(ctx sdk.Context, msg MsgOpenInit, man Handshaker) sdk.Result { - _, err := man.OpenInit(ctx, msg.PortID, msg.ChannelID, msg.Channel) +// NewHandler creates a new Handler instance for IBC connection +// transactions +func NewHandler(k keeper.Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + switch msg := msg.(type) { + case types.MsgChannelOpenInit: + return handleMsgChannelOpenInit(ctx, k, msg) + + case types.MsgChannelOpenTry: + return handleMsgChannelOpenTry(ctx, k, msg) + + case types.MsgChannelOpenAck: + return handleMsgChannelOpenAck(ctx, k, msg) + + case types.MsgChannelOpenConfirm: + return handleMsgChannelOpenConfirm(ctx, k, msg) + + case types.MsgChannelCloseInit: + return handleMsgChannelCloseInit(ctx, k, msg) + + case types.MsgChannelCloseConfirm: + return handleMsgChannelCloseConfirm(ctx, k, msg) + + default: + errMsg := fmt.Sprintf("unrecognized IBC connection message type: %T", msg) + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +func handleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenInit) sdk.Result { + _, err := k.ChanOpenInit( + ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, + msg.Channel.Counterparty, msg.Channel.Version, + ) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), 100, "").Result() + return sdk.ResultFromError(err) } - return sdk.Result{} + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelOpenInit, + sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} } -func HandleMsgOpenTry(ctx sdk.Context, msg MsgOpenTry, man Handshaker) sdk.Result { - _, err := man.OpenTry(ctx, msg.Proofs, msg.Height, msg.PortID, msg.ChannelID, msg.Channel) +func handleMsgChannelOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenTry) sdk.Result { + _, err := k.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, + msg.Channel.Counterparty, msg.Channel.Version, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, + ) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), 200, "").Result() + return sdk.ResultFromError(err) } - return sdk.Result{} + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelOpenTry, + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), // TODO: double check sender and receiver + sdk.NewAttribute(types.AttributeKeyReceiverPort, msg.Channel.Counterparty.PortID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} } -func HandleMsgOpenAck(ctx sdk.Context, msg MsgOpenAck, man Handshaker) sdk.Result { - _, err := man.OpenAck(ctx, msg.Proofs, msg.Height, msg.PortID, msg.ChannelID) +func handleMsgChannelOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenAck) sdk.Result { + err := k.ChanOpenAck( + ctx, msg.PortID, msg.ChannelID, msg.CounterpartyVersion, msg.ProofTry, msg.ProofHeight, + ) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), 300, "").Result() + return sdk.ResultFromError(err) } - return sdk.Result{} + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelOpenAck, + sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} +} + +func handleMsgChannelOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenConfirm) sdk.Result { + err := k.ChanOpenConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofAck, msg.ProofHeight) + if err != nil { + return sdk.ResultFromError(err) + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelOpenConfirm, + sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} } -func HandleMsgOpenConfirm(ctx sdk.Context, msg MsgOpenConfirm, man Handshaker) sdk.Result { - _, err := man.OpenConfirm(ctx, msg.Proofs, msg.Height, msg.PortID, msg.ChannelID) +func handleMsgChannelCloseInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseInit) sdk.Result { + err := k.ChanCloseInit(ctx, msg.PortID, msg.ChannelID) if err != nil { - return sdk.NewError(sdk.CodespaceType("ibc"), 400, "").Result() + return sdk.ResultFromError(err) } - return sdk.Result{} + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelCloseInit, + sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} +} + +func handleMsgChannelCloseConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseConfirm) sdk.Result { + err := k.ChanCloseConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofInit, msg.ProofHeight) + if err != nil { + return sdk.ResultFromError(err) + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelCloseConfirm, + sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} } diff --git a/x/ibc/04-channel/types/codec.go b/x/ibc/04-channel/types/codec.go index d0c98e2e71e4..99c0a14af18e 100644 --- a/x/ibc/04-channel/types/codec.go +++ b/x/ibc/04-channel/types/codec.go @@ -10,10 +10,10 @@ var SubModuleCdc *codec.Codec func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*exported.PacketI)(nil), nil) - cdc.RegisterConcrete(MsgChanOpenInit{}, "ibc/channel/MsgChanOpenInit", nil) - cdc.RegisterConcrete(MsgChanOpenTry{}, "ibc/channel/MsgChanOpenTry", nil) - cdc.RegisterConcrete(MsgChanOpenAck{}, "ibc/channel/MsgChanOpenAck", nil) - cdc.RegisterConcrete(MsgChanOpenConfirm{}, "ibc/channel/MsgChanOpenConfirm", nil) + cdc.RegisterConcrete(MsgChannelOpenInit{}, "ibc/channel/MsgChannelOpenInit", nil) + cdc.RegisterConcrete(MsgChannelOpenTry{}, "ibc/channel/MsgChannelOpenTry", nil) + cdc.RegisterConcrete(MsgChannelOpenAck{}, "ibc/channel/MsgChannelOpenAck", nil) + cdc.RegisterConcrete(MsgChannelOpenConfirm{}, "ibc/channel/MsgChannelOpenConfirm", nil) } func SetMsgChanCodec(cdc *codec.Codec) { diff --git a/x/ibc/04-channel/types/events.go b/x/ibc/04-channel/types/events.go index 96de0272b2bc..90d38b274aaf 100644 --- a/x/ibc/04-channel/types/events.go +++ b/x/ibc/04-channel/types/events.go @@ -1,10 +1,28 @@ package types +import ( + "fmt" + + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// IBC channel events const ( - EventTypeSendPacket = "send_packet" + EventTypeSendPacket = "send_packet" + EventTypeChannelOpenInit = "channel_open_init" + EventTypeChannelOpenTry = "channel_open_try" + EventTypeChannelOpenAck = "channel_open_ack" + EventTypeChannelOpenConfirm = "channel_open_confirm" + EventTypeChannelCloseInit = "channel_close_init" + EventTypeChannelCloseConfirm = "channel_close_confirm" AttributeKeySenderPort = "sender_port" AttributeKeyReceiverPort = "receiver_port" AttributeKeyChannelID = "channel_id" AttributeKeySequence = "sequence" ) + +// IBC channel events vars +var ( + AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, SubModuleName) +) diff --git a/x/ibc/04-channel/types/msgs.go b/x/ibc/04-channel/types/msgs.go index 116e6ecc6cb3..a425e7d9b36a 100644 --- a/x/ibc/04-channel/types/msgs.go +++ b/x/ibc/04-channel/types/msgs.go @@ -7,9 +7,9 @@ import ( ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) -var _ sdk.Msg = MsgChanOpenInit{} +var _ sdk.Msg = MsgChannelOpenInit{} -type MsgChanOpenInit struct { +type MsgChannelOpenInit struct { PortID string `json:"port_id"` ChannelID string `json:"channel_id"` Channel Channel `json:"channel"` @@ -17,165 +17,237 @@ type MsgChanOpenInit struct { } // Route implements sdk.Msg -func (msg MsgChanOpenInit) Route() string { +func (msg MsgChannelOpenInit) Route() string { return ibctypes.RouterKey } // Type implements sdk.Msg -func (msg MsgChanOpenInit) Type() string { - return "chan_open_init" +func (msg MsgChannelOpenInit) Type() string { + return "channel_open_init" } // ValidateBasic implements sdk.Msg -func (msg MsgChanOpenInit) ValidateBasic() sdk.Error { +func (msg MsgChannelOpenInit) ValidateBasic() sdk.Error { // TODO: return nil } // GetSignBytes implements sdk.Msg -func (msg MsgChanOpenInit) GetSignBytes() []byte { +func (msg MsgChannelOpenInit) GetSignBytes() []byte { return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) } // GetSigners implements sdk.Msg -func (msg MsgChanOpenInit) GetSigners() []sdk.AccAddress { +func (msg MsgChannelOpenInit) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } -var _ sdk.Msg = MsgChanOpenTry{} +var _ sdk.Msg = MsgChannelOpenTry{} -type MsgChanOpenTry struct { - PortID string `json:"port_id"` - ChannelID string `json:"channel_id"` - Channel Channel `json:"channel"` - Proofs []ics23.Proof `json:"proofs"` - Height uint64 `json:"height"` - Signer sdk.AccAddress `json:"signer"` +type MsgChannelOpenTry struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Channel Channel `json:"channel"` + CounterpartyVersion string `json:"counterparty_version"` + ProofInit ics23.Proof `json:"proof_init"` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` } // Route implements sdk.Msg -func (msg MsgChanOpenTry) Route() string { +func (msg MsgChannelOpenTry) Route() string { return ibctypes.RouterKey } // Type implements sdk.Msg -func (msg MsgChanOpenTry) Type() string { - return "chan_open_try" +func (msg MsgChannelOpenTry) Type() string { + return "channel_open_try" } // ValidateBasic implements sdk.Msg -func (msg MsgChanOpenTry) ValidateBasic() sdk.Error { +func (msg MsgChannelOpenTry) ValidateBasic() sdk.Error { // TODO: return nil } // GetSignBytes implements sdk.Msg -func (msg MsgChanOpenTry) GetSignBytes() []byte { +func (msg MsgChannelOpenTry) GetSignBytes() []byte { return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) } // GetSigners implements sdk.Msg -func (msg MsgChanOpenTry) GetSigners() []sdk.AccAddress { +func (msg MsgChannelOpenTry) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } -var _ sdk.Msg = MsgChanOpenAck{} +var _ sdk.Msg = MsgChannelOpenAck{} -type MsgChanOpenAck struct { - PortID string `json:"port_id"` - ChannelID string `json:"channel_id"` - Proofs []ics23.Proof `json:"proofs"` - Height uint64 `json:"height"` - Signer sdk.AccAddress `json:"signer"` +type MsgChannelOpenAck struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + CounterpartyVersion string `json:"counterparty_version"` + ProofTry ics23.Proof `json:"proof_try"` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` } // Route implements sdk.Msg -func (msg MsgChanOpenAck) Route() string { +func (msg MsgChannelOpenAck) Route() string { return ibctypes.RouterKey } // Type implements sdk.Msg -func (msg MsgChanOpenAck) Type() string { - return "chan_open_ack" +func (msg MsgChannelOpenAck) Type() string { + return "channel_open_ack" } // ValidateBasic implements sdk.Msg -func (msg MsgChanOpenAck) ValidateBasic() sdk.Error { +func (msg MsgChannelOpenAck) ValidateBasic() sdk.Error { // TODO: return nil } // GetSignBytes implements sdk.Msg -func (msg MsgChanOpenAck) GetSignBytes() []byte { +func (msg MsgChannelOpenAck) GetSignBytes() []byte { return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) } // GetSigners implements sdk.Msg -func (msg MsgChanOpenAck) GetSigners() []sdk.AccAddress { +func (msg MsgChannelOpenAck) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } -var _ sdk.Msg = MsgChanOpenConfirm{} +var _ sdk.Msg = MsgChannelOpenConfirm{} -type MsgChanOpenConfirm struct { +type MsgChannelOpenConfirm struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + ProofAck ics23.Proof `json:"proof_ack"` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` +} + +// Route implements sdk.Msg +func (msg MsgChannelOpenConfirm) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgChannelOpenConfirm) Type() string { + return "channel_open_confirm" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelOpenConfirm) ValidateBasic() sdk.Error { + // TODO: + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgChannelOpenConfirm) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgChannelOpenConfirm) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgChannelCloseInit{} + +type MsgChannelCloseInit struct { PortID string `json:"port_id"` ChannelID string `json:"channel_id"` - Proofs []ics23.Proof `json:"proofs"` - Height uint64 `json:"height"` Signer sdk.AccAddress `json:"signer"` } // Route implements sdk.Msg -func (msg MsgChanOpenConfirm) Route() string { +func (msg MsgChannelCloseInit) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgChannelCloseInit) Type() string { + return "channel_close_init" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgChannelCloseInit) ValidateBasic() sdk.Error { + // TODO: + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgChannelCloseInit) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgChannelCloseInit) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgChannelCloseConfirm{} + +type MsgChannelCloseConfirm struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + ProofInit ics23.Proof `json:"proof_init"` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` +} + +// Route implements sdk.Msg +func (msg MsgChannelCloseConfirm) Route() string { return ibctypes.RouterKey } // Type implements sdk.Msg -func (msg MsgChanOpenConfirm) Type() string { - return "chan_open_confirm" +func (msg MsgChannelCloseConfirm) Type() string { + return "channel_close_confirm" } // ValidateBasic implements sdk.Msg -func (msg MsgChanOpenConfirm) ValidateBasic() sdk.Error { +func (msg MsgChannelCloseConfirm) ValidateBasic() sdk.Error { // TODO: return nil } // GetSignBytes implements sdk.Msg -func (msg MsgChanOpenConfirm) GetSignBytes() []byte { +func (msg MsgChannelCloseConfirm) GetSignBytes() []byte { return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) } // GetSigners implements sdk.Msg -func (msg MsgChanOpenConfirm) GetSigners() []sdk.AccAddress { +func (msg MsgChannelCloseConfirm) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } -var _ sdk.Msg = MsgPacket{} +var _ sdk.Msg = MsgSendPacket{} -// MsgPacket PortID dependent on type -// ChannelID can be empty if batched & not first MsgPacket +// MsgSendPacket PortID dependent on type +// ChannelID can be empty if batched & not first MsgSendPacket // Height uint64 // height of the commitment root for the proofs -type MsgPacket struct { +type MsgSendPacket struct { Packet exported.PacketI `json:"packet" yaml:"packet"` - ChannelID string `json:"channel_id,omitempty" yaml:"channel_id"` + ChannelID string `json:"channel_id" yaml:"channel_id"` Proofs []ics23.Proof `json:"proofs" yaml:"proofs"` Height uint64 `json:"height" yaml:"height"` - Signer sdk.AccAddress `json:"signer,omitempty" yaml:"signer"` + Signer sdk.AccAddress `json:"signer" yaml:"signer"` } // Route implements sdk.Msg -func (msg MsgPacket) Route() string { +func (msg MsgSendPacket) Route() string { return ibctypes.RouterKey } // Type implements sdk.Msg -func (msg MsgPacket) Type() string { - return "packet" +func (msg MsgSendPacket) Type() string { + return "send_packet" } // ValidateBasic implements sdk.Msg -func (msg MsgPacket) ValidateBasic() sdk.Error { +func (msg MsgSendPacket) ValidateBasic() sdk.Error { // TODO: // Check PortID ChannelID len // Check packet != nil @@ -185,11 +257,11 @@ func (msg MsgPacket) ValidateBasic() sdk.Error { } // GetSignBytes implements sdk.Msg -func (msg MsgPacket) GetSignBytes() []byte { +func (msg MsgSendPacket) GetSignBytes() []byte { return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) } // GetSigners implements sdk.Msg -func (msg MsgPacket) GetSigners() []sdk.AccAddress { +func (msg MsgSendPacket) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } diff --git a/x/ibc/04-channel/tests/channel_test.go b/x/ibc/04-channel/types/tests/channel_test.go similarity index 94% rename from x/ibc/04-channel/tests/channel_test.go rename to x/ibc/04-channel/types/tests/channel_test.go index 1bd8edb8d443..3b5f676298b1 100644 --- a/x/ibc/04-channel/tests/channel_test.go +++ b/x/ibc/04-channel/types/tests/channel_test.go @@ -1,4 +1,4 @@ -package channel +package test import ( "testing" @@ -9,7 +9,7 @@ import ( client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" tmclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint" tendermint "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" - channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + ics04 "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/23-commitment/merkle" ) @@ -20,7 +20,7 @@ func registerCodec(cdc *codec.Codec) { commitment.RegisterCodec(cdc) merkle.RegisterCodec(cdc) codec.RegisterCrypto(cdc) - channel.RegisterCodec(cdc) + ics04.RegisterCodec(cdc) cdc.RegisterConcrete(MyPacket{}, "test/MyPacket", nil) } diff --git a/x/ibc/04-channel/tests/types.go b/x/ibc/04-channel/types/tests/types.go similarity index 82% rename from x/ibc/04-channel/tests/types.go rename to x/ibc/04-channel/types/tests/types.go index add562813d5e..8389934377a4 100644 --- a/x/ibc/04-channel/tests/types.go +++ b/x/ibc/04-channel/types/tests/types.go @@ -11,7 +11,7 @@ import ( tendermint "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/tests" - channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + ics04 "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -20,7 +20,7 @@ const PortName = "port-test" type Node struct { *connection.Node Counterparty *Node - Channel channel.Channel + Channel ics04.Channel Cdc *codec.Codec } @@ -36,13 +36,13 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { Cdc: cdc, } - res.Channel = channel.Channel{ + res.Channel = ics04.Channel{ Counterparty: res.Counterparty.Name, CounterpartyPort: PortName, ConnectionHops: []string{res.Name}, } - res.Counterparty.Channel = channel.Channel{ + res.Counterparty.Channel = ics04.Channel{ Counterparty: res.Name, CounterpartyPort: PortName, ConnectionHops: []string{res.Counterparty.Name}, @@ -51,18 +51,18 @@ func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { return res } -func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Context, channel.Handshaker) { +func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Context, ics04.Handshaker) { ctx := node.Context() store, err := commitment.NewStore(node.Counterparty.Root(), node.Counterparty.Prefix(), proofs) require.NoError(t, err) ctx = commitment.WithStore(ctx, store) man := node.Manager() - return ctx, channel.NewHandshaker(man) + return ctx, ics04.NewHandshaker(man) } -func (node *Node) CLIState() channel.HandshakeState { +func (node *Node) CLIState() ics04.HandshakeState { man := node.Manager() - return channel.NewHandshaker(man).CLIState(PortName, node.Name, []string{node.Name}) + return ics04.NewHandshaker(man).CLIState(PortName, node.Name, []string{node.Name}) } func base(cdc *codec.Codec, key sdk.StoreKey) (state.Mapping, state.Mapping) { @@ -71,17 +71,17 @@ func base(cdc *codec.Codec, key sdk.StoreKey) (state.Mapping, state.Mapping) { return protocol, free } -func (node *Node) Manager() channel.Manager { +func (node *Node) Manager() ics04.Manager { protocol, _ := base(node.Cdc, node.Key) _, connman := node.Node.Manager() - return channel.NewManager(protocol, connman) + return ics04.NewManager(protocol, connman) } func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) obj, err := man.OpenInit(ctx, PortName, node.Name, node.Channel) require.NoError(t, err) - require.Equal(t, channel.Init, obj.Stage.Get(ctx)) + require.Equal(t, ics04.Init, obj.Stage.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) require.False(t, obj.Available.Get(ctx)) } @@ -90,30 +90,30 @@ func (node *Node) OpenTry(t *testing.T, height uint64, proofs ...commitment.Proo ctx, man := node.Handshaker(t, proofs) obj, err := man.OpenTry(ctx, proofs, height, PortName, node.Name, node.Channel) require.NoError(t, err) - require.Equal(t, channel.OpenTry, obj.Stage.Get(ctx)) + require.Equal(t, ics04.OpenTry, obj.Stage.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) require.False(t, obj.Available.Get(ctx)) - node.SetState(channel.OpenTry) + node.SetState(ics04.OpenTry) } func (node *Node) OpenAck(t *testing.T, height uint64, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) obj, err := man.OpenAck(ctx, proofs, height, PortName, node.Name) require.NoError(t, err) - require.Equal(t, channel.Open, obj.Stage.Get(ctx)) + require.Equal(t, ics04.Open, obj.Stage.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) require.True(t, obj.Available.Get(ctx)) - node.SetState(channel.Open) + node.SetState(ics04.Open) } func (node *Node) OpenConfirm(t *testing.T, height uint64, proofs ...commitment.Proof) { ctx, man := node.Handshaker(t, proofs) obj, err := man.OpenConfirm(ctx, proofs, height, PortName, node.Name) require.NoError(t, err) - require.Equal(t, channel.Open, obj.Stage.Get(ctx)) + require.Equal(t, ics04.Open, obj.Stage.Get(ctx)) require.Equal(t, node.Channel, obj.GetChannel(ctx)) require.True(t, obj.Available.Get(ctx)) - node.SetState(channel.CloseTry) + node.SetState(ics04.CloseTry) } func (node *Node) Handshake(t *testing.T) { @@ -146,7 +146,7 @@ func (node *Node) Handshake(t *testing.T) { node.Counterparty.OpenConfirm(t, uint64(header.Height), pstate) } -func (node *Node) Send(t *testing.T, packet channel.Packet) { +func (node *Node) Send(t *testing.T, packet ics04.Packet) { ctx, man := node.Context(), node.Manager() obj, err := man.Query(ctx, PortName, node.Name) require.NoError(t, err) @@ -157,7 +157,7 @@ func (node *Node) Send(t *testing.T, packet channel.Packet) { require.Equal(t, node.Cdc.MustMarshalBinaryBare(packet), obj.PacketCommit(ctx, seq+1)) } -func (node *Node) Receive(t *testing.T, packet channel.Packet, height uint64, proofs ...commitment.Proof) { +func (node *Node) Receive(t *testing.T, packet ics04.Packet, height uint64, proofs ...commitment.Proof) { ctx, man := node.Context(), node.Manager() obj, err := man.Query(ctx, PortName, node.Name) require.NoError(t, err) From bb4c55146647543b2e6e85457615cad8d51bd20c Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 14 Oct 2019 15:33:12 +0200 Subject: [PATCH 286/378] add channel errors --- x/ibc/04-channel/client/utils/types.go | 65 -------------------------- x/ibc/04-channel/keeper/handshake.go | 65 +++++++++----------------- x/ibc/04-channel/keeper/packet.go | 32 ++++++------- x/ibc/04-channel/keeper/timeout.go | 17 +++---- x/ibc/04-channel/types/errors.go | 53 ++++++++++++++++++++- 5 files changed, 100 insertions(+), 132 deletions(-) delete mode 100644 x/ibc/04-channel/client/utils/types.go diff --git a/x/ibc/04-channel/client/utils/types.go b/x/ibc/04-channel/client/utils/types.go deleted file mode 100644 index 579cead225c8..000000000000 --- a/x/ibc/04-channel/client/utils/types.go +++ /dev/null @@ -1,65 +0,0 @@ -package utils - -import ( - channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -type JSONState struct { - Channel channel.Channel `json:"channel"` - ChannelProof commitment.Proof `json:"channel_proof,omitempty"` - Available bool `json:"available"` - AvailableProof commitment.Proof `json:"available_proof,omitempty"` - SequenceSend uint64 `json:"sequence_send"` - SequenceSendProof commitment.Proof `json:"sequence_send_proof,omitempty"` - SequenceReceive uint64 `json:"sequence_receive"` - SequenceReceiveProof commitment.Proof `json:"sequence_receive_proof,omitempty"` - // Kind string `json:"kind"` - // KindProof commitment.Proof `json:"kind_proof,omitempty"` -} - -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, -) JSONState { - return JSONState{ - Channel: channel, - ChannelProof: channelp, - Available: avail, - AvailableProof: availp, - // Kind: kind, - // KindProof: kindp, - } -} - -type HandshakeJSONState struct { - JSONState `json:"channel"` - 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 NewHandshakeJSONState( - 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, - - state byte, statep commitment.Proof, - timeout uint64, timeoutp commitment.Proof, -) HandshakeJSONState { - return HandshakeJSONState{ - JSONState: NewJSONState(channel, channelp, avail, availp, seqsend, seqsendp, seqrecv, seqrecvp), - State: state, - StateProof: statep, - NextTimeout: timeout, - NextTimeoutProof: timeoutp, - } -} diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go index ab0084f45dc5..9d7c07cdc843 100644 --- a/x/ibc/04-channel/keeper/handshake.go +++ b/x/ibc/04-channel/keeper/handshake.go @@ -22,17 +22,17 @@ func (k Keeper) ChanOpenInit( ) (string, error) { // TODO: abortTransactionUnless(validateChannelIdentifier(portIdentifier, channelIdentifier)) if len(connectionHops) != 1 { - return "", errors.New("connection hops length must be 1") // TODO: sdk.Error + return "", types.ErrInvalidConnectionHops(k.codespace) } _, found := k.GetChannel(ctx, portID, channelID) if found { - return "", errors.New("channel already exists") // TODO: sdk.Error + return "", types.ErrChannelExists(k.codespace) } connection, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) if !found { - return "", errors.New("connection not found") // TODO: ics03 sdk.Error + return "", ics03types.ErrConnectionNotFound(k.codespace) } // TODO: inconsistency on ICS03 (`none`) and ICS04 (`CLOSED`) @@ -77,12 +77,12 @@ func (k Keeper) ChanOpenTry( ) (string, error) { if len(connectionHops) != 1 { - return "", errors.New("ConnectionHops length must be 1") + return "", types.ErrInvalidConnectionHops(k.codespace) } _, found := k.GetChannel(ctx, portID, channelID) if found { - return "", errors.New("channel already exists") // TODO: sdk.Error + return "", types.ErrChannelExists(k.codespace) } // TODO: Blocked - ICS05 Not implemented yet @@ -97,7 +97,7 @@ func (k Keeper) ChanOpenTry( connection, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) if !found { - return "", errors.New("connection not found") // TODO: ics03 sdk.Error + return "", ics03types.ErrConnectionNotFound(k.codespace) } if connection.State != ics03types.OPEN { @@ -126,19 +126,8 @@ func (k Keeper) ChanOpenTry( types.ChannelPath(counterparty.PortID, counterparty.ChannelID), bz, ) { - return "", errors.New("counterparty channel doesn't match the expected one") - } - - // TODO: - // if !connection.verifyMembership( - // proofHeight, - // proofInit, - // channelPath(counterpartyPortIdentifier, counterpartyChannelIdentifier), - // Channel{INIT, order, portIdentifier, - // channelIdentifier, channel.CounterpartyHops(), counterpartyVersion} - // ) { - // return err - // } + return "", types.ErrInvalidCounterpartyChannel(k.codespace) + } k.SetChannel(ctx, portID, channelID, channel) @@ -163,7 +152,7 @@ func (k Keeper) ChanOpenAck( channel, found := k.GetChannel(ctx, portID, channelID) if !found { - return errors.New("channel not found") // TODO: sdk.Error + return types.ErrChannelNotFound(k.codespace) } if channel.State != types.INIT { @@ -172,7 +161,7 @@ func (k Keeper) ChanOpenAck( _, found = k.GetChannelCapability(ctx, portID, channelID) if !found { - return errors.New("channel capability key not found") // TODO: sdk.Error + return types.ErrChannelCapabilityNotFound(k.codespace) } // if !AuthenticateCapabilityKey(capabilityKey) { @@ -181,7 +170,7 @@ func (k Keeper) ChanOpenAck( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return errors.New("connection not found") // TODO: ics03 sdk.Error + return ics03types.ErrConnectionNotFound(k.codespace) } if connection.State != ics03types.OPEN { @@ -205,7 +194,7 @@ func (k Keeper) ChanOpenAck( types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), bz, ) { - return errors.New("counterparty channel doesn't match the expected one") + return types.ErrInvalidCounterpartyChannel(k.codespace) } channel.State = types.OPEN @@ -226,7 +215,7 @@ func (k Keeper) ChanOpenConfirm( ) error { channel, found := k.GetChannel(ctx, portID, channelID) if !found { - return errors.New("channel not found") // TODO: sdk.Error + return types.ErrChannelNotFound(k.codespace) } if channel.State != types.OPENTRY { @@ -235,7 +224,7 @@ func (k Keeper) ChanOpenConfirm( _, found = k.GetChannelCapability(ctx, portID, channelID) if !found { - return errors.New("channel capability key not found") // TODO: sdk.Error + return types.ErrChannelCapabilityNotFound(k.codespace) } // if !AuthenticateCapabilityKey(capabilityKey) { @@ -244,7 +233,7 @@ func (k Keeper) ChanOpenConfirm( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return errors.New("connection not found") // TODO: ics03 sdk.Error + return ics03types.ErrConnectionNotFound(k.codespace) } if connection.State != ics03types.OPEN { @@ -267,7 +256,7 @@ func (k Keeper) ChanOpenConfirm( types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), bz, ) { - return errors.New("counterparty channel doesn't match the expected one") + return types.ErrInvalidCounterpartyChannel(k.codespace) } channel.State = types.OPEN @@ -286,7 +275,7 @@ func (k Keeper) ChanOpenConfirm( func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error { _, found := k.GetChannelCapability(ctx, portID, channelID) if !found { - return errors.New("channel capability key not found") // TODO: sdk.Error + return types.ErrChannelCapabilityNotFound(k.codespace) } // if !AuthenticateCapabilityKey(capabilityKey) { @@ -295,7 +284,7 @@ func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error { channel, found := k.GetChannel(ctx, portID, channelID) if !found { - return errors.New("channel not found") // TODO: sdk.Error + return types.ErrChannelNotFound(k.codespace) } if channel.State == types.CLOSED { @@ -304,7 +293,7 @@ func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error { connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return errors.New("connection not found") // TODO: ics03 sdk.Error + return ics03types.ErrConnectionNotFound(k.codespace) } if connection.State != ics03types.OPEN { @@ -328,7 +317,7 @@ func (k Keeper) ChanCloseConfirm( ) error { _, found := k.GetChannelCapability(ctx, portID, channelID) if !found { - return errors.New("channel capability key not found") // TODO: sdk.Error + return types.ErrChannelCapabilityNotFound(k.codespace) } // if !AuthenticateCapabilityKey(capabilityKey) { @@ -337,7 +326,7 @@ func (k Keeper) ChanCloseConfirm( channel, found := k.GetChannel(ctx, portID, channelID) if !found { - return errors.New("channel not found") // TODO: sdk.Error + return types.ErrChannelNotFound(k.codespace) } if channel.State == types.CLOSED { @@ -346,7 +335,7 @@ func (k Keeper) ChanCloseConfirm( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return errors.New("connection not found") // TODO: ics03 sdk.Error + return ics03types.ErrConnectionNotFound(k.codespace) } if connection.State != ics03types.OPEN { @@ -369,7 +358,7 @@ func (k Keeper) ChanCloseConfirm( types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), bz, ) { - return errors.New("counterparty channel doesn't match the expected one") + return types.ErrInvalidCounterpartyChannel(k.codespace) } channel.State = types.CLOSED @@ -377,11 +366,3 @@ func (k Keeper) ChanCloseConfirm( return nil } - -func assertTimeout(ctx sdk.Context, timeoutHeight uint64) error { - if uint64(ctx.BlockHeight()) > timeoutHeight { - return errors.New("timeout") - } - - return nil -} diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go index 73dde2984213..3fbd2dfe935c 100644 --- a/x/ibc/04-channel/keeper/packet.go +++ b/x/ibc/04-channel/keeper/packet.go @@ -31,7 +31,7 @@ func (k Keeper) CleanupPacket( ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, errors.New("channel not found") // TODO: sdk.Error + return nil, types.ErrChannelNotFound(k.codespace) } if channel.State != types.OPEN { @@ -40,7 +40,7 @@ func (k Keeper) CleanupPacket( _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, errors.New("channel capability key not found") // TODO: sdk.Error + return nil, types.ErrChannelCapabilityNotFound(k.codespace) } // if !AuthenticateCapabilityKey(capabilityKey) { @@ -53,7 +53,7 @@ func (k Keeper) CleanupPacket( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, errors.New("connection not found") // TODO: ics03 sdk.Error + return nil, ics03types.ErrConnectionNotFound(k.codespace) } if packet.DestPort() != channel.Counterparty.PortID { @@ -140,16 +140,16 @@ func (k Keeper) SendPacket(ctx sdk.Context, packet exported.PacketI) error { } if consensusState.GetHeight() >= packet.TimeoutHeight() { - return errors.New("invalid height") // TODO: sdk.Error + return types.ErrPacketTimeout(k.codespace) } nextSequenceSend, found := k.GetNextSequenceSend(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return errors.New("next seq send counter not found") // TODO: sdk.Error + return types.ErrSequenceNotFound(k.codespace, "send") } if packet.Sequence() != nextSequenceSend { - return errors.New("invalid packet sequence") + return types.ErrInvalidPacketSequence(k.codespace) } nextSequenceSend++ @@ -171,7 +171,7 @@ func (k Keeper) RecvPacket( channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, errors.New("channel not found") // TODO: sdk.Error + return nil, types.ErrChannelNotFound(k.codespace) } if channel.State != types.OPEN { @@ -180,7 +180,7 @@ func (k Keeper) RecvPacket( _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, errors.New("channel capability key not found") // TODO: sdk.Error + return nil, types.ErrChannelCapabilityNotFound(k.codespace) } // if !AuthenticateCapabilityKey(capabilityKey) { @@ -198,7 +198,7 @@ func (k Keeper) RecvPacket( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, errors.New("connection not found") // TODO: ics03 sdk.Error + return nil, ics03types.ErrConnectionNotFound(k.codespace) } if connection.State != ics03types.OPEN { @@ -206,7 +206,7 @@ func (k Keeper) RecvPacket( } if uint64(ctx.BlockHeight()) >= packet.TimeoutHeight() { - return nil, errors.New("packet receive timeout") + return nil, types.ErrPacketTimeout(k.codespace) } if !k.connectionKeeper.VerifyMembership( @@ -214,7 +214,7 @@ func (k Keeper) RecvPacket( types.PacketCommitmentPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), packet.Data(), // TODO: hash data ) { - return nil, errors.New("counterparty channel doesn't match the expected one") + return nil, errors.New("couldn't verify counterparty packet commitment") } if len(acknowledgement) > 0 || channel.Ordering == types.UNORDERED { @@ -227,11 +227,11 @@ func (k Keeper) RecvPacket( if channel.Ordering == types.ORDERED { nextSequenceRecv, found := k.GetNextSequenceRecv(ctx, packet.DestPort(), packet.DestChannel()) if !found { - return nil, errors.New("next seq receive counter not found") // TODO: sdk.Error + return nil, types.ErrSequenceNotFound(k.codespace, "receive") } if packet.Sequence() != nextSequenceRecv { - return nil, errors.New("invalid packet sequence") + return nil, types.ErrInvalidPacketSequence(k.codespace) } nextSequenceRecv++ @@ -255,7 +255,7 @@ func (k Keeper) AcknowledgePacket( ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, errors.New("channel not found") // TODO: sdk.Error + return nil, types.ErrChannelNotFound(k.codespace) } if channel.State != types.OPEN { @@ -264,7 +264,7 @@ func (k Keeper) AcknowledgePacket( _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, errors.New("channel capability key not found") // TODO: sdk.Error + return nil, types.ErrChannelCapabilityNotFound(k.codespace) } // if !AuthenticateCapabilityKey(capabilityKey) { @@ -282,7 +282,7 @@ func (k Keeper) AcknowledgePacket( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, errors.New("connection not found") // TODO: ics03 sdk.Error + return nil, ics03types.ErrConnectionNotFound(k.codespace) } if connection.State != ics03types.OPEN { diff --git a/x/ibc/04-channel/keeper/timeout.go b/x/ibc/04-channel/keeper/timeout.go index 54bec7120af9..0c0962245bca 100644 --- a/x/ibc/04-channel/keeper/timeout.go +++ b/x/ibc/04-channel/keeper/timeout.go @@ -5,6 +5,7 @@ import ( "errors" sdk "github.com/cosmos/cosmos-sdk/types" + ics03types "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" @@ -24,7 +25,7 @@ func (k Keeper) TimoutPacket( ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, errors.New("channel not found") // TODO: sdk.Error + return nil, types.ErrChannelNotFound(k.codespace) } if channel.State != types.OPEN { @@ -33,7 +34,7 @@ func (k Keeper) TimoutPacket( _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, errors.New("channel capability key not found") // TODO: sdk.Error + return nil, types.ErrChannelCapabilityNotFound(k.codespace) } // if !AuthenticateCapabilityKey(capabilityKey) { @@ -46,7 +47,7 @@ func (k Keeper) TimoutPacket( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, errors.New("connection not found") // TODO: ics03 sdk.Error + return nil, ics03types.ErrConnectionNotFound(k.codespace) } if packet.DestPort() != channel.Counterparty.PortID { @@ -54,7 +55,7 @@ func (k Keeper) TimoutPacket( } if proofHeight < packet.TimeoutHeight() { - return nil, errors.New("timeout on counterparty connection end") + return nil, types.ErrPacketTimeout(k.codespace) } if nextSequenceRecv >= packet.Sequence() { @@ -109,12 +110,12 @@ func (k Keeper) TimeoutOnClose( ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, errors.New("channel not found") // TODO: sdk.Error + return nil, types.ErrChannelNotFound(k.codespace) } _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, errors.New("channel capability key not found") // TODO: sdk.Error + return nil, types.ErrChannelCapabilityNotFound(k.codespace) } // if !AuthenticateCapabilityKey(capabilityKey) { @@ -127,7 +128,7 @@ func (k Keeper) TimeoutOnClose( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, errors.New("connection not found") // TODO: ics03 sdk.Error + return nil, ics03types.ErrConnectionNotFound(k.codespace) } if packet.DestPort() != channel.Counterparty.PortID { @@ -158,7 +159,7 @@ func (k Keeper) TimeoutOnClose( types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), bz, ) { - return nil, errors.New("counterparty channel doesn't match the expected one") + return nil, types.ErrInvalidCounterpartyChannel(k.codespace) } if !k.connectionKeeper.VerifyNonMembership( diff --git a/x/ibc/04-channel/types/errors.go b/x/ibc/04-channel/types/errors.go index a1cefd783c40..1c5bb10f19ea 100644 --- a/x/ibc/04-channel/types/errors.go +++ b/x/ibc/04-channel/types/errors.go @@ -1,10 +1,61 @@ package types import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" ) -// connection error codes +// channel error codes const ( DefaultCodespace sdk.CodespaceType = SubModuleName + + CodeChannelExists sdk.CodeType = 101 + CodeChannelNotFound sdk.CodeType = 102 + CodeInvalidConnectionHops sdk.CodeType = 103 + CodeInvalidCounterpartyChannel sdk.CodeType = 104 + CodeChannelCapabilityNotFound sdk.CodeType = 105 + CodeInvalidPacketSequence sdk.CodeType = 106 + CodeSequenceNotFound sdk.CodeType = 107 + CodePacketTimeout sdk.CodeType = 108 ) + +// ErrChannelExists implements sdk.Error +func ErrChannelExists(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeChannelExists, "channel already exists") +} + +// ErrChannelNotFound implements sdk.Error +func ErrChannelNotFound(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeChannelNotFound, "channel not found") +} + +// ErrInvalidConnectionHops implements sdk.Error +func ErrInvalidConnectionHops(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidConnectionHops, "IBC v1 only supports one connection hop") +} + +// ErrInvalidCounterpartyChannel implements sdk.Error +func ErrInvalidCounterpartyChannel(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidCounterpartyChannel, "counterparty channel doesn't match the expected one") +} + +// ErrChannelCapabilityNotFound implements sdk.Error +func ErrChannelCapabilityNotFound(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeChannelCapabilityNotFound, "channel capability key not found") +} + +// ErrInvalidPacketSequence implements sdk.Error +func ErrInvalidPacketSequence(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidPacketSequence, "invalid packet sequence counter") +} + +// ErrSequenceNotFound implements sdk.Error +func ErrSequenceNotFound(codespace sdk.CodespaceType, seqType string) sdk.Error { + return sdk.NewError(codespace, CodeSequenceNotFound, fmt.Sprintf("next %s sequence counter not found", seqType)) +} + +// ErrPacketTimeout implements sdk.Error +func ErrPacketTimeout(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodePacketTimeout, "packet timeout") +} From 4c50d4febbcbec785aaa0b9b3d64cec75ae7c6f8 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 14 Oct 2019 15:53:39 +0200 Subject: [PATCH 287/378] channel querier --- x/ibc/04-channel/client/cli/query.go | 135 ++--- x/ibc/04-channel/client/cli/tx.go | 832 +++++++++++++-------------- x/ibc/04-channel/keeper/querier.go | 44 ++ x/ibc/04-channel/types/codec.go | 2 + x/ibc/04-channel/types/keys.go | 2 +- x/ibc/04-channel/types/querier.go | 21 + 6 files changed, 493 insertions(+), 543 deletions(-) create mode 100644 x/ibc/04-channel/keeper/querier.go create mode 100644 x/ibc/04-channel/types/querier.go diff --git a/x/ibc/04-channel/client/cli/query.go b/x/ibc/04-channel/client/cli/query.go index aad646c24047..972a33d3e33f 100644 --- a/x/ibc/04-channel/client/cli/query.go +++ b/x/ibc/04-channel/client/cli/query.go @@ -2,141 +2,74 @@ package cli import ( "fmt" + "strings" "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" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ) -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.CLIQuery(state.NewCLIQuerier(ctx), portid, chanid) -} +// TODO: get proofs +// const ( +// FlagProve = "prove" +// ) +// GetQueryCmd returns the query commands for IBC channels func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - ibcQueryCmd := &cobra.Command{ + ics04ChannelQueryCmd := &cobra.Command{ Use: "channel", - Short: "Channel query subcommands", + Short: "IBC channel query subcommands", DisableFlagParsing: true, } - ibcQueryCmd.AddCommand(cli.GetCommands( + ics04ChannelQueryCmd.AddCommand(cli.GetCommands( GetCmdQueryChannel(storeKey, cdc), )...) - return ibcQueryCmd -} - -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(q) - if err != nil { - return - } - - seqsend, seqsendp, err := obj.SeqSendCLI(q) - if err != nil { - return - } - - seqrecv, seqrecvp, err := obj.SeqRecvCLI(q) - if err != nil { - return - } - - if prove { - return utils.NewJSONState( - conn, connp, - avail, availp, - // kind, kindp, - seqsend, seqsendp, - seqrecv, seqrecvp, - ), nil - } - - return utils.NewJSONState( - conn, nil, - avail, nil, - seqsend, nil, - seqrecv, nil, - ), nil + return ics04ChannelQueryCmd } +// GetCmdQueryChannel defines the command to query a channel end func GetCmdQueryChannel(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "channel", + Use: "end [port-id] [channel-id]", Short: "Query stored connection", - Args: cobra.ExactArgs(2), + Long: strings.TrimSpace(fmt.Sprintf(`Query stored connection end + +Example: +$ %s query ibc channel end [port-id] [channel-id] + `, version.ClientName), + ), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.NewCLIContext().WithCodec(cdc) - obj, err := object(ctx, cdc, storeKey, version.DefaultPrefix(), args[0], args[1]) + cliCtx := context.NewCLIContext().WithCodec(cdc) + portID := args[0] + channelID := args[1] + + bz, err := cdc.MarshalJSON(types.NewQueryChannelParams(portID, channelID)) if err != nil { return err } - jsonobj, err := QueryChannel(ctx, obj, viper.GetBool(FlagProve)) + + res, _, err := cliCtx.QueryWithData(types.ChannelPath(portID, channelID), bz) if err != nil { return err } - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, jsonobj)) + var channel types.Channel + if err := cdc.UnmarshalJSON(res, &channel); err != nil { + return err + } - return nil + return cliCtx.PrintOutput(channel) }, } - cmd.Flags().Bool(FlagProve, false, "(optional) show proofs for the query results") + // cmd.Flags().Bool(FlagProve, false, "(optional) show proofs for the query results") 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 7a8dfc792d57..3937fa9818c0 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -1,443 +1,393 @@ package cli -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" - FlagFrom1 = "from1" - FlagFrom2 = "from2" -) - -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(q, portid, chanid) -} - -// 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 - } - - 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(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.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). - WithCodec(cdc). - WithNodeURI(viper.GetString(FlagNode1)). - WithBroadcastMode(flags.BroadcastBlock) - q1 := state.NewCLIQuerier(ctx1) - - ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). - WithCodec(cdc). - WithNodeURI(viper.GetString(FlagNode2)). - 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}, - } - - chan2 := channel.Channel{ - Counterparty: chanid1, - CounterpartyPort: portid1, - ConnectionHops: []string{connid2}, - } - - 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 - } - clientid1 := conn1.Client - - conn2, _, err := obj2.OriginConnection().ConnectionCLI(q2) - if err != nil { - return err - } - clientid2 := conn2.Client - - // TODO: check state and if not Idle continue existing process - msginit := channel.MsgOpenInit{ - PortID: portid1, - ChannelID: chanid1, - Channel: chan1, - Signer: ctx1.GetFromAddress(), - } - - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msginit}) - if err != nil { - return err - } - - // 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 - } - - msgupdate := client.MsgUpdateClient{ - ClientID: clientid2, - Header: header, - Signer: ctx2.GetFromAddress(), - } - - 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 - } - _, pstate, err := obj1.StageCLI(q1) - if err != nil { - return err - } - - msgtry := channel.MsgOpenTry{ - 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}) - if err != nil { - return err - } - - // 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 - } - - msgupdate = client.MsgUpdateClient{ - ClientID: clientid1, - Header: header, - Signer: ctx1.GetFromAddress(), - } - - 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 - } - _, pstate, err = obj2.StageCLI(q2) - if err != nil { - return err - } - - msgack := channel.MsgOpenAck{ - PortID: portid1, - ChannelID: chanid1, - Proofs: []commitment.Proof{pchan, pstate}, - Height: uint64(header.Height), - Signer: ctx1.GetFromAddress(), - } - - err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgack}) - if err != nil { - return err - } - - // 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 - } - - 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{ - PortID: portid2, - ChannelID: chanid2, - Proofs: []commitment.Proof{pstate}, - Height: uint64(header.Height), - Signer: ctx2.GetFromAddress(), - } - - err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgconfirm}) - if err != nil { - return err - } - - 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 -} - -func GetCmdFlushPackets(storeKey string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "flush", - Short: "flush packets on queue", - Args: cobra.ExactArgs(2), - // Args: []string{portid, chanid} - RunE: func(cmd *cobra.Command, args []string) error { - txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - ctx1 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). - WithCodec(cdc). - WithNodeURI(viper.GetString(FlagNode1)). - WithBroadcastMode(flags.BroadcastBlock) - q1 := state.NewCLIQuerier(ctx1) - - ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). - WithCodec(cdc). - WithNodeURI(viper.GetString(FlagNode2)). - WithBroadcastMode(flags.BroadcastBlock) - q2 := state.NewCLIQuerier(ctx2) - - portid1, chanid1 := args[0], args[1] - - obj1, err := flush(q1, cdc, storeKey, version.DefaultPrefix(), portid1, chanid1) - if err != nil { - return err - } - - chan1, _, err := obj1.ChannelCLI(q1) - if err != nil { - return err - } - - portid2, chanid2 := chan1.CounterpartyPort, chan1.Counterparty - - obj2, err := flush(q2, cdc, storeKey, version.DefaultPrefix(), portid2, chanid2) - if err != nil { - return err - } - - chan2, _, err := obj2.ChannelCLI(q2) - if err != nil { - return err - } - - connobj2, err := conn(q2, cdc, storeKey, version.DefaultPrefix(), chan2.ConnectionHops[0]) - if err != nil { - return err - } - - conn2, _, err := connobj2.ConnectionCLI(q2) - if err != nil { - return err - } - - client2 := conn2.Client - - 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 - }, - } - - 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 - -} +// import ( +// "errors" +// "fmt" +// "time" + +// "github.com/spf13/cobra" +// "github.com/spf13/viper" + +// "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" +// connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" +// ics04 "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" +// FlagFrom1 = "from1" +// FlagFrom2 = "from2" +// ) + +// 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(q, portid, chanid) +// } + +// 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 +// } + +// func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { +// cmd := &cobra.Command{ +// Use: "handshake", +// 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.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). +// WithCodec(cdc). +// WithNodeURI(viper.GetString(FlagNode1)). +// WithBroadcastMode(flags.BroadcastBlock) +// q1 := state.NewCLIQuerier(ctx1) + +// ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). +// WithCodec(cdc). +// WithNodeURI(viper.GetString(FlagNode2)). +// 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}, +// } + +// chan2 := channel.Channel{ +// Counterparty: chanid1, +// CounterpartyPort: portid1, +// ConnectionHops: []string{connid2}, +// } + +// 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 +// } +// clientid1 := conn1.Client + +// conn2, _, err := obj2.OriginConnection().ConnectionCLI(q2) +// if err != nil { +// return err +// } +// clientid2 := conn2.Client + +// // TODO: check state and if not Idle continue existing process +// msginit := channel.MsgOpenInit{ +// PortID: portid1, +// ChannelID: chanid1, +// Channel: chan1, +// Signer: ctx1.GetFromAddress(), +// } + +// err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msginit}) +// if err != nil { +// return err +// } + +// // 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 +// } + +// msgupdate := client.MsgUpdateClient{ +// ClientID: clientid2, +// Header: header, +// Signer: ctx2.GetFromAddress(), +// } + +// 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 +// } +// _, pstate, err := obj1.StageCLI(q1) +// if err != nil { +// return err +// } + +// msgtry := channel.MsgOpenTry{ +// 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}) +// if err != nil { +// return err +// } + +// // 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 +// } + +// msgupdate = client.MsgUpdateClient{ +// ClientID: clientid1, +// Header: header, +// Signer: ctx1.GetFromAddress(), +// } + +// 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 +// } +// _, pstate, err = obj2.StageCLI(q2) +// if err != nil { +// return err +// } + +// msgack := channel.MsgOpenAck{ +// PortID: portid1, +// ChannelID: chanid1, +// Proofs: []commitment.Proof{pchan, pstate}, +// Height: uint64(header.Height), +// Signer: ctx1.GetFromAddress(), +// } + +// err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgack}) +// if err != nil { +// return err +// } + +// // 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 +// } + +// 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{ +// PortID: portid2, +// ChannelID: chanid2, +// Proofs: []commitment.Proof{pstate}, +// Height: uint64(header.Height), +// Signer: ctx2.GetFromAddress(), +// } + +// err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgconfirm}) +// if err != nil { +// return err +// } + +// 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 +// } + +// func GetCmdFlushPackets(storeKey string, cdc *codec.Codec) *cobra.Command { +// cmd := &cobra.Command{ +// Use: "flush", +// Short: "flush packets on queue", +// Args: cobra.ExactArgs(2), +// // Args: []string{portid, chanid} +// RunE: func(cmd *cobra.Command, args []string) error { +// txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) +// ctx1 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). +// WithCodec(cdc). +// WithNodeURI(viper.GetString(FlagNode1)). +// WithBroadcastMode(flags.BroadcastBlock) +// q1 := state.NewCLIQuerier(ctx1) + +// ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). +// WithCodec(cdc). +// WithNodeURI(viper.GetString(FlagNode2)). +// WithBroadcastMode(flags.BroadcastBlock) +// q2 := state.NewCLIQuerier(ctx2) + +// portid1, chanid1 := args[0], args[1] + +// obj1, err := flush(q1, cdc, storeKey, version.DefaultPrefix(), portid1, chanid1) +// if err != nil { +// return err +// } + +// chan1, _, err := obj1.ChannelCLI(q1) +// if err != nil { +// return err +// } + +// portid2, chanid2 := chan1.CounterpartyPort, chan1.Counterparty + +// obj2, err := flush(q2, cdc, storeKey, version.DefaultPrefix(), portid2, chanid2) +// if err != nil { +// return err +// } + +// chan2, _, err := obj2.ChannelCLI(q2) +// if err != nil { +// return err +// } + +// connobj2, err := conn(q2, cdc, storeKey, version.DefaultPrefix(), chan2.ConnectionHops[0]) +// if err != nil { +// return err +// } + +// conn2, _, err := connobj2.ConnectionCLI(q2) +// if err != nil { +// return err +// } + +// client2 := conn2.Client + +// 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 +// }, +// } + +// 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/keeper/querier.go b/x/ibc/04-channel/keeper/querier.go new file mode 100644 index 000000000000..da03dd9d070f --- /dev/null +++ b/x/ibc/04-channel/keeper/querier.go @@ -0,0 +1,44 @@ +package keeper + +import ( + "fmt" + + abci "github.com/tendermint/tendermint/abci/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" +) + +// NewQuerier creates a querier for the IBC channel +func NewQuerier(k Keeper) sdk.Querier { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + switch path[0] { + case types.QueryChannel: + return queryClientState(ctx, req, k) + + default: + return nil, sdk.ErrUnknownRequest("unknown IBC channel query endpoint") + } + } +} + +func queryClientState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { + var params types.QueryChannelParams + + err := types.SubModuleCdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + } + + channel, found := k.GetChannel(ctx, params.PortID, params.ChannelID) + if !found { + return nil, types.ErrChannelNotFound(k.codespace) + } + + bz, err := types.SubModuleCdc.MarshalJSON(channel) + if err != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + } + + return bz, nil +} diff --git a/x/ibc/04-channel/types/codec.go b/x/ibc/04-channel/types/codec.go index 99c0a14af18e..cf70c38f9587 100644 --- a/x/ibc/04-channel/types/codec.go +++ b/x/ibc/04-channel/types/codec.go @@ -14,6 +14,8 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgChannelOpenTry{}, "ibc/channel/MsgChannelOpenTry", nil) cdc.RegisterConcrete(MsgChannelOpenAck{}, "ibc/channel/MsgChannelOpenAck", nil) cdc.RegisterConcrete(MsgChannelOpenConfirm{}, "ibc/channel/MsgChannelOpenConfirm", nil) + cdc.RegisterConcrete(MsgChannelCloseInit{}, "ibc/channel/MsgChannelCloseInit", nil) + cdc.RegisterConcrete(MsgChannelCloseConfirm{}, "ibc/channel/MsgChannelCloseConfirm", nil) } func SetMsgChanCodec(cdc *codec.Codec) { diff --git a/x/ibc/04-channel/types/keys.go b/x/ibc/04-channel/types/keys.go index 26fb0b209770..f308640b2e32 100644 --- a/x/ibc/04-channel/types/keys.go +++ b/x/ibc/04-channel/types/keys.go @@ -24,7 +24,7 @@ func ChannelPath(portID, channelID string) string { } // ChannelCapabilityPath defines the path under which capability keys associated -// with a channel are stores +// with a channel are stored func ChannelCapabilityPath(portID, channelID string) string { return fmt.Sprintf("%s/key", ChannelPath(portID, channelID)) } diff --git a/x/ibc/04-channel/types/querier.go b/x/ibc/04-channel/types/querier.go new file mode 100644 index 000000000000..ac9eb8910d5d --- /dev/null +++ b/x/ibc/04-channel/types/querier.go @@ -0,0 +1,21 @@ +package types + +// query routes supported by the IBC channel Querier +const ( + QueryChannel = "channel" +) + +// QueryChannelParams defines the params for the following queries: +// - 'custom/ibc/channel' +type QueryChannelParams struct { + PortID string + ChannelID string +} + +// NewQueryChannelParams creates a new QueryChannelParams instance +func NewQueryChannelParams(portID, channelID string) QueryChannelParams { + return QueryChannelParams{ + PortID: portID, + ChannelID: channelID, + } +} From 01634820984a0b09bd86f954bdbe7bcefbf08585 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 14 Oct 2019 16:13:03 +0200 Subject: [PATCH 288/378] update expected client keeper and export verification funcs --- x/ibc/03-connection/keeper/handshake.go | 52 ++++++++++++++----- x/ibc/03-connection/keeper/keeper.go | 6 ++- x/ibc/03-connection/types/errors.go | 6 +++ x/ibc/03-connection/types/expected_keepers.go | 2 + 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index ddfa8926e4e1..5add48319e33 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -74,18 +74,27 @@ func (k Keeper) ConnOpenTry( // connection defines chain B's ConnectionEnd connection := types.NewConnectionEnd(clientID, counterparty, []string{version}) + expConnBz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedConn) + if err != nil { + return err + } - ok := k.verifyMembership( + ok := k.VerifyMembership( ctx, connection, proofHeight, proofInit, - types.ConnectionPath(connectionID), expectedConn, + types.ConnectionPath(connectionID), expConnBz, ) if !ok { return errors.New("couldn't verify connection membership on counterparty's client") // TODO: sdk.Error } - ok = k.verifyMembership( + expConsStateBz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedConsensusState) + if err != nil { + return err + } + + ok = k.VerifyMembership( ctx, connection, proofHeight, proofInit, - ics02types.ConsensusStatePath(counterparty.ClientID), expectedConsensusState, + ics02types.ConsensusStatePath(counterparty.ClientID), expConsStateBz, ) if !ok { return errors.New("couldn't verify consensus state membership on counterparty's client") // TODO: sdk.Error @@ -101,7 +110,7 @@ func (k Keeper) ConnOpenTry( } connection.State = types.TRYOPEN - err := k.addConnectionToClient(ctx, clientID, connectionID) + err = k.addConnectionToClient(ctx, clientID, connectionID) if err != nil { return sdkerrors.Wrap(err, "cannot relay connection attempt") } @@ -144,22 +153,32 @@ func (k Keeper) ConnOpenAck( return errors.New("client consensus state not found") // TODO: use ICS02 error } - prefix := getCommitmentPrefix() + prefix := k.clientKeeper.GetCommitmentPath() expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, prefix) expectedConn := types.NewConnectionEnd(connection.ClientID, expectedCounterparty, []string{version}) expectedConn.State = types.TRYOPEN - ok := k.verifyMembership( + expConnBz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedConn) + if err != nil { + return err + } + + ok := k.VerifyMembership( ctx, connection, proofHeight, proofTry, - types.ConnectionPath(connection.Counterparty.ConnectionID), expectedConn, + types.ConnectionPath(connection.Counterparty.ConnectionID), expConnBz, ) if !ok { return errors.New("couldn't verify connection membership on counterparty's client") // TODO: sdk.Error } - ok = k.verifyMembership( + expConsStateBz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedConsensusState) + if err != nil { + return err + } + + ok = k.VerifyMembership( ctx, connection, proofHeight, proofTry, - ics02types.ConsensusStatePath(connection.Counterparty.ClientID), expectedConsensusState, + ics02types.ConsensusStatePath(connection.Counterparty.ClientID), expConsStateBz, ) if !ok { return errors.New("couldn't verify consensus state membership on counterparty's client") // TODO: sdk.Error @@ -198,17 +217,22 @@ func (k Keeper) ConnOpenConfirm( return errors.New("connection is in a non valid state") // TODO: sdk.Error } - prefix := getCommitmentPrefix() + prefix := k.clientKeeper.GetCommitmentPath() expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, prefix) expectedConn := types.NewConnectionEnd(connection.ClientID, expectedCounterparty, connection.Versions) expectedConn.State = types.OPEN - ok := k.verifyMembership( + expConnBz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedConn) + if err != nil { + return err + } + + ok := k.VerifyMembership( ctx, connection, proofHeight, proofAck, - types.ConnectionPath(connection.Counterparty.ConnectionID), expectedConn, + types.ConnectionPath(connection.Counterparty.ConnectionID), expConnBz, ) if !ok { - return errors.New("couldn't verify connection membership on counterparty's client") // TODO: sdk.Error + return types.ErrInvalidCounterpartyConnection(k.codespace) } connection.State = types.OPEN diff --git a/x/ibc/03-connection/keeper/keeper.go b/x/ibc/03-connection/keeper/keeper.go index e63885b6727c..4cdc998e9c26 100644 --- a/x/ibc/03-connection/keeper/keeper.go +++ b/x/ibc/03-connection/keeper/keeper.go @@ -114,7 +114,8 @@ func (k Keeper) removeConnectionFromClient(ctx sdk.Context, clientID, connection return nil } -func (k Keeper) verifyMembership( +// VerifyMembership helper function for state membership verification +func (k Keeper) VerifyMembership( ctx sdk.Context, connection types.ConnectionEnd, height uint64, @@ -130,7 +131,8 @@ func (k Keeper) verifyMembership( return k.clientKeeper.VerifyMembership(ctx, clientState, height, proof, path, value) } -func (k Keeper) verifyNonMembership( +// VerifyNonMembership helper function for state non-membership verification +func (k Keeper) VerifyNonMembership( ctx sdk.Context, connection types.ConnectionEnd, height uint64, diff --git a/x/ibc/03-connection/types/errors.go b/x/ibc/03-connection/types/errors.go index 9b38ec3c4f4c..d6ce1c6a300f 100644 --- a/x/ibc/03-connection/types/errors.go +++ b/x/ibc/03-connection/types/errors.go @@ -12,6 +12,7 @@ const ( CodeConnectionNotFound sdk.CodeType = 102 CodeClientConnectionPathsNotFound sdk.CodeType = 103 CodeConnectionPath sdk.CodeType = 104 + CodeInvalidCounterpartyConnection sdk.CodeType = 105 ) // ErrConnectionExists implements sdk.Error @@ -33,3 +34,8 @@ func ErrClientConnectionPathsNotFound(codespace sdk.CodespaceType) sdk.Error { func ErrConnectionPath(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeConnectionPath, "connection path is not associated to the client") } + +// ErrInvalidCounterpartyConnection implements sdk.Error +func ErrInvalidCounterpartyConnection(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidCounterpartyConnection, "couldn't verify connection membership on counterparty's client") +} diff --git a/x/ibc/03-connection/types/expected_keepers.go b/x/ibc/03-connection/types/expected_keepers.go index 89f84de3188d..2c03af61160b 100644 --- a/x/ibc/03-connection/types/expected_keepers.go +++ b/x/ibc/03-connection/types/expected_keepers.go @@ -5,10 +5,12 @@ import ( ics02exported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ics02types "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) // ClientKeeper expected account IBC client keeper type ClientKeeper interface { + GetCommitmentPath() ics23.Prefix GetConsensusState(ctx sdk.Context, clientID string) (ics02exported.ConsensusState, bool) GetClientState(ctx sdk.Context, clientID string) (ics02types.ClientState, bool) VerifyMembership( From 7c37222eb31a6877a3f64108b2d5add325871224 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 14 Oct 2019 17:41:28 +0200 Subject: [PATCH 289/378] ICS 05 Implementation --- store/types/store.go | 4 ++ types/store.go | 1 + x/ibc/05-port/exported/exported.go | 13 +++++++ x/ibc/05-port/keeper/keeper.go | 59 ++++++++++++++++++++++++++++++ x/ibc/05-port/types/errors.go | 23 ++++++++++++ x/ibc/05-port/types/keys.go | 31 ++++++++++++++++ 6 files changed, 131 insertions(+) create mode 100644 x/ibc/05-port/exported/exported.go create mode 100644 x/ibc/05-port/keeper/keeper.go create mode 100644 x/ibc/05-port/types/errors.go create mode 100644 x/ibc/05-port/types/keys.go diff --git a/store/types/store.go b/store/types/store.go index 5b5e64742552..bd8a3d58c85a 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -277,6 +277,10 @@ type StoreKey interface { String() string } +// CapabilityKey represent the Cosmos SDK keys for object-capability +// generation in the IBC protocol as defined in https://github.com/cosmos/ics/tree/master/spec/ics-005-port-allocation#data-structures +type CapabilityKey StoreKey + // KVStoreKey is used for accessing substores. // Only the pointer value should ever be used - it functions as a capabilities key. type KVStoreKey struct { diff --git a/types/store.go b/types/store.go index c34b6d437d09..db18b127b69d 100644 --- a/types/store.go +++ b/types/store.go @@ -69,6 +69,7 @@ const ( // nolint - reexport type ( StoreKey = types.StoreKey + CapabilityKey = types.CapabilityKey KVStoreKey = types.KVStoreKey TransientStoreKey = types.TransientStoreKey ) diff --git a/x/ibc/05-port/exported/exported.go b/x/ibc/05-port/exported/exported.go new file mode 100644 index 000000000000..1024602fb770 --- /dev/null +++ b/x/ibc/05-port/exported/exported.go @@ -0,0 +1,13 @@ +// Package exported defines the `generate()` and `authenticate()` functions for +// capability keys as defined in https://github.com/cosmos/ics/tree/master/spec/ics-005-port-allocation#data-structures. +package exported + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Generate +type Generate func() sdk.CapabilityKey + +// Authenticate +type Authenticate func(key sdk.CapabilityKey) bool diff --git a/x/ibc/05-port/keeper/keeper.go b/x/ibc/05-port/keeper/keeper.go new file mode 100644 index 000000000000..2516ed3fc362 --- /dev/null +++ b/x/ibc/05-port/keeper/keeper.go @@ -0,0 +1,59 @@ +package keeper + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/05-port/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" +) + +// Keeper defines the IBC connection keeper +type Keeper struct { + storeKey sdk.StoreKey + cdc *codec.Codec + codespace sdk.CodespaceType + prefix []byte // prefix bytes for accessing the store +} + +// NewKeeper creates a new IBC connection Keeper instance +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) Keeper { + return Keeper{ + storeKey: key, + cdc: cdc, + codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/ports", + prefix: []byte(types.SubModuleName + "/"), // "ports/" + } +} + +// GetPort returns a port with a particular identifier +func (k Keeper) GetPort(ctx sdk.Context, portID string) (string, bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(types.KeyPort(portID)) + if bz == nil { + return "", false + } + + return string(bz), true +} + +// SetPort sets a port to the store +func (k Keeper) SetPort(ctx sdk.Context, portID string, capabilityKey sdk.CapabilityKey) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := k.cdc.MustMarshalBinaryLengthPrefixed(capabilityKey) + store.Set(types.KeyPort(portID), bz) +} + +// BindPort binds to an unallocated port, failing if the port has already been +// allocated. +func (k Keeper) BindPort(ctx sdk.Context, portID string, generateFn exported.Generate) sdk.Error { + _, found := k.GetPort(ctx, portID) + if found { + return types.ErrPortExists(k.codespace) + } + key := generateFn() + k.SetPort(ctx, portID, key) + return nil +} diff --git a/x/ibc/05-port/types/errors.go b/x/ibc/05-port/types/errors.go new file mode 100644 index 000000000000..f86ebdf057eb --- /dev/null +++ b/x/ibc/05-port/types/errors.go @@ -0,0 +1,23 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// connection error codes +const ( + DefaultCodespace sdk.CodespaceType = SubModuleName + + CodePortExists sdk.CodeType = 101 + CodePortNotFound sdk.CodeType = 102 +) + +// ErrPortExists implements sdk.Error +func ErrPortExists(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodePortExists, "port already binded") +} + +// ErrPortNotFound implements sdk.Error +func ErrPortNotFound(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodePortNotFound, "port not found") +} diff --git a/x/ibc/05-port/types/keys.go b/x/ibc/05-port/types/keys.go new file mode 100644 index 000000000000..342a931f19db --- /dev/null +++ b/x/ibc/05-port/types/keys.go @@ -0,0 +1,31 @@ +package types + +import ( + "fmt" +) + +const ( + // SubModuleName defines the IBC ports name + SubModuleName = "ports" + + // StoreKey is the store key string for IBC connections + StoreKey = SubModuleName + + // RouterKey is the message route for IBC connections + RouterKey = SubModuleName + + // QuerierRoute is the querier route for IBC connections + QuerierRoute = SubModuleName +) + +// The following paths are the keys to the store as defined in https://github.com/cosmos/ics/tree/master/spec/ics-005-port-allocation#store-paths + +// PortPath defines the path under which ports paths are stored +func PortPath(portID string) string { + return fmt.Sprintf("ports/%s", portID) +} + +// KeyPort returns the store key for a particular port +func KeyPort(portID string) []byte { + return []byte(PortPath(portID)) +} From a8244dc8bd813af989e769743e9d5d83986e7297 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 14 Oct 2019 21:21:18 +0200 Subject: [PATCH 290/378] release port and godocs --- x/ibc/05-port/alias.go | 36 ++++++++++++++++ x/ibc/05-port/exported/exported.go | 6 ++- x/ibc/05-port/keeper/keeper.go | 66 ++++++++++++++++++++++++++++-- x/ibc/05-port/types/errors.go | 18 ++++++-- x/ibc/05-port/types/port.go | 14 +++++++ 5 files changed, 132 insertions(+), 8 deletions(-) create mode 100644 x/ibc/05-port/alias.go create mode 100644 x/ibc/05-port/types/port.go diff --git a/x/ibc/05-port/alias.go b/x/ibc/05-port/alias.go new file mode 100644 index 000000000000..8f36b91e54af --- /dev/null +++ b/x/ibc/05-port/alias.go @@ -0,0 +1,36 @@ +package ics05 + +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/05-port/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/05-port/types + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/05-port/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" +) + +const ( + DefaultCodespace = types.DefaultCodespace + SubModuleName = types.SubModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute +) + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper + ErrPortExists = types.ErrPortExists + ErrPortNotFound = types.ErrPortNotFound + ErrPortNotAuthenticated = types.ErrPortNotAuthenticated + ErrInvalidPortID = types.ErrInvalidPortID + PortPath = types.PortPath + KeyPort = types.KeyPort + ValidatePortID = types.ValidatePortID +) + +type ( + Keeper = keeper.Keeper +) diff --git a/x/ibc/05-port/exported/exported.go b/x/ibc/05-port/exported/exported.go index 1024602fb770..b38beed8bfbc 100644 --- a/x/ibc/05-port/exported/exported.go +++ b/x/ibc/05-port/exported/exported.go @@ -6,8 +6,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// Generate +// Generate creates a new object-capability key, which must +// be returned by the outer-layer function. type Generate func() sdk.CapabilityKey -// Authenticate +// Authenticate defines an authentication function defined by +// each module to authenticate their own. type Authenticate func(key sdk.CapabilityKey) bool diff --git a/x/ibc/05-port/keeper/keeper.go b/x/ibc/05-port/keeper/keeper.go index 2516ed3fc362..0aa6845dc8e7 100644 --- a/x/ibc/05-port/keeper/keeper.go +++ b/x/ibc/05-port/keeper/keeper.go @@ -29,14 +29,16 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) } // GetPort returns a port with a particular identifier -func (k Keeper) GetPort(ctx sdk.Context, portID string) (string, bool) { +func (k Keeper) GetPort(ctx sdk.Context, portID string) (sdk.CapabilityKey, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := store.Get(types.KeyPort(portID)) if bz == nil { - return "", false + return nil, false } - return string(bz), true + var capabilityKey sdk.CapabilityKey + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &capabilityKey) + return capabilityKey, true } // SetPort sets a port to the store @@ -46,9 +48,19 @@ func (k Keeper) SetPort(ctx sdk.Context, portID string, capabilityKey sdk.Capabi store.Set(types.KeyPort(portID), bz) } +// delete a port ID key from the store +func (k Keeper) deletePort(ctx sdk.Context, portID string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + store.Delete(types.KeyPort(portID)) +} + // BindPort binds to an unallocated port, failing if the port has already been // allocated. func (k Keeper) BindPort(ctx sdk.Context, portID string, generateFn exported.Generate) sdk.Error { + if !types.ValidatePortID(portID) { + return types.ErrInvalidPortID(k.codespace) + } + _, found := k.GetPort(ctx, portID) if found { return types.ErrPortExists(k.codespace) @@ -57,3 +69,51 @@ func (k Keeper) BindPort(ctx sdk.Context, portID string, generateFn exported.Gen k.SetPort(ctx, portID, key) return nil } + +// TransferPort allows an existing port (i.e capability key) to be transfered +// to another module and thus stored under another path. +// +// NOTE: not neccessary if the host state machine supports object-capabilities, +// since the port reference is a bearer capability. +func (k Keeper) TransferPort( + ctx sdk.Context, + portID string, + authenticateFn exported.Authenticate, + generateFn exported.Generate, +) sdk.Error { + port, found := k.GetPort(ctx, portID) + if !found { + return types.ErrPortNotFound(k.codespace) + } + + if !authenticateFn(port) { + return types.ErrPortNotAuthenticated(k.codespace) + } + + key := generateFn() + k.SetPort(ctx, portID, key) + return nil +} + +// ReleasePort allows a module to release a port such that other modules may +// then bind to it. +// +// WARNING: releasing a port will allow other modules to bind to that port and +// possibly intercept incoming channel opening handshakes. Modules should release +// ports only when doing so is safe. +func (k Keeper) ReleasePort( + ctx sdk.Context, + portID string, + authenticateFn exported.Authenticate) sdk.Error { + port, found := k.GetPort(ctx, portID) + if !found { + return types.ErrPortNotFound(k.codespace) + } + + if !authenticateFn(port) { + return types.ErrPortNotAuthenticated(k.codespace) + } + + k.deletePort(ctx, portID) + return nil +} diff --git a/x/ibc/05-port/types/errors.go b/x/ibc/05-port/types/errors.go index f86ebdf057eb..e8ef1fc53992 100644 --- a/x/ibc/05-port/types/errors.go +++ b/x/ibc/05-port/types/errors.go @@ -4,12 +4,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// connection error codes +// port error codes const ( DefaultCodespace sdk.CodespaceType = SubModuleName - CodePortExists sdk.CodeType = 101 - CodePortNotFound sdk.CodeType = 102 + CodePortExists sdk.CodeType = 101 + CodePortNotFound sdk.CodeType = 102 + CodePortNotAuthenticated sdk.CodeType = 103 + CodeInvalidPortID sdk.CodeType = 104 ) // ErrPortExists implements sdk.Error @@ -21,3 +23,13 @@ func ErrPortExists(codespace sdk.CodespaceType) sdk.Error { func ErrPortNotFound(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodePortNotFound, "port not found") } + +// ErrPortNotAuthenticated implements sdk.Error +func ErrPortNotAuthenticated(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodePortNotAuthenticated, "port failed authentication") +} + +// ErrInvalidPortID implements sdk.Error +func ErrInvalidPortID(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidPortID, "invalid port ID") +} diff --git a/x/ibc/05-port/types/port.go b/x/ibc/05-port/types/port.go new file mode 100644 index 000000000000..b651b8539a51 --- /dev/null +++ b/x/ibc/05-port/types/port.go @@ -0,0 +1,14 @@ +package types + +import ( + "strings" +) + +// ValidatePortID validates that the provided port identifier is not empty +// and that it's +func ValidatePortID(portID string) bool { + if strings.TrimSpace(portID) == "" { + return false + } + return true +} From a8ceb4585044cd5d9b81e3095a115f656cf7c833 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 15 Oct 2019 11:24:41 +0200 Subject: [PATCH 291/378] Update x/ibc/02-client/client/cli/query.go Co-Authored-By: Jack Zampolin --- x/ibc/02-client/client/cli/query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index a3ce9f401418..f1a0674c8b96 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -95,7 +95,7 @@ $ %s query ibc client root [client-id] [height] id := args[0] height, err := strconv.ParseUint(args[1], 10, 64) if err != nil { - return err + return fmt.Errorf("expected integer height, got: %v\n", args[1]) } bz, err := cdc.MarshalJSON(types.NewQueryCommitmentRootParams(id, height)) From 956eb5cfa44016982018b7054cb9c842ec1da803 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 15 Oct 2019 11:32:36 +0200 Subject: [PATCH 292/378] Update x/ibc/02-client/types/tendermint/consensus_state.go Co-Authored-By: Jack Zampolin --- x/ibc/02-client/types/tendermint/consensus_state.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ibc/02-client/types/tendermint/consensus_state.go b/x/ibc/02-client/types/tendermint/consensus_state.go index dd9b2413a422..0a52c598a9ec 100644 --- a/x/ibc/02-client/types/tendermint/consensus_state.go +++ b/x/ibc/02-client/types/tendermint/consensus_state.go @@ -42,7 +42,7 @@ func (cs ConsensusState) GetRoot() ics23.Root { func (cs ConsensusState) CheckValidityAndUpdateState(header exported.Header) (exported.ConsensusState, error) { tmHeader, ok := header.(Header) if !ok { - return nil, errors.New("header is not from a tendermint consensus") + return nil, errors.New("header not a valid tendermint header") } if err := cs.checkValidity(tmHeader); err != nil { From c573d5760bd1353f024a6f91d9c4459321dc4493 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 15 Oct 2019 12:49:23 +0200 Subject: [PATCH 293/378] address some of the review comments --- x/ibc/02-client/alias.go | 49 ++++++++++++++-------------- x/ibc/02-client/client/cli/query.go | 31 ++++++++++++------ x/ibc/02-client/doc.go | 4 +-- x/ibc/02-client/exported/exported.go | 2 +- x/ibc/02-client/handler.go | 37 ++++----------------- x/ibc/02-client/keeper/client.go | 2 +- x/ibc/02-client/module.go | 2 +- x/ibc/02-client/types/events.go | 8 ++--- x/ibc/02-client/types/keys.go | 2 +- x/ibc/02-client/types/querier.go | 10 +++--- x/ibc/alias.go | 3 +- x/ibc/handler.go | 21 ++++++++++-- x/ibc/module.go | 4 +-- 13 files changed, 91 insertions(+), 84 deletions(-) diff --git a/x/ibc/02-client/alias.go b/x/ibc/02-client/alias.go index f66d835dfa0e..a93de15094b7 100644 --- a/x/ibc/02-client/alias.go +++ b/x/ibc/02-client/alias.go @@ -1,9 +1,10 @@ +package client + // nolint // autogenerated code using github.com/rigelrozanski/multitool // aliases generated for the following subdirectories: // ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper // ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/02-client/types -package ics02 import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper" @@ -11,27 +12,24 @@ import ( ) const ( - DefaultCodespace = types.DefaultCodespace - CodeClientExists = types.CodeClientExists - CodeClientNotFound = types.CodeClientNotFound - CodeClientFrozen = types.CodeClientFrozen - CodeConsensusStateNotFound = types.CodeConsensusStateNotFound - CodeInvalidConsensusState = types.CodeInvalidConsensusState - CodeClientTypeNotFound = types.CodeClientTypeNotFound - CodeInvalidClientType = types.CodeInvalidClientType - CodeRootNotFound = types.CodeRootNotFound - EventTypeCreateClient = types.EventTypeCreateClient - EventTypeUpdateClient = types.EventTypeUpdateClient - EventTypeSubmitMisbehaviour = types.EventTypeSubmitMisbehaviour - AttributeKeyClientID = types.AttributeKeyClientID - SubModuleName = types.SubModuleName - StoreKey = types.StoreKey - RouterKey = types.RouterKey - QuerierRoute = types.QuerierRoute - QueryClientState = types.QueryClientState - QueryConsensusState = types.QueryConsensusState - QueryCommitmentPath = types.QueryCommitmentPath - QueryCommitmentRoot = types.QueryCommitmentRoot + DefaultCodespace = types.DefaultCodespace + CodeClientExists = types.CodeClientExists + CodeClientNotFound = types.CodeClientNotFound + CodeClientFrozen = types.CodeClientFrozen + CodeConsensusStateNotFound = types.CodeConsensusStateNotFound + CodeInvalidConsensusState = types.CodeInvalidConsensusState + CodeClientTypeNotFound = types.CodeClientTypeNotFound + CodeInvalidClientType = types.CodeInvalidClientType + CodeRootNotFound = types.CodeRootNotFound + AttributeKeyClientID = types.AttributeKeyClientID + SubModuleName = types.SubModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute + QueryClientState = types.QueryClientState + QueryConsensusState = types.QueryConsensusState + QueryCommitmentPath = types.QueryCommitmentPath + QueryCommitmentRoot = types.QueryCommitmentRoot ) var ( @@ -63,8 +61,11 @@ var ( NewClientState = types.NewClientState // variable aliases - SubModuleCdc = types.SubModuleCdc - AttributeValueCategory = types.AttributeValueCategory + SubModuleCdc = types.SubModuleCdc + EventTypeCreateClient = types.EventTypeCreateClient + EventTypeUpdateClient = types.EventTypeUpdateClient + EventTypeSubmitMisbehaviour = types.EventTypeSubmitMisbehaviour + AttributeValueCategory = types.AttributeValueCategory ) type ( diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index f1a0674c8b96..fbef4a4e8181 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -1,6 +1,7 @@ package cli import ( + "errors" "fmt" "strconv" "strings" @@ -55,14 +56,17 @@ $ %s query ibc client state [client-id] Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - id := args[0] + clientID := args[0] + if strings.TrimSpace(clientID) == "" { + return errors.New("client ID can't be blank") + } - bz, err := cdc.MarshalJSON(types.NewQueryClientStateParams(id)) + bz, err := cdc.MarshalJSON(types.NewQueryClientStateParams(clientID)) if err != nil { return err } - res, _, err := cliCtx.QueryWithData(types.ClientStatePath(id), bz) + res, _, err := cliCtx.QueryWithData(types.ClientStatePath(clientID), bz) if err != nil { return err } @@ -92,18 +96,22 @@ $ %s query ibc client root [client-id] [height] Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - id := args[0] + clientID := args[0] + if strings.TrimSpace(clientID) == "" { + return errors.New("client ID can't be blank") + } + height, err := strconv.ParseUint(args[1], 10, 64) if err != nil { - return fmt.Errorf("expected integer height, got: %v\n", args[1]) + return fmt.Errorf("expected integer height, got: %v", args[1]) } - bz, err := cdc.MarshalJSON(types.NewQueryCommitmentRootParams(id, height)) + bz, err := cdc.MarshalJSON(types.NewQueryCommitmentRootParams(clientID, height)) if err != nil { return err } - res, _, err := cliCtx.QueryWithData(types.RootPath(id, height), bz) + res, _, err := cliCtx.QueryWithData(types.RootPath(clientID, height), bz) if err != nil { return err } @@ -134,14 +142,17 @@ $ %s query ibc client consensus-state [client-id] Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - id := args[0] + clientID := args[0] + if strings.TrimSpace(clientID) == "" { + return errors.New("client ID can't be blank") + } - bz, err := cdc.MarshalJSON(types.NewQueryClientStateParams(id)) + bz, err := cdc.MarshalJSON(types.NewQueryClientStateParams(clientID)) if err != nil { return err } - res, _, err := cliCtx.QueryWithData(types.ConsensusStatePath(id), bz) + res, _, err := cliCtx.QueryWithData(types.ConsensusStatePath(clientID), bz) if err != nil { return err } diff --git a/x/ibc/02-client/doc.go b/x/ibc/02-client/doc.go index c2ce8f7729e6..061e160d9739 100644 --- a/x/ibc/02-client/doc.go +++ b/x/ibc/02-client/doc.go @@ -1,5 +1,5 @@ /* -Package ics02 implements the ICS 02 - Client Semenatics specification +Package client implements the ICS 02 - Client Semenatics specification https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics. This concrete implementations defines types and method to store and update light clients which tracks on other chain's state. @@ -51,4 +51,4 @@ each corresponds to `spec: Header.{height, proof, state, root}`. `spec: interface ClientState` is implemented by `type State`. */ -package ics02 +package client diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index 8e97b68b6f6f..074dfff0024e 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -49,7 +49,7 @@ type Header interface { // Client types const ( - ClientTypeTendermint string = "Tendermint" + ClientTypeTendermint string = "tendermint" ) // ClientType defines the type of the consensus algorithm diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go index f2da176b4771..b7394edf0e29 100644 --- a/x/ibc/02-client/handler.go +++ b/x/ibc/02-client/handler.go @@ -1,35 +1,11 @@ -package ics02 +package client import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" ) -// NewHandler creates a new Handler instance for IBC client -// transactions -func NewHandler(k Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case MsgCreateClient: - return handleMsgCreateClient(ctx, k, msg) - - case MsgUpdateClient: - return handleMsgUpdateClient(ctx, k, msg) - - case MsgSubmitMisbehaviour: - return handleMsgSubmitMisbehaviour(ctx, k, msg) - - default: - errMsg := fmt.Sprintf("unrecognized IBC Client message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() - } - } -} - -func handleMsgCreateClient(ctx sdk.Context, k Keeper, msg MsgCreateClient) sdk.Result { +// HandleMsgCreateClient defines the sdk.Handler for MsgCreateClient +func HandleMsgCreateClient(ctx sdk.Context, k Keeper, msg MsgCreateClient) sdk.Result { _, err := k.CreateClient(ctx, msg.ClientID, msg.ClientType, msg.ConsensusState) if err != nil { return sdk.ResultFromError(err) @@ -50,7 +26,8 @@ func handleMsgCreateClient(ctx sdk.Context, k Keeper, msg MsgCreateClient) sdk.R return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgUpdateClient(ctx sdk.Context, k Keeper, msg MsgUpdateClient) sdk.Result { +// HandleMsgUpdateClient defines the sdk.Handler for MsgUpdateClient +func HandleMsgUpdateClient(ctx sdk.Context, k Keeper, msg MsgUpdateClient) sdk.Result { err := k.UpdateClient(ctx, msg.ClientID, msg.Header) if err != nil { return sdk.ResultFromError(err) @@ -68,11 +45,11 @@ func handleMsgUpdateClient(ctx sdk.Context, k Keeper, msg MsgUpdateClient) sdk.R ), }) - // TODO: events return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgSubmitMisbehaviour(ctx sdk.Context, k Keeper, msg MsgSubmitMisbehaviour) sdk.Result { +// HandleMsgSubmitMisbehaviour defines the sdk.Handler for MsgSubmitMisbehaviour +func HandleMsgSubmitMisbehaviour(ctx sdk.Context, k Keeper, msg MsgSubmitMisbehaviour) sdk.Result { err := k.CheckMisbehaviourAndUpdateState(ctx, msg.ClientID, msg.Evidence) if err != nil { return sdk.ResultFromError(err) diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go index f0645b49b5e4..df3aaf53d23b 100644 --- a/x/ibc/02-client/keeper/client.go +++ b/x/ibc/02-client/keeper/client.go @@ -79,7 +79,7 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H k.SetConsensusState(ctx, clientID, consensusState) k.SetCommitmentRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) - k.Logger(ctx).Info(fmt.Sprintf("client %s updated at height %d", clientID, consensusState.GetHeight())) + k.Logger(ctx).Info(fmt.Sprintf("client %s updated to height %d", clientID, consensusState.GetHeight())) return nil } diff --git a/x/ibc/02-client/module.go b/x/ibc/02-client/module.go index c839e262a101..a4586961b08a 100644 --- a/x/ibc/02-client/module.go +++ b/x/ibc/02-client/module.go @@ -1,4 +1,4 @@ -package ics02 +package client import ( "fmt" diff --git a/x/ibc/02-client/types/events.go b/x/ibc/02-client/types/events.go index 6258a7e328d9..7e7f9a508cee 100644 --- a/x/ibc/02-client/types/events.go +++ b/x/ibc/02-client/types/events.go @@ -8,14 +8,14 @@ import ( // IBC client events const ( - EventTypeCreateClient = "create_client" - EventTypeUpdateClient = "update_client" - EventTypeSubmitMisbehaviour = "submit_misbehaviour" - AttributeKeyClientID = "client_id" ) // IBC client events vars var ( + EventTypeCreateClient = MsgCreateClient{}.Type() + EventTypeUpdateClient = MsgUpdateClient{}.Type() + EventTypeSubmitMisbehaviour = MsgSubmitMisbehaviour{}.Type() + AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, SubModuleName) ) diff --git a/x/ibc/02-client/types/keys.go b/x/ibc/02-client/types/keys.go index edc91fe2c4a3..8d97ca893324 100644 --- a/x/ibc/02-client/types/keys.go +++ b/x/ibc/02-client/types/keys.go @@ -6,7 +6,7 @@ import ( const ( // SubModuleName defines the IBC client name - SubModuleName = "clients" + SubModuleName = "client" // StoreKey is the store key string for IBC client StoreKey = SubModuleName diff --git a/x/ibc/02-client/types/querier.go b/x/ibc/02-client/types/querier.go index 17c41a01b40a..6e58b6c00f57 100644 --- a/x/ibc/02-client/types/querier.go +++ b/x/ibc/02-client/types/querier.go @@ -2,15 +2,15 @@ package types // query routes supported by the IBC client Querier const ( - QueryClientState = "clientState" - QueryConsensusState = "consensusState" - QueryCommitmentPath = "commitmentPath" + QueryClientState = "client_state" + QueryConsensusState = "consensus_state" + QueryCommitmentPath = "commitment_path" QueryCommitmentRoot = "roots" ) // QueryClientStateParams defines the params for the following queries: -// - 'custom/ibc/clients//clientState' -// - 'custom/ibc/clients//consensusState' +// - 'custom/ibc/clients//client_state' +// - 'custom/ibc/clients//consensus_state' type QueryClientStateParams struct { ClientID string } diff --git a/x/ibc/alias.go b/x/ibc/alias.go index 34587f7580e8..d71d90640ab2 100644 --- a/x/ibc/alias.go +++ b/x/ibc/alias.go @@ -1,9 +1,10 @@ +package ibc + // nolint // autogenerated code using github.com/rigelrozanski/multitool // aliases generated for the following subdirectories: // ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/keeper // ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/types -package ibc import ( "github.com/cosmos/cosmos-sdk/x/ibc/keeper" diff --git a/x/ibc/handler.go b/x/ibc/handler.go index 5420e956fb4f..5dc802b6f063 100644 --- a/x/ibc/handler.go +++ b/x/ibc/handler.go @@ -1,13 +1,30 @@ package ibc import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" ) // NewHandler defines the IBC handler func NewHandler(k Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - // TODO: - return sdk.Result{} + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + switch msg := msg.(type) { + case client.MsgCreateClient: + return client.HandleMsgCreateClient(ctx, k.ClientKeeper, msg) + + case client.MsgUpdateClient: + return client.HandleMsgUpdateClient(ctx, k.ClientKeeper, msg) + + case client.MsgSubmitMisbehaviour: + return client.HandleMsgSubmitMisbehaviour(ctx, k.ClientKeeper, msg) + + default: + errMsg := fmt.Sprintf("unrecognized IBC Client message type: %T", msg) + return sdk.ErrUnknownRequest(errMsg).Result() + } } } diff --git a/x/ibc/module.go b/x/ibc/module.go index 950ab8938c14..5a56db96877f 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - ics02 "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/client/cli" "github.com/cosmos/cosmos-sdk/x/ibc/types" @@ -36,7 +36,7 @@ func (AppModuleBasic) Name() string { // RegisterCodec registers the staking module's types for the given codec. func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { - ics02.RegisterCodec(cdc) + client.RegisterCodec(cdc) ics23.RegisterCodec(cdc) } From f852b1baaa2adb0d7d1fca10e38ec79a1ab6d42e Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 15 Oct 2019 15:21:07 +0200 Subject: [PATCH 294/378] resolve some TODOs and address comments from review --- x/ibc/02-client/keeper/keeper.go | 2 +- x/ibc/03-connection/alias.go | 78 +++++++++++++++++++ x/ibc/03-connection/handler.go | 42 +++------- x/ibc/03-connection/keeper/handshake.go | 54 ++++++------- x/ibc/03-connection/keeper/keeper.go | 7 +- x/ibc/03-connection/types/connection.go | 70 +++++++++++++---- x/ibc/03-connection/types/errors.go | 26 +++++-- x/ibc/03-connection/types/events.go | 10 +-- x/ibc/03-connection/types/expected_keepers.go | 1 - x/ibc/03-connection/types/msgs.go | 55 ++++++++++++- x/ibc/handler.go | 15 +++- x/ibc/keeper/keeper.go | 12 ++- 12 files changed, 271 insertions(+), 101 deletions(-) create mode 100644 x/ibc/03-connection/alias.go diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index d0f83ce19d31..2fc960e3c527 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -42,7 +42,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { } // GetCommitmentPath returns the commitment path of the client -func (k Keeper) GetCommitmentPath() merkle.Prefix { +func (k Keeper) GetCommitmentPath() ics23.Prefix { return merkle.NewPrefix([][]byte{[]byte(k.storeKey.Name())}, k.prefix) } diff --git a/x/ibc/03-connection/alias.go b/x/ibc/03-connection/alias.go new file mode 100644 index 000000000000..c6d743c9c7f9 --- /dev/null +++ b/x/ibc/03-connection/alias.go @@ -0,0 +1,78 @@ +package connection + +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/03-connection/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" +) + +const ( + NONE = types.NONE + DefaultCodespace = types.DefaultCodespace + CodeConnectionExists = types.CodeConnectionExists + CodeConnectionNotFound = types.CodeConnectionNotFound + CodeClientConnectionPathsNotFound = types.CodeClientConnectionPathsNotFound + CodeConnectionPath = types.CodeConnectionPath + CodeInvalidCounterpartyConnection = types.CodeInvalidCounterpartyConnection + AttributeKeyConnectionID = types.AttributeKeyConnectionID + AttributeKeyCounterpartyClientID = types.AttributeKeyCounterpartyClientID + SubModuleName = types.SubModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute + QueryClientState = types.QueryClientState + QueryConsensusState = types.QueryConsensusState + QueryCommitmentPath = types.QueryCommitmentPath + QueryCommitmentRoot = types.QueryCommitmentRoot +) + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper + RegisterCodec = types.RegisterCodec + SetMsgConnectionCodec = types.SetMsgConnectionCodec + NewConnectionEnd = types.NewConnectionEnd + NewCounterparty = types.NewCounterparty + ErrConnectionExists = types.ErrConnectionExists + ErrConnectionNotFound = types.ErrConnectionNotFound + ErrClientConnectionPathsNotFound = types.ErrClientConnectionPathsNotFound + ErrConnectionPath = types.ErrConnectionPath + ErrInvalidCounterpartyConnection = types.ErrInvalidCounterpartyConnection + ConnectionPath = types.ConnectionPath + ClientConnectionsPath = types.ClientConnectionsPath + KeyConnection = types.KeyConnection + KeyClientConnections = types.KeyClientConnections + NewMsgConnectionOpenInit = types.NewMsgConnectionOpenInit + NewMsgConnectionOpenTry = types.NewMsgConnectionOpenTry + NewMsgConnectionOpenAck = types.NewMsgConnectionOpenAck + NewMsgConnectionOpenConfirm = types.NewMsgConnectionOpenConfirm + NewQueryConnectionParams = types.NewQueryConnectionParams + NewQueryClientConnectionsParams = types.NewQueryClientConnectionsParams + + // variable aliases + SubModuleCdc = types.SubModuleCdc + EventTypeConnectionOpenInit = types.EventTypeConnectionOpenInit + EventTypeConnectionOpenTry = types.EventTypeConnectionOpenTry + EventTypeConnectionOpenAck = types.EventTypeConnectionOpenAck + EventTypeConnectionOpenConfirm = types.EventTypeConnectionOpenConfirm + AttributeValueCategory = types.AttributeValueCategory +) + +type ( + Keeper = keeper.Keeper + ConnectionState = types.ConnectionState + ConnectionEnd = types.ConnectionEnd + Counterparty = types.Counterparty + ClientKeeper = types.ClientKeeper + MsgConnectionOpenInit = types.MsgConnectionOpenInit + MsgConnectionOpenTry = types.MsgConnectionOpenTry + MsgConnectionOpenAck = types.MsgConnectionOpenAck + MsgConnectionOpenConfirm = types.MsgConnectionOpenConfirm + QueryConnectionParams = types.QueryConnectionParams + QueryClientConnectionsParams = types.QueryClientConnectionsParams +) diff --git a/x/ibc/03-connection/handler.go b/x/ibc/03-connection/handler.go index 0f13f5eb088a..13cecb1693fe 100644 --- a/x/ibc/03-connection/handler.go +++ b/x/ibc/03-connection/handler.go @@ -1,40 +1,13 @@ -package ics03 +package connection import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/keeper" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" ) -// NewHandler creates a new Handler instance for IBC connection -// transactions -func NewHandler(k keeper.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case types.MsgConnectionOpenInit: - return handleMsgConnectionOpenInit(ctx, k, msg) - - case types.MsgConnectionOpenTry: - return handleMsgConnectionOpenTry(ctx, k, msg) - - case types.MsgConnectionOpenAck: - return handleMsgConnectionOpenAck(ctx, k, msg) - - case types.MsgConnectionOpenConfirm: - return handleMsgConnectionOpenConfirm(ctx, k, msg) - - default: - errMsg := fmt.Sprintf("unrecognized IBC connection message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() - } - } -} - -func handleMsgConnectionOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenInit) sdk.Result { +// HandleMsgConnectionOpenInit defines the sdk.Handler for MsgConnectionOpenInit +func HandleMsgConnectionOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenInit) sdk.Result { err := k.ConnOpenInit(ctx, msg.ConnectionID, msg.ClientID, msg.Counterparty) if err != nil { return sdk.ResultFromError(err) @@ -56,7 +29,8 @@ func handleMsgConnectionOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.Msg return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgConnectionOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenTry) sdk.Result { +// HandleMsgConnectionOpenTry defines the sdk.Handler for MsgConnectionOpenTry +func HandleMsgConnectionOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenTry) sdk.Result { err := k.ConnOpenTry( ctx, msg.ConnectionID, msg.Counterparty, msg.ClientID, msg.CounterpartyVersions, msg.ProofInit, msg.ProofHeight, msg.ConsensusHeight) @@ -80,7 +54,8 @@ func handleMsgConnectionOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgC return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgConnectionOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenAck) sdk.Result { +// HandleMsgConnectionOpenAck defines the sdk.Handler for MsgConnectionOpenAck +func HandleMsgConnectionOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenAck) sdk.Result { err := k.ConnOpenAck( ctx, msg.ConnectionID, msg.Version, msg.ProofTry, msg.ProofHeight, msg.ConsensusHeight, @@ -104,7 +79,8 @@ func handleMsgConnectionOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgC return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgConnectionOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenConfirm) sdk.Result { +// HandleMsgConnectionOpenConfirm defines the sdk.Handler for MsgConnectionOpenConfirm +func HandleMsgConnectionOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgConnectionOpenConfirm) sdk.Result { err := k.ConnOpenConfirm(ctx, msg.ConnectionID, msg.ProofAck, msg.ProofHeight) if err != nil { return sdk.ResultFromError(err) diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index 5add48319e33..e3cb3c44b4f6 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -12,23 +12,23 @@ import ( ) // ConnOpenInit initialises a connection attempt on chain A. +// +// CONTRACT: Must provide a valid identifiers func (k Keeper) ConnOpenInit( ctx sdk.Context, connectionID, // identifier clientID string, counterparty types.Counterparty, // desiredCounterpartyConnectionIdentifier, counterpartyPrefix, counterpartyClientIdentifier ) error { - // TODO: validateConnectionIdentifier(identifier) _, found := k.GetConnection(ctx, connectionID) if found { - return sdkerrors.Wrap(types.ErrConnectionExists(k.codespace), "cannot initialize connection") + return sdkerrors.Wrap(types.ErrConnectionExists(k.codespace, connectionID), "cannot initialize connection") } // connection defines chain A's ConnectionEnd - connection := types.NewConnectionEnd(clientID, counterparty, k.getCompatibleVersions()) - connection.State = types.INIT - + connection := types.NewConnectionEnd(types.INIT, clientID, counterparty, k.getCompatibleVersions()) k.SetConnection(ctx, connectionID, connection) + err := k.addConnectionToClient(ctx, clientID, connectionID) if err != nil { sdkerrors.Wrap(err, "cannot initialize connection") @@ -42,6 +42,8 @@ func (k Keeper) ConnOpenInit( // code is executed on chain B). // // NOTE: here chain A acts as the counterparty +// +// CONTRACT: Must provide a valid identifiers func (k Keeper) ConnOpenTry( ctx sdk.Context, connectionID string, // desiredIdentifier @@ -52,7 +54,6 @@ func (k Keeper) ConnOpenTry( proofHeight uint64, consensusHeight uint64, ) error { - // TODO: validateConnectionIdentifier(identifier) if consensusHeight > uint64(ctx.BlockHeight()) { return errors.New("invalid consensus height") // TODO: sdk.Error } @@ -64,16 +65,15 @@ func (k Keeper) ConnOpenTry( // expectedConn defines Chain A's ConnectionEnd // NOTE: chain A's counterparty is chain B (i.e where this code is executed) - // TODO: prefix should be `getCommitmentPrefix()` - expectedCounterparty := types.NewCounterparty(counterparty.ClientID, connectionID, counterparty.Prefix) - expectedConn := types.NewConnectionEnd(clientID, expectedCounterparty, counterpartyVersions) - expectedConn.State = types.INIT + prefix := k.clientKeeper.GetCommitmentPath() // i.e `getCommitmentPrefix()` + expectedCounterparty := types.NewCounterparty(counterparty.ClientID, connectionID, prefix) + expectedConn := types.NewConnectionEnd(types.INIT, clientID, expectedCounterparty, counterpartyVersions) // chain B picks a version from Chain A's available versions version := k.pickVersion(counterpartyVersions) // connection defines chain B's ConnectionEnd - connection := types.NewConnectionEnd(clientID, counterparty, []string{version}) + connection := types.NewConnectionEnd(types.NONE, clientID, counterparty, []string{version}) expConnBz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedConn) if err != nil { return err @@ -102,7 +102,7 @@ func (k Keeper) ConnOpenTry( _, found = k.GetConnection(ctx, connectionID) if found { - return sdkerrors.Wrap(types.ErrConnectionExists(k.codespace), "cannot relay connection attempt") + return sdkerrors.Wrap(types.ErrConnectionExists(k.codespace, connectionID), "cannot relay connection attempt") } if !checkVersion(version, counterpartyVersions[0]) { @@ -122,6 +122,8 @@ func (k Keeper) ConnOpenTry( // ConnOpenAck relays acceptance of a connection open attempt from chain B back // to chain A (this code is executed on chain A). +// +// CONTRACT: Must provide a valid identifiers func (k Keeper) ConnOpenAck( ctx sdk.Context, connectionID string, @@ -137,15 +139,18 @@ func (k Keeper) ConnOpenAck( connection, found := k.GetConnection(ctx, connectionID) if !found { - return sdkerrors.Wrap(types.ErrConnectionNotFound(k.codespace), "cannot relay ACK of open attempt") + return sdkerrors.Wrap(types.ErrConnectionNotFound(k.codespace, connectionID), "cannot relay ACK of open attempt") } if connection.State != types.INIT { return errors.New("connection is in a non valid state") // TODO: sdk.Error } - if !checkVersion(connection.Versions[0], version) { - return errors.New("versions don't match") // TODO: sdk.Error + if !checkVersion(connection.LatestVersion(), version) { + return types.ErrInvalidVersion( + k.codespace, + fmt.Sprintf("connection version does't match provided one (%s ≠ %s)", connection.LatestVersion(), version), + ) } expectedConsensusState, found := k.clientKeeper.GetConsensusState(ctx, connection.ClientID) @@ -155,8 +160,7 @@ func (k Keeper) ConnOpenAck( prefix := k.clientKeeper.GetCommitmentPath() expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, prefix) - expectedConn := types.NewConnectionEnd(connection.ClientID, expectedCounterparty, []string{version}) - expectedConn.State = types.TRYOPEN + expectedConn := types.NewConnectionEnd(types.TRYOPEN, connection.ClientID, expectedCounterparty, []string{version}) expConnBz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedConn) if err != nil { @@ -185,14 +189,6 @@ func (k Keeper) ConnOpenAck( } connection.State = types.OPEN - - // abort if version is the last one - // TODO: what does this suppose to mean ? - compatibleVersions := getCompatibleVersions() - if compatibleVersions[len(compatibleVersions)-1] == version { - return errors.New("versions don't match") // TODO: sdk.Error - } - connection.Versions = []string{version} k.SetConnection(ctx, connectionID, connection) k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: INIT -> OPEN ", connectionID)) @@ -201,16 +197,17 @@ func (k Keeper) ConnOpenAck( // ConnOpenConfirm confirms opening of a connection on chain A to chain B, after // which the connection is open on both chains (this code is executed on chain B). +// +// CONTRACT: Must provide a valid identifiers func (k Keeper) ConnOpenConfirm( ctx sdk.Context, connectionID string, proofAck ics23.Proof, proofHeight uint64, ) error { - // TODO: validateConnectionIdentifier(identifier) connection, found := k.GetConnection(ctx, connectionID) if !found { - return sdkerrors.Wrap(types.ErrConnectionNotFound(k.codespace), "cannot relay ACK of open attempt") + return sdkerrors.Wrap(types.ErrConnectionNotFound(k.codespace, connectionID), "cannot relay ACK of open attempt") } if connection.State != types.TRYOPEN { @@ -219,8 +216,7 @@ func (k Keeper) ConnOpenConfirm( prefix := k.clientKeeper.GetCommitmentPath() expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, prefix) - expectedConn := types.NewConnectionEnd(connection.ClientID, expectedCounterparty, connection.Versions) - expectedConn.State = types.OPEN + expectedConn := types.NewConnectionEnd(types.OPEN, connection.ClientID, expectedCounterparty, connection.Versions) expConnBz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedConn) if err != nil { diff --git a/x/ibc/03-connection/keeper/keeper.go b/x/ibc/03-connection/keeper/keeper.go index 4cdc998e9c26..3ba4e36f3c52 100644 --- a/x/ibc/03-connection/keeper/keeper.go +++ b/x/ibc/03-connection/keeper/keeper.go @@ -87,7 +87,7 @@ func (k Keeper) SetClientConnectionPaths(ctx sdk.Context, clientID string, paths func (k Keeper) addConnectionToClient(ctx sdk.Context, clientID, connectionID string) sdk.Error { conns, found := k.GetClientConnectionPaths(ctx, clientID) if !found { - return types.ErrClientConnectionPathsNotFound(k.codespace) + return types.ErrClientConnectionPathsNotFound(k.codespace, clientID) } conns = append(conns, connectionID) @@ -102,7 +102,7 @@ func (k Keeper) addConnectionToClient(ctx sdk.Context, clientID, connectionID st func (k Keeper) removeConnectionFromClient(ctx sdk.Context, clientID, connectionID string) sdk.Error { conns, found := k.GetClientConnectionPaths(ctx, clientID) if !found { - return types.ErrClientConnectionPathsNotFound(k.codespace) + return types.ErrClientConnectionPathsNotFound(k.codespace, clientID) } conns, ok := removePath(conns, connectionID) @@ -166,8 +166,7 @@ func (k Keeper) applyPrefix(prefix ics23.Prefix, path string) string { // checkVersion is an opaque function defined by the host state machine which // determines if two versions are compatible func checkVersion(version, counterpartyVersion string) bool { - // TODO: - return true + return version == counterpartyVersion } // removePath is an util function to remove a path from a set. diff --git a/x/ibc/03-connection/types/connection.go b/x/ibc/03-connection/types/connection.go index ad744dddc004..a03a023ee820 100644 --- a/x/ibc/03-connection/types/connection.go +++ b/x/ibc/03-connection/types/connection.go @@ -6,18 +6,6 @@ import ( // ICS03 - Connection Data Structures as defined in https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#data-structures -// ConnectionState defines the state of a connection between two disctinct -// chains -type ConnectionState = byte - -// available connection states -const ( - NONE ConnectionState = iota // default ConnectionState - INIT - TRYOPEN - OPEN -) - // ConnectionEnd defines a stateful object on a chain connected to another separate // one. // NOTE: there must only be 2 defined ConnectionEnds to stablish a connection @@ -34,15 +22,25 @@ type ConnectionEnd struct { } // NewConnectionEnd creates a new ConnectionEnd instance. -func NewConnectionEnd(clientID string, counterparty Counterparty, versions []string) ConnectionEnd { +func NewConnectionEnd(state ConnectionState, clientID string, counterparty Counterparty, versions []string) ConnectionEnd { return ConnectionEnd{ - State: NONE, + State: state, ClientID: clientID, Counterparty: counterparty, Versions: versions, } } +// LatestVersion gets the latest version of a connection protocol +func (ce ConnectionEnd) LatestVersion() string { + if len(ce.Versions) == 0 { + return "" + } + return ce.Versions[len(ce.Versions)-1] +} + +// TODO: create a custom JSON marshaler + // Counterparty defines the counterparty chain associated with a connection end. type Counterparty struct { ClientID string `json:"client_id" yaml:"client_id"` @@ -58,3 +56,47 @@ func NewCounterparty(clientID, connectionID string, prefix ics23.Prefix) Counter Prefix: prefix, } } + +// ConnectionState defines the state of a connection between two disctinct +// chains +type ConnectionState = byte + +// available connection states +const ( + NONE ConnectionState = iota // default ConnectionState + INIT + TRYOPEN + OPEN +) + +// ConnectionStateToString returns the string representation of a connection state +func ConnectionStateToString(state ConnectionState) string { + switch state { + case NONE: + return "NONE" + case INIT: + return "INIT" + case TRYOPEN: + return "TRYOPEN" + case OPEN: + return "OPEN" + default: + return "" + } +} + +// StringToConnectionState parses a string into a connection state +func StringToConnectionState(state string) ConnectionState { + switch state { + case "NONE": + return NONE + case "INIT": + return INIT + case "TRYOPEN": + return TRYOPEN + case "OPEN": + return OPEN + default: + return NONE + } +} diff --git a/x/ibc/03-connection/types/errors.go b/x/ibc/03-connection/types/errors.go index d6ce1c6a300f..b25164aaf68e 100644 --- a/x/ibc/03-connection/types/errors.go +++ b/x/ibc/03-connection/types/errors.go @@ -1,6 +1,8 @@ package types import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -13,21 +15,23 @@ const ( CodeClientConnectionPathsNotFound sdk.CodeType = 103 CodeConnectionPath sdk.CodeType = 104 CodeInvalidCounterpartyConnection sdk.CodeType = 105 + CodeInvalidVersion sdk.CodeType = 106 + CodeInvalidHeight sdk.CodeType = 107 ) // ErrConnectionExists implements sdk.Error -func ErrConnectionExists(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeConnectionExists, "connection already exists") +func ErrConnectionExists(codespace sdk.CodespaceType, connectionID string) sdk.Error { + return sdk.NewError(codespace, CodeConnectionExists, fmt.Sprintf("connection with ID %s already exists", connectionID)) } // ErrConnectionNotFound implements sdk.Error -func ErrConnectionNotFound(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeConnectionNotFound, "connection not found") +func ErrConnectionNotFound(codespace sdk.CodespaceType, connectionID string) sdk.Error { + return sdk.NewError(codespace, CodeConnectionNotFound, fmt.Sprintf("connection with ID %s not found", connectionID)) } // ErrClientConnectionPathsNotFound implements sdk.Error -func ErrClientConnectionPathsNotFound(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeClientConnectionPathsNotFound, "client connection paths not found") +func ErrClientConnectionPathsNotFound(codespace sdk.CodespaceType, clientID string) sdk.Error { + return sdk.NewError(codespace, CodeClientConnectionPathsNotFound, fmt.Sprintf("client connection paths not found for ID %s", clientID)) } // ErrConnectionPath implements sdk.Error @@ -39,3 +43,13 @@ func ErrConnectionPath(codespace sdk.CodespaceType) sdk.Error { func ErrInvalidCounterpartyConnection(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidCounterpartyConnection, "couldn't verify connection membership on counterparty's client") } + +// ErrInvalidVersion implements sdk.Error +func ErrInvalidVersion(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidVersion, msg) +} + +// ErrInvalidHeight implements sdk.Error +func ErrInvalidHeight(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidHeight, msg) +} diff --git a/x/ibc/03-connection/types/events.go b/x/ibc/03-connection/types/events.go index 5dece7400bdb..2ede46db907c 100644 --- a/x/ibc/03-connection/types/events.go +++ b/x/ibc/03-connection/types/events.go @@ -8,16 +8,16 @@ import ( // IBC connection events const ( - EventTypeConnectionOpenInit = "connection_open_init" - EventTypeConnectionOpenTry = "connection_open_try" - EventTypeConnectionOpenAck = "connection_open_ack" - EventTypeConnectionOpenConfirm = "connection_open_confirm" - AttributeKeyConnectionID = "connection_id" AttributeKeyCounterpartyClientID = "counterparty_client_id" ) // IBC connection events vars var ( + EventTypeConnectionOpenInit = MsgConnectionOpenInit{}.Type() + EventTypeConnectionOpenTry = MsgConnectionOpenTry{}.Type() + EventTypeConnectionOpenAck = MsgConnectionOpenAck{}.Type() + EventTypeConnectionOpenConfirm = MsgConnectionOpenConfirm{}.Type() + AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, SubModuleName) ) diff --git a/x/ibc/03-connection/types/expected_keepers.go b/x/ibc/03-connection/types/expected_keepers.go index 2c03af61160b..5fa30c6c4f40 100644 --- a/x/ibc/03-connection/types/expected_keepers.go +++ b/x/ibc/03-connection/types/expected_keepers.go @@ -5,7 +5,6 @@ import ( ics02exported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ics02types "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" ) // ClientKeeper expected account IBC client keeper diff --git a/x/ibc/03-connection/types/msgs.go b/x/ibc/03-connection/types/msgs.go index 2984d4436f7b..c72825b04e4c 100644 --- a/x/ibc/03-connection/types/msgs.go +++ b/x/ibc/03-connection/types/msgs.go @@ -1,6 +1,8 @@ package types import ( + "strings" + sdk "github.com/cosmos/cosmos-sdk/types" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" @@ -44,7 +46,10 @@ func (msg MsgConnectionOpenInit) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgConnectionOpenInit) ValidateBasic() sdk.Error { - // TODO: + // TODO: validate IDs; Blocked on ICS24 + if msg.Signer.Empty() { + return sdk.ErrInvalidAddress("missing signer address") + } return nil } @@ -105,7 +110,28 @@ func (msg MsgConnectionOpenTry) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgConnectionOpenTry) ValidateBasic() sdk.Error { - // TODO: + // TODO: validate IDs; Blocked on ICS24 + if len(msg.CounterpartyVersions) == 0 { + return ErrInvalidVersion(DefaultCodespace, "missing counterparty versions") + } + + for _, version := range msg.CounterpartyVersions { + if strings.TrimSpace(version) == "" { + return ErrInvalidVersion(DefaultCodespace, "version can't be blank") + } + } + + if msg.ProofHeight == 0 { + return ErrInvalidHeight(DefaultCodespace, "proof height must be > 0") + } + + if msg.ConsensusHeight == 0 { + return ErrInvalidHeight(DefaultCodespace, "consensus height must be > 0") + } + + if msg.Signer.Empty() { + return sdk.ErrInvalidAddress("missing signer address") + } return nil } @@ -160,7 +186,21 @@ func (msg MsgConnectionOpenAck) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgConnectionOpenAck) ValidateBasic() sdk.Error { - // TODO: + if strings.TrimSpace(msg.Version) == "" { + return ErrInvalidVersion(DefaultCodespace, "version can't be blank") + } + + if msg.ProofHeight == 0 { + return ErrInvalidHeight(DefaultCodespace, "proof height must be > 0") + } + + if msg.ConsensusHeight == 0 { + return ErrInvalidHeight(DefaultCodespace, "consensus height must be > 0") + } + + if msg.Signer.Empty() { + return sdk.ErrInvalidAddress("missing signer address") + } return nil } @@ -209,7 +249,14 @@ func (msg MsgConnectionOpenConfirm) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgConnectionOpenConfirm) ValidateBasic() sdk.Error { - // TODO: + // TODO: validate IDs; Blocked on ICS24 + if msg.ProofHeight == 0 { + return ErrInvalidHeight(DefaultCodespace, "proof height must be > 0") + } + + if msg.Signer.Empty() { + return sdk.ErrInvalidAddress("missing signer address") + } return nil } diff --git a/x/ibc/handler.go b/x/ibc/handler.go index 5dc802b6f063..ed740f39183e 100644 --- a/x/ibc/handler.go +++ b/x/ibc/handler.go @@ -5,6 +5,7 @@ import ( 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" ) // NewHandler defines the IBC handler @@ -22,8 +23,20 @@ func NewHandler(k Keeper) sdk.Handler { case client.MsgSubmitMisbehaviour: return client.HandleMsgSubmitMisbehaviour(ctx, k.ClientKeeper, msg) + case connection.MsgConnectionOpenInit: + return connection.HandleMsgConnectionOpenInit(ctx, k.ConnectionKeeper, msg) + + case connection.MsgConnectionOpenTry: + return connection.HandleMsgConnectionOpenTry(ctx, k.ConnectionKeeper, msg) + + case connection.MsgConnectionOpenAck: + return connection.HandleMsgConnectionOpenAck(ctx, k.ConnectionKeeper, msg) + + case connection.MsgConnectionOpenConfirm: + return connection.HandleMsgConnectionOpenConfirm(ctx, k.ConnectionKeeper, msg) + default: - errMsg := fmt.Sprintf("unrecognized IBC Client message type: %T", msg) + errMsg := fmt.Sprintf("unrecognized IBC message type: %T", msg) return sdk.ErrUnknownRequest(errMsg).Result() } } diff --git a/x/ibc/keeper/keeper.go b/x/ibc/keeper/keeper.go index 1dd8abef5596..dafe8892d167 100644 --- a/x/ibc/keeper/keeper.go +++ b/x/ibc/keeper/keeper.go @@ -3,17 +3,23 @@ package keeper import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - ics02 "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" ) // Keeper defines each ICS keeper for IBC type Keeper struct { - ClientKeeper ics02.Keeper + ClientKeeper client.Keeper + ConnectionKeeper connection.Keeper } // NewKeeper creates a new ibc Keeper func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) Keeper { + clientKeeper := client.NewKeeper(cdc, key, codespace) + connectionKeeper := connection.NewKeeper(cdc, key, codespace, clientKeeper) + return Keeper{ - ClientKeeper: ics02.NewKeeper(cdc, key, codespace), + ClientKeeper: clientKeeper, + ConnectionKeeper: connectionKeeper, } } From 245901c42e380862e4f8134af3c6c1da631ad7cc Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 15 Oct 2019 17:03:22 +0200 Subject: [PATCH 295/378] update connection versioning --- x/ibc/03-connection/keeper/handshake.go | 28 ++++---- x/ibc/03-connection/keeper/keeper.go | 20 +----- x/ibc/03-connection/types/connection.go | 8 --- x/ibc/03-connection/types/errors.go | 6 ++ x/ibc/03-connection/types/keys.go | 2 +- x/ibc/03-connection/types/version.go | 96 +++++++++++++++++++++++++ 6 files changed, 117 insertions(+), 43 deletions(-) create mode 100644 x/ibc/03-connection/types/version.go diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index e3cb3c44b4f6..7b96f0b0d175 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -13,7 +13,7 @@ import ( // ConnOpenInit initialises a connection attempt on chain A. // -// CONTRACT: Must provide a valid identifiers +// NOTE: Identifiers are checked on msg validation. func (k Keeper) ConnOpenInit( ctx sdk.Context, connectionID, // identifier @@ -26,7 +26,7 @@ func (k Keeper) ConnOpenInit( } // connection defines chain A's ConnectionEnd - connection := types.NewConnectionEnd(types.INIT, clientID, counterparty, k.getCompatibleVersions()) + connection := types.NewConnectionEnd(types.INIT, clientID, counterparty, types.GetCompatibleVersions()) k.SetConnection(ctx, connectionID, connection) err := k.addConnectionToClient(ctx, clientID, connectionID) @@ -41,9 +41,9 @@ func (k Keeper) ConnOpenInit( // ConnOpenTry relays notice of a connection attempt on chain A to chain B (this // code is executed on chain B). // -// NOTE: here chain A acts as the counterparty -// -// CONTRACT: Must provide a valid identifiers +// NOTE: +// - Here chain A acts as the counterparty +// - Identifiers are checked on msg validation func (k Keeper) ConnOpenTry( ctx sdk.Context, connectionID string, // desiredIdentifier @@ -69,8 +69,9 @@ func (k Keeper) ConnOpenTry( expectedCounterparty := types.NewCounterparty(counterparty.ClientID, connectionID, prefix) expectedConn := types.NewConnectionEnd(types.INIT, clientID, expectedCounterparty, counterpartyVersions) - // chain B picks a version from Chain A's available versions - version := k.pickVersion(counterpartyVersions) + // chain B picks a version from Chain A's available versions that is compatible + // with the supported IBC versions + version := types.PickVersion(counterpartyVersions, types.GetCompatibleVersions()) // connection defines chain B's ConnectionEnd connection := types.NewConnectionEnd(types.NONE, clientID, counterparty, []string{version}) @@ -105,10 +106,6 @@ func (k Keeper) ConnOpenTry( return sdkerrors.Wrap(types.ErrConnectionExists(k.codespace, connectionID), "cannot relay connection attempt") } - if !checkVersion(version, counterpartyVersions[0]) { - return errors.New("versions don't match") // TODO: sdk.Error - } - connection.State = types.TRYOPEN err = k.addConnectionToClient(ctx, clientID, connectionID) if err != nil { @@ -123,7 +120,7 @@ func (k Keeper) ConnOpenTry( // ConnOpenAck relays acceptance of a connection open attempt from chain B back // to chain A (this code is executed on chain A). // -// CONTRACT: Must provide a valid identifiers +// NOTE: Identifiers are checked on msg validation. func (k Keeper) ConnOpenAck( ctx sdk.Context, connectionID string, @@ -132,7 +129,6 @@ func (k Keeper) ConnOpenAck( proofHeight uint64, consensusHeight uint64, ) error { - // TODO: validateConnectionIdentifier(identifier) if consensusHeight > uint64(ctx.BlockHeight()) { return errors.New("invalid consensus height") // TODO: sdk.Error } @@ -146,10 +142,10 @@ func (k Keeper) ConnOpenAck( return errors.New("connection is in a non valid state") // TODO: sdk.Error } - if !checkVersion(connection.LatestVersion(), version) { + if types.LatestVersion(connection.Versions) != version { return types.ErrInvalidVersion( k.codespace, - fmt.Sprintf("connection version does't match provided one (%s ≠ %s)", connection.LatestVersion(), version), + fmt.Sprintf("connection version does't match provided one (%s ≠ %s)", types.LatestVersion(connection.Versions), version), ) } @@ -198,7 +194,7 @@ func (k Keeper) ConnOpenAck( // ConnOpenConfirm confirms opening of a connection on chain A to chain B, after // which the connection is open on both chains (this code is executed on chain B). // -// CONTRACT: Must provide a valid identifiers +// NOTE: Identifiers are checked on msg validation. func (k Keeper) ConnOpenConfirm( ctx sdk.Context, connectionID string, diff --git a/x/ibc/03-connection/keeper/keeper.go b/x/ibc/03-connection/keeper/keeper.go index 3ba4e36f3c52..07d8563a615b 100644 --- a/x/ibc/03-connection/keeper/keeper.go +++ b/x/ibc/03-connection/keeper/keeper.go @@ -28,8 +28,8 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType, return Keeper{ storeKey: key, cdc: cdc, - codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/connections", - prefix: []byte(types.SubModuleName + "/"), // "connections/" + codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/connection", + prefix: []byte(types.SubModuleName + "/"), // "connection/" clientKeeper: ck, } } @@ -148,27 +148,11 @@ func (k Keeper) VerifyNonMembership( return k.clientKeeper.VerifyNonMembership(ctx, clientState, height, proof, path) } -func (k Keeper) getCompatibleVersions() []string { - // TODO: - return nil -} - -func (k Keeper) pickVersion(counterpartyVersions []string) string { - // TODO: - return "" -} - func (k Keeper) applyPrefix(prefix ics23.Prefix, path string) string { // TODO: return path } -// checkVersion is an opaque function defined by the host state machine which -// determines if two versions are compatible -func checkVersion(version, counterpartyVersion string) bool { - return version == counterpartyVersion -} - // removePath is an util function to remove a path from a set. // // TODO: move to ICS24 diff --git a/x/ibc/03-connection/types/connection.go b/x/ibc/03-connection/types/connection.go index a03a023ee820..25ad7ef8f4dc 100644 --- a/x/ibc/03-connection/types/connection.go +++ b/x/ibc/03-connection/types/connection.go @@ -31,14 +31,6 @@ func NewConnectionEnd(state ConnectionState, clientID string, counterparty Count } } -// LatestVersion gets the latest version of a connection protocol -func (ce ConnectionEnd) LatestVersion() string { - if len(ce.Versions) == 0 { - return "" - } - return ce.Versions[len(ce.Versions)-1] -} - // TODO: create a custom JSON marshaler // Counterparty defines the counterparty chain associated with a connection end. diff --git a/x/ibc/03-connection/types/errors.go b/x/ibc/03-connection/types/errors.go index b25164aaf68e..cfdfd9f5eeda 100644 --- a/x/ibc/03-connection/types/errors.go +++ b/x/ibc/03-connection/types/errors.go @@ -17,6 +17,7 @@ const ( CodeInvalidCounterpartyConnection sdk.CodeType = 105 CodeInvalidVersion sdk.CodeType = 106 CodeInvalidHeight sdk.CodeType = 107 + CodeInvalidConnectionState sdk.CodeType = 108 ) // ErrConnectionExists implements sdk.Error @@ -53,3 +54,8 @@ func ErrInvalidVersion(codespace sdk.CodespaceType, msg string) sdk.Error { func ErrInvalidHeight(codespace sdk.CodespaceType, msg string) sdk.Error { return sdk.NewError(codespace, CodeInvalidHeight, msg) } + +// ErrInvalidConnectionState implements sdk.Error +func ErrInvalidConnectionState(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidConnectionState, msg) +} diff --git a/x/ibc/03-connection/types/keys.go b/x/ibc/03-connection/types/keys.go index 339c945a52b5..7dd82ae80a2e 100644 --- a/x/ibc/03-connection/types/keys.go +++ b/x/ibc/03-connection/types/keys.go @@ -6,7 +6,7 @@ import ( const ( // SubModuleName defines the IBC connection name - SubModuleName = "connections" + SubModuleName = "connection" // StoreKey is the store key string for IBC connections StoreKey = SubModuleName diff --git a/x/ibc/03-connection/types/version.go b/x/ibc/03-connection/types/version.go new file mode 100644 index 000000000000..aa33a6a7b781 --- /dev/null +++ b/x/ibc/03-connection/types/version.go @@ -0,0 +1,96 @@ +package types + +// GetCompatibleVersions returns an ordered set of compatible IBC versions for the +// caller chain's connection end. +func GetCompatibleVersions() []string { + return []string{"1.0.0"} +} + +// LatestVersion gets the latest version of a connection protocol +// +// CONTRACT: version array MUST be already sorted. +func LatestVersion(versions []string) string { + if len(versions) == 0 { + return "" + } + return versions[len(versions)-1] +} + +// PickVersion picks the counterparty latest version that is matches the list +// of compatible versions for the connection. +func PickVersion(counterpartyVersions, compatibleVersions []string) string { + + n := len(counterpartyVersions) + m := len(compatibleVersions) + + // aux hash maps to lookup already seen versions + counterpartyVerLookup := make(map[string]bool) + compatibleVerLookup := make(map[string]bool) + + // versions suported + var supportedVersions []string + + switch { + case n == 0: + return "" + case n == m: + for i := n - 1; i >= 0; i-- { + counterpartyVerLookup[counterpartyVersions[i]] = true + compatibleVerLookup[compatibleVersions[i]] = true + + // check if we've seen any of the versions + if _, ok := compatibleVerLookup[counterpartyVersions[i]]; ok { + supportedVersions = append(supportedVersions, counterpartyVersions[i]) + } + + if _, ok := counterpartyVerLookup[compatibleVersions[i]]; ok { + // TODO: check if the version is already in the array + supportedVersions = append(supportedVersions, compatibleVersions[i]) + } + } + case n > m: + for i := n - 1; i >= m; i-- { + counterpartyVerLookup[compatibleVersions[i]] = true + } + + for i := m - 1; i >= 0; i-- { + counterpartyVerLookup[counterpartyVersions[i]] = true + compatibleVerLookup[compatibleVersions[i]] = true + + // check if we've seen any of the versions + if _, ok := compatibleVerLookup[counterpartyVersions[i]]; ok { + supportedVersions = append(supportedVersions, counterpartyVersions[i]) + } + + if _, ok := counterpartyVerLookup[compatibleVersions[i]]; ok { + supportedVersions = append(supportedVersions, compatibleVersions[i]) + } + } + + case n < m: + for i := m - 1; i >= n; i-- { + compatibleVerLookup[compatibleVersions[i]] = true + } + + for i := n - 1; i >= 0; i-- { + counterpartyVerLookup[counterpartyVersions[i]] = true + compatibleVerLookup[compatibleVersions[i]] = true + + // check if we've seen any of the versions + if _, ok := compatibleVerLookup[counterpartyVersions[i]]; ok { + supportedVersions = append(supportedVersions, counterpartyVersions[i]) + } + + if _, ok := counterpartyVerLookup[compatibleVersions[i]]; ok { + supportedVersions = append(supportedVersions, compatibleVersions[i]) + } + } + } + + if len(supportedVersions) == 0 { + return "" + } + + // TODO: compare latest version before appending + return supportedVersions[len(supportedVersions)-1] +} From 7a821449728cb36a8cdf218c7179e6c0fde95562 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 15 Oct 2019 18:25:16 +0200 Subject: [PATCH 296/378] minor error updates --- x/ibc/03-connection/client/cli/tx.go | 246 ------------------------ x/ibc/03-connection/keeper/handshake.go | 10 +- x/ibc/03-connection/types/codec.go | 1 + x/ibc/03-connection/types/version.go | 2 +- 4 files changed, 10 insertions(+), 249 deletions(-) diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index a7376dfcdc81..856f6ba47449 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -20,11 +20,6 @@ import ( ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -// const ( -// FlagNode2 = "node2" -// FlagFrom2 = "from2" -// ) - // GetTxCmd returns the transaction commands for IBC Connections func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ics03ConnectionTxCmd := &cobra.Command{ @@ -61,10 +56,6 @@ $ %s tx ibc connection open-init [connection-id] [client-id] [counterparty-conne RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) - // cliCtx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). - // WithCodec(cdc). - // WithNodeURI(viper.GetString(FlagNode2)). - // WithBroadcastMode(flags.BroadcastBlock) connectionID := args[0] clientID := args[1] @@ -115,9 +106,6 @@ $ %s tx ibc connection open-try connection-id] [client-id] cliCtx := context.NewCLIContext(). WithCodec(cdc). WithHeight(viper.GetInt64(flags.FlagHeight)) - // cliCtx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). - // WithCodec(cdc). - // WithNodeURI(viper.GetString(FlagNode2)). connectionID := args[0] clientID := args[1] @@ -182,10 +170,6 @@ $ %s tx ibc connection open-ack [connection-id] [path/to/proof_try.json] [versio RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) - // cliCtx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). - // WithCodec(cdc). - // WithNodeURI(viper.GetString(FlagNode2)). - // WithBroadcastMode(flags.BroadcastBlock) connectionID := args[0] proofBz, err := ioutil.ReadFile(args[1]) @@ -236,10 +220,6 @@ $ %s tx ibc connection open-confirm [connection-id] [path/to/proof_ack.json] cliCtx := context.NewCLIContext(). WithCodec(cdc). WithHeight(viper.GetInt64(flags.FlagHeight)) - // cliCtx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). - // WithCodec(cdc). - // WithNodeURI(viper.GetString(FlagNode2)). - // WithBroadcastMode(flags.BroadcastBlock) connectionID := args[0] @@ -279,229 +259,3 @@ func lastHeight(cliCtx context.CLIContext) (uint64, error) { return uint64(info.Response.LastBlockHeight), nil } - -// func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { -// cmd := &cobra.Command{ -// Use: "handshake", -// Short: "initiate connection handshake between two chains", -// Args: cobra.ExactArgs(6), -// RunE: func(cmd *cobra.Command, args []string) error { -// txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) -// ctx1 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). -// WithCodec(cdc). -// WithNodeURI(viper.GetString(FlagNode1)). -// WithBroadcastMode(flags.BroadcastBlock) -// q1 := storestate.NewCLIQuerier(ctx1) - -// ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). -// WithCodec(cdc). -// WithNodeURI(viper.GetString(FlagNode2)). -// WithBroadcastMode(flags.BroadcastBlock) -// q2 := storestate.NewCLIQuerier(ctx2) - -// connId1 := args[0] -// clientId1 := args[1] -// connId2 := args[3] -// clientId2 := args[4] - -// var path1 commitment.Prefix -// path1bz, err := ioutil.ReadFile(args[2]) -// if err != nil { -// return err -// } -// if err = cdc.UnmarshalJSON(path1bz, &path1); err != nil { -// return err -// } -// conn1 := connection.Connection{ -// Client: clientId1, -// Counterparty: connId2, -// Path: path1, -// } - -// obj1, err := handshake(q1, cdc, storeKey, version.DefaultPrefix(), connId1) -// if err != nil { -// return err -// } - -// var path2 commitment.Prefix -// path2bz, err := ioutil.ReadFile(args[5]) -// if err != nil { -// return err -// } -// if err = cdc.UnmarshalJSON(path2bz, &path2); err != nil { -// return err -// } -// conn2 := connection.Connection{ -// Client: clientId2, -// Counterparty: connId1, -// Path: path2, -// } - -// obj2, err := handshake(q2, cdc, storeKey, version.DefaultPrefix(), connId2) -// if err != nil { -// return err -// } - -// // TODO: check state and if not Idle continue existing process -// msgInit := connection.MsgOpenInit{ -// ConnectionID: connId1, -// Connection: conn1, -// CounterpartyClient: conn2.Client, -// Signer: ctx1.GetFromAddress(), -// } - -// err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgInit}) -// 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 -// } - -// msgUpdate := client.MsgUpdateClient{ -// ClientID: conn2.Client, -// Header: header, -// Signer: ctx2.GetFromAddress(), -// } - -// err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) -// if err != nil { -// return err -// } - -// q1 = storestate.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 -// } -// _, pstate, err := obj1.StageCLI(q1) -// if err != nil { -// return err -// } -// _, pcounter, err := obj1.CounterpartyClientCLI(q1) -// if err != nil { -// return err -// } - -// msgTry := connection.MsgOpenTry{ -// ConnectionID: connId2, -// Connection: conn2, -// CounterpartyClient: conn1.Client, -// Proofs: []commitment.Proof{pconn, pstate, pcounter}, -// Height: uint64(header.Height), -// Signer: ctx2.GetFromAddress(), -// } - -// err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgTry}) -// 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(ctx2) -// if err != nil { -// return err -// } - -// msgUpdate = client.MsgUpdateClient{ -// ClientID: conn1.Client, -// Header: header, -// Signer: ctx1.GetFromAddress(), -// } - -// err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgUpdate}) -// if err != nil { -// return err -// } - -// q2 = storestate.NewCLIQuerier(ctx2.WithHeight(header.Height - 1)) - -// _, pconn, err = obj2.ConnectionCLI(q2) -// if err != nil { -// return err -// } -// _, pstate, err = obj2.StageCLI(q2) -// if err != nil { -// return err -// } -// _, pcounter, err = obj2.CounterpartyClientCLI(q2) -// if err != nil { -// return err -// } - -// 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}) -// 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 -// } - -// msgUpdate = client.MsgUpdateClient{ -// ClientID: conn2.Client, -// Header: header, -// Signer: ctx2.GetFromAddress(), -// } - -// err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgUpdate}) -// if err != nil { -// return err -// } - -// q1 = storestate.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) - -// _, pstate, err = obj1.StageCLI(q1) -// if err != nil { -// return err -// } - -// msgConfirm := connection.MsgOpenConfirm{ -// ConnectionID: connId2, -// Proofs: []commitment.Proof{pstate}, -// Height: uint64(header.Height), -// Signer: ctx2.GetFromAddress(), -// } - -// err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgConfirm}) -// if err != nil { -// return err -// } - -// return nil -// }, -// } -// cmd.Flags().String(FlagNode2, "tcp://localhost:26657", "") -// cmd.Flags().String(FlagFrom2, "", "") - -// return cmd -// } diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index 7b96f0b0d175..8dc0760ad1a2 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -139,7 +139,10 @@ func (k Keeper) ConnOpenAck( } if connection.State != types.INIT { - return errors.New("connection is in a non valid state") // TODO: sdk.Error + return types.ErrInvalidConnectionState( + k.codespace, + fmt.Sprintf("connection state is not INIT (got %s)", types.ConnectionStateToString(connection.State)), + ) } if types.LatestVersion(connection.Versions) != version { @@ -207,7 +210,10 @@ func (k Keeper) ConnOpenConfirm( } if connection.State != types.TRYOPEN { - return errors.New("connection is in a non valid state") // TODO: sdk.Error + return types.ErrInvalidConnectionState( + k.codespace, + fmt.Sprintf("connection state is not TRYOPEN (got %s)", types.ConnectionStateToString(connection.State)), + ) } prefix := k.clientKeeper.GetCommitmentPath() diff --git a/x/ibc/03-connection/types/codec.go b/x/ibc/03-connection/types/codec.go index 81758fa41f3c..5c197d6142b5 100644 --- a/x/ibc/03-connection/types/codec.go +++ b/x/ibc/03-connection/types/codec.go @@ -11,6 +11,7 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgConnectionOpenTry{}, "ibc/connection/MsgConnectionOpenTry", nil) cdc.RegisterConcrete(MsgConnectionOpenAck{}, "ibc/connection/MsgConnectionOpenAck", nil) cdc.RegisterConcrete(MsgConnectionOpenConfirm{}, "ibc/connection/MsgConnectionOpenConfirm", nil) + cdc.RegisterConcrete(ConnectionEnd{}, "ibc/connection/ConnectionEnd", nil) } func SetMsgConnectionCodec(cdc *codec.Codec) { diff --git a/x/ibc/03-connection/types/version.go b/x/ibc/03-connection/types/version.go index aa33a6a7b781..bf74a52dae92 100644 --- a/x/ibc/03-connection/types/version.go +++ b/x/ibc/03-connection/types/version.go @@ -31,7 +31,7 @@ func PickVersion(counterpartyVersions, compatibleVersions []string) string { var supportedVersions []string switch { - case n == 0: + case n == 0 || m == 0: return "" case n == m: for i := n - 1; i >= 0; i-- { From 1b45a24a2aa421e9007de7099ecea25d6f96eb2a Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 15 Oct 2019 18:53:39 +0200 Subject: [PATCH 297/378] update ICS04 with downstream changes --- x/ibc/04-channel/alias.go | 103 +++++++++++++++++++++ x/ibc/04-channel/cli.go | 2 +- x/ibc/04-channel/handler.go | 48 ++-------- x/ibc/04-channel/keeper/handshake.go | 26 +++--- x/ibc/04-channel/keeper/keeper.go | 7 +- x/ibc/04-channel/keeper/packet.go | 20 ++-- x/ibc/04-channel/keeper/querier.go | 2 +- x/ibc/04-channel/keeper/timeout.go | 10 +- x/ibc/04-channel/types/codec.go | 1 + x/ibc/04-channel/types/errors.go | 8 +- x/ibc/04-channel/types/expected_keepers.go | 17 ++-- x/ibc/handler.go | 22 +++++ x/ibc/keeper/keeper.go | 4 + x/ibc/module.go | 1 + 14 files changed, 187 insertions(+), 84 deletions(-) create mode 100644 x/ibc/04-channel/alias.go diff --git a/x/ibc/04-channel/alias.go b/x/ibc/04-channel/alias.go new file mode 100644 index 000000000000..3859972efa1f --- /dev/null +++ b/x/ibc/04-channel/alias.go @@ -0,0 +1,103 @@ +package channel + +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" +) + +const ( + UNORDERED = types.UNORDERED + ORDERED = types.ORDERED + CLOSED = types.CLOSED + INIT = types.INIT + OPENTRY = types.OPENTRY + OPEN = types.OPEN + DefaultCodespace = types.DefaultCodespace + CodeChannelExists = types.CodeChannelExists + CodeChannelNotFound = types.CodeChannelNotFound + CodeInvalidConnectionHops = types.CodeInvalidConnectionHops + CodeInvalidCounterpartyChannel = types.CodeInvalidCounterpartyChannel + CodeChannelCapabilityNotFound = types.CodeChannelCapabilityNotFound + CodeInvalidPacketSequence = types.CodeInvalidPacketSequence + CodeSequenceNotFound = types.CodeSequenceNotFound + CodePacketTimeout = types.CodePacketTimeout + EventTypeSendPacket = types.EventTypeSendPacket + EventTypeChannelOpenInit = types.EventTypeChannelOpenInit + EventTypeChannelOpenTry = types.EventTypeChannelOpenTry + EventTypeChannelOpenAck = types.EventTypeChannelOpenAck + EventTypeChannelOpenConfirm = types.EventTypeChannelOpenConfirm + EventTypeChannelCloseInit = types.EventTypeChannelCloseInit + EventTypeChannelCloseConfirm = types.EventTypeChannelCloseConfirm + AttributeKeySenderPort = types.AttributeKeySenderPort + AttributeKeyReceiverPort = types.AttributeKeyReceiverPort + AttributeKeyChannelID = types.AttributeKeyChannelID + AttributeKeySequence = types.AttributeKeySequence + SubModuleName = types.SubModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute + QueryChannel = types.QueryChannel +) + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper + NewQuerier = keeper.NewQuerier + NewChannel = types.NewChannel + NewCounterparty = types.NewCounterparty + RegisterCodec = types.RegisterCodec + SetMsgChanCodec = types.SetMsgChanCodec + ErrChannelExists = types.ErrChannelExists + ErrChannelNotFound = types.ErrChannelNotFound + ErrInvalidConnectionHops = types.ErrInvalidConnectionHops + ErrInvalidCounterpartyChannel = types.ErrInvalidCounterpartyChannel + ErrChannelCapabilityNotFound = types.ErrChannelCapabilityNotFound + ErrInvalidPacketSequence = types.ErrInvalidPacketSequence + ErrSequenceNotFound = types.ErrSequenceNotFound + ErrPacketTimeout = types.ErrPacketTimeout + ChannelPath = types.ChannelPath + ChannelCapabilityPath = types.ChannelCapabilityPath + NextSequenceSendPath = types.NextSequenceSendPath + NextSequenceRecvPath = types.NextSequenceRecvPath + PacketCommitmentPath = types.PacketCommitmentPath + PacketAcknowledgementPath = types.PacketAcknowledgementPath + KeyChannel = types.KeyChannel + KeyChannelCapabilityPath = types.KeyChannelCapabilityPath + KeyNextSequenceSend = types.KeyNextSequenceSend + KeyNextSequenceRecv = types.KeyNextSequenceRecv + KeyPacketCommitment = types.KeyPacketCommitment + KeyPacketAcknowledgement = types.KeyPacketAcknowledgement + NewPacket = types.NewPacket + NewQueryChannelParams = types.NewQueryChannelParams + + // variable aliases + SubModuleCdc = types.SubModuleCdc + AttributeValueCategory = types.AttributeValueCategory +) + +type ( + Keeper = keeper.Keeper + ChannelOrder = types.ChannelOrder + ChannelState = types.ChannelState + Channel = types.Channel + Counterparty = types.Counterparty + ClientKeeper = types.ClientKeeper + ConnectionKeeper = types.ConnectionKeeper + MsgChannelOpenInit = types.MsgChannelOpenInit + MsgChannelOpenTry = types.MsgChannelOpenTry + MsgChannelOpenAck = types.MsgChannelOpenAck + MsgChannelOpenConfirm = types.MsgChannelOpenConfirm + MsgChannelCloseInit = types.MsgChannelCloseInit + MsgChannelCloseConfirm = types.MsgChannelCloseConfirm + MsgSendPacket = types.MsgSendPacket + Packet = types.Packet + OpaquePacket = types.OpaquePacket + Port = types.Port + QueryChannelParams = types.QueryChannelParams +) diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go index b03a9d8b2615..0cbc44a37b80 100644 --- a/x/ibc/04-channel/cli.go +++ b/x/ibc/04-channel/cli.go @@ -1,4 +1,4 @@ -package ics04 +package channel // import ( // "bytes" diff --git a/x/ibc/04-channel/handler.go b/x/ibc/04-channel/handler.go index 2b324a955ae3..7085a392de8c 100644 --- a/x/ibc/04-channel/handler.go +++ b/x/ibc/04-channel/handler.go @@ -1,46 +1,12 @@ -package ics04 +package channel import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ) -// NewHandler creates a new Handler instance for IBC connection -// transactions -func NewHandler(k keeper.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case types.MsgChannelOpenInit: - return handleMsgChannelOpenInit(ctx, k, msg) - - case types.MsgChannelOpenTry: - return handleMsgChannelOpenTry(ctx, k, msg) - - case types.MsgChannelOpenAck: - return handleMsgChannelOpenAck(ctx, k, msg) - - case types.MsgChannelOpenConfirm: - return handleMsgChannelOpenConfirm(ctx, k, msg) - - case types.MsgChannelCloseInit: - return handleMsgChannelCloseInit(ctx, k, msg) - - case types.MsgChannelCloseConfirm: - return handleMsgChannelCloseConfirm(ctx, k, msg) - - default: - errMsg := fmt.Sprintf("unrecognized IBC connection message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() - } - } -} - -func handleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenInit) sdk.Result { +func HandleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenInit) sdk.Result { _, err := k.ChanOpenInit( ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, msg.Channel.Counterparty, msg.Channel.Version, @@ -65,7 +31,7 @@ func handleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgCha return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgChannelOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenTry) sdk.Result { +func HandleMsgChannelOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenTry) sdk.Result { _, err := k.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, msg.Channel.Counterparty, msg.Channel.Version, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, ) @@ -90,7 +56,7 @@ func handleMsgChannelOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgChan return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgChannelOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenAck) sdk.Result { +func HandleMsgChannelOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenAck) sdk.Result { err := k.ChanOpenAck( ctx, msg.PortID, msg.ChannelID, msg.CounterpartyVersion, msg.ProofTry, msg.ProofHeight, ) @@ -114,7 +80,7 @@ func handleMsgChannelOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgChan return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgChannelOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenConfirm) sdk.Result { +func HandleMsgChannelOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenConfirm) sdk.Result { err := k.ChanOpenConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofAck, msg.ProofHeight) if err != nil { return sdk.ResultFromError(err) @@ -136,7 +102,7 @@ func handleMsgChannelOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.Msg return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgChannelCloseInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseInit) sdk.Result { +func HandleMsgChannelCloseInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseInit) sdk.Result { err := k.ChanCloseInit(ctx, msg.PortID, msg.ChannelID) if err != nil { return sdk.ResultFromError(err) @@ -158,7 +124,7 @@ func handleMsgChannelCloseInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgCh return sdk.Result{Events: ctx.EventManager().Events()} } -func handleMsgChannelCloseConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseConfirm) sdk.Result { +func HandleMsgChannelCloseConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseConfirm) sdk.Result { err := k.ChanCloseConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofInit, msg.ProofHeight) if err != nil { return sdk.ResultFromError(err) diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go index 9d7c07cdc843..bbbcdacfd88c 100644 --- a/x/ibc/04-channel/keeper/handshake.go +++ b/x/ibc/04-channel/keeper/handshake.go @@ -27,12 +27,12 @@ func (k Keeper) ChanOpenInit( _, found := k.GetChannel(ctx, portID, channelID) if found { - return "", types.ErrChannelExists(k.codespace) + return "", types.ErrChannelExists(k.codespace, channelID) } connection, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) if !found { - return "", ics03types.ErrConnectionNotFound(k.codespace) + return "", ics03types.ErrConnectionNotFound(k.codespace, connectionHops[0]) } // TODO: inconsistency on ICS03 (`none`) and ICS04 (`CLOSED`) @@ -40,7 +40,6 @@ func (k Keeper) ChanOpenInit( return "", errors.New("connection is closed") } - // TODO: Blocked - ICS05 Not implemented yet // port, found := k.portKeeper.GetPort(ctx, portID) // if !found { // return errors.New("port not found") // TODO: ics05 sdk.Error @@ -82,10 +81,9 @@ func (k Keeper) ChanOpenTry( _, found := k.GetChannel(ctx, portID, channelID) if found { - return "", types.ErrChannelExists(k.codespace) + return "", types.ErrChannelExists(k.codespace, channelID) } - // TODO: Blocked - ICS05 Not implemented yet // port, found := k.portKeeper.GetPort(ctx, portID) // if !found { // return errors.New("port not found") // TODO: ics05 sdk.Error @@ -97,7 +95,7 @@ func (k Keeper) ChanOpenTry( connection, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) if !found { - return "", ics03types.ErrConnectionNotFound(k.codespace) + return "", ics03types.ErrConnectionNotFound(k.codespace, connectionHops[0]) } if connection.State != ics03types.OPEN { @@ -152,7 +150,7 @@ func (k Keeper) ChanOpenAck( channel, found := k.GetChannel(ctx, portID, channelID) if !found { - return types.ErrChannelNotFound(k.codespace) + return types.ErrChannelNotFound(k.codespace, channelID) } if channel.State != types.INIT { @@ -170,7 +168,7 @@ func (k Keeper) ChanOpenAck( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return ics03types.ErrConnectionNotFound(k.codespace) + return ics03types.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } if connection.State != ics03types.OPEN { @@ -215,7 +213,7 @@ func (k Keeper) ChanOpenConfirm( ) error { channel, found := k.GetChannel(ctx, portID, channelID) if !found { - return types.ErrChannelNotFound(k.codespace) + return types.ErrChannelNotFound(k.codespace, channelID) } if channel.State != types.OPENTRY { @@ -233,7 +231,7 @@ func (k Keeper) ChanOpenConfirm( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return ics03types.ErrConnectionNotFound(k.codespace) + return ics03types.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } if connection.State != ics03types.OPEN { @@ -284,7 +282,7 @@ func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error { channel, found := k.GetChannel(ctx, portID, channelID) if !found { - return types.ErrChannelNotFound(k.codespace) + return types.ErrChannelNotFound(k.codespace, channelID) } if channel.State == types.CLOSED { @@ -293,7 +291,7 @@ func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error { connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return ics03types.ErrConnectionNotFound(k.codespace) + return ics03types.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } if connection.State != ics03types.OPEN { @@ -326,7 +324,7 @@ func (k Keeper) ChanCloseConfirm( channel, found := k.GetChannel(ctx, portID, channelID) if !found { - return types.ErrChannelNotFound(k.codespace) + return types.ErrChannelNotFound(k.codespace, channelID) } if channel.State == types.CLOSED { @@ -335,7 +333,7 @@ func (k Keeper) ChanCloseConfirm( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return ics03types.ErrConnectionNotFound(k.codespace) + return ics03types.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } if connection.State != ics03types.OPEN { diff --git a/x/ibc/04-channel/keeper/keeper.go b/x/ibc/04-channel/keeper/keeper.go index c1411674442a..65dc33f22c94 100644 --- a/x/ibc/04-channel/keeper/keeper.go +++ b/x/ibc/04-channel/keeper/keeper.go @@ -22,12 +22,15 @@ type Keeper struct { clientKeeper types.ClientKeeper connectionKeeper types.ConnectionKeeper + portKeeper types.PortKeeper } // NewKeeper creates a new IBC channel Keeper instance func NewKeeper( cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType, - clientKeeper types.ClientKeeper, connectionKeeper types.ConnectionKeeper) Keeper { + clientKeeper types.ClientKeeper, connectionKeeper types.ConnectionKeeper, + // portKeeper types.PortKeeper, +) Keeper { return Keeper{ storeKey: key, cdc: cdc, @@ -35,6 +38,7 @@ func NewKeeper( prefix: []byte(types.SubModuleName + "/"), // "channel/" clientKeeper: clientKeeper, connectionKeeper: connectionKeeper, + // portKeeper: portKeeper, } } @@ -75,7 +79,6 @@ func (k Keeper) GetChannelCapability(ctx sdk.Context, portID, channelID string) } // SetChannelCapability sets a channel's capability key to the store -// TODO: is the key a string ? func (k Keeper) SetChannelCapability(ctx sdk.Context, portID, channelID string, key string) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) store.Set(types.KeyChannelCapabilityPath(portID, channelID), []byte(key)) diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go index 3fbd2dfe935c..487362647baa 100644 --- a/x/ibc/04-channel/keeper/packet.go +++ b/x/ibc/04-channel/keeper/packet.go @@ -5,7 +5,7 @@ import ( "errors" sdk "github.com/cosmos/cosmos-sdk/types" - ics03types "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" @@ -31,7 +31,7 @@ func (k Keeper) CleanupPacket( ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, types.ErrChannelNotFound(k.codespace) + return nil, types.ErrChannelNotFound(k.codespace, packet.SourceChannel()) } if channel.State != types.OPEN { @@ -53,7 +53,7 @@ func (k Keeper) CleanupPacket( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, ics03types.ErrConnectionNotFound(k.codespace) + return nil, connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } if packet.DestPort() != channel.Counterparty.PortID { @@ -130,7 +130,7 @@ func (k Keeper) SendPacket(ctx sdk.Context, packet exported.PacketI) error { return errors.New("connection not found") // TODO: ics03 sdk.Error } - if connection.State == ics03types.NONE { + if connection.State == connectiontypes.NONE { return errors.New("connection is closed") // TODO: sdk.Error } @@ -171,7 +171,7 @@ func (k Keeper) RecvPacket( channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, types.ErrChannelNotFound(k.codespace) + return nil, types.ErrChannelNotFound(k.codespace, packet.SourceChannel()) } if channel.State != types.OPEN { @@ -198,10 +198,10 @@ func (k Keeper) RecvPacket( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, ics03types.ErrConnectionNotFound(k.codespace) + return nil, connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } - if connection.State != ics03types.OPEN { + if connection.State != connectiontypes.OPEN { return nil, errors.New("connection is not open") // TODO: ics03 sdk.Error } @@ -255,7 +255,7 @@ func (k Keeper) AcknowledgePacket( ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, types.ErrChannelNotFound(k.codespace) + return nil, types.ErrChannelNotFound(k.codespace, packet.SourceChannel()) } if channel.State != types.OPEN { @@ -282,10 +282,10 @@ func (k Keeper) AcknowledgePacket( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, ics03types.ErrConnectionNotFound(k.codespace) + return nil, connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } - if connection.State != ics03types.OPEN { + if connection.State != connectiontypes.OPEN { return nil, errors.New("connection is not open") // TODO: ics03 sdk.Error } diff --git a/x/ibc/04-channel/keeper/querier.go b/x/ibc/04-channel/keeper/querier.go index da03dd9d070f..bc4b18f4f310 100644 --- a/x/ibc/04-channel/keeper/querier.go +++ b/x/ibc/04-channel/keeper/querier.go @@ -32,7 +32,7 @@ func queryClientState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, channel, found := k.GetChannel(ctx, params.PortID, params.ChannelID) if !found { - return nil, types.ErrChannelNotFound(k.codespace) + return nil, types.ErrChannelNotFound(k.codespace, params.ChannelID) } bz, err := types.SubModuleCdc.MarshalJSON(channel) diff --git a/x/ibc/04-channel/keeper/timeout.go b/x/ibc/04-channel/keeper/timeout.go index 0c0962245bca..08e8e33bc1c6 100644 --- a/x/ibc/04-channel/keeper/timeout.go +++ b/x/ibc/04-channel/keeper/timeout.go @@ -5,7 +5,7 @@ import ( "errors" sdk "github.com/cosmos/cosmos-sdk/types" - ics03types "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" @@ -25,7 +25,7 @@ func (k Keeper) TimoutPacket( ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, types.ErrChannelNotFound(k.codespace) + return nil, types.ErrChannelNotFound(k.codespace, packet.SourceChannel()) } if channel.State != types.OPEN { @@ -47,7 +47,7 @@ func (k Keeper) TimoutPacket( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, ics03types.ErrConnectionNotFound(k.codespace) + return nil, connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } if packet.DestPort() != channel.Counterparty.PortID { @@ -110,7 +110,7 @@ func (k Keeper) TimeoutOnClose( ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return nil, types.ErrChannelNotFound(k.codespace) + return nil, types.ErrChannelNotFound(k.codespace, packet.SourceChannel()) } _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) @@ -128,7 +128,7 @@ func (k Keeper) TimeoutOnClose( connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, ics03types.ErrConnectionNotFound(k.codespace) + return nil, connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } if packet.DestPort() != channel.Counterparty.PortID { diff --git a/x/ibc/04-channel/types/codec.go b/x/ibc/04-channel/types/codec.go index cf70c38f9587..8f21c50037d1 100644 --- a/x/ibc/04-channel/types/codec.go +++ b/x/ibc/04-channel/types/codec.go @@ -9,6 +9,7 @@ var SubModuleCdc *codec.Codec func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*exported.PacketI)(nil), nil) + cdc.RegisterConcrete(Packet{}, "ibc/channel/Packet", nil) cdc.RegisterConcrete(MsgChannelOpenInit{}, "ibc/channel/MsgChannelOpenInit", nil) cdc.RegisterConcrete(MsgChannelOpenTry{}, "ibc/channel/MsgChannelOpenTry", nil) diff --git a/x/ibc/04-channel/types/errors.go b/x/ibc/04-channel/types/errors.go index 1c5bb10f19ea..813c2c368165 100644 --- a/x/ibc/04-channel/types/errors.go +++ b/x/ibc/04-channel/types/errors.go @@ -21,13 +21,13 @@ const ( ) // ErrChannelExists implements sdk.Error -func ErrChannelExists(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeChannelExists, "channel already exists") +func ErrChannelExists(codespace sdk.CodespaceType, channelID string) sdk.Error { + return sdk.NewError(codespace, CodeChannelExists, fmt.Sprintf("channel with ID %s already exists", channelID)) } // ErrChannelNotFound implements sdk.Error -func ErrChannelNotFound(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeChannelNotFound, "channel not found") +func ErrChannelNotFound(codespace sdk.CodespaceType, channelID string) sdk.Error { + return sdk.NewError(codespace, CodeChannelNotFound, fmt.Sprintf("channel with ID %s not found", channelID)) } // ErrInvalidConnectionHops implements sdk.Error diff --git a/x/ibc/04-channel/types/expected_keepers.go b/x/ibc/04-channel/types/expected_keepers.go index ff7c7b586370..29784021947e 100644 --- a/x/ibc/04-channel/types/expected_keepers.go +++ b/x/ibc/04-channel/types/expected_keepers.go @@ -2,25 +2,30 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" - ics02exported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - ics03types "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // ClientKeeper expected account IBC client keeper type ClientKeeper interface { - GetConsensusState(ctx sdk.Context, clientID string) (ics02exported.ConsensusState, bool) + GetConsensusState(ctx sdk.Context, clientID string) (clientexported.ConsensusState, bool) } // ConnectionKeeper expected account IBC connection keeper type ConnectionKeeper interface { - GetConnection(ctx sdk.Context, connectionID string) (ics03types.ConnectionEnd, bool) + GetConnection(ctx sdk.Context, connectionID string) (connectiontypes.ConnectionEnd, bool) VerifyMembership( - ctx sdk.Context, connection ics03types.ConnectionEnd, height uint64, + ctx sdk.Context, connection connectiontypes.ConnectionEnd, height uint64, proof ics23.Proof, path string, value []byte, ) bool VerifyNonMembership( - ctx sdk.Context, connection ics03types.ConnectionEnd, height uint64, + ctx sdk.Context, connection connectiontypes.ConnectionEnd, height uint64, proof ics23.Proof, path string, ) bool } + +// PortKeeper expected account IBC port keeper +type PortKeeper interface { + GetPort(ctx sdk.Context, portID string) (sdk.CapabilityKey, bool) +} diff --git a/x/ibc/handler.go b/x/ibc/handler.go index ed740f39183e..b80267dd7d92 100644 --- a/x/ibc/handler.go +++ b/x/ibc/handler.go @@ -6,6 +6,7 @@ import ( 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" ) // NewHandler defines the IBC handler @@ -14,6 +15,7 @@ func NewHandler(k Keeper) sdk.Handler { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { + // IBC client msgs case client.MsgCreateClient: return client.HandleMsgCreateClient(ctx, k.ClientKeeper, msg) @@ -23,6 +25,7 @@ func NewHandler(k Keeper) sdk.Handler { case client.MsgSubmitMisbehaviour: return client.HandleMsgSubmitMisbehaviour(ctx, k.ClientKeeper, msg) + // IBC connection msgs case connection.MsgConnectionOpenInit: return connection.HandleMsgConnectionOpenInit(ctx, k.ConnectionKeeper, msg) @@ -35,6 +38,25 @@ func NewHandler(k Keeper) sdk.Handler { case connection.MsgConnectionOpenConfirm: return connection.HandleMsgConnectionOpenConfirm(ctx, k.ConnectionKeeper, msg) + // IBC channel msgs + case channel.MsgChannelOpenInit: + return channel.HandleMsgChannelOpenInit(ctx, k.ChannelKeeper, msg) + + case channel.MsgChannelOpenTry: + return channel.HandleMsgChannelOpenTry(ctx, k.ChannelKeeper, msg) + + case channel.MsgChannelOpenAck: + return channel.HandleMsgChannelOpenAck(ctx, k.ChannelKeeper, msg) + + case channel.MsgChannelOpenConfirm: + return channel.HandleMsgChannelOpenConfirm(ctx, k.ChannelKeeper, msg) + + case channel.MsgChannelCloseInit: + return channel.HandleMsgChannelCloseInit(ctx, k.ChannelKeeper, msg) + + case channel.MsgChannelCloseConfirm: + return channel.HandleMsgChannelCloseConfirm(ctx, k.ChannelKeeper, msg) + default: errMsg := fmt.Sprintf("unrecognized IBC message type: %T", msg) return sdk.ErrUnknownRequest(errMsg).Result() diff --git a/x/ibc/keeper/keeper.go b/x/ibc/keeper/keeper.go index dafe8892d167..12325f2b1c88 100644 --- a/x/ibc/keeper/keeper.go +++ b/x/ibc/keeper/keeper.go @@ -5,21 +5,25 @@ import ( 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" ) // Keeper defines each ICS keeper for IBC type Keeper struct { ClientKeeper client.Keeper ConnectionKeeper connection.Keeper + ChannelKeeper channel.Keeper } // NewKeeper creates a new ibc Keeper func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) Keeper { clientKeeper := client.NewKeeper(cdc, key, codespace) connectionKeeper := connection.NewKeeper(cdc, key, codespace, clientKeeper) + channelKeeper := channel.NewKeeper(cdc, key, codespace, clientKeeper, connectionKeeper) return Keeper{ ClientKeeper: clientKeeper, ConnectionKeeper: connectionKeeper, + ChannelKeeper: channelKeeper, } } diff --git a/x/ibc/module.go b/x/ibc/module.go index 5a56db96877f..447ec2cb03fe 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -37,6 +37,7 @@ func (AppModuleBasic) Name() string { // RegisterCodec registers the staking module's types for the given codec. func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { client.RegisterCodec(cdc) + channel.RegisterCodec(cdc) ics23.RegisterCodec(cdc) } From c079abb04fa4106362d9b9a828d2ccbdef2ad732 Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Tue, 15 Oct 2019 14:43:20 -0700 Subject: [PATCH 298/378] Implement tx cli actions --- x/ibc/04-channel/client/cli/tx.go | 795 +++++++++++++++--------------- x/ibc/04-channel/types/errors.go | 12 + x/ibc/04-channel/types/msgs.go | 133 ++++- 3 files changed, 533 insertions(+), 407 deletions(-) diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index 3937fa9818c0..9abc07c3fd2c 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -1,393 +1,406 @@ package cli -// import ( -// "errors" -// "fmt" -// "time" - -// "github.com/spf13/cobra" -// "github.com/spf13/viper" - -// "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" -// connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" -// ics04 "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" -// FlagFrom1 = "from1" -// FlagFrom2 = "from2" -// ) - -// 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(q, portid, chanid) -// } - -// 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 -// } - -// func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { -// cmd := &cobra.Command{ -// Use: "handshake", -// 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.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). -// WithCodec(cdc). -// WithNodeURI(viper.GetString(FlagNode1)). -// WithBroadcastMode(flags.BroadcastBlock) -// q1 := state.NewCLIQuerier(ctx1) - -// ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). -// WithCodec(cdc). -// WithNodeURI(viper.GetString(FlagNode2)). -// 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}, -// } - -// chan2 := channel.Channel{ -// Counterparty: chanid1, -// CounterpartyPort: portid1, -// ConnectionHops: []string{connid2}, -// } - -// 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 -// } -// clientid1 := conn1.Client - -// conn2, _, err := obj2.OriginConnection().ConnectionCLI(q2) -// if err != nil { -// return err -// } -// clientid2 := conn2.Client - -// // TODO: check state and if not Idle continue existing process -// msginit := channel.MsgOpenInit{ -// PortID: portid1, -// ChannelID: chanid1, -// Channel: chan1, -// Signer: ctx1.GetFromAddress(), -// } - -// err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msginit}) -// if err != nil { -// return err -// } - -// // 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 -// } - -// msgupdate := client.MsgUpdateClient{ -// ClientID: clientid2, -// Header: header, -// Signer: ctx2.GetFromAddress(), -// } - -// 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 -// } -// _, pstate, err := obj1.StageCLI(q1) -// if err != nil { -// return err -// } - -// msgtry := channel.MsgOpenTry{ -// 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}) -// if err != nil { -// return err -// } - -// // 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 -// } - -// msgupdate = client.MsgUpdateClient{ -// ClientID: clientid1, -// Header: header, -// Signer: ctx1.GetFromAddress(), -// } - -// 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 -// } -// _, pstate, err = obj2.StageCLI(q2) -// if err != nil { -// return err -// } - -// msgack := channel.MsgOpenAck{ -// PortID: portid1, -// ChannelID: chanid1, -// Proofs: []commitment.Proof{pchan, pstate}, -// Height: uint64(header.Height), -// Signer: ctx1.GetFromAddress(), -// } - -// err = utils.GenerateOrBroadcastMsgs(ctx1, txBldr, []sdk.Msg{msgack}) -// if err != nil { -// return err -// } - -// // 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 -// } - -// 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{ -// PortID: portid2, -// ChannelID: chanid2, -// Proofs: []commitment.Proof{pstate}, -// Height: uint64(header.Height), -// Signer: ctx2.GetFromAddress(), -// } - -// err = utils.GenerateOrBroadcastMsgs(ctx2, txBldr, []sdk.Msg{msgconfirm}) -// if err != nil { -// return err -// } - -// 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 -// } - -// func GetCmdFlushPackets(storeKey string, cdc *codec.Codec) *cobra.Command { -// cmd := &cobra.Command{ -// Use: "flush", -// Short: "flush packets on queue", -// Args: cobra.ExactArgs(2), -// // Args: []string{portid, chanid} -// RunE: func(cmd *cobra.Command, args []string) error { -// txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) -// ctx1 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom1)). -// WithCodec(cdc). -// WithNodeURI(viper.GetString(FlagNode1)). -// WithBroadcastMode(flags.BroadcastBlock) -// q1 := state.NewCLIQuerier(ctx1) - -// ctx2 := context.NewCLIContextWithFrom(viper.GetString(FlagFrom2)). -// WithCodec(cdc). -// WithNodeURI(viper.GetString(FlagNode2)). -// WithBroadcastMode(flags.BroadcastBlock) -// q2 := state.NewCLIQuerier(ctx2) - -// portid1, chanid1 := args[0], args[1] - -// obj1, err := flush(q1, cdc, storeKey, version.DefaultPrefix(), portid1, chanid1) -// if err != nil { -// return err -// } - -// chan1, _, err := obj1.ChannelCLI(q1) -// if err != nil { -// return err -// } - -// portid2, chanid2 := chan1.CounterpartyPort, chan1.Counterparty - -// obj2, err := flush(q2, cdc, storeKey, version.DefaultPrefix(), portid2, chanid2) -// if err != nil { -// return err -// } - -// chan2, _, err := obj2.ChannelCLI(q2) -// if err != nil { -// return err -// } - -// connobj2, err := conn(q2, cdc, storeKey, version.DefaultPrefix(), chan2.ConnectionHops[0]) -// if err != nil { -// return err -// } - -// conn2, _, err := connobj2.ConnectionCLI(q2) -// if err != nil { -// return err -// } - -// client2 := conn2.Client - -// 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 -// }, -// } - -// 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 - -// } +import ( + "fmt" + "io/ioutil" + "os" + "strconv" + "strings" + + "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/04-channel/types" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + FlagUnordered = "unordered" + IBCVersion = "version" +) + +// GetTxCmd returns the transaction commands for IBC Connections +func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + ics04ChannelTxCmd := &cobra.Command{ + Use: "connection", + Short: "IBC connection transaction subcommands", + } + + ics04ChannelTxCmd.AddCommand(client.PostCommands( + GetMsgChannelOpenInitCmd(storeKey, cdc), + GetMsgChannelOpenTryCmd(storeKey, cdc), + GetMsgChannelOpenAckCmd(storeKey, cdc), + GetMsgChannelOpenConfirmCmd(storeKey, cdc), + GetMsgChannelCloseInitCmd(storeKey, cdc), + GetMsgChannelCloseConfirmCmd(storeKey, cdc), + GetMsgSendPacketCmd(storeKey, cdc), + )...) + + return ics04ChannelTxCmd +} + +// GetMsgChannelOpenInitCmd returns the command to create a MsgChannelOpenInit transaction +func GetMsgChannelOpenInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "open-init [port-id] [channel-id] [cp-port-id] [cp-channel-id] [connection-hops]", + Short: "Creates and sends a ChannelOpenInit message", + Args: cobra.ExactArgs(5), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + portID, err := validatePortID(args[0]) + if err != nil { + return err + } + + channelID, err := validateChannelID(args[1]) + if err != nil { + return err + } + + channel, err := createChannelFromArgs(args[2], args[3], args[4]) + if err != nil { + return err + } + + msg := types.NewMsgChannelOpenInit(portID, channelID, channel, cliCtx.GetFromAddress()) + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + + cmd.Flags().Bool(FlagUnordered, false, "Pass flag for opening unordered channels") + + return cmd +} + +// GetMsgChannelOpenTryCmd returns the command to create a MsgChannelOpenTry transaction +func GetMsgChannelOpenTryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "open-try [port-id] [channel-id] [cp-port-id] [cp-channel-id] [connection-hops] [/path/to/proof-init.json] [proof-height]", + Short: "Creates and sends a ChannelOpenTry message", + Args: cobra.ExactArgs(7), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + portID, err := validatePortID(args[0]) + if err != nil { + return err + } + + channelID, err := validateChannelID(args[1]) + if err != nil { + return err + } + + channel, err := createChannelFromArgs(args[2], args[3], args[4]) + if err != nil { + return err + } + + var proof ics23.Proof + if err := cdc.UnmarshalJSON([]byte(args[5]), &proof); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") + contents, err := ioutil.ReadFile(args[5]) + if err != nil { + return fmt.Errorf("error opening proof file: %v\n", err) + } + if err := cdc.UnmarshalJSON(contents, &proof); err != nil { + return fmt.Errorf("error unmarshalling proof file: %v\n", err) + } + } + + proofHeight, err := validateProofHeight(args[6]) + if err != nil { + return err + } + + msg := types.NewMsgChannelOpenTry(portID, channelID, channel, IBCVersion, proof, proofHeight, cliCtx.GetFromAddress()) + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + + cmd.Flags().Bool(FlagUnordered, false, "Pass flag for opening unordered channels") + + return cmd +} + +// GetMsgChannelOpenAckCmd returns the command to create a MsgChannelOpenAck transaction +func GetMsgChannelOpenAckCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "open-ack [port-id] [channel-id] [/path/to/proof-try.json] [proof-height]", + Short: "Creates and sends a ChannelOpenAck message", + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + portID, err := validatePortID(args[0]) + if err != nil { + return err + } + + channelID, err := validateChannelID(args[1]) + if err != nil { + return err + } + + var proof ics23.Proof + if err := cdc.UnmarshalJSON([]byte(args[2]), &proof); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") + contents, err := ioutil.ReadFile(args[2]) + if err != nil { + return fmt.Errorf("error opening proof file: %v\n", err) + } + if err := cdc.UnmarshalJSON(contents, &proof); err != nil { + return fmt.Errorf("error unmarshalling proof file: %v\n", err) + } + } + + proofHeight, err := validateProofHeight(args[3]) + if err != nil { + return err + } + + msg := types.NewMsgChannelOpenAck(portID, channelID, IBCVersion, proof, proofHeight, cliCtx.GetFromAddress()) + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} + +// GetMsgChannelOpenConfirmCmd returns the command to create a MsgChannelOpenConfirm transaction +func GetMsgChannelOpenConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "open-confirm [port-id] [channel-id] [/path/to/proof-ack.json] [proof-height]", + Short: "Creates and sends a ChannelOpenConfirm message", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + portID, err := validatePortID(args[0]) + if err != nil { + return err + } + + channelID, err := validateChannelID(args[1]) + if err != nil { + return err + } + + var proof ics23.Proof + if err := cdc.UnmarshalJSON([]byte(args[2]), &proof); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") + contents, err := ioutil.ReadFile(args[2]) + if err != nil { + return fmt.Errorf("error opening proof file: %v\n", err) + } + if err := cdc.UnmarshalJSON(contents, &proof); err != nil { + return fmt.Errorf("error unmarshalling proof file: %v\n", err) + } + } + + proofHeight, err := validateProofHeight(args[3]) + if err != nil { + return err + } + + msg := types.NewMsgChannelOpenConfirm(portID, channelID, proof, proofHeight, cliCtx.GetFromAddress()) + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} + +// GetMsgChannelCloseInitCmd returns the command to create a MsgChannelCloseInit transaction +func GetMsgChannelCloseInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "close-init [port-id] [channel-id]", + Short: "Creates and sends a ChannelCloseInit message", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + portID, err := validatePortID(args[0]) + if err != nil { + return err + } + + channelID, err := validateChannelID(args[1]) + if err != nil { + return err + } + + msg := types.NewMsgChannelCloseInit(portID, channelID, cliCtx.GetFromAddress()) + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} + +// GetMsgChannelCloseConfirmCmd returns the command to create a MsgChannelCloseConfirm transaction +func GetMsgChannelCloseConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "close-confirm [port-id] [channel-id] [/path/to/proof-init.json] [proof-height]", + Short: "Creates and sends a ChannelCloseConfirm message", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + portID, err := validatePortID(args[0]) + if err != nil { + return err + } + + channelID, err := validateChannelID(args[1]) + if err != nil { + return err + } + + var proof ics23.Proof + if err := cdc.UnmarshalJSON([]byte(args[2]), &proof); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") + contents, err := ioutil.ReadFile(args[2]) + if err != nil { + return fmt.Errorf("error opening proof file: %v\n", err) + } + if err := cdc.UnmarshalJSON(contents, &proof); err != nil { + return fmt.Errorf("error unmarshalling proof file: %v\n", err) + } + } + + proofHeight, err := validateProofHeight(args[3]) + if err != nil { + return err + } + + msg := types.NewMsgChannelCloseConfirm(portID, channelID, proof, proofHeight, cliCtx.GetFromAddress()) + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} + +// GetMsgSendPacketCmd returns the command to create a MsgChannelCloseConfirm transaction +func GetMsgSendPacketCmd(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "send-packet [channel-id] [/path/to/packet-proof.json] [proof-height] [/path/to/packet-data.json]", + Short: "Creates and sends a SendPacket message", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + channelID, err := validateChannelID(args[0]) + if err != nil { + return err + } + + var proofs []ics23.Proof + if err := cdc.UnmarshalJSON([]byte(args[1]), &proofs); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") + contents, err := ioutil.ReadFile(args[1]) + if err != nil { + return fmt.Errorf("error opening proofs file: %v\n", err) + } + if err := cdc.UnmarshalJSON(contents, &proofs); err != nil { + return fmt.Errorf("error unmarshalling proofs file: %v\n", err) + } + } + + proofHeight, err := validateProofHeight(args[2]) + if err != nil { + return err + } + + var packet exported.PacketI + if err := cdc.UnmarshalJSON([]byte(args[3]), &packet); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") + contents, err := ioutil.ReadFile(args[3]) + if err != nil { + return fmt.Errorf("error opening packet file: %v\n", err) + } + if err := cdc.UnmarshalJSON(contents, &packet); err != nil { + return fmt.Errorf("error unmarshalling packet file: %v\n", err) + } + } + + msg := types.NewMsgSendPacket(packet, channelID, proofs, proofHeight, cliCtx.GetFromAddress()) + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + return cmd +} + +func channelOrder() types.ChannelOrder { + if viper.GetBool(FlagUnordered) { + return types.UNORDERED + } + return types.ORDERED +} + +func validatePortID(pid string) (string, error) { + // TODO: Add validation here + return pid, nil +} + +func validateChannelID(cid string) (string, error) { + // TODO: Add validation here + return cid, nil +} + +func validateChannelHops(hops string) ([]string, error) { + // TODO: Add validation here + return strings.Split(hops, ","), nil +} + +func validateProofHeight(height string) (uint64, error) { + // TODO: More validation? + i, err := strconv.ParseInt(height, 10, 64) + return uint64(i), err +} + +func createChannelFromArgs(pid string, cid string, hops string) (types.Channel, error) { + var channel types.Channel + portID, err := validatePortID(pid) + if err != nil { + return channel, err + } + + channelID, err := validateChannelID(cid) + if err != nil { + return channel, err + } + + channelHops, err := validateChannelHops(hops) + if err != nil { + return channel, err + } + + channel = types.Channel{ + State: types.INIT, + Ordering: channelOrder(), + Counterparty: types.Counterparty{portID, channelID}, + ConnectionHops: channelHops, + Version: IBCVersion, + } + + return channel, nil +} diff --git a/x/ibc/04-channel/types/errors.go b/x/ibc/04-channel/types/errors.go index 1c5bb10f19ea..30796243d9d5 100644 --- a/x/ibc/04-channel/types/errors.go +++ b/x/ibc/04-channel/types/errors.go @@ -18,6 +18,8 @@ const ( CodeInvalidPacketSequence sdk.CodeType = 106 CodeSequenceNotFound sdk.CodeType = 107 CodePacketTimeout sdk.CodeType = 108 + CodeChanIDLen sdk.CodeType = 109 + CodePortIDLen sdk.CodeType = 110 ) // ErrChannelExists implements sdk.Error @@ -59,3 +61,13 @@ func ErrSequenceNotFound(codespace sdk.CodespaceType, seqType string) sdk.Error func ErrPacketTimeout(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodePacketTimeout, "packet timeout") } + +// ErrChanIDLen implements sdk.Error +func ErrLenChanID(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeChanIDLen, "chanid too long") +} + +// ErrLenPortID implements sdk.Error +func ErrLenPortID(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodePortIDLen, "portid too long") +} diff --git a/x/ibc/04-channel/types/msgs.go b/x/ibc/04-channel/types/msgs.go index a425e7d9b36a..aa875d805f1e 100644 --- a/x/ibc/04-channel/types/msgs.go +++ b/x/ibc/04-channel/types/msgs.go @@ -7,6 +7,11 @@ import ( ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) +const ( + lenPortID = 64 + lenChanID = 64 +) + var _ sdk.Msg = MsgChannelOpenInit{} type MsgChannelOpenInit struct { @@ -16,6 +21,10 @@ type MsgChannelOpenInit struct { Signer sdk.AccAddress `json:"signer"` } +func NewMsgChannelOpenInit(portID string, channelID string, channel Channel, signer sdk.AccAddress) MsgChannelOpenInit { + return MsgChannelOpenInit{portID, channelID, channel, signer} +} + // Route implements sdk.Msg func (msg MsgChannelOpenInit) Route() string { return ibctypes.RouterKey @@ -23,12 +32,22 @@ func (msg MsgChannelOpenInit) Route() string { // Type implements sdk.Msg func (msg MsgChannelOpenInit) Type() string { - return "channel_open_init" + return EventTypeChannelOpenInit } // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenInit) ValidateBasic() sdk.Error { - // TODO: + // Check PortID + if len(msg.PortID) > lenPortID { + return ErrLenPortID(DefaultCodespace) + } + + // Check ChanID + if len(msg.ChannelID) > lenChanID { + return ErrLenChanID(DefaultCodespace) + } + + // Signer can be empty return nil } @@ -54,6 +73,10 @@ type MsgChannelOpenTry struct { Signer sdk.AccAddress `json:"signer"` } +func NewMsgChannelOpenTry(portID string, channelID string, channel Channel, cpv string, proofInit ics23.Proof, proofHeight uint64, signer sdk.AccAddress) MsgChannelOpenTry { + return MsgChannelOpenTry{portID, channelID, channel, cpv, proofInit, proofHeight, signer} +} + // Route implements sdk.Msg func (msg MsgChannelOpenTry) Route() string { return ibctypes.RouterKey @@ -61,12 +84,24 @@ func (msg MsgChannelOpenTry) Route() string { // Type implements sdk.Msg func (msg MsgChannelOpenTry) Type() string { - return "channel_open_try" + return EventTypeChannelOpenTry } // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenTry) ValidateBasic() sdk.Error { - // TODO: + // Check PortID + if len(msg.PortID) > lenPortID { + return ErrLenPortID(DefaultCodespace) + } + + // Check ChanID + if len(msg.ChannelID) > lenChanID { + return ErrLenChanID(DefaultCodespace) + } + + // Check proofs != nil + // Check channel != nil + // Signer can be empty return nil } @@ -91,6 +126,10 @@ type MsgChannelOpenAck struct { Signer sdk.AccAddress `json:"signer"` } +func NewMsgChannelOpenAck(port string, channelID string, cpv string, proofTry ics23.Proof, proofHeight uint64, signer sdk.AccAddress) MsgChannelOpenAck { + return MsgChannelOpenAck{port, channelID, cpv, proofTry, proofHeight, signer} +} + // Route implements sdk.Msg func (msg MsgChannelOpenAck) Route() string { return ibctypes.RouterKey @@ -98,12 +137,23 @@ func (msg MsgChannelOpenAck) Route() string { // Type implements sdk.Msg func (msg MsgChannelOpenAck) Type() string { - return "channel_open_ack" + return EventTypeChannelOpenAck } // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenAck) ValidateBasic() sdk.Error { - // TODO: + // Check PortID + if len(msg.PortID) > lenPortID { + return ErrLenPortID(DefaultCodespace) + } + + // Check ChanID + if len(msg.ChannelID) > lenChanID { + return ErrLenChanID(DefaultCodespace) + } + + // Check proofs != nil + // Signer can be empty return nil } @@ -127,6 +177,10 @@ type MsgChannelOpenConfirm struct { Signer sdk.AccAddress `json:"signer"` } +func NewMsgChannelOpenConfirm(portID string, channelID string, proofAck ics23.Proof, proofHeight uint64, signer sdk.AccAddress) MsgChannelOpenConfirm { + return MsgChannelOpenConfirm{portID, channelID, proofAck, proofHeight, signer} +} + // Route implements sdk.Msg func (msg MsgChannelOpenConfirm) Route() string { return ibctypes.RouterKey @@ -134,12 +188,23 @@ func (msg MsgChannelOpenConfirm) Route() string { // Type implements sdk.Msg func (msg MsgChannelOpenConfirm) Type() string { - return "channel_open_confirm" + return EventTypeChannelOpenConfirm } // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenConfirm) ValidateBasic() sdk.Error { - // TODO: + // Check PortID + if len(msg.PortID) > lenPortID { + return ErrLenPortID(DefaultCodespace) + } + + // Check ChanID + if len(msg.ChannelID) > lenChanID { + return ErrLenChanID(DefaultCodespace) + } + + // Check proofs != nil + // Signer can be empty return nil } @@ -161,6 +226,10 @@ type MsgChannelCloseInit struct { Signer sdk.AccAddress `json:"signer"` } +func NewMsgChannelCloseInit(portID string, channelID string, signer sdk.AccAddress) MsgChannelCloseInit { + return MsgChannelCloseInit{portID, channelID, signer} +} + // Route implements sdk.Msg func (msg MsgChannelCloseInit) Route() string { return ibctypes.RouterKey @@ -168,12 +237,22 @@ func (msg MsgChannelCloseInit) Route() string { // Type implements sdk.Msg func (msg MsgChannelCloseInit) Type() string { - return "channel_close_init" + return EventTypeChannelCloseInit } // ValidateBasic implements sdk.Msg func (msg MsgChannelCloseInit) ValidateBasic() sdk.Error { - // TODO: + // Check PortID + if len(msg.PortID) > lenPortID { + return ErrLenPortID(DefaultCodespace) + } + + // Check ChanID + if len(msg.ChannelID) > lenChanID { + return ErrLenChanID(DefaultCodespace) + } + + // Signer can be empty return nil } @@ -197,6 +276,10 @@ type MsgChannelCloseConfirm struct { Signer sdk.AccAddress `json:"signer"` } +func NewMsgChannelCloseConfirm(portID string, channelID string, proofInit ics23.Proof, proofHeight uint64, signer sdk.AccAddress) MsgChannelCloseConfirm { + return MsgChannelCloseConfirm{portID, channelID, proofInit, proofHeight, signer} +} + // Route implements sdk.Msg func (msg MsgChannelCloseConfirm) Route() string { return ibctypes.RouterKey @@ -204,12 +287,23 @@ func (msg MsgChannelCloseConfirm) Route() string { // Type implements sdk.Msg func (msg MsgChannelCloseConfirm) Type() string { - return "channel_close_confirm" + return EventTypeChannelCloseConfirm } // ValidateBasic implements sdk.Msg func (msg MsgChannelCloseConfirm) ValidateBasic() sdk.Error { - // TODO: + // Check PortID + if len(msg.PortID) > lenPortID { + return ErrLenPortID(DefaultCodespace) + } + + // Check ChanID + if len(msg.ChannelID) > lenChanID { + return ErrLenChanID(DefaultCodespace) + } + + // Check proofs != nil + // Signer can be empty return nil } @@ -236,6 +330,10 @@ type MsgSendPacket struct { Signer sdk.AccAddress `json:"signer" yaml:"signer"` } +func NewMsgSendPacket(packet exported.PacketI, channelID string, proofs []ics23.Proof, height uint64, signer sdk.AccAddress) MsgSendPacket { + return MsgSendPacket{packet, channelID, proofs, height, signer} +} + // Route implements sdk.Msg func (msg MsgSendPacket) Route() string { return ibctypes.RouterKey @@ -243,15 +341,18 @@ func (msg MsgSendPacket) Route() string { // Type implements sdk.Msg func (msg MsgSendPacket) Type() string { - return "send_packet" + return EventTypeSendPacket } // ValidateBasic implements sdk.Msg func (msg MsgSendPacket) ValidateBasic() sdk.Error { - // TODO: - // Check PortID ChannelID len - // Check packet != nil + // Check ChanID + if len(msg.ChannelID) > lenChanID { + return ErrLenChanID(DefaultCodespace) + } + // Check proofs != nil + // Check packet != nil // Signer can be empty return nil } From 2b4cb051361eb6246260557e0414d9c05fa9913f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 16 Oct 2019 11:35:57 +0200 Subject: [PATCH 299/378] add MsgSendPacket handler; msg validation, errors and events --- x/ibc/04-channel/alias.go | 21 ++- x/ibc/04-channel/client/cli/tx.go | 146 ++++++----------- x/ibc/04-channel/exported/exported.go | 5 - x/ibc/04-channel/handler.go | 30 ++++ x/ibc/04-channel/keeper/handshake.go | 1 - x/ibc/04-channel/keeper/timeout.go | 4 +- x/ibc/04-channel/types/channel.go | 100 +++++++++--- x/ibc/04-channel/types/codec.go | 2 +- x/ibc/04-channel/types/errors.go | 16 +- x/ibc/04-channel/types/events.go | 16 +- x/ibc/04-channel/types/msgs.go | 223 ++++++++++++++++++++------ x/ibc/04-channel/types/packet.go | 32 ++-- x/ibc/04-channel/types/port.go | 30 ---- x/ibc/handler.go | 3 + x/ibc/module.go | 1 + 15 files changed, 385 insertions(+), 245 deletions(-) delete mode 100644 x/ibc/04-channel/types/port.go diff --git a/x/ibc/04-channel/alias.go b/x/ibc/04-channel/alias.go index 3859972efa1f..dcfe2263cac0 100644 --- a/x/ibc/04-channel/alias.go +++ b/x/ibc/04-channel/alias.go @@ -27,13 +27,6 @@ const ( CodeInvalidPacketSequence = types.CodeInvalidPacketSequence CodeSequenceNotFound = types.CodeSequenceNotFound CodePacketTimeout = types.CodePacketTimeout - EventTypeSendPacket = types.EventTypeSendPacket - EventTypeChannelOpenInit = types.EventTypeChannelOpenInit - EventTypeChannelOpenTry = types.EventTypeChannelOpenTry - EventTypeChannelOpenAck = types.EventTypeChannelOpenAck - EventTypeChannelOpenConfirm = types.EventTypeChannelOpenConfirm - EventTypeChannelCloseInit = types.EventTypeChannelCloseInit - EventTypeChannelCloseConfirm = types.EventTypeChannelCloseConfirm AttributeKeySenderPort = types.AttributeKeySenderPort AttributeKeyReceiverPort = types.AttributeKeyReceiverPort AttributeKeyChannelID = types.AttributeKeyChannelID @@ -73,12 +66,18 @@ var ( KeyNextSequenceRecv = types.KeyNextSequenceRecv KeyPacketCommitment = types.KeyPacketCommitment KeyPacketAcknowledgement = types.KeyPacketAcknowledgement - NewPacket = types.NewPacket NewQueryChannelParams = types.NewQueryChannelParams // variable aliases - SubModuleCdc = types.SubModuleCdc - AttributeValueCategory = types.AttributeValueCategory + SubModuleCdc = types.SubModuleCdc + EventTypeSendPacket = types.EventTypeSendPacket + EventTypeChannelOpenInit = types.EventTypeChannelOpenInit + EventTypeChannelOpenTry = types.EventTypeChannelOpenTry + EventTypeChannelOpenAck = types.EventTypeChannelOpenAck + EventTypeChannelOpenConfirm = types.EventTypeChannelOpenConfirm + EventTypeChannelCloseInit = types.EventTypeChannelCloseInit + EventTypeChannelCloseConfirm = types.EventTypeChannelCloseConfirm + AttributeValueCategory = types.AttributeValueCategory ) type ( @@ -96,8 +95,6 @@ type ( MsgChannelCloseInit = types.MsgChannelCloseInit MsgChannelCloseConfirm = types.MsgChannelCloseConfirm MsgSendPacket = types.MsgSendPacket - Packet = types.Packet OpaquePacket = types.OpaquePacket - Port = types.Port QueryChannelParams = types.QueryChannelParams ) diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index 9abc07c3fd2c..f0bec2764fc2 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -13,9 +13,9 @@ import ( 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/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -48,29 +48,24 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { // GetMsgChannelOpenInitCmd returns the command to create a MsgChannelOpenInit transaction func GetMsgChannelOpenInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "open-init [port-id] [channel-id] [cp-port-id] [cp-channel-id] [connection-hops]", + Use: "open-init [port-id] [channel-id] [counterparty-port-id] [counterparty-channel-id] [connection-hops]", Short: "Creates and sends a ChannelOpenInit message", Args: cobra.ExactArgs(5), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) - portID, err := validatePortID(args[0]) - if err != nil { - return err - } - - channelID, err := validateChannelID(args[1]) - if err != nil { - return err - } - + portID := args[0] + channelID := args[1] channel, err := createChannelFromArgs(args[2], args[3], args[4]) if err != nil { return err } msg := types.NewMsgChannelOpenInit(portID, channelID, channel, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err + } return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, @@ -84,23 +79,15 @@ func GetMsgChannelOpenInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command // GetMsgChannelOpenTryCmd returns the command to create a MsgChannelOpenTry transaction func GetMsgChannelOpenTryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "open-try [port-id] [channel-id] [cp-port-id] [cp-channel-id] [connection-hops] [/path/to/proof-init.json] [proof-height]", + Use: "open-try [port-id] [channel-id] [counterparty-port-id] [counterparty-channel-id] [connection-hops] [/path/to/proof-init.json] [proof-height]", Short: "Creates and sends a ChannelOpenTry message", Args: cobra.ExactArgs(7), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) - portID, err := validatePortID(args[0]) - if err != nil { - return err - } - - channelID, err := validateChannelID(args[1]) - if err != nil { - return err - } - + portID := args[0] + channelID := args[1] channel, err := createChannelFromArgs(args[2], args[3], args[4]) if err != nil { return err @@ -111,10 +98,10 @@ func GetMsgChannelOpenTryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") contents, err := ioutil.ReadFile(args[5]) if err != nil { - return fmt.Errorf("error opening proof file: %v\n", err) + return fmt.Errorf("error opening proof file: %v", err) } if err := cdc.UnmarshalJSON(contents, &proof); err != nil { - return fmt.Errorf("error unmarshalling proof file: %v\n", err) + return fmt.Errorf("error unmarshalling proof file: %v", err) } } @@ -124,6 +111,9 @@ func GetMsgChannelOpenTryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { } msg := types.NewMsgChannelOpenTry(portID, channelID, channel, IBCVersion, proof, proofHeight, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err + } return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, @@ -144,25 +134,18 @@ func GetMsgChannelOpenAckCmd(storeKey string, cdc *codec.Codec) *cobra.Command { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) - portID, err := validatePortID(args[0]) - if err != nil { - return err - } - - channelID, err := validateChannelID(args[1]) - if err != nil { - return err - } + portID := args[0] + channelID := args[1] var proof ics23.Proof if err := cdc.UnmarshalJSON([]byte(args[2]), &proof); err != nil { fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") contents, err := ioutil.ReadFile(args[2]) if err != nil { - return fmt.Errorf("error opening proof file: %v\n", err) + return fmt.Errorf("error opening proof file: %v", err) } if err := cdc.UnmarshalJSON(contents, &proof); err != nil { - return fmt.Errorf("error unmarshalling proof file: %v\n", err) + return fmt.Errorf("error unmarshalling proof file: %v", err) } } @@ -172,6 +155,9 @@ func GetMsgChannelOpenAckCmd(storeKey string, cdc *codec.Codec) *cobra.Command { } msg := types.NewMsgChannelOpenAck(portID, channelID, IBCVersion, proof, proofHeight, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err + } return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, @@ -189,25 +175,18 @@ func GetMsgChannelOpenConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comma txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) - portID, err := validatePortID(args[0]) - if err != nil { - return err - } - - channelID, err := validateChannelID(args[1]) - if err != nil { - return err - } + portID := args[0] + channelID := args[1] var proof ics23.Proof if err := cdc.UnmarshalJSON([]byte(args[2]), &proof); err != nil { fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") contents, err := ioutil.ReadFile(args[2]) if err != nil { - return fmt.Errorf("error opening proof file: %v\n", err) + return fmt.Errorf("error opening proof file: %v", err) } if err := cdc.UnmarshalJSON(contents, &proof); err != nil { - return fmt.Errorf("error unmarshalling proof file: %v\n", err) + return fmt.Errorf("error unmarshalling proof file: %v", err) } } @@ -217,6 +196,9 @@ func GetMsgChannelOpenConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comma } msg := types.NewMsgChannelOpenConfirm(portID, channelID, proof, proofHeight, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err + } return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, @@ -234,18 +216,14 @@ func GetMsgChannelCloseInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) - portID, err := validatePortID(args[0]) - if err != nil { - return err - } + portID := args[0] + channelID := args[1] - channelID, err := validateChannelID(args[1]) - if err != nil { + msg := types.NewMsgChannelCloseInit(portID, channelID, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { return err } - msg := types.NewMsgChannelCloseInit(portID, channelID, cliCtx.GetFromAddress()) - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } @@ -262,25 +240,18 @@ func GetMsgChannelCloseConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comm txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) - portID, err := validatePortID(args[0]) - if err != nil { - return err - } - - channelID, err := validateChannelID(args[1]) - if err != nil { - return err - } + portID := args[0] + channelID := args[1] var proof ics23.Proof if err := cdc.UnmarshalJSON([]byte(args[2]), &proof); err != nil { fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") contents, err := ioutil.ReadFile(args[2]) if err != nil { - return fmt.Errorf("error opening proof file: %v\n", err) + return fmt.Errorf("error opening proof file: %v", err) } if err := cdc.UnmarshalJSON(contents, &proof); err != nil { - return fmt.Errorf("error unmarshalling proof file: %v\n", err) + return fmt.Errorf("error unmarshalling proof file: %v", err) } } @@ -290,6 +261,9 @@ func GetMsgChannelCloseConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comm } msg := types.NewMsgChannelCloseConfirm(portID, channelID, proof, proofHeight, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err + } return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, @@ -300,48 +274,29 @@ func GetMsgChannelCloseConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comm // GetMsgSendPacketCmd returns the command to create a MsgChannelCloseConfirm transaction func GetMsgSendPacketCmd(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "send-packet [channel-id] [/path/to/packet-proof.json] [proof-height] [/path/to/packet-data.json]", + Use: "send-packet [/path/to/packet-data.json]", Short: "Creates and sends a SendPacket message", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) - channelID, err := validateChannelID(args[0]) - if err != nil { - return err - } - - var proofs []ics23.Proof - if err := cdc.UnmarshalJSON([]byte(args[1]), &proofs); err != nil { - fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") - contents, err := ioutil.ReadFile(args[1]) - if err != nil { - return fmt.Errorf("error opening proofs file: %v\n", err) - } - if err := cdc.UnmarshalJSON(contents, &proofs); err != nil { - return fmt.Errorf("error unmarshalling proofs file: %v\n", err) - } - } - - proofHeight, err := validateProofHeight(args[2]) - if err != nil { - return err - } - var packet exported.PacketI - if err := cdc.UnmarshalJSON([]byte(args[3]), &packet); err != nil { + if err := cdc.UnmarshalJSON([]byte(args[0]), &packet); err != nil { fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") - contents, err := ioutil.ReadFile(args[3]) + contents, err := ioutil.ReadFile(args[0]) if err != nil { - return fmt.Errorf("error opening packet file: %v\n", err) + return fmt.Errorf("error opening packet file: %v", err) } if err := cdc.UnmarshalJSON(contents, &packet); err != nil { - return fmt.Errorf("error unmarshalling packet file: %v\n", err) + return fmt.Errorf("error unmarshalling packet file: %v", err) } } - msg := types.NewMsgSendPacket(packet, channelID, proofs, proofHeight, cliCtx.GetFromAddress()) + msg := types.NewMsgSendPacket(packet, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err + } return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, @@ -356,6 +311,7 @@ func channelOrder() types.ChannelOrder { return types.ORDERED } +// TODO: Move to ICS24 func validatePortID(pid string) (string, error) { // TODO: Add validation here return pid, nil @@ -397,7 +353,7 @@ func createChannelFromArgs(pid string, cid string, hops string) (types.Channel, channel = types.Channel{ State: types.INIT, Ordering: channelOrder(), - Counterparty: types.Counterparty{portID, channelID}, + Counterparty: types.NewCounterparty(portID, channelID), ConnectionHops: channelHops, Version: IBCVersion, } diff --git a/x/ibc/04-channel/exported/exported.go b/x/ibc/04-channel/exported/exported.go index 7f1a537b28f1..e3f4f42a1772 100644 --- a/x/ibc/04-channel/exported/exported.go +++ b/x/ibc/04-channel/exported/exported.go @@ -8,9 +8,4 @@ type PacketI interface { DestPort() string DestChannel() string Data() []byte - - // // Non ICS04 interface functions - // Type() string - // ValidateBasic() sdk.Error - // Marshal() []byte // Should exclude PortID/ChannelID info } diff --git a/x/ibc/04-channel/handler.go b/x/ibc/04-channel/handler.go index 7085a392de8c..da5304e7ac5c 100644 --- a/x/ibc/04-channel/handler.go +++ b/x/ibc/04-channel/handler.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ) +// HandleMsgChannelOpenInit defines the sdk.Handler for MsgChannelOpenInit func HandleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenInit) sdk.Result { _, err := k.ChanOpenInit( ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, @@ -31,6 +32,7 @@ func HandleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgCha return sdk.Result{Events: ctx.EventManager().Events()} } +// HandleMsgChannelOpenTry defines the sdk.Handler for MsgChannelOpenTry func HandleMsgChannelOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenTry) sdk.Result { _, err := k.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, msg.Channel.Counterparty, msg.Channel.Version, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, @@ -56,6 +58,7 @@ func HandleMsgChannelOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgChan return sdk.Result{Events: ctx.EventManager().Events()} } +// HandleMsgChannelOpenAck defines the sdk.Handler for MsgChannelOpenAck func HandleMsgChannelOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenAck) sdk.Result { err := k.ChanOpenAck( ctx, msg.PortID, msg.ChannelID, msg.CounterpartyVersion, msg.ProofTry, msg.ProofHeight, @@ -80,6 +83,7 @@ func HandleMsgChannelOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgChan return sdk.Result{Events: ctx.EventManager().Events()} } +// HandleMsgChannelOpenConfirm defines the sdk.Handler for MsgChannelOpenConfirm func HandleMsgChannelOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenConfirm) sdk.Result { err := k.ChanOpenConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofAck, msg.ProofHeight) if err != nil { @@ -102,6 +106,7 @@ func HandleMsgChannelOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.Msg return sdk.Result{Events: ctx.EventManager().Events()} } +// HandleMsgChannelCloseInit defines the sdk.Handler for MsgChannelCloseInit func HandleMsgChannelCloseInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseInit) sdk.Result { err := k.ChanCloseInit(ctx, msg.PortID, msg.ChannelID) if err != nil { @@ -124,6 +129,7 @@ func HandleMsgChannelCloseInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgCh return sdk.Result{Events: ctx.EventManager().Events()} } +// HandleMsgChannelCloseConfirm defines the sdk.Handler for MsgChannelCloseConfirm func HandleMsgChannelCloseConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseConfirm) sdk.Result { err := k.ChanCloseConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofInit, msg.ProofHeight) if err != nil { @@ -145,3 +151,27 @@ func HandleMsgChannelCloseConfirm(ctx sdk.Context, k keeper.Keeper, msg types.Ms return sdk.Result{Events: ctx.EventManager().Events()} } + +// HandleMsgSendPacket defines the sdk.Handler for MsgSendPacket +func HandleMsgSendPacket(ctx sdk.Context, k Keeper, msg MsgSendPacket) sdk.Result { + err := k.SendPacket(ctx, msg.Packet) + if err != nil { + return sdk.ResultFromError(err) + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeSendPacket, + sdk.NewAttribute(types.AttributeKeySenderPort, msg.Packet.SourcePort()), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.Packet.SourceChannel()), + // TODO: destination port and channel events + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} +} diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go index bbbcdacfd88c..e0653e79d38a 100644 --- a/x/ibc/04-channel/keeper/handshake.go +++ b/x/ibc/04-channel/keeper/handshake.go @@ -35,7 +35,6 @@ func (k Keeper) ChanOpenInit( return "", ics03types.ErrConnectionNotFound(k.codespace, connectionHops[0]) } - // TODO: inconsistency on ICS03 (`none`) and ICS04 (`CLOSED`) if connection.State == ics03types.NONE { return "", errors.New("connection is closed") } diff --git a/x/ibc/04-channel/keeper/timeout.go b/x/ibc/04-channel/keeper/timeout.go index 08e8e33bc1c6..725e49b58ba8 100644 --- a/x/ibc/04-channel/keeper/timeout.go +++ b/x/ibc/04-channel/keeper/timeout.go @@ -11,12 +11,12 @@ import ( ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -// TimoutPacket is called by a module which originally attempted to send a +// TimeoutPacket is called by a module which originally attempted to send a // packet to a counterparty module, where the timeout height has passed on the // counterparty chain without the packet being committed, to prove that the // packet can no longer be executed and to allow the calling module to safely // perform appropriate state transitions. -func (k Keeper) TimoutPacket( +func (k Keeper) TimeoutPacket( ctx sdk.Context, packet exported.PacketI, proof ics23.Proof, diff --git a/x/ibc/04-channel/types/channel.go b/x/ibc/04-channel/types/channel.go index 3c56f6cecef6..923096135440 100644 --- a/x/ibc/04-channel/types/channel.go +++ b/x/ibc/04-channel/types/channel.go @@ -1,26 +1,5 @@ package types -// ChannelOrder defines if a channel is ORDERED or UNORDERED -type ChannelOrder byte - -// channel order types -const ( - UNORDERED ChannelOrder = iota // packets can be delivered in any order, which may differ from the order in which they were sent. - ORDERED // packets are delivered exactly in the order which they were sent -) - -// ChannelState defines if a channel is in one of the following states: -// CLOSED, INIT, OPENTRY or OPEN -type ChannelState byte - -// channel state types -const ( - CLOSED ChannelState = iota // A channel end has been closed and can no longer be used to send or receive packets. - INIT // A channel end has just started the opening handshake. - OPENTRY // A channel end has acknowledged the handshake step on the counterparty chain. - OPEN // A channel end has completed the handshake and is ready to send and receive packets. -) - type Channel struct { State ChannelState `json:"state" yaml:"state"` Ordering ChannelOrder `json:"ordering" yaml:"ordering"` @@ -53,6 +32,7 @@ func (ch Channel) CounterpartyHops() []string { return counterPartyHops } +// Counterparty defines the counterparty chain's channel and port identifiers type Counterparty struct { PortID string `json:"port_id" yaml:"port_id"` ChannelID string `json:"channel_id" yaml:"channel_id"` @@ -65,3 +45,81 @@ func NewCounterparty(portID, channelID string) Counterparty { ChannelID: channelID, } } + +// ChannelOrder defines if a channel is ORDERED or UNORDERED +type ChannelOrder byte + +// channel order types +const ( + NONE ChannelOrder = iota // zero-value for channel ordering + UNORDERED // packets can be delivered in any order, which may differ from the order in which they were sent. + ORDERED // packets are delivered exactly in the order which they were sent +) + +// ChannelOrderToString returns the string representation of a channel order +func ChannelOrderToString(order ChannelOrder) string { + switch order { + case UNORDERED: + return "UNORDERED" + case ORDERED: + return "ORDERED" + default: + return "" + } +} + +// StringToChannelOrder parses a string into a channel order byte +func StringToChannelOrder(order string) ChannelOrder { + switch order { + case "UNORDERED": + return UNORDERED + case "ORDERED": + return ORDERED + default: + return NONE + } +} + +// ChannelState defines if a channel is in one of the following states: +// CLOSED, INIT, OPENTRY or OPEN +type ChannelState byte + +// channel state types +const ( + CLOSED ChannelState = iota + 1 // A channel end has been closed and can no longer be used to send or receive packets. + INIT // A channel end has just started the opening handshake. + OPENTRY // A channel end has acknowledged the handshake step on the counterparty chain. + OPEN // A channel end has completed the handshake and is ready to send and receive packets. +) + +// ChannelStateToString returns the string representation of a channel state +func ChannelStateToString(state ChannelState) string { + switch state { + case CLOSED: + return "CLOSED" + case INIT: + return "INIT" + case OPENTRY: + return "OPENTRY" + case OPEN: + return "OPEN" + default: + return "CLOSED" + } +} + +// StringToChannelState parses a string into a channel state byte +func StringToChannelState(state string) ChannelState { + switch state { + case "CLOSED": + return CLOSED + case "INIT": + return INIT + case "OPENTRY": + return OPENTRY + case "OPEN": + return OPEN + default: + return CLOSED + } +} diff --git a/x/ibc/04-channel/types/codec.go b/x/ibc/04-channel/types/codec.go index 8f21c50037d1..4cfc1e773a1e 100644 --- a/x/ibc/04-channel/types/codec.go +++ b/x/ibc/04-channel/types/codec.go @@ -9,7 +9,7 @@ var SubModuleCdc *codec.Codec func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*exported.PacketI)(nil), nil) - cdc.RegisterConcrete(Packet{}, "ibc/channel/Packet", nil) + cdc.RegisterConcrete(OpaquePacket{}, "ibc/channel/OpaquePacket", nil) cdc.RegisterConcrete(MsgChannelOpenInit{}, "ibc/channel/MsgChannelOpenInit", nil) cdc.RegisterConcrete(MsgChannelOpenTry{}, "ibc/channel/MsgChannelOpenTry", nil) diff --git a/x/ibc/04-channel/types/errors.go b/x/ibc/04-channel/types/errors.go index 933163838c4e..402db58ce9d9 100644 --- a/x/ibc/04-channel/types/errors.go +++ b/x/ibc/04-channel/types/errors.go @@ -18,8 +18,8 @@ const ( CodeInvalidPacketSequence sdk.CodeType = 106 CodeSequenceNotFound sdk.CodeType = 107 CodePacketTimeout sdk.CodeType = 108 - CodeChanIDLen sdk.CodeType = 109 - CodePortIDLen sdk.CodeType = 110 + CodeInvalidPortID sdk.CodeType = 109 + CodeInvalidChannelID sdk.CodeType = 110 ) // ErrChannelExists implements sdk.Error @@ -62,12 +62,12 @@ func ErrPacketTimeout(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodePacketTimeout, "packet timeout") } -// ErrChanIDLen implements sdk.Error -func ErrLenChanID(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeChanIDLen, "chanid too long") +// ErrInvalidPortID implements sdk.Error +func ErrInvalidPortID(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidPortID, msg) } -// ErrLenPortID implements sdk.Error -func ErrLenPortID(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodePortIDLen, "portid too long") +// ErrInvalidChannelID implements sdk.Error +func ErrInvalidChannelID(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidChannelID, msg) } diff --git a/x/ibc/04-channel/types/events.go b/x/ibc/04-channel/types/events.go index 90d38b274aaf..7b81f1033285 100644 --- a/x/ibc/04-channel/types/events.go +++ b/x/ibc/04-channel/types/events.go @@ -8,14 +8,6 @@ import ( // IBC channel events const ( - EventTypeSendPacket = "send_packet" - EventTypeChannelOpenInit = "channel_open_init" - EventTypeChannelOpenTry = "channel_open_try" - EventTypeChannelOpenAck = "channel_open_ack" - EventTypeChannelOpenConfirm = "channel_open_confirm" - EventTypeChannelCloseInit = "channel_close_init" - EventTypeChannelCloseConfirm = "channel_close_confirm" - AttributeKeySenderPort = "sender_port" AttributeKeyReceiverPort = "receiver_port" AttributeKeyChannelID = "channel_id" @@ -24,5 +16,13 @@ const ( // IBC channel events vars var ( + EventTypeSendPacket = MsgSendPacket{}.Type() + EventTypeChannelOpenInit = MsgChannelOpenInit{}.Type() + EventTypeChannelOpenTry = MsgChannelOpenTry{}.Type() + EventTypeChannelOpenAck = MsgChannelOpenAck{}.Type() + EventTypeChannelOpenConfirm = MsgChannelOpenConfirm{}.Type() + EventTypeChannelCloseInit = MsgChannelCloseInit{}.Type() + EventTypeChannelCloseConfirm = MsgChannelCloseConfirm{}.Type() + AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, SubModuleName) ) diff --git a/x/ibc/04-channel/types/msgs.go b/x/ibc/04-channel/types/msgs.go index aa875d805f1e..8b9a883f1b0f 100644 --- a/x/ibc/04-channel/types/msgs.go +++ b/x/ibc/04-channel/types/msgs.go @@ -1,6 +1,9 @@ package types import ( + "fmt" + "strings" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" @@ -8,6 +11,7 @@ import ( ) const ( + // TODO: double check lenght. Eventually move to ICS24 lenPortID = 64 lenChanID = 64 ) @@ -21,8 +25,16 @@ type MsgChannelOpenInit struct { Signer sdk.AccAddress `json:"signer"` } -func NewMsgChannelOpenInit(portID string, channelID string, channel Channel, signer sdk.AccAddress) MsgChannelOpenInit { - return MsgChannelOpenInit{portID, channelID, channel, signer} +// NewMsgChannelOpenInit creates a new MsgChannelCloseInit MsgChannelOpenInit +func NewMsgChannelOpenInit( + portID, channelID string, channel Channel, signer sdk.AccAddress, +) MsgChannelOpenInit { + return MsgChannelOpenInit{ + PortID: portID, + ChannelID: channelID, + Channel: channel, + Signer: signer, + } } // Route implements sdk.Msg @@ -32,19 +44,25 @@ func (msg MsgChannelOpenInit) Route() string { // Type implements sdk.Msg func (msg MsgChannelOpenInit) Type() string { - return EventTypeChannelOpenInit + return "channel_open_init" } // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenInit) ValidateBasic() sdk.Error { - // Check PortID + if strings.TrimSpace(msg.PortID) == "" { + return ErrInvalidPortID(DefaultCodespace, "port ID can't be blank") + } + if len(msg.PortID) > lenPortID { - return ErrLenPortID(DefaultCodespace) + return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("port ID length can't be > %d", lenPortID)) + } + + if strings.TrimSpace(msg.ChannelID) == "" { + return ErrInvalidPortID(DefaultCodespace, "channel ID can't be blank") } - // Check ChanID if len(msg.ChannelID) > lenChanID { - return ErrLenChanID(DefaultCodespace) + return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("channel ID length can't be > %d", lenChanID)) } // Signer can be empty @@ -73,8 +91,20 @@ type MsgChannelOpenTry struct { Signer sdk.AccAddress `json:"signer"` } -func NewMsgChannelOpenTry(portID string, channelID string, channel Channel, cpv string, proofInit ics23.Proof, proofHeight uint64, signer sdk.AccAddress) MsgChannelOpenTry { - return MsgChannelOpenTry{portID, channelID, channel, cpv, proofInit, proofHeight, signer} +// NewMsgChannelOpenTry creates a new MsgChannelOpenTry instance +func NewMsgChannelOpenTry( + portID, channelID string, channel Channel, cpv string, proofInit ics23.Proof, + proofHeight uint64, signer sdk.AccAddress, +) MsgChannelOpenTry { + return MsgChannelOpenTry{ + PortID: portID, + ChannelID: channelID, + Channel: channel, + CounterpartyVersion: cpv, + ProofInit: proofInit, + ProofHeight: proofHeight, + Signer: signer, + } } // Route implements sdk.Msg @@ -84,19 +114,26 @@ func (msg MsgChannelOpenTry) Route() string { // Type implements sdk.Msg func (msg MsgChannelOpenTry) Type() string { - return EventTypeChannelOpenTry + return "channel_open_try" } // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenTry) ValidateBasic() sdk.Error { - // Check PortID + + if strings.TrimSpace(msg.PortID) == "" { + return ErrInvalidPortID(DefaultCodespace, "port ID can't be blank") + } + if len(msg.PortID) > lenPortID { - return ErrLenPortID(DefaultCodespace) + return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("port ID length can't be > %d", lenPortID)) + } + + if strings.TrimSpace(msg.ChannelID) == "" { + return ErrInvalidPortID(DefaultCodespace, "channel ID can't be blank") } - // Check ChanID if len(msg.ChannelID) > lenChanID { - return ErrLenChanID(DefaultCodespace) + return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("channel ID length can't be > %d", lenChanID)) } // Check proofs != nil @@ -126,8 +163,19 @@ type MsgChannelOpenAck struct { Signer sdk.AccAddress `json:"signer"` } -func NewMsgChannelOpenAck(port string, channelID string, cpv string, proofTry ics23.Proof, proofHeight uint64, signer sdk.AccAddress) MsgChannelOpenAck { - return MsgChannelOpenAck{port, channelID, cpv, proofTry, proofHeight, signer} +// NewMsgChannelOpenAck creates a new MsgChannelOpenAck instance +func NewMsgChannelOpenAck( + portID, channelID string, cpv string, proofTry ics23.Proof, proofHeight uint64, + signer sdk.AccAddress, +) MsgChannelOpenAck { + return MsgChannelOpenAck{ + PortID: portID, + ChannelID: channelID, + CounterpartyVersion: cpv, + ProofTry: proofTry, + ProofHeight: proofHeight, + Signer: signer, + } } // Route implements sdk.Msg @@ -137,19 +185,25 @@ func (msg MsgChannelOpenAck) Route() string { // Type implements sdk.Msg func (msg MsgChannelOpenAck) Type() string { - return EventTypeChannelOpenAck + return "channel_open_ack" } // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenAck) ValidateBasic() sdk.Error { - // Check PortID + if strings.TrimSpace(msg.PortID) == "" { + return ErrInvalidPortID(DefaultCodespace, "port ID can't be blank") + } + if len(msg.PortID) > lenPortID { - return ErrLenPortID(DefaultCodespace) + return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("port ID length can't be > %d", lenPortID)) + } + + if strings.TrimSpace(msg.ChannelID) == "" { + return ErrInvalidPortID(DefaultCodespace, "channel ID can't be blank") } - // Check ChanID if len(msg.ChannelID) > lenChanID { - return ErrLenChanID(DefaultCodespace) + return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("channel ID length can't be > %d", lenChanID)) } // Check proofs != nil @@ -177,8 +231,18 @@ type MsgChannelOpenConfirm struct { Signer sdk.AccAddress `json:"signer"` } -func NewMsgChannelOpenConfirm(portID string, channelID string, proofAck ics23.Proof, proofHeight uint64, signer sdk.AccAddress) MsgChannelOpenConfirm { - return MsgChannelOpenConfirm{portID, channelID, proofAck, proofHeight, signer} +// NewMsgChannelOpenConfirm creates a new MsgChannelOpenConfirm instance +func NewMsgChannelOpenConfirm( + portID, channelID string, proofAck ics23.Proof, proofHeight uint64, + signer sdk.AccAddress, +) MsgChannelOpenConfirm { + return MsgChannelOpenConfirm{ + PortID: portID, + ChannelID: channelID, + ProofAck: proofAck, + ProofHeight: proofHeight, + Signer: signer, + } } // Route implements sdk.Msg @@ -188,19 +252,25 @@ func (msg MsgChannelOpenConfirm) Route() string { // Type implements sdk.Msg func (msg MsgChannelOpenConfirm) Type() string { - return EventTypeChannelOpenConfirm + return "channel_open_confirm" } // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenConfirm) ValidateBasic() sdk.Error { - // Check PortID + if strings.TrimSpace(msg.PortID) == "" { + return ErrInvalidPortID(DefaultCodespace, "port ID can't be blank") + } + if len(msg.PortID) > lenPortID { - return ErrLenPortID(DefaultCodespace) + return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("port ID length can't be > %d", lenPortID)) + } + + if strings.TrimSpace(msg.ChannelID) == "" { + return ErrInvalidPortID(DefaultCodespace, "channel ID can't be blank") } - // Check ChanID if len(msg.ChannelID) > lenChanID { - return ErrLenChanID(DefaultCodespace) + return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("channel ID length can't be > %d", lenChanID)) } // Check proofs != nil @@ -226,8 +296,13 @@ type MsgChannelCloseInit struct { Signer sdk.AccAddress `json:"signer"` } +// NewMsgChannelCloseInit creates a new MsgChannelCloseInit instance func NewMsgChannelCloseInit(portID string, channelID string, signer sdk.AccAddress) MsgChannelCloseInit { - return MsgChannelCloseInit{portID, channelID, signer} + return MsgChannelCloseInit{ + PortID: portID, + ChannelID: channelID, + Signer: signer, + } } // Route implements sdk.Msg @@ -237,19 +312,25 @@ func (msg MsgChannelCloseInit) Route() string { // Type implements sdk.Msg func (msg MsgChannelCloseInit) Type() string { - return EventTypeChannelCloseInit + return "channel_close_init" } // ValidateBasic implements sdk.Msg func (msg MsgChannelCloseInit) ValidateBasic() sdk.Error { - // Check PortID + if strings.TrimSpace(msg.PortID) == "" { + return ErrInvalidPortID(DefaultCodespace, "port ID can't be blank") + } + if len(msg.PortID) > lenPortID { - return ErrLenPortID(DefaultCodespace) + return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("port ID length can't be > %d", lenPortID)) + } + + if strings.TrimSpace(msg.ChannelID) == "" { + return ErrInvalidPortID(DefaultCodespace, "channel ID can't be blank") } - // Check ChanID if len(msg.ChannelID) > lenChanID { - return ErrLenChanID(DefaultCodespace) + return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("channel ID length can't be > %d", lenChanID)) } // Signer can be empty @@ -276,8 +357,18 @@ type MsgChannelCloseConfirm struct { Signer sdk.AccAddress `json:"signer"` } -func NewMsgChannelCloseConfirm(portID string, channelID string, proofInit ics23.Proof, proofHeight uint64, signer sdk.AccAddress) MsgChannelCloseConfirm { - return MsgChannelCloseConfirm{portID, channelID, proofInit, proofHeight, signer} +// NewMsgChannelCloseConfirm creates a new MsgChannelCloseConfirm instance +func NewMsgChannelCloseConfirm( + portID, channelID string, proofInit ics23.Proof, proofHeight uint64, + signer sdk.AccAddress, +) MsgChannelCloseConfirm { + return MsgChannelCloseConfirm{ + PortID: portID, + ChannelID: channelID, + ProofInit: proofInit, + ProofHeight: proofHeight, + Signer: signer, + } } // Route implements sdk.Msg @@ -287,19 +378,25 @@ func (msg MsgChannelCloseConfirm) Route() string { // Type implements sdk.Msg func (msg MsgChannelCloseConfirm) Type() string { - return EventTypeChannelCloseConfirm + return "channel_close_confirm" } // ValidateBasic implements sdk.Msg func (msg MsgChannelCloseConfirm) ValidateBasic() sdk.Error { - // Check PortID + if strings.TrimSpace(msg.PortID) == "" { + return ErrInvalidPortID(DefaultCodespace, "port ID can't be blank") + } + if len(msg.PortID) > lenPortID { - return ErrLenPortID(DefaultCodespace) + return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("port ID length can't be > %d", lenPortID)) + } + + if strings.TrimSpace(msg.ChannelID) == "" { + return ErrInvalidPortID(DefaultCodespace, "channel ID can't be blank") } - // Check ChanID if len(msg.ChannelID) > lenChanID { - return ErrLenChanID(DefaultCodespace) + return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("channel ID length can't be > %d", lenChanID)) } // Check proofs != nil @@ -330,8 +427,12 @@ type MsgSendPacket struct { Signer sdk.AccAddress `json:"signer" yaml:"signer"` } -func NewMsgSendPacket(packet exported.PacketI, channelID string, proofs []ics23.Proof, height uint64, signer sdk.AccAddress) MsgSendPacket { - return MsgSendPacket{packet, channelID, proofs, height, signer} +// NewMsgSendPacket creates a new MsgSendPacket instance +func NewMsgSendPacket(packet exported.PacketI, signer sdk.AccAddress) MsgSendPacket { + return MsgSendPacket{ + Packet: packet, + Signer: signer, + } } // Route implements sdk.Msg @@ -341,14 +442,42 @@ func (msg MsgSendPacket) Route() string { // Type implements sdk.Msg func (msg MsgSendPacket) Type() string { - return EventTypeSendPacket + return "send_packet" } // ValidateBasic implements sdk.Msg func (msg MsgSendPacket) ValidateBasic() sdk.Error { - // Check ChanID - if len(msg.ChannelID) > lenChanID { - return ErrLenChanID(DefaultCodespace) + // TODO: move to Packet validation function + if strings.TrimSpace(msg.Packet.SourcePort()) == "" { + return ErrInvalidPortID(DefaultCodespace, "packet source port ID can't be blank") + } + + if len(msg.Packet.SourcePort()) > lenPortID { + return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("packet source port ID length can't be > %d", lenPortID)) + } + + if strings.TrimSpace(msg.Packet.DestPort()) == "" { + return ErrInvalidPortID(DefaultCodespace, "packet destination port ID can't be blank") + } + + if len(msg.Packet.DestPort()) > lenPortID { + return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("packet destination port ID length can't be > %d", lenPortID)) + } + + if strings.TrimSpace(msg.Packet.SourceChannel()) == "" { + return ErrInvalidPortID(DefaultCodespace, "packet source channel ID can't be blank") + } + + if len(msg.Packet.SourceChannel()) > lenChanID { + return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("packet source channel ID length can't be > %d", lenChanID)) + } + + if strings.TrimSpace(msg.Packet.DestChannel()) == "" { + return ErrInvalidPortID(DefaultCodespace, "packet destination channel ID can't be blank") + } + + if len(msg.Packet.DestChannel()) > lenChanID { + return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("packet destination channel ID length can't be > %d", lenChanID)) } // Check proofs != nil diff --git a/x/ibc/04-channel/types/packet.go b/x/ibc/04-channel/types/packet.go index ffde3410e96f..fc9ce61ad47b 100644 --- a/x/ibc/04-channel/types/packet.go +++ b/x/ibc/04-channel/types/packet.go @@ -4,10 +4,10 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" ) -var _ exported.PacketI = Packet{} +var _ exported.PacketI = packet{} -// Packet defines a type that carries data across different chains through IBC -type Packet struct { +// packet defines a type that carries data across different chains through IBC +type packet struct { sequence uint64 // number corresponds to the order of sends and receives, where a packet with an earlier sequence number must be sent and received before a packet with a later sequence number. timeout uint64 // indicates a consensus height on the destination chain after which the packet will no longer be processed, and will instead count as having timed-out. sourcePort string // identifies the port on the sending chain. @@ -17,12 +17,12 @@ type Packet struct { data []byte // opaque value which can be defined by the application logic of the associated modules. } -// NewPacket creates a new Packet instance -func NewPacket( +// newPacket creates a new Packet instance +func newPacket( sequence, timeout uint64, sourcePort, sourceChannel, destinationPort, destinationChannel string, data []byte, -) Packet { - return Packet{ +) packet { + return packet{ sequence, timeout, sourcePort, @@ -34,29 +34,31 @@ func NewPacket( } // Sequence implements PacketI interface -func (p Packet) Sequence() uint64 { return p.sequence } +func (p packet) Sequence() uint64 { return p.sequence } // TimeoutHeight implements PacketI interface -func (p Packet) TimeoutHeight() uint64 { return p.timeout } +func (p packet) TimeoutHeight() uint64 { return p.timeout } // SourcePort implements PacketI interface -func (p Packet) SourcePort() string { return p.sourcePort } +func (p packet) SourcePort() string { return p.sourcePort } // SourceChannel implements PacketI interface -func (p Packet) SourceChannel() string { return p.sourceChannel } +func (p packet) SourceChannel() string { return p.sourceChannel } // DestPort implements PacketI interface -func (p Packet) DestPort() string { return p.destinationPort } +func (p packet) DestPort() string { return p.destinationPort } // DestChannel implements PacketI interface -func (p Packet) DestChannel() string { return p.destinationChannel } +func (p packet) DestChannel() string { return p.destinationChannel } // Data implements PacketI interface -func (p Packet) Data() []byte { return p.data } +func (p packet) Data() []byte { return p.data } + +var _ exported.PacketI = OpaquePacket{} // OpaquePacket is a packet, but cloaked in an obscuring data type by the host // state machine, such that a module cannot act upon it other than to pass it to // the IBC handler -type OpaquePacket Packet +type OpaquePacket packet // TODO: Obscure data type diff --git a/x/ibc/04-channel/types/port.go b/x/ibc/04-channel/types/port.go deleted file mode 100644 index a8183103fb75..000000000000 --- a/x/ibc/04-channel/types/port.go +++ /dev/null @@ -1,30 +0,0 @@ -package types - -type Port struct { - id string -} - -// ID of the port -func (p Port) ID() string { - return p.id -} - -// // bindPort, expected to be called only at init time -// // TODO: is it safe to support runtime bindPort? -// func (man Manager) Port(id string) Port { -// if _, ok := man.ports[id]; ok { -// panic("port already occupied") -// } -// man.ports[id] = struct{}{} -// return Port{man, id} -// } - -// // releasePort -// func (port Port) Release() { -// delete(port.channel.ports, port.id) -// } - -// func (man Manager) IsValid(port Port) bool { -// _, ok := man.ports[port.id] -// return ok -// } diff --git a/x/ibc/handler.go b/x/ibc/handler.go index b80267dd7d92..8822b0206da9 100644 --- a/x/ibc/handler.go +++ b/x/ibc/handler.go @@ -57,6 +57,9 @@ func NewHandler(k Keeper) sdk.Handler { case channel.MsgChannelCloseConfirm: return channel.HandleMsgChannelCloseConfirm(ctx, k.ChannelKeeper, msg) + case channel.MsgSendPacket: + return channel.HandleMsgSendPacket(ctx, k.ChannelKeeper, msg) + default: errMsg := fmt.Sprintf("unrecognized IBC message type: %T", msg) return sdk.ErrUnknownRequest(errMsg).Result() diff --git a/x/ibc/module.go b/x/ibc/module.go index 447ec2cb03fe..a186412e3a99 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -13,6 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/client/cli" "github.com/cosmos/cosmos-sdk/x/ibc/types" From 012bf5453e11bca3dadce1360e45ca9774d8cd7b Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 16 Oct 2019 12:22:22 +0200 Subject: [PATCH 300/378] update errors and add port Keeper to ibc Keeper --- x/ibc/05-port/alias.go | 2 +- x/ibc/05-port/keeper/keeper.go | 10 +++++----- x/ibc/05-port/types/errors.go | 10 ++++++---- x/ibc/05-port/types/keys.go | 10 +++++----- x/ibc/keeper/keeper.go | 4 ++++ 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/x/ibc/05-port/alias.go b/x/ibc/05-port/alias.go index 8f36b91e54af..ccf3db732be3 100644 --- a/x/ibc/05-port/alias.go +++ b/x/ibc/05-port/alias.go @@ -1,4 +1,4 @@ -package ics05 +package port // nolint // autogenerated code using github.com/rigelrozanski/multitool diff --git a/x/ibc/05-port/keeper/keeper.go b/x/ibc/05-port/keeper/keeper.go index 0aa6845dc8e7..858b15f14b4d 100644 --- a/x/ibc/05-port/keeper/keeper.go +++ b/x/ibc/05-port/keeper/keeper.go @@ -23,8 +23,8 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) return Keeper{ storeKey: key, cdc: cdc, - codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/ports", - prefix: []byte(types.SubModuleName + "/"), // "ports/" + codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/port", + prefix: []byte(types.SubModuleName + "/"), // "port/" } } @@ -63,7 +63,7 @@ func (k Keeper) BindPort(ctx sdk.Context, portID string, generateFn exported.Gen _, found := k.GetPort(ctx, portID) if found { - return types.ErrPortExists(k.codespace) + return types.ErrPortExists(k.codespace, portID) } key := generateFn() k.SetPort(ctx, portID, key) @@ -83,7 +83,7 @@ func (k Keeper) TransferPort( ) sdk.Error { port, found := k.GetPort(ctx, portID) if !found { - return types.ErrPortNotFound(k.codespace) + return types.ErrPortNotFound(k.codespace, portID) } if !authenticateFn(port) { @@ -107,7 +107,7 @@ func (k Keeper) ReleasePort( authenticateFn exported.Authenticate) sdk.Error { port, found := k.GetPort(ctx, portID) if !found { - return types.ErrPortNotFound(k.codespace) + return types.ErrPortNotFound(k.codespace, portID) } if !authenticateFn(port) { diff --git a/x/ibc/05-port/types/errors.go b/x/ibc/05-port/types/errors.go index e8ef1fc53992..20031c826107 100644 --- a/x/ibc/05-port/types/errors.go +++ b/x/ibc/05-port/types/errors.go @@ -1,6 +1,8 @@ package types import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -15,13 +17,13 @@ const ( ) // ErrPortExists implements sdk.Error -func ErrPortExists(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodePortExists, "port already binded") +func ErrPortExists(codespace sdk.CodespaceType, portID string) sdk.Error { + return sdk.NewError(codespace, CodePortExists, fmt.Sprintf("port with ID %s is already binded", portID)) } // ErrPortNotFound implements sdk.Error -func ErrPortNotFound(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodePortNotFound, "port not found") +func ErrPortNotFound(codespace sdk.CodespaceType, portID string) sdk.Error { + return sdk.NewError(codespace, CodePortNotFound, fmt.Sprintf("port with ID %s not found", portID)) } // ErrPortNotAuthenticated implements sdk.Error diff --git a/x/ibc/05-port/types/keys.go b/x/ibc/05-port/types/keys.go index 342a931f19db..b1250e0e4463 100644 --- a/x/ibc/05-port/types/keys.go +++ b/x/ibc/05-port/types/keys.go @@ -5,16 +5,16 @@ import ( ) const ( - // SubModuleName defines the IBC ports name - SubModuleName = "ports" + // SubModuleName defines the IBC port name + SubModuleName = "port" - // StoreKey is the store key string for IBC connections + // StoreKey is the store key string for IBC ports StoreKey = SubModuleName - // RouterKey is the message route for IBC connections + // RouterKey is the message route for IBC ports RouterKey = SubModuleName - // QuerierRoute is the querier route for IBC connections + // QuerierRoute is the querier route for IBC ports QuerierRoute = SubModuleName ) diff --git a/x/ibc/keeper/keeper.go b/x/ibc/keeper/keeper.go index dafe8892d167..c9708a6e79a1 100644 --- a/x/ibc/keeper/keeper.go +++ b/x/ibc/keeper/keeper.go @@ -5,21 +5,25 @@ import ( 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" + port "github.com/cosmos/cosmos-sdk/x/ibc/05-port" ) // Keeper defines each ICS keeper for IBC type Keeper struct { ClientKeeper client.Keeper ConnectionKeeper connection.Keeper + PortKeeper port.Keeper } // NewKeeper creates a new ibc Keeper func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) Keeper { clientKeeper := client.NewKeeper(cdc, key, codespace) connectionKeeper := connection.NewKeeper(cdc, key, codespace, clientKeeper) + portKeeper := port.NewKeeper(cdc, key, codespace) return Keeper{ ClientKeeper: clientKeeper, ConnectionKeeper: connectionKeeper, + PortKeeper: portKeeper, } } From 6af2ce7a0bf8d08217d1be3d620d27637040734f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 16 Oct 2019 15:53:30 +0200 Subject: [PATCH 301/378] minor UX improvements --- x/ibc/02-client/client/cli/tx.go | 77 +++++++++++++++++----------- x/ibc/02-client/exported/exported.go | 15 +++++- x/ibc/02-client/types/errors.go | 14 ++--- 3 files changed, 67 insertions(+), 39 deletions(-) diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index ef9b0674882c..a9efc1162461 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -3,6 +3,7 @@ package cli import ( "fmt" "io/ioutil" + "os" "strings" "github.com/spf13/cobra" @@ -52,21 +53,27 @@ $ %s tx ibc client create [client-id] [path/to/consensus_state.json] --from node txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) - contents, err := ioutil.ReadFile(args[1]) - if err != nil { - return err - } + clientID := args[0] var state exported.ConsensusState - if err := cdc.UnmarshalJSON(contents, &state); err != nil { - return err + if err := cdc.UnmarshalJSON([]byte(args[1]), &state); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") + + contents, err := ioutil.ReadFile(args[1]) + if err != nil { + return fmt.Errorf("error opening proof file: %v", err) + } + if err := cdc.UnmarshalJSON(contents, &state); err != nil { + return fmt.Errorf("error unmarshalling consensus state file: %v", err) + } } - msg := types.MsgCreateClient{ - ClientID: args[0], - - ConsensusState: state, - Signer: cliCtx.GetFromAddress(), + msg := types.NewMsgCreateClient( + clientID, exported.ClientTypeToString(state.ClientType()), state, + cliCtx.GetFromAddress(), + ) + if err := msg.ValidateBasic(); err != nil { + return err } return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) @@ -92,20 +99,24 @@ $ %s tx ibc client create [client-id] [path/to/header.json] --from node0 --home txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) - bz, err := ioutil.ReadFile(args[1]) - if err != nil { - return err - } + clientID := args[0] var header exported.Header - if err := cdc.UnmarshalJSON(bz, &header); err != nil { - return err + if err := cdc.UnmarshalJSON([]byte(args[1]), &header); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") + + contents, err := ioutil.ReadFile(args[1]) + if err != nil { + return fmt.Errorf("error opening proof file: %v", err) + } + if err := cdc.UnmarshalJSON(contents, &header); err != nil { + return fmt.Errorf("error unmarshalling header file: %v", err) + } } - msg := types.MsgUpdateClient{ - ClientID: args[0], - Header: header, - Signer: cliCtx.GetFromAddress(), + msg := types.NewMsgUpdateClient(clientID, header, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err } return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) @@ -132,20 +143,24 @@ $ %s tx ibc client misbehaviour [client-id] [path/to/evidence.json] --from node0 txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc) - bz, err := ioutil.ReadFile(args[1]) - if err != nil { - return err - } + clientID := args[0] var evidence exported.Evidence - if err := cdc.UnmarshalJSON(bz, &evidence); err != nil { - return err + if err := cdc.UnmarshalJSON([]byte(args[1]), &evidence); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") + + contents, err := ioutil.ReadFile(args[1]) + if err != nil { + return fmt.Errorf("error opening proof file: %v", err) + } + if err := cdc.UnmarshalJSON(contents, &evidence); err != nil { + return fmt.Errorf("error unmarshalling evidence file: %v", err) + } } - msg := types.MsgSubmitMisbehaviour{ - ClientID: args[0], - Evidence: evidence, - Signer: cliCtx.GetFromAddress(), + msg := types.NewMsgSubmitMisbehaviour(clientID, evidence, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err } return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index 074dfff0024e..ce0f51af84af 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -76,8 +76,8 @@ func RegisterClientType(ty string) { // ClientTypeFromStr returns a byte that corresponds to the registered client // type. It returns 0 if the type is not found/registered. -func ClientTypeFromStr(ty string) ClientType { - switch ty { +func ClientTypeFromStr(clientType string) ClientType { + switch clientType { case ClientTypeTendermint: return Tendermint @@ -85,3 +85,14 @@ func ClientTypeFromStr(ty string) ClientType { return 0 } } + +// ClientTypeToString returns the string representation of a client type +func ClientTypeToString(clientType ClientType) string { + switch clientType { + case Tendermint: + return ClientTypeTendermint + + default: + return "" + } +} diff --git a/x/ibc/02-client/types/errors.go b/x/ibc/02-client/types/errors.go index 90707e84d815..282e697d3bce 100644 --- a/x/ibc/02-client/types/errors.go +++ b/x/ibc/02-client/types/errors.go @@ -1,6 +1,8 @@ package types import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -19,18 +21,18 @@ const ( ) // ErrClientExists implements sdk.Error -func ErrClientExists(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeClientExists, "client already exists") +func ErrClientExists(codespace sdk.CodespaceType, clientID string) sdk.Error { + return sdk.NewError(codespace, CodeClientExists, fmt.Sprintf("client with ID %s already exists", clientID)) } // ErrClientNotFound implements sdk.Error -func ErrClientNotFound(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeClientNotFound, "client not found") +func ErrClientNotFound(codespace sdk.CodespaceType, clientID string) sdk.Error { + return sdk.NewError(codespace, CodeClientNotFound, fmt.Sprintf("client with ID %s not found", clientID)) } // ErrClientFrozen implements sdk.Error -func ErrClientFrozen(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeClientFrozen, "client is frozen due to misbehaviour") +func ErrClientFrozen(codespace sdk.CodespaceType, clientID string) sdk.Error { + return sdk.NewError(codespace, CodeClientFrozen, fmt.Sprintf("client with ID %s is frozen due to misbehaviour", clientID)) } // ErrConsensusStateNotFound implements sdk.Error From 8be3af78e5c3a0d3b5d564d1d75a29e63d3a5e99 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 16 Oct 2019 15:56:22 +0200 Subject: [PATCH 302/378] rename pkg --- x/ibc/client/cli/cli.go | 6 +++--- x/ibc/keeper/keeper.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/x/ibc/client/cli/cli.go b/x/ibc/client/cli/cli.go index 640d4b3f580c..f2fa0fa9030a 100644 --- a/x/ibc/client/cli/cli.go +++ b/x/ibc/client/cli/cli.go @@ -5,7 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" - ics02 "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client" "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -20,7 +20,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { } ibcTxCmd.AddCommand( - ics02.GetTxCmd(cdc, storeKey), + ibcclient.GetTxCmd(cdc, storeKey), ) return ibcTxCmd } @@ -37,7 +37,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { } ibcQueryCmd.AddCommand( - ics02.GetQueryCmd(cdc, queryRoute), + ibcclient.GetQueryCmd(cdc, queryRoute), ) return ibcQueryCmd } diff --git a/x/ibc/keeper/keeper.go b/x/ibc/keeper/keeper.go index 1dd8abef5596..fce91fb353bd 100644 --- a/x/ibc/keeper/keeper.go +++ b/x/ibc/keeper/keeper.go @@ -3,17 +3,17 @@ package keeper import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - ics02 "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" ) // Keeper defines each ICS keeper for IBC type Keeper struct { - ClientKeeper ics02.Keeper + ClientKeeper client.Keeper } // NewKeeper creates a new ibc Keeper func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) Keeper { return Keeper{ - ClientKeeper: ics02.NewKeeper(cdc, key, codespace), + ClientKeeper: client.NewKeeper(cdc, key, codespace), } } From 53ab47db24733eeaaaf2ee1ca52cda4518d8a2cc Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 16 Oct 2019 16:01:18 +0200 Subject: [PATCH 303/378] fixes --- x/ibc/02-client/keeper/client.go | 8 ++++---- x/ibc/02-client/keeper/keeper.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go index df3aaf53d23b..de26aa6c6591 100644 --- a/x/ibc/02-client/keeper/client.go +++ b/x/ibc/02-client/keeper/client.go @@ -17,7 +17,7 @@ func (k Keeper) CreateClient( ) (types.ClientState, error) { _, found := k.GetClientState(ctx, clientID) if found { - return types.ClientState{}, types.ErrClientExists(k.codespace) + return types.ClientState{}, types.ErrClientExists(k.codespace, clientID) } _, found = k.GetClientType(ctx, clientID) @@ -51,11 +51,11 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H clientState, found := k.GetClientState(ctx, clientID) if !found { - return sdkerrors.Wrap(types.ErrClientNotFound(k.codespace), "cannot update client") + return sdkerrors.Wrap(types.ErrClientNotFound(k.codespace, clientID), "cannot update client") } if clientState.Frozen { - return sdkerrors.Wrap(types.ErrClientFrozen(k.codespace), "cannot update client") + return sdkerrors.Wrap(types.ErrClientFrozen(k.codespace, clientID), "cannot update client") } consensusState, found := k.GetConsensusState(ctx, clientID) @@ -88,7 +88,7 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, clientID string, evidence exported.Evidence) error { clientState, found := k.GetClientState(ctx, clientID) if !found { - sdk.ResultFromError(types.ErrClientNotFound(k.codespace)) + sdk.ResultFromError(types.ErrClientNotFound(k.codespace, clientID)) } err := k.checkMisbehaviour(ctx, evidence) diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index d0f83ce19d31..660fdc450f24 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -149,7 +149,7 @@ func (k Keeper) checkMisbehaviour(ctx sdk.Context, evidence exported.Evidence) e // freeze updates the state of the client in the event of a misbehaviour func (k Keeper) freeze(ctx sdk.Context, clientState types.ClientState) (types.ClientState, error) { if clientState.Frozen { - return types.ClientState{}, sdkerrors.Wrap(types.ErrClientFrozen(k.codespace), "already frozen") + return types.ClientState{}, sdkerrors.Wrap(types.ErrClientFrozen(k.codespace, clientState.ID()), "already frozen") } clientState.Frozen = true From 499abb4b1dee900bc6958ac980323ae2ca91b093 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 18 Oct 2019 11:54:02 +0200 Subject: [PATCH 304/378] refactor ICS23 --- x/ibc/23-commitment/codec.go | 12 -- x/ibc/23-commitment/context.go | 18 --- .../{types.go => exported/exported.go} | 24 +-- x/ibc/23-commitment/keeper/keeper.go | 81 ++++++++++ x/ibc/23-commitment/merkle/merkle.go | 112 ------------- x/ibc/23-commitment/merkle/merkle_test.go | 134 --------------- x/ibc/23-commitment/merkle/utils.go | 34 ---- x/ibc/23-commitment/store.go | 105 ------------ .../23-commitment/{merkle => types}/codec.go | 8 +- x/ibc/23-commitment/types/merkle.go | 153 ++++++++++++++++++ x/ibc/23-commitment/types/state.go | 24 +++ x/ibc/23-commitment/types/utils.go | 8 + 12 files changed, 286 insertions(+), 427 deletions(-) delete mode 100644 x/ibc/23-commitment/codec.go delete mode 100644 x/ibc/23-commitment/context.go rename x/ibc/23-commitment/{types.go => exported/exported.go} (66%) create mode 100644 x/ibc/23-commitment/keeper/keeper.go delete mode 100644 x/ibc/23-commitment/merkle/merkle.go delete mode 100644 x/ibc/23-commitment/merkle/merkle_test.go delete mode 100644 x/ibc/23-commitment/merkle/utils.go delete mode 100644 x/ibc/23-commitment/store.go rename x/ibc/23-commitment/{merkle => types}/codec.go (50%) create mode 100644 x/ibc/23-commitment/types/merkle.go create mode 100644 x/ibc/23-commitment/types/state.go create mode 100644 x/ibc/23-commitment/types/utils.go diff --git a/x/ibc/23-commitment/codec.go b/x/ibc/23-commitment/codec.go deleted file mode 100644 index 7312c5942d85..000000000000 --- a/x/ibc/23-commitment/codec.go +++ /dev/null @@ -1,12 +0,0 @@ -package ics23 - -import ( - "github.com/cosmos/cosmos-sdk/codec" -) - -// RegisterCodec registers types declared in this package -func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterInterface((*Root)(nil), nil) - cdc.RegisterInterface((*Prefix)(nil), nil) - cdc.RegisterInterface((*Proof)(nil), nil) -} diff --git a/x/ibc/23-commitment/context.go b/x/ibc/23-commitment/context.go deleted file mode 100644 index af3f300ef9f2..000000000000 --- a/x/ibc/23-commitment/context.go +++ /dev/null @@ -1,18 +0,0 @@ -package ics23 - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// ContextKeyCommitmentKVStore is a singleton type used as the key for the commitment store -type ContextKeyCommitmentKVStore struct{} - -// WithStore returns the context updated with the store -func WithStore(ctx sdk.Context, store Store) sdk.Context { - return ctx.WithValue(ContextKeyCommitmentKVStore{}, store) -} - -// GetStore returns the store from the context -func GetStore(ctx sdk.Context) Store { - return ctx.Value(ContextKeyCommitmentKVStore{}).(Store) -} diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/exported/exported.go similarity index 66% rename from x/ibc/23-commitment/types.go rename to x/ibc/23-commitment/exported/exported.go index bba7711bb32f..c63af1b385f2 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/exported/exported.go @@ -1,4 +1,4 @@ -package ics23 +package exported // ICS 023 Types Implementation // @@ -7,27 +7,29 @@ package ics23 // spec:Path and spec:Value are defined as bytestring -// Root implements spec:CommitmentRoot. +// RootI implements spec:CommitmentRoot. // A root is constructed from a set of key-value pairs, // and the inclusion or non-inclusion of an arbitrary key-value pair // can be proven with the proof. -type Root interface { - CommitmentKind() string +type RootI interface { + CommitmentType() string + Bytes() []byte } -// Prefix implements spec:CommitmentPrefix. +// PrefixI implements spec:CommitmentPrefix. // Prefix is the additional information provided to the verification function. // Prefix represents the common "prefix" that a set of keys shares. -type Prefix interface { - CommitmentKind() string +type PrefixI interface { + CommitmentType() string } -// Proof implements spec:CommitmentProof. +// ProofI implements spec:CommitmentProof. // Proof can prove whether the key-value pair is a part of the Root or not. // Each proof has designated key-value pair it is able to prove. // Proofs includes key but value is provided dynamically at the verification time. -type Proof interface { - CommitmentKind() string +type ProofI interface { + CommitmentType() string GetKey() []byte - Verify(Root, Prefix, []byte) error + VerifyMembership(RootI, PrefixI, []byte) bool + VerifyAbsence(RootI, PrefixI) bool } diff --git a/x/ibc/23-commitment/keeper/keeper.go b/x/ibc/23-commitment/keeper/keeper.go new file mode 100644 index 000000000000..31fa76d5ee38 --- /dev/null +++ b/x/ibc/23-commitment/keeper/keeper.go @@ -0,0 +1,81 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +// Keeper defines the IBC commitment keeper (i.e the vector commitment manager). +// A vector commitment manager has the ability to add or remove items from the +// commitment state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments#definitions. +type Keeper struct { + prefix exported.PrefixI + proofs map[string]exported.ProofI + verified map[string][]byte +} + +// NewKeeper returns a prefixed store given base store and prefix. +func NewKeeper(prefix exported.PrefixI, proofs []exported.ProofI) Keeper { + return Keeper{ + prefix: prefix, + proofs: make(map[string]exported.ProofI), + verified: make(map[string][]byte), + } +} + +// GetRoot returns the application Hash at the curretn block height as a commitment +// root for proof verification. +func (k Keeper) GetRoot(ctx sdk.Context) exported.RootI { + return types.NewRoot(ctx.BlockHeader().AppHash) +} + +// // NewStore constructs a new Store with the root, path, and proofs. +// // The result store will be stored in the context and used by the +// // commitment.Value types. +// func NewStore(root RootI, prefix PrefixI, proofs []ProofI) (StoreI, error) { +// if root.CommitmentType() != prefix.CommitmentType() { +// return nil, errors.New("prefix type not matching with root's") +// } + +// res := &store{ +// root: root, +// prefix: prefix, +// proofs: make(map[string]ProofI), +// verified: make(map[string][]byte), +// } + +// for _, proof := range proofs { +// if proof.CommitmentType() != root.CommitmentType() { +// return nil, errors.New("proof type not matching with root's") +// } +// res.proofs[string(proof.GetKey())] = proof +// } + +// return res, nil +// } + +// // Prove implements spec:verifyMembership and spec:verifyNonMembership. +// // The path should be one of the path format defined under +// // https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements +// // Prove retrieves the matching proof with the provided path from the internal map +// // and call Verify method on it with internal Root and Prefix. +// // Prove acts as verifyMembership if value is not nil, and verifyNonMembership if nil. +// func (store *store) Prove(path, value []byte) bool { +// stored, ok := store.verified[string(path)] +// if ok && bytes.Equal(stored, value) { +// return true +// } +// proof, ok := store.proofs[string(path)] +// if !ok { +// return false +// } + +// err := proof.Verify(store.root, store.prefix, value) +// if err != nil { +// return false +// } +// store.verified[string(path)] = value + +// return true +// } diff --git a/x/ibc/23-commitment/merkle/merkle.go b/x/ibc/23-commitment/merkle/merkle.go deleted file mode 100644 index 798b41d840ad..000000000000 --- a/x/ibc/23-commitment/merkle/merkle.go +++ /dev/null @@ -1,112 +0,0 @@ -package merkle - -import ( - "errors" - - "github.com/tendermint/tendermint/crypto/merkle" - - "github.com/cosmos/cosmos-sdk/store/rootmulti" - - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -// ICS 023 Merkle Types Implementation -// -// This file defines Merkle commitment types that implements ICS 023. - -const merkleKind = "merkle" - -// merkle.Proof implementation of Proof -// Applied on SDK-based IBC implementation -var _ ics23.Root = Root{} - -// Root is Merkle root hash -// In Cosmos-SDK, the AppHash of the Header becomes Root. -type Root struct { - Hash []byte `json:"hash"` -} - -// NewRoot constructs a new Root -func NewRoot(hash []byte) Root { - return Root{ - Hash: hash, - } -} - -// Implements ics23.Root -func (Root) CommitmentKind() string { - return merkleKind -} - -var _ ics23.Prefix = Prefix{} - -// Prefix is merkle path prefixed to the key. -// The constructed key from the Path and the key will be append(Path.KeyPath, append(Path.KeyPrefix, key...)) -type Prefix struct { - // KeyPath is the list of keys prepended before the prefixed key - KeyPath [][]byte `json:"key_path"` - // KeyPrefix is a byte slice prefixed before the key - KeyPrefix []byte `json:"key_prefix"` -} - -// NewPrefix constructs new Prefix instance -func NewPrefix(keypath [][]byte, keyprefix []byte) Prefix { - return Prefix{ - KeyPath: keypath, - KeyPrefix: keyprefix, - } -} - -// Implements ics23.Prefix -func (Prefix) CommitmentKind() string { - return merkleKind -} - -func (prefix Prefix) Key(key []byte) []byte { - return ics23.Join(prefix.KeyPrefix, key) -} - -var _ ics23.Proof = Proof{} - -// Proof is Merkle proof with the key information. -type Proof struct { - Proof *merkle.Proof `json:"proof"` - Key []byte `json:"key"` -} - -// Implements ics23.Proof -func (Proof) CommitmentKind() string { - return merkleKind -} - -// Returns the key of the proof -func (proof Proof) GetKey() []byte { - return proof.Key -} - -// Verify proves the proof against the given root, path, and value. -func (proof Proof) Verify(croot ics23.Root, cpath ics23.Prefix, value []byte) error { - root, ok := croot.(Root) - if !ok { - return errors.New("invalid commitment root type") - } - - path, ok := cpath.(Prefix) - if !ok { - return errors.New("invalid commitment path type") - } - - keypath := merkle.KeyPath{} - for _, key := range path.KeyPath { - keypath = keypath.AppendKey(key, merkle.KeyEncodingHex) - } - keypath = keypath.AppendKey(append(path.KeyPrefix, proof.Key...), merkle.KeyEncodingHex) - - // TODO: hard coded for now, should be extensible - runtime := rootmulti.DefaultProofRuntime() - - if value != nil { - return runtime.VerifyValue(proof.Proof, root.Hash, keypath.String(), value) - } - return runtime.VerifyAbsence(proof.Proof, root.Hash, keypath.String()) -} diff --git a/x/ibc/23-commitment/merkle/merkle_test.go b/x/ibc/23-commitment/merkle/merkle_test.go deleted file mode 100644 index 0c73e7676ce8..000000000000 --- a/x/ibc/23-commitment/merkle/merkle_test.go +++ /dev/null @@ -1,134 +0,0 @@ -package merkle - -import ( - "crypto/rand" - "testing" - - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store" - "github.com/cosmos/cosmos-sdk/store/state" - "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -func defaultComponents() (sdk.StoreKey, sdk.Context, types.CommitMultiStore, *codec.Codec) { - key := sdk.NewKVStoreKey("test") - db := dbm.NewMemDB() - cms := store.NewCommitMultiStore(db) - cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) - err := cms.LoadLatestVersion() - if err != nil { - panic(err) - } - ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) - cdc := codec.New() - return key, ctx, cms, cdc -} - -func commit(cms types.CommitMultiStore) Root { - cid := cms.Commit() - return NewRoot(cid.Hash) -} - -// TestStore tests Merkle proof on the ics23.Store -// Sets/upates key-value pairs and prove with the query result proofs -func TestStore(t *testing.T) { - k, ctx, cms, cdc := defaultComponents() - storeName := k.Name() - prefix := []byte{0x01, 0x03, 0x05, 0xAA, 0xBB} - mapp := state.NewMapping(k, cdc, prefix) - path := NewPrefix([][]byte{[]byte(storeName)}, prefix) - - m := make(map[string][]byte) - kvpn := 10 - - // Repeat to test on multiple commits - for repeat := 0; repeat < 10; repeat++ { - - // Initializes random generated key-value pairs - for i := 0; i < kvpn; i++ { - k, v := make([]byte, 16), make([]byte, 16) - rand.Read(k) - rand.Read(v) - m[string(k)] = v - mapp.Value(k).Set(ctx, v) - } - - // Commit store - root := commit(cms) - - // Test query, and accumulate proofs - proofs := make([]ics23.Proof, 0, kvpn) - for k, v := range m { - q := state.NewStoreQuerier(cms.(types.Queryable)) - v0, p, err := mapp.Value([]byte(k)).QueryRaw(q) - require.NoError(t, err) - require.Equal(t, cdc.MustMarshalBinaryBare(v), v0, "Queried value different at %d", repeat) - proofs = append(proofs, Proof{Key: []byte(k), Proof: p}) - } - - // Add some exclusion proofs - for i := 0; i < 10; i++ { - k := make([]byte, 64) - rand.Read(k) - q := state.NewStoreQuerier(cms.(types.Queryable)) - v, p, err := mapp.Value([]byte(k)).QueryRaw(q) - require.NoError(t, err) - require.Nil(t, v) - proofs = append(proofs, Proof{Key: []byte(k), Proof: p}) - m[string(k)] = []byte{} - } - - cstore, err := ics23.NewStore(root, path, proofs) - require.NoError(t, err) - - // Test commitment store - for k, v := range m { - if len(v) != 0 { - require.True(t, cstore.Prove([]byte(k), cdc.MustMarshalBinaryBare(v))) - } else { - require.True(t, cstore.Prove([]byte(k), nil)) - } - } - - // Modify existing data - for k := range m { - v := make([]byte, 64) - rand.Read(v) - m[k] = v - mapp.Value([]byte(k)).Set(ctx, v) - } - - root = commit(cms) - - // Test query, and accumulate proofs - proofs = make([]ics23.Proof, 0, kvpn) - for k, v := range m { - q := state.NewStoreQuerier(cms.(types.Queryable)) - v0, p, err := mapp.Value([]byte(k)).QueryRaw(q) - require.NoError(t, err) - require.Equal(t, cdc.MustMarshalBinaryBare(v), v0) - proofs = append(proofs, Proof{Key: []byte(k), Proof: p}) - } - - cstore, err = ics23.NewStore(root, path, proofs) - require.NoError(t, err) - - // Test commitment store - for k, v := range m { - if len(v) != 0 { - require.True(t, cstore.Prove([]byte(k), cdc.MustMarshalBinaryBare(v))) - } else { - require.True(t, cstore.Prove([]byte(k), nil)) - } - } - } -} diff --git a/x/ibc/23-commitment/merkle/utils.go b/x/ibc/23-commitment/merkle/utils.go deleted file mode 100644 index a2813762b7b6..000000000000 --- a/x/ibc/23-commitment/merkle/utils.go +++ /dev/null @@ -1,34 +0,0 @@ -package merkle - -import ( - "errors" - - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/store/types" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -func QueryMultiStore(cms types.CommitMultiStore, storeName string, prefix []byte, key []byte) ([]byte, Proof, error) { - queryable, ok := cms.(types.Queryable) - if !ok { - panic("commitMultiStore not queryable") - } - qres := queryable.Query(RequestQueryMultiStore(storeName, prefix, key)) - if !qres.IsOK() { - return nil, Proof{}, errors.New(qres.Log) - } - - return qres.Value, Proof{Key: key, Proof: qres.Proof}, nil -} - -func RequestQueryMultiStore(storeName string, prefix []byte, key []byte) abci.RequestQuery { - // Suffixing path with "/key". - // iavl.Store.Query() switches over the last path element, - // and performs key-value query only if it is "/key" - return abci.RequestQuery{ - Path: "/" + storeName + "/key", - Data: ics23.Join(prefix, key), - Prove: true, - } -} diff --git a/x/ibc/23-commitment/store.go b/x/ibc/23-commitment/store.go deleted file mode 100644 index 941adaf230a0..000000000000 --- a/x/ibc/23-commitment/store.go +++ /dev/null @@ -1,105 +0,0 @@ -package ics23 - -import ( - "bytes" - "errors" -) - -// ICS 023 Function Implementation -// -// This file includes functions defined under -// https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments - -// Store partially implements spec:verifyMembership and spec:verifyNonMembership. -// Store holds Root, Prefix, and list of Proofs that will be verified. -// Proofs incldues their respective Paths. Values are provided at the verification time. -type Store interface { - Prove(path, value []byte) bool -} - -var _ Store = prefix{} - -type prefix struct { - store Store - prefix []byte -} - -// NewPrefix returns a prefixed store given base store and prefix. -// Prefix store for commitment proofs is used for similar path bytestring -// prefixing UX with local KVStore. -func NewPrefix(store Store, pref []byte) Store { - return &prefix{ - store: store, - prefix: pref, - } -} - -// Prove implements Store. -func (prefix prefix) Prove(path, value []byte) bool { - return prefix.store.Prove(Join(prefix.prefix, path), value) -} - -var _ Store = (*store)(nil) - -type store struct { - root Root - prefix Prefix - proofs map[string]Proof - verified map[string][]byte -} - -// NewStore constructs a new Store with the root, path, and proofs. -// The result store will be stored in the context and used by the -// commitment.Value types. -func NewStore(root Root, prefix Prefix, proofs []Proof) (Store, error) { - if root.CommitmentKind() != prefix.CommitmentKind() { - return nil, errors.New("prefix type not matching with root's") - } - - res := &store{ - root: root, - prefix: prefix, - proofs: make(map[string]Proof), - verified: make(map[string][]byte), - } - - for _, proof := range proofs { - if proof.CommitmentKind() != root.CommitmentKind() { - return nil, errors.New("proof type not matching with root's") - } - res.proofs[string(proof.GetKey())] = proof - } - - return res, nil -} - -// Prove implements spec:verifyMembership and spec:verifyNonMembership. -// The path should be one of the path format defined under -// https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements -// Prove retrieves the matching proof with the provided path from the internal map -// and call Verify method on it with internal Root and Prefix. -// Prove acts as verifyMembership if value is not nil, and verifyNonMembership if nil. -func (store *store) Prove(path, value []byte) bool { - stored, ok := store.verified[string(path)] - if ok && bytes.Equal(stored, value) { - return true - } - proof, ok := store.proofs[string(path)] - if !ok { - return false - } - err := proof.Verify(store.root, store.prefix, value) - if err != nil { - return false - } - store.verified[string(path)] = value - - return true -} - -func Join(a, b []byte) (res []byte) { - res = make([]byte, len(a)+len(b)) - copy(res, a) - copy(res[len(a):], b) - return -} diff --git a/x/ibc/23-commitment/merkle/codec.go b/x/ibc/23-commitment/types/codec.go similarity index 50% rename from x/ibc/23-commitment/merkle/codec.go rename to x/ibc/23-commitment/types/codec.go index bbb83afa87a4..b5a21331309d 100644 --- a/x/ibc/23-commitment/merkle/codec.go +++ b/x/ibc/23-commitment/types/codec.go @@ -1,10 +1,16 @@ -package merkle +package types import ( "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" ) +// RegisterCodec registers types declared in this package func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterInterface((*exported.RootI)(nil), nil) + cdc.RegisterInterface((*exported.PrefixI)(nil), nil) + cdc.RegisterInterface((*exported.ProofI)(nil), nil) + cdc.RegisterConcrete(Root{}, "ibc/commitment/merkle/Root", nil) cdc.RegisterConcrete(Prefix{}, "ibc/commitment/merkle/Prefix", nil) cdc.RegisterConcrete(Proof{}, "ibc/commitment/merkle/Proof", nil) diff --git a/x/ibc/23-commitment/types/merkle.go b/x/ibc/23-commitment/types/merkle.go new file mode 100644 index 000000000000..94b723e203e1 --- /dev/null +++ b/x/ibc/23-commitment/types/merkle.go @@ -0,0 +1,153 @@ +package types + +import ( + "github.com/tendermint/tendermint/crypto/merkle" + + "github.com/cosmos/cosmos-sdk/store/rootmulti" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" +) + +// ICS 023 Merkle Types Implementation +// +// This file defines Merkle commitment types that implements ICS 023. + +const merkleKind = "merkle" + +// merkle.Proof implementation of Proof +// Applied on SDK-based IBC implementation +var _ exported.RootI = Root{} + +// Root defines a merkle root hash. +// In the Cosmos SDK, the AppHash of a block header becomes the Root. +type Root struct { + Hash []byte `json:"hash" yaml:"hash"` +} + +// NewRoot constructs a new Root +func NewRoot(hash []byte) Root { + return Root{ + Hash: hash, + } +} + +// CommitmentType implements RootI interface +func (Root) CommitmentType() string { + return merkleKind +} + +// Bytes implements RootI interface +func (r Root) Bytes() []byte { + return r.Hash +} + +var _ exported.PrefixI = Prefix{} + +// TODO: applyPrefix() + +// Prefix is merkle path prefixed to the key. +// The constructed key from the Path and the key will be append(Path.KeyPath, append(Path.KeyPrefix, key...)) +type Prefix struct { + // KeyPath is the list of keys prepended before the prefixed key + KeyPath [][]byte `json:"key_path" yaml:"key_path"` + // KeyPrefix is a byte slice prefixed before the key + KeyPrefix []byte `json:"key_prefix" yaml:"key_prefix"` +} + +// NewPrefix constructs new Prefix instance +func NewPrefix(keypath [][]byte, keyprefix []byte) Prefix { + return Prefix{ + KeyPath: keypath, + KeyPrefix: keyprefix, + } +} + +// CommitmentType implements PrefixI +func (Prefix) CommitmentType() string { + return merkleKind +} + +// Key returns the full commitment prefix key +func (prefix Prefix) Key(key []byte) []byte { + return join(prefix.KeyPrefix, key) +} + +var _ exported.ProofI = Proof{} + +// Proof is a wrapper type that contains a merkle proof and the key used to verify . +// It demonstrates membership or non-membership for an element or set of elements, +// verifiable in conjunction with a known commitment root. Proofs should be +// succinct. +type Proof struct { + Proof *merkle.Proof `json:"proof" yaml:"proof"` + Key []byte `json:"key" yaml:"key"` +} + +// CommitmentType implements ProofI +func (Proof) CommitmentType() string { + return merkleKind +} + +// GetKey returns the key of the commitment proof +func (proof Proof) GetKey() []byte { + return proof.Key +} + +// GetRawProof returns the raw merkle proof +func (proof Proof) GetRawProof() *merkle.Proof { + return proof.Proof +} + +// VerifyMembership proves the proof against the given root, path, and value. +func (proof Proof) VerifyMembership(commitmentRoot exported.RootI, commitmentPrefix exported.PrefixI, value []byte) bool { + root, ok := commitmentRoot.(Root) + if !ok { + return false + } + + path, ok := commitmentPrefix.(Prefix) + if !ok { + return false + } + + keypath := merkle.KeyPath{} + for _, key := range path.KeyPath { + keypath = keypath.AppendKey(key, merkle.KeyEncodingHex) + } + keypath = keypath.AppendKey(append(path.KeyPrefix, proof.Key...), merkle.KeyEncodingHex) + + runtime := rootmulti.DefaultProofRuntime() + + err := runtime.VerifyValue(proof.Proof, root.Hash, keypath.String(), value) + if err != nil { + return false + } + + return true +} + +// VerifyAbsence verifies the absence of a proof against the given root, path. +func (proof Proof) VerifyAbsence(commitmentRoot exported.RootI, commitmentPrefix exported.PrefixI) bool { + root, ok := commitmentRoot.(Root) + if !ok { + return false + } + + path, ok := commitmentPrefix.(Prefix) + if !ok { + return false + } + + keypath := merkle.KeyPath{} + for _, key := range path.KeyPath { + keypath = keypath.AppendKey(key, merkle.KeyEncodingHex) + } + keypath = keypath.AppendKey(append(path.KeyPrefix, proof.Key...), merkle.KeyEncodingHex) + + runtime := rootmulti.DefaultProofRuntime() + + err := runtime.VerifyAbsence(proof.Proof, root.Hash, keypath.String()) + if err != nil { + return false + } + return true +} diff --git a/x/ibc/23-commitment/types/state.go b/x/ibc/23-commitment/types/state.go new file mode 100644 index 000000000000..8d0a4fb4abfd --- /dev/null +++ b/x/ibc/23-commitment/types/state.go @@ -0,0 +1,24 @@ +package types + +// State implements a commitment state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments#commitment-state. +// It represents full state of the commitment, which will be stored by the manager. +type State struct { + vectorCommitment map[string][]byte +} + +// NewState creates a new commitment State instance +func NewState(vectorCommitment map[string][]byte) State { + return State{ + vectorCommitment: vectorCommitment, + } +} + +// Set adds a mapping from a path -> value to the vector commitment. +func (s *State) Set(path string, commitment []byte) { + s.vectorCommitment[path] = commitment +} + +// Remove removes a commitment under a specific path. +func (s *State) Remove(path string) { + delete(s.vectorCommitment, path) +} diff --git a/x/ibc/23-commitment/types/utils.go b/x/ibc/23-commitment/types/utils.go new file mode 100644 index 000000000000..a53ca19812bd --- /dev/null +++ b/x/ibc/23-commitment/types/utils.go @@ -0,0 +1,8 @@ +package types + +func join(a, b []byte) (res []byte) { + res = make([]byte, len(a)+len(b)) + copy(res, a) + copy(res[len(a):], b) + return +} From a925d88056c8614469d36a56e4b81229e9558572 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 18 Oct 2019 17:06:08 +0200 Subject: [PATCH 305/378] cleanup types --- x/ibc/23-commitment/exported/exported.go | 16 ++- x/ibc/23-commitment/types/codec.go | 2 + x/ibc/23-commitment/types/merkle.go | 129 +++++++++++------------ x/ibc/23-commitment/types/state.go | 24 ----- 4 files changed, 76 insertions(+), 95 deletions(-) delete mode 100644 x/ibc/23-commitment/types/state.go diff --git a/x/ibc/23-commitment/exported/exported.go b/x/ibc/23-commitment/exported/exported.go index c63af1b385f2..77a78f89ee10 100644 --- a/x/ibc/23-commitment/exported/exported.go +++ b/x/ibc/23-commitment/exported/exported.go @@ -13,14 +13,21 @@ package exported // can be proven with the proof. type RootI interface { CommitmentType() string - Bytes() []byte + GetHash() []byte } // PrefixI implements spec:CommitmentPrefix. -// Prefix is the additional information provided to the verification function. // Prefix represents the common "prefix" that a set of keys shares. type PrefixI interface { CommitmentType() string + Bytes() []byte +} + +// PathI implements spec:CommitmentPath. +// A path is the additional information provided to the verification function. +type PathI interface { + CommitmentType() string + String() string } // ProofI implements spec:CommitmentProof. @@ -29,7 +36,6 @@ type PrefixI interface { // Proofs includes key but value is provided dynamically at the verification time. type ProofI interface { CommitmentType() string - GetKey() []byte - VerifyMembership(RootI, PrefixI, []byte) bool - VerifyAbsence(RootI, PrefixI) bool + VerifyMembership(RootI, PathI, []byte) bool + VerifyAbsence(RootI, PathI) bool } diff --git a/x/ibc/23-commitment/types/codec.go b/x/ibc/23-commitment/types/codec.go index b5a21331309d..c2b96c48ad3f 100644 --- a/x/ibc/23-commitment/types/codec.go +++ b/x/ibc/23-commitment/types/codec.go @@ -9,9 +9,11 @@ import ( func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*exported.RootI)(nil), nil) cdc.RegisterInterface((*exported.PrefixI)(nil), nil) + cdc.RegisterInterface((*exported.PathI)(nil), nil) cdc.RegisterInterface((*exported.ProofI)(nil), nil) cdc.RegisterConcrete(Root{}, "ibc/commitment/merkle/Root", nil) cdc.RegisterConcrete(Prefix{}, "ibc/commitment/merkle/Prefix", nil) + cdc.RegisterConcrete(Path{}, "ibc/commitment/merkle/Path", nil) cdc.RegisterConcrete(Proof{}, "ibc/commitment/merkle/Proof", nil) } diff --git a/x/ibc/23-commitment/types/merkle.go b/x/ibc/23-commitment/types/merkle.go index 94b723e203e1..7eadf8b2bdd6 100644 --- a/x/ibc/23-commitment/types/merkle.go +++ b/x/ibc/23-commitment/types/merkle.go @@ -1,6 +1,8 @@ package types import ( + "strings" + "github.com/tendermint/tendermint/crypto/merkle" "github.com/cosmos/cosmos-sdk/store/rootmulti" @@ -11,6 +13,7 @@ import ( // // This file defines Merkle commitment types that implements ICS 023. +// TODO: use iota const merkleKind = "merkle" // merkle.Proof implementation of Proof @@ -35,29 +38,23 @@ func (Root) CommitmentType() string { return merkleKind } -// Bytes implements RootI interface -func (r Root) Bytes() []byte { +// GetHash implements RootI interface +func (r Root) GetHash() []byte { return r.Hash } var _ exported.PrefixI = Prefix{} -// TODO: applyPrefix() - // Prefix is merkle path prefixed to the key. // The constructed key from the Path and the key will be append(Path.KeyPath, append(Path.KeyPrefix, key...)) type Prefix struct { - // KeyPath is the list of keys prepended before the prefixed key - KeyPath [][]byte `json:"key_path" yaml:"key_path"` - // KeyPrefix is a byte slice prefixed before the key - KeyPrefix []byte `json:"key_prefix" yaml:"key_prefix"` + KeyPrefix []byte `json:"key_prefix" yaml:"key_prefix"` // byte slice prefixed before the key } // NewPrefix constructs new Prefix instance -func NewPrefix(keypath [][]byte, keyprefix []byte) Prefix { +func NewPrefix(keyPrefix []byte) Prefix { return Prefix{ - KeyPath: keypath, - KeyPrefix: keyprefix, + KeyPrefix: keyPrefix, } } @@ -66,20 +63,63 @@ func (Prefix) CommitmentType() string { return merkleKind } -// Key returns the full commitment prefix key -func (prefix Prefix) Key(key []byte) []byte { - return join(prefix.KeyPrefix, key) +// Bytes returns the key prefix bytes +func (p Prefix) Bytes() []byte { + return p.KeyPrefix +} + +var _ exported.PathI = Path{} + +// Path is the path used to verify commitment proofs, which can be an arbitrary +// structured object (defined by a commitment type). +type Path struct { + KeyPath merkle.KeyPath `json:"key_path" yaml:"key_path"` // byte slice prefixed before the key +} + +// NewPath creates a new CommitmentPath instance +func NewPath(keyPathStr []string) Path { + merkleKeyPath := merkle.KeyPath{} + for _, keyStr := range keyPathStr { + merkleKeyPath = merkleKeyPath.AppendKey([]byte(keyStr), merkle.KeyEncodingHex) + } + + return Path{ + KeyPath: merkleKeyPath, + } +} + +// CommitmentType implements PathI +func (Path) CommitmentType() string { + return merkleKind +} + +// String implements fmt.Stringer +func (p Path) String() string { + return p.KeyPath.String() +} + +// ApplyPrefix constructs a new commitment path from the arguments. It interprets +// the path argument in the context of the prefix argument. +// +// CONTRACT: provided path string MUST be a well formated path. See ICS24 for +// reference. +func ApplyPrefix(prefix exported.PrefixI, path string) Path { + // Split paths by the separator + pathSlice := strings.Split(path, "/") + commitmentPath := NewPath(pathSlice) + + commitmentPath.KeyPath = commitmentPath.KeyPath.AppendKey(prefix.Bytes(), merkle.KeyEncodingHex) + return commitmentPath } var _ exported.ProofI = Proof{} -// Proof is a wrapper type that contains a merkle proof and the key used to verify . +// Proof is a wrapper type that contains a merkle proof. // It demonstrates membership or non-membership for an element or set of elements, // verifiable in conjunction with a known commitment root. Proofs should be // succinct. type Proof struct { Proof *merkle.Proof `json:"proof" yaml:"proof"` - Key []byte `json:"key" yaml:"key"` } // CommitmentType implements ProofI @@ -87,37 +127,10 @@ func (Proof) CommitmentType() string { return merkleKind } -// GetKey returns the key of the commitment proof -func (proof Proof) GetKey() []byte { - return proof.Key -} - -// GetRawProof returns the raw merkle proof -func (proof Proof) GetRawProof() *merkle.Proof { - return proof.Proof -} - -// VerifyMembership proves the proof against the given root, path, and value. -func (proof Proof) VerifyMembership(commitmentRoot exported.RootI, commitmentPrefix exported.PrefixI, value []byte) bool { - root, ok := commitmentRoot.(Root) - if !ok { - return false - } - - path, ok := commitmentPrefix.(Prefix) - if !ok { - return false - } - - keypath := merkle.KeyPath{} - for _, key := range path.KeyPath { - keypath = keypath.AppendKey(key, merkle.KeyEncodingHex) - } - keypath = keypath.AppendKey(append(path.KeyPrefix, proof.Key...), merkle.KeyEncodingHex) - +// VerifyMembership verifies the membership pf a merkle proof against the given root, path, and value. +func (proof Proof) VerifyMembership(root exported.RootI, path exported.PathI, value []byte) bool { runtime := rootmulti.DefaultProofRuntime() - - err := runtime.VerifyValue(proof.Proof, root.Hash, keypath.String(), value) + err := runtime.VerifyValue(proof.Proof, root.GetHash(), path.String(), value) if err != nil { return false } @@ -125,29 +138,13 @@ func (proof Proof) VerifyMembership(commitmentRoot exported.RootI, commitmentPre return true } -// VerifyAbsence verifies the absence of a proof against the given root, path. -func (proof Proof) VerifyAbsence(commitmentRoot exported.RootI, commitmentPrefix exported.PrefixI) bool { - root, ok := commitmentRoot.(Root) - if !ok { - return false - } - - path, ok := commitmentPrefix.(Prefix) - if !ok { - return false - } - - keypath := merkle.KeyPath{} - for _, key := range path.KeyPath { - keypath = keypath.AppendKey(key, merkle.KeyEncodingHex) - } - keypath = keypath.AppendKey(append(path.KeyPrefix, proof.Key...), merkle.KeyEncodingHex) - +// VerifyAbsence verifies the absence of a merkle proof against the given root and path. +func (proof Proof) VerifyAbsence(root exported.RootI, path exported.PathI) bool { runtime := rootmulti.DefaultProofRuntime() - - err := runtime.VerifyAbsence(proof.Proof, root.Hash, keypath.String()) + err := runtime.VerifyAbsence(proof.Proof, root.GetHash(), path.String()) if err != nil { return false } + return true } diff --git a/x/ibc/23-commitment/types/state.go b/x/ibc/23-commitment/types/state.go deleted file mode 100644 index 8d0a4fb4abfd..000000000000 --- a/x/ibc/23-commitment/types/state.go +++ /dev/null @@ -1,24 +0,0 @@ -package types - -// State implements a commitment state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments#commitment-state. -// It represents full state of the commitment, which will be stored by the manager. -type State struct { - vectorCommitment map[string][]byte -} - -// NewState creates a new commitment State instance -func NewState(vectorCommitment map[string][]byte) State { - return State{ - vectorCommitment: vectorCommitment, - } -} - -// Set adds a mapping from a path -> value to the vector commitment. -func (s *State) Set(path string, commitment []byte) { - s.vectorCommitment[path] = commitment -} - -// Remove removes a commitment under a specific path. -func (s *State) Remove(path string) { - delete(s.vectorCommitment, path) -} From c3b6b181700dc46c95770cb2749b291766032a14 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 21 Oct 2019 12:36:31 +0200 Subject: [PATCH 306/378] ICS 5 updates (#5222) * Validate port identifiers * Refactor to static bind * Add comments * Add 'GetPorts' query function --- x/ibc/03-connection/keeper/querier.go | 2 +- x/ibc/05-port/keeper/keeper.go | 108 +++++++------------------- x/ibc/05-port/types/port.go | 3 + 3 files changed, 33 insertions(+), 80 deletions(-) diff --git a/x/ibc/03-connection/keeper/querier.go b/x/ibc/03-connection/keeper/querier.go index 90ced33fcc24..bf47cd9d2932 100644 --- a/x/ibc/03-connection/keeper/querier.go +++ b/x/ibc/03-connection/keeper/querier.go @@ -6,7 +6,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/03-commitment/types" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" ) // NewQuerier creates a querier for the IBC client diff --git a/x/ibc/05-port/keeper/keeper.go b/x/ibc/05-port/keeper/keeper.go index 858b15f14b4d..b72ecd3f6ede 100644 --- a/x/ibc/05-port/keeper/keeper.go +++ b/x/ibc/05-port/keeper/keeper.go @@ -4,9 +4,7 @@ import ( "fmt" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/05-port/exported" "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" ) @@ -16,6 +14,8 @@ type Keeper struct { cdc *codec.Codec codespace sdk.CodespaceType prefix []byte // prefix bytes for accessing the store + ports map[sdk.CapabilityKey]string + bound []string } // NewKeeper creates a new IBC connection Keeper instance @@ -25,95 +25,45 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) cdc: cdc, codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/port", prefix: []byte(types.SubModuleName + "/"), // "port/" + ports: make(map[sdk.CapabilityKey]string), // map of capabilities to port ids } } -// GetPort returns a port with a particular identifier -func (k Keeper) GetPort(ctx sdk.Context, portID string) (sdk.CapabilityKey, bool) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) - bz := store.Get(types.KeyPort(portID)) - if bz == nil { - return nil, false - } - - var capabilityKey sdk.CapabilityKey - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &capabilityKey) - return capabilityKey, true -} - -// SetPort sets a port to the store -func (k Keeper) SetPort(ctx sdk.Context, portID string, capabilityKey sdk.CapabilityKey) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) - bz := k.cdc.MustMarshalBinaryLengthPrefixed(capabilityKey) - store.Set(types.KeyPort(portID), bz) +// GetPorts returns the list of bound ports. +// (these ports still must have been bound statically) +func (k Keeper) GetPorts() []string { + return k.bound } -// delete a port ID key from the store -func (k Keeper) deletePort(ctx sdk.Context, portID string) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) - store.Delete(types.KeyPort(portID)) -} - -// BindPort binds to an unallocated port, failing if the port has already been -// allocated. -func (k Keeper) BindPort(ctx sdk.Context, portID string, generateFn exported.Generate) sdk.Error { +// BindPort binds to a port and returns the associated capability. +// Ports must be bound statically when the chain starts in `app.go`. +// The capability must then be passed to a module which will need to pass +// it as an extra parameter when calling functions on the IBC module. +func (k Keeper) BindPort(portID string) sdk.CapabilityKey { if !types.ValidatePortID(portID) { - return types.ErrInvalidPortID(k.codespace) - } - - _, found := k.GetPort(ctx, portID) - if found { - return types.ErrPortExists(k.codespace, portID) - } - key := generateFn() - k.SetPort(ctx, portID, key) - return nil -} - -// TransferPort allows an existing port (i.e capability key) to be transfered -// to another module and thus stored under another path. -// -// NOTE: not neccessary if the host state machine supports object-capabilities, -// since the port reference is a bearer capability. -func (k Keeper) TransferPort( - ctx sdk.Context, - portID string, - authenticateFn exported.Authenticate, - generateFn exported.Generate, -) sdk.Error { - port, found := k.GetPort(ctx, portID) - if !found { - return types.ErrPortNotFound(k.codespace, portID) + panic(fmt.Sprintf("invalid port id: %s", types.ErrInvalidPortID(k.codespace))) } - if !authenticateFn(port) { - return types.ErrPortNotAuthenticated(k.codespace) + for _, b := range k.bound { + if b == portID { + panic(fmt.Sprintf("port %s is already bound", portID)) + } } - key := generateFn() - k.SetPort(ctx, portID, key) - return nil + key := sdk.NewKVStoreKey(portID) + k.ports[key] = portID + k.bound = append(k.bound, portID) + return key } -// ReleasePort allows a module to release a port such that other modules may -// then bind to it. -// -// WARNING: releasing a port will allow other modules to bind to that port and -// possibly intercept incoming channel opening handshakes. Modules should release -// ports only when doing so is safe. -func (k Keeper) ReleasePort( - ctx sdk.Context, - portID string, - authenticateFn exported.Authenticate) sdk.Error { - port, found := k.GetPort(ctx, portID) - if !found { - return types.ErrPortNotFound(k.codespace, portID) - } - - if !authenticateFn(port) { - return types.ErrPortNotAuthenticated(k.codespace) +// Authenticate authenticates a capability key against a port ID +// by checking if the memory address of the capability was previously +// generated and bound to the port (provided as a parameter) which the capability +// is being authenticated against. +func (k Keeper) Authenticate(key sdk.CapabilityKey, portID string) bool { + if !types.ValidatePortID(portID) { + panic(fmt.Sprintf("invalid port id: %s", types.ErrInvalidPortID(k.codespace))) } - k.deletePort(ctx, portID) - return nil + return k.ports[key] == portID } diff --git a/x/ibc/05-port/types/port.go b/x/ibc/05-port/types/port.go index b651b8539a51..d2cd60806f18 100644 --- a/x/ibc/05-port/types/port.go +++ b/x/ibc/05-port/types/port.go @@ -10,5 +10,8 @@ func ValidatePortID(portID string) bool { if strings.TrimSpace(portID) == "" { return false } + if len(portID) < 3 || len(portID) > 10 { + return false + } return true } From 74d8a4b878912bc431f61dfdf6759b6c1745623b Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 21 Oct 2019 16:13:24 +0200 Subject: [PATCH 307/378] rename pkg and fix import --- x/ibc/03-connection/keeper/handshake.go | 14 +++--- x/ibc/03-connection/keeper/keeper.go | 8 ++-- x/ibc/03-connection/keeper/querier.go | 2 +- x/ibc/03-connection/types/connection.go | 10 ++-- x/ibc/03-connection/types/expected_keepers.go | 20 ++++---- x/ibc/03-connection/types/msgs.go | 48 +++++++++---------- x/ibc/03-connection/types/querier.go | 18 +++---- 7 files changed, 60 insertions(+), 60 deletions(-) diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index 8dc0760ad1a2..bba6a0819633 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -6,9 +6,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - ics02types "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // ConnOpenInit initialises a connection attempt on chain A. @@ -50,7 +50,7 @@ func (k Keeper) ConnOpenTry( counterparty types.Counterparty, // counterpartyConnectionIdentifier, counterpartyPrefix and counterpartyClientIdentifier clientID string, counterpartyVersions []string, - proofInit ics23.Proof, + proofInit commitment.Proof, proofHeight uint64, consensusHeight uint64, ) error { @@ -95,7 +95,7 @@ func (k Keeper) ConnOpenTry( ok = k.VerifyMembership( ctx, connection, proofHeight, proofInit, - ics02types.ConsensusStatePath(counterparty.ClientID), expConsStateBz, + clienttypes.ConsensusStatePath(counterparty.ClientID), expConsStateBz, ) if !ok { return errors.New("couldn't verify consensus state membership on counterparty's client") // TODO: sdk.Error @@ -125,7 +125,7 @@ func (k Keeper) ConnOpenAck( ctx sdk.Context, connectionID string, version string, - proofTry ics23.Proof, + proofTry commitment.Proof, proofHeight uint64, consensusHeight uint64, ) error { @@ -181,7 +181,7 @@ func (k Keeper) ConnOpenAck( ok = k.VerifyMembership( ctx, connection, proofHeight, proofTry, - ics02types.ConsensusStatePath(connection.Counterparty.ClientID), expConsStateBz, + clienttypes.ConsensusStatePath(connection.Counterparty.ClientID), expConsStateBz, ) if !ok { return errors.New("couldn't verify consensus state membership on counterparty's client") // TODO: sdk.Error @@ -201,7 +201,7 @@ func (k Keeper) ConnOpenAck( func (k Keeper) ConnOpenConfirm( ctx sdk.Context, connectionID string, - proofAck ics23.Proof, + proofAck commitment.Proof, proofHeight uint64, ) error { connection, found := k.GetConnection(ctx, connectionID) diff --git a/x/ibc/03-connection/keeper/keeper.go b/x/ibc/03-connection/keeper/keeper.go index 07d8563a615b..9ee79f461a17 100644 --- a/x/ibc/03-connection/keeper/keeper.go +++ b/x/ibc/03-connection/keeper/keeper.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -119,7 +119,7 @@ func (k Keeper) VerifyMembership( ctx sdk.Context, connection types.ConnectionEnd, height uint64, - proof ics23.Proof, + proof commitment.Proof, path string, value []byte, ) bool { @@ -136,7 +136,7 @@ func (k Keeper) VerifyNonMembership( ctx sdk.Context, connection types.ConnectionEnd, height uint64, - proof ics23.Proof, + proof commitment.Proof, path string, ) bool { clientState, found := k.clientKeeper.GetClientState(ctx, connection.ClientID) @@ -148,7 +148,7 @@ func (k Keeper) VerifyNonMembership( return k.clientKeeper.VerifyNonMembership(ctx, clientState, height, proof, path) } -func (k Keeper) applyPrefix(prefix ics23.Prefix, path string) string { +func (k Keeper) applyPrefix(prefix commitment.Prefix, path string) string { // TODO: return path } diff --git a/x/ibc/03-connection/keeper/querier.go b/x/ibc/03-connection/keeper/querier.go index 90ced33fcc24..bf47cd9d2932 100644 --- a/x/ibc/03-connection/keeper/querier.go +++ b/x/ibc/03-connection/keeper/querier.go @@ -6,7 +6,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/03-commitment/types" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" ) // NewQuerier creates a querier for the IBC client diff --git a/x/ibc/03-connection/types/connection.go b/x/ibc/03-connection/types/connection.go index 25ad7ef8f4dc..155a1fc44a72 100644 --- a/x/ibc/03-connection/types/connection.go +++ b/x/ibc/03-connection/types/connection.go @@ -1,7 +1,7 @@ package types import ( - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // ICS03 - Connection Data Structures as defined in https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#data-structures @@ -35,13 +35,13 @@ func NewConnectionEnd(state ConnectionState, clientID string, counterparty Count // Counterparty defines the counterparty chain associated with a connection end. type Counterparty struct { - ClientID string `json:"client_id" yaml:"client_id"` - ConnectionID string `json:"connection_id" yaml:"connection_id"` - Prefix ics23.Prefix `json:"prefix" yaml:"prefix` + ClientID string `json:"client_id" yaml:"client_id"` + ConnectionID string `json:"connection_id" yaml:"connection_id"` + Prefix commitment.Prefix `json:"prefix" yaml:"prefix` } // NewCounterparty creates a new Counterparty instance. -func NewCounterparty(clientID, connectionID string, prefix ics23.Prefix) Counterparty { +func NewCounterparty(clientID, connectionID string, prefix commitment.Prefix) Counterparty { return Counterparty{ ClientID: clientID, ConnectionID: connectionID, diff --git a/x/ibc/03-connection/types/expected_keepers.go b/x/ibc/03-connection/types/expected_keepers.go index 5fa30c6c4f40..8301ca89a917 100644 --- a/x/ibc/03-connection/types/expected_keepers.go +++ b/x/ibc/03-connection/types/expected_keepers.go @@ -2,22 +2,22 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" - ics02exported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - ics02types "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // ClientKeeper expected account IBC client keeper type ClientKeeper interface { - GetCommitmentPath() ics23.Prefix - GetConsensusState(ctx sdk.Context, clientID string) (ics02exported.ConsensusState, bool) - GetClientState(ctx sdk.Context, clientID string) (ics02types.ClientState, bool) + GetCommitmentPath() commitment.Prefix + GetConsensusState(ctx sdk.Context, clientID string) (clientexported.ConsensusState, bool) + GetClientState(ctx sdk.Context, clientID string) (clienttypes.ClientState, bool) VerifyMembership( - ctx sdk.Context, clientState ics02types.ClientState, height uint64, - proof ics23.Proof, path string, value []byte, + ctx sdk.Context, clientState clienttypes.ClientState, height uint64, + proof commitment.Proof, path string, value []byte, ) bool VerifyNonMembership( - ctx sdk.Context, clientState ics02types.ClientState, height uint64, - proof ics23.Proof, path string, + ctx sdk.Context, clientState clienttypes.ClientState, height uint64, + proof commitment.Proof, path string, ) bool } diff --git a/x/ibc/03-connection/types/msgs.go b/x/ibc/03-connection/types/msgs.go index c72825b04e4c..960161a676e2 100644 --- a/x/ibc/03-connection/types/msgs.go +++ b/x/ibc/03-connection/types/msgs.go @@ -4,7 +4,7 @@ import ( "strings" sdk "github.com/cosmos/cosmos-sdk/types" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -22,7 +22,7 @@ type MsgConnectionOpenInit struct { // NewMsgConnectionOpenInit creates a new MsgConnectionOpenInit instance func NewMsgConnectionOpenInit( connectionID, clientID, counterpartyConnectionID, - counterpartyClientID string, counterpartyPrefix ics23.Prefix, + counterpartyClientID string, counterpartyPrefix commitment.Prefix, signer sdk.AccAddress, ) MsgConnectionOpenInit { counterparty := NewCounterparty(counterpartyClientID, counterpartyConnectionID, counterpartyPrefix) @@ -68,21 +68,21 @@ var _ sdk.Msg = MsgConnectionOpenTry{} // MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a connection // on Chain B. type MsgConnectionOpenTry struct { - ConnectionID string `json:"connection_id"` - ClientID string `json:"client_id"` - Counterparty Counterparty `json:"counterparty"` - CounterpartyVersions []string `json:"counterparty_versions"` - ProofInit ics23.Proof `json:"proof_init"` // proof of the initialization the connection on Chain A: `none -> INIT` - ProofHeight uint64 `json:"proof_height"` - ConsensusHeight uint64 `json:"consensus_height"` - Signer sdk.AccAddress `json:"signer"` + ConnectionID string `json:"connection_id"` + ClientID string `json:"client_id"` + Counterparty Counterparty `json:"counterparty"` + CounterpartyVersions []string `json:"counterparty_versions"` + ProofInit commitment.Proof `json:"proof_init"` // proof of the initialization the connection on Chain A: `none -> INIT` + ProofHeight uint64 `json:"proof_height"` + ConsensusHeight uint64 `json:"consensus_height"` + Signer sdk.AccAddress `json:"signer"` } // NewMsgConnectionOpenTry creates a new MsgConnectionOpenTry instance func NewMsgConnectionOpenTry( connectionID, clientID, counterpartyConnectionID, - counterpartyClientID string, counterpartyPrefix ics23.Prefix, - counterpartyVersions []string, proofInit ics23.Proof, + counterpartyClientID string, counterpartyPrefix commitment.Prefix, + counterpartyVersions []string, proofInit commitment.Proof, proofHeight, consensusHeight uint64, signer sdk.AccAddress, ) MsgConnectionOpenTry { counterparty := NewCounterparty(counterpartyClientID, counterpartyConnectionID, counterpartyPrefix) @@ -150,17 +150,17 @@ var _ sdk.Msg = MsgConnectionOpenAck{} // MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to acknowledge // the change of connection state to TRYOPEN on Chain B. type MsgConnectionOpenAck struct { - ConnectionID string `json:"connection_id"` - ProofTry ics23.Proof `json:"proof_try"` // proof for the change of the connection state on Chain B: `none -> TRYOPEN` - ProofHeight uint64 `json:"proof_height"` - ConsensusHeight uint64 `json:"consensus_height"` - Version string `json:"version"` - Signer sdk.AccAddress `json:"signer"` + ConnectionID string `json:"connection_id"` + ProofTry commitment.Proof `json:"proof_try"` // proof for the change of the connection state on Chain B: `none -> TRYOPEN` + ProofHeight uint64 `json:"proof_height"` + ConsensusHeight uint64 `json:"consensus_height"` + Version string `json:"version"` + Signer sdk.AccAddress `json:"signer"` } // NewMsgConnectionOpenAck creates a new MsgConnectionOpenAck instance func NewMsgConnectionOpenAck( - connectionID string, proofTry ics23.Proof, + connectionID string, proofTry commitment.Proof, proofHeight, consensusHeight uint64, version string, signer sdk.AccAddress, ) MsgConnectionOpenAck { @@ -219,15 +219,15 @@ var _ sdk.Msg = MsgConnectionOpenConfirm{} // MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to acknowledge // the change of connection state to OPEN on Chain A. type MsgConnectionOpenConfirm struct { - ConnectionID string `json:"connection_id"` - ProofAck ics23.Proof `json:"proof_ack"` // proof for the change of the connection state on Chain A: `INIT -> OPEN` - ProofHeight uint64 `json:"proof_height"` - Signer sdk.AccAddress `json:"signer"` + ConnectionID string `json:"connection_id"` + ProofAck commitment.Proof `json:"proof_ack"` // proof for the change of the connection state on Chain A: `INIT -> OPEN` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` } // NewMsgConnectionOpenConfirm creates a new MsgConnectionOpenConfirm instance func NewMsgConnectionOpenConfirm( - connectionID string, proofAck ics23.Proof, proofHeight uint64, signer sdk.AccAddress, + connectionID string, proofAck commitment.Proof, proofHeight uint64, signer sdk.AccAddress, ) MsgConnectionOpenConfirm { return MsgConnectionOpenConfirm{ ConnectionID: connectionID, diff --git a/x/ibc/03-connection/types/querier.go b/x/ibc/03-connection/types/querier.go index 1360277ea051..e0e5e1fc0ff8 100644 --- a/x/ibc/03-connection/types/querier.go +++ b/x/ibc/03-connection/types/querier.go @@ -1,7 +1,7 @@ package types import ( - ics23merkle "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" + commitmentmerkle "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" "github.com/tendermint/tendermint/crypto/merkle" ) @@ -14,9 +14,9 @@ const ( // ConnectionResponse defines the client query response for a connection which // also includes a proof and the height from which the proof was retrieved. type ConnectionResponse struct { - Connection ConnectionEnd `json:"connection" yaml:"connection"` - Proof ics23merkle.Proof `json:"proof,omitempty" yaml:"proof,omitempty"` - ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` + Connection ConnectionEnd `json:"connection" yaml:"connection"` + Proof commitmentmerkle.Proof `json:"proof,omitempty" yaml:"proof,omitempty"` + ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` } // NewConnectionResponse creates a new ConnectionResponse instance @@ -25,7 +25,7 @@ func NewConnectionResponse( ) ConnectionResponse { return ConnectionResponse{ Connection: connection, - Proof: ics23merkle.NewProof(proof, KeyConnection(connectionID)), + Proof: commitmentmerkle.NewProof(proof, KeyConnection(connectionID)), ProofHeight: uint64(height), } } @@ -47,9 +47,9 @@ func NewQueryConnectionParams(clientID string) QueryConnectionParams { // connection paths which also includes a proof and the height from which the // proof was retrieved. type ClientConnectionsResponse struct { - ConnectionPaths []string `json:"connection_paths" yaml:"connection_paths"` - Proof ics23merkle.Proof `json:"proof,omitempty" yaml:"proof,omitempty"` - ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` + ConnectionPaths []string `json:"connection_paths" yaml:"connection_paths"` + Proof commitmentmerkle.Proof `json:"proof,omitempty" yaml:"proof,omitempty"` + ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` } // NewClientConnectionsResponse creates a new ConnectionPaths instance @@ -58,7 +58,7 @@ func NewClientConnectionsResponse( ) ClientConnectionsResponse { return ClientConnectionsResponse{ ConnectionPaths: connectionPaths, - Proof: ics23merkle.NewProof(proof, KeyClientConnections(clientID)), + Proof: commitmentmerkle.NewProof(proof, KeyClientConnections(clientID)), ProofHeight: uint64(height), } } From c12c2980c57a9914360d6d8451b136e13a1de685 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 21 Oct 2019 17:40:22 +0200 Subject: [PATCH 308/378] implement batch verification --- x/ibc/23-commitment/exported/exported.go | 2 +- x/ibc/23-commitment/keeper/keeper.go | 107 ++++++++++++----------- x/ibc/23-commitment/types/merkle.go | 4 +- 3 files changed, 57 insertions(+), 56 deletions(-) diff --git a/x/ibc/23-commitment/exported/exported.go b/x/ibc/23-commitment/exported/exported.go index 77a78f89ee10..9e0d8d0ef776 100644 --- a/x/ibc/23-commitment/exported/exported.go +++ b/x/ibc/23-commitment/exported/exported.go @@ -37,5 +37,5 @@ type PathI interface { type ProofI interface { CommitmentType() string VerifyMembership(RootI, PathI, []byte) bool - VerifyAbsence(RootI, PathI) bool + VerifyNonMembership(RootI, PathI) bool } diff --git a/x/ibc/23-commitment/keeper/keeper.go b/x/ibc/23-commitment/keeper/keeper.go index 31fa76d5ee38..62790e6b83cb 100644 --- a/x/ibc/23-commitment/keeper/keeper.go +++ b/x/ibc/23-commitment/keeper/keeper.go @@ -1,6 +1,8 @@ package keeper import ( + "bytes" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" @@ -10,72 +12,71 @@ import ( // A vector commitment manager has the ability to add or remove items from the // commitment state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments#definitions. type Keeper struct { - prefix exported.PrefixI - proofs map[string]exported.ProofI - verified map[string][]byte + prefix exported.PrefixI + verifiedMemberships map[string][]byte // lookup map for returning already verified membership proofs + verifiedAbsences map[string]bool // lookup map for returning already verified absences } -// NewKeeper returns a prefixed store given base store and prefix. -func NewKeeper(prefix exported.PrefixI, proofs []exported.ProofI) Keeper { +// NewKeeper returns a new Keeper +func NewKeeper(prefix exported.PrefixI) Keeper { return Keeper{ - prefix: prefix, - proofs: make(map[string]exported.ProofI), - verified: make(map[string][]byte), + prefix: prefix, + verifiedMemberships: make(map[string][]byte), + verifiedAbsences: make(map[string]bool), } } -// GetRoot returns the application Hash at the curretn block height as a commitment +// CalculateRoot returns the application Hash at the curretn block height as a commitment // root for proof verification. -func (k Keeper) GetRoot(ctx sdk.Context) exported.RootI { +func (k Keeper) CalculateRoot(ctx sdk.Context) exported.RootI { return types.NewRoot(ctx.BlockHeader().AppHash) } -// // NewStore constructs a new Store with the root, path, and proofs. -// // The result store will be stored in the context and used by the -// // commitment.Value types. -// func NewStore(root RootI, prefix PrefixI, proofs []ProofI) (StoreI, error) { -// if root.CommitmentType() != prefix.CommitmentType() { -// return nil, errors.New("prefix type not matching with root's") -// } +// BatchVerifyMembership verifies a proof that many paths have been set to +// specific values in a commitment. It calls the proof's VerifyMembership method +// with the calculated root and the provided paths. +// Returns false on the first failed membership verification. +func (k Keeper) BatchVerifyMembership(ctx sdk.Context, proof exported.ProofI, items map[string][]byte) bool { + root := k.CalculateRoot(ctx) + + for pathStr, value := range items { + storedValue, ok := k.verifiedMemberships[pathStr] + if ok && bytes.Equal(storedValue, value) { + continue + } -// res := &store{ -// root: root, -// prefix: prefix, -// proofs: make(map[string]ProofI), -// verified: make(map[string][]byte), -// } + path := types.ApplyPrefix(k.prefix, pathStr) + ok = proof.VerifyMembership(root, path, value) + if !ok { + return false + } -// for _, proof := range proofs { -// if proof.CommitmentType() != root.CommitmentType() { -// return nil, errors.New("proof type not matching with root's") -// } -// res.proofs[string(proof.GetKey())] = proof -// } + k.verifiedMemberships[pathStr] = value + } -// return res, nil -// } + return true +} -// // Prove implements spec:verifyMembership and spec:verifyNonMembership. -// // The path should be one of the path format defined under -// // https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements -// // Prove retrieves the matching proof with the provided path from the internal map -// // and call Verify method on it with internal Root and Prefix. -// // Prove acts as verifyMembership if value is not nil, and verifyNonMembership if nil. -// func (store *store) Prove(path, value []byte) bool { -// stored, ok := store.verified[string(path)] -// if ok && bytes.Equal(stored, value) { -// return true -// } -// proof, ok := store.proofs[string(path)] -// if !ok { -// return false -// } +// BatchVerifyNonMembership verifies a proof that many paths have not been set +// to any value in a commitment. It calls the proof's VerifyNonMembership method +// with the calculated root and the provided paths. +// Returns false on the first failed non-membership verification. +func (k Keeper) BatchVerifyNonMembership(ctx sdk.Context, proof exported.ProofI, paths []string) bool { + root := k.CalculateRoot(ctx) + for _, pathStr := range paths { + ok := k.verifiedAbsences[pathStr] + if ok { + continue + } -// err := proof.Verify(store.root, store.prefix, value) -// if err != nil { -// return false -// } -// store.verified[string(path)] = value + path := types.ApplyPrefix(k.prefix, pathStr) + ok = proof.VerifyNonMembership(root, path) + if !ok { + return false + } -// return true -// } + k.verifiedAbsences[pathStr] = true + } + + return true +} diff --git a/x/ibc/23-commitment/types/merkle.go b/x/ibc/23-commitment/types/merkle.go index 7eadf8b2bdd6..0a89c58e682b 100644 --- a/x/ibc/23-commitment/types/merkle.go +++ b/x/ibc/23-commitment/types/merkle.go @@ -138,8 +138,8 @@ func (proof Proof) VerifyMembership(root exported.RootI, path exported.PathI, va return true } -// VerifyAbsence verifies the absence of a merkle proof against the given root and path. -func (proof Proof) VerifyAbsence(root exported.RootI, path exported.PathI) bool { +// VerifyNonMembership verifies the absence of a merkle proof against the given root and path. +func (proof Proof) VerifyNonMembership(root exported.RootI, path exported.PathI) bool { runtime := rootmulti.DefaultProofRuntime() err := runtime.VerifyAbsence(proof.Proof, root.GetHash(), path.String()) if err != nil { From a34b7411549b185866766f0acdfd5915b6c873f2 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 21 Oct 2019 17:56:15 +0200 Subject: [PATCH 309/378] gosimple suggestion --- x/ibc/23-commitment/types/merkle.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/x/ibc/23-commitment/types/merkle.go b/x/ibc/23-commitment/types/merkle.go index 0a89c58e682b..0a61a997213b 100644 --- a/x/ibc/23-commitment/types/merkle.go +++ b/x/ibc/23-commitment/types/merkle.go @@ -131,20 +131,12 @@ func (Proof) CommitmentType() string { func (proof Proof) VerifyMembership(root exported.RootI, path exported.PathI, value []byte) bool { runtime := rootmulti.DefaultProofRuntime() err := runtime.VerifyValue(proof.Proof, root.GetHash(), path.String(), value) - if err != nil { - return false - } - - return true + return err == nil } // VerifyNonMembership verifies the absence of a merkle proof against the given root and path. func (proof Proof) VerifyNonMembership(root exported.RootI, path exported.PathI) bool { runtime := rootmulti.DefaultProofRuntime() err := runtime.VerifyAbsence(proof.Proof, root.GetHash(), path.String()) - if err != nil { - return false - } - - return true + return err == nil } From 9b7727566361ed82fc6b869f7d6c313a57676d96 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 22 Oct 2019 14:38:14 +0200 Subject: [PATCH 310/378] various fixes; remove legacy tests; remove commitment path query --- x/ibc/02-client/client/cli/query.go | 36 +--- x/ibc/02-client/exported/exported.go | 4 +- x/ibc/02-client/keeper/keeper.go | 39 ++-- x/ibc/02-client/keeper/querier.go | 13 -- x/ibc/02-client/types/querier.go | 1 - .../types/tendermint/consensus_state.go | 16 +- .../types/tendermint/tests/tendermint_test.go | 52 ----- .../02-client/types/tendermint/tests/types.go | 198 ------------------ .../02-client/types/tendermint/tests/utils.go | 8 - .../types/tendermint/tests/valset.go | 182 ---------------- x/ibc/module.go | 6 +- 11 files changed, 30 insertions(+), 525 deletions(-) delete mode 100644 x/ibc/02-client/types/tendermint/tests/tendermint_test.go delete mode 100644 x/ibc/02-client/types/tendermint/tests/types.go delete mode 100644 x/ibc/02-client/types/tendermint/tests/utils.go delete mode 100644 x/ibc/02-client/types/tendermint/tests/valset.go diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index fbef4a4e8181..1e2e4f1ef5b2 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -17,8 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" ) // GetQueryCmd returns the query commands for IBC clients @@ -32,7 +31,6 @@ func GetQueryCmd(queryRouter string, cdc *codec.Codec) *cobra.Command { ics02ClientQueryCmd.AddCommand(client.GetCommands( GetCmdQueryConsensusState(queryRouter, cdc), - GetCmdQueryPath(queryRouter, cdc), GetCmdQueryHeader(cdc), GetCmdQueryClientState(queryRouter, cdc), GetCmdQueryRoot(queryRouter, cdc), @@ -116,7 +114,7 @@ $ %s query ibc client root [client-id] [height] return err } - var root ics23.Root + var root commitmentexported.RootI if err := cdc.UnmarshalJSON(res, &root); err != nil { return err } @@ -167,36 +165,6 @@ $ %s query ibc client consensus-state [client-id] } } -// GetCmdQueryPath defines the command to query the commitment path -func GetCmdQueryPath(storeName string, cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "path", - Short: "Query the commitment path of the running chain", - Long: strings.TrimSpace(fmt.Sprintf(`Query the commitment path - -Example: -$ %s query ibc client path - `, version.ClientName), - ), - RunE: func(cmd *cobra.Command, args []string) error { - cliCtx := context.NewCLIContext().WithCodec(cdc) - - // TODO: get right path - res, _, err := cliCtx.Query("") - if err != nil { - return err - } - - var path merkle.Prefix - if err := cdc.UnmarshalJSON(res, &path); err != nil { - return err - } - - return cliCtx.PrintOutput(path) - }, - } -} - // GetCmdQueryHeader defines the command to query the latest header on the chain // TODO: do we really need this cmd ?? func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index ce0f51af84af..05db3902130f 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -3,7 +3,7 @@ package exported import ( "fmt" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" ) // Blockchain is consensus algorithm which generates valid Headers. It generates @@ -21,7 +21,7 @@ type ConsensusState interface { // GetRoot returns the commitment root of the consensus state, // which is used for key-value pair verification. - GetRoot() ics23.Root + GetRoot() commitmentexported.RootI // CheckValidityAndUpdateState returns the updated consensus state // only if the header is a descendent of this consensus state. diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index 660fdc450f24..feef68f3a7f3 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -12,8 +12,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -41,11 +41,6 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName)) } -// GetCommitmentPath returns the commitment path of the client -func (k Keeper) GetCommitmentPath() merkle.Prefix { - return merkle.NewPrefix([][]byte{[]byte(k.storeKey.Name())}, k.prefix) -} - // GetClientState gets a particular client from the store func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (types.ClientState, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) @@ -104,20 +99,20 @@ func (k Keeper) SetConsensusState(ctx sdk.Context, clientID string, consensusSta } // GetCommitmentRoot gets a commitment Root from a particular height to a client -func (k Keeper) GetCommitmentRoot(ctx sdk.Context, clientID string, height uint64) (ics23.Root, bool) { +func (k Keeper) GetCommitmentRoot(ctx sdk.Context, clientID string, height uint64) (commitmentexported.RootI, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := store.Get(types.KeyRoot(clientID, height)) if bz == nil { return nil, false } - var root ics23.Root + var root commitmentexported.RootI k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &root) return root, true } // SetCommitmentRoot sets a commitment Root from a particular height to a client -func (k Keeper) SetCommitmentRoot(ctx sdk.Context, clientID string, height uint64, root ics23.Root) { +func (k Keeper) SetCommitmentRoot(ctx sdk.Context, clientID string, height uint64, root commitmentexported.RootI) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := k.cdc.MustMarshalBinaryLengthPrefixed(root) store.Set(types.KeyRoot(clientID, height), bz) @@ -161,8 +156,8 @@ func (k Keeper) VerifyMembership( ctx sdk.Context, clientState types.ClientState, height uint64, // sequence - proof ics23.Proof, - path string, + proof commitmentexported.ProofI, + pathStr string, value []byte, ) bool { if clientState.Frozen { @@ -174,12 +169,10 @@ func (k Keeper) VerifyMembership( return false } - prefix := merkle.NewPrefix([][]byte{[]byte(path)}, nil) // TODO: keyprefix? - if err := proof.Verify(root, prefix, value); err != nil { - return false - } + prefix := commitmenttypes.NewPrefix(k.prefix) + path := commitmenttypes.ApplyPrefix(prefix, pathStr) - return true + return proof.VerifyMembership(root, path, value) } // VerifyNonMembership state non-membership function defined by the client type @@ -187,8 +180,8 @@ func (k Keeper) VerifyNonMembership( ctx sdk.Context, clientState types.ClientState, height uint64, // sequence - proof ics23.Proof, - path string, + proof commitmentexported.ProofI, + pathStr string, ) bool { if clientState.Frozen { return false @@ -199,10 +192,8 @@ func (k Keeper) VerifyNonMembership( return false } - prefix := merkle.NewPrefix([][]byte{[]byte(path)}, nil) // TODO: keyprefix? - if err := proof.Verify(root, prefix, nil); err != nil { - return false - } + prefix := commitmenttypes.NewPrefix(k.prefix) + path := commitmenttypes.ApplyPrefix(prefix, pathStr) - return true + return proof.VerifyNonMembership(root, path) } diff --git a/x/ibc/02-client/keeper/querier.go b/x/ibc/02-client/keeper/querier.go index 3b014d916ac3..dc52cdd20f4e 100644 --- a/x/ibc/02-client/keeper/querier.go +++ b/x/ibc/02-client/keeper/querier.go @@ -17,8 +17,6 @@ func NewQuerier(k Keeper) sdk.Querier { return queryClientState(ctx, req, k) case types.QueryConsensusState: return queryConsensusState(ctx, req, k) - case types.QueryCommitmentPath: - return queryCommitmentPath(k) case types.QueryCommitmentRoot: return queryCommitmentRoot(ctx, req, k) default: @@ -71,17 +69,6 @@ func queryConsensusState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]by return bz, nil } -func queryCommitmentPath(k Keeper) ([]byte, sdk.Error) { - path := k.GetCommitmentPath() - - bz, err := types.SubModuleCdc.MarshalJSON(path) - if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) - } - - return bz, nil -} - func queryCommitmentRoot(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { var params types.QueryCommitmentRootParams diff --git a/x/ibc/02-client/types/querier.go b/x/ibc/02-client/types/querier.go index 6e58b6c00f57..eff5bce07b67 100644 --- a/x/ibc/02-client/types/querier.go +++ b/x/ibc/02-client/types/querier.go @@ -4,7 +4,6 @@ package types const ( QueryClientState = "client_state" QueryConsensusState = "consensus_state" - QueryCommitmentPath = "commitment_path" QueryCommitmentRoot = "roots" ) diff --git a/x/ibc/02-client/types/tendermint/consensus_state.go b/x/ibc/02-client/types/tendermint/consensus_state.go index 0a52c598a9ec..6a369433c9f5 100644 --- a/x/ibc/02-client/types/tendermint/consensus_state.go +++ b/x/ibc/02-client/types/tendermint/consensus_state.go @@ -8,18 +8,18 @@ import ( tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" ) var _ exported.ConsensusState = ConsensusState{} // ConsensusState defines a Tendermint consensus state type ConsensusState struct { - ChainID string `json:"chain_id" yaml:"chain_id"` - Height uint64 `json:"height" yaml:"height"` // NOTE: defined as 'sequence' in the spec - Root ics23.Root `json:"root" yaml:"root"` - NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` // contains the PublicKey + ChainID string `json:"chain_id" yaml:"chain_id"` + Height uint64 `json:"height" yaml:"height"` // NOTE: defined as 'sequence' in the spec + Root commitmentexported.RootI `json:"root" yaml:"root"` + NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` // contains the PublicKey } // ClientType returns Tendermint @@ -33,7 +33,7 @@ func (cs ConsensusState) GetHeight() uint64 { } // GetRoot returns the commitment Root for the specific -func (cs ConsensusState) GetRoot() ics23.Root { +func (cs ConsensusState) GetRoot() commitmentexported.RootI { return cs.Root } @@ -84,7 +84,7 @@ func (cs ConsensusState) checkValidity(header Header) error { // update the consensus state from a new header func (cs ConsensusState) update(header Header) ConsensusState { cs.Height = header.GetHeight() - cs.Root = merkle.NewRoot(header.AppHash) + cs.Root = commitmenttypes.NewRoot(header.AppHash) cs.NextValidatorSet = header.NextValidatorSet return cs } diff --git a/x/ibc/02-client/types/tendermint/tests/tendermint_test.go b/x/ibc/02-client/types/tendermint/tests/tendermint_test.go deleted file mode 100644 index e7d09644126a..000000000000 --- a/x/ibc/02-client/types/tendermint/tests/tendermint_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package tendermint - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func testUpdate(t *testing.T, interval int, ok bool) { - node := NewNode(NewMockValidators(100, 10), "f8wib", []byte{0x98, 0x78}) - - _ = node.Commit() - - verifier := node.LastStateVerifier() - - for i := 0; i < 100; i++ { - header := node.Commit() - - if i%interval == 0 { - err := verifier.Validate(header, node.PrevValset, node.Valset) - if ok { - require.NoError(t, err) - } else { - require.Error(t, err) - } - } - } -} - -func TestEveryBlockUpdate(t *testing.T) { - testUpdate(t, 1, true) -} - -func TestEvenBlockUpdate(t *testing.T) { - testUpdate(t, 2, true) -} - -func TestSixthBlockUpdate(t *testing.T) { - testUpdate(t, 6, true) -} - -/* -// This should fail, since the amount of mutation is so large -// Commented out because it sometimes success -func TestTenthBlockUpdate(t *testing.T) { - testUpdate(t, 10, false) -} -*/ - -func TestProofs(t *testing.T) { - testProof(t) -} diff --git a/x/ibc/02-client/types/tendermint/tests/types.go b/x/ibc/02-client/types/tendermint/tests/types.go deleted file mode 100644 index 532b01c635ee..000000000000 --- a/x/ibc/02-client/types/tendermint/tests/types.go +++ /dev/null @@ -1,198 +0,0 @@ -package tendermint - -import ( - "bytes" - "crypto/rand" - "testing" - - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tendermint/libs/common" - "github.com/tendermint/tendermint/libs/log" - tmtypes "github.com/tendermint/tendermint/types" - dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store" - stypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" -) - -const chainid = "testchain" - -func defaultComponents(storename string) (sdk.StoreKey, sdk.Context, stypes.CommitMultiStore, *codec.Codec) { - key := sdk.NewKVStoreKey(storename) - - db := dbm.NewMemDB() - cms := store.NewCommitMultiStore(db) - cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) - err := cms.LoadLatestVersion() - if err != nil { - panic(err) - } - ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) - cdc := codec.New() - return key, ctx, cms, cdc -} - -type Node struct { - PrevValset MockValidators - Valset MockValidators - - Cms sdk.CommitMultiStore - Key sdk.StoreKey - Store sdk.KVStore - - Commits []tmtypes.SignedHeader - - StoreName string - KeyPrefix []byte -} - -func NewNode(valset MockValidators, storeName string, prefix []byte) *Node { - key, ctx, cms, _ := defaultComponents(storeName) - - return &Node{ - Valset: valset, - Cms: cms, - Key: key, - Store: ctx.KVStore(key), - Commits: nil, - StoreName: storeName, - KeyPrefix: prefix, - } -} - -func (node *Node) Prefix() merkle.Prefix { - return merkle.NewPrefix([][]byte{[]byte(node.StoreName)}, node.KeyPrefix) -} - -func (node *Node) Last() tmtypes.SignedHeader { - if len(node.Commits) == 0 { - return tmtypes.SignedHeader{} - } - return node.Commits[len(node.Commits)-1] -} - -func (node *Node) Commit() tendermint.Header { - valsethash := node.Valset.ValidatorSet().Hash() - nextvalset := node.Valset.Mutate() - nextvalsethash := nextvalset.ValidatorSet().Hash() - commitid := node.Cms.Commit() - - header := tmtypes.Header{ - ChainID: chainid, - Height: int64(len(node.Commits) + 1), - LastBlockID: tmtypes.BlockID{ - Hash: node.Last().Header.Hash(), - }, - - ValidatorsHash: valsethash, - NextValidatorsHash: nextvalsethash, - AppHash: commitid.Hash, - } - - commit := node.Valset.Sign(header) - - node.PrevValset = node.Valset - node.Valset = nextvalset - node.Commits = append(node.Commits, commit) - - return tendermint.Header{ - SignedHeader: commit, - ValidatorSet: node.PrevValset.ValidatorSet(), - NextValidatorSet: node.Valset.ValidatorSet(), - } -} - -func (node *Node) LastStateVerifier() *Verifier { - return NewVerifier(node.Last(), node.Valset, node.Root()) -} - -func (node *Node) Root() merkle.Root { - return merkle.NewRoot(node.Last().AppHash) - -} - -func (node *Node) Context() sdk.Context { - return sdk.NewContext(node.Cms, abci.Header{}, false, log.NewNopLogger()) -} - -type Verifier struct { - exported.ConsensusState -} - -func NewVerifier(header tmtypes.SignedHeader, nextvalset MockValidators, root merkle.Root) *Verifier { - return &Verifier{ - tendermint.ConsensusState{ - ChainID: chainid, - Height: uint64(header.Height), - Root: merkle.NewRoot(header.AppHash), - NextValidatorSet: nextvalset.ValidatorSet(), - }, - } -} - -func (v *Verifier) Validate(header tendermint.Header, valset, nextvalset MockValidators) error { - newcs, err := v.ConsensusState.CheckValidityAndUpdateState(header) - if err != nil { - return err - } - v.ConsensusState = newcs.(tendermint.ConsensusState) - - return nil -} - -func (node *Node) Query(t *testing.T, k []byte) ([]byte, commitment.Proof) { - k = bytes.TrimPrefix(k, node.KeyPrefix) - value, proof, err := merkle.QueryMultiStore(node.Cms, node.StoreName, node.KeyPrefix, k) - require.NoError(t, err) - return value, proof -} - -func (node *Node) Set(k, value []byte) { - node.Store.Set(join(node.KeyPrefix, k), value) -} - -// nolint:deadcode,unused -func testProof(t *testing.T) { - node := NewNode(NewMockValidators(100, 10), "1", []byte{0x00, 0x01}) - - node.Commit() - - kvps := cmn.KVPairs{} - for h := 0; h < 20; h++ { - for i := 0; i < 100; i++ { - k := make([]byte, 32) - v := make([]byte, 32) - _, err := rand.Read(k) - require.NoError(t, err) - _, err = rand.Read(v) - require.NoError(t, err) - kvps = append(kvps, cmn.KVPair{Key: k, Value: v}) - node.Set(k, v) - } - - header := node.Commit() - proofs := []commitment.Proof{} - root := merkle.NewRoot(header.AppHash) - for _, kvp := range kvps { - v, p := node.Query(t, kvp.Key) - - require.Equal(t, kvp.Value, v) - proofs = append(proofs, p) - } - cstore, err := commitment.NewStore(root, node.Prefix(), proofs) - require.NoError(t, err) - - for _, kvp := range kvps { - require.True(t, cstore.Prove(kvp.Key, kvp.Value)) - } - } -} diff --git a/x/ibc/02-client/types/tendermint/tests/utils.go b/x/ibc/02-client/types/tendermint/tests/utils.go deleted file mode 100644 index d5262a14a29b..000000000000 --- a/x/ibc/02-client/types/tendermint/tests/utils.go +++ /dev/null @@ -1,8 +0,0 @@ -package tendermint - -func join(a, b []byte) (res []byte) { - res = make([]byte, len(a)+len(b)) - copy(res, a) - copy(res[len(a):], b) - return -} diff --git a/x/ibc/02-client/types/tendermint/tests/valset.go b/x/ibc/02-client/types/tendermint/tests/valset.go deleted file mode 100644 index 30bd194682c8..000000000000 --- a/x/ibc/02-client/types/tendermint/tests/valset.go +++ /dev/null @@ -1,182 +0,0 @@ -package tendermint - -import ( - "bytes" - "sort" - - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - tmtypes "github.com/tendermint/tendermint/types" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// reimplementing tmtypes.MockPV to make it marshallable -type mockPV struct { - PrivKey crypto.PrivKey -} - -var _ tmtypes.PrivValidator = (*mockPV)(nil) - -func newMockPV() *mockPV { - return &mockPV{ed25519.GenPrivKey()} -} - -func (pv *mockPV) GetAddress() tmtypes.Address { - return pv.PrivKey.PubKey().Address() -} - -func (pv *mockPV) GetPubKey() crypto.PubKey { - return pv.PrivKey.PubKey() -} - -func (pv *mockPV) SignVote(chainID string, vote *tmtypes.Vote) error { - signBytes := vote.SignBytes(chainID) - sig, err := pv.PrivKey.Sign(signBytes) - if err != nil { - return err - } - vote.Signature = sig - return nil -} - -func (pv *mockPV) SignProposal(string, *tmtypes.Proposal) error { - panic("not needed") -} - -// MockValset -type MockValidator struct { - MockPV *mockPV - Power sdk.Dec -} - -func NewMockValidator(power sdk.Dec) MockValidator { - return MockValidator{ - MockPV: newMockPV(), - Power: power, - } -} - -func (val MockValidator) GetOperator() sdk.ValAddress { - return sdk.ValAddress(val.MockPV.GetAddress()) -} - -func (val MockValidator) GetConsAddr() sdk.ConsAddress { - return sdk.GetConsAddress(val.MockPV.GetPubKey()) -} - -func (val MockValidator) GetConsPubKey() crypto.PubKey { - return val.MockPV.GetPubKey() -} - -func (val MockValidator) GetPower() sdk.Dec { - return val.Power -} - -func (val MockValidator) Validator() *tmtypes.Validator { - return tmtypes.NewValidator( - val.GetConsPubKey(), - val.GetPower().RoundInt64(), - ) -} - -type MockValidators []MockValidator - -var _ sort.Interface = MockValidators{} - -// TODO: differentiate power between the vals -func NewMockValidators(num int, power int64) MockValidators { - res := make(MockValidators, num) - for i := range res { - res[i] = NewMockValidator(sdk.NewDec(power)) - } - - sort.Sort(res) - - return res -} - -func (vals MockValidators) Len() int { - return len(vals) -} - -func (vals MockValidators) Less(i, j int) bool { - return bytes.Compare([]byte(vals[i].GetConsAddr()), []byte(vals[j].GetConsAddr())) == -1 -} - -func (vals MockValidators) Swap(i, j int) { - it := vals[j] - vals[j] = vals[i] - vals[i] = it -} - -func (vals MockValidators) TotalPower() sdk.Dec { - res := sdk.ZeroDec() - for _, val := range vals { - res = res.Add(val.Power) - } - return res -} - -func (vals MockValidators) Sign(header tmtypes.Header) tmtypes.SignedHeader { - - precommits := make([]*tmtypes.CommitSig, len(vals)) - for i, val := range vals { - vote := &tmtypes.Vote{ - BlockID: tmtypes.BlockID{ - Hash: header.Hash(), - }, - ValidatorAddress: val.MockPV.GetAddress(), - ValidatorIndex: i, - Height: header.Height, - Type: tmtypes.PrecommitType, - } - _ = val.MockPV.SignVote(chainid, vote) - precommits[i] = vote.CommitSig() - } - - return tmtypes.SignedHeader{ - Header: &header, - Commit: &tmtypes.Commit{ - BlockID: tmtypes.BlockID{ - Hash: header.Hash(), - }, - Precommits: precommits, - }, - } -} - -// Mutate valset -func (vals MockValidators) Mutate() MockValidators { - num := len(vals) / 20 // 5% change each block - - res := make(MockValidators, len(vals)) - - for i := 0; i < len(vals)-num; i++ { - res[i] = vals[num:][i] - } - - for i := len(vals) - num; i < len(vals); i++ { - res[i] = NewMockValidator(vals[0].Power) - } - - sort.Sort(res) - - for i, val := range vals { - if val != res[i] { - return res - } - } - - panic("not mutated") -} - -func (vals MockValidators) ValidatorSet() *tmtypes.ValidatorSet { - tmvals := make([]*tmtypes.Validator, len(vals)) - - for i, val := range vals { - tmvals[i] = val.Validator() - } - - return tmtypes.NewValidatorSet(tmvals) -} diff --git a/x/ibc/module.go b/x/ibc/module.go index 5a56db96877f..b250e9c355ef 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -13,7 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/client/cli" "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -37,7 +37,7 @@ func (AppModuleBasic) Name() string { // RegisterCodec registers the staking module's types for the given codec. func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { client.RegisterCodec(cdc) - ics23.RegisterCodec(cdc) + commitment.RegisterCodec(cdc) } // DefaultGenesis returns default genesis state as raw bytes for the staking @@ -53,7 +53,7 @@ func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { // RegisterRESTRoutes registers the REST routes for the staking module. func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { - //noop + /// TODO: } // GetTxCmd returns the root tx command for the staking module. From 40fca1a82f8ede9c586ebb757ed697010d55fcf2 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 22 Oct 2019 14:59:39 +0200 Subject: [PATCH 311/378] alias --- x/ibc/23-commitment/alias.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 x/ibc/23-commitment/alias.go diff --git a/x/ibc/23-commitment/alias.go b/x/ibc/23-commitment/alias.go new file mode 100644 index 000000000000..4c40bbfed20b --- /dev/null +++ b/x/ibc/23-commitment/alias.go @@ -0,0 +1,30 @@ +package commitment + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper + RegisterCodec = types.RegisterCodec + NewRoot = types.NewRoot + NewPrefix = types.NewPrefix + NewPath = types.NewPath + ApplyPrefix = types.ApplyPrefix +) + +type ( + Keeper = keeper.Keeper + Root = types.Root + Prefix = types.Prefix + Path = types.Path + Proof = types.Proof +) From deceeb8633d77322de3887e724e1e27826a80ccc Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 22 Oct 2019 15:05:35 +0200 Subject: [PATCH 312/378] minor updates from ICS23 --- x/ibc/02-client/alias.go | 1 - x/ibc/02-client/keeper/keeper.go | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/x/ibc/02-client/alias.go b/x/ibc/02-client/alias.go index a93de15094b7..b282922159d2 100644 --- a/x/ibc/02-client/alias.go +++ b/x/ibc/02-client/alias.go @@ -28,7 +28,6 @@ const ( QuerierRoute = types.QuerierRoute QueryClientState = types.QueryClientState QueryConsensusState = types.QueryConsensusState - QueryCommitmentPath = types.QueryCommitmentPath QueryCommitmentRoot = types.QueryCommitmentRoot ) diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index feef68f3a7f3..6b31b58e98ee 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -12,8 +12,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" - commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -169,8 +169,8 @@ func (k Keeper) VerifyMembership( return false } - prefix := commitmenttypes.NewPrefix(k.prefix) - path := commitmenttypes.ApplyPrefix(prefix, pathStr) + prefix := commitment.NewPrefix(k.prefix) + path := commitment.ApplyPrefix(prefix, pathStr) return proof.VerifyMembership(root, path, value) } @@ -192,8 +192,8 @@ func (k Keeper) VerifyNonMembership( return false } - prefix := commitmenttypes.NewPrefix(k.prefix) - path := commitmenttypes.ApplyPrefix(prefix, pathStr) + prefix := commitment.NewPrefix(k.prefix) + path := commitment.ApplyPrefix(prefix, pathStr) return proof.VerifyNonMembership(root, path) } From 2a1a14426748489d742ae88d8bf05a8126d34a07 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 22 Oct 2019 15:06:06 +0200 Subject: [PATCH 313/378] renaming --- x/ibc/02-client/types/tendermint/consensus_state.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/ibc/02-client/types/tendermint/consensus_state.go b/x/ibc/02-client/types/tendermint/consensus_state.go index 6a369433c9f5..2f8ce8abbc84 100644 --- a/x/ibc/02-client/types/tendermint/consensus_state.go +++ b/x/ibc/02-client/types/tendermint/consensus_state.go @@ -8,8 +8,8 @@ import ( tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" - commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" ) var _ exported.ConsensusState = ConsensusState{} @@ -84,7 +84,7 @@ func (cs ConsensusState) checkValidity(header Header) error { // update the consensus state from a new header func (cs ConsensusState) update(header Header) ConsensusState { cs.Height = header.GetHeight() - cs.Root = commitmenttypes.NewRoot(header.AppHash) + cs.Root = commitment.NewRoot(header.AppHash) cs.NextValidatorSet = header.NextValidatorSet return cs } From 714e6e2ab9150843984dc0ee704ff75c03dfd5aa Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 22 Oct 2019 16:23:22 +0200 Subject: [PATCH 314/378] update verification and rename root funcs --- x/ibc/02-client/client/cli/query.go | 4 ++-- x/ibc/02-client/keeper/client.go | 4 ++-- x/ibc/02-client/keeper/keeper.go | 25 ++++++++++--------------- x/ibc/02-client/keeper/querier.go | 2 +- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 1e2e4f1ef5b2..75d20c41ccd7 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -83,9 +83,9 @@ $ %s query ibc client state [client-id] func GetCmdQueryRoot(storeKey string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "root [client-id] [height]", - Short: "Query stored root", + Short: "Query a verified commitment root", Long: strings.TrimSpace( - fmt.Sprintf(`Query a stored commitment root at a specific height for a particular client + fmt.Sprintf(`Query an already verified commitment root at a specific height for a particular client Example: $ %s query ibc client root [client-id] [height] diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go index de26aa6c6591..71d3bb3eb195 100644 --- a/x/ibc/02-client/keeper/client.go +++ b/x/ibc/02-client/keeper/client.go @@ -31,7 +31,7 @@ func (k Keeper) CreateClient( } clientState := k.initialize(ctx, clientID, consensusState) - k.SetCommitmentRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) + k.SetVerifiedRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) k.SetClientState(ctx, clientState) k.SetClientType(ctx, clientID, clientType) return clientState, nil @@ -78,7 +78,7 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H } k.SetConsensusState(ctx, clientID, consensusState) - k.SetCommitmentRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) + k.SetVerifiedRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) k.Logger(ctx).Info(fmt.Sprintf("client %s updated to height %d", clientID, consensusState.GetHeight())) return nil } diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index 6b31b58e98ee..1469544ab530 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -12,7 +12,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -98,8 +97,9 @@ func (k Keeper) SetConsensusState(ctx sdk.Context, clientID string, consensusSta store.Set(types.KeyClientState(clientID), bz) } -// GetCommitmentRoot gets a commitment Root from a particular height to a client -func (k Keeper) GetCommitmentRoot(ctx sdk.Context, clientID string, height uint64) (commitmentexported.RootI, bool) { +// GetVerifiedRoot gets a verified commitment Root from a particular height to +// a client +func (k Keeper) GetVerifiedRoot(ctx sdk.Context, clientID string, height uint64) (commitmentexported.RootI, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := store.Get(types.KeyRoot(clientID, height)) if bz == nil { @@ -111,8 +111,9 @@ func (k Keeper) GetCommitmentRoot(ctx sdk.Context, clientID string, height uint6 return root, true } -// SetCommitmentRoot sets a commitment Root from a particular height to a client -func (k Keeper) SetCommitmentRoot(ctx sdk.Context, clientID string, height uint64, root commitmentexported.RootI) { +// SetVerifiedRoot sets a verified commitment Root from a particular height to +// a client +func (k Keeper) SetVerifiedRoot(ctx sdk.Context, clientID string, height uint64, root commitmentexported.RootI) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := k.cdc.MustMarshalBinaryLengthPrefixed(root) store.Set(types.KeyRoot(clientID, height), bz) @@ -157,21 +158,18 @@ func (k Keeper) VerifyMembership( clientState types.ClientState, height uint64, // sequence proof commitmentexported.ProofI, - pathStr string, + path commitmentexported.PathI, value []byte, ) bool { if clientState.Frozen { return false } - root, found := k.GetCommitmentRoot(ctx, clientState.ID(), height) + root, found := k.GetVerifiedRoot(ctx, clientState.ID(), height) if !found { return false } - prefix := commitment.NewPrefix(k.prefix) - path := commitment.ApplyPrefix(prefix, pathStr) - return proof.VerifyMembership(root, path, value) } @@ -181,19 +179,16 @@ func (k Keeper) VerifyNonMembership( clientState types.ClientState, height uint64, // sequence proof commitmentexported.ProofI, - pathStr string, + path commitmentexported.PathI, ) bool { if clientState.Frozen { return false } - root, found := k.GetCommitmentRoot(ctx, clientState.ID(), height) + root, found := k.GetVerifiedRoot(ctx, clientState.ID(), height) if !found { return false } - prefix := commitment.NewPrefix(k.prefix) - path := commitment.ApplyPrefix(prefix, pathStr) - return proof.VerifyNonMembership(root, path) } diff --git a/x/ibc/02-client/keeper/querier.go b/x/ibc/02-client/keeper/querier.go index dc52cdd20f4e..24172c087f43 100644 --- a/x/ibc/02-client/keeper/querier.go +++ b/x/ibc/02-client/keeper/querier.go @@ -77,7 +77,7 @@ func queryCommitmentRoot(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]by return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } - root, found := k.GetCommitmentRoot(ctx, params.ClientID, params.Height) + root, found := k.GetVerifiedRoot(ctx, params.ClientID, params.Height) if !found { return nil, types.ErrRootNotFound(k.codespace) } From 4282729610ecf2e508e3e0c6a051a605447f1217 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 22 Oct 2019 16:48:06 +0200 Subject: [PATCH 315/378] rm legacy tests; add query proofs support --- x/ibc/04-channel/client/cli/query.go | 35 ++-- x/ibc/04-channel/keeper/handshake.go | 10 +- x/ibc/04-channel/types/expected_keepers.go | 6 +- x/ibc/04-channel/types/packet.go | 2 +- x/ibc/04-channel/types/querier.go | 29 ++++ x/ibc/04-channel/types/tests/channel_test.go | 85 ---------- x/ibc/04-channel/types/tests/types.go | 168 ------------------- 7 files changed, 60 insertions(+), 275 deletions(-) delete mode 100644 x/ibc/04-channel/types/tests/channel_test.go delete mode 100644 x/ibc/04-channel/types/tests/types.go diff --git a/x/ibc/04-channel/client/cli/query.go b/x/ibc/04-channel/client/cli/query.go index 972a33d3e33f..0078b9f00b4b 100644 --- a/x/ibc/04-channel/client/cli/query.go +++ b/x/ibc/04-channel/client/cli/query.go @@ -5,19 +5,18 @@ import ( "strings" "github.com/spf13/cobra" + "github.com/spf13/viper" + + abci "github.com/tendermint/tendermint/abci/types" cli "github.com/cosmos/cosmos-sdk/client" "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/version" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ) -// TODO: get proofs -// const ( -// FlagProve = "prove" -// ) - // GetQueryCmd returns the query commands for IBC channels func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ics04ChannelQueryCmd := &cobra.Command{ @@ -34,11 +33,11 @@ func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { } // GetCmdQueryChannel defines the command to query a channel end -func GetCmdQueryChannel(storeKey string, cdc *codec.Codec) *cobra.Command { +func GetCmdQueryChannel(queryRoute string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "end [port-id] [channel-id]", - Short: "Query stored connection", - Long: strings.TrimSpace(fmt.Sprintf(`Query stored connection end + Short: "Query a channel end", + Long: strings.TrimSpace(fmt.Sprintf(`Query an IBC channel end Example: $ %s query ibc channel end [port-id] [channel-id] @@ -55,21 +54,31 @@ $ %s query ibc channel end [port-id] [channel-id] return err } - res, _, err := cliCtx.QueryWithData(types.ChannelPath(portID, channelID), bz) + req := abci.RequestQuery{ + Path: fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryChannel), + Data: bz, + Prove: viper.GetBool(flags.FlagProve), + } + + res, err := cliCtx.QueryABCI(req) if err != nil { return err } var channel types.Channel - if err := cdc.UnmarshalJSON(res, &channel); err != nil { + if err := cdc.UnmarshalJSON(res.Value, &channel); err != nil { return err } - return cliCtx.PrintOutput(channel) + if res.Proof == nil { + return cliCtx.PrintOutput(channel) + } + + channelRes := types.NewChannelResponse(portID, channelID, channel, res.Proof, res.Height) + return cliCtx.PrintOutput(channelRes) }, } - - // cmd.Flags().Bool(FlagProve, false, "(optional) show proofs for the query results") + cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results") return cmd } diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go index 7005b187f503..58096210ad74 100644 --- a/x/ibc/04-channel/keeper/handshake.go +++ b/x/ibc/04-channel/keeper/handshake.go @@ -7,7 +7,7 @@ import ( connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" porttypes "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" ) // ChanOpenInit is called by a module to initiate a channel opening handshake with @@ -71,7 +71,7 @@ func (k Keeper) ChanOpenTry( counterparty types.Counterparty, version, counterpartyVersion string, - proofInit ics23.Proof, + proofInit commitmentexported.ProofI, proofHeight uint64, ) (string, error) { @@ -144,7 +144,7 @@ func (k Keeper) ChanOpenAck( portID, channelID, counterpartyVersion string, - proofTry ics23.Proof, + proofTry commitmentexported.ProofI, proofHeight uint64, ) error { @@ -208,7 +208,7 @@ func (k Keeper) ChanOpenConfirm( ctx sdk.Context, portID, channelID string, - proofAck ics23.Proof, + proofAck commitmentexported.ProofI, proofHeight uint64, ) error { channel, found := k.GetChannel(ctx, portID, channelID) @@ -310,7 +310,7 @@ func (k Keeper) ChanCloseConfirm( ctx sdk.Context, portID, channelID string, - proofInit ics23.Proof, + proofInit commitmentexported.ProofI, proofHeight uint64, ) error { _, found := k.GetChannelCapability(ctx, portID, channelID) diff --git a/x/ibc/04-channel/types/expected_keepers.go b/x/ibc/04-channel/types/expected_keepers.go index 29784021947e..56b1c90a051e 100644 --- a/x/ibc/04-channel/types/expected_keepers.go +++ b/x/ibc/04-channel/types/expected_keepers.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" ) // ClientKeeper expected account IBC client keeper @@ -17,11 +17,11 @@ type ConnectionKeeper interface { GetConnection(ctx sdk.Context, connectionID string) (connectiontypes.ConnectionEnd, bool) VerifyMembership( ctx sdk.Context, connection connectiontypes.ConnectionEnd, height uint64, - proof ics23.Proof, path string, value []byte, + proof commitmentexported.ProofI, path string, value []byte, ) bool VerifyNonMembership( ctx sdk.Context, connection connectiontypes.ConnectionEnd, height uint64, - proof ics23.Proof, path string, + proof commitmentexported.ProofI, path string, ) bool } diff --git a/x/ibc/04-channel/types/packet.go b/x/ibc/04-channel/types/packet.go index fc9ce61ad47b..09d33748e6aa 100644 --- a/x/ibc/04-channel/types/packet.go +++ b/x/ibc/04-channel/types/packet.go @@ -54,7 +54,7 @@ func (p packet) DestChannel() string { return p.destinationChannel } // Data implements PacketI interface func (p packet) Data() []byte { return p.data } -var _ exported.PacketI = OpaquePacket{} +// var _ exported.PacketI = OpaquePacket{} // OpaquePacket is a packet, but cloaked in an obscuring data type by the host // state machine, such that a module cannot act upon it other than to pass it to diff --git a/x/ibc/04-channel/types/querier.go b/x/ibc/04-channel/types/querier.go index ac9eb8910d5d..f6960d663cfb 100644 --- a/x/ibc/04-channel/types/querier.go +++ b/x/ibc/04-channel/types/querier.go @@ -1,10 +1,39 @@ package types +import ( + "strings" + + "github.com/tendermint/tendermint/crypto/merkle" + + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + // query routes supported by the IBC channel Querier const ( QueryChannel = "channel" ) +// ChannelResponse defines the client query response for a channel which also +// includes a proof,its path and the height from which the proof was retrieved. +type ChannelResponse struct { + Channel Channel `json:"channel" yaml:"channel"` + Proof commitment.Proof `json:"proof,omitempty" yaml:"proof,omitempty"` + ProofPath commitment.Path `json:"proof_path,omitempty" yaml:"proof_path,omitempty"` + ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` +} + +// NewChannelResponse creates a new ChannelResponse instance +func NewChannelResponse( + portID, channelID string, channel Channel, proof *merkle.Proof, height int64, +) ChannelResponse { + return ChannelResponse{ + Channel: channel, + Proof: commitment.Proof{Proof: proof}, + ProofPath: commitment.NewPath(strings.Split(ChannelPath(portID, channelID), "/")), + ProofHeight: uint64(height), + } +} + // QueryChannelParams defines the params for the following queries: // - 'custom/ibc/channel' type QueryChannelParams struct { diff --git a/x/ibc/04-channel/types/tests/channel_test.go b/x/ibc/04-channel/types/tests/channel_test.go deleted file mode 100644 index 3b5f676298b1..000000000000 --- a/x/ibc/04-channel/types/tests/channel_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package test - -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" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" - ics04 "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/23-commitment/merkle" -) - -func registerCodec(cdc *codec.Codec) { - client.RegisterCodec(cdc) - tmclient.RegisterCodec(cdc) - commitment.RegisterCodec(cdc) - merkle.RegisterCodec(cdc) - codec.RegisterCrypto(cdc) - ics04.RegisterCodec(cdc) - cdc.RegisterConcrete(MyPacket{}, "test/MyPacket", nil) -} - -func TestHandshake(t *testing.T) { - cdc := codec.New() - registerCodec(cdc) - - node := NewNode(tendermint.NewMockValidators(100, 10), tendermint.NewMockValidators(100, 10), cdc) - - node.Handshake(t) -} - -type MyPacket struct { - Message string -} - -func (packet MyPacket) Commit() []byte { - return []byte(packet.Message) -} - -func (packet MyPacket) Timeout() uint64 { - return 100 // TODO -} - -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) { - cdc := codec.New() - registerCodec(cdc) - - node := NewNode(tendermint.NewMockValidators(100, 10), tendermint.NewMockValidators(100, 10), cdc) - - node.Handshake(t) - - node.Send(t, MyPacket{"ping"}) - header := node.Commit() - - node.Counterparty.UpdateClient(t, header) - cliobj := node.CLIState() - _, ppacket := node.QueryValue(t, cliobj.Packets.Value(1)) - node.Counterparty.Receive(t, MyPacket{"ping"}, uint64(header.Height), ppacket) -} diff --git a/x/ibc/04-channel/types/tests/types.go b/x/ibc/04-channel/types/tests/types.go deleted file mode 100644 index 8389934377a4..000000000000 --- a/x/ibc/04-channel/types/tests/types.go +++ /dev/null @@ -1,168 +0,0 @@ -package channel - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/state" - sdk "github.com/cosmos/cosmos-sdk/types" - - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/02-client/tendermint/tests" - connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/tests" - ics04 "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -const PortName = "port-test" - -type Node struct { - *connection.Node - Counterparty *Node - Channel ics04.Channel - Cdc *codec.Codec -} - -func NewNode(self, counter tendermint.MockValidators, cdc *codec.Codec) *Node { - res := &Node{ - Node: connection.NewNode(self, counter, cdc), - Cdc: cdc, - } - - res.Counterparty = &Node{ - Node: res.Node.Counterparty, - Counterparty: res, - Cdc: cdc, - } - - res.Channel = ics04.Channel{ - Counterparty: res.Counterparty.Name, - CounterpartyPort: PortName, - ConnectionHops: []string{res.Name}, - } - - res.Counterparty.Channel = ics04.Channel{ - Counterparty: res.Name, - CounterpartyPort: PortName, - ConnectionHops: []string{res.Counterparty.Name}, - } - - return res -} - -func (node *Node) Handshaker(t *testing.T, proofs []commitment.Proof) (sdk.Context, ics04.Handshaker) { - ctx := node.Context() - store, err := commitment.NewStore(node.Counterparty.Root(), node.Counterparty.Prefix(), proofs) - require.NoError(t, err) - ctx = commitment.WithStore(ctx, store) - man := node.Manager() - return ctx, ics04.NewHandshaker(man) -} - -func (node *Node) CLIState() ics04.HandshakeState { - man := node.Manager() - return ics04.NewHandshaker(man).CLIState(PortName, node.Name, []string{node.Name}) -} - -func base(cdc *codec.Codec, key sdk.StoreKey) (state.Mapping, state.Mapping) { - protocol := state.NewMapping(key, cdc, []byte("protocol/")) - free := state.NewMapping(key, cdc, []byte("free")) - return protocol, free -} - -func (node *Node) Manager() ics04.Manager { - protocol, _ := base(node.Cdc, node.Key) - _, connman := node.Node.Manager() - return ics04.NewManager(protocol, connman) -} - -func (node *Node) OpenInit(t *testing.T, proofs ...commitment.Proof) { - ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenInit(ctx, PortName, node.Name, node.Channel) - require.NoError(t, err) - require.Equal(t, ics04.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, height uint64, proofs ...commitment.Proof) { - ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenTry(ctx, proofs, height, PortName, node.Name, node.Channel) - require.NoError(t, err) - require.Equal(t, ics04.OpenTry, obj.Stage.Get(ctx)) - require.Equal(t, node.Channel, obj.GetChannel(ctx)) - require.False(t, obj.Available.Get(ctx)) - node.SetState(ics04.OpenTry) -} - -func (node *Node) OpenAck(t *testing.T, height uint64, proofs ...commitment.Proof) { - ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenAck(ctx, proofs, height, PortName, node.Name) - require.NoError(t, err) - require.Equal(t, ics04.Open, obj.Stage.Get(ctx)) - require.Equal(t, node.Channel, obj.GetChannel(ctx)) - require.True(t, obj.Available.Get(ctx)) - node.SetState(ics04.Open) -} - -func (node *Node) OpenConfirm(t *testing.T, height uint64, proofs ...commitment.Proof) { - ctx, man := node.Handshaker(t, proofs) - obj, err := man.OpenConfirm(ctx, proofs, height, PortName, node.Name) - require.NoError(t, err) - require.Equal(t, ics04.Open, obj.Stage.Get(ctx)) - require.Equal(t, node.Channel, obj.GetChannel(ctx)) - require.True(t, obj.Available.Get(ctx)) - node.SetState(ics04.CloseTry) -} - -func (node *Node) Handshake(t *testing.T) { - node.Node.Handshake(t) - - // self.OpenInit - node.OpenInit(t) - header := node.Commit() - - // counterparty.OpenTry - node.Counterparty.UpdateClient(t, header) - cliobj := node.CLIState() - _, pchan := node.QueryValue(t, cliobj.Channel) - _, 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.CLIState() - _, pchan = node.Counterparty.QueryValue(t, cliobj.Channel) - _, 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.CLIState() - _, pstate = node.QueryValue(t, cliobj.Stage) - node.Counterparty.OpenConfirm(t, uint64(header.Height), pstate) -} - -func (node *Node) Send(t *testing.T, packet ics04.Packet) { - ctx, man := node.Context(), node.Manager() - obj, err := man.Query(ctx, PortName, node.Name) - require.NoError(t, err) - seq := obj.SeqSend.Get(ctx) - 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 ics04.Packet, height uint64, proofs ...commitment.Proof) { - ctx, man := node.Context(), node.Manager() - obj, err := man.Query(ctx, PortName, node.Name) - require.NoError(t, err) - seq := obj.SeqRecv.Get(ctx) - err = man.Receive(ctx, proofs, height, PortName, node.Name, packet) - require.NoError(t, err) - require.Equal(t, seq+1, obj.SeqRecv.Get(ctx)) -} From 8fe17f6c895ed79bd5120b69da9cecd22791454f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 22 Oct 2019 18:09:03 +0200 Subject: [PATCH 316/378] remove capability key generation and authentication logic --- x/ibc/04-channel/keeper/handshake.go | 76 ++++++++-------------------- 1 file changed, 22 insertions(+), 54 deletions(-) diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go index 58096210ad74..c6589c3cedcd 100644 --- a/x/ibc/04-channel/keeper/handshake.go +++ b/x/ibc/04-channel/keeper/handshake.go @@ -20,29 +20,29 @@ func (k Keeper) ChanOpenInit( channelID string, counterparty types.Counterparty, version string, -) (string, error) { +) error { // TODO: abortTransactionUnless(validateChannelIdentifier(portIdentifier, channelIdentifier)) if len(connectionHops) != 1 { - return "", types.ErrInvalidConnectionHops(k.codespace) + return types.ErrInvalidConnectionHops(k.codespace) } _, found := k.GetChannel(ctx, portID, channelID) if found { - return "", types.ErrChannelExists(k.codespace, channelID) + return types.ErrChannelExists(k.codespace, channelID) } connection, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) if !found { - return "", connectiontypes.ErrConnectionNotFound(k.codespace, connectionHops[0]) + return connectiontypes.ErrConnectionNotFound(k.codespace, connectionHops[0]) } if connection.State == connectiontypes.NONE { - return "", errors.New("connection is closed") + return errors.New("connection is closed") } _, found = k.portKeeper.GetPort(ctx, portID) if !found { - return "", porttypes.ErrPortNotFound(k.codespace, portID) + return porttypes.ErrPortNotFound(k.codespace, portID) } // if !k.portKeeper.AuthenticatePort(port.ID()) { @@ -52,12 +52,11 @@ func (k Keeper) ChanOpenInit( channel := types.NewChannel(types.INIT, order, counterparty, connectionHops, version) k.SetChannel(ctx, portID, channelID, channel) - key := "" // TODO: generate key - k.SetChannelCapability(ctx, portID, channelID, key) + // TODO: generate channel capability key and set it to store k.SetNextSequenceSend(ctx, portID, channelID, 1) k.SetNextSequenceRecv(ctx, portID, channelID, 1) - return key, nil + return nil } // ChanOpenTry is called by a module to accept the first step of a channel opening @@ -73,20 +72,20 @@ func (k Keeper) ChanOpenTry( counterpartyVersion string, proofInit commitmentexported.ProofI, proofHeight uint64, -) (string, error) { +) error { if len(connectionHops) != 1 { - return "", types.ErrInvalidConnectionHops(k.codespace) + return types.ErrInvalidConnectionHops(k.codespace) } _, found := k.GetChannel(ctx, portID, channelID) if found { - return "", types.ErrChannelExists(k.codespace, channelID) + return types.ErrChannelExists(k.codespace, channelID) } _, found = k.portKeeper.GetPort(ctx, portID) if !found { - return "", porttypes.ErrPortNotFound(k.codespace, portID) + return porttypes.ErrPortNotFound(k.codespace, portID) } // if !k.portKeeper.AuthenticatePort(port.ID()) { @@ -95,11 +94,11 @@ func (k Keeper) ChanOpenTry( connection, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) if !found { - return "", connectiontypes.ErrConnectionNotFound(k.codespace, connectionHops[0]) + return connectiontypes.ErrConnectionNotFound(k.codespace, connectionHops[0]) } if connection.State != connectiontypes.OPEN { - return "", errors.New("connection is not open") + return errors.New("connection is not open") } // NOTE: this step has been switched with the one below to reverse the connection @@ -116,7 +115,7 @@ func (k Keeper) ChanOpenTry( bz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedChannel) if err != nil { - return "", errors.New("failed to marshal expected channel") + return errors.New("failed to marshal expected channel") } if !k.connectionKeeper.VerifyMembership( @@ -124,17 +123,16 @@ func (k Keeper) ChanOpenTry( types.ChannelPath(counterparty.PortID, counterparty.ChannelID), bz, ) { - return "", types.ErrInvalidCounterpartyChannel(k.codespace) + return types.ErrInvalidCounterpartyChannel(k.codespace) } k.SetChannel(ctx, portID, channelID, channel) - key := "" // TODO: generate key - k.SetChannelCapability(ctx, portID, channelID, key) + // TODO: generate channel capability key and set it to store k.SetNextSequenceSend(ctx, portID, channelID, 1) k.SetNextSequenceRecv(ctx, portID, channelID, 1) - return key, nil + return nil } // ChanOpenAck is called by the handshake-originating module to acknowledge the @@ -157,14 +155,7 @@ func (k Keeper) ChanOpenAck( return errors.New("invalid channel state") // TODO: sdk.Error } - _, found = k.GetChannelCapability(ctx, portID, channelID) - if !found { - return types.ErrChannelCapabilityNotFound(k.codespace) - } - - // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") // TODO: sdk.Error - // } + // TODO: get channel capability key and authenticate it connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { @@ -220,14 +211,7 @@ func (k Keeper) ChanOpenConfirm( return errors.New("invalid channel state") // TODO: sdk.Error } - _, found = k.GetChannelCapability(ctx, portID, channelID) - if !found { - return types.ErrChannelCapabilityNotFound(k.codespace) - } - - // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") // TODO: sdk.Error - // } + // TODO: get channel capability key and authenticate it connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { @@ -271,15 +255,7 @@ func (k Keeper) ChanOpenConfirm( // ChanCloseInit is called by either module to close their end of the channel. Once // closed, channels cannot be reopened. func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error { - _, found := k.GetChannelCapability(ctx, portID, channelID) - if !found { - return types.ErrChannelCapabilityNotFound(k.codespace) - } - - // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") // TODO: sdk.Error - // } - + // TODO: get channel capability key and authenticate it channel, found := k.GetChannel(ctx, portID, channelID) if !found { return types.ErrChannelNotFound(k.codespace, channelID) @@ -313,15 +289,7 @@ func (k Keeper) ChanCloseConfirm( proofInit commitmentexported.ProofI, proofHeight uint64, ) error { - _, found := k.GetChannelCapability(ctx, portID, channelID) - if !found { - return types.ErrChannelCapabilityNotFound(k.codespace) - } - - // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") // TODO: sdk.Error - // } - + // TODO: get channel capability key and authenticate it channel, found := k.GetChannel(ctx, portID, channelID) if !found { return types.ErrChannelNotFound(k.codespace, channelID) From de13f5acd4416fcf6add8367c9b74c155f4ca3b7 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 22 Oct 2019 18:25:08 +0200 Subject: [PATCH 317/378] move querier to x/ibc --- x/ibc/02-client/alias.go | 6 ++++-- x/ibc/02-client/keeper/querier.go | 27 ++++++--------------------- x/ibc/02-client/types/querier.go | 2 +- x/ibc/alias.go | 3 ++- x/ibc/keeper/querier.go | 24 ++++++++++++++++++++++++ x/ibc/module.go | 3 +-- 6 files changed, 38 insertions(+), 27 deletions(-) create mode 100644 x/ibc/keeper/querier.go diff --git a/x/ibc/02-client/alias.go b/x/ibc/02-client/alias.go index b282922159d2..44eef2a19e8e 100644 --- a/x/ibc/02-client/alias.go +++ b/x/ibc/02-client/alias.go @@ -28,13 +28,15 @@ const ( QuerierRoute = types.QuerierRoute QueryClientState = types.QueryClientState QueryConsensusState = types.QueryConsensusState - QueryCommitmentRoot = types.QueryCommitmentRoot + QueryVerifiedRoot = types.QueryVerifiedRoot ) var ( // functions aliases NewKeeper = keeper.NewKeeper - NewQuerier = keeper.NewQuerier + QuerierClientState = keeper.QuerierClientState + QuerierConsensusState = keeper.QuerierConsensusState + QuerierVerifiedRoot = keeper.QuerierVerifiedRoot RegisterCodec = types.RegisterCodec ErrClientExists = types.ErrClientExists ErrClientNotFound = types.ErrClientNotFound diff --git a/x/ibc/02-client/keeper/querier.go b/x/ibc/02-client/keeper/querier.go index 24172c087f43..8c9ce5a263ef 100644 --- a/x/ibc/02-client/keeper/querier.go +++ b/x/ibc/02-client/keeper/querier.go @@ -9,23 +9,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" ) -// NewQuerier creates a querier for the IBC client -func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { - switch path[0] { - case types.QueryClientState: - return queryClientState(ctx, req, k) - case types.QueryConsensusState: - return queryConsensusState(ctx, req, k) - case types.QueryCommitmentRoot: - return queryCommitmentRoot(ctx, req, k) - default: - return nil, sdk.ErrUnknownRequest("unknown IBC client query endpoint") - } - } -} - -func queryClientState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +// QuerierClientState defines the sdk.Querier to query the IBC client state +func QuerierClientState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { var params types.QueryClientStateParams err := types.SubModuleCdc.UnmarshalJSON(req.Data, ¶ms) @@ -33,8 +18,6 @@ func queryClientState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } - // NOTE: clientID won't be exported as it's declared as private - // TODO: should we create a custom ExportedClientState to make it public ? clientState, found := k.GetClientState(ctx, params.ClientID) if !found { return nil, types.ErrClientTypeNotFound(k.codespace) @@ -48,7 +31,8 @@ func queryClientState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, return bz, nil } -func queryConsensusState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +// QuerierConsensusState defines the sdk.Querier to query a consensus state +func QuerierConsensusState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { var params types.QueryClientStateParams err := types.SubModuleCdc.UnmarshalJSON(req.Data, ¶ms) @@ -69,7 +53,8 @@ func queryConsensusState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]by return bz, nil } -func queryCommitmentRoot(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +// QuerierVerifiedRoot defines the sdk.Querier to query a verified commitment root +func QuerierVerifiedRoot(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { var params types.QueryCommitmentRootParams err := types.SubModuleCdc.UnmarshalJSON(req.Data, ¶ms) diff --git a/x/ibc/02-client/types/querier.go b/x/ibc/02-client/types/querier.go index eff5bce07b67..2f5de5af0572 100644 --- a/x/ibc/02-client/types/querier.go +++ b/x/ibc/02-client/types/querier.go @@ -4,7 +4,7 @@ package types const ( QueryClientState = "client_state" QueryConsensusState = "consensus_state" - QueryCommitmentRoot = "roots" + QueryVerifiedRoot = "roots" ) // QueryClientStateParams defines the params for the following queries: diff --git a/x/ibc/alias.go b/x/ibc/alias.go index d71d90640ab2..7c1ad02349e2 100644 --- a/x/ibc/alias.go +++ b/x/ibc/alias.go @@ -20,7 +20,8 @@ const ( var ( // functions aliases - NewKeeper = keeper.NewKeeper + NewKeeper = keeper.NewKeeper + NewQuerier = keeper.NewQuerier ) type ( diff --git a/x/ibc/keeper/querier.go b/x/ibc/keeper/querier.go new file mode 100644 index 000000000000..7cbd4ec9c499 --- /dev/null +++ b/x/ibc/keeper/querier.go @@ -0,0 +1,24 @@ +package keeper + +import ( + abci "github.com/tendermint/tendermint/abci/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" +) + +// NewQuerier creates a querier for the IBC module +func NewQuerier(k Keeper) sdk.Querier { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + switch path[0] { + case client.QueryClientState: + return client.QuerierClientState(ctx, req, k.ClientKeeper) + case client.QueryConsensusState: + return client.QuerierConsensusState(ctx, req, k.ClientKeeper) + case client.QueryVerifiedRoot: + return client.QuerierVerifiedRoot(ctx, req, k.ClientKeeper) + default: + return nil, sdk.ErrUnknownRequest("unknown IBC client query endpoint") + } + } +} diff --git a/x/ibc/module.go b/x/ibc/module.go index b250e9c355ef..675b18aa1ddf 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -106,8 +106,7 @@ func (AppModule) QuerierRoute() string { // NewQuerierHandler returns the staking module sdk.Querier. func (am AppModule) NewQuerierHandler() sdk.Querier { - // return NewQuerier(am.keeper - return nil + return NewQuerier(am.keeper) } // InitGenesis performs genesis initialization for the staking module. It returns From aae117f5ecbfd9da52c273d729d2944da542c1f6 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 22 Oct 2019 18:37:31 +0200 Subject: [PATCH 318/378] update query.go to use 'custom/...' query path --- x/ibc/02-client/alias.go | 2 +- x/ibc/02-client/client/cli/query.go | 22 +++++++++++----------- x/ibc/02-client/keeper/client.go | 6 +++--- x/ibc/02-client/keeper/keeper.go | 20 ++++++++++---------- x/ibc/02-client/types/state.go | 12 ++++++------ 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/x/ibc/02-client/alias.go b/x/ibc/02-client/alias.go index 44eef2a19e8e..1d82de808c50 100644 --- a/x/ibc/02-client/alias.go +++ b/x/ibc/02-client/alias.go @@ -76,5 +76,5 @@ type ( MsgSubmitMisbehaviour = types.MsgSubmitMisbehaviour QueryClientStateParams = types.QueryClientStateParams QueryCommitmentRootParams = types.QueryCommitmentRootParams - ClientState = types.ClientState + State = types.State ) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 75d20c41ccd7..9fbecbd2aebd 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -21,7 +21,7 @@ import ( ) // GetQueryCmd returns the query commands for IBC clients -func GetQueryCmd(queryRouter string, cdc *codec.Codec) *cobra.Command { +func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { ics02ClientQueryCmd := &cobra.Command{ Use: "client", Short: "IBC client query subcommands", @@ -30,17 +30,17 @@ func GetQueryCmd(queryRouter string, cdc *codec.Codec) *cobra.Command { } ics02ClientQueryCmd.AddCommand(client.GetCommands( - GetCmdQueryConsensusState(queryRouter, cdc), + GetCmdQueryConsensusState(queryRoute, cdc), GetCmdQueryHeader(cdc), - GetCmdQueryClientState(queryRouter, cdc), - GetCmdQueryRoot(queryRouter, cdc), + GetCmdQueryClientState(queryRoute, cdc), + GetCmdQueryRoot(queryRoute, cdc), )...) return ics02ClientQueryCmd } // GetCmdQueryClientState defines the command to query the state of a client with // a given id as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#query -func GetCmdQueryClientState(storeKey string, cdc *codec.Codec) *cobra.Command { +func GetCmdQueryClientState(queryRoute string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "state [client-id]", Short: "Query a client state", @@ -64,12 +64,12 @@ $ %s query ibc client state [client-id] return err } - res, _, err := cliCtx.QueryWithData(types.ClientStatePath(clientID), bz) + res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryClientState), bz) if err != nil { return err } - var clientState types.ClientState + var clientState types.State if err := cdc.UnmarshalJSON(res, &clientState); err != nil { return err } @@ -80,7 +80,7 @@ $ %s query ibc client state [client-id] } // GetCmdQueryRoot defines the command to query -func GetCmdQueryRoot(storeKey string, cdc *codec.Codec) *cobra.Command { +func GetCmdQueryRoot(queryRoute string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "root [client-id] [height]", Short: "Query a verified commitment root", @@ -109,7 +109,7 @@ $ %s query ibc client root [client-id] [height] return err } - res, _, err := cliCtx.QueryWithData(types.RootPath(clientID, height), bz) + res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryVerifiedRoot), bz) if err != nil { return err } @@ -126,7 +126,7 @@ $ %s query ibc client root [client-id] [height] // GetCmdQueryConsensusState defines the command to query the consensus state of // the chain as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#query -func GetCmdQueryConsensusState(storeKey string, cdc *codec.Codec) *cobra.Command { +func GetCmdQueryConsensusState(queryRoute string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "consensus-state [client-id]", Short: "Query the latest consensus state of the client", @@ -150,7 +150,7 @@ $ %s query ibc client consensus-state [client-id] return err } - res, _, err := cliCtx.QueryWithData(types.ConsensusStatePath(clientID), bz) + res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryConsensusState), bz) if err != nil { return err } diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go index 71d3bb3eb195..26a0469b1038 100644 --- a/x/ibc/02-client/keeper/client.go +++ b/x/ibc/02-client/keeper/client.go @@ -14,10 +14,10 @@ import ( func (k Keeper) CreateClient( ctx sdk.Context, clientID string, clientTypeStr string, consensusState exported.ConsensusState, -) (types.ClientState, error) { +) (types.State, error) { _, found := k.GetClientState(ctx, clientID) if found { - return types.ClientState{}, types.ErrClientExists(k.codespace, clientID) + return types.State{}, types.ErrClientExists(k.codespace, clientID) } _, found = k.GetClientType(ctx, clientID) @@ -27,7 +27,7 @@ func (k Keeper) CreateClient( clientType := exported.ClientTypeFromStr(clientTypeStr) if clientType == 0 { - return types.ClientState{}, types.ErrInvalidClientType(k.codespace) + return types.State{}, types.ErrInvalidClientType(k.codespace) } clientState := k.initialize(ctx, clientID, consensusState) diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index 1469544ab530..6c5c4f1d1c78 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -41,20 +41,20 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { } // GetClientState gets a particular client from the store -func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (types.ClientState, bool) { +func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (types.State, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := store.Get(types.KeyClientState(clientID)) if bz == nil { - return types.ClientState{}, false + return types.State{}, false } - var clientState types.ClientState + var clientState types.State k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &clientState) return clientState, true } // SetClientState sets a particular Client to the store -func (k Keeper) SetClientState(ctx sdk.Context, clientState types.ClientState) { +func (k Keeper) SetClientState(ctx sdk.Context, clientState types.State) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := k.cdc.MustMarshalBinaryLengthPrefixed(clientState) store.Set(types.KeyClientState(clientState.ID()), bz) @@ -119,9 +119,9 @@ func (k Keeper) SetVerifiedRoot(ctx sdk.Context, clientID string, height uint64, store.Set(types.KeyRoot(clientID, height), bz) } -// ClientState returns a new client state with a given id as defined in +// State returns a new client state with a given id as defined in // https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#example-implementation -func (k Keeper) initialize(ctx sdk.Context, clientID string, consensusState exported.ConsensusState) types.ClientState { +func (k Keeper) initialize(ctx sdk.Context, clientID string, consensusState exported.ConsensusState) types.State { clientState := types.NewClientState(clientID) k.SetConsensusState(ctx, clientID, consensusState) return clientState @@ -143,9 +143,9 @@ func (k Keeper) checkMisbehaviour(ctx sdk.Context, evidence exported.Evidence) e } // freeze updates the state of the client in the event of a misbehaviour -func (k Keeper) freeze(ctx sdk.Context, clientState types.ClientState) (types.ClientState, error) { +func (k Keeper) freeze(ctx sdk.Context, clientState types.State) (types.State, error) { if clientState.Frozen { - return types.ClientState{}, sdkerrors.Wrap(types.ErrClientFrozen(k.codespace, clientState.ID()), "already frozen") + return types.State{}, sdkerrors.Wrap(types.ErrClientFrozen(k.codespace, clientState.ID()), "already frozen") } clientState.Frozen = true @@ -155,7 +155,7 @@ func (k Keeper) freeze(ctx sdk.Context, clientState types.ClientState) (types.Cl // VerifyMembership state membership verification function defined by the client type func (k Keeper) VerifyMembership( ctx sdk.Context, - clientState types.ClientState, + clientState types.State, height uint64, // sequence proof commitmentexported.ProofI, path commitmentexported.PathI, @@ -176,7 +176,7 @@ func (k Keeper) VerifyMembership( // VerifyNonMembership state non-membership function defined by the client type func (k Keeper) VerifyNonMembership( ctx sdk.Context, - clientState types.ClientState, + clientState types.State, height uint64, // sequence proof commitmentexported.ProofI, path commitmentexported.PathI, diff --git a/x/ibc/02-client/types/state.go b/x/ibc/02-client/types/state.go index d900908b0018..8c60260df0a2 100644 --- a/x/ibc/02-client/types/state.go +++ b/x/ibc/02-client/types/state.go @@ -1,8 +1,8 @@ package types -// ClientState is a type that represents the state of a client. +// State is a type that represents the state of a client. // Any actor holding the Stage can access on and modify that client information. -type ClientState struct { +type State struct { // Client ID id string // Boolean that states if the client is frozen when a misbehaviour proof is @@ -11,14 +11,14 @@ type ClientState struct { } // NewClientState creates a new ClientState instance -func NewClientState(id string) ClientState { - return ClientState{ +func NewClientState(id string) State { + return State{ id: id, Frozen: false, } } // ID returns the client identifier -func (cs ClientState) ID() string { - return cs.id +func (s State) ID() string { + return s.id } From f8fd580040fe3635d936d529107e7a80afd8be5f Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Tue, 22 Oct 2019 11:31:52 -0700 Subject: [PATCH 319/378] add tests --- x/ibc/23-commitment/keeper/keeper_test.go | 1 + x/ibc/23-commitment/types/merkle_test.go | 40 +++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 x/ibc/23-commitment/keeper/keeper_test.go create mode 100644 x/ibc/23-commitment/types/merkle_test.go diff --git a/x/ibc/23-commitment/keeper/keeper_test.go b/x/ibc/23-commitment/keeper/keeper_test.go new file mode 100644 index 000000000000..9429264902a9 --- /dev/null +++ b/x/ibc/23-commitment/keeper/keeper_test.go @@ -0,0 +1 @@ +package keeper_test diff --git a/x/ibc/23-commitment/types/merkle_test.go b/x/ibc/23-commitment/types/merkle_test.go new file mode 100644 index 000000000000..1b69f05e5b1e --- /dev/null +++ b/x/ibc/23-commitment/types/merkle_test.go @@ -0,0 +1,40 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/store/iavl" + "github.com/cosmos/cosmos-sdk/store/rootmulti" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + + abci "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tm-db" +) + +func TestVerifyMembership(t *testing.T) { + db := dbm.NewMemDB() + store := rootmulti.NewStore(db) + + iavlStoreKey := storetypes.NewKVStoreKey("iavlStoreKey") + + store.MountStoreWithDB(iavlStoreKey, storetypes.StoreTypeIAVL, nil) + store.LoadVersion(0) + + iavlStore := store.GetCommitStore(iavlStoreKey).(*iavl.Store) + iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE")) + + res := store.Query(abci.RequestQuery{ + Path: "/iavlStoreKey/key", // required path to get key/value+proof + Data: []byte("MYKEY"), + Prove: true, + }) + require.NotNil(t, res.Proof) + + proof := types.Proof{ + Proof: res.Proof, + } + +} From cbc11061006de1cbdf4929eb104036af7e31991e Mon Sep 17 00:00:00 2001 From: Aditya Date: Tue, 22 Oct 2019 17:42:22 -0400 Subject: [PATCH 320/378] ICS 24 Implementation (#5229) * add validation functions * validate path in ics-23 * address @fede comments * move errors into host package --- types/errors/errors.go | 6 +++ x/ibc/23-commitment/keeper/keeper.go | 10 +++- x/ibc/23-commitment/types/merkle.go | 9 +++- x/ibc/24-host/errors.go | 16 ++++++ x/ibc/24-host/validate.go | 74 ++++++++++++++++++++++++++++ 5 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 x/ibc/24-host/errors.go create mode 100644 x/ibc/24-host/validate.go diff --git a/types/errors/errors.go b/types/errors/errors.go index 642c433d90b2..370e6c591469 100644 --- a/types/errors/errors.go +++ b/types/errors/errors.go @@ -65,6 +65,12 @@ var ( // ErrNoSignatures to doc ErrNoSignatures = Register(RootCodespace, 16, "no signatures supplied") + // ErrInvalidId to doc + ErrInvalidID = Register(RootCodespace, 17, "invalid identifier") + + // ErrInvalidPath to doc + ErrInvalidPath = Register(RootCodespace, 18, "invalid path") + // ErrPanic is only set when we recover from a panic, so we know to // redact potentially sensitive system info ErrPanic = Register(UndefinedCodespace, 111222, "panic") diff --git a/x/ibc/23-commitment/keeper/keeper.go b/x/ibc/23-commitment/keeper/keeper.go index 62790e6b83cb..eb1a2dfb8c60 100644 --- a/x/ibc/23-commitment/keeper/keeper.go +++ b/x/ibc/23-commitment/keeper/keeper.go @@ -45,7 +45,10 @@ func (k Keeper) BatchVerifyMembership(ctx sdk.Context, proof exported.ProofI, it continue } - path := types.ApplyPrefix(k.prefix, pathStr) + path, err := types.ApplyPrefix(k.prefix, pathStr) + if err != nil { + return false + } ok = proof.VerifyMembership(root, path, value) if !ok { return false @@ -69,7 +72,10 @@ func (k Keeper) BatchVerifyNonMembership(ctx sdk.Context, proof exported.ProofI, continue } - path := types.ApplyPrefix(k.prefix, pathStr) + path, err := types.ApplyPrefix(k.prefix, pathStr) + if err != nil { + return false + } ok = proof.VerifyNonMembership(root, path) if !ok { return false diff --git a/x/ibc/23-commitment/types/merkle.go b/x/ibc/23-commitment/types/merkle.go index 0a61a997213b..95ac011f9936 100644 --- a/x/ibc/23-commitment/types/merkle.go +++ b/x/ibc/23-commitment/types/merkle.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/rootmulti" "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ) // ICS 023 Merkle Types Implementation @@ -103,13 +104,17 @@ func (p Path) String() string { // // CONTRACT: provided path string MUST be a well formated path. See ICS24 for // reference. -func ApplyPrefix(prefix exported.PrefixI, path string) Path { +func ApplyPrefix(prefix exported.PrefixI, path string) (Path, error) { + err := host.DefaultPathValidator(path) + if err != nil { + return Path{}, err + } // Split paths by the separator pathSlice := strings.Split(path, "/") commitmentPath := NewPath(pathSlice) commitmentPath.KeyPath = commitmentPath.KeyPath.AppendKey(prefix.Bytes(), merkle.KeyEncodingHex) - return commitmentPath + return commitmentPath, nil } var _ exported.ProofI = Proof{} diff --git a/x/ibc/24-host/errors.go b/x/ibc/24-host/errors.go new file mode 100644 index 000000000000..e1fa5e0e7a08 --- /dev/null +++ b/x/ibc/24-host/errors.go @@ -0,0 +1,16 @@ +package host + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// IBCCodeSpace is the codespace for all errors defined in the ibc module +const IBCCodeSpace = "ibc" + +var ( + // ErrInvalidID is returned if identifier string is invalid + ErrInvalidID = sdkerrors.Register(IBCCodeSpace, 1, "invalid identifier") + + // ErrInvalidPath is returned if path string is invalid + ErrInvalidPath = sdkerrors.Register(IBCCodeSpace, 2, "invalid path") +) diff --git a/x/ibc/24-host/validate.go b/x/ibc/24-host/validate.go new file mode 100644 index 000000000000..00dd5f8ba99e --- /dev/null +++ b/x/ibc/24-host/validate.go @@ -0,0 +1,74 @@ +package host + +import ( + "regexp" + "strings" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// ICS 024 Identifier and Path Validation Implementation +// +// This file defines ValidateFn to validate identifier and path strings +// The spec for ICS 024 can be located here: +// https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements + +// regular expression to check string is lowercase alphabetic characters only +var isAlphaLower = regexp.MustCompile(`^[a-z]+$`).MatchString + +// regular expression to check string is alphanumeric +var isAlphaNumeric = regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString + +// ValidateFn function type to validate path and identifier bytestrings +type ValidateFn func(string) error + +// Default validator function for Client, Connection, and Channel +// identifiers +// Valid Identifier must be between 10-20 characters and only +// contain lowercase alphabetic characters +func DefaultIdentifierValidator(id string) error { + // valid id MUST NOT contain "/" separator + if strings.Contains(id, "/") { + return sdkerrors.Wrap(ErrInvalidID, "identifier cannot contain separator: /") + } + // valid id must be between 10 and 20 characters + if len(id) < 10 || len(id) > 20 { + return sdkerrors.Wrapf(ErrInvalidID, "identifier has invalid length: %d, must be between 10-20 characters", len(id)) + } + // valid id must contain only lower alphabetic characters + if !isAlphaLower(id) { + return sdkerrors.Wrap(ErrInvalidID, "identifier must contain only lowercase alphabetic characters") + } + return nil +} + +// NewPathValidator takes in a Identifier Validator function and returns +// a Path Validator function which requires path only has valid identifiers +// alphanumeric character strings, and "/" separators +func NewPathValidator(idValidator ValidateFn) ValidateFn { + return func(path string) error { + pathArr := strings.Split(path, "/") + for _, p := range pathArr { + // Each path element must either be valid identifier or alphanumeric + err := idValidator(p) + if err != nil && !isAlphaNumeric(p) { + return sdkerrors.Wrapf(ErrInvalidPath, "path contains invalid identifier or non-alphanumeric path element: %s", p) + } + } + return nil + } +} + +// Default Path Validator takes in path string and validates +// with default identifier rules. This is optimized by simply +// checking that all path elements are alphanumeric +func DefaultPathValidator(path string) error { + pathArr := strings.Split(path, "/") + for _, p := range pathArr { + // Each path element must either be alphanumeric + if !isAlphaNumeric(p) { + return sdkerrors.Wrapf(ErrInvalidPath, "invalid path element containing non-alphanumeric characters: %s", p) + } + } + return nil +} From 23ae99489ab18b2dbb7dff983e3f557660c2f9c6 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 23 Oct 2019 12:27:12 +0200 Subject: [PATCH 321/378] flatten ICS23 structure --- x/ibc/23-commitment/alias.go | 30 ------- x/ibc/23-commitment/{types => }/codec.go | 11 ++- x/ibc/23-commitment/keeper/keeper.go | 88 ------------------- x/ibc/23-commitment/{types => }/merkle.go | 46 +++++----- .../{exported/exported.go => types.go} | 34 +++++-- x/ibc/23-commitment/types/utils.go | 8 -- x/ibc/23-commitment/verify.go | 62 +++++++++++++ x/ibc/24-host/validate.go | 10 +-- 8 files changed, 122 insertions(+), 167 deletions(-) delete mode 100644 x/ibc/23-commitment/alias.go rename x/ibc/23-commitment/{types => }/codec.go (59%) delete mode 100644 x/ibc/23-commitment/keeper/keeper.go rename x/ibc/23-commitment/{types => }/merkle.go (77%) rename x/ibc/23-commitment/{exported/exported.go => types.go} (69%) delete mode 100644 x/ibc/23-commitment/types/utils.go create mode 100644 x/ibc/23-commitment/verify.go diff --git a/x/ibc/23-commitment/alias.go b/x/ibc/23-commitment/alias.go deleted file mode 100644 index 4c40bbfed20b..000000000000 --- a/x/ibc/23-commitment/alias.go +++ /dev/null @@ -1,30 +0,0 @@ -package commitment - -import ( - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/keeper" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" -) - -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types - -var ( - // functions aliases - NewKeeper = keeper.NewKeeper - RegisterCodec = types.RegisterCodec - NewRoot = types.NewRoot - NewPrefix = types.NewPrefix - NewPath = types.NewPath - ApplyPrefix = types.ApplyPrefix -) - -type ( - Keeper = keeper.Keeper - Root = types.Root - Prefix = types.Prefix - Path = types.Path - Proof = types.Proof -) diff --git a/x/ibc/23-commitment/types/codec.go b/x/ibc/23-commitment/codec.go similarity index 59% rename from x/ibc/23-commitment/types/codec.go rename to x/ibc/23-commitment/codec.go index c2b96c48ad3f..7e90e8cac69e 100644 --- a/x/ibc/23-commitment/types/codec.go +++ b/x/ibc/23-commitment/codec.go @@ -1,16 +1,15 @@ -package types +package commitment import ( "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" ) // RegisterCodec registers types declared in this package func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterInterface((*exported.RootI)(nil), nil) - cdc.RegisterInterface((*exported.PrefixI)(nil), nil) - cdc.RegisterInterface((*exported.PathI)(nil), nil) - cdc.RegisterInterface((*exported.ProofI)(nil), nil) + cdc.RegisterInterface((*RootI)(nil), nil) + cdc.RegisterInterface((*PrefixI)(nil), nil) + cdc.RegisterInterface((*PathI)(nil), nil) + cdc.RegisterInterface((*ProofI)(nil), nil) cdc.RegisterConcrete(Root{}, "ibc/commitment/merkle/Root", nil) cdc.RegisterConcrete(Prefix{}, "ibc/commitment/merkle/Prefix", nil) diff --git a/x/ibc/23-commitment/keeper/keeper.go b/x/ibc/23-commitment/keeper/keeper.go deleted file mode 100644 index eb1a2dfb8c60..000000000000 --- a/x/ibc/23-commitment/keeper/keeper.go +++ /dev/null @@ -1,88 +0,0 @@ -package keeper - -import ( - "bytes" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" -) - -// Keeper defines the IBC commitment keeper (i.e the vector commitment manager). -// A vector commitment manager has the ability to add or remove items from the -// commitment state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-023-vector-commitments#definitions. -type Keeper struct { - prefix exported.PrefixI - verifiedMemberships map[string][]byte // lookup map for returning already verified membership proofs - verifiedAbsences map[string]bool // lookup map for returning already verified absences -} - -// NewKeeper returns a new Keeper -func NewKeeper(prefix exported.PrefixI) Keeper { - return Keeper{ - prefix: prefix, - verifiedMemberships: make(map[string][]byte), - verifiedAbsences: make(map[string]bool), - } -} - -// CalculateRoot returns the application Hash at the curretn block height as a commitment -// root for proof verification. -func (k Keeper) CalculateRoot(ctx sdk.Context) exported.RootI { - return types.NewRoot(ctx.BlockHeader().AppHash) -} - -// BatchVerifyMembership verifies a proof that many paths have been set to -// specific values in a commitment. It calls the proof's VerifyMembership method -// with the calculated root and the provided paths. -// Returns false on the first failed membership verification. -func (k Keeper) BatchVerifyMembership(ctx sdk.Context, proof exported.ProofI, items map[string][]byte) bool { - root := k.CalculateRoot(ctx) - - for pathStr, value := range items { - storedValue, ok := k.verifiedMemberships[pathStr] - if ok && bytes.Equal(storedValue, value) { - continue - } - - path, err := types.ApplyPrefix(k.prefix, pathStr) - if err != nil { - return false - } - ok = proof.VerifyMembership(root, path, value) - if !ok { - return false - } - - k.verifiedMemberships[pathStr] = value - } - - return true -} - -// BatchVerifyNonMembership verifies a proof that many paths have not been set -// to any value in a commitment. It calls the proof's VerifyNonMembership method -// with the calculated root and the provided paths. -// Returns false on the first failed non-membership verification. -func (k Keeper) BatchVerifyNonMembership(ctx sdk.Context, proof exported.ProofI, paths []string) bool { - root := k.CalculateRoot(ctx) - for _, pathStr := range paths { - ok := k.verifiedAbsences[pathStr] - if ok { - continue - } - - path, err := types.ApplyPrefix(k.prefix, pathStr) - if err != nil { - return false - } - ok = proof.VerifyNonMembership(root, path) - if !ok { - return false - } - - k.verifiedAbsences[pathStr] = true - } - - return true -} diff --git a/x/ibc/23-commitment/types/merkle.go b/x/ibc/23-commitment/merkle.go similarity index 77% rename from x/ibc/23-commitment/types/merkle.go rename to x/ibc/23-commitment/merkle.go index 95ac011f9936..980fe0e4247c 100644 --- a/x/ibc/23-commitment/types/merkle.go +++ b/x/ibc/23-commitment/merkle.go @@ -1,4 +1,4 @@ -package types +package commitment import ( "strings" @@ -6,7 +6,6 @@ import ( "github.com/tendermint/tendermint/crypto/merkle" "github.com/cosmos/cosmos-sdk/store/rootmulti" - "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ) @@ -14,12 +13,9 @@ import ( // // This file defines Merkle commitment types that implements ICS 023. -// TODO: use iota -const merkleKind = "merkle" - -// merkle.Proof implementation of Proof +// Merkle proof implementation of the Proof interface // Applied on SDK-based IBC implementation -var _ exported.RootI = Root{} +var _ RootI = Root{} // Root defines a merkle root hash. // In the Cosmos SDK, the AppHash of a block header becomes the Root. @@ -34,9 +30,9 @@ func NewRoot(hash []byte) Root { } } -// CommitmentType implements RootI interface -func (Root) CommitmentType() string { - return merkleKind +// GetCommitmentType implements RootI interface +func (Root) GetCommitmentType() Type { + return Merkle } // GetHash implements RootI interface @@ -44,7 +40,7 @@ func (r Root) GetHash() []byte { return r.Hash } -var _ exported.PrefixI = Prefix{} +var _ PrefixI = Prefix{} // Prefix is merkle path prefixed to the key. // The constructed key from the Path and the key will be append(Path.KeyPath, append(Path.KeyPrefix, key...)) @@ -59,9 +55,9 @@ func NewPrefix(keyPrefix []byte) Prefix { } } -// CommitmentType implements PrefixI -func (Prefix) CommitmentType() string { - return merkleKind +// GetCommitmentType implements PrefixI +func (Prefix) GetCommitmentType() Type { + return Merkle } // Bytes returns the key prefix bytes @@ -69,7 +65,7 @@ func (p Prefix) Bytes() []byte { return p.KeyPrefix } -var _ exported.PathI = Path{} +var _ PathI = Path{} // Path is the path used to verify commitment proofs, which can be an arbitrary // structured object (defined by a commitment type). @@ -89,9 +85,9 @@ func NewPath(keyPathStr []string) Path { } } -// CommitmentType implements PathI -func (Path) CommitmentType() string { - return merkleKind +// GetCommitmentType implements PathI +func (Path) GetCommitmentType() Type { + return Merkle } // String implements fmt.Stringer @@ -104,7 +100,7 @@ func (p Path) String() string { // // CONTRACT: provided path string MUST be a well formated path. See ICS24 for // reference. -func ApplyPrefix(prefix exported.PrefixI, path string) (Path, error) { +func ApplyPrefix(prefix PrefixI, path string) (Path, error) { err := host.DefaultPathValidator(path) if err != nil { return Path{}, err @@ -117,7 +113,7 @@ func ApplyPrefix(prefix exported.PrefixI, path string) (Path, error) { return commitmentPath, nil } -var _ exported.ProofI = Proof{} +var _ ProofI = Proof{} // Proof is a wrapper type that contains a merkle proof. // It demonstrates membership or non-membership for an element or set of elements, @@ -127,20 +123,20 @@ type Proof struct { Proof *merkle.Proof `json:"proof" yaml:"proof"` } -// CommitmentType implements ProofI -func (Proof) CommitmentType() string { - return merkleKind +// GetCommitmentType implements ProofI +func (Proof) GetCommitmentType() Type { + return Merkle } // VerifyMembership verifies the membership pf a merkle proof against the given root, path, and value. -func (proof Proof) VerifyMembership(root exported.RootI, path exported.PathI, value []byte) bool { +func (proof Proof) VerifyMembership(root RootI, path PathI, value []byte) bool { runtime := rootmulti.DefaultProofRuntime() err := runtime.VerifyValue(proof.Proof, root.GetHash(), path.String(), value) return err == nil } // VerifyNonMembership verifies the absence of a merkle proof against the given root and path. -func (proof Proof) VerifyNonMembership(root exported.RootI, path exported.PathI) bool { +func (proof Proof) VerifyNonMembership(root RootI, path PathI) bool { runtime := rootmulti.DefaultProofRuntime() err := runtime.VerifyAbsence(proof.Proof, root.GetHash(), path.String()) return err == nil diff --git a/x/ibc/23-commitment/exported/exported.go b/x/ibc/23-commitment/types.go similarity index 69% rename from x/ibc/23-commitment/exported/exported.go rename to x/ibc/23-commitment/types.go index 9e0d8d0ef776..af33cd0b7f99 100644 --- a/x/ibc/23-commitment/exported/exported.go +++ b/x/ibc/23-commitment/types.go @@ -1,4 +1,4 @@ -package exported +package commitment // ICS 023 Types Implementation // @@ -12,21 +12,21 @@ package exported // and the inclusion or non-inclusion of an arbitrary key-value pair // can be proven with the proof. type RootI interface { - CommitmentType() string + GetCommitmentType() Type GetHash() []byte } // PrefixI implements spec:CommitmentPrefix. // Prefix represents the common "prefix" that a set of keys shares. type PrefixI interface { - CommitmentType() string + GetCommitmentType() Type Bytes() []byte } // PathI implements spec:CommitmentPath. // A path is the additional information provided to the verification function. type PathI interface { - CommitmentType() string + GetCommitmentType() Type String() string } @@ -35,7 +35,31 @@ type PathI interface { // Each proof has designated key-value pair it is able to prove. // Proofs includes key but value is provided dynamically at the verification time. type ProofI interface { - CommitmentType() string + GetCommitmentType() Type VerifyMembership(RootI, PathI, []byte) bool VerifyNonMembership(RootI, PathI) bool } + +// Type defines the type of the commitment +type Type byte + +// Registered commitment types +const ( + Merkle Type = iota + 1 // 1 +) + +// Client types +const ( + TypeMerkle string = "merkle" +) + +// TypeToString returns the string representation of a client type +func TypeToString(commitmentType Type) string { + switch commitmentType { + case Merkle: + return TypeMerkle + + default: + return "" + } +} diff --git a/x/ibc/23-commitment/types/utils.go b/x/ibc/23-commitment/types/utils.go deleted file mode 100644 index a53ca19812bd..000000000000 --- a/x/ibc/23-commitment/types/utils.go +++ /dev/null @@ -1,8 +0,0 @@ -package types - -func join(a, b []byte) (res []byte) { - res = make([]byte, len(a)+len(b)) - copy(res, a) - copy(res[len(a):], b) - return -} diff --git a/x/ibc/23-commitment/verify.go b/x/ibc/23-commitment/verify.go new file mode 100644 index 000000000000..7c620c2b5a90 --- /dev/null +++ b/x/ibc/23-commitment/verify.go @@ -0,0 +1,62 @@ +package commitment + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// CalculateRoot returns the application Hash at the curretn block height as a commitment +// root for proof verification. +func CalculateRoot(ctx sdk.Context) RootI { + return NewRoot(ctx.BlockHeader().AppHash) +} + +// BatchVerifyMembership verifies a proof that many paths have been set to +// specific values in a commitment. It calls the proof's VerifyMembership method +// with the calculated root and the provided paths. +// Returns false on the first failed membership verification. +func BatchVerifyMembership( + ctx sdk.Context, + proof ProofI, + prefix PrefixI, + items map[string][]byte, +) bool { + root := CalculateRoot(ctx) + + for pathStr, value := range items { + path, err := ApplyPrefix(prefix, pathStr) + if err != nil { + return false + } + + if ok := proof.VerifyMembership(root, path, value); !ok { + return false + } + } + + return true +} + +// BatchVerifyNonMembership verifies a proof that many paths have not been set +// to any value in a commitment. It calls the proof's VerifyNonMembership method +// with the calculated root and the provided paths. +// Returns false on the first failed non-membership verification. +func BatchVerifyNonMembership( + ctx sdk.Context, + proof ProofI, + prefix PrefixI, + paths []string, +) bool { + root := CalculateRoot(ctx) + for _, pathStr := range paths { + path, err := ApplyPrefix(prefix, pathStr) + if err != nil { + return false + } + + if ok := proof.VerifyNonMembership(root, path); !ok { + return false + } + } + + return true +} diff --git a/x/ibc/24-host/validate.go b/x/ibc/24-host/validate.go index 00dd5f8ba99e..38128de234ae 100644 --- a/x/ibc/24-host/validate.go +++ b/x/ibc/24-host/validate.go @@ -22,10 +22,10 @@ var isAlphaNumeric = regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString // ValidateFn function type to validate path and identifier bytestrings type ValidateFn func(string) error -// Default validator function for Client, Connection, and Channel -// identifiers -// Valid Identifier must be between 10-20 characters and only -// contain lowercase alphabetic characters +// DefaultIdentifierValidator is the default validator function for Client, +// Connection and Channel identifiers. +// A valid Identifier must be between 10-20 characters and only contain lowercase +// alphabetic characters, func DefaultIdentifierValidator(id string) error { // valid id MUST NOT contain "/" separator if strings.Contains(id, "/") { @@ -59,7 +59,7 @@ func NewPathValidator(idValidator ValidateFn) ValidateFn { } } -// Default Path Validator takes in path string and validates +// DefaultPathValidator takes in path string and validates // with default identifier rules. This is optimized by simply // checking that all path elements are alphanumeric func DefaultPathValidator(path string) error { From e1fa5f8b884f0d1e3897f977076e13fc0f12bade Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 23 Oct 2019 12:34:14 +0200 Subject: [PATCH 322/378] fix ApplyPrefix --- x/ibc/23-commitment/merkle.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x/ibc/23-commitment/merkle.go b/x/ibc/23-commitment/merkle.go index 980fe0e4247c..0f161f01ba7f 100644 --- a/x/ibc/23-commitment/merkle.go +++ b/x/ibc/23-commitment/merkle.go @@ -107,9 +107,11 @@ func ApplyPrefix(prefix PrefixI, path string) (Path, error) { } // Split paths by the separator pathSlice := strings.Split(path, "/") + keyPath := merkle.KeyPath{} commitmentPath := NewPath(pathSlice) - commitmentPath.KeyPath = commitmentPath.KeyPath.AppendKey(prefix.Bytes(), merkle.KeyEncodingHex) + keyPath = keyPath.AppendKey(prefix.Bytes(), merkle.KeyEncodingHex) + commitmentPath.KeyPath = append(keyPath, commitmentPath.KeyPath...) return commitmentPath, nil } From 4f896026fb5ed0fbee701c4bdeb50a788d440861 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 23 Oct 2019 16:48:55 +0200 Subject: [PATCH 323/378] updates from ICS23 and ICS24 --- x/ibc/02-client/client/cli/query.go | 4 ++-- x/ibc/02-client/exported/exported.go | 4 ++-- x/ibc/02-client/keeper/keeper.go | 16 ++++++++-------- .../types/tendermint/consensus_state.go | 11 +++++------ 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 9fbecbd2aebd..9bd992b5d939 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -17,7 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // GetQueryCmd returns the query commands for IBC clients @@ -114,7 +114,7 @@ $ %s query ibc client root [client-id] [height] return err } - var root commitmentexported.RootI + var root commitment.RootI if err := cdc.UnmarshalJSON(res, &root); err != nil { return err } diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index 05db3902130f..dcab60459283 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -3,7 +3,7 @@ package exported import ( "fmt" - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // Blockchain is consensus algorithm which generates valid Headers. It generates @@ -21,7 +21,7 @@ type ConsensusState interface { // GetRoot returns the commitment root of the consensus state, // which is used for key-value pair verification. - GetRoot() commitmentexported.RootI + GetRoot() commitment.RootI // CheckValidityAndUpdateState returns the updated consensus state // only if the header is a descendent of this consensus state. diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index 6c5c4f1d1c78..c9495758cbfc 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -99,21 +99,21 @@ func (k Keeper) SetConsensusState(ctx sdk.Context, clientID string, consensusSta // GetVerifiedRoot gets a verified commitment Root from a particular height to // a client -func (k Keeper) GetVerifiedRoot(ctx sdk.Context, clientID string, height uint64) (commitmentexported.RootI, bool) { +func (k Keeper) GetVerifiedRoot(ctx sdk.Context, clientID string, height uint64) (commitment.RootI, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := store.Get(types.KeyRoot(clientID, height)) if bz == nil { return nil, false } - var root commitmentexported.RootI + var root commitment.RootI k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &root) return root, true } // SetVerifiedRoot sets a verified commitment Root from a particular height to // a client -func (k Keeper) SetVerifiedRoot(ctx sdk.Context, clientID string, height uint64, root commitmentexported.RootI) { +func (k Keeper) SetVerifiedRoot(ctx sdk.Context, clientID string, height uint64, root commitment.RootI) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := k.cdc.MustMarshalBinaryLengthPrefixed(root) store.Set(types.KeyRoot(clientID, height), bz) @@ -157,8 +157,8 @@ func (k Keeper) VerifyMembership( ctx sdk.Context, clientState types.State, height uint64, // sequence - proof commitmentexported.ProofI, - path commitmentexported.PathI, + proof commitment.ProofI, + path commitment.PathI, value []byte, ) bool { if clientState.Frozen { @@ -178,8 +178,8 @@ func (k Keeper) VerifyNonMembership( ctx sdk.Context, clientState types.State, height uint64, // sequence - proof commitmentexported.ProofI, - path commitmentexported.PathI, + proof commitment.ProofI, + path commitment.PathI, ) bool { if clientState.Frozen { return false diff --git a/x/ibc/02-client/types/tendermint/consensus_state.go b/x/ibc/02-client/types/tendermint/consensus_state.go index 2f8ce8abbc84..74e8a9f42dfa 100644 --- a/x/ibc/02-client/types/tendermint/consensus_state.go +++ b/x/ibc/02-client/types/tendermint/consensus_state.go @@ -9,17 +9,16 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" ) var _ exported.ConsensusState = ConsensusState{} // ConsensusState defines a Tendermint consensus state type ConsensusState struct { - ChainID string `json:"chain_id" yaml:"chain_id"` - Height uint64 `json:"height" yaml:"height"` // NOTE: defined as 'sequence' in the spec - Root commitmentexported.RootI `json:"root" yaml:"root"` - NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` // contains the PublicKey + ChainID string `json:"chain_id" yaml:"chain_id"` + Height uint64 `json:"height" yaml:"height"` // NOTE: defined as 'sequence' in the spec + Root commitment.RootI `json:"root" yaml:"root"` + NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` // contains the PublicKey } // ClientType returns Tendermint @@ -33,7 +32,7 @@ func (cs ConsensusState) GetHeight() uint64 { } // GetRoot returns the commitment Root for the specific -func (cs ConsensusState) GetRoot() commitmentexported.RootI { +func (cs ConsensusState) GetRoot() commitment.RootI { return cs.Root } From 22f874a8b9e6cdbda4f8fc0ca143d2719f398462 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 23 Oct 2019 18:18:23 +0200 Subject: [PATCH 324/378] msg.ValidateBasic and ADR09 evidence interface --- x/ibc/02-client/exported/exported.go | 39 +++++++++++-------- x/ibc/02-client/keeper/keeper.go | 26 ++++++------- x/ibc/02-client/types/codec.go | 1 + x/ibc/02-client/types/errors.go | 12 ++++++ x/ibc/02-client/types/msgs.go | 27 +++++++++++-- x/ibc/02-client/types/tendermint/header.go | 19 --------- .../types/tendermint/misbehaviour.go | 3 +- 7 files changed, 74 insertions(+), 53 deletions(-) diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index dcab60459283..d482a54553d8 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -1,7 +1,7 @@ package exported import ( - "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -28,11 +28,25 @@ type ConsensusState interface { CheckValidityAndUpdateState(Header) (ConsensusState, error) } -// Evidence contains two disctict headers used to submit client equivocation -// TODO: use evidence module type +// Evidence from ADR 009: Evidence Module +// TODO: use evidence module interface once merged type Evidence interface { - H1() Header - H2() Header + Route() string + Type() string + String() string + ValidateBasic() sdk.Error + + // The consensus address of the malicious validator at time of infraction + GetConsensusAddress() sdk.ConsAddress + + // Height at which the infraction occurred + GetHeight() int64 + + // The total power of the malicious validator at time of infraction + GetValidatorPower() int64 + + // The total validator set power at time of infraction + GetTotalPower() int64 } // Misbehaviour defines a specific consensus kind and an evidence @@ -60,18 +74,9 @@ const ( Tendermint ClientType = iota + 1 // 1 ) -var validClientTypes = map[string]struct{}{ - ClientTypeTendermint: {}, -} - -// RegisterClientType registers a client type. It will panic if the type is -// already registered. -func RegisterClientType(ty string) { - if _, ok := validClientTypes[ty]; ok { - panic(fmt.Sprintf("already registered client type: %s", ty)) - } - - validClientTypes[ty] = struct{}{} +// ValidClientTypes returns the registerd client types for this chain +var ValidClientTypes = map[string]bool{ + ClientTypeTendermint: true, } // ClientTypeFromStr returns a byte that corresponds to the registered client diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index c9495758cbfc..d0c45f0a6ffd 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -11,7 +11,6 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -128,18 +127,19 @@ func (k Keeper) initialize(ctx sdk.Context, clientID string, consensusState expo } func (k Keeper) checkMisbehaviour(ctx sdk.Context, evidence exported.Evidence) error { - switch evidence.H1().ClientType() { - case exported.Tendermint: - var tmEvidence tendermint.Evidence - _, ok := evidence.(tendermint.Evidence) - if !ok { - return sdkerrors.Wrap(types.ErrInvalidClientType(k.codespace), "consensus type is not Tendermint") - } - // TODO: pass past consensus states - return tendermint.CheckMisbehaviour(tmEvidence) - default: - panic("unregistered consensus type") - } + // switch evidence.H1().ClientType() { + // case exported.Tendermint: + // var tmEvidence tendermint.Evidence + // _, ok := evidence.(tendermint.Evidence) + // if !ok { + // return sdkerrors.Wrap(types.ErrInvalidClientType(k.codespace), "consensus type is not Tendermint") + // } + // // TODO: pass past consensus states + // return tendermint.CheckMisbehaviour(tmEvidence) + // default: + // panic("unregistered consensus type") + // } + return nil } // freeze updates the state of the client in the event of a misbehaviour diff --git a/x/ibc/02-client/types/codec.go b/x/ibc/02-client/types/codec.go index c556850a0ca2..eae86ec2b53d 100644 --- a/x/ibc/02-client/types/codec.go +++ b/x/ibc/02-client/types/codec.go @@ -12,6 +12,7 @@ var SubModuleCdc *codec.Codec func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*exported.Blockchain)(nil), nil) cdc.RegisterInterface((*exported.ConsensusState)(nil), nil) + cdc.RegisterInterface((*exported.Evidence)(nil), nil) cdc.RegisterInterface((*exported.Header)(nil), nil) cdc.RegisterInterface((*exported.Misbehaviour)(nil), nil) diff --git a/x/ibc/02-client/types/errors.go b/x/ibc/02-client/types/errors.go index 282e697d3bce..b6f8a84c9aa9 100644 --- a/x/ibc/02-client/types/errors.go +++ b/x/ibc/02-client/types/errors.go @@ -18,6 +18,8 @@ const ( CodeClientTypeNotFound sdk.CodeType = 106 CodeInvalidClientType sdk.CodeType = 107 CodeRootNotFound sdk.CodeType = 108 + CodeInvalidHeader sdk.CodeType = 109 + CodeInvalidEvidence sdk.CodeType = 110 ) // ErrClientExists implements sdk.Error @@ -59,3 +61,13 @@ func ErrInvalidClientType(codespace sdk.CodespaceType) sdk.Error { func ErrRootNotFound(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeRootNotFound, "commitment root not found") } + +// ErrInvalidHeader implements sdk.Error +func ErrInvalidHeader(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidHeader, "invalid header") +} + +// ErrInvalidEvidence implements sdk.Error +func ErrInvalidEvidence(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidEvidence, "invalid evidence") +} diff --git a/x/ibc/02-client/types/msgs.go b/x/ibc/02-client/types/msgs.go index 17e1848cd577..450b7f99c86e 100644 --- a/x/ibc/02-client/types/msgs.go +++ b/x/ibc/02-client/types/msgs.go @@ -1,8 +1,11 @@ package types import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -41,7 +44,15 @@ func (msg MsgCreateClient) ValidateBasic() sdk.Error { if msg.Signer.Empty() { return sdk.ErrInvalidAddress("empty address") } - // TODO: validate client type and ID + if err := host.DefaultIdentifierValidator(msg.ClientID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid client ID: %s", err.Error())) + } + if !exported.ValidClientTypes[msg.ClientType] { + return ErrInvalidClientType(DefaultCodespace) + } + if msg.ConsensusState == nil { + return ErrInvalidConsensus(DefaultCodespace) + } return nil } @@ -88,7 +99,12 @@ func (msg MsgUpdateClient) ValidateBasic() sdk.Error { if msg.Signer.Empty() { return sdk.ErrInvalidAddress("empty address") } - // TODO: validate client ID + if err := host.DefaultIdentifierValidator(msg.ClientID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid client ID: %s", err.Error())) + } + if msg.Header == nil { + return ErrInvalidHeader(DefaultCodespace) + } return nil } @@ -133,7 +149,12 @@ func (msg MsgSubmitMisbehaviour) ValidateBasic() sdk.Error { if msg.Signer.Empty() { return sdk.ErrInvalidAddress("empty address") } - // TODO: validate client ID + if err := host.DefaultIdentifierValidator(msg.ClientID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid client ID: %s", err.Error())) + } + if msg.Evidence == nil { + return ErrInvalidEvidence(DefaultCodespace) + } return nil } diff --git a/x/ibc/02-client/types/tendermint/header.go b/x/ibc/02-client/types/tendermint/header.go index 9d6178cc2d7f..62202b1e6b02 100644 --- a/x/ibc/02-client/types/tendermint/header.go +++ b/x/ibc/02-client/types/tendermint/header.go @@ -27,22 +27,3 @@ func (h Header) ClientType() exported.ClientType { func (h Header) GetHeight() uint64 { return uint64(h.Height) } - -var _ exported.Evidence = Evidence{} - -// Evidence defines two disctinct Tendermint headers used to submit a client misbehaviour -// TODO: use evidence module's types -type Evidence struct { - Header1 Header `json:"header_one" yaml:"header_one"` - Header2 Header `json:"header_two" yaml:"header_two"` -} - -// H1 returns the first header -func (e Evidence) H1() exported.Header { - return e.Header1 -} - -// H2 returns the second header -func (e Evidence) H2() exported.Header { - return e.Header2 -} diff --git a/x/ibc/02-client/types/tendermint/misbehaviour.go b/x/ibc/02-client/types/tendermint/misbehaviour.go index 15787450e4ca..229a0ab36967 100644 --- a/x/ibc/02-client/types/tendermint/misbehaviour.go +++ b/x/ibc/02-client/types/tendermint/misbehaviour.go @@ -2,10 +2,11 @@ package tendermint import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ) // CheckMisbehaviour checks if the evidence provided is a misbehaviour -func CheckMisbehaviour(evidence Evidence) sdk.Error { +func CheckMisbehaviour(evidence exported.Evidence) sdk.Error { // TODO: check evidence return nil } From 2edb03fdee729e8af413288dedef62eecfc0cec9 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Wed, 23 Oct 2019 11:55:00 -0700 Subject: [PATCH 325/378] complete types testing --- x/ibc/23-commitment/types/merkle.go | 17 +++-- x/ibc/23-commitment/types/merkle_test.go | 92 ++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 4 deletions(-) diff --git a/x/ibc/23-commitment/types/merkle.go b/x/ibc/23-commitment/types/merkle.go index 0a89c58e682b..7b0fe28e8d35 100644 --- a/x/ibc/23-commitment/types/merkle.go +++ b/x/ibc/23-commitment/types/merkle.go @@ -80,7 +80,7 @@ type Path struct { func NewPath(keyPathStr []string) Path { merkleKeyPath := merkle.KeyPath{} for _, keyStr := range keyPathStr { - merkleKeyPath = merkleKeyPath.AppendKey([]byte(keyStr), merkle.KeyEncodingHex) + merkleKeyPath = merkleKeyPath.AppendKey([]byte(keyStr), merkle.KeyEncodingURL) } return Path{ @@ -106,10 +106,19 @@ func (p Path) String() string { func ApplyPrefix(prefix exported.PrefixI, path string) Path { // Split paths by the separator pathSlice := strings.Split(path, "/") - commitmentPath := NewPath(pathSlice) + merkleKeyPath := merkle.KeyPath{} + + // append prefix first + merkleKeyPath = merkleKeyPath.AppendKey(prefix.Bytes(), merkle.KeyEncodingURL) + + // append all path elements after + for _, keyStr := range pathSlice { + merkleKeyPath = merkleKeyPath.AppendKey([]byte(keyStr), merkle.KeyEncodingURL) + } - commitmentPath.KeyPath = commitmentPath.KeyPath.AppendKey(prefix.Bytes(), merkle.KeyEncodingHex) - return commitmentPath + return Path{ + KeyPath: merkleKeyPath, + } } var _ exported.ProofI = Proof{} diff --git a/x/ibc/23-commitment/types/merkle_test.go b/x/ibc/23-commitment/types/merkle_test.go index 1b69f05e5b1e..10e8158bffce 100644 --- a/x/ibc/23-commitment/types/merkle_test.go +++ b/x/ibc/23-commitment/types/merkle_test.go @@ -25,6 +25,7 @@ func TestVerifyMembership(t *testing.T) { iavlStore := store.GetCommitStore(iavlStoreKey).(*iavl.Store) iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE")) + cid := store.Commit() res := store.Query(abci.RequestQuery{ Path: "/iavlStoreKey/key", // required path to get key/value+proof @@ -37,4 +38,95 @@ func TestVerifyMembership(t *testing.T) { Proof: res.Proof, } + cases := []struct { + root []byte + pathArr []string + value []byte + shouldPass bool + errString string + }{ + {cid.Hash, []string{"iavlStoreKey", "MYKEY"}, []byte("MYVALUE"), true, "valid membership proof failed"}, // valid proof + {cid.Hash, []string{"iavlStoreKey", "MYKEY"}, []byte("WRONGVALUE"), false, "invalid membership proof with wrong value passed"}, // invalid proof with wrong value + {cid.Hash, []string{"iavlStoreKey", "MYKEY"}, []byte(nil), false, "invalid membership proof with wrong value passed"}, // invalid proof with nil value + {cid.Hash, []string{"iavlStoreKey", "NOTMYKEY"}, []byte("MYVALUE"), false, "invalid membership proof with wrong key passed"}, // invalid proof with wrong key + {cid.Hash, []string{"iavlStoreKey", "MYKEY", "MYKEY"}, []byte("MYVALUE"), false, "invalid membership proof with wrong path passed"}, // invalid proof with wrong path + {cid.Hash, []string{"iavlStoreKey"}, []byte("MYVALUE"), false, "invalid membership proof with wrong path passed"}, // invalid proof with wrong path + {cid.Hash, []string{"MYKEY"}, []byte("MYVALUE"), false, "invalid membership proof with wrong path passed"}, // invalid proof with wrong path + {cid.Hash, []string{"otherStoreKey", "MYKEY"}, []byte("MYVALUE"), false, "invalid membership proof with wrong store prefix passed"}, // invalid proof with wrong store prefix + {[]byte("WRONGROOT"), []string{"iavlStoreKey", "MYKEY"}, []byte("MYVALUE"), false, "invalid membership proof with wrong root passed"}, // invalid proof with wrong root + {[]byte(nil), []string{"iavlStoreKey", "MYKEY"}, []byte("MYVALUE"), false, "invalid membership proof with nil root passed"}, // invalid proof with nil root + } + + for i, tc := range cases { + root := types.NewRoot(tc.root) + path := types.NewPath(tc.pathArr) + + ok := proof.VerifyMembership(root, path, tc.value) + + require.True(t, ok == tc.shouldPass, "Test case %d failed: %s", i, tc.errString) + } + +} + +func TestVerifyNonMembership(t *testing.T) { + db := dbm.NewMemDB() + store := rootmulti.NewStore(db) + + iavlStoreKey := storetypes.NewKVStoreKey("iavlStoreKey") + + store.MountStoreWithDB(iavlStoreKey, storetypes.StoreTypeIAVL, nil) + store.LoadVersion(0) + + iavlStore := store.GetCommitStore(iavlStoreKey).(*iavl.Store) + iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE")) + cid := store.Commit() + + // Get Proof + res := store.Query(abci.RequestQuery{ + Path: "/iavlStoreKey/key", // required path to get key/value+proof + Data: []byte("MYABSENTKEY"), + Prove: true, + }) + require.NotNil(t, res.Proof) + + proof := types.Proof{ + Proof: res.Proof, + } + + cases := []struct { + root []byte + pathArr []string + shouldPass bool + errString string + }{ + {cid.Hash, []string{"iavlStoreKey", "MYABSENTKEY"}, true, "valid non-membership proof failed"}, // valid proof + {cid.Hash, []string{"iavlStoreKey", "MYKEY"}, false, "invalid non-membership proof with wrong key passed"}, // invalid proof with existent key + {cid.Hash, []string{"iavlStoreKey", "MYKEY", "MYABSENTKEY"}, false, "invalid non-membership proof with wrong path passed"}, // invalid proof with wrong path + {cid.Hash, []string{"iavlStoreKey", "MYABSENTKEY", "MYKEY"}, false, "invalid non-membership proof with wrong path passed"}, // invalid proof with wrong path + {cid.Hash, []string{"iavlStoreKey"}, false, "invalid non-membership proof with wrong path passed"}, // invalid proof with wrong path + {cid.Hash, []string{"MYABSENTKEY"}, false, "invalid non-membership proof with wrong path passed"}, // invalid proof with wrong path + {cid.Hash, []string{"otherStoreKey", "MYABSENTKEY"}, false, "invalid non-membership proof with wrong store prefix passed"}, // invalid proof with wrong store prefix + {[]byte("WRONGROOT"), []string{"iavlStoreKey", "MYABSENTKEY"}, false, "invalid non-membership proof with wrong root passed"}, // invalid proof with wrong root + {[]byte(nil), []string{"iavlStoreKey", "MYABSENTKEY"}, false, "invalid non-membership proof with nil root passed"}, // invalid proof with nil root + } + + for i, tc := range cases { + root := types.NewRoot(tc.root) + path := types.NewPath(tc.pathArr) + + ok := proof.VerifyNonMembership(root, path) + + require.True(t, ok == tc.shouldPass, "Test case %d failed: %s", i, tc.errString) + } + +} + +func TestApplyPrefix(t *testing.T) { + prefix := types.NewPrefix([]byte("storePrefixKey")) + + pathStr := "path1/path2/path3/key" + + prefixedPath := types.ApplyPrefix(prefix, pathStr) + + require.Equal(t, "/storePrefixKey/path1/path2/path3/key", prefixedPath.String(), "Prefixed path incorrect") } From 696db2e9d3847caffdf58f5479e0a36b7136708b Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Wed, 23 Oct 2019 12:42:54 -0700 Subject: [PATCH 326/378] delete empty test file --- x/ibc/23-commitment/keeper/keeper_test.go | 1 - 1 file changed, 1 deletion(-) delete mode 100644 x/ibc/23-commitment/keeper/keeper_test.go diff --git a/x/ibc/23-commitment/keeper/keeper_test.go b/x/ibc/23-commitment/keeper/keeper_test.go deleted file mode 100644 index 9429264902a9..000000000000 --- a/x/ibc/23-commitment/keeper/keeper_test.go +++ /dev/null @@ -1 +0,0 @@ -package keeper_test From 69db1f2902ff3a1a1272bef392caf794d8e8b681 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Wed, 23 Oct 2019 12:44:29 -0700 Subject: [PATCH 327/378] remove ibc errors from core error package --- types/errors/errors.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/types/errors/errors.go b/types/errors/errors.go index 370e6c591469..642c433d90b2 100644 --- a/types/errors/errors.go +++ b/types/errors/errors.go @@ -65,12 +65,6 @@ var ( // ErrNoSignatures to doc ErrNoSignatures = Register(RootCodespace, 16, "no signatures supplied") - // ErrInvalidId to doc - ErrInvalidID = Register(RootCodespace, 17, "invalid identifier") - - // ErrInvalidPath to doc - ErrInvalidPath = Register(RootCodespace, 18, "invalid path") - // ErrPanic is only set when we recover from a panic, so we know to // redact potentially sensitive system info ErrPanic = Register(UndefinedCodespace, 111222, "panic") From 021544f50d1b4c2e2e6915bfffdbc9c212c72794 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 24 Oct 2019 14:57:48 +0200 Subject: [PATCH 328/378] custom JSON marshaling; msg.ValidateBasic; renaming of variables --- x/ibc/03-connection/alias.go | 6 +- x/ibc/03-connection/keeper/handshake.go | 12 +- x/ibc/03-connection/keeper/keeper.go | 34 +++--- x/ibc/03-connection/keeper/querier.go | 21 +--- x/ibc/03-connection/types/connection.go | 107 +++++++++++++----- x/ibc/03-connection/types/errors.go | 12 ++ x/ibc/03-connection/types/expected_keepers.go | 12 +- x/ibc/03-connection/types/msgs.go | 91 +++++++++------ x/ibc/24-host/utils.go | 11 ++ x/ibc/keeper/querier.go | 8 +- 10 files changed, 198 insertions(+), 116 deletions(-) create mode 100644 x/ibc/24-host/utils.go diff --git a/x/ibc/03-connection/alias.go b/x/ibc/03-connection/alias.go index fcc82b49dad1..0b8513f561bb 100644 --- a/x/ibc/03-connection/alias.go +++ b/x/ibc/03-connection/alias.go @@ -32,6 +32,8 @@ const ( var ( // functions aliases NewKeeper = keeper.NewKeeper + QuerierConnection = keeper.QuerierConnection + QuerierClientConnections = keeper.QuerierClientConnections RegisterCodec = types.RegisterCodec SetMsgConnectionCodec = types.SetMsgConnectionCodec NewConnectionEnd = types.NewConnectionEnd @@ -63,8 +65,8 @@ var ( type ( Keeper = keeper.Keeper - ConnectionState = types.ConnectionState - ConnectionEnd = types.ConnectionEnd + State = types.State + End = types.ConnectionEnd Counterparty = types.Counterparty ClientKeeper = types.ClientKeeper MsgConnectionOpenInit = types.MsgConnectionOpenInit diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index c9ca7c350d0d..e833fb90656b 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -8,7 +8,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // ConnOpenInit initialises a connection attempt on chain A. @@ -50,7 +50,7 @@ func (k Keeper) ConnOpenTry( counterparty types.Counterparty, // counterpartyConnectionIdentifier, counterpartyPrefix and counterpartyClientIdentifier clientID string, counterpartyVersions []string, - proofInit commitmentexported.ProofI, + proofInit commitment.ProofI, proofHeight uint64, consensusHeight uint64, ) error { @@ -125,7 +125,7 @@ func (k Keeper) ConnOpenAck( ctx sdk.Context, connectionID string, version string, - proofTry commitmentexported.ProofI, + proofTry commitment.ProofI, proofHeight uint64, consensusHeight uint64, ) error { @@ -141,7 +141,7 @@ func (k Keeper) ConnOpenAck( if connection.State != types.INIT { return types.ErrInvalidConnectionState( k.codespace, - fmt.Sprintf("connection state is not INIT (got %s)", types.ConnectionStateToString(connection.State)), + fmt.Sprintf("connection state is not INIT (got %s)", connection.State.String()), ) } @@ -201,7 +201,7 @@ func (k Keeper) ConnOpenAck( func (k Keeper) ConnOpenConfirm( ctx sdk.Context, connectionID string, - proofAck commitmentexported.ProofI, + proofAck commitment.ProofI, proofHeight uint64, ) error { connection, found := k.GetConnection(ctx, connectionID) @@ -212,7 +212,7 @@ func (k Keeper) ConnOpenConfirm( if connection.State != types.TRYOPEN { return types.ErrInvalidConnectionState( k.codespace, - fmt.Sprintf("connection state is not TRYOPEN (got %s)", types.ConnectionStateToString(connection.State)), + fmt.Sprintf("connection state is not TRYOPEN (got %s)", connection.State.String()), ) } diff --git a/x/ibc/03-connection/keeper/keeper.go b/x/ibc/03-connection/keeper/keeper.go index c4a888678bc9..222ee0fc63e5 100644 --- a/x/ibc/03-connection/keeper/keeper.go +++ b/x/ibc/03-connection/keeper/keeper.go @@ -10,7 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -42,7 +42,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { // GetCommitmentPrefix returns the IBC connection store prefix as a commitment // Prefix -func (k Keeper) GetCommitmentPrefix() commitmentexported.PrefixI { +func (k Keeper) GetCommitmentPrefix() commitment.PrefixI { return commitment.NewPrefix(k.prefix) } @@ -112,7 +112,7 @@ func (k Keeper) removeConnectionFromClient(ctx sdk.Context, clientID, connection return types.ErrClientConnectionPathsNotFound(k.codespace, clientID) } - conns, ok := removePath(conns, connectionID) + conns, ok := host.RemovePath(conns, connectionID) if !ok { return types.ErrConnectionPath(k.codespace) } @@ -126,7 +126,7 @@ func (k Keeper) VerifyMembership( ctx sdk.Context, connection types.ConnectionEnd, height uint64, - proof commitmentexported.ProofI, + proof commitment.ProofI, pathStr string, value []byte, ) bool { @@ -134,7 +134,11 @@ func (k Keeper) VerifyMembership( if !found { return false } - path := commitment.ApplyPrefix(connection.Counterparty.Prefix, pathStr) + path, err := commitment.ApplyPrefix(connection.Counterparty.Prefix, pathStr) + if err != nil { + return false + } + return k.clientKeeper.VerifyMembership(ctx, clientState, height, proof, path, value) } @@ -143,7 +147,7 @@ func (k Keeper) VerifyNonMembership( ctx sdk.Context, connection types.ConnectionEnd, height uint64, - proof commitmentexported.ProofI, + proof commitment.ProofI, pathStr string, ) bool { clientState, found := k.clientKeeper.GetClientState(ctx, connection.ClientID) @@ -151,18 +155,10 @@ func (k Keeper) VerifyNonMembership( return false } - path := commitment.ApplyPrefix(connection.Counterparty.Prefix, pathStr) - return k.clientKeeper.VerifyNonMembership(ctx, clientState, height, proof, path) -} - -// removePath is an util function to remove a path from a set. -// -// TODO: move to ICS24 -func removePath(paths []string, path string) ([]string, bool) { - for i, p := range paths { - if p == path { - return append(paths[:i], paths[i+1:]...), true - } + path, err := commitment.ApplyPrefix(connection.Counterparty.Prefix, pathStr) + if err != nil { + return false } - return paths, false + + return k.clientKeeper.VerifyNonMembership(ctx, clientState, height, proof, path) } diff --git a/x/ibc/03-connection/keeper/querier.go b/x/ibc/03-connection/keeper/querier.go index bf47cd9d2932..85bb02559e78 100644 --- a/x/ibc/03-connection/keeper/querier.go +++ b/x/ibc/03-connection/keeper/querier.go @@ -9,22 +9,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" ) -// NewQuerier creates a querier for the IBC client -func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { - switch path[0] { - case types.QueryConnection: - return queryConnection(ctx, req, k) - case types.QueryClientConnections: - return queryClientConnections(ctx, req, k) - - default: - return nil, sdk.ErrUnknownRequest("unknown IBC connection query endpoint") - } - } -} - -func queryConnection(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +// QuerierConnection defines the sdk.Querier to query a connection end +func QuerierConnection(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { var params types.QueryConnectionParams err := types.SubModuleCdc.UnmarshalJSON(req.Data, ¶ms) @@ -45,7 +31,8 @@ func queryConnection(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, return bz, nil } -func queryClientConnections(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +// QuerierClientConnections defines the sdk.Querier to query the client connections +func QuerierClientConnections(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { var params types.QueryClientConnectionsParams err := types.SubModuleCdc.UnmarshalJSON(req.Data, ¶ms) diff --git a/x/ibc/03-connection/types/connection.go b/x/ibc/03-connection/types/connection.go index 103050ddf5d8..f3263deb8e1b 100644 --- a/x/ibc/03-connection/types/connection.go +++ b/x/ibc/03-connection/types/connection.go @@ -1,7 +1,12 @@ package types import ( - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + "encoding/json" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ) // ICS03 - Connection Data Structures as defined in https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#data-structures @@ -11,8 +16,8 @@ import ( // NOTE: there must only be 2 defined ConnectionEnds to stablish a connection // between two chains. type ConnectionEnd struct { - State ConnectionState `json:"state" yaml:"state"` - ClientID string `json:"client_id" yaml:"client_id"` + State State `json:"state" yaml:"state"` + ClientID string `json:"client_id" yaml:"client_id"` // Counterparty chain associated with this connection. Counterparty Counterparty `json:"counterparty" yaml:"counterparty"` @@ -22,7 +27,7 @@ type ConnectionEnd struct { } // NewConnectionEnd creates a new ConnectionEnd instance. -func NewConnectionEnd(state ConnectionState, clientID string, counterparty Counterparty, versions []string) ConnectionEnd { +func NewConnectionEnd(state State, clientID string, counterparty Counterparty, versions []string) ConnectionEnd { return ConnectionEnd{ State: state, ClientID: clientID, @@ -35,13 +40,13 @@ func NewConnectionEnd(state ConnectionState, clientID string, counterparty Count // Counterparty defines the counterparty chain associated with a connection end. type Counterparty struct { - ClientID string `json:"client_id" yaml:"client_id"` - ConnectionID string `json:"connection_id" yaml:"connection_id"` - Prefix commitmentexported.PrefixI `json:"prefix" yaml:"prefix"` + ClientID string `json:"client_id" yaml:"client_id"` + ConnectionID string `json:"connection_id" yaml:"connection_id"` + Prefix commitment.PrefixI `json:"prefix" yaml:"prefix"` } // NewCounterparty creates a new Counterparty instance. -func NewCounterparty(clientID, connectionID string, prefix commitmentexported.PrefixI) Counterparty { +func NewCounterparty(clientID, connectionID string, prefix commitment.PrefixI) Counterparty { return Counterparty{ ClientID: clientID, ConnectionID: connectionID, @@ -49,46 +54,90 @@ func NewCounterparty(clientID, connectionID string, prefix commitmentexported.Pr } } -// ConnectionState defines the state of a connection between two disctinct +// ValidateBasic performs a basic validation check of the identifiers and prefix +func (c Counterparty) ValidateBasic() sdk.Error { + if err := host.DefaultIdentifierValidator(c.ConnectionID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid counterparty connection ID: %s", err.Error())) + } + if err := host.DefaultIdentifierValidator(c.ClientID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid counterparty client ID: %s", err.Error())) + } + if c.Prefix == nil || len(c.Prefix.Bytes()) == 0 { + return ErrInvalidCounterparty(DefaultCodespace, "invalid counterparty prefix") + } + return nil +} + +// State defines the state of a connection between two disctinct // chains -type ConnectionState = byte +type State byte // available connection states const ( - NONE ConnectionState = iota // default ConnectionState + NONE State = iota // default State INIT TRYOPEN OPEN ) -// ConnectionStateToString returns the string representation of a connection state -func ConnectionStateToString(state ConnectionState) string { - switch state { +// string representation of the connection states +const ( + StateNone string = "NONE" + StateInit string = "INIT" + StateTryOpen string = "TRYOPEN" + StateOpen string = "OPEN" +) + +// String implements the Stringer interface +func (cs State) String() string { + switch cs { case NONE: - return "NONE" + return StateNone case INIT: - return "INIT" + return StateInit case TRYOPEN: - return "TRYOPEN" + return StateTryOpen case OPEN: - return "OPEN" + return StateOpen default: return "" } } -// StringToConnectionState parses a string into a connection state -func StringToConnectionState(state string) ConnectionState { +// StateFromString parses a string into a connection state +func StateFromString(state string) (State, error) { switch state { - case "NONE": - return NONE - case "INIT": - return INIT - case "TRYOPEN": - return TRYOPEN - case "OPEN": - return OPEN + case StateNone: + return NONE, nil + case StateInit: + return INIT, nil + case StateTryOpen: + return TRYOPEN, nil + case StateOpen: + return OPEN, nil default: - return NONE + return NONE, fmt.Errorf("'%s' is not a valid vote option", state) } } + +// MarshalJSON marshal to JSON using string. +func (cs State) MarshalJSON() ([]byte, error) { + return json.Marshal(cs.String()) +} + +// UnmarshalJSON decodes from JSON assuming Bech32 encoding. +func (cs *State) UnmarshalJSON(data []byte) error { + var s string + err := json.Unmarshal(data, &s) + if err != nil { + return err + } + + bz2, err := StateFromString(s) + if err != nil { + return err + } + + *cs = bz2 + return nil +} diff --git a/x/ibc/03-connection/types/errors.go b/x/ibc/03-connection/types/errors.go index cfdfd9f5eeda..b2a2cbe2ad5f 100644 --- a/x/ibc/03-connection/types/errors.go +++ b/x/ibc/03-connection/types/errors.go @@ -18,6 +18,8 @@ const ( CodeInvalidVersion sdk.CodeType = 106 CodeInvalidHeight sdk.CodeType = 107 CodeInvalidConnectionState sdk.CodeType = 108 + CodeInvalidProof sdk.CodeType = 109 + CodeInvalidCounterparty sdk.CodeType = 110 ) // ErrConnectionExists implements sdk.Error @@ -59,3 +61,13 @@ func ErrInvalidHeight(codespace sdk.CodespaceType, msg string) sdk.Error { func ErrInvalidConnectionState(codespace sdk.CodespaceType, msg string) sdk.Error { return sdk.NewError(codespace, CodeInvalidConnectionState, msg) } + +// ErrInvalidConnectionProof implements sdk.Error +func ErrInvalidConnectionProof(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidProof, msg) +} + +// ErrInvalidCounterparty implements sdk.Error +func ErrInvalidCounterparty(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidCounterparty, msg) +} diff --git a/x/ibc/03-connection/types/expected_keepers.go b/x/ibc/03-connection/types/expected_keepers.go index eda9811fcca2..8af1beb2ba7a 100644 --- a/x/ibc/03-connection/types/expected_keepers.go +++ b/x/ibc/03-connection/types/expected_keepers.go @@ -4,19 +4,19 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // ClientKeeper expected account IBC client keeper type ClientKeeper interface { GetConsensusState(ctx sdk.Context, clientID string) (clientexported.ConsensusState, bool) - GetClientState(ctx sdk.Context, clientID string) (client.ClientState, bool) + GetClientState(ctx sdk.Context, clientID string) (client.State, bool) VerifyMembership( - ctx sdk.Context, clientState client.ClientState, height uint64, - proof commitmentexported.ProofI, path commitmentexported.PathI, value []byte, + ctx sdk.Context, clientState client.State, height uint64, + proof commitment.ProofI, path commitment.PathI, value []byte, ) bool VerifyNonMembership( - ctx sdk.Context, clientState client.ClientState, height uint64, - proof commitmentexported.ProofI, path commitmentexported.PathI, + ctx sdk.Context, clientState client.State, height uint64, + proof commitment.ProofI, path commitment.PathI, ) bool } diff --git a/x/ibc/03-connection/types/msgs.go b/x/ibc/03-connection/types/msgs.go index 91e29cdf974d..965a9ae98b39 100644 --- a/x/ibc/03-connection/types/msgs.go +++ b/x/ibc/03-connection/types/msgs.go @@ -1,10 +1,12 @@ package types import ( + "fmt" "strings" sdk "github.com/cosmos/cosmos-sdk/types" - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -22,7 +24,7 @@ type MsgConnectionOpenInit struct { // NewMsgConnectionOpenInit creates a new MsgConnectionOpenInit instance func NewMsgConnectionOpenInit( connectionID, clientID, counterpartyConnectionID, - counterpartyClientID string, counterpartyPrefix commitmentexported.PrefixI, + counterpartyClientID string, counterpartyPrefix commitment.PrefixI, signer sdk.AccAddress, ) MsgConnectionOpenInit { counterparty := NewCounterparty(counterpartyClientID, counterpartyConnectionID, counterpartyPrefix) @@ -46,11 +48,16 @@ func (msg MsgConnectionOpenInit) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgConnectionOpenInit) ValidateBasic() sdk.Error { - // TODO: validate IDs; Blocked on ICS24 + if err := host.DefaultIdentifierValidator(msg.ConnectionID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid connection ID: %s", err.Error())) + } + if err := host.DefaultIdentifierValidator(msg.ClientID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid client ID: %s", err.Error())) + } if msg.Signer.Empty() { return sdk.ErrInvalidAddress("missing signer address") } - return nil + return msg.Counterparty.ValidateBasic() } // GetSignBytes implements sdk.Msg @@ -68,21 +75,21 @@ var _ sdk.Msg = MsgConnectionOpenTry{} // MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a connection // on Chain B. type MsgConnectionOpenTry struct { - ConnectionID string `json:"connection_id"` - ClientID string `json:"client_id"` - Counterparty Counterparty `json:"counterparty"` - CounterpartyVersions []string `json:"counterparty_versions"` - ProofInit commitmentexported.ProofI `json:"proof_init"` // proof of the initialization the connection on Chain A: `none -> INIT` - ProofHeight uint64 `json:"proof_height"` - ConsensusHeight uint64 `json:"consensus_height"` - Signer sdk.AccAddress `json:"signer"` + ConnectionID string `json:"connection_id"` + ClientID string `json:"client_id"` + Counterparty Counterparty `json:"counterparty"` + CounterpartyVersions []string `json:"counterparty_versions"` + ProofInit commitment.ProofI `json:"proof_init"` // proof of the initialization the connection on Chain A: `none -> INIT` + ProofHeight uint64 `json:"proof_height"` + ConsensusHeight uint64 `json:"consensus_height"` + Signer sdk.AccAddress `json:"signer"` } // NewMsgConnectionOpenTry creates a new MsgConnectionOpenTry instance func NewMsgConnectionOpenTry( connectionID, clientID, counterpartyConnectionID, - counterpartyClientID string, counterpartyPrefix commitmentexported.PrefixI, - counterpartyVersions []string, proofInit commitmentexported.ProofI, + counterpartyClientID string, counterpartyPrefix commitment.PrefixI, + counterpartyVersions []string, proofInit commitment.ProofI, proofHeight, consensusHeight uint64, signer sdk.AccAddress, ) MsgConnectionOpenTry { counterparty := NewCounterparty(counterpartyClientID, counterpartyConnectionID, counterpartyPrefix) @@ -110,29 +117,33 @@ func (msg MsgConnectionOpenTry) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgConnectionOpenTry) ValidateBasic() sdk.Error { - // TODO: validate IDs; Blocked on ICS24 + if err := host.DefaultIdentifierValidator(msg.ConnectionID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid connection ID: %s", err.Error())) + } + if err := host.DefaultIdentifierValidator(msg.ClientID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid client ID: %s", err.Error())) + } if len(msg.CounterpartyVersions) == 0 { return ErrInvalidVersion(DefaultCodespace, "missing counterparty versions") } - for _, version := range msg.CounterpartyVersions { if strings.TrimSpace(version) == "" { return ErrInvalidVersion(DefaultCodespace, "version can't be blank") } } - + if msg.ProofInit == nil { + return ErrInvalidConnectionProof(DefaultCodespace, "proof init cannot be nil") + } if msg.ProofHeight == 0 { return ErrInvalidHeight(DefaultCodespace, "proof height must be > 0") } - if msg.ConsensusHeight == 0 { return ErrInvalidHeight(DefaultCodespace, "consensus height must be > 0") } - if msg.Signer.Empty() { return sdk.ErrInvalidAddress("missing signer address") } - return nil + return msg.Counterparty.ValidateBasic() } // GetSignBytes implements sdk.Msg @@ -150,17 +161,17 @@ var _ sdk.Msg = MsgConnectionOpenAck{} // MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to acknowledge // the change of connection state to TRYOPEN on Chain B. type MsgConnectionOpenAck struct { - ConnectionID string `json:"connection_id"` - ProofTry commitmentexported.ProofI `json:"proof_try"` // proof for the change of the connection state on Chain B: `none -> TRYOPEN` - ProofHeight uint64 `json:"proof_height"` - ConsensusHeight uint64 `json:"consensus_height"` - Version string `json:"version"` - Signer sdk.AccAddress `json:"signer"` + ConnectionID string `json:"connection_id"` + ProofTry commitment.ProofI `json:"proof_try"` // proof for the change of the connection state on Chain B: `none -> TRYOPEN` + ProofHeight uint64 `json:"proof_height"` + ConsensusHeight uint64 `json:"consensus_height"` + Version string `json:"version"` + Signer sdk.AccAddress `json:"signer"` } // NewMsgConnectionOpenAck creates a new MsgConnectionOpenAck instance func NewMsgConnectionOpenAck( - connectionID string, proofTry commitmentexported.ProofI, + connectionID string, proofTry commitment.ProofI, proofHeight, consensusHeight uint64, version string, signer sdk.AccAddress, ) MsgConnectionOpenAck { @@ -186,18 +197,21 @@ func (msg MsgConnectionOpenAck) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgConnectionOpenAck) ValidateBasic() sdk.Error { + if err := host.DefaultIdentifierValidator(msg.ConnectionID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid connection ID: %s", err.Error())) + } if strings.TrimSpace(msg.Version) == "" { return ErrInvalidVersion(DefaultCodespace, "version can't be blank") } - + if msg.ProofTry == nil { + return ErrInvalidConnectionProof(DefaultCodespace, "proof try cannot be nil") + } if msg.ProofHeight == 0 { return ErrInvalidHeight(DefaultCodespace, "proof height must be > 0") } - if msg.ConsensusHeight == 0 { return ErrInvalidHeight(DefaultCodespace, "consensus height must be > 0") } - if msg.Signer.Empty() { return sdk.ErrInvalidAddress("missing signer address") } @@ -219,15 +233,15 @@ var _ sdk.Msg = MsgConnectionOpenConfirm{} // MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to acknowledge // the change of connection state to OPEN on Chain A. type MsgConnectionOpenConfirm struct { - ConnectionID string `json:"connection_id"` - ProofAck commitmentexported.ProofI `json:"proof_ack"` // proof for the change of the connection state on Chain A: `INIT -> OPEN` - ProofHeight uint64 `json:"proof_height"` - Signer sdk.AccAddress `json:"signer"` + ConnectionID string `json:"connection_id"` + ProofAck commitment.ProofI `json:"proof_ack"` // proof for the change of the connection state on Chain A: `INIT -> OPEN` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` } // NewMsgConnectionOpenConfirm creates a new MsgConnectionOpenConfirm instance func NewMsgConnectionOpenConfirm( - connectionID string, proofAck commitmentexported.ProofI, proofHeight uint64, signer sdk.AccAddress, + connectionID string, proofAck commitment.ProofI, proofHeight uint64, signer sdk.AccAddress, ) MsgConnectionOpenConfirm { return MsgConnectionOpenConfirm{ ConnectionID: connectionID, @@ -249,7 +263,12 @@ func (msg MsgConnectionOpenConfirm) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgConnectionOpenConfirm) ValidateBasic() sdk.Error { - // TODO: validate IDs; Blocked on ICS24 + if err := host.DefaultIdentifierValidator(msg.ConnectionID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid connection ID: %s", err.Error())) + } + if msg.ProofAck == nil { + return ErrInvalidConnectionProof(DefaultCodespace, "proof ack cannot be nil") + } if msg.ProofHeight == 0 { return ErrInvalidHeight(DefaultCodespace, "proof height must be > 0") } diff --git a/x/ibc/24-host/utils.go b/x/ibc/24-host/utils.go new file mode 100644 index 000000000000..c75f356561f6 --- /dev/null +++ b/x/ibc/24-host/utils.go @@ -0,0 +1,11 @@ +package host + +// RemovePath is an util function to remove a path from a set. +func RemovePath(paths []string, path string) ([]string, bool) { + for i, p := range paths { + if p == path { + return append(paths[:i], paths[i+1:]...), true + } + } + return paths, false +} diff --git a/x/ibc/keeper/querier.go b/x/ibc/keeper/querier.go index 7cbd4ec9c499..cb9b260d135a 100644 --- a/x/ibc/keeper/querier.go +++ b/x/ibc/keeper/querier.go @@ -5,6 +5,7 @@ import ( 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" ) // NewQuerier creates a querier for the IBC module @@ -17,8 +18,13 @@ func NewQuerier(k Keeper) sdk.Querier { return client.QuerierConsensusState(ctx, req, k.ClientKeeper) case client.QueryVerifiedRoot: return client.QuerierVerifiedRoot(ctx, req, k.ClientKeeper) + case connection.QueryConnection: + return connection.QuerierConnection(ctx, req, k.ConnectionKeeper) + case connection.QueryClientConnections: + return connection.QuerierClientConnections(ctx, req, k.ConnectionKeeper) + default: - return nil, sdk.ErrUnknownRequest("unknown IBC client query endpoint") + return nil, sdk.ErrUnknownRequest("unknown IBC query endpoint") } } } From 7809e4dd3e31e8f74f21340491d8c58fecdff6d7 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 24 Oct 2019 14:59:47 +0200 Subject: [PATCH 329/378] minor update --- x/ibc/03-connection/types/connection.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ibc/03-connection/types/connection.go b/x/ibc/03-connection/types/connection.go index f3263deb8e1b..4d48b9dccd46 100644 --- a/x/ibc/03-connection/types/connection.go +++ b/x/ibc/03-connection/types/connection.go @@ -116,7 +116,7 @@ func StateFromString(state string) (State, error) { case StateOpen: return OPEN, nil default: - return NONE, fmt.Errorf("'%s' is not a valid vote option", state) + return NONE, fmt.Errorf("'%s' is not a valid connection state", state) } } From 102ab3dff568ff478c40fc32e925591bd2013600 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 24 Oct 2019 15:17:25 +0200 Subject: [PATCH 330/378] custom JSON marshaling --- x/ibc/02-client/client/cli/tx.go | 2 +- x/ibc/02-client/doc.go | 44 --------------- x/ibc/02-client/exported/exported.go | 62 ++++++++++++++-------- x/ibc/02-client/handler.go | 9 +++- x/ibc/02-client/keeper/client.go | 7 +-- x/ibc/02-client/module.go | 9 ++-- x/ibc/02-client/types/errors.go | 4 +- x/ibc/02-client/types/msgs.go | 22 ++++---- x/ibc/02-client/types/tendermint/header.go | 1 - 9 files changed, 67 insertions(+), 93 deletions(-) diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index a9efc1162461..92e37b15c9b5 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -69,7 +69,7 @@ $ %s tx ibc client create [client-id] [path/to/consensus_state.json] --from node } msg := types.NewMsgCreateClient( - clientID, exported.ClientTypeToString(state.ClientType()), state, + clientID, state.ClientType().String(), state, cliCtx.GetFromAddress(), ) if err := msg.ValidateBasic(); err != nil { diff --git a/x/ibc/02-client/doc.go b/x/ibc/02-client/doc.go index 061e160d9739..2b6952ba97eb 100644 --- a/x/ibc/02-client/doc.go +++ b/x/ibc/02-client/doc.go @@ -6,49 +6,5 @@ clients which tracks on other chain's state. The main type is `Client`, which provides `commitment.Root` to verify state proofs and `ConsensusState` to verify header proofs. - -Specification - -```typescript -interface ConsensusState { - height: uint64 - root: CommitmentRoot - validityPredicate: ValidityPredicate - eqivocationPredicate: EquivocationPredicate -} - -interface ClientState { - consensusState: ConsensusState - verifiedRoots: Map - frozen: bool -} - -interface Header { - height: uint64 - proof: HeaderProof - state: Maybe[ConsensusState] - root: CommitmentRoot -} - -type ValidityPredicate = (ConsensusState, Header) => Error | ConsensusState - -type EquivocationPredicate = (ConsensusState, Header, Header) => bool -``` - -Implementation - -1. Types - -`spec: interface ConsensusState` is implemented by `type ConsensusState`. `ConsensusState.{GetHeight(), GetRoot(), -Validate(), Equivocation()}` each corresponds to `spec: ConsensusState.{height, root, validityPredicate, -equivocationPredicate}`. `ConsensusState.Kind()` returns `Kind`, which is an enum indicating the type of the -consensus algorithm. - -`spec: interface Header` is implemented by `type Header`. `Header{GetHeight(), Proof(), State(), GetRoot()}` -each corresponds to `spec: Header.{height, proof, state, root}`. - -2. Manager - -`spec: interface ClientState` is implemented by `type State`. */ package client diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index d482a54553d8..ff5f586a75cb 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -1,6 +1,9 @@ package exported import ( + "encoding/json" + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" @@ -61,43 +64,58 @@ type Header interface { GetHeight() uint64 } -// Client types -const ( - ClientTypeTendermint string = "tendermint" -) - // ClientType defines the type of the consensus algorithm type ClientType byte -// Registered consensus types +// available client types const ( Tendermint ClientType = iota + 1 // 1 ) -// ValidClientTypes returns the registerd client types for this chain -var ValidClientTypes = map[string]bool{ - ClientTypeTendermint: true, +// string representation of the client types +const ( + ClientTypeTendermint string = "tendermint" +) + +func (ct ClientType) String() string { + switch ct { + case Tendermint: + return ClientTypeTendermint + default: + return "" + } } -// ClientTypeFromStr returns a byte that corresponds to the registered client -// type. It returns 0 if the type is not found/registered. -func ClientTypeFromStr(clientType string) ClientType { - switch clientType { - case ClientTypeTendermint: - return Tendermint +// MarshalJSON marshal to JSON using string. +func (ct ClientType) MarshalJSON() ([]byte, error) { + return json.Marshal(ct.String()) +} - default: - return 0 +// UnmarshalJSON decodes from JSON. +func (ct *ClientType) UnmarshalJSON(data []byte) error { + var s string + err := json.Unmarshal(data, &s) + if err != nil { + return err + } + + bz2, err := ClientTypeFromString(s) + if err != nil { + return err } + + *ct = bz2 + return nil } -// ClientTypeToString returns the string representation of a client type -func ClientTypeToString(clientType ClientType) string { +// ClientTypeFromString returns a byte that corresponds to the registered client +// type. It returns 0 if the type is not found/registered. +func ClientTypeFromString(clientType string) (ClientType, error) { switch clientType { - case Tendermint: - return ClientTypeTendermint + case ClientTypeTendermint: + return Tendermint, nil default: - return "" + return 0, fmt.Errorf("'%s' is not a valid client type", clientType) } } diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go index b7394edf0e29..1b1e1807b54a 100644 --- a/x/ibc/02-client/handler.go +++ b/x/ibc/02-client/handler.go @@ -2,11 +2,18 @@ package client import ( sdk "github.com/cosmos/cosmos-sdk/types" + exported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ) // HandleMsgCreateClient defines the sdk.Handler for MsgCreateClient func HandleMsgCreateClient(ctx sdk.Context, k Keeper, msg MsgCreateClient) sdk.Result { - _, err := k.CreateClient(ctx, msg.ClientID, msg.ClientType, msg.ConsensusState) + clientType, err := exported.ClientTypeFromString(msg.ClientType) + if err != nil { + return sdk.ResultFromError(ErrInvalidClientType(DefaultCodespace, err.Error())) + } + + // TODO: should we create an event with the new client state id ? + _, err = k.CreateClient(ctx, msg.ClientID, clientType, msg.ConsensusState) if err != nil { return sdk.ResultFromError(err) } diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go index 26a0469b1038..e180919dec7c 100644 --- a/x/ibc/02-client/keeper/client.go +++ b/x/ibc/02-client/keeper/client.go @@ -13,7 +13,7 @@ import ( // state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create func (k Keeper) CreateClient( ctx sdk.Context, clientID string, - clientTypeStr string, consensusState exported.ConsensusState, + clientType exported.ClientType, consensusState exported.ConsensusState, ) (types.State, error) { _, found := k.GetClientState(ctx, clientID) if found { @@ -25,11 +25,6 @@ func (k Keeper) CreateClient( panic(fmt.Sprintf("consensus type is already defined for client %s", clientID)) } - clientType := exported.ClientTypeFromStr(clientTypeStr) - if clientType == 0 { - return types.State{}, types.ErrInvalidClientType(k.codespace) - } - clientState := k.initialize(ctx, clientID, consensusState) k.SetVerifiedRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) k.SetClientState(ctx, clientState) diff --git a/x/ibc/02-client/module.go b/x/ibc/02-client/module.go index a4586961b08a..3df05cdfbdf2 100644 --- a/x/ibc/02-client/module.go +++ b/x/ibc/02-client/module.go @@ -11,23 +11,22 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/cli" ) -// Name returns the staking module's name +// Name returns the IBC client name func Name() string { return SubModuleName } -// RegisterRESTRoutes registers the REST routes for the staking module. +// RegisterRESTRoutes registers the REST routes for the IBC client func RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { // TODO: - // rest.RegisterRoutes(ctx, rtr) } -// GetTxCmd returns the root tx command for the staking module. +// GetTxCmd returns the root tx command for the IBC client func GetTxCmd(cdc *codec.Codec, storeKey string) *cobra.Command { return cli.GetTxCmd(fmt.Sprintf("%s/%s", storeKey, SubModuleName), cdc) } -// GetQueryCmd returns no root query command for the staking module. +// GetQueryCmd returns no root query command for the IBC client func GetQueryCmd(cdc *codec.Codec, queryRoute string) *cobra.Command { return cli.GetQueryCmd(fmt.Sprintf("%s/%s", queryRoute, SubModuleName), cdc) } diff --git a/x/ibc/02-client/types/errors.go b/x/ibc/02-client/types/errors.go index b6f8a84c9aa9..d4e6e9bb5558 100644 --- a/x/ibc/02-client/types/errors.go +++ b/x/ibc/02-client/types/errors.go @@ -53,8 +53,8 @@ func ErrClientTypeNotFound(codespace sdk.CodespaceType) sdk.Error { } // ErrInvalidClientType implements sdk.Error -func ErrInvalidClientType(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidClientType, "client type mismatch") +func ErrInvalidClientType(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidClientType, msg) } // ErrRootNotFound implements sdk.Error diff --git a/x/ibc/02-client/types/msgs.go b/x/ibc/02-client/types/msgs.go index 450b7f99c86e..c9d46cafa4db 100644 --- a/x/ibc/02-client/types/msgs.go +++ b/x/ibc/02-client/types/msgs.go @@ -41,18 +41,18 @@ func (msg MsgCreateClient) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgCreateClient) ValidateBasic() sdk.Error { - if msg.Signer.Empty() { - return sdk.ErrInvalidAddress("empty address") - } if err := host.DefaultIdentifierValidator(msg.ClientID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid client ID: %s", err.Error())) } - if !exported.ValidClientTypes[msg.ClientType] { - return ErrInvalidClientType(DefaultCodespace) + if _, err := exported.ClientTypeFromString(msg.ClientType); err != nil { + return ErrInvalidClientType(DefaultCodespace, err.Error()) } if msg.ConsensusState == nil { return ErrInvalidConsensus(DefaultCodespace) } + if msg.Signer.Empty() { + return sdk.ErrInvalidAddress("empty address") + } return nil } @@ -96,15 +96,15 @@ func (msg MsgUpdateClient) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgUpdateClient) ValidateBasic() sdk.Error { - if msg.Signer.Empty() { - return sdk.ErrInvalidAddress("empty address") - } if err := host.DefaultIdentifierValidator(msg.ClientID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid client ID: %s", err.Error())) } if msg.Header == nil { return ErrInvalidHeader(DefaultCodespace) } + if msg.Signer.Empty() { + return sdk.ErrInvalidAddress("empty address") + } return nil } @@ -146,15 +146,15 @@ func (msg MsgSubmitMisbehaviour) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgSubmitMisbehaviour) ValidateBasic() sdk.Error { - if msg.Signer.Empty() { - return sdk.ErrInvalidAddress("empty address") - } if err := host.DefaultIdentifierValidator(msg.ClientID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid client ID: %s", err.Error())) } if msg.Evidence == nil { return ErrInvalidEvidence(DefaultCodespace) } + if msg.Signer.Empty() { + return sdk.ErrInvalidAddress("empty address") + } return nil } diff --git a/x/ibc/02-client/types/tendermint/header.go b/x/ibc/02-client/types/tendermint/header.go index 62202b1e6b02..c2d9cfebc9c5 100644 --- a/x/ibc/02-client/types/tendermint/header.go +++ b/x/ibc/02-client/types/tendermint/header.go @@ -10,7 +10,6 @@ var _ exported.Header = Header{} // Header defines the Tendermint consensus Header type Header struct { - // TODO: define Tendermint header type manually, don't use tmtypes tmtypes.SignedHeader ValidatorSet *tmtypes.ValidatorSet `json:"validator_set" yaml:"validator_set"` NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` From c8289a84af3e203800f8af2edaf11716c9f03698 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 24 Oct 2019 15:52:04 +0200 Subject: [PATCH 331/378] use host validation for port ids --- x/ibc/05-port/exported/exported.go | 15 --------------- x/ibc/05-port/keeper/keeper.go | 9 +++++---- x/ibc/05-port/types/port.go | 17 ----------------- 3 files changed, 5 insertions(+), 36 deletions(-) delete mode 100644 x/ibc/05-port/exported/exported.go delete mode 100644 x/ibc/05-port/types/port.go diff --git a/x/ibc/05-port/exported/exported.go b/x/ibc/05-port/exported/exported.go deleted file mode 100644 index b38beed8bfbc..000000000000 --- a/x/ibc/05-port/exported/exported.go +++ /dev/null @@ -1,15 +0,0 @@ -// Package exported defines the `generate()` and `authenticate()` functions for -// capability keys as defined in https://github.com/cosmos/ics/tree/master/spec/ics-005-port-allocation#data-structures. -package exported - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// Generate creates a new object-capability key, which must -// be returned by the outer-layer function. -type Generate func() sdk.CapabilityKey - -// Authenticate defines an authentication function defined by -// each module to authenticate their own. -type Authenticate func(key sdk.CapabilityKey) bool diff --git a/x/ibc/05-port/keeper/keeper.go b/x/ibc/05-port/keeper/keeper.go index b72ecd3f6ede..083c7db108f2 100644 --- a/x/ibc/05-port/keeper/keeper.go +++ b/x/ibc/05-port/keeper/keeper.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ) // Keeper defines the IBC connection keeper @@ -40,8 +41,8 @@ func (k Keeper) GetPorts() []string { // The capability must then be passed to a module which will need to pass // it as an extra parameter when calling functions on the IBC module. func (k Keeper) BindPort(portID string) sdk.CapabilityKey { - if !types.ValidatePortID(portID) { - panic(fmt.Sprintf("invalid port id: %s", types.ErrInvalidPortID(k.codespace))) + if err := host.DefaultIdentifierValidator(portID); err != nil { + panic(err.Error()) } for _, b := range k.bound { @@ -61,8 +62,8 @@ func (k Keeper) BindPort(portID string) sdk.CapabilityKey { // generated and bound to the port (provided as a parameter) which the capability // is being authenticated against. func (k Keeper) Authenticate(key sdk.CapabilityKey, portID string) bool { - if !types.ValidatePortID(portID) { - panic(fmt.Sprintf("invalid port id: %s", types.ErrInvalidPortID(k.codespace))) + if err := host.DefaultIdentifierValidator(portID); err != nil { + panic(err.Error()) } return k.ports[key] == portID diff --git a/x/ibc/05-port/types/port.go b/x/ibc/05-port/types/port.go deleted file mode 100644 index d2cd60806f18..000000000000 --- a/x/ibc/05-port/types/port.go +++ /dev/null @@ -1,17 +0,0 @@ -package types - -import ( - "strings" -) - -// ValidatePortID validates that the provided port identifier is not empty -// and that it's -func ValidatePortID(portID string) bool { - if strings.TrimSpace(portID) == "" { - return false - } - if len(portID) < 3 || len(portID) > 10 { - return false - } - return true -} From 7cab0185c0036c8824a603148ffef454868f5044 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 24 Oct 2019 17:42:47 +0200 Subject: [PATCH 332/378] downstream changes; custom marshal JSON; msg validation, and update errors --- x/ibc/03-connection/alias.go | 4 + x/ibc/04-channel/alias.go | 1 - x/ibc/04-channel/exported/exported.go | 5 + x/ibc/04-channel/keeper/handshake.go | 111 +++++++---- x/ibc/04-channel/keeper/packet.go | 73 ++++--- x/ibc/04-channel/keeper/querier.go | 16 +- x/ibc/04-channel/keeper/timeout.go | 30 +-- x/ibc/04-channel/types/channel.go | 172 +++++++++++----- x/ibc/04-channel/types/errors.go | 12 ++ x/ibc/04-channel/types/expected_keepers.go | 15 +- x/ibc/04-channel/types/msgs.go | 217 ++++++--------------- x/ibc/04-channel/types/packet.go | 96 ++++++--- x/ibc/05-port/alias.go | 1 - x/ibc/keeper/querier.go | 4 +- 14 files changed, 427 insertions(+), 330 deletions(-) diff --git a/x/ibc/03-connection/alias.go b/x/ibc/03-connection/alias.go index 0b8513f561bb..4f2fa381f72f 100644 --- a/x/ibc/03-connection/alias.go +++ b/x/ibc/03-connection/alias.go @@ -13,6 +13,9 @@ import ( const ( NONE = types.NONE + INIT = types.INIT + TRYOPEN = types.TRYOPEN + OPEN = types.OPEN DefaultCodespace = types.DefaultCodespace CodeConnectionExists = types.CodeConnectionExists CodeConnectionNotFound = types.CodeConnectionNotFound @@ -43,6 +46,7 @@ var ( ErrClientConnectionPathsNotFound = types.ErrClientConnectionPathsNotFound ErrConnectionPath = types.ErrConnectionPath ErrInvalidCounterpartyConnection = types.ErrInvalidCounterpartyConnection + ErrInvalidConnectionState = types.ErrInvalidConnectionState ConnectionPath = types.ConnectionPath ClientConnectionsPath = types.ClientConnectionsPath KeyConnection = types.KeyConnection diff --git a/x/ibc/04-channel/alias.go b/x/ibc/04-channel/alias.go index dcfe2263cac0..8e82aa78404a 100644 --- a/x/ibc/04-channel/alias.go +++ b/x/ibc/04-channel/alias.go @@ -41,7 +41,6 @@ const ( var ( // functions aliases NewKeeper = keeper.NewKeeper - NewQuerier = keeper.NewQuerier NewChannel = types.NewChannel NewCounterparty = types.NewCounterparty RegisterCodec = types.RegisterCodec diff --git a/x/ibc/04-channel/exported/exported.go b/x/ibc/04-channel/exported/exported.go index e3f4f42a1772..9559db87ca25 100644 --- a/x/ibc/04-channel/exported/exported.go +++ b/x/ibc/04-channel/exported/exported.go @@ -1,5 +1,9 @@ package exported +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + type PacketI interface { Sequence() uint64 TimeoutHeight() uint64 @@ -8,4 +12,5 @@ type PacketI interface { DestPort() string DestChannel() string Data() []byte + ValidateBasic() sdk.Error } diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go index c6589c3cedcd..f89d0c7a9e9c 100644 --- a/x/ibc/04-channel/keeper/handshake.go +++ b/x/ibc/04-channel/keeper/handshake.go @@ -2,19 +2,20 @@ package keeper import ( "errors" + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" - porttypes "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + port "github.com/cosmos/cosmos-sdk/x/ibc/05-port" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // ChanOpenInit is called by a module to initiate a channel opening handshake with // a module on another chain. func (k Keeper) ChanOpenInit( ctx sdk.Context, - order types.ChannelOrder, + order types.Order, connectionHops []string, portID, channelID string, @@ -31,18 +32,21 @@ func (k Keeper) ChanOpenInit( return types.ErrChannelExists(k.codespace, channelID) } - connection, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) if !found { - return connectiontypes.ErrConnectionNotFound(k.codespace, connectionHops[0]) + return connection.ErrConnectionNotFound(k.codespace, connectionHops[0]) } - if connection.State == connectiontypes.NONE { - return errors.New("connection is closed") + if connectionEnd.State == connection.NONE { + return connection.ErrInvalidConnectionState( + k.codespace, + fmt.Sprintf("connection state cannot be NONE"), + ) } _, found = k.portKeeper.GetPort(ctx, portID) if !found { - return porttypes.ErrPortNotFound(k.codespace, portID) + return port.ErrPortNotFound(k.codespace, portID) } // if !k.portKeeper.AuthenticatePort(port.ID()) { @@ -63,14 +67,14 @@ func (k Keeper) ChanOpenInit( // handshake initiated by a module on another chain. func (k Keeper) ChanOpenTry( ctx sdk.Context, - order types.ChannelOrder, + order types.Order, connectionHops []string, portID, channelID string, counterparty types.Counterparty, version, counterpartyVersion string, - proofInit commitmentexported.ProofI, + proofInit commitment.ProofI, proofHeight uint64, ) error { @@ -85,20 +89,23 @@ func (k Keeper) ChanOpenTry( _, found = k.portKeeper.GetPort(ctx, portID) if !found { - return porttypes.ErrPortNotFound(k.codespace, portID) + return port.ErrPortNotFound(k.codespace, portID) } // if !k.portKeeper.AuthenticatePort(port.ID()) { // return errors.New("port is not valid") // TODO: ics05 sdk.Error // } - connection, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) if !found { - return connectiontypes.ErrConnectionNotFound(k.codespace, connectionHops[0]) + return connection.ErrConnectionNotFound(k.codespace, connectionHops[0]) } - if connection.State != connectiontypes.OPEN { - return errors.New("connection is not open") + if connectionEnd.State != connection.OPEN { + return connection.ErrInvalidConnectionState( + k.codespace, + fmt.Sprintf("connection state is not OPEN (got %s)", connectionEnd.State.String()), + ) } // NOTE: this step has been switched with the one below to reverse the connection @@ -119,7 +126,7 @@ func (k Keeper) ChanOpenTry( } if !k.connectionKeeper.VerifyMembership( - ctx, connection, proofHeight, proofInit, + ctx, connectionEnd, proofHeight, proofInit, types.ChannelPath(counterparty.PortID, counterparty.ChannelID), bz, ) { @@ -142,7 +149,7 @@ func (k Keeper) ChanOpenAck( portID, channelID, counterpartyVersion string, - proofTry commitmentexported.ProofI, + proofTry commitment.ProofI, proofHeight uint64, ) error { @@ -152,18 +159,24 @@ func (k Keeper) ChanOpenAck( } if channel.State != types.INIT { - return errors.New("invalid channel state") // TODO: sdk.Error + return types.ErrInvalidChannelState( + k.codespace, + fmt.Sprintf("channel state is not INIT (got %s)", channel.State.String()), + ) } // TODO: get channel capability key and authenticate it - connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) + return connection.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } - if connection.State != connectiontypes.OPEN { - return errors.New("connection is not open") + if connectionEnd.State != connection.OPEN { + return connection.ErrInvalidConnectionState( + k.codespace, + fmt.Sprintf("connection state is not OPEN (got %s)", connectionEnd.State.String()), + ) } // counterparty of the counterparty channel end (i.e self) @@ -179,7 +192,7 @@ func (k Keeper) ChanOpenAck( } if !k.connectionKeeper.VerifyMembership( - ctx, connection, proofHeight, proofTry, + ctx, connectionEnd, proofHeight, proofTry, types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), bz, ) { @@ -199,7 +212,7 @@ func (k Keeper) ChanOpenConfirm( ctx sdk.Context, portID, channelID string, - proofAck commitmentexported.ProofI, + proofAck commitment.ProofI, proofHeight uint64, ) error { channel, found := k.GetChannel(ctx, portID, channelID) @@ -208,18 +221,24 @@ func (k Keeper) ChanOpenConfirm( } if channel.State != types.OPENTRY { - return errors.New("invalid channel state") // TODO: sdk.Error + return types.ErrInvalidChannelState( + k.codespace, + fmt.Sprintf("channel state is not OPENTRY (got %s)", channel.State.String()), + ) } // TODO: get channel capability key and authenticate it - connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) + return connection.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } - if connection.State != connectiontypes.OPEN { - return errors.New("connection is not open") + if connectionEnd.State != connection.OPEN { + return connection.ErrInvalidConnectionState( + k.codespace, + fmt.Sprintf("connection state is not OPEN (got %s)", connectionEnd.State.String()), + ) } counterparty := types.NewCounterparty(portID, channelID) @@ -234,7 +253,7 @@ func (k Keeper) ChanOpenConfirm( } if !k.connectionKeeper.VerifyMembership( - ctx, connection, proofHeight, proofAck, + ctx, connectionEnd, proofHeight, proofAck, types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), bz, ) { @@ -262,16 +281,19 @@ func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error { } if channel.State == types.CLOSED { - return errors.New("channel already closed") // TODO: sdk.Error + return types.ErrInvalidChannelState(k.codespace, "channel is already CLOSED") } - connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) + return connection.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } - if connection.State != connectiontypes.OPEN { - return errors.New("connection is not open") + if connectionEnd.State != connection.OPEN { + return connection.ErrInvalidConnectionState( + k.codespace, + fmt.Sprintf("connection state is not OPEN (got %s)", connectionEnd.State.String()), + ) } channel.State = types.CLOSED @@ -286,7 +308,7 @@ func (k Keeper) ChanCloseConfirm( ctx sdk.Context, portID, channelID string, - proofInit commitmentexported.ProofI, + proofInit commitment.ProofI, proofHeight uint64, ) error { // TODO: get channel capability key and authenticate it @@ -296,16 +318,19 @@ func (k Keeper) ChanCloseConfirm( } if channel.State == types.CLOSED { - return errors.New("channel already closed") // TODO: sdk.Error + return types.ErrInvalidChannelState(k.codespace, "channel is already CLOSED") } - connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) + return connection.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } - if connection.State != connectiontypes.OPEN { - return errors.New("connection is not open") + if connectionEnd.State != connection.OPEN { + return connection.ErrInvalidConnectionState( + k.codespace, + fmt.Sprintf("connection state is not OPEN (got %s)", connectionEnd.State.String()), + ) } counterparty := types.NewCounterparty(portID, channelID) @@ -320,7 +345,7 @@ func (k Keeper) ChanCloseConfirm( } if !k.connectionKeeper.VerifyMembership( - ctx, connection, proofHeight, proofInit, + ctx, connectionEnd, proofHeight, proofInit, types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), bz, ) { diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go index 487362647baa..01e375a3f331 100644 --- a/x/ibc/04-channel/keeper/packet.go +++ b/x/ibc/04-channel/keeper/packet.go @@ -3,12 +3,13 @@ package keeper import ( "bytes" "errors" + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // CleanupPacket is called by a module to remove a received packet commitment @@ -24,7 +25,7 @@ import ( func (k Keeper) CleanupPacket( ctx sdk.Context, packet exported.PacketI, - proof ics23.Proof, + proof commitment.ProofI, proofHeight, nextSequenceRecv uint64, acknowledgement []byte, @@ -35,7 +36,10 @@ func (k Keeper) CleanupPacket( } if channel.State != types.OPEN { - return nil, errors.New("channel is not open") // TODO: sdk.Error + return nil, types.ErrInvalidChannelState( + k.codespace, + fmt.Sprintf("channel state is not OPEN (got %s)", channel.State.String()), + ) } _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) @@ -51,9 +55,9 @@ func (k Keeper) CleanupPacket( return nil, errors.New("invalid packet destination channel") } - connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) + return nil, connection.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } if packet.DestPort() != channel.Counterparty.PortID { @@ -73,13 +77,13 @@ func (k Keeper) CleanupPacket( switch channel.Ordering { case types.ORDERED: ok = k.connectionKeeper.VerifyMembership( - ctx, connection, proofHeight, proof, + ctx, connectionEnd, proofHeight, proof, types.NextSequenceRecvPath(packet.DestPort(), packet.DestChannel()), sdk.Uint64ToBigEndian(nextSequenceRecv), ) case types.UNORDERED: ok = k.connectionKeeper.VerifyMembership( - ctx, connection, proofHeight, proof, + ctx, connectionEnd, proofHeight, proof, types.PacketAcknowledgementPath(packet.DestPort(), packet.DestChannel(), packet.Sequence()), acknowledgement, ) @@ -105,7 +109,10 @@ func (k Keeper) SendPacket(ctx sdk.Context, packet exported.PacketI) error { } if channel.State == types.CLOSED { - return errors.New("channel is closed") // TODO: sdk.Error + return types.ErrInvalidChannelState( + k.codespace, + fmt.Sprintf("channel is CLOSED (got %s)", channel.State.String()), + ) } _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) @@ -125,16 +132,16 @@ func (k Keeper) SendPacket(ctx sdk.Context, packet exported.PacketI) error { return errors.New("invalid packet destination channel") } - connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { return errors.New("connection not found") // TODO: ics03 sdk.Error } - if connection.State == connectiontypes.NONE { + if connectionEnd.State == connection.NONE { return errors.New("connection is closed") // TODO: sdk.Error } - consensusState, found := k.clientKeeper.GetConsensusState(ctx, connection.ClientID) + consensusState, found := k.clientKeeper.GetConsensusState(ctx, connectionEnd.ClientID) if !found { return errors.New("consensus state not found") // TODO: sdk.Error } @@ -164,7 +171,7 @@ func (k Keeper) SendPacket(ctx sdk.Context, packet exported.PacketI) error { func (k Keeper) RecvPacket( ctx sdk.Context, packet exported.PacketI, - proof ics23.Proof, + proof commitment.ProofI, proofHeight uint64, acknowledgement []byte, ) (exported.PacketI, error) { @@ -175,7 +182,10 @@ func (k Keeper) RecvPacket( } if channel.State != types.OPEN { - return nil, errors.New("channel not open") // TODO: sdk.Error + return nil, types.ErrInvalidChannelState( + k.codespace, + fmt.Sprintf("channel state is not OPEN (got %s)", channel.State.String()), + ) } _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) @@ -196,21 +206,26 @@ func (k Keeper) RecvPacket( return nil, errors.New("invalid packet source channel") } - connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) + return nil, connection.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } - if connection.State != connectiontypes.OPEN { - return nil, errors.New("connection is not open") // TODO: ics03 sdk.Error + if connectionEnd.State != connection.OPEN { + return connection.ErrInvalidConnectionState( + k.codespace, + fmt.Sprintf("connection state is not OPEN (got %s)", connectionEnd.State.String()), + ) } if uint64(ctx.BlockHeight()) >= packet.TimeoutHeight() { return nil, types.ErrPacketTimeout(k.codespace) } + // TODO: cast to packet + if !k.connectionKeeper.VerifyMembership( - ctx, connection, proofHeight, proof, + ctx, connectionEnd, proofHeight, proof, types.PacketCommitmentPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), packet.Data(), // TODO: hash data ) { @@ -250,7 +265,7 @@ func (k Keeper) AcknowledgePacket( ctx sdk.Context, packet exported.PacketI, acknowledgement []byte, - proof ics23.Proof, + proof commitment.ProofI, proofHeight uint64, ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) @@ -259,7 +274,10 @@ func (k Keeper) AcknowledgePacket( } if channel.State != types.OPEN { - return nil, errors.New("channel not open") // TODO: sdk.Error + return nil, types.ErrInvalidChannelState( + k.codespace, + fmt.Sprintf("channel state is not OPEN (got %s)", channel.State.String()), + ) } _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) @@ -280,13 +298,16 @@ func (k Keeper) AcknowledgePacket( return nil, errors.New("invalid packet source channel") } - connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) + return nil, connection.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } - if connection.State != connectiontypes.OPEN { - return nil, errors.New("connection is not open") // TODO: ics03 sdk.Error + if connectionEnd.State != connection.OPEN { + return connection.ErrInvalidConnectionState( + k.codespace, + fmt.Sprintf("connection state is not OPEN (got %s)", connectionEnd.State.String()), + ) } commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) @@ -295,7 +316,7 @@ func (k Keeper) AcknowledgePacket( } if !k.connectionKeeper.VerifyMembership( - ctx, connection, proofHeight, proof, + ctx, connectionEnd, proofHeight, proof, types.PacketAcknowledgementPath(packet.DestPort(), packet.DestChannel(), packet.Sequence()), acknowledgement, // TODO: hash ACK ) { diff --git a/x/ibc/04-channel/keeper/querier.go b/x/ibc/04-channel/keeper/querier.go index bc4b18f4f310..08a371f028c0 100644 --- a/x/ibc/04-channel/keeper/querier.go +++ b/x/ibc/04-channel/keeper/querier.go @@ -9,20 +9,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ) -// NewQuerier creates a querier for the IBC channel -func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { - switch path[0] { - case types.QueryChannel: - return queryClientState(ctx, req, k) - - default: - return nil, sdk.ErrUnknownRequest("unknown IBC channel query endpoint") - } - } -} - -func queryClientState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +// QuerierChannel defines the sdk.Querier to query a module's channel +func QuerierChannel(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { var params types.QueryChannelParams err := types.SubModuleCdc.UnmarshalJSON(req.Data, ¶ms) diff --git a/x/ibc/04-channel/keeper/timeout.go b/x/ibc/04-channel/keeper/timeout.go index 725e49b58ba8..24b14f70e9e4 100644 --- a/x/ibc/04-channel/keeper/timeout.go +++ b/x/ibc/04-channel/keeper/timeout.go @@ -3,12 +3,13 @@ package keeper import ( "bytes" "errors" + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // TimeoutPacket is called by a module which originally attempted to send a @@ -19,7 +20,7 @@ import ( func (k Keeper) TimeoutPacket( ctx sdk.Context, packet exported.PacketI, - proof ics23.Proof, + proof commitment.ProofI, proofHeight uint64, nextSequenceRecv uint64, ) (exported.PacketI, error) { @@ -29,7 +30,10 @@ func (k Keeper) TimeoutPacket( } if channel.State != types.OPEN { - return nil, errors.New("channel is not open") // TODO: sdk.Error + return nil, types.ErrInvalidChannelState( + k.codespace, + fmt.Sprintf("channel state is not OPEN (got %s)", channel.State.String()), + ) } _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) @@ -45,9 +49,9 @@ func (k Keeper) TimeoutPacket( return nil, errors.New("invalid packet destination channel") } - connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) + return nil, connection.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } if packet.DestPort() != channel.Counterparty.PortID { @@ -71,13 +75,13 @@ func (k Keeper) TimeoutPacket( switch channel.Ordering { case types.ORDERED: ok = k.connectionKeeper.VerifyMembership( - ctx, connection, proofHeight, proof, + ctx, connectionEnd, proofHeight, proof, types.NextSequenceRecvPath(packet.DestPort(), packet.DestChannel()), sdk.Uint64ToBigEndian(nextSequenceRecv), ) case types.UNORDERED: ok = k.connectionKeeper.VerifyNonMembership( - ctx, connection, proofHeight, proof, + ctx, connectionEnd, proofHeight, proof, types.PacketAcknowledgementPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), ) default: @@ -105,7 +109,7 @@ func (k Keeper) TimeoutOnClose( ctx sdk.Context, packet exported.PacketI, proofNonMembership, - proofClosed ics23.Proof, + proofClosed commitment.ProofI, proofHeight uint64, ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) @@ -126,9 +130,9 @@ func (k Keeper) TimeoutOnClose( return nil, errors.New("invalid packet destination channel") } - connection, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, connectiontypes.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) + return nil, connection.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } if packet.DestPort() != channel.Counterparty.PortID { @@ -155,7 +159,7 @@ func (k Keeper) TimeoutOnClose( } if !k.connectionKeeper.VerifyMembership( - ctx, connection, proofHeight, proofClosed, + ctx, connectionEnd, proofHeight, proofClosed, types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), bz, ) { @@ -163,7 +167,7 @@ func (k Keeper) TimeoutOnClose( } if !k.connectionKeeper.VerifyNonMembership( - ctx, connection, proofHeight, proofNonMembership, + ctx, connectionEnd, proofHeight, proofNonMembership, types.PacketAcknowledgementPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), ) { return nil, errors.New("cannot verify absence of acknowledgement at packet index") diff --git a/x/ibc/04-channel/types/channel.go b/x/ibc/04-channel/types/channel.go index 923096135440..8b9e7c9c0511 100644 --- a/x/ibc/04-channel/types/channel.go +++ b/x/ibc/04-channel/types/channel.go @@ -1,8 +1,16 @@ package types +import ( + "encoding/json" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" +) + type Channel struct { - State ChannelState `json:"state" yaml:"state"` - Ordering ChannelOrder `json:"ordering" yaml:"ordering"` + State State `json:"state" yaml:"state"` + Ordering Order `json:"ordering" yaml:"ordering"` Counterparty Counterparty `json:"counterparty" yaml:"counterparty"` ConnectionHops []string `json:"connection_hops" yaml:"connection_hops"` Version string `json:"version" yaml:"version "` @@ -10,7 +18,7 @@ type Channel struct { // NewChannel creates a new Channel instance func NewChannel( - state ChannelState, ordering ChannelOrder, counterparty Counterparty, + state State, ordering Order, counterparty Counterparty, hops []string, version string, ) Channel { return Channel{ @@ -46,80 +54,154 @@ func NewCounterparty(portID, channelID string) Counterparty { } } -// ChannelOrder defines if a channel is ORDERED or UNORDERED -type ChannelOrder byte +// ValidateBasic performs a basic validation check of the identifiers +func (c Counterparty) ValidateBasic() sdk.Error { + if err := host.DefaultIdentifierValidator(c.PortID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid counterparty connection ID: %s", err.Error())) + } + if err := host.DefaultIdentifierValidator(c.ChannelID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid counterparty client ID: %s", err.Error())) + } + return nil +} + +// Order defines if a channel is ORDERED or UNORDERED +type Order byte + +// string representation of the channel ordering +const ( + NONE Order = iota // zero-value for channel ordering + UNORDERED // packets can be delivered in any order, which may differ from the order in which they were sent. + ORDERED // packets are delivered exactly in the order which they were sent +) // channel order types const ( - NONE ChannelOrder = iota // zero-value for channel ordering - UNORDERED // packets can be delivered in any order, which may differ from the order in which they were sent. - ORDERED // packets are delivered exactly in the order which they were sent + OrderNone string = "NONE" + OrderUnordered string = "UNORDERED" + OrderOrdered string = "ORDERED" ) -// ChannelOrderToString returns the string representation of a channel order -func ChannelOrderToString(order ChannelOrder) string { - switch order { +// String implements the Stringer interface +func (o Order) String() string { + switch o { + case NONE: + return OrderNone case UNORDERED: - return "UNORDERED" + return OrderUnordered case ORDERED: - return "ORDERED" + return OrderOrdered default: return "" } } -// StringToChannelOrder parses a string into a channel order byte -func StringToChannelOrder(order string) ChannelOrder { +// MarshalJSON marshal to JSON using string. +func (o Order) MarshalJSON() ([]byte, error) { + return json.Marshal(o.String()) +} + +// UnmarshalJSON decodes from JSON. +func (o *Order) UnmarshalJSON(data []byte) error { + var s string + err := json.Unmarshal(data, &s) + if err != nil { + return err + } + + bz2, err := OrderFromString(s) + if err != nil { + return err + } + + *o = bz2 + return nil +} + +// OrderFromString parses a string into a channel order byte +func OrderFromString(order string) (Order, error) { switch order { - case "UNORDERED": - return UNORDERED - case "ORDERED": - return ORDERED + case OrderNone: + return NONE, nil + case OrderUnordered: + return UNORDERED, nil + case OrderOrdered: + return ORDERED, nil default: - return NONE + return 0, fmt.Errorf("'%s' is not a valid channel ordering", order) } } -// ChannelState defines if a channel is in one of the following states: +// State defines if a channel is in one of the following states: // CLOSED, INIT, OPENTRY or OPEN -type ChannelState byte +type State byte // channel state types const ( - CLOSED ChannelState = iota + 1 // A channel end has been closed and can no longer be used to send or receive packets. - INIT // A channel end has just started the opening handshake. - OPENTRY // A channel end has acknowledged the handshake step on the counterparty chain. - OPEN // A channel end has completed the handshake and is ready to send and receive packets. + CLOSED State = iota + 1 // A channel end has been closed and can no longer be used to send or receive packets. + INIT // A channel end has just started the opening handshake. + OPENTRY // A channel end has acknowledged the handshake step on the counterparty chain. + OPEN // A channel end has completed the handshake and is ready to send and receive packets. ) -// ChannelStateToString returns the string representation of a channel state -func ChannelStateToString(state ChannelState) string { - switch state { +// string representation of the channel states +const ( + StateClosed string = "CLOSED" + StateInit string = "INIT" + StateOpenTry string = "OPENTRY" + StateOpen string = "OPEN" +) + +// String implements the Stringer interface +func (s State) String() string { + switch s { case CLOSED: - return "CLOSED" + return StateClosed case INIT: - return "INIT" + return StateInit case OPENTRY: - return "OPENTRY" + return StateOpenTry case OPEN: - return "OPEN" + return StateOpen default: - return "CLOSED" + return "" } } -// StringToChannelState parses a string into a channel state byte -func StringToChannelState(state string) ChannelState { +// MarshalJSON marshal to JSON using string. +func (s State) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// UnmarshalJSON decodes from JSON. +func (s *State) UnmarshalJSON(data []byte) error { + var stateStr string + err := json.Unmarshal(data, &stateStr) + if err != nil { + return err + } + + bz2, err := StateFromString(stateStr) + if err != nil { + return err + } + + *s = bz2 + return nil +} + +// StateFromString parses a string into a channel state byte +func StateFromString(state string) (State, error) { switch state { - case "CLOSED": - return CLOSED - case "INIT": - return INIT - case "OPENTRY": - return OPENTRY - case "OPEN": - return OPEN + case StateClosed: + return CLOSED, nil + case StateInit: + return INIT, nil + case StateOpenTry: + return OPENTRY, nil + case StateOpen: + return OPEN, nil default: - return CLOSED + return CLOSED, fmt.Errorf("'%s' is not a valid channel state", state) } } diff --git a/x/ibc/04-channel/types/errors.go b/x/ibc/04-channel/types/errors.go index 402db58ce9d9..d2b2c5a179f4 100644 --- a/x/ibc/04-channel/types/errors.go +++ b/x/ibc/04-channel/types/errors.go @@ -20,6 +20,8 @@ const ( CodePacketTimeout sdk.CodeType = 108 CodeInvalidPortID sdk.CodeType = 109 CodeInvalidChannelID sdk.CodeType = 110 + CodeInvalidChannelState sdk.CodeType = 111 + CodeInvalidPacketData sdk.CodeType = 112 ) // ErrChannelExists implements sdk.Error @@ -71,3 +73,13 @@ func ErrInvalidPortID(codespace sdk.CodespaceType, msg string) sdk.Error { func ErrInvalidChannelID(codespace sdk.CodespaceType, msg string) sdk.Error { return sdk.NewError(codespace, CodeInvalidChannelID, msg) } + +// ErrInvalidChannelState implements sdk.Error +func ErrInvalidChannelState(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidChannelState, msg) +} + +// ErrInvalidPacketData implements sdk.Error +func ErrInvalidPacketData(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidPacketData, msg) +} diff --git a/x/ibc/04-channel/types/expected_keepers.go b/x/ibc/04-channel/types/expected_keepers.go index 56b1c90a051e..3789bb2422fa 100644 --- a/x/ibc/04-channel/types/expected_keepers.go +++ b/x/ibc/04-channel/types/expected_keepers.go @@ -3,8 +3,8 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" - commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // ClientKeeper expected account IBC client keeper @@ -14,18 +14,19 @@ type ClientKeeper interface { // ConnectionKeeper expected account IBC connection keeper type ConnectionKeeper interface { - GetConnection(ctx sdk.Context, connectionID string) (connectiontypes.ConnectionEnd, bool) + GetConnection(ctx sdk.Context, connectionID string) (connection.End, bool) VerifyMembership( - ctx sdk.Context, connection connectiontypes.ConnectionEnd, height uint64, - proof commitmentexported.ProofI, path string, value []byte, + ctx sdk.Context, connection connection.End, height uint64, + proof commitment.ProofI, path string, value []byte, ) bool VerifyNonMembership( - ctx sdk.Context, connection connectiontypes.ConnectionEnd, height uint64, - proof commitmentexported.ProofI, path string, + ctx sdk.Context, connection connection.End, height uint64, + proof commitment.ProofI, path string, ) bool } // PortKeeper expected account IBC port keeper type PortKeeper interface { GetPort(ctx sdk.Context, portID string) (sdk.CapabilityKey, bool) + Authenticate(key sdk.CapabilityKey, portID string) bool } diff --git a/x/ibc/04-channel/types/msgs.go b/x/ibc/04-channel/types/msgs.go index 8b9a883f1b0f..72fd1b664915 100644 --- a/x/ibc/04-channel/types/msgs.go +++ b/x/ibc/04-channel/types/msgs.go @@ -2,20 +2,14 @@ package types import ( "fmt" - "strings" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) -const ( - // TODO: double check lenght. Eventually move to ICS24 - lenPortID = 64 - lenChanID = 64 -) - var _ sdk.Msg = MsgChannelOpenInit{} type MsgChannelOpenInit struct { @@ -49,23 +43,13 @@ func (msg MsgChannelOpenInit) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenInit) ValidateBasic() sdk.Error { - if strings.TrimSpace(msg.PortID) == "" { - return ErrInvalidPortID(DefaultCodespace, "port ID can't be blank") - } - - if len(msg.PortID) > lenPortID { - return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("port ID length can't be > %d", lenPortID)) + if err := host.DefaultIdentifierValidator(msg.PortID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) } - - if strings.TrimSpace(msg.ChannelID) == "" { - return ErrInvalidPortID(DefaultCodespace, "channel ID can't be blank") - } - - if len(msg.ChannelID) > lenChanID { - return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("channel ID length can't be > %d", lenChanID)) + if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } - - // Signer can be empty + // Signer can be empty // TODO: Why? return nil } @@ -82,18 +66,18 @@ func (msg MsgChannelOpenInit) GetSigners() []sdk.AccAddress { var _ sdk.Msg = MsgChannelOpenTry{} type MsgChannelOpenTry struct { - PortID string `json:"port_id"` - ChannelID string `json:"channel_id"` - Channel Channel `json:"channel"` - CounterpartyVersion string `json:"counterparty_version"` - ProofInit ics23.Proof `json:"proof_init"` - ProofHeight uint64 `json:"proof_height"` - Signer sdk.AccAddress `json:"signer"` + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + Channel Channel `json:"channel"` + CounterpartyVersion string `json:"counterparty_version"` + ProofInit commitment.ProofI `json:"proof_init"` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` } // NewMsgChannelOpenTry creates a new MsgChannelOpenTry instance func NewMsgChannelOpenTry( - portID, channelID string, channel Channel, cpv string, proofInit ics23.Proof, + portID, channelID string, channel Channel, cpv string, proofInit commitment.ProofI, proofHeight uint64, signer sdk.AccAddress, ) MsgChannelOpenTry { return MsgChannelOpenTry{ @@ -119,21 +103,11 @@ func (msg MsgChannelOpenTry) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenTry) ValidateBasic() sdk.Error { - - if strings.TrimSpace(msg.PortID) == "" { - return ErrInvalidPortID(DefaultCodespace, "port ID can't be blank") + if err := host.DefaultIdentifierValidator(msg.PortID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) } - - if len(msg.PortID) > lenPortID { - return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("port ID length can't be > %d", lenPortID)) - } - - if strings.TrimSpace(msg.ChannelID) == "" { - return ErrInvalidPortID(DefaultCodespace, "channel ID can't be blank") - } - - if len(msg.ChannelID) > lenChanID { - return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("channel ID length can't be > %d", lenChanID)) + if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } // Check proofs != nil @@ -155,17 +129,17 @@ func (msg MsgChannelOpenTry) GetSigners() []sdk.AccAddress { var _ sdk.Msg = MsgChannelOpenAck{} type MsgChannelOpenAck struct { - PortID string `json:"port_id"` - ChannelID string `json:"channel_id"` - CounterpartyVersion string `json:"counterparty_version"` - ProofTry ics23.Proof `json:"proof_try"` - ProofHeight uint64 `json:"proof_height"` - Signer sdk.AccAddress `json:"signer"` + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + CounterpartyVersion string `json:"counterparty_version"` + ProofTry commitment.ProofI `json:"proof_try"` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` } // NewMsgChannelOpenAck creates a new MsgChannelOpenAck instance func NewMsgChannelOpenAck( - portID, channelID string, cpv string, proofTry ics23.Proof, proofHeight uint64, + portID, channelID string, cpv string, proofTry commitment.ProofI, proofHeight uint64, signer sdk.AccAddress, ) MsgChannelOpenAck { return MsgChannelOpenAck{ @@ -190,20 +164,11 @@ func (msg MsgChannelOpenAck) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenAck) ValidateBasic() sdk.Error { - if strings.TrimSpace(msg.PortID) == "" { - return ErrInvalidPortID(DefaultCodespace, "port ID can't be blank") - } - - if len(msg.PortID) > lenPortID { - return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("port ID length can't be > %d", lenPortID)) - } - - if strings.TrimSpace(msg.ChannelID) == "" { - return ErrInvalidPortID(DefaultCodespace, "channel ID can't be blank") + if err := host.DefaultIdentifierValidator(msg.PortID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) } - - if len(msg.ChannelID) > lenChanID { - return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("channel ID length can't be > %d", lenChanID)) + if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } // Check proofs != nil @@ -224,16 +189,16 @@ func (msg MsgChannelOpenAck) GetSigners() []sdk.AccAddress { var _ sdk.Msg = MsgChannelOpenConfirm{} type MsgChannelOpenConfirm struct { - PortID string `json:"port_id"` - ChannelID string `json:"channel_id"` - ProofAck ics23.Proof `json:"proof_ack"` - ProofHeight uint64 `json:"proof_height"` - Signer sdk.AccAddress `json:"signer"` + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + ProofAck commitment.ProofI `json:"proof_ack"` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` } // NewMsgChannelOpenConfirm creates a new MsgChannelOpenConfirm instance func NewMsgChannelOpenConfirm( - portID, channelID string, proofAck ics23.Proof, proofHeight uint64, + portID, channelID string, proofAck commitment.ProofI, proofHeight uint64, signer sdk.AccAddress, ) MsgChannelOpenConfirm { return MsgChannelOpenConfirm{ @@ -257,20 +222,11 @@ func (msg MsgChannelOpenConfirm) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenConfirm) ValidateBasic() sdk.Error { - if strings.TrimSpace(msg.PortID) == "" { - return ErrInvalidPortID(DefaultCodespace, "port ID can't be blank") - } - - if len(msg.PortID) > lenPortID { - return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("port ID length can't be > %d", lenPortID)) + if err := host.DefaultIdentifierValidator(msg.PortID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) } - - if strings.TrimSpace(msg.ChannelID) == "" { - return ErrInvalidPortID(DefaultCodespace, "channel ID can't be blank") - } - - if len(msg.ChannelID) > lenChanID { - return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("channel ID length can't be > %d", lenChanID)) + if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } // Check proofs != nil @@ -317,20 +273,11 @@ func (msg MsgChannelCloseInit) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgChannelCloseInit) ValidateBasic() sdk.Error { - if strings.TrimSpace(msg.PortID) == "" { - return ErrInvalidPortID(DefaultCodespace, "port ID can't be blank") + if err := host.DefaultIdentifierValidator(msg.PortID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) } - - if len(msg.PortID) > lenPortID { - return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("port ID length can't be > %d", lenPortID)) - } - - if strings.TrimSpace(msg.ChannelID) == "" { - return ErrInvalidPortID(DefaultCodespace, "channel ID can't be blank") - } - - if len(msg.ChannelID) > lenChanID { - return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("channel ID length can't be > %d", lenChanID)) + if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } // Signer can be empty @@ -350,16 +297,16 @@ func (msg MsgChannelCloseInit) GetSigners() []sdk.AccAddress { var _ sdk.Msg = MsgChannelCloseConfirm{} type MsgChannelCloseConfirm struct { - PortID string `json:"port_id"` - ChannelID string `json:"channel_id"` - ProofInit ics23.Proof `json:"proof_init"` - ProofHeight uint64 `json:"proof_height"` - Signer sdk.AccAddress `json:"signer"` + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` + ProofInit commitment.ProofI `json:"proof_init"` + ProofHeight uint64 `json:"proof_height"` + Signer sdk.AccAddress `json:"signer"` } // NewMsgChannelCloseConfirm creates a new MsgChannelCloseConfirm instance func NewMsgChannelCloseConfirm( - portID, channelID string, proofInit ics23.Proof, proofHeight uint64, + portID, channelID string, proofInit commitment.ProofI, proofHeight uint64, signer sdk.AccAddress, ) MsgChannelCloseConfirm { return MsgChannelCloseConfirm{ @@ -383,20 +330,11 @@ func (msg MsgChannelCloseConfirm) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgChannelCloseConfirm) ValidateBasic() sdk.Error { - if strings.TrimSpace(msg.PortID) == "" { - return ErrInvalidPortID(DefaultCodespace, "port ID can't be blank") + if err := host.DefaultIdentifierValidator(msg.PortID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) } - - if len(msg.PortID) > lenPortID { - return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("port ID length can't be > %d", lenPortID)) - } - - if strings.TrimSpace(msg.ChannelID) == "" { - return ErrInvalidPortID(DefaultCodespace, "channel ID can't be blank") - } - - if len(msg.ChannelID) > lenChanID { - return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("channel ID length can't be > %d", lenChanID)) + if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } // Check proofs != nil @@ -420,11 +358,11 @@ var _ sdk.Msg = MsgSendPacket{} // ChannelID can be empty if batched & not first MsgSendPacket // Height uint64 // height of the commitment root for the proofs type MsgSendPacket struct { - Packet exported.PacketI `json:"packet" yaml:"packet"` - ChannelID string `json:"channel_id" yaml:"channel_id"` - Proofs []ics23.Proof `json:"proofs" yaml:"proofs"` - Height uint64 `json:"height" yaml:"height"` - Signer sdk.AccAddress `json:"signer" yaml:"signer"` + Packet exported.PacketI `json:"packet" yaml:"packet"` + ChannelID string `json:"channel_id" yaml:"channel_id"` + Proofs []commitment.ProofI `json:"proofs" yaml:"proofs"` + Height uint64 `json:"height" yaml:"height"` + Signer sdk.AccAddress `json:"signer" yaml:"signer"` } // NewMsgSendPacket creates a new MsgSendPacket instance @@ -447,43 +385,16 @@ func (msg MsgSendPacket) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgSendPacket) ValidateBasic() sdk.Error { - // TODO: move to Packet validation function - if strings.TrimSpace(msg.Packet.SourcePort()) == "" { - return ErrInvalidPortID(DefaultCodespace, "packet source port ID can't be blank") + if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } - - if len(msg.Packet.SourcePort()) > lenPortID { - return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("packet source port ID length can't be > %d", lenPortID)) - } - - if strings.TrimSpace(msg.Packet.DestPort()) == "" { - return ErrInvalidPortID(DefaultCodespace, "packet destination port ID can't be blank") + if msg.Height == 0 { + return sdk.ErrInvalidSequence("invalid height") } - - if len(msg.Packet.DestPort()) > lenPortID { - return ErrInvalidPortID(DefaultCodespace, fmt.Sprintf("packet destination port ID length can't be > %d", lenPortID)) - } - - if strings.TrimSpace(msg.Packet.SourceChannel()) == "" { - return ErrInvalidPortID(DefaultCodespace, "packet source channel ID can't be blank") - } - - if len(msg.Packet.SourceChannel()) > lenChanID { - return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("packet source channel ID length can't be > %d", lenChanID)) - } - - if strings.TrimSpace(msg.Packet.DestChannel()) == "" { - return ErrInvalidPortID(DefaultCodespace, "packet destination channel ID can't be blank") - } - - if len(msg.Packet.DestChannel()) > lenChanID { - return ErrInvalidChannelID(DefaultCodespace, fmt.Sprintf("packet destination channel ID length can't be > %d", lenChanID)) - } - // Check proofs != nil // Check packet != nil // Signer can be empty - return nil + return msg.Packet.ValidateBasic() } // GetSignBytes implements sdk.Msg diff --git a/x/ibc/04-channel/types/packet.go b/x/ibc/04-channel/types/packet.go index 09d33748e6aa..57ca7f687c32 100644 --- a/x/ibc/04-channel/types/packet.go +++ b/x/ibc/04-channel/types/packet.go @@ -1,28 +1,32 @@ package types import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ) -var _ exported.PacketI = packet{} - -// packet defines a type that carries data across different chains through IBC -type packet struct { - sequence uint64 // number corresponds to the order of sends and receives, where a packet with an earlier sequence number must be sent and received before a packet with a later sequence number. - timeout uint64 // indicates a consensus height on the destination chain after which the packet will no longer be processed, and will instead count as having timed-out. - sourcePort string // identifies the port on the sending chain. - sourceChannel string // identifies the channel end on the sending chain. - destinationPort string // identifies the port on the receiving chain. - destinationChannel string // identifies the channel end on the receiving chain. - data []byte // opaque value which can be defined by the application logic of the associated modules. +var _ exported.PacketI = Packet{} + +// Packet defines a type that carries data across different chains through IBC +type Packet struct { + sequence uint64 `json:"sequence"` // number corresponds to the order of sends and receives, where a Packet with an earlier sequence number must be sent and received before a Packet with a later sequence number. + timeout uint64 `json:"timeout"` // indicates a consensus height on the destination chain after which the Packet will no longer be processed, and will instead count as having timed-out. + sourcePort string `json:"source_port"` // identifies the port on the sending chain. + sourceChannel string `json:"source_channel"` // identifies the channel end on the sending chain. + destinationPort string `json:"destination_port"` // identifies the port on the receiving chain. + destinationChannel string `json:"destination_channel"` // identifies the channel end on the receiving chain. + data []byte `json:"data"` // opaque value which can be defined by the application logic of the associated modules. } -// newPacket creates a new Packet instance -func newPacket( +// NewPacket creates a new Packet instance +func NewPacket( sequence, timeout uint64, sourcePort, sourceChannel, destinationPort, destinationChannel string, data []byte, -) packet { - return packet{ +) Packet { + return Packet{ sequence, timeout, sourcePort, @@ -34,31 +38,71 @@ func newPacket( } // Sequence implements PacketI interface -func (p packet) Sequence() uint64 { return p.sequence } +func (p Packet) Sequence() uint64 { return p.sequence } // TimeoutHeight implements PacketI interface -func (p packet) TimeoutHeight() uint64 { return p.timeout } +func (p Packet) TimeoutHeight() uint64 { return p.timeout } // SourcePort implements PacketI interface -func (p packet) SourcePort() string { return p.sourcePort } +func (p Packet) SourcePort() string { return p.sourcePort } // SourceChannel implements PacketI interface -func (p packet) SourceChannel() string { return p.sourceChannel } +func (p Packet) SourceChannel() string { return p.sourceChannel } // DestPort implements PacketI interface -func (p packet) DestPort() string { return p.destinationPort } +func (p Packet) DestPort() string { return p.destinationPort } // DestChannel implements PacketI interface -func (p packet) DestChannel() string { return p.destinationChannel } +func (p Packet) DestChannel() string { return p.destinationChannel } // Data implements PacketI interface -func (p packet) Data() []byte { return p.data } +func (p Packet) Data() []byte { return p.data } + +// ValidateBasic implements PacketI interface +func (p Packet) ValidateBasic() sdk.Error { + if err := host.DefaultIdentifierValidator(p.sourcePort); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid source port ID: %s", err.Error())) + } + if err := host.DefaultIdentifierValidator(p.destinationPort); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid destination port ID: %s", err.Error())) + } + if err := host.DefaultIdentifierValidator(p.sourceChannel); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid source channel ID: %s", err.Error())) + } + if err := host.DefaultIdentifierValidator(p.destinationChannel); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid destination channel ID: %s", err.Error())) + } + if p.sequence == 0 { + return ErrInvalidPacketSequence(DefaultCodespace) + } + if p.timeout == 0 { + return ErrPacketTimeout(DefaultCodespace) + } + if len(p.data) == 0 { + return ErrInvalidPacketData(DefaultCodespace, "Packet data cannot be empty") + } + return nil +} -// var _ exported.PacketI = OpaquePacket{} +var _ exported.PacketI = OpaquePacket{} -// OpaquePacket is a packet, but cloaked in an obscuring data type by the host +// OpaquePacket is a Packet, but cloaked in an obscuring data type by the host // state machine, such that a module cannot act upon it other than to pass it to // the IBC handler -type OpaquePacket packet +type OpaquePacket struct { + *Packet +} -// TODO: Obscure data type +// NewOpaquePacket creates a new OpaquePacket instance +func NewOpaquePacket(sequence, timeout uint64, sourcePort, sourceChannel, + destinationPort, destinationChannel string, data []byte, +) OpaquePacket { + Packet := NewPacket( + sequence, timeout, sourcePort, sourceChannel, destinationPort, + destinationChannel, data, + ) + return OpaquePacket{&Packet} +} + +// Data implements PacketI interface +func (op OpaquePacket) Data() []byte { return nil } diff --git a/x/ibc/05-port/alias.go b/x/ibc/05-port/alias.go index ccf3db732be3..d690f1baf507 100644 --- a/x/ibc/05-port/alias.go +++ b/x/ibc/05-port/alias.go @@ -28,7 +28,6 @@ var ( ErrInvalidPortID = types.ErrInvalidPortID PortPath = types.PortPath KeyPort = types.KeyPort - ValidatePortID = types.ValidatePortID ) type ( diff --git a/x/ibc/keeper/querier.go b/x/ibc/keeper/querier.go index cb9b260d135a..a9a36f18fa48 100644 --- a/x/ibc/keeper/querier.go +++ b/x/ibc/keeper/querier.go @@ -6,6 +6,7 @@ import ( 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" ) // NewQuerier creates a querier for the IBC module @@ -22,7 +23,8 @@ func NewQuerier(k Keeper) sdk.Querier { return connection.QuerierConnection(ctx, req, k.ConnectionKeeper) case connection.QueryClientConnections: return connection.QuerierClientConnections(ctx, req, k.ConnectionKeeper) - + case channel.QueryChannel: + return channel.QuerierChannel(ctx, req, k.ChannelKeeper) default: return nil, sdk.ErrUnknownRequest("unknown IBC query endpoint") } From a81f236fd568f794cdb7abdb9b50096234ff2110 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 24 Oct 2019 19:16:43 +0200 Subject: [PATCH 333/378] update errors and aliases --- x/ibc/04-channel/alias.go | 34 +++++++++-- x/ibc/04-channel/cli.go | 81 ------------------------- x/ibc/04-channel/client/cli/tx.go | 46 ++++----------- x/ibc/04-channel/handler.go | 4 +- x/ibc/04-channel/keeper/handshake.go | 4 +- x/ibc/04-channel/keeper/packet.go | 88 +++++++++++++++++++--------- x/ibc/04-channel/keeper/timeout.go | 38 +++++++----- x/ibc/04-channel/types/errors.go | 28 ++------- x/ibc/04-channel/types/msgs.go | 1 - x/ibc/04-channel/types/packet.go | 12 ++-- 10 files changed, 138 insertions(+), 198 deletions(-) delete mode 100644 x/ibc/04-channel/cli.go diff --git a/x/ibc/04-channel/alias.go b/x/ibc/04-channel/alias.go index 8e82aa78404a..b55f57833c60 100644 --- a/x/ibc/04-channel/alias.go +++ b/x/ibc/04-channel/alias.go @@ -12,21 +12,30 @@ import ( ) const ( + NONE = types.NONE UNORDERED = types.UNORDERED ORDERED = types.ORDERED + OrderNone = types.OrderNone + OrderUnordered = types.OrderUnordered + OrderOrdered = types.OrderOrdered CLOSED = types.CLOSED INIT = types.INIT OPENTRY = types.OPENTRY OPEN = types.OPEN + StateClosed = types.StateClosed + StateInit = types.StateInit + StateOpenTry = types.StateOpenTry + StateOpen = types.StateOpen DefaultCodespace = types.DefaultCodespace CodeChannelExists = types.CodeChannelExists CodeChannelNotFound = types.CodeChannelNotFound CodeInvalidConnectionHops = types.CodeInvalidConnectionHops CodeInvalidCounterpartyChannel = types.CodeInvalidCounterpartyChannel CodeChannelCapabilityNotFound = types.CodeChannelCapabilityNotFound - CodeInvalidPacketSequence = types.CodeInvalidPacketSequence + CodeInvalidPacket = types.CodeInvalidPacket CodeSequenceNotFound = types.CodeSequenceNotFound CodePacketTimeout = types.CodePacketTimeout + CodeInvalidChannelState = types.CodeInvalidChannelState AttributeKeySenderPort = types.AttributeKeySenderPort AttributeKeyReceiverPort = types.AttributeKeyReceiverPort AttributeKeyChannelID = types.AttributeKeyChannelID @@ -41,8 +50,11 @@ const ( var ( // functions aliases NewKeeper = keeper.NewKeeper + QuerierChannel = keeper.QuerierChannel NewChannel = types.NewChannel NewCounterparty = types.NewCounterparty + OrderFromString = types.OrderFromString + StateFromString = types.StateFromString RegisterCodec = types.RegisterCodec SetMsgChanCodec = types.SetMsgChanCodec ErrChannelExists = types.ErrChannelExists @@ -50,9 +62,10 @@ var ( ErrInvalidConnectionHops = types.ErrInvalidConnectionHops ErrInvalidCounterpartyChannel = types.ErrInvalidCounterpartyChannel ErrChannelCapabilityNotFound = types.ErrChannelCapabilityNotFound - ErrInvalidPacketSequence = types.ErrInvalidPacketSequence + ErrInvalidPacket = types.ErrInvalidPacket ErrSequenceNotFound = types.ErrSequenceNotFound ErrPacketTimeout = types.ErrPacketTimeout + ErrInvalidChannelState = types.ErrInvalidChannelState ChannelPath = types.ChannelPath ChannelCapabilityPath = types.ChannelCapabilityPath NextSequenceSendPath = types.NextSequenceSendPath @@ -65,6 +78,16 @@ var ( KeyNextSequenceRecv = types.KeyNextSequenceRecv KeyPacketCommitment = types.KeyPacketCommitment KeyPacketAcknowledgement = types.KeyPacketAcknowledgement + NewMsgChannelOpenInit = types.NewMsgChannelOpenInit + NewMsgChannelOpenTry = types.NewMsgChannelOpenTry + NewMsgChannelOpenAck = types.NewMsgChannelOpenAck + NewMsgChannelOpenConfirm = types.NewMsgChannelOpenConfirm + NewMsgChannelCloseInit = types.NewMsgChannelCloseInit + NewMsgChannelCloseConfirm = types.NewMsgChannelCloseConfirm + NewMsgSendPacket = types.NewMsgSendPacket + NewPacket = types.NewPacket + NewOpaquePacket = types.NewOpaquePacket + NewChannelResponse = types.NewChannelResponse NewQueryChannelParams = types.NewQueryChannelParams // variable aliases @@ -81,12 +104,13 @@ var ( type ( Keeper = keeper.Keeper - ChannelOrder = types.ChannelOrder - ChannelState = types.ChannelState Channel = types.Channel Counterparty = types.Counterparty + Order = types.Order + State = types.State ClientKeeper = types.ClientKeeper ConnectionKeeper = types.ConnectionKeeper + PortKeeper = types.PortKeeper MsgChannelOpenInit = types.MsgChannelOpenInit MsgChannelOpenTry = types.MsgChannelOpenTry MsgChannelOpenAck = types.MsgChannelOpenAck @@ -94,6 +118,8 @@ type ( MsgChannelCloseInit = types.MsgChannelCloseInit MsgChannelCloseConfirm = types.MsgChannelCloseConfirm MsgSendPacket = types.MsgSendPacket + Packet = types.Packet OpaquePacket = types.OpaquePacket + ChannelResponse = types.ChannelResponse QueryChannelParams = types.QueryChannelParams ) diff --git a/x/ibc/04-channel/cli.go b/x/ibc/04-channel/cli.go deleted file mode 100644 index 0cbc44a37b80..000000000000 --- a/x/ibc/04-channel/cli.go +++ /dev/null @@ -1,81 +0,0 @@ -package channel - -// import ( -// "bytes" - -// "github.com/cosmos/cosmos-sdk/store/state" -// "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/merkle" -// ) - -// 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.State(connid)) -// } -// return obj -// } - -// func (man Manager) CLIQuery(q state.ABCIQuerier, portid, chanid string) (obj State, err error) { -// obj = man.object(portid, chanid) -// channel, _, err := obj.ChannelCLI(q) -// if err != nil { -// return -// } -// for _, connid := range channel.ConnectionHops { -// obj.Connections = append(obj.Connections, man.connection.State(connid)) -// } -// return -// } - -// func (obj State) prefix() []byte { -// return bytes.Split(obj.Channel.KeyBytes(), LocalRoot())[0] -// } - -// 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 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 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 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 State) PacketCLI(q state.ABCIQuerier, index uint64) (res Packet, proof merkle.Proof, err error) { -// packet := obj.Packets.Value(index) -// tmproof, err := packet.Query(q, &res) -// proof = merkle.NewProofFromValue(tmproof, obj.prefix(), packet) -// return -// } - -// func (man Handshaker) CLIQuery(q state.ABCIQuerier, portid, chanid string) (HandshakeState, error) { -// obj, err := man.Manager.CLIQuery(q, portid, chanid) -// if err != nil { -// return HandshakeState{}, err -// } -// return man.createState(obj), nil -// } - -// func (man Handshaker) CLIState(portid, chanid string, connids []string) HandshakeState { -// return man.createState(man.Manager.CLIState(portid, chanid, connids)) -// } - -// 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/tx.go b/x/ibc/04-channel/client/cli/tx.go index f0bec2764fc2..f30f3f21846f 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -105,12 +105,12 @@ func GetMsgChannelOpenTryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { } } - proofHeight, err := validateProofHeight(args[6]) + proofHeight, err := strconv.ParseInt(args[6], 10, 64) if err != nil { return err } - msg := types.NewMsgChannelOpenTry(portID, channelID, channel, IBCVersion, proof, proofHeight, cliCtx.GetFromAddress()) + msg := types.NewMsgChannelOpenTry(portID, channelID, channel, IBCVersion, proof, uint64(proofHeight), cliCtx.GetFromAddress()) if err := msg.ValidateBasic(); err != nil { return err } @@ -149,12 +149,12 @@ func GetMsgChannelOpenAckCmd(storeKey string, cdc *codec.Codec) *cobra.Command { } } - proofHeight, err := validateProofHeight(args[3]) + proofHeight, err := strconv.ParseInt(args[3], 10, 64) if err != nil { return err } - msg := types.NewMsgChannelOpenAck(portID, channelID, IBCVersion, proof, proofHeight, cliCtx.GetFromAddress()) + msg := types.NewMsgChannelOpenAck(portID, channelID, IBCVersion, proof, uint64(proofHeight), cliCtx.GetFromAddress()) if err := msg.ValidateBasic(); err != nil { return err } @@ -190,12 +190,12 @@ func GetMsgChannelOpenConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comma } } - proofHeight, err := validateProofHeight(args[3]) + proofHeight, err := strconv.ParseInt(args[3], 10, 64) if err != nil { return err } - msg := types.NewMsgChannelOpenConfirm(portID, channelID, proof, proofHeight, cliCtx.GetFromAddress()) + msg := types.NewMsgChannelOpenConfirm(portID, channelID, proof, uint64(proofHeight), cliCtx.GetFromAddress()) if err := msg.ValidateBasic(); err != nil { return err } @@ -255,12 +255,12 @@ func GetMsgChannelCloseConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comm } } - proofHeight, err := validateProofHeight(args[3]) + proofHeight, err := strconv.ParseInt(args[3], 10, 64) if err != nil { return err } - msg := types.NewMsgChannelCloseConfirm(portID, channelID, proof, proofHeight, cliCtx.GetFromAddress()) + msg := types.NewMsgChannelCloseConfirm(portID, channelID, proof, uint64(proofHeight), cliCtx.GetFromAddress()) if err := msg.ValidateBasic(); err != nil { return err } @@ -304,46 +304,20 @@ func GetMsgSendPacketCmd(storeKey string, cdc *codec.Codec) *cobra.Command { return cmd } -func channelOrder() types.ChannelOrder { +func channelOrder() types.Order { if viper.GetBool(FlagUnordered) { return types.UNORDERED } return types.ORDERED } -// TODO: Move to ICS24 -func validatePortID(pid string) (string, error) { - // TODO: Add validation here - return pid, nil -} - -func validateChannelID(cid string) (string, error) { - // TODO: Add validation here - return cid, nil -} - func validateChannelHops(hops string) ([]string, error) { // TODO: Add validation here return strings.Split(hops, ","), nil } -func validateProofHeight(height string) (uint64, error) { - // TODO: More validation? - i, err := strconv.ParseInt(height, 10, 64) - return uint64(i), err -} - -func createChannelFromArgs(pid string, cid string, hops string) (types.Channel, error) { +func createChannelFromArgs(portID, channelID string, hops string) (types.Channel, error) { var channel types.Channel - portID, err := validatePortID(pid) - if err != nil { - return channel, err - } - - channelID, err := validateChannelID(cid) - if err != nil { - return channel, err - } channelHops, err := validateChannelHops(hops) if err != nil { diff --git a/x/ibc/04-channel/handler.go b/x/ibc/04-channel/handler.go index da5304e7ac5c..b4e62b666e23 100644 --- a/x/ibc/04-channel/handler.go +++ b/x/ibc/04-channel/handler.go @@ -8,7 +8,7 @@ import ( // HandleMsgChannelOpenInit defines the sdk.Handler for MsgChannelOpenInit func HandleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenInit) sdk.Result { - _, err := k.ChanOpenInit( + err := k.ChanOpenInit( ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, msg.Channel.Counterparty, msg.Channel.Version, ) @@ -34,7 +34,7 @@ func HandleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgCha // HandleMsgChannelOpenTry defines the sdk.Handler for MsgChannelOpenTry func HandleMsgChannelOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenTry) sdk.Result { - _, err := k.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, + err := k.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, msg.Channel.Counterparty, msg.Channel.Version, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, ) if err != nil { diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go index f89d0c7a9e9c..19292249a264 100644 --- a/x/ibc/04-channel/keeper/handshake.go +++ b/x/ibc/04-channel/keeper/handshake.go @@ -50,7 +50,7 @@ func (k Keeper) ChanOpenInit( } // if !k.portKeeper.AuthenticatePort(port.ID()) { - // return errors.New("port is not valid") // TODO: ics05 sdk.Error + // return errors.New("port is not valid") // } channel := types.NewChannel(types.INIT, order, counterparty, connectionHops, version) @@ -93,7 +93,7 @@ func (k Keeper) ChanOpenTry( } // if !k.portKeeper.AuthenticatePort(port.ID()) { - // return errors.New("port is not valid") // TODO: ics05 sdk.Error + // return errors.New("port is not valid") // } connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go index 01e375a3f331..82b871d31284 100644 --- a/x/ibc/04-channel/keeper/packet.go +++ b/x/ibc/04-channel/keeper/packet.go @@ -6,6 +6,7 @@ import ( "fmt" 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" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" @@ -48,11 +49,14 @@ func (k Keeper) CleanupPacket( } // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") // TODO: sdk.Error + // return errors.New("invalid capability key") // } if packet.DestChannel() != channel.Counterparty.ChannelID { - return nil, errors.New("invalid packet destination channel") + return nil, types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.DestChannel(), channel.Counterparty.ChannelID), + ) } connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) @@ -61,16 +65,19 @@ func (k Keeper) CleanupPacket( } if packet.DestPort() != channel.Counterparty.PortID { - return nil, errors.New("invalid packet destination port") + return nil, types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.DestPort(), channel.Counterparty.PortID), + ) } if nextSequenceRecv >= packet.Sequence() { - return nil, errors.New("packet already received") + return nil, types.ErrInvalidPacket(k.codespace, "packet already received") } commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data - return nil, errors.New("packet hasn't been sent") + return nil, types.ErrInvalidPacket(k.codespace, "packet hasn't been sent") } var ok bool @@ -88,11 +95,11 @@ func (k Keeper) CleanupPacket( acknowledgement, ) default: - panic("invalid channel ordering type") + panic(fmt.Sprintf("invalid channel ordering type %v", channel.Ordering)) } if !ok { - return nil, errors.New("failed packet verification") // TODO: sdk.Error + return nil, types.ErrInvalidPacket(k.codespace, "packet verification failed") } k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) @@ -105,7 +112,7 @@ func (k Keeper) CleanupPacket( func (k Keeper) SendPacket(ctx sdk.Context, packet exported.PacketI) error { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return errors.New("channel not found") // TODO: sdk.Error + return types.ErrChannelNotFound(k.codespace, packet.SourceChannel()) } if channel.State == types.CLOSED { @@ -117,33 +124,42 @@ func (k Keeper) SendPacket(ctx sdk.Context, packet exported.PacketI) error { _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { - return errors.New("channel capability key not found") // TODO: sdk.Error + return types.ErrChannelCapabilityNotFound(k.codespace) } // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") // TODO: sdk.Error + // return errors.New("invalid capability key") // } if packet.DestPort() != channel.Counterparty.PortID { - return errors.New("invalid packet destination port") + return types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.DestPort(), channel.Counterparty.PortID), + ) } if packet.DestChannel() != channel.Counterparty.ChannelID { - return errors.New("invalid packet destination channel") + return types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.DestChannel(), channel.Counterparty.ChannelID), + ) } connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return errors.New("connection not found") // TODO: ics03 sdk.Error + return connection.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } if connectionEnd.State == connection.NONE { - return errors.New("connection is closed") // TODO: sdk.Error + return connection.ErrInvalidConnectionState( + k.codespace, + fmt.Sprintf("connection is closed (i.e NONE)"), + ) } consensusState, found := k.clientKeeper.GetConsensusState(ctx, connectionEnd.ClientID) if !found { - return errors.New("consensus state not found") // TODO: sdk.Error + return client.ErrConsensusStateNotFound(k.codespace) } if consensusState.GetHeight() >= packet.TimeoutHeight() { @@ -156,7 +172,10 @@ func (k Keeper) SendPacket(ctx sdk.Context, packet exported.PacketI) error { } if packet.Sequence() != nextSequenceSend { - return types.ErrInvalidPacketSequence(k.codespace) + return types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet sequence ≠ next send sequence (%d ≠ %d)", packet.Sequence(), nextSequenceSend), + ) } nextSequenceSend++ @@ -194,16 +213,22 @@ func (k Keeper) RecvPacket( } // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") // TODO: sdk.Error + // return errors.New("invalid capability key") // } // packet must come from the channel's counterparty if packet.SourcePort() != channel.Counterparty.PortID { - return nil, errors.New("invalid packet source port") + return nil, types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet source port doesn't match the counterparty's port (%s ≠ %s)", packet.SourcePort(), channel.Counterparty.PortID), + ) } if packet.SourceChannel() != channel.Counterparty.ChannelID { - return nil, errors.New("invalid packet source channel") + return nil, types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet source channel doesn't match the counterparty's channel (%s ≠ %s)", packet.SourceChannel(), channel.Counterparty.ChannelID), + ) } connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) @@ -212,7 +237,7 @@ func (k Keeper) RecvPacket( } if connectionEnd.State != connection.OPEN { - return connection.ErrInvalidConnectionState( + return nil, connection.ErrInvalidConnectionState( k.codespace, fmt.Sprintf("connection state is not OPEN (got %s)", connectionEnd.State.String()), ) @@ -222,8 +247,6 @@ func (k Keeper) RecvPacket( return nil, types.ErrPacketTimeout(k.codespace) } - // TODO: cast to packet - if !k.connectionKeeper.VerifyMembership( ctx, connectionEnd, proofHeight, proof, types.PacketCommitmentPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), @@ -246,7 +269,10 @@ func (k Keeper) RecvPacket( } if packet.Sequence() != nextSequenceRecv { - return nil, types.ErrInvalidPacketSequence(k.codespace) + return nil, types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet sequence ≠ next receive sequence (%d ≠ %d)", packet.Sequence(), nextSequenceRecv), + ) } nextSequenceRecv++ @@ -286,16 +312,22 @@ func (k Keeper) AcknowledgePacket( } // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") // TODO: sdk.Error + // return errors.New("invalid capability key") // } // packet must come from the channel's counterparty if packet.SourcePort() != channel.Counterparty.PortID { - return nil, errors.New("invalid packet source port") + return nil, types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet source port doesn't match the counterparty's port (%s ≠ %s)", packet.SourcePort(), channel.Counterparty.PortID), + ) } if packet.SourceChannel() != channel.Counterparty.ChannelID { - return nil, errors.New("invalid packet source channel") + return nil, types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet source channel doesn't match the counterparty's channel (%s ≠ %s)", packet.SourceChannel(), channel.Counterparty.ChannelID), + ) } connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) @@ -304,7 +336,7 @@ func (k Keeper) AcknowledgePacket( } if connectionEnd.State != connection.OPEN { - return connection.ErrInvalidConnectionState( + return nil, connection.ErrInvalidConnectionState( k.codespace, fmt.Sprintf("connection state is not OPEN (got %s)", connectionEnd.State.String()), ) @@ -312,7 +344,7 @@ func (k Keeper) AcknowledgePacket( commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data - return nil, errors.New("packet hasn't been sent") + return nil, types.ErrInvalidPacket(k.codespace, "packet hasn't been sent") } if !k.connectionKeeper.VerifyMembership( diff --git a/x/ibc/04-channel/keeper/timeout.go b/x/ibc/04-channel/keeper/timeout.go index 24b14f70e9e4..f75f04f4fe3b 100644 --- a/x/ibc/04-channel/keeper/timeout.go +++ b/x/ibc/04-channel/keeper/timeout.go @@ -42,11 +42,14 @@ func (k Keeper) TimeoutPacket( } // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") // TODO: sdk.Error + // return errors.New("invalid capability key") // } if packet.DestChannel() != channel.Counterparty.ChannelID { - return nil, errors.New("invalid packet destination channel") + return nil, types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.DestChannel(), channel.Counterparty.ChannelID), + ) } connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) @@ -55,7 +58,10 @@ func (k Keeper) TimeoutPacket( } if packet.DestPort() != channel.Counterparty.PortID { - return nil, errors.New("invalid packet destination port") + return nil, types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.DestPort(), channel.Counterparty.PortID), + ) } if proofHeight < packet.TimeoutHeight() { @@ -63,12 +69,12 @@ func (k Keeper) TimeoutPacket( } if nextSequenceRecv >= packet.Sequence() { - return nil, errors.New("packet already received") + return nil, types.ErrInvalidPacket(k.codespace, "packet already received") } commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data - return nil, errors.New("packet hasn't been sent") + return nil, types.ErrInvalidPacket(k.codespace, "packet hasn't been sent") } var ok bool @@ -85,11 +91,11 @@ func (k Keeper) TimeoutPacket( types.PacketAcknowledgementPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), ) default: - panic("invalid channel ordering type") + panic(fmt.Sprintf("invalid channel ordering type %v", channel.Ordering)) } if !ok { - return nil, errors.New("failed packet verification") // TODO: sdk.Error + return nil, types.ErrInvalidPacket(k.codespace, "packet verification failed") } k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) @@ -123,11 +129,14 @@ func (k Keeper) TimeoutOnClose( } // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") // TODO: sdk.Error + // return errors.New("invalid capability key") // } if packet.DestChannel() != channel.Counterparty.ChannelID { - return nil, errors.New("invalid packet destination channel") + return nil, types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.DestChannel(), channel.Counterparty.ChannelID), + ) } connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) @@ -136,16 +145,15 @@ func (k Keeper) TimeoutOnClose( } if packet.DestPort() != channel.Counterparty.PortID { - return nil, errors.New("invalid packet destination port") - } - - if packet.DestPort() != channel.Counterparty.PortID { - return nil, errors.New("port id doesn't match with counterparty's") + return nil, types.ErrInvalidPacket( + k.codespace, + fmt.Sprintf("packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.DestPort(), channel.Counterparty.PortID), + ) } commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data - return nil, errors.New("packet hasn't been sent") + return nil, types.ErrInvalidPacket(k.codespace, "packet hasn't been sent") } counterparty := types.NewCounterparty(packet.SourcePort(), packet.SourceChannel()) diff --git a/x/ibc/04-channel/types/errors.go b/x/ibc/04-channel/types/errors.go index d2b2c5a179f4..dc3b74722e43 100644 --- a/x/ibc/04-channel/types/errors.go +++ b/x/ibc/04-channel/types/errors.go @@ -15,13 +15,10 @@ const ( CodeInvalidConnectionHops sdk.CodeType = 103 CodeInvalidCounterpartyChannel sdk.CodeType = 104 CodeChannelCapabilityNotFound sdk.CodeType = 105 - CodeInvalidPacketSequence sdk.CodeType = 106 + CodeInvalidPacket sdk.CodeType = 106 CodeSequenceNotFound sdk.CodeType = 107 CodePacketTimeout sdk.CodeType = 108 - CodeInvalidPortID sdk.CodeType = 109 - CodeInvalidChannelID sdk.CodeType = 110 - CodeInvalidChannelState sdk.CodeType = 111 - CodeInvalidPacketData sdk.CodeType = 112 + CodeInvalidChannelState sdk.CodeType = 109 ) // ErrChannelExists implements sdk.Error @@ -49,9 +46,9 @@ func ErrChannelCapabilityNotFound(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeChannelCapabilityNotFound, "channel capability key not found") } -// ErrInvalidPacketSequence implements sdk.Error -func ErrInvalidPacketSequence(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidPacketSequence, "invalid packet sequence counter") +// ErrInvalidPacket implements sdk.Error +func ErrInvalidPacket(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidPacket, "invalid packet sequence counter") } // ErrSequenceNotFound implements sdk.Error @@ -64,22 +61,7 @@ func ErrPacketTimeout(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodePacketTimeout, "packet timeout") } -// ErrInvalidPortID implements sdk.Error -func ErrInvalidPortID(codespace sdk.CodespaceType, msg string) sdk.Error { - return sdk.NewError(codespace, CodeInvalidPortID, msg) -} - -// ErrInvalidChannelID implements sdk.Error -func ErrInvalidChannelID(codespace sdk.CodespaceType, msg string) sdk.Error { - return sdk.NewError(codespace, CodeInvalidChannelID, msg) -} - // ErrInvalidChannelState implements sdk.Error func ErrInvalidChannelState(codespace sdk.CodespaceType, msg string) sdk.Error { return sdk.NewError(codespace, CodeInvalidChannelState, msg) } - -// ErrInvalidPacketData implements sdk.Error -func ErrInvalidPacketData(codespace sdk.CodespaceType, msg string) sdk.Error { - return sdk.NewError(codespace, CodeInvalidPacketData, msg) -} diff --git a/x/ibc/04-channel/types/msgs.go b/x/ibc/04-channel/types/msgs.go index 72fd1b664915..db8fdf21784c 100644 --- a/x/ibc/04-channel/types/msgs.go +++ b/x/ibc/04-channel/types/msgs.go @@ -392,7 +392,6 @@ func (msg MsgSendPacket) ValidateBasic() sdk.Error { return sdk.ErrInvalidSequence("invalid height") } // Check proofs != nil - // Check packet != nil // Signer can be empty return msg.Packet.ValidateBasic() } diff --git a/x/ibc/04-channel/types/packet.go b/x/ibc/04-channel/types/packet.go index 57ca7f687c32..29baa1c118e7 100644 --- a/x/ibc/04-channel/types/packet.go +++ b/x/ibc/04-channel/types/packet.go @@ -61,25 +61,25 @@ func (p Packet) Data() []byte { return p.data } // ValidateBasic implements PacketI interface func (p Packet) ValidateBasic() sdk.Error { if err := host.DefaultIdentifierValidator(p.sourcePort); err != nil { - return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid source port ID: %s", err.Error())) + return ErrInvalidPacket(DefaultCodespace, fmt.Sprintf("invalid source port ID: %s", err.Error())) } if err := host.DefaultIdentifierValidator(p.destinationPort); err != nil { - return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid destination port ID: %s", err.Error())) + return ErrInvalidPacket(DefaultCodespace, fmt.Sprintf("invalid destination port ID: %s", err.Error())) } if err := host.DefaultIdentifierValidator(p.sourceChannel); err != nil { - return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid source channel ID: %s", err.Error())) + return ErrInvalidPacket(DefaultCodespace, fmt.Sprintf("invalid source channel ID: %s", err.Error())) } if err := host.DefaultIdentifierValidator(p.destinationChannel); err != nil { - return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid destination channel ID: %s", err.Error())) + return ErrInvalidPacket(DefaultCodespace, fmt.Sprintf("invalid destination channel ID: %s", err.Error())) } if p.sequence == 0 { - return ErrInvalidPacketSequence(DefaultCodespace) + return ErrInvalidPacket(DefaultCodespace, "packet sequence cannot be 0") } if p.timeout == 0 { return ErrPacketTimeout(DefaultCodespace) } if len(p.data) == 0 { - return ErrInvalidPacketData(DefaultCodespace, "Packet data cannot be empty") + return ErrInvalidPacket(DefaultCodespace, "packet data cannot be empty") } return nil } From 33312c2dccc3e90c565ee95813af8646128ef4c0 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Thu, 24 Oct 2019 13:41:10 -0700 Subject: [PATCH 334/378] start batch-verify tests --- x/ibc/23-commitment/verify_test.go | 74 ++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 x/ibc/23-commitment/verify_test.go diff --git a/x/ibc/23-commitment/verify_test.go b/x/ibc/23-commitment/verify_test.go new file mode 100644 index 000000000000..5b94160dfd1c --- /dev/null +++ b/x/ibc/23-commitment/verify_test.go @@ -0,0 +1,74 @@ +package commitment_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/cosmos/cosmos-sdk/store/iavl" + "github.com/cosmos/cosmos-sdk/store/rootmulti" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" +) + +func TestBatchVerifyMembership(t *testing.T) { + db := dbm.NewMemDB() + store := rootmulti.NewStore(db) + + iavlStoreKey := storetypes.NewKVStoreKey("iavlStoreKey") + + store.MountStoreWithDB(iavlStoreKey, storetypes.StoreTypeIAVL, nil) + store.LoadVersion(0) + + iavlStore := store.GetCommitStore(iavlStoreKey).(*iavl.Store) + for i := 0; i < 5; i++ { + iavlStore.Set([]byte(fmt.Sprintf("KEY:%d", i)), []byte(fmt.Sprintf("VAL:%d", i))) + } + cid := store.Commit() + + header := abci.Header{AppHash: cid.Hash} + ctx := sdk.NewContext(store, header, false, log.NewNopLogger()) + + res := store.Query(abci.RequestQuery{ + Path: "/iavlStoreKey/subspace", + Data: []byte("KEY:"), + Height: cid.Version, + Prove: true, + }) + require.NotNil(t, res.Proof) + + proof := commitment.Proof{ + Proof: res.Proof, + } + prefix := commitment.NewPrefix([]byte("iavlStoreKey")) + + keyBatches := [][]string{ + {"KEY:1"}, // batch verify one key + {"KEY:1", "KEY:2"}, // batch verify first 2 keys in subspace + {"KEY:2", "KEY:3", "KEY:4"}, // batch verify middle 3 keys in subspace + {"KEY:4", "KEY:5"}, // batch verify last 2 keys in subspace + {"KEY:3", "KEY:2"}, // batch verify keys in reverse order + {"KEY:4", "KEY:1"}, // batch verify non-contingous keys + {"KEY:2", "KEY:3", "KEY:4", "KEY:1", "KEY:5"}, // batch verify all keys in random order + } + + for i, batch := range keyBatches { + items := make(map[string][]byte) + + for _, key := range batch { + // key-pair must have form KEY:{str} => VAL:{str} + splitKey := strings.Split(key, ":") + items[key] = []byte(fmt.Sprintf("VAL:%s", splitKey[1])) + } + + ok := commitment.BatchVerifyMembership(ctx, proof, prefix, items) + + require.True(t, ok, "Test case %d failed on batch verify", i) + } +} From 8d95afae9edb5fa6a951be4a689a236c6569b0b9 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 25 Oct 2019 11:48:57 +0200 Subject: [PATCH 335/378] update msg validation and CLI UX --- x/ibc/04-channel/alias.go | 6 +- x/ibc/04-channel/client/cli/tx.go | 111 +++++++++++++-------------- x/ibc/04-channel/keeper/handshake.go | 17 +--- x/ibc/04-channel/keeper/timeout.go | 2 +- x/ibc/04-channel/types/channel.go | 28 +++++++ x/ibc/04-channel/types/errors.go | 32 ++++---- x/ibc/04-channel/types/msgs.go | 75 +++++++++++------- 7 files changed, 154 insertions(+), 117 deletions(-) diff --git a/x/ibc/04-channel/alias.go b/x/ibc/04-channel/alias.go index b55f57833c60..f85ba2d79a62 100644 --- a/x/ibc/04-channel/alias.go +++ b/x/ibc/04-channel/alias.go @@ -29,13 +29,14 @@ const ( DefaultCodespace = types.DefaultCodespace CodeChannelExists = types.CodeChannelExists CodeChannelNotFound = types.CodeChannelNotFound - CodeInvalidConnectionHops = types.CodeInvalidConnectionHops CodeInvalidCounterpartyChannel = types.CodeInvalidCounterpartyChannel CodeChannelCapabilityNotFound = types.CodeChannelCapabilityNotFound CodeInvalidPacket = types.CodeInvalidPacket CodeSequenceNotFound = types.CodeSequenceNotFound CodePacketTimeout = types.CodePacketTimeout + CodeInvalidChannel = types.CodeInvalidChannel CodeInvalidChannelState = types.CodeInvalidChannelState + CodeInvalidChannelProof = types.CodeInvalidChannelProof AttributeKeySenderPort = types.AttributeKeySenderPort AttributeKeyReceiverPort = types.AttributeKeyReceiverPort AttributeKeyChannelID = types.AttributeKeyChannelID @@ -59,13 +60,14 @@ var ( SetMsgChanCodec = types.SetMsgChanCodec ErrChannelExists = types.ErrChannelExists ErrChannelNotFound = types.ErrChannelNotFound - ErrInvalidConnectionHops = types.ErrInvalidConnectionHops ErrInvalidCounterpartyChannel = types.ErrInvalidCounterpartyChannel ErrChannelCapabilityNotFound = types.ErrChannelCapabilityNotFound ErrInvalidPacket = types.ErrInvalidPacket ErrSequenceNotFound = types.ErrSequenceNotFound ErrPacketTimeout = types.ErrPacketTimeout + ErrInvalidChannel = types.ErrInvalidChannel ErrInvalidChannelState = types.ErrInvalidChannelState + ErrInvalidChannelProof = types.ErrInvalidChannelProof ChannelPath = types.ChannelPath ChannelCapabilityPath = types.ChannelCapabilityPath NextSequenceSendPath = types.NextSequenceSendPath diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index f30f3f21846f..b5ee5b46295e 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -7,6 +7,9 @@ import ( "strconv" "strings" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" @@ -15,14 +18,13 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/client/utils" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/spf13/cobra" - "github.com/spf13/viper" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) +// IBC channel flags var ( - FlagUnordered = "unordered" - IBCVersion = "version" + FlagOrdered = "ordered" + FlagIBCVersion = "ibc-version" ) // GetTxCmd returns the transaction commands for IBC Connections @@ -57,12 +59,16 @@ func GetMsgChannelOpenInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command portID := args[0] channelID := args[1] - channel, err := createChannelFromArgs(args[2], args[3], args[4]) - if err != nil { - return err - } - - msg := types.NewMsgChannelOpenInit(portID, channelID, channel, cliCtx.GetFromAddress()) + counterpartyPortID := args[2] + counterpartyChannelID := args[3] + hops := strings.Split(args[4], "/") + order := channelOrder() + version := viper.GetString(FlagIBCVersion) + + msg := types.NewMsgChannelOpenInit( + portID, channelID, version, order, hops, + counterpartyPortID, counterpartyChannelID, cliCtx.GetFromAddress(), + ) if err := msg.ValidateBasic(); err != nil { return err } @@ -71,7 +77,8 @@ func GetMsgChannelOpenInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command }, } - cmd.Flags().Bool(FlagUnordered, false, "Pass flag for opening unordered channels") + cmd.Flags().Bool(FlagOrdered, true, "Pass flag for opening ordered channels") + cmd.Flags().String(FlagIBCVersion, "1.0.0", "supported IBC version") return cmd } @@ -88,12 +95,13 @@ func GetMsgChannelOpenTryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { portID := args[0] channelID := args[1] - channel, err := createChannelFromArgs(args[2], args[3], args[4]) - if err != nil { - return err - } + counterpartyPortID := args[2] + counterpartyChannelID := args[3] + hops := strings.Split(args[4], "/") + order := channelOrder() + version := viper.GetString(FlagIBCVersion) // TODO: diferenciate between channel and counterparty versions - var proof ics23.Proof + var proof commitment.ProofI if err := cdc.UnmarshalJSON([]byte(args[5]), &proof); err != nil { fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") contents, err := ioutil.ReadFile(args[5]) @@ -110,7 +118,11 @@ func GetMsgChannelOpenTryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msg := types.NewMsgChannelOpenTry(portID, channelID, channel, IBCVersion, proof, uint64(proofHeight), cliCtx.GetFromAddress()) + msg := types.NewMsgChannelOpenTry( + portID, channelID, version, order, hops, + counterpartyPortID, counterpartyChannelID, version, + proof, uint64(proofHeight), cliCtx.GetFromAddress(), + ) if err := msg.ValidateBasic(); err != nil { return err } @@ -118,8 +130,8 @@ func GetMsgChannelOpenTryCmd(storeKey string, cdc *codec.Codec) *cobra.Command { return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } - - cmd.Flags().Bool(FlagUnordered, false, "Pass flag for opening unordered channels") + cmd.Flags().Bool(FlagOrdered, true, "Pass flag for opening ordered channels") + cmd.Flags().String(FlagIBCVersion, "1.0.0", "supported IBC version") return cmd } @@ -136,8 +148,9 @@ func GetMsgChannelOpenAckCmd(storeKey string, cdc *codec.Codec) *cobra.Command { portID := args[0] channelID := args[1] + version := viper.GetString(FlagIBCVersion) // TODO: diferenciate between channel and counterparty versions - var proof ics23.Proof + var proof commitment.ProofI if err := cdc.UnmarshalJSON([]byte(args[2]), &proof); err != nil { fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") contents, err := ioutil.ReadFile(args[2]) @@ -154,7 +167,9 @@ func GetMsgChannelOpenAckCmd(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - msg := types.NewMsgChannelOpenAck(portID, channelID, IBCVersion, proof, uint64(proofHeight), cliCtx.GetFromAddress()) + msg := types.NewMsgChannelOpenAck( + portID, channelID, version, proof, uint64(proofHeight), cliCtx.GetFromAddress(), + ) if err := msg.ValidateBasic(); err != nil { return err } @@ -162,12 +177,13 @@ func GetMsgChannelOpenAckCmd(storeKey string, cdc *codec.Codec) *cobra.Command { return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } + cmd.Flags().String(FlagIBCVersion, "1.0.0", "supported IBC version") return cmd } // GetMsgChannelOpenConfirmCmd returns the command to create a MsgChannelOpenConfirm transaction func GetMsgChannelOpenConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "open-confirm [port-id] [channel-id] [/path/to/proof-ack.json] [proof-height]", Short: "Creates and sends a ChannelOpenConfirm message", Args: cobra.ExactArgs(1), @@ -178,7 +194,7 @@ func GetMsgChannelOpenConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comma portID := args[0] channelID := args[1] - var proof ics23.Proof + var proof commitment.ProofI if err := cdc.UnmarshalJSON([]byte(args[2]), &proof); err != nil { fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") contents, err := ioutil.ReadFile(args[2]) @@ -195,7 +211,9 @@ func GetMsgChannelOpenConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comma return err } - msg := types.NewMsgChannelOpenConfirm(portID, channelID, proof, uint64(proofHeight), cliCtx.GetFromAddress()) + msg := types.NewMsgChannelOpenConfirm( + portID, channelID, proof, uint64(proofHeight), cliCtx.GetFromAddress(), + ) if err := msg.ValidateBasic(); err != nil { return err } @@ -203,12 +221,11 @@ func GetMsgChannelOpenConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comma return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } - return cmd } // GetMsgChannelCloseInitCmd returns the command to create a MsgChannelCloseInit transaction func GetMsgChannelCloseInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "close-init [port-id] [channel-id]", Short: "Creates and sends a ChannelCloseInit message", Args: cobra.ExactArgs(1), @@ -227,12 +244,11 @@ func GetMsgChannelCloseInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } - return cmd } // GetMsgChannelCloseConfirmCmd returns the command to create a MsgChannelCloseConfirm transaction func GetMsgChannelCloseConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "close-confirm [port-id] [channel-id] [/path/to/proof-init.json] [proof-height]", Short: "Creates and sends a ChannelCloseConfirm message", Args: cobra.ExactArgs(1), @@ -243,7 +259,7 @@ func GetMsgChannelCloseConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comm portID := args[0] channelID := args[1] - var proof ics23.Proof + var proof commitment.ProofI if err := cdc.UnmarshalJSON([]byte(args[2]), &proof); err != nil { fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") contents, err := ioutil.ReadFile(args[2]) @@ -260,7 +276,9 @@ func GetMsgChannelCloseConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comm return err } - msg := types.NewMsgChannelCloseConfirm(portID, channelID, proof, uint64(proofHeight), cliCtx.GetFromAddress()) + msg := types.NewMsgChannelCloseConfirm( + portID, channelID, proof, uint64(proofHeight), cliCtx.GetFromAddress(), + ) if err := msg.ValidateBasic(); err != nil { return err } @@ -268,7 +286,6 @@ func GetMsgChannelCloseConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comm return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } - return cmd } // GetMsgSendPacketCmd returns the command to create a MsgChannelCloseConfirm transaction @@ -305,32 +322,8 @@ func GetMsgSendPacketCmd(storeKey string, cdc *codec.Codec) *cobra.Command { } func channelOrder() types.Order { - if viper.GetBool(FlagUnordered) { - return types.UNORDERED - } - return types.ORDERED -} - -func validateChannelHops(hops string) ([]string, error) { - // TODO: Add validation here - return strings.Split(hops, ","), nil -} - -func createChannelFromArgs(portID, channelID string, hops string) (types.Channel, error) { - var channel types.Channel - - channelHops, err := validateChannelHops(hops) - if err != nil { - return channel, err + if viper.GetBool(FlagOrdered) { + return types.ORDERED } - - channel = types.Channel{ - State: types.INIT, - Ordering: channelOrder(), - Counterparty: types.NewCounterparty(portID, channelID), - ConnectionHops: channelHops, - Version: IBCVersion, - } - - return channel, nil + return types.UNORDERED } diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go index 19292249a264..83cb411502d5 100644 --- a/x/ibc/04-channel/keeper/handshake.go +++ b/x/ibc/04-channel/keeper/handshake.go @@ -23,10 +23,6 @@ func (k Keeper) ChanOpenInit( version string, ) error { // TODO: abortTransactionUnless(validateChannelIdentifier(portIdentifier, channelIdentifier)) - if len(connectionHops) != 1 { - return types.ErrInvalidConnectionHops(k.codespace) - } - _, found := k.GetChannel(ctx, portID, channelID) if found { return types.ErrChannelExists(k.codespace, channelID) @@ -77,11 +73,6 @@ func (k Keeper) ChanOpenTry( proofInit commitment.ProofI, proofHeight uint64, ) error { - - if len(connectionHops) != 1 { - return types.ErrInvalidConnectionHops(k.codespace) - } - _, found := k.GetChannel(ctx, portID, channelID) if found { return types.ErrChannelExists(k.codespace, channelID) @@ -130,7 +121,7 @@ func (k Keeper) ChanOpenTry( types.ChannelPath(counterparty.PortID, counterparty.ChannelID), bz, ) { - return types.ErrInvalidCounterpartyChannel(k.codespace) + return types.ErrInvalidCounterpartyChannel(k.codespace, "channel membership verification failed") } k.SetChannel(ctx, portID, channelID, channel) @@ -196,7 +187,7 @@ func (k Keeper) ChanOpenAck( types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), bz, ) { - return types.ErrInvalidCounterpartyChannel(k.codespace) + return types.ErrInvalidCounterpartyChannel(k.codespace, "channel membership verification failed") } channel.State = types.OPEN @@ -257,7 +248,7 @@ func (k Keeper) ChanOpenConfirm( types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), bz, ) { - return types.ErrInvalidCounterpartyChannel(k.codespace) + return types.ErrInvalidCounterpartyChannel(k.codespace, "channel membership verification failed") } channel.State = types.OPEN @@ -349,7 +340,7 @@ func (k Keeper) ChanCloseConfirm( types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), bz, ) { - return types.ErrInvalidCounterpartyChannel(k.codespace) + return types.ErrInvalidCounterpartyChannel(k.codespace, "channel membership verification failed") } channel.State = types.CLOSED diff --git a/x/ibc/04-channel/keeper/timeout.go b/x/ibc/04-channel/keeper/timeout.go index f75f04f4fe3b..5d9f5ebc8ae2 100644 --- a/x/ibc/04-channel/keeper/timeout.go +++ b/x/ibc/04-channel/keeper/timeout.go @@ -171,7 +171,7 @@ func (k Keeper) TimeoutOnClose( types.ChannelPath(channel.Counterparty.PortID, channel.Counterparty.ChannelID), bz, ) { - return nil, types.ErrInvalidCounterpartyChannel(k.codespace) + return nil, types.ErrInvalidCounterpartyChannel(k.codespace, "channel membership verification failed") } if !k.connectionKeeper.VerifyNonMembership( diff --git a/x/ibc/04-channel/types/channel.go b/x/ibc/04-channel/types/channel.go index 8b9e7c9c0511..e57869c9ff36 100644 --- a/x/ibc/04-channel/types/channel.go +++ b/x/ibc/04-channel/types/channel.go @@ -3,8 +3,10 @@ package types import ( "encoding/json" "fmt" + "strings" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/errors" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ) @@ -40,6 +42,32 @@ func (ch Channel) CounterpartyHops() []string { return counterPartyHops } +// ValidateBasic performs a basic validation of the channel fields +func (ch Channel) ValidateBasic() sdk.Error { + if ch.State.String() == "" { + return ErrInvalidChannelState( + DefaultCodespace, + "channel order should be either 'ORDERED' or 'UNORDERED'", + ) + } + if ch.Ordering.String() == "" { + return ErrInvalidChannel( + DefaultCodespace, + "channel order should be either 'ORDERED' or 'UNORDERED'", + ) + } + if len(ch.ConnectionHops) != 1 { + return ErrInvalidChannel(DefaultCodespace, "IBC v1 only supports one connection hop") + } + if err := host.DefaultIdentifierValidator(ch.ConnectionHops[0]); err != nil { + return ErrInvalidChannel(DefaultCodespace, errors.Wrap(err, "invalid connection hop ID").Error()) + } + if strings.TrimSpace(ch.Version) == "" { + return ErrInvalidChannel(DefaultCodespace, "channel version can't be blank") + } + return ch.Counterparty.ValidateBasic() +} + // Counterparty defines the counterparty chain's channel and port identifiers type Counterparty struct { PortID string `json:"port_id" yaml:"port_id"` diff --git a/x/ibc/04-channel/types/errors.go b/x/ibc/04-channel/types/errors.go index dc3b74722e43..92140b3aef2a 100644 --- a/x/ibc/04-channel/types/errors.go +++ b/x/ibc/04-channel/types/errors.go @@ -12,13 +12,14 @@ const ( CodeChannelExists sdk.CodeType = 101 CodeChannelNotFound sdk.CodeType = 102 - CodeInvalidConnectionHops sdk.CodeType = 103 - CodeInvalidCounterpartyChannel sdk.CodeType = 104 - CodeChannelCapabilityNotFound sdk.CodeType = 105 - CodeInvalidPacket sdk.CodeType = 106 - CodeSequenceNotFound sdk.CodeType = 107 - CodePacketTimeout sdk.CodeType = 108 + CodeInvalidCounterpartyChannel sdk.CodeType = 103 + CodeChannelCapabilityNotFound sdk.CodeType = 104 + CodeInvalidPacket sdk.CodeType = 105 + CodeSequenceNotFound sdk.CodeType = 106 + CodePacketTimeout sdk.CodeType = 107 + CodeInvalidChannel sdk.CodeType = 108 CodeInvalidChannelState sdk.CodeType = 109 + CodeInvalidChannelProof sdk.CodeType = 110 ) // ErrChannelExists implements sdk.Error @@ -31,14 +32,9 @@ func ErrChannelNotFound(codespace sdk.CodespaceType, channelID string) sdk.Error return sdk.NewError(codespace, CodeChannelNotFound, fmt.Sprintf("channel with ID %s not found", channelID)) } -// ErrInvalidConnectionHops implements sdk.Error -func ErrInvalidConnectionHops(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidConnectionHops, "IBC v1 only supports one connection hop") -} - // ErrInvalidCounterpartyChannel implements sdk.Error -func ErrInvalidCounterpartyChannel(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidCounterpartyChannel, "counterparty channel doesn't match the expected one") +func ErrInvalidCounterpartyChannel(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidCounterpartyChannel, msg) } // ErrChannelCapabilityNotFound implements sdk.Error @@ -61,7 +57,17 @@ func ErrPacketTimeout(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodePacketTimeout, "packet timeout") } +// ErrInvalidChannel implements sdk.Error +func ErrInvalidChannel(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidChannel, msg) +} + // ErrInvalidChannelState implements sdk.Error func ErrInvalidChannelState(codespace sdk.CodespaceType, msg string) sdk.Error { return sdk.NewError(codespace, CodeInvalidChannelState, msg) } + +// ErrInvalidChannelProof implements sdk.Error +func ErrInvalidChannelProof(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidChannelProof, msg) +} diff --git a/x/ibc/04-channel/types/msgs.go b/x/ibc/04-channel/types/msgs.go index db8fdf21784c..e7033466aac4 100644 --- a/x/ibc/04-channel/types/msgs.go +++ b/x/ibc/04-channel/types/msgs.go @@ -2,6 +2,7 @@ package types import ( "fmt" + "strings" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" @@ -21,8 +22,11 @@ type MsgChannelOpenInit struct { // NewMsgChannelOpenInit creates a new MsgChannelCloseInit MsgChannelOpenInit func NewMsgChannelOpenInit( - portID, channelID string, channel Channel, signer sdk.AccAddress, + portID, channelID string, version string, channelOrder Order, connectionHops []string, + counterpartyPortID, counterpartyChannelID string, signer sdk.AccAddress, ) MsgChannelOpenInit { + counterparty := NewCounterparty(counterpartyPortID, counterpartyChannelID) + channel := NewChannel(INIT, channelOrder, counterparty, connectionHops, version) return MsgChannelOpenInit{ PortID: portID, ChannelID: channelID, @@ -49,8 +53,8 @@ func (msg MsgChannelOpenInit) ValidateBasic() sdk.Error { if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } - // Signer can be empty // TODO: Why? - return nil + // Signer can be empty + return msg.Channel.ValidateBasic() } // GetSignBytes implements sdk.Msg @@ -77,14 +81,17 @@ type MsgChannelOpenTry struct { // NewMsgChannelOpenTry creates a new MsgChannelOpenTry instance func NewMsgChannelOpenTry( - portID, channelID string, channel Channel, cpv string, proofInit commitment.ProofI, - proofHeight uint64, signer sdk.AccAddress, + portID, channelID, version string, channelOrder Order, connectionHops []string, + counterpartyPortID, counterpartyChannelID, counterpartyVersion string, + proofInit commitment.ProofI, proofHeight uint64, signer sdk.AccAddress, ) MsgChannelOpenTry { + counterparty := NewCounterparty(counterpartyPortID, counterpartyChannelID) + channel := NewChannel(INIT, channelOrder, counterparty, connectionHops, version) return MsgChannelOpenTry{ PortID: portID, ChannelID: channelID, Channel: channel, - CounterpartyVersion: cpv, + CounterpartyVersion: counterpartyVersion, ProofInit: proofInit, ProofHeight: proofHeight, Signer: signer, @@ -109,11 +116,17 @@ func (msg MsgChannelOpenTry) ValidateBasic() sdk.Error { if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } - - // Check proofs != nil - // Check channel != nil + if strings.TrimSpace(msg.CounterpartyVersion) == "" { + return ErrInvalidCounterpartyChannel(DefaultCodespace, "counterparty version cannot be blank") + } + if msg.ProofInit == nil { + return ErrInvalidChannelProof(DefaultCodespace, "cannot submit an empty proof") + } + if msg.ProofHeight == 0 { + return ErrInvalidChannelProof(DefaultCodespace, "proof height must be > 0") + } // Signer can be empty - return nil + return msg.Channel.ValidateBasic() } // GetSignBytes implements sdk.Msg @@ -170,8 +183,15 @@ func (msg MsgChannelOpenAck) ValidateBasic() sdk.Error { if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } - - // Check proofs != nil + if strings.TrimSpace(msg.CounterpartyVersion) == "" { + return ErrInvalidCounterpartyChannel(DefaultCodespace, "counterparty version cannot be blank") + } + if msg.ProofTry == nil { + return ErrInvalidChannelProof(DefaultCodespace, "cannot submit an empty proof") + } + if msg.ProofHeight == 0 { + return ErrInvalidChannelProof(DefaultCodespace, "proof height must be > 0") + } // Signer can be empty return nil } @@ -228,8 +248,12 @@ func (msg MsgChannelOpenConfirm) ValidateBasic() sdk.Error { if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } - - // Check proofs != nil + if msg.ProofAck == nil { + return ErrInvalidChannelProof(DefaultCodespace, "cannot submit an empty proof") + } + if msg.ProofHeight == 0 { + return ErrInvalidChannelProof(DefaultCodespace, "proof height must be > 0") + } // Signer can be empty return nil } @@ -279,7 +303,6 @@ func (msg MsgChannelCloseInit) ValidateBasic() sdk.Error { if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } - // Signer can be empty return nil } @@ -336,8 +359,12 @@ func (msg MsgChannelCloseConfirm) ValidateBasic() sdk.Error { if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } - - // Check proofs != nil + if msg.ProofInit == nil { + return ErrInvalidChannelProof(DefaultCodespace, "cannot submit an empty proof") + } + if msg.ProofHeight == 0 { + return ErrInvalidChannelProof(DefaultCodespace, "proof height must be > 0") + } // Signer can be empty return nil } @@ -358,11 +385,8 @@ var _ sdk.Msg = MsgSendPacket{} // ChannelID can be empty if batched & not first MsgSendPacket // Height uint64 // height of the commitment root for the proofs type MsgSendPacket struct { - Packet exported.PacketI `json:"packet" yaml:"packet"` - ChannelID string `json:"channel_id" yaml:"channel_id"` - Proofs []commitment.ProofI `json:"proofs" yaml:"proofs"` - Height uint64 `json:"height" yaml:"height"` - Signer sdk.AccAddress `json:"signer" yaml:"signer"` + Packet exported.PacketI `json:"packet" yaml:"packet"` + Signer sdk.AccAddress `json:"signer" yaml:"signer"` } // NewMsgSendPacket creates a new MsgSendPacket instance @@ -385,13 +409,6 @@ func (msg MsgSendPacket) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgSendPacket) ValidateBasic() sdk.Error { - if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { - return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) - } - if msg.Height == 0 { - return sdk.ErrInvalidSequence("invalid height") - } - // Check proofs != nil // Signer can be empty return msg.Packet.ValidateBasic() } From 523972041d97f300d331367909e68d99c194f584 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 25 Oct 2019 12:05:00 +0200 Subject: [PATCH 336/378] minor changes on commitment types --- x/ibc/23-commitment/merkle.go | 6 ++++++ x/ibc/23-commitment/types.go | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/x/ibc/23-commitment/merkle.go b/x/ibc/23-commitment/merkle.go index 206f921d85af..8754823e0683 100644 --- a/x/ibc/23-commitment/merkle.go +++ b/x/ibc/23-commitment/merkle.go @@ -1,6 +1,7 @@ package commitment import ( + "errors" "strings" "github.com/tendermint/tendermint/crypto/merkle" @@ -105,6 +106,11 @@ func ApplyPrefix(prefix PrefixI, path string) (Path, error) { if err != nil { return Path{}, err } + + if prefix == nil || len(prefix.Bytes()) == 0 { + return Path{}, errors.New("prefix can't be empty") + } + // Split paths by the separator pathSlice := strings.Split(path, "/") keyPath := merkle.KeyPath{} diff --git a/x/ibc/23-commitment/types.go b/x/ibc/23-commitment/types.go index af33cd0b7f99..1b70f4f04d9c 100644 --- a/x/ibc/23-commitment/types.go +++ b/x/ibc/23-commitment/types.go @@ -48,14 +48,14 @@ const ( Merkle Type = iota + 1 // 1 ) -// Client types +// string representation of the commitment types const ( TypeMerkle string = "merkle" ) -// TypeToString returns the string representation of a client type -func TypeToString(commitmentType Type) string { - switch commitmentType { +// String implements the Stringer interface +func (ct Type) String() string { + switch ct { case Merkle: return TypeMerkle From 46f9cbd4fe2b9f6a80bd15cd6c24b50f1dd5381d Mon Sep 17 00:00:00 2001 From: vincent Date: Fri, 25 Oct 2019 18:50:43 +0800 Subject: [PATCH 337/378] fix channel and packet check (#5243) --- x/ibc/04-channel/keeper/handshake.go | 2 +- x/ibc/04-channel/keeper/packet.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go index 83cb411502d5..780ccbd99a7b 100644 --- a/x/ibc/04-channel/keeper/handshake.go +++ b/x/ibc/04-channel/keeper/handshake.go @@ -173,7 +173,7 @@ func (k Keeper) ChanOpenAck( // counterparty of the counterparty channel end (i.e self) counterparty := types.NewCounterparty(portID, channelID) expectedChannel := types.NewChannel( - types.INIT, channel.Ordering, counterparty, + types.OPENTRY, channel.Ordering, counterparty, channel.CounterpartyHops(), channel.Version, ) diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go index 82b871d31284..3858c57f3ed7 100644 --- a/x/ibc/04-channel/keeper/packet.go +++ b/x/ibc/04-channel/keeper/packet.go @@ -195,9 +195,9 @@ func (k Keeper) RecvPacket( acknowledgement []byte, ) (exported.PacketI, error) { - channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) + channel, found := k.GetChannel(ctx, packet.DestPort(), packet.DestChannel()) if !found { - return nil, types.ErrChannelNotFound(k.codespace, packet.SourceChannel()) + return nil, types.ErrChannelNotFound(k.codespace, packet.DestChannel()) } if channel.State != types.OPEN { @@ -207,7 +207,7 @@ func (k Keeper) RecvPacket( ) } - _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) + _, found = k.GetChannelCapability(ctx, packet.DestPort(), packet.DestChannel()) if !found { return nil, types.ErrChannelCapabilityNotFound(k.codespace) } From e048a6c6522b0cba6956d708070acd7f11c7e9cb Mon Sep 17 00:00:00 2001 From: vincent Date: Fri, 25 Oct 2019 18:53:20 +0800 Subject: [PATCH 338/378] R4R - Store consensus state correctly (#5242) * store consensus state correctly * fix client example --- x/ibc/02-client/client/cli/tx.go | 2 +- x/ibc/02-client/keeper/keeper.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index 92e37b15c9b5..fc92efb874ba 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -91,7 +91,7 @@ func GetCmdUpdateClient(cdc *codec.Codec) *cobra.Command { Long: strings.TrimSpace(fmt.Sprintf(`update existing client with a header: Example: -$ %s tx ibc client create [client-id] [path/to/header.json] --from node0 --home ../node0/cli --chain-id $CID +$ %s tx ibc client update [client-id] [path/to/header.json] --from node0 --home ../node0/cli --chain-id $CID `, version.ClientName), ), Args: cobra.ExactArgs(2), diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index d0c45f0a6ffd..c9f7fbe1c9f7 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -79,7 +79,7 @@ func (k Keeper) SetClientType(ctx sdk.Context, clientID string, clientType expor // GetConsensusState creates a new client state and populates it with a given consensus state func (k Keeper) GetConsensusState(ctx sdk.Context, clientID string) (exported.ConsensusState, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) - bz := store.Get(types.KeyClientState(clientID)) + bz := store.Get(types.KeyConsensusState(clientID)) if bz == nil { return nil, false } @@ -93,7 +93,7 @@ func (k Keeper) GetConsensusState(ctx sdk.Context, clientID string) (exported.Co func (k Keeper) SetConsensusState(ctx sdk.Context, clientID string, consensusState exported.ConsensusState) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := k.cdc.MustMarshalBinaryLengthPrefixed(consensusState) - store.Set(types.KeyClientState(clientID), bz) + store.Set(types.KeyConsensusState(clientID), bz) } // GetVerifiedRoot gets a verified commitment Root from a particular height to From 0c187bf7b1d3de81a2cf8a607395206e8b27fbf3 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 25 Oct 2019 12:55:44 +0200 Subject: [PATCH 339/378] update alias --- x/ibc/02-client/alias.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/ibc/02-client/alias.go b/x/ibc/02-client/alias.go index 1d82de808c50..aedc47bfdc76 100644 --- a/x/ibc/02-client/alias.go +++ b/x/ibc/02-client/alias.go @@ -21,6 +21,8 @@ const ( CodeClientTypeNotFound = types.CodeClientTypeNotFound CodeInvalidClientType = types.CodeInvalidClientType CodeRootNotFound = types.CodeRootNotFound + CodeInvalidHeader = types.CodeInvalidHeader + CodeInvalidEvidence = types.CodeInvalidEvidence AttributeKeyClientID = types.AttributeKeyClientID SubModuleName = types.SubModuleName StoreKey = types.StoreKey @@ -46,6 +48,8 @@ var ( ErrClientTypeNotFound = types.ErrClientTypeNotFound ErrInvalidClientType = types.ErrInvalidClientType ErrRootNotFound = types.ErrRootNotFound + ErrInvalidHeader = types.ErrInvalidHeader + ErrInvalidEvidence = types.ErrInvalidEvidence ClientStatePath = types.ClientStatePath ClientTypePath = types.ClientTypePath ConsensusStatePath = types.ConsensusStatePath From 24e6d29e21062094452db99ab5aeb238310fa245 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 25 Oct 2019 12:57:23 +0200 Subject: [PATCH 340/378] update alias --- x/ibc/03-connection/alias.go | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/x/ibc/03-connection/alias.go b/x/ibc/03-connection/alias.go index 0b8513f561bb..9dc689d50154 100644 --- a/x/ibc/03-connection/alias.go +++ b/x/ibc/03-connection/alias.go @@ -13,12 +13,21 @@ import ( const ( NONE = types.NONE + StateNone = types.StateNone + StateInit = types.StateInit + StateTryOpen = types.StateTryOpen + StateOpen = types.StateOpen DefaultCodespace = types.DefaultCodespace CodeConnectionExists = types.CodeConnectionExists CodeConnectionNotFound = types.CodeConnectionNotFound CodeClientConnectionPathsNotFound = types.CodeClientConnectionPathsNotFound CodeConnectionPath = types.CodeConnectionPath CodeInvalidCounterpartyConnection = types.CodeInvalidCounterpartyConnection + CodeInvalidVersion = types.CodeInvalidVersion + CodeInvalidHeight = types.CodeInvalidHeight + CodeInvalidConnectionState = types.CodeInvalidConnectionState + CodeInvalidProof = types.CodeInvalidProof + CodeInvalidCounterparty = types.CodeInvalidCounterparty AttributeKeyConnectionID = types.AttributeKeyConnectionID AttributeKeyCounterpartyClientID = types.AttributeKeyCounterpartyClientID SubModuleName = types.SubModuleName @@ -38,11 +47,17 @@ var ( SetMsgConnectionCodec = types.SetMsgConnectionCodec NewConnectionEnd = types.NewConnectionEnd NewCounterparty = types.NewCounterparty + StateFromString = types.StateFromString ErrConnectionExists = types.ErrConnectionExists ErrConnectionNotFound = types.ErrConnectionNotFound ErrClientConnectionPathsNotFound = types.ErrClientConnectionPathsNotFound ErrConnectionPath = types.ErrConnectionPath ErrInvalidCounterpartyConnection = types.ErrInvalidCounterpartyConnection + ErrInvalidVersion = types.ErrInvalidVersion + ErrInvalidHeight = types.ErrInvalidHeight + ErrInvalidConnectionState = types.ErrInvalidConnectionState + ErrInvalidConnectionProof = types.ErrInvalidConnectionProof + ErrInvalidCounterparty = types.ErrInvalidCounterparty ConnectionPath = types.ConnectionPath ClientConnectionsPath = types.ClientConnectionsPath KeyConnection = types.KeyConnection @@ -51,8 +66,13 @@ var ( NewMsgConnectionOpenTry = types.NewMsgConnectionOpenTry NewMsgConnectionOpenAck = types.NewMsgConnectionOpenAck NewMsgConnectionOpenConfirm = types.NewMsgConnectionOpenConfirm + NewConnectionResponse = types.NewConnectionResponse NewQueryConnectionParams = types.NewQueryConnectionParams + NewClientConnectionsResponse = types.NewClientConnectionsResponse NewQueryClientConnectionsParams = types.NewQueryClientConnectionsParams + GetCompatibleVersions = types.GetCompatibleVersions + LatestVersion = types.LatestVersion + PickVersion = types.PickVersion // variable aliases SubModuleCdc = types.SubModuleCdc @@ -65,14 +85,16 @@ var ( type ( Keeper = keeper.Keeper - State = types.State - End = types.ConnectionEnd + ConnectionEnd = types.ConnectionEnd Counterparty = types.Counterparty + State = types.State ClientKeeper = types.ClientKeeper MsgConnectionOpenInit = types.MsgConnectionOpenInit MsgConnectionOpenTry = types.MsgConnectionOpenTry MsgConnectionOpenAck = types.MsgConnectionOpenAck MsgConnectionOpenConfirm = types.MsgConnectionOpenConfirm + ConnectionResponse = types.ConnectionResponse QueryConnectionParams = types.QueryConnectionParams + ClientConnectionsResponse = types.ClientConnectionsResponse QueryClientConnectionsParams = types.QueryClientConnectionsParams ) From bd2170208ff30d52589a4a13dce74f8918ee4fbe Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 25 Oct 2019 13:04:05 +0200 Subject: [PATCH 341/378] update alias and keeper.GetPort() --- x/ibc/05-port/alias.go | 15 +++++++++------ x/ibc/05-port/keeper/keeper.go | 6 ++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/x/ibc/05-port/alias.go b/x/ibc/05-port/alias.go index ccf3db732be3..a74c7fe61537 100644 --- a/x/ibc/05-port/alias.go +++ b/x/ibc/05-port/alias.go @@ -12,11 +12,15 @@ import ( ) const ( - DefaultCodespace = types.DefaultCodespace - SubModuleName = types.SubModuleName - StoreKey = types.StoreKey - RouterKey = types.RouterKey - QuerierRoute = types.QuerierRoute + DefaultCodespace = types.DefaultCodespace + CodePortExists = types.CodePortExists + CodePortNotFound = types.CodePortNotFound + CodePortNotAuthenticated = types.CodePortNotAuthenticated + CodeInvalidPortID = types.CodeInvalidPortID + SubModuleName = types.SubModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute ) var ( @@ -28,7 +32,6 @@ var ( ErrInvalidPortID = types.ErrInvalidPortID PortPath = types.PortPath KeyPort = types.KeyPort - ValidatePortID = types.ValidatePortID ) type ( diff --git a/x/ibc/05-port/keeper/keeper.go b/x/ibc/05-port/keeper/keeper.go index 083c7db108f2..c684700f7e71 100644 --- a/x/ibc/05-port/keeper/keeper.go +++ b/x/ibc/05-port/keeper/keeper.go @@ -36,6 +36,12 @@ func (k Keeper) GetPorts() []string { return k.bound } +// GetPort retrieves a given port ID from keeper map +func (k Keeper) GetPort(ck sdk.CapabilityKey) (string, bool) { + portID, found := k.ports[ck] + return portID, found +} + // BindPort binds to a port and returns the associated capability. // Ports must be bound statically when the chain starts in `app.go`. // The capability must then be passed to a module which will need to pass From afc0583d9c27cb4c1062675ff874d20ef6db4681 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 25 Oct 2019 15:21:46 +0200 Subject: [PATCH 342/378] authenticate port ID; remove send packet msg from CLI --- x/ibc/04-channel/client/cli/tx.go | 37 +-------------- x/ibc/04-channel/handler.go | 24 ---------- x/ibc/04-channel/keeper/handshake.go | 52 +++++++++++++--------- x/ibc/04-channel/keeper/packet.go | 48 +++++++++----------- x/ibc/04-channel/keeper/timeout.go | 14 +++--- x/ibc/04-channel/types/expected_keepers.go | 1 - x/ibc/04-channel/types/msgs.go | 45 ------------------- 7 files changed, 63 insertions(+), 158 deletions(-) diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index b5ee5b46295e..2bea84398bcc 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -16,7 +16,6 @@ import ( 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/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -41,12 +40,13 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { GetMsgChannelOpenConfirmCmd(storeKey, cdc), GetMsgChannelCloseInitCmd(storeKey, cdc), GetMsgChannelCloseConfirmCmd(storeKey, cdc), - GetMsgSendPacketCmd(storeKey, cdc), )...) return ics04ChannelTxCmd } +// TODO: module needs to pass the capability key (i.e store key) + // GetMsgChannelOpenInitCmd returns the command to create a MsgChannelOpenInit transaction func GetMsgChannelOpenInitCmd(storeKey string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ @@ -288,39 +288,6 @@ func GetMsgChannelCloseConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comm } } -// GetMsgSendPacketCmd returns the command to create a MsgChannelCloseConfirm transaction -func GetMsgSendPacketCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "send-packet [/path/to/packet-data.json]", - Short: "Creates and sends a SendPacket message", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContext().WithCodec(cdc) - - var packet exported.PacketI - if err := cdc.UnmarshalJSON([]byte(args[0]), &packet); err != nil { - fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") - contents, err := ioutil.ReadFile(args[0]) - if err != nil { - return fmt.Errorf("error opening packet file: %v", err) - } - if err := cdc.UnmarshalJSON(contents, &packet); err != nil { - return fmt.Errorf("error unmarshalling packet file: %v", err) - } - } - - msg := types.NewMsgSendPacket(packet, cliCtx.GetFromAddress()) - if err := msg.ValidateBasic(); err != nil { - return err - } - - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } - return cmd -} - func channelOrder() types.Order { if viper.GetBool(FlagOrdered) { return types.ORDERED diff --git a/x/ibc/04-channel/handler.go b/x/ibc/04-channel/handler.go index b4e62b666e23..31c97b668e1a 100644 --- a/x/ibc/04-channel/handler.go +++ b/x/ibc/04-channel/handler.go @@ -151,27 +151,3 @@ func HandleMsgChannelCloseConfirm(ctx sdk.Context, k keeper.Keeper, msg types.Ms return sdk.Result{Events: ctx.EventManager().Events()} } - -// HandleMsgSendPacket defines the sdk.Handler for MsgSendPacket -func HandleMsgSendPacket(ctx sdk.Context, k Keeper, msg MsgSendPacket) sdk.Result { - err := k.SendPacket(ctx, msg.Packet) - if err != nil { - return sdk.ResultFromError(err) - } - - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeSendPacket, - sdk.NewAttribute(types.AttributeKeySenderPort, msg.Packet.SourcePort()), - sdk.NewAttribute(types.AttributeKeyChannelID, msg.Packet.SourceChannel()), - // TODO: destination port and channel events - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), - ), - }) - - return sdk.Result{Events: ctx.EventManager().Events()} -} diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go index bbfa30943abe..d3ba56cfa081 100644 --- a/x/ibc/04-channel/keeper/handshake.go +++ b/x/ibc/04-channel/keeper/handshake.go @@ -20,6 +20,7 @@ func (k Keeper) ChanOpenInit( channelID string, counterparty types.Counterparty, version string, + portCapability sdk.CapabilityKey, ) error { // TODO: abortTransactionUnless(validateChannelIdentifier(portIdentifier, channelIdentifier)) _, found := k.GetChannel(ctx, portID, channelID) @@ -39,14 +40,9 @@ func (k Keeper) ChanOpenInit( ) } - // _, found = k.portKeeper.GetPort(portID) - // if !found { - // return port.ErrPortNotFound(k.codespace, portID) - // } - - // if !k.portKeeper.AuthenticatePort(port.ID()) { - // return errors.New("port is not valid") - // } + if !k.portKeeper.Authenticate(portCapability, portID) { + return errors.New("port is not valid") + } channel := types.NewChannel(types.INIT, order, counterparty, connectionHops, version) k.SetChannel(ctx, portID, channelID, channel) @@ -71,20 +67,16 @@ func (k Keeper) ChanOpenTry( counterpartyVersion string, proofInit commitment.ProofI, proofHeight uint64, + portCapability sdk.CapabilityKey, ) error { _, found := k.GetChannel(ctx, portID, channelID) if found { return types.ErrChannelExists(k.codespace, channelID) } - // _, found = k.portKeeper.GetPort(portID) - // if !found { - // return port.ErrPortNotFound(k.codespace, portID) - // } - - // if !k.portKeeper.AuthenticatePort(port.ID()) { - // return errors.New("port is not valid") - // } + if !k.portKeeper.Authenticate(portCapability, portID) { + return errors.New("port is not valid") + } connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) if !found { @@ -141,6 +133,7 @@ func (k Keeper) ChanOpenAck( counterpartyVersion string, proofTry commitment.ProofI, proofHeight uint64, + portCapability sdk.CapabilityKey, ) error { channel, found := k.GetChannel(ctx, portID, channelID) @@ -155,7 +148,9 @@ func (k Keeper) ChanOpenAck( ) } - // TODO: get channel capability key and authenticate it + if !k.portKeeper.Authenticate(portCapability, portID) { + return errors.New("port is not valid") + } connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { @@ -204,6 +199,7 @@ func (k Keeper) ChanOpenConfirm( channelID string, proofAck commitment.ProofI, proofHeight uint64, + portCapability sdk.CapabilityKey, ) error { channel, found := k.GetChannel(ctx, portID, channelID) if !found { @@ -217,7 +213,9 @@ func (k Keeper) ChanOpenConfirm( ) } - // TODO: get channel capability key and authenticate it + if !k.portKeeper.Authenticate(portCapability, portID) { + return errors.New("port is not valid") + } connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { @@ -263,8 +261,16 @@ func (k Keeper) ChanOpenConfirm( // ChanCloseInit is called by either module to close their end of the channel. Once // closed, channels cannot be reopened. -func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error { - // TODO: get channel capability key and authenticate it +func (k Keeper) ChanCloseInit( + ctx sdk.Context, + portID, + channelID string, + portCapability sdk.CapabilityKey, +) error { + if !k.portKeeper.Authenticate(portCapability, portID) { + return errors.New("port is not valid") + } + channel, found := k.GetChannel(ctx, portID, channelID) if !found { return types.ErrChannelNotFound(k.codespace, channelID) @@ -300,8 +306,12 @@ func (k Keeper) ChanCloseConfirm( channelID string, proofInit commitment.ProofI, proofHeight uint64, + portCapability sdk.CapabilityKey, ) error { - // TODO: get channel capability key and authenticate it + if !k.portKeeper.Authenticate(portCapability, portID) { + return errors.New("port is not valid") + } + channel, found := k.GetChannel(ctx, portID, channelID) if !found { return types.ErrChannelNotFound(k.codespace, channelID) diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go index 3858c57f3ed7..f43bffc22704 100644 --- a/x/ibc/04-channel/keeper/packet.go +++ b/x/ibc/04-channel/keeper/packet.go @@ -30,6 +30,7 @@ func (k Keeper) CleanupPacket( proofHeight, nextSequenceRecv uint64, acknowledgement []byte, + portCapability sdk.CapabilityKey, ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { @@ -48,9 +49,9 @@ func (k Keeper) CleanupPacket( return nil, types.ErrChannelCapabilityNotFound(k.codespace) } - // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") - // } + if !k.portKeeper.Authenticate(portCapability, packet.SourcePort()) { + return nil, errors.New("port is not valid") + } if packet.DestChannel() != channel.Counterparty.ChannelID { return nil, types.ErrInvalidPacket( @@ -109,7 +110,15 @@ func (k Keeper) CleanupPacket( // SendPacket is called by a module in order to send an IBC packet on a channel // end owned by the calling module to the corresponding module on the counterparty // chain. -func (k Keeper) SendPacket(ctx sdk.Context, packet exported.PacketI) error { +func (k Keeper) SendPacket( + ctx sdk.Context, + packet exported.PacketI, + portCapability sdk.CapabilityKey, +) error { + if err := packet.ValidateBasic(); err != nil { + return err + } + channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { return types.ErrChannelNotFound(k.codespace, packet.SourceChannel()) @@ -122,15 +131,10 @@ func (k Keeper) SendPacket(ctx sdk.Context, packet exported.PacketI) error { ) } - _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) - if !found { - return types.ErrChannelCapabilityNotFound(k.codespace) + if !k.portKeeper.Authenticate(portCapability, packet.SourcePort()) { + return errors.New("port is not valid") } - // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") - // } - if packet.DestPort() != channel.Counterparty.PortID { return types.ErrInvalidPacket( k.codespace, @@ -193,6 +197,7 @@ func (k Keeper) RecvPacket( proof commitment.ProofI, proofHeight uint64, acknowledgement []byte, + portCapability sdk.CapabilityKey, ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.DestPort(), packet.DestChannel()) @@ -207,15 +212,10 @@ func (k Keeper) RecvPacket( ) } - _, found = k.GetChannelCapability(ctx, packet.DestPort(), packet.DestChannel()) - if !found { - return nil, types.ErrChannelCapabilityNotFound(k.codespace) + if !k.portKeeper.Authenticate(portCapability, packet.DestPort()) { + return nil, errors.New("port is not valid") } - // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") - // } - // packet must come from the channel's counterparty if packet.SourcePort() != channel.Counterparty.PortID { return nil, types.ErrInvalidPacket( @@ -293,6 +293,7 @@ func (k Keeper) AcknowledgePacket( acknowledgement []byte, proof commitment.ProofI, proofHeight uint64, + portCapability sdk.CapabilityKey, ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { @@ -306,15 +307,10 @@ func (k Keeper) AcknowledgePacket( ) } - _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) - if !found { - return nil, types.ErrChannelCapabilityNotFound(k.codespace) + if !k.portKeeper.Authenticate(portCapability, packet.SourcePort()) { + return nil, errors.New("invalid capability key") } - // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") - // } - // packet must come from the channel's counterparty if packet.SourcePort() != channel.Counterparty.PortID { return nil, types.ErrInvalidPacket( @@ -352,7 +348,7 @@ func (k Keeper) AcknowledgePacket( types.PacketAcknowledgementPath(packet.DestPort(), packet.DestChannel(), packet.Sequence()), acknowledgement, // TODO: hash ACK ) { - return nil, errors.New("invalid acknowledgement on counterparty chain") // TODO: sdk.Error + return nil, errors.New("invalid acknowledgement on counterparty chain") } k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) diff --git a/x/ibc/04-channel/keeper/timeout.go b/x/ibc/04-channel/keeper/timeout.go index 5d9f5ebc8ae2..232e60eb6de1 100644 --- a/x/ibc/04-channel/keeper/timeout.go +++ b/x/ibc/04-channel/keeper/timeout.go @@ -23,6 +23,7 @@ func (k Keeper) TimeoutPacket( proof commitment.ProofI, proofHeight uint64, nextSequenceRecv uint64, + portCapability sdk.CapabilityKey, ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { @@ -41,9 +42,9 @@ func (k Keeper) TimeoutPacket( return nil, types.ErrChannelCapabilityNotFound(k.codespace) } - // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") - // } + if !k.portKeeper.Authenticate(portCapability, packet.SourcePort()) { + return nil, errors.New("port is not valid") + } if packet.DestChannel() != channel.Counterparty.ChannelID { return nil, types.ErrInvalidPacket( @@ -117,6 +118,7 @@ func (k Keeper) TimeoutOnClose( proofNonMembership, proofClosed commitment.ProofI, proofHeight uint64, + portCapability sdk.CapabilityKey, ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) if !found { @@ -128,9 +130,9 @@ func (k Keeper) TimeoutOnClose( return nil, types.ErrChannelCapabilityNotFound(k.codespace) } - // if !AuthenticateCapabilityKey(capabilityKey) { - // return errors.New("invalid capability key") - // } + if !k.portKeeper.Authenticate(portCapability, packet.SourcePort()) { + return nil, errors.New("port is not valid") + } if packet.DestChannel() != channel.Counterparty.ChannelID { return nil, types.ErrInvalidPacket( diff --git a/x/ibc/04-channel/types/expected_keepers.go b/x/ibc/04-channel/types/expected_keepers.go index 85829b491d92..ab88a2284f27 100644 --- a/x/ibc/04-channel/types/expected_keepers.go +++ b/x/ibc/04-channel/types/expected_keepers.go @@ -27,6 +27,5 @@ type ConnectionKeeper interface { // PortKeeper expected account IBC port keeper type PortKeeper interface { - GetPort(key sdk.CapabilityKey) (string, bool) Authenticate(key sdk.CapabilityKey, portID string) bool } diff --git a/x/ibc/04-channel/types/msgs.go b/x/ibc/04-channel/types/msgs.go index e7033466aac4..9f01bc04d2dc 100644 --- a/x/ibc/04-channel/types/msgs.go +++ b/x/ibc/04-channel/types/msgs.go @@ -5,7 +5,6 @@ import ( "strings" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" @@ -378,47 +377,3 @@ func (msg MsgChannelCloseConfirm) GetSignBytes() []byte { func (msg MsgChannelCloseConfirm) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } - -var _ sdk.Msg = MsgSendPacket{} - -// MsgSendPacket PortID dependent on type -// ChannelID can be empty if batched & not first MsgSendPacket -// Height uint64 // height of the commitment root for the proofs -type MsgSendPacket struct { - Packet exported.PacketI `json:"packet" yaml:"packet"` - Signer sdk.AccAddress `json:"signer" yaml:"signer"` -} - -// NewMsgSendPacket creates a new MsgSendPacket instance -func NewMsgSendPacket(packet exported.PacketI, signer sdk.AccAddress) MsgSendPacket { - return MsgSendPacket{ - Packet: packet, - Signer: signer, - } -} - -// Route implements sdk.Msg -func (msg MsgSendPacket) Route() string { - return ibctypes.RouterKey -} - -// Type implements sdk.Msg -func (msg MsgSendPacket) Type() string { - return "send_packet" -} - -// ValidateBasic implements sdk.Msg -func (msg MsgSendPacket) ValidateBasic() sdk.Error { - // Signer can be empty - return msg.Packet.ValidateBasic() -} - -// GetSignBytes implements sdk.Msg -func (msg MsgSendPacket) GetSignBytes() []byte { - return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) -} - -// GetSigners implements sdk.Msg -func (msg MsgSendPacket) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} From 335954c0466519c31f2811bb557b86f8c0f786c1 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 25 Oct 2019 15:25:50 +0200 Subject: [PATCH 343/378] comment out handlers --- x/ibc/04-channel/alias.go | 3 - x/ibc/04-channel/handler.go | 296 +++++++++++++++---------------- x/ibc/04-channel/types/events.go | 1 - x/ibc/handler.go | 30 ++-- 4 files changed, 158 insertions(+), 172 deletions(-) diff --git a/x/ibc/04-channel/alias.go b/x/ibc/04-channel/alias.go index f85ba2d79a62..01948305fd47 100644 --- a/x/ibc/04-channel/alias.go +++ b/x/ibc/04-channel/alias.go @@ -86,7 +86,6 @@ var ( NewMsgChannelOpenConfirm = types.NewMsgChannelOpenConfirm NewMsgChannelCloseInit = types.NewMsgChannelCloseInit NewMsgChannelCloseConfirm = types.NewMsgChannelCloseConfirm - NewMsgSendPacket = types.NewMsgSendPacket NewPacket = types.NewPacket NewOpaquePacket = types.NewOpaquePacket NewChannelResponse = types.NewChannelResponse @@ -94,7 +93,6 @@ var ( // variable aliases SubModuleCdc = types.SubModuleCdc - EventTypeSendPacket = types.EventTypeSendPacket EventTypeChannelOpenInit = types.EventTypeChannelOpenInit EventTypeChannelOpenTry = types.EventTypeChannelOpenTry EventTypeChannelOpenAck = types.EventTypeChannelOpenAck @@ -119,7 +117,6 @@ type ( MsgChannelOpenConfirm = types.MsgChannelOpenConfirm MsgChannelCloseInit = types.MsgChannelCloseInit MsgChannelCloseConfirm = types.MsgChannelCloseConfirm - MsgSendPacket = types.MsgSendPacket Packet = types.Packet OpaquePacket = types.OpaquePacket ChannelResponse = types.ChannelResponse diff --git a/x/ibc/04-channel/handler.go b/x/ibc/04-channel/handler.go index 31c97b668e1a..105f7ae1a9eb 100644 --- a/x/ibc/04-channel/handler.go +++ b/x/ibc/04-channel/handler.go @@ -1,153 +1,147 @@ package channel -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper" - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" -) - -// HandleMsgChannelOpenInit defines the sdk.Handler for MsgChannelOpenInit -func HandleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenInit) sdk.Result { - err := k.ChanOpenInit( - ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, - msg.Channel.Counterparty, msg.Channel.Version, - ) - if err != nil { - return sdk.ResultFromError(err) - } - - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeChannelOpenInit, - sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), - sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), - ), - }) - - return sdk.Result{Events: ctx.EventManager().Events()} -} - -// HandleMsgChannelOpenTry defines the sdk.Handler for MsgChannelOpenTry -func HandleMsgChannelOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenTry) sdk.Result { - err := k.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, - msg.Channel.Counterparty, msg.Channel.Version, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, - ) - if err != nil { - return sdk.ResultFromError(err) - } - - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeChannelOpenTry, - sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), - sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), // TODO: double check sender and receiver - sdk.NewAttribute(types.AttributeKeyReceiverPort, msg.Channel.Counterparty.PortID), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), - ), - }) - - return sdk.Result{Events: ctx.EventManager().Events()} -} - -// HandleMsgChannelOpenAck defines the sdk.Handler for MsgChannelOpenAck -func HandleMsgChannelOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenAck) sdk.Result { - err := k.ChanOpenAck( - ctx, msg.PortID, msg.ChannelID, msg.CounterpartyVersion, msg.ProofTry, msg.ProofHeight, - ) - if err != nil { - return sdk.ResultFromError(err) - } - - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeChannelOpenAck, - sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), - sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), - ), - }) - - return sdk.Result{Events: ctx.EventManager().Events()} -} - -// HandleMsgChannelOpenConfirm defines the sdk.Handler for MsgChannelOpenConfirm -func HandleMsgChannelOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenConfirm) sdk.Result { - err := k.ChanOpenConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofAck, msg.ProofHeight) - if err != nil { - return sdk.ResultFromError(err) - } - - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeChannelOpenConfirm, - sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), - sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), - ), - }) - - return sdk.Result{Events: ctx.EventManager().Events()} -} - -// HandleMsgChannelCloseInit defines the sdk.Handler for MsgChannelCloseInit -func HandleMsgChannelCloseInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseInit) sdk.Result { - err := k.ChanCloseInit(ctx, msg.PortID, msg.ChannelID) - if err != nil { - return sdk.ResultFromError(err) - } - - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeChannelCloseInit, - sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), - sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), - ), - }) - - return sdk.Result{Events: ctx.EventManager().Events()} -} - -// HandleMsgChannelCloseConfirm defines the sdk.Handler for MsgChannelCloseConfirm -func HandleMsgChannelCloseConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseConfirm) sdk.Result { - err := k.ChanCloseConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofInit, msg.ProofHeight) - if err != nil { - return sdk.ResultFromError(err) - } - - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeChannelCloseConfirm, - sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), - sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), - ), - }) - - return sdk.Result{Events: ctx.EventManager().Events()} -} +// // HandleMsgChannelOpenInit defines the sdk.Handler for MsgChannelOpenInit +// func HandleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenInit) sdk.Result { +// err := k.ChanOpenInit( +// ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, +// msg.Channel.Counterparty, msg.Channel.Version, +// ) +// if err != nil { +// return sdk.ResultFromError(err) +// } + +// ctx.EventManager().EmitEvents(sdk.Events{ +// sdk.NewEvent( +// types.EventTypeChannelOpenInit, +// sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), +// sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), +// ), +// sdk.NewEvent( +// sdk.EventTypeMessage, +// sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), +// sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), +// ), +// }) + +// return sdk.Result{Events: ctx.EventManager().Events()} +// } + +// // HandleMsgChannelOpenTry defines the sdk.Handler for MsgChannelOpenTry +// func HandleMsgChannelOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenTry) sdk.Result { +// err := k.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, +// msg.Channel.Counterparty, msg.Channel.Version, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, +// ) +// if err != nil { +// return sdk.ResultFromError(err) +// } + +// ctx.EventManager().EmitEvents(sdk.Events{ +// sdk.NewEvent( +// types.EventTypeChannelOpenTry, +// sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), +// sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), // TODO: double check sender and receiver +// sdk.NewAttribute(types.AttributeKeyReceiverPort, msg.Channel.Counterparty.PortID), +// ), +// sdk.NewEvent( +// sdk.EventTypeMessage, +// sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), +// sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), +// ), +// }) + +// return sdk.Result{Events: ctx.EventManager().Events()} +// } + +// // HandleMsgChannelOpenAck defines the sdk.Handler for MsgChannelOpenAck +// func HandleMsgChannelOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenAck) sdk.Result { +// err := k.ChanOpenAck( +// ctx, msg.PortID, msg.ChannelID, msg.CounterpartyVersion, msg.ProofTry, msg.ProofHeight, +// ) +// if err != nil { +// return sdk.ResultFromError(err) +// } + +// ctx.EventManager().EmitEvents(sdk.Events{ +// sdk.NewEvent( +// types.EventTypeChannelOpenAck, +// sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), +// sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), +// ), +// sdk.NewEvent( +// sdk.EventTypeMessage, +// sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), +// sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), +// ), +// }) + +// return sdk.Result{Events: ctx.EventManager().Events()} +// } + +// // HandleMsgChannelOpenConfirm defines the sdk.Handler for MsgChannelOpenConfirm +// func HandleMsgChannelOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenConfirm) sdk.Result { +// err := k.ChanOpenConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofAck, msg.ProofHeight) +// if err != nil { +// return sdk.ResultFromError(err) +// } + +// ctx.EventManager().EmitEvents(sdk.Events{ +// sdk.NewEvent( +// types.EventTypeChannelOpenConfirm, +// sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), +// sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), +// ), +// sdk.NewEvent( +// sdk.EventTypeMessage, +// sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), +// sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), +// ), +// }) + +// return sdk.Result{Events: ctx.EventManager().Events()} +// } + +// // HandleMsgChannelCloseInit defines the sdk.Handler for MsgChannelCloseInit +// func HandleMsgChannelCloseInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseInit) sdk.Result { +// err := k.ChanCloseInit(ctx, msg.PortID, msg.ChannelID) +// if err != nil { +// return sdk.ResultFromError(err) +// } + +// ctx.EventManager().EmitEvents(sdk.Events{ +// sdk.NewEvent( +// types.EventTypeChannelCloseInit, +// sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), +// sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), +// ), +// sdk.NewEvent( +// sdk.EventTypeMessage, +// sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), +// sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), +// ), +// }) + +// return sdk.Result{Events: ctx.EventManager().Events()} +// } + +// // HandleMsgChannelCloseConfirm defines the sdk.Handler for MsgChannelCloseConfirm +// func HandleMsgChannelCloseConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseConfirm) sdk.Result { +// err := k.ChanCloseConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofInit, msg.ProofHeight) +// if err != nil { +// return sdk.ResultFromError(err) +// } + +// ctx.EventManager().EmitEvents(sdk.Events{ +// sdk.NewEvent( +// types.EventTypeChannelCloseConfirm, +// sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), +// sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), +// ), +// sdk.NewEvent( +// sdk.EventTypeMessage, +// sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), +// sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), +// ), +// }) + +// return sdk.Result{Events: ctx.EventManager().Events()} +// } diff --git a/x/ibc/04-channel/types/events.go b/x/ibc/04-channel/types/events.go index 7b81f1033285..b82b3e8700cf 100644 --- a/x/ibc/04-channel/types/events.go +++ b/x/ibc/04-channel/types/events.go @@ -16,7 +16,6 @@ const ( // IBC channel events vars var ( - EventTypeSendPacket = MsgSendPacket{}.Type() EventTypeChannelOpenInit = MsgChannelOpenInit{}.Type() EventTypeChannelOpenTry = MsgChannelOpenTry{}.Type() EventTypeChannelOpenAck = MsgChannelOpenAck{}.Type() diff --git a/x/ibc/handler.go b/x/ibc/handler.go index 8822b0206da9..d3f700a4d970 100644 --- a/x/ibc/handler.go +++ b/x/ibc/handler.go @@ -6,7 +6,6 @@ import ( 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" ) // NewHandler defines the IBC handler @@ -38,27 +37,24 @@ func NewHandler(k Keeper) sdk.Handler { case connection.MsgConnectionOpenConfirm: return connection.HandleMsgConnectionOpenConfirm(ctx, k.ConnectionKeeper, msg) - // IBC channel msgs - case channel.MsgChannelOpenInit: - return channel.HandleMsgChannelOpenInit(ctx, k.ChannelKeeper, msg) + // // IBC channel msgs + // case channel.MsgChannelOpenInit: + // return channel.HandleMsgChannelOpenInit(ctx, k.ChannelKeeper, msg) - case channel.MsgChannelOpenTry: - return channel.HandleMsgChannelOpenTry(ctx, k.ChannelKeeper, msg) + // case channel.MsgChannelOpenTry: + // return channel.HandleMsgChannelOpenTry(ctx, k.ChannelKeeper, msg) - case channel.MsgChannelOpenAck: - return channel.HandleMsgChannelOpenAck(ctx, k.ChannelKeeper, msg) + // case channel.MsgChannelOpenAck: + // return channel.HandleMsgChannelOpenAck(ctx, k.ChannelKeeper, msg) - case channel.MsgChannelOpenConfirm: - return channel.HandleMsgChannelOpenConfirm(ctx, k.ChannelKeeper, msg) + // case channel.MsgChannelOpenConfirm: + // return channel.HandleMsgChannelOpenConfirm(ctx, k.ChannelKeeper, msg) - case channel.MsgChannelCloseInit: - return channel.HandleMsgChannelCloseInit(ctx, k.ChannelKeeper, msg) + // case channel.MsgChannelCloseInit: + // return channel.HandleMsgChannelCloseInit(ctx, k.ChannelKeeper, msg) - case channel.MsgChannelCloseConfirm: - return channel.HandleMsgChannelCloseConfirm(ctx, k.ChannelKeeper, msg) - - case channel.MsgSendPacket: - return channel.HandleMsgSendPacket(ctx, k.ChannelKeeper, msg) + // case channel.MsgChannelCloseConfirm: + // return channel.HandleMsgChannelCloseConfirm(ctx, k.ChannelKeeper, msg) default: errMsg := fmt.Sprintf("unrecognized IBC message type: %T", msg) From 09adf432678f71196f64d366ea5fcc31eb1109b1 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 25 Oct 2019 15:34:06 +0200 Subject: [PATCH 344/378] add ibc module to simapp --- simapp/app.go | 10 ++++++++-- x/ibc/alias.go | 9 +++++---- x/ibc/types/types.go | 13 ++++++++++--- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/simapp/app.go b/simapp/app.go index 53e671a1242d..750472533b57 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -22,6 +22,7 @@ import ( distr "github.com/cosmos/cosmos-sdk/x/distribution" "github.com/cosmos/cosmos-sdk/x/genutil" "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/cosmos/cosmos-sdk/x/ibc" "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/params" paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" @@ -54,6 +55,7 @@ var ( params.AppModuleBasic{}, crisis.AppModuleBasic{}, slashing.AppModuleBasic{}, + ibc.AppModuleBasic{}, ) // module account permissions @@ -101,6 +103,7 @@ type SimApp struct { GovKeeper gov.Keeper CrisisKeeper crisis.Keeper ParamsKeeper params.Keeper + IBCKeeper ibc.Keeper // the module manager mm *module.Manager @@ -123,7 +126,7 @@ func NewSimApp( keys := sdk.NewKVStoreKeys(bam.MainStoreKey, auth.StoreKey, staking.StoreKey, supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey, - gov.StoreKey, params.StoreKey) + gov.StoreKey, params.StoreKey, ibc.StoreKey) tkeys := sdk.NewTransientStoreKeys(params.TStoreKey) app := &SimApp{ @@ -172,6 +175,8 @@ func NewSimApp( staking.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()), ) + app.IBCKeeper = ibc.NewKeeper(app.cdc, keys[ibc.StoreKey], ibc.DefaultCodespace) + // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. app.mm = module.NewManager( @@ -185,6 +190,7 @@ func NewSimApp( distr.NewAppModule(app.DistrKeeper, app.SupplyKeeper), slashing.NewAppModule(app.SlashingKeeper, app.StakingKeeper), staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper), + ibc.NewAppModule(app.IBCKeeper), ) // During begin block slashing happens after distr.BeginBlocker so that @@ -200,7 +206,7 @@ func NewSimApp( auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName, slashing.ModuleName, gov.ModuleName, mint.ModuleName, supply.ModuleName, crisis.ModuleName, - genutil.ModuleName, + ibc.ModuleName, genutil.ModuleName, ) app.mm.RegisterInvariants(&app.CrisisKeeper) diff --git a/x/ibc/alias.go b/x/ibc/alias.go index 7c1ad02349e2..abb2aae3c59a 100644 --- a/x/ibc/alias.go +++ b/x/ibc/alias.go @@ -12,10 +12,11 @@ import ( ) const ( - ModuleName = types.ModuleName - StoreKey = types.StoreKey - QuerierRoute = types.QuerierRoute - RouterKey = types.RouterKey + ModuleName = types.ModuleName + StoreKey = types.StoreKey + QuerierRoute = types.QuerierRoute + RouterKey = types.RouterKey + DefaultCodespace = types.DefaultCodespace ) var ( diff --git a/x/ibc/types/types.go b/x/ibc/types/types.go index 535a8f2461e5..bce43911994f 100644 --- a/x/ibc/types/types.go +++ b/x/ibc/types/types.go @@ -1,15 +1,22 @@ package types +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + const ( // ModuleName is the name of the IBC module ModuleName = "ibc" // StoreKey is the string store representation - StoreKey = ModuleName + StoreKey string = ModuleName // QuerierRoute is the querier route for the IBC module - QuerierRoute = ModuleName + QuerierRoute string = ModuleName // RouterKey is the msg router key for the IBC module - RouterKey = ModuleName + RouterKey string = ModuleName + + // DefaultCodespace of the IBC module + DefaultCodespace sdk.CodespaceType = ModuleName ) From 0363390f976c256dcb45546208eb5d7d0d3b5825 Mon Sep 17 00:00:00 2001 From: vincent Date: Sat, 26 Oct 2019 02:55:17 +0800 Subject: [PATCH 345/378] ICS20 implementation (#5204) * add ibc bank mock * modify handler * import channel * add receiving logic * add cli proof handling * modify cli * modify receiver type * modify errcode * optimize codes * add denom prefix when source is true * refactor code * error return --- x/ibc/04-channel/types/events.go | 1 + x/ibc/client/cli/cli.go | 2 + x/ibc/mock/bank/alias.go | 30 +++ x/ibc/mock/bank/client/cli/flags.go | 27 +++ x/ibc/mock/bank/client/cli/tx.go | 128 +++++++++++++ x/ibc/mock/bank/handler.go | 44 +++++ x/ibc/mock/bank/internal/keeper/keeper.go | 181 ++++++++++++++++++ x/ibc/mock/bank/internal/types/codec.go | 24 +++ x/ibc/mock/bank/internal/types/errors.go | 17 ++ .../bank/internal/types/expected_keepers.go | 32 ++++ x/ibc/mock/bank/internal/types/keys.go | 21 ++ x/ibc/mock/bank/internal/types/msgs.go | 105 ++++++++++ x/ibc/mock/bank/internal/types/packet.go | 122 ++++++++++++ x/ibc/mock/bank/module.go | 110 +++++++++++ 14 files changed, 844 insertions(+) create mode 100644 x/ibc/mock/bank/alias.go create mode 100644 x/ibc/mock/bank/client/cli/flags.go create mode 100644 x/ibc/mock/bank/client/cli/tx.go create mode 100644 x/ibc/mock/bank/handler.go create mode 100644 x/ibc/mock/bank/internal/keeper/keeper.go create mode 100644 x/ibc/mock/bank/internal/types/codec.go create mode 100644 x/ibc/mock/bank/internal/types/errors.go create mode 100644 x/ibc/mock/bank/internal/types/expected_keepers.go create mode 100644 x/ibc/mock/bank/internal/types/keys.go create mode 100644 x/ibc/mock/bank/internal/types/msgs.go create mode 100644 x/ibc/mock/bank/internal/types/packet.go create mode 100644 x/ibc/mock/bank/module.go diff --git a/x/ibc/04-channel/types/events.go b/x/ibc/04-channel/types/events.go index b82b3e8700cf..72d92cbf2237 100644 --- a/x/ibc/04-channel/types/events.go +++ b/x/ibc/04-channel/types/events.go @@ -12,6 +12,7 @@ const ( AttributeKeyReceiverPort = "receiver_port" AttributeKeyChannelID = "channel_id" AttributeKeySequence = "sequence" + AttributeKeyPacket = "packet" ) // IBC channel events vars diff --git a/x/ibc/client/cli/cli.go b/x/ibc/client/cli/cli.go index 4e25e3ce508f..e6163dfc7d57 100644 --- a/x/ibc/client/cli/cli.go +++ b/x/ibc/client/cli/cli.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + mockbank "github.com/cosmos/cosmos-sdk/x/ibc/mock/bank" "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -23,6 +24,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ibcTxCmd.AddCommand( ibcclient.GetTxCmd(cdc, storeKey), connection.GetTxCmd(cdc, storeKey), + mockbank.GetTxCmd(cdc), ) return ibcTxCmd } diff --git a/x/ibc/mock/bank/alias.go b/x/ibc/mock/bank/alias.go new file mode 100644 index 000000000000..230489e7099c --- /dev/null +++ b/x/ibc/mock/bank/alias.go @@ -0,0 +1,30 @@ +package mockbank + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/mock/bank/internal/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/bank/internal/types" +) + +// nolint +type ( + MsgTransfer = types.MsgTransfer + MsgRecvTransferPacket = types.MsgRecvTransferPacket + Keeper = keeper.Keeper +) + +const ( + ModuleName = types.ModuleName + StoreKey = types.StoreKey + TStoreKey = types.TStoreKey + QuerierRoute = types.QuerierRoute + RouterKey = types.RouterKey +) + +// nolint +var ( + RegisterCdc = types.RegisterCodec + + NewKeeper = keeper.NewKeeper + NewMsgTransfer = types.NewMsgTransfer + NewMsgRecvTransferPacket = types.NewMsgRecvTransferPacket +) diff --git a/x/ibc/mock/bank/client/cli/flags.go b/x/ibc/mock/bank/client/cli/flags.go new file mode 100644 index 000000000000..24218867aa86 --- /dev/null +++ b/x/ibc/mock/bank/client/cli/flags.go @@ -0,0 +1,27 @@ +package cli + +import ( + flag "github.com/spf13/pflag" +) + +const ( + FlagSrcPort = "src-port" + FlagSrcChannel = "src-channel" + FlagDenom = "denom" + FlagAmount = "amount" + FlagReceiver = "receiver" + FlagSource = "source" +) + +var ( + FsTransfer = flag.NewFlagSet("", flag.ContinueOnError) +) + +func init() { + FsTransfer.String(FlagSrcPort, "", "the source port ID") + FsTransfer.String(FlagSrcChannel, "", "the source channel ID") + FsTransfer.String(FlagDenom, "", "the denomination of the token to be transferred") + FsTransfer.String(FlagAmount, "", "the amount of the token to be transferred") + FsTransfer.String(FlagReceiver, "", "the recipient") + FsTransfer.Bool(FlagSource, true, "indicate if the sending chain is the source chain of the token") +} diff --git a/x/ibc/mock/bank/client/cli/tx.go b/x/ibc/mock/bank/client/cli/tx.go new file mode 100644 index 000000000000..a7d96935a0ff --- /dev/null +++ b/x/ibc/mock/bank/client/cli/tx.go @@ -0,0 +1,128 @@ +package cli + +import ( + "fmt" + "io/ioutil" + "os" + "strconv" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "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" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/bank/internal/types" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func GetTxCmd(cdc *codec.Codec) *cobra.Command { + txCmd := &cobra.Command{ + Use: "ibcmockbank", + Short: "IBC mockbank module transaction subcommands", + // RunE: client.ValidateCmd, + } + txCmd.AddCommand( + GetTransferTxCmd(cdc), + GetMsgRecvPacketCmd(cdc), + ) + + return txCmd +} + +func GetTransferTxCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "transfer --src-port --src-channel --denom --amount --receiver --source ", + Short: "Transfer tokens across chains through IBC", + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + ctx := context.NewCLIContext().WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) + + sender := ctx.GetFromAddress() + receiver := viper.GetString(FlagReceiver) + denom := viper.GetString(FlagDenom) + srcPort := viper.GetString(FlagSrcPort) + srcChan := viper.GetString(FlagSrcChannel) + source := viper.GetBool(FlagSource) + + amount, ok := sdk.NewIntFromString(viper.GetString(FlagAmount)) + if !ok { + return fmt.Errorf("invalid amount") + } + + msg := types.NewMsgTransfer(srcPort, srcChan, denom, amount, sender, receiver, source) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return utils.GenerateOrBroadcastMsgs(ctx, txBldr, []sdk.Msg{msg}) + }, + } + + cmd.Flags().AddFlagSet(FsTransfer) + + cmd.MarkFlagRequired(FlagSrcPort) + cmd.MarkFlagRequired(FlagSrcChannel) + cmd.MarkFlagRequired(FlagDenom) + cmd.MarkFlagRequired(FlagAmount) + cmd.MarkFlagRequired(FlagReceiver) + + cmd = client.PostCommands(cmd)[0] + + return cmd +} + +// GetMsgRecvPacketCmd returns the command to create a MsgRecvTransferPacket transaction +func GetMsgRecvPacketCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "recv-packet [/path/to/packet-data.json] [/path/to/proof.json] [height]", + Short: "Creates and sends a SendPacket message", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) + + var packet types.Packet + if err := cdc.UnmarshalJSON([]byte(args[0]), &packet); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...\n") + contents, err := ioutil.ReadFile(args[0]) + if err != nil { + return fmt.Errorf("error opening packet file: %v", err) + } + if err := packet.UnmarshalJSON(contents); err != nil { + return fmt.Errorf("error unmarshalling packet file: %v", err) + } + } + + var proof ics23.Proof + if err := cdc.UnmarshalJSON([]byte(args[1]), &proof); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...\n") + contents, err := ioutil.ReadFile(args[1]) + if err != nil { + return fmt.Errorf("error opening proofs file: %v", err) + } + if err := cdc.UnmarshalJSON(contents, &proof); err != nil { + return fmt.Errorf("error unmarshalling proofs file: %v", err) + } + } + + height, err := strconv.ParseUint(args[2], 10, 64) + if err != nil { + return fmt.Errorf("error height: %v", err) + } + + msg := types.NewMsgRecvTransferPacket(packet, []ics23.Proof{proof}, height, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + + cmd = client.PostCommands(cmd)[0] + return cmd +} diff --git a/x/ibc/mock/bank/handler.go b/x/ibc/mock/bank/handler.go new file mode 100644 index 000000000000..efe2bf9f5f8b --- /dev/null +++ b/x/ibc/mock/bank/handler.go @@ -0,0 +1,44 @@ +package mockbank + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + ics04 "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" +) + +func NewHandler(k Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case MsgTransfer: + return handleMsgTransfer(ctx, k, msg) + case MsgRecvTransferPacket: + return handleMsgRecvTransferPacket(ctx, k, msg) + default: + return sdk.ErrUnknownRequest("failed to parse message").Result() + } + } +} + +func handleMsgTransfer(ctx sdk.Context, k Keeper, msg MsgTransfer) (res sdk.Result) { + err := k.SendTransfer(ctx, msg.SrcPort, msg.SrcChannel, msg.Denomination, msg.Amount, msg.Sender, msg.Receiver, msg.Source) + if err != nil { + return err.Result() + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, ics04.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), + )) + + return sdk.Result{Events: ctx.EventManager().Events()} +} + +func handleMsgRecvTransferPacket(ctx sdk.Context, k Keeper, msg MsgRecvTransferPacket) (res sdk.Result) { + err := k.ReceiveTransfer(ctx, msg.Packet, msg.Proofs[0], msg.Height) + if err != nil { + return err.Result() + } + + return sdk.Result{Events: ctx.EventManager().Events()} +} diff --git a/x/ibc/mock/bank/internal/keeper/keeper.go b/x/ibc/mock/bank/internal/keeper/keeper.go new file mode 100644 index 000000000000..ceb4ae71fbae --- /dev/null +++ b/x/ibc/mock/bank/internal/keeper/keeper.go @@ -0,0 +1,181 @@ +package keeper + +import ( + "fmt" + "strings" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + ics04 "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/mock/bank/internal/types" + "github.com/tendermint/tendermint/crypto" +) + +const ( + DefaultPacketTimeout = 1000 // default packet timeout relative to the current block height +) + +type Keeper struct { + cdc *codec.Codec + key sdk.StoreKey + ck types.ChannelKeeper + bk types.BankKeeper +} + +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ck types.ChannelKeeper, bk types.BankKeeper) Keeper { + return Keeper{ + cdc: cdc, + key: key, + ck: ck, + bk: bk, + } +} + +// SendTransfer handles transfer sending logic +func (k Keeper) SendTransfer(ctx sdk.Context, srcPort, srcChan string, denom string, amount sdk.Int, sender sdk.AccAddress, receiver string, source bool) sdk.Error { + // get the port and channel of the counterparty + channel, ok := k.ck.GetChannel(ctx, srcPort, srcChan) + if !ok { + return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), ics04.CodeChannelNotFound, "failed to get channel") + } + + dstPort := channel.Counterparty.PortID + dstChan := channel.Counterparty.ChannelID + + // get the next sequence + sequence, ok := k.ck.GetNextSequenceSend(ctx, srcPort, srcChan) + if !ok { + return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), ics04.CodeSequenceNotFound, "failed to retrieve sequence") + } + + if source { + // build the receiving denomination prefix + prefix := fmt.Sprintf("%s/%s", dstPort, dstChan) + denom = prefix + denom + } + + return k.createOutgoingPacket(ctx, sequence, srcPort, srcChan, dstPort, dstChan, denom, amount, sender, receiver, source) +} + +// ReceiveTransfer handles transfer receiving logic +func (k Keeper) ReceiveTransfer(ctx sdk.Context, packet exported.PacketI, proof ics23.Proof, height uint64) sdk.Error { + _, err := k.ck.RecvPacket(ctx, packet, proof, height, nil) + if err != nil { + return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeErrReceivePacket, "failed to receive packet") + } + + var data types.TransferPacketData + err = data.UnmarshalJSON(packet.Data()) + if err != nil { + return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeInvalidPacketData, "invalid packet data") + } + + receiverAddr, err := sdk.AccAddressFromBech32(data.Receiver) + if err != nil { + return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeInvalidReceiver, "invalid receiver address") + } + + if data.Source { + // mint tokens + + // check the denom prefix + prefix := fmt.Sprintf("%s/%s", packet.DestPort(), packet.DestChannel()) + if !strings.HasPrefix(data.Denomination, prefix) { + return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeIncorrectDenom, "incorrect denomination") + } + + _, err := k.bk.AddCoins(ctx, receiverAddr, sdk.Coins{sdk.NewCoin(data.Denomination, data.Amount)}) + if err != nil { + return err + } + + } else { + // unescrow tokens + + // check the denom prefix + prefix := fmt.Sprintf("%s/%s", packet.SourcePort(), packet.SourceChannel()) + if !strings.HasPrefix(data.Denomination, prefix) { + return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeIncorrectDenom, "incorrect denomination") + } + + escrowAddress := k.GetEscrowAddress(packet.DestChannel()) + err := k.bk.SendCoins(ctx, escrowAddress, receiverAddr, sdk.Coins{sdk.NewCoin(data.Denomination[len(prefix):], data.Amount)}) + if err != nil { + return err + } + } + + return nil +} + +func (k Keeper) createOutgoingPacket(ctx sdk.Context, seq uint64, srcPort, srcChan, dstPort, dstChan string, denom string, amount sdk.Int, sender sdk.AccAddress, receiver string, source bool) sdk.Error { + if source { + // escrow tokens + + // get escrow address + escrowAddress := k.GetEscrowAddress(srcChan) + + // check the denom prefix + prefix := fmt.Sprintf("%s/%s", dstPort, dstChan) + if !strings.HasPrefix(denom, prefix) { + return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeIncorrectDenom, "incorrect denomination") + } + + err := k.bk.SendCoins(ctx, sender, escrowAddress, sdk.Coins{sdk.NewCoin(denom[len(prefix):], amount)}) + if err != nil { + return err + } + + } else { + // burn vouchers from sender + + // check the denom prefix + prefix := fmt.Sprintf("%s/%s", srcPort, srcChan) + if !strings.HasPrefix(denom, prefix) { + return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeIncorrectDenom, "incorrect denomination") + } + + _, err := k.bk.SubtractCoins(ctx, sender, sdk.Coins{sdk.NewCoin(denom, amount)}) + if err != nil { + return err + } + } + + // build packet + packetData := types.TransferPacketData{ + Denomination: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Source: source, + } + + packetDataBz, err := packetData.MarshalJSON() + if err != nil { + return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeInvalidPacketData, "invalid packet data") + } + + packet := types.NewPacket(seq, uint64(ctx.BlockHeight())+DefaultPacketTimeout, srcPort, srcChan, dstPort, dstChan, packetDataBz) + + err = k.ck.SendPacket(ctx, packet) + if err != nil { + return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeErrSendPacket, "failed to send packet") + } + + packetJson, _ := packet.MarshalJSON() + ctx.EventManager().EmitEvent(sdk.NewEvent( + ics04.EventTypeSendPacket, + sdk.NewAttribute(ics04.AttributeKeySenderPort, srcPort), + sdk.NewAttribute(ics04.AttributeKeyChannelID, srcChan), + sdk.NewAttribute(ics04.AttributeKeyPacket, string(packetJson)), + )) + + return nil +} + +// GetEscrowAddress returns the escrow address for the specified channel +func (k Keeper) GetEscrowAddress(chanID string) sdk.AccAddress { + return sdk.AccAddress(crypto.AddressHash([]byte(chanID))) +} diff --git a/x/ibc/mock/bank/internal/types/codec.go b/x/ibc/mock/bank/internal/types/codec.go new file mode 100644 index 000000000000..e0762be3f3d2 --- /dev/null +++ b/x/ibc/mock/bank/internal/types/codec.go @@ -0,0 +1,24 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + 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/23-commitment/merkle" +) + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(Packet{}, "ibcmockbank/Packet", nil) + cdc.RegisterConcrete(TransferPacketData{}, "ibcmockbank/TransferPacketData", nil) + cdc.RegisterConcrete(MsgTransfer{}, "ibcmockbank/MsgTransfer", nil) + cdc.RegisterConcrete(MsgRecvTransferPacket{}, "ibcmockbank/MsgRecvTransferPacket", nil) +} + +var MouduleCdc = codec.New() + +func init() { + RegisterCodec(MouduleCdc) + channel.RegisterCodec(MouduleCdc) + commitment.RegisterCodec(MouduleCdc) + merkle.RegisterCodec(MouduleCdc) +} diff --git a/x/ibc/mock/bank/internal/types/errors.go b/x/ibc/mock/bank/internal/types/errors.go new file mode 100644 index 000000000000..52582daccfe0 --- /dev/null +++ b/x/ibc/mock/bank/internal/types/errors.go @@ -0,0 +1,17 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// ibcmockbank errors reserve 100 ~ 199. +const ( + CodeIncorrectDenom sdk.CodeType = 101 + CodeInvalidAmount sdk.CodeType = 102 + CodeInvalidAddress sdk.CodeType = 103 + CodeInvalidReceiver sdk.CodeType = 104 + CodeErrSendPacket sdk.CodeType = 105 + CodeErrReceivePacket sdk.CodeType = 106 + CodeProofMissing sdk.CodeType = 107 + CodeInvalidPacketData sdk.CodeType = 108 +) diff --git a/x/ibc/mock/bank/internal/types/expected_keepers.go b/x/ibc/mock/bank/internal/types/expected_keepers.go new file mode 100644 index 000000000000..45156d2675b5 --- /dev/null +++ b/x/ibc/mock/bank/internal/types/expected_keepers.go @@ -0,0 +1,32 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +type BankKeeper interface { + AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) + + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error + + SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) +} + +type ChannelKeeper interface { + GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) + + GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) + + RecvPacket( + ctx sdk.Context, + packet exported.PacketI, + proof ics23.Proof, + proofHeight uint64, + acknowledgement []byte, + ) (exported.PacketI, error) + + SendPacket(ctx sdk.Context, packet exported.PacketI) error +} diff --git a/x/ibc/mock/bank/internal/types/keys.go b/x/ibc/mock/bank/internal/types/keys.go new file mode 100644 index 000000000000..a5e764dfbb72 --- /dev/null +++ b/x/ibc/mock/bank/internal/types/keys.go @@ -0,0 +1,21 @@ +package types + +const ( + // ModuleName is the name of the module + ModuleName = "ibcmockbank" + + // StoreKey is the string store representation + StoreKey = ModuleName + + // TStoreKey is the string transient store representation + TStoreKey = "transient_" + ModuleName + + // QuerierRoute is the querier route for the module + QuerierRoute = ModuleName + + // RouterKey is the msg router key for the module + RouterKey = ModuleName + + // codespace + DefaultCodespace = ModuleName +) diff --git a/x/ibc/mock/bank/internal/types/msgs.go b/x/ibc/mock/bank/internal/types/msgs.go new file mode 100644 index 000000000000..ad87c838c1b4 --- /dev/null +++ b/x/ibc/mock/bank/internal/types/msgs.go @@ -0,0 +1,105 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + ics04 "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +const ( + TypeMsgTransfer = "transfer" + TypeMsgRecvTransferPacket = "recv-transfer-packet" +) + +type MsgTransfer struct { + SrcPort string `json:"src_port" yaml:"src_port"` + SrcChannel string `json:"src_channel" yaml:"src_channel"` + Denomination string `json:"denomination" yaml:"denomination"` + Amount sdk.Int `json:"amount" yaml:"amount"` + Sender sdk.AccAddress `json:"sender" yaml:"sender"` + Receiver string `json:"receiver" yaml:"receiver"` + Source bool `json:"source" yaml:"source"` +} +type MsgRecvTransferPacket struct { + Packet ics04.PacketI `json:"packet" yaml:"packet"` + Proofs []ics23.Proof `json:"proofs" yaml:"proofs"` + Height uint64 `json:"height" yaml:"height"` + Signer sdk.AccAddress `json:"signer" yaml:"signer"` +} + +func NewMsgTransfer(srcPort, srcChannel string, denom string, amount sdk.Int, sender sdk.AccAddress, receiver string, source bool) MsgTransfer { + return MsgTransfer{ + SrcPort: srcPort, + SrcChannel: srcChannel, + Denomination: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Source: source, + } +} + +func (MsgTransfer) Route() string { + return RouterKey +} + +func (MsgTransfer) Type() string { + return TypeMsgTransfer +} + +func (msg MsgTransfer) ValidateBasic() sdk.Error { + if !msg.Amount.IsPositive() { + return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeInvalidAmount, "invalid amount") + } + + if msg.Sender.Empty() || len(msg.Receiver) == 0 { + return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeInvalidAddress, "invalid address") + } + + return nil +} + +func (msg MsgTransfer) GetSignBytes() []byte { + return sdk.MustSortJSON(MouduleCdc.MustMarshalJSON(msg)) +} + +func (msg MsgTransfer) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Sender} +} + +func NewMsgRecvTransferPacket(packet ics04.PacketI, proofs []ics23.Proof, height uint64, signer sdk.AccAddress) MsgRecvTransferPacket { + return MsgRecvTransferPacket{ + Packet: packet, + Proofs: proofs, + Height: height, + Signer: signer, + } +} + +func (MsgRecvTransferPacket) Route() string { + return RouterKey +} + +func (MsgRecvTransferPacket) Type() string { + return TypeMsgRecvTransferPacket +} + +func (msg MsgRecvTransferPacket) ValidateBasic() sdk.Error { + if msg.Proofs == nil { + return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeProofMissing, "proof missing") + } + + if msg.Signer.Empty() { + return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeInvalidAddress, "invalid signer") + } + + return nil +} + +func (msg MsgRecvTransferPacket) GetSignBytes() []byte { + return sdk.MustSortJSON(MouduleCdc.MustMarshalJSON(msg)) +} + +func (msg MsgRecvTransferPacket) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} diff --git a/x/ibc/mock/bank/internal/types/packet.go b/x/ibc/mock/bank/internal/types/packet.go new file mode 100644 index 000000000000..c1b8fdbb9e6b --- /dev/null +++ b/x/ibc/mock/bank/internal/types/packet.go @@ -0,0 +1,122 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" +) + +var _ exported.PacketI = Packet{} + +// Packet defines a type that carries data across different chains through IBC +type Packet struct { + sequence uint64 // number corresponds to the order of sends and receives, where a packet with an earlier sequence number must be sent and received before a packet with a later sequence number. + timeout uint64 // indicates a consensus height on the destination chain after which the packet will no longer be processed, and will instead count as having timed-out. + sourcePort string // identifies the port on the sending chain. + sourceChannel string // identifies the channel end on the sending chain. + destinationPort string // identifies the port on the receiving chain. + destinationChannel string // identifies the channel end on the receiving chain. + data []byte // opaque value which can be defined by the application logic of the associated modules. +} + +// newPacket creates a new Packet instance +func NewPacket( + sequence, timeout uint64, sourcePort, sourceChannel, + destinationPort, destinationChannel string, data []byte, +) Packet { + return Packet{ + sequence, + timeout, + sourcePort, + sourceChannel, + destinationPort, + destinationChannel, + data, + } +} + +// Sequence implements PacketI interface +func (p Packet) Sequence() uint64 { return p.sequence } + +// TimeoutHeight implements PacketI interface +func (p Packet) TimeoutHeight() uint64 { return p.timeout } + +// SourcePort implements PacketI interface +func (p Packet) SourcePort() string { return p.sourcePort } + +// SourceChannel implements PacketI interface +func (p Packet) SourceChannel() string { return p.sourceChannel } + +// DestPort implements PacketI interface +func (p Packet) DestPort() string { return p.destinationPort } + +// DestChannel implements PacketI interface +func (p Packet) DestChannel() string { return p.destinationChannel } + +// Data implements PacketI interface +func (p Packet) Data() []byte { return p.data } + +func (p Packet) MarshalJSON() ([]byte, error) { + return MouduleCdc.MarshalJSON(p) +} + +func (p *Packet) UnmarshalJSON(bz []byte) (err error) { + return MouduleCdc.UnmarshalJSON(bz, p) +} + +// TransferPacketData defines a struct for the packet payload +type TransferPacketData struct { + Denomination string `json:"denomination" yaml:"denomination"` + Amount sdk.Int `json:"amount" yaml:"amount"` + Sender sdk.AccAddress `json:"sender" yaml:"sender"` + Receiver string `json:"receiver" yaml:"receiver"` + Source bool `json:"source" yaml:"source"` +} + +func (tpd TransferPacketData) MarshalAmino() ([]byte, error) { + return MouduleCdc.MarshalBinaryBare(tpd) +} + +func (tpd *TransferPacketData) UnmarshalAmino(bz []byte) (err error) { + return MouduleCdc.UnmarshalBinaryBare(bz, tpd) +} + +func (tpd TransferPacketData) Marshal() []byte { + return MouduleCdc.MustMarshalBinaryBare(tpd) +} + +func (tpd TransferPacketData) MarshalJSON() ([]byte, error) { + return MouduleCdc.MarshalJSON(tpd) +} + +func (tpd *TransferPacketData) UnmarshalJSON(bz []byte) (err error) { + return MouduleCdc.UnmarshalJSON(bz, tpd) +} + +func (tpd TransferPacketData) String() string { + return fmt.Sprintf(`TransferPacketData: + Denomination %s + Amount: %s + Sender: %s + Receiver: %s + Source: %v`, + tpd.Denomination, + tpd.Amount.String(), + tpd.Sender.String(), + tpd.Receiver, + tpd.Source, + ) +} + +func (tpd TransferPacketData) Validate() error { + if !tpd.Amount.IsPositive() { + return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeInvalidAmount, "invalid amount") + } + + if tpd.Sender.Empty() || len(tpd.Receiver) == 0 { + return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeInvalidAddress, "invalid address") + } + + return nil +} diff --git a/x/ibc/mock/bank/module.go b/x/ibc/mock/bank/module.go new file mode 100644 index 000000000000..e033d1de5666 --- /dev/null +++ b/x/ibc/mock/bank/module.go @@ -0,0 +1,110 @@ +package mockbank + +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/bank/client/cli" +) + +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) { + RegisterCdc(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 nil +} + +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{} +} + +// GetTxCmd returns the root tx command for the ibc-channel module. +func GetTxCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetTxCmd(cdc) +} From 8a622017a278e7e295e6bbde1baddb315e636ec4 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Fri, 25 Oct 2019 12:31:29 -0700 Subject: [PATCH 346/378] switch ibc antehandler to decorator pattern --- x/ibc/24-host/errors.go | 3 ++ x/ibc/ante.go | 61 +++++++++++++++++++++++++ x/ibc/mock/bank/internal/types/codec.go | 2 - 3 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 x/ibc/ante.go diff --git a/x/ibc/24-host/errors.go b/x/ibc/24-host/errors.go index e1fa5e0e7a08..afc1c26ea303 100644 --- a/x/ibc/24-host/errors.go +++ b/x/ibc/24-host/errors.go @@ -13,4 +13,7 @@ var ( // ErrInvalidPath is returned if path string is invalid ErrInvalidPath = sdkerrors.Register(IBCCodeSpace, 2, "invalid path") + + // ErrInvalidPacket is returned if packets embedded in msg are invalid + ErrInvalidPacket = sdkerrors.Register(IBCCodeSpace, 3, "invalid packet extracted from msg") ) diff --git a/x/ibc/ante.go b/x/ibc/ante.go new file mode 100644 index 000000000000..ea9ee9d10bb9 --- /dev/null +++ b/x/ibc/ante.go @@ -0,0 +1,61 @@ +package ibc + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" +) + +// 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.AnteDecorator { + return func(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + msgs, abort := ExtractMsgPackets(tx.GetMsgs()) + if abort { + return ctx, host.ErrInvalidPacket + } + + // GasMeter already set by auth.AnteHandler + + err := VerifyMsgPackets(ctx, channel, msgs) + if err != nil { + return ctx, sdkerrors.Wrap(host.ErrInvalidPacket, err.Error()) + } + + return next(ctx, tx, simulate) + } +} diff --git a/x/ibc/mock/bank/internal/types/codec.go b/x/ibc/mock/bank/internal/types/codec.go index e0762be3f3d2..d20501ff5baa 100644 --- a/x/ibc/mock/bank/internal/types/codec.go +++ b/x/ibc/mock/bank/internal/types/codec.go @@ -4,7 +4,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" 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/23-commitment/merkle" ) func RegisterCodec(cdc *codec.Codec) { @@ -20,5 +19,4 @@ func init() { RegisterCodec(MouduleCdc) channel.RegisterCodec(MouduleCdc) commitment.RegisterCodec(MouduleCdc) - merkle.RegisterCodec(MouduleCdc) } From 2a6a77a7dc9d61ec0809ce83940e2cb26e9b54ff Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Fri, 25 Oct 2019 12:33:57 -0700 Subject: [PATCH 347/378] fix name/comment --- x/ibc/ante.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x/ibc/ante.go b/x/ibc/ante.go index ea9ee9d10bb9..720a76afd5b4 100644 --- a/x/ibc/ante.go +++ b/x/ibc/ante.go @@ -42,15 +42,13 @@ func VerifyMsgPackets(ctx sdk.Context, channel channel.Manager, msgs []MsgPacket return nil } -func NewAnteHandler(channel channel.Manager) sdk.AnteDecorator { +func NewAnteDecorator(channel channel.Manager) sdk.AnteDecorator { return func(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { msgs, abort := ExtractMsgPackets(tx.GetMsgs()) if abort { return ctx, host.ErrInvalidPacket } - // GasMeter already set by auth.AnteHandler - err := VerifyMsgPackets(ctx, channel, msgs) if err != nil { return ctx, sdkerrors.Wrap(host.ErrInvalidPacket, err.Error()) From f3120bf8382bb9eb804d8bb396d2934f5251fff7 Mon Sep 17 00:00:00 2001 From: vincent Date: Tue, 29 Oct 2019 22:05:28 +0800 Subject: [PATCH 348/378] ICS 20 implementation (#5250) * move ics20 code to 20-transfer * clean code * fix compiling error * add transfer module * address ICS20 comments from review * add routing callbacks * clean code * add missing err return * modify err type * modify err type * add supply handling * modify proof type * add comments for msg and packet data * add timeout supply handling * modify module account name * use supply keeper for burn and mint coins * restructure keeper * update alias and module.go * golangci linter * add ics20 handler to IBC handler * update callbacks --- simapp/app.go | 16 +- x/ibc/04-channel/types/codec.go | 1 + x/ibc/04-channel/types/events.go | 1 - x/ibc/20-transfer/alias.go | 61 ++++++ x/ibc/20-transfer/client/cli/tx.go | 70 +++++++ x/ibc/20-transfer/genesis.go | 17 ++ x/ibc/20-transfer/handler.go | 24 +++ x/ibc/20-transfer/keeper/callbacks.go | 185 ++++++++++++++++++ x/ibc/20-transfer/keeper/keeper.go | 67 +++++++ x/ibc/20-transfer/keeper/relay.go | 178 +++++++++++++++++ x/ibc/20-transfer/module.go | 18 ++ x/ibc/20-transfer/types/codec.go | 20 ++ x/ibc/20-transfer/types/errors.go | 49 +++++ x/ibc/20-transfer/types/events.go | 17 ++ x/ibc/20-transfer/types/expected_keepers.go | 42 ++++ x/ibc/20-transfer/types/keys.go | 42 ++++ x/ibc/20-transfer/types/msgs.go | 75 +++++++ x/ibc/20-transfer/types/packet.go | 70 +++++++ x/ibc/ante.go | 106 +++++----- x/ibc/client/cli/cli.go | 2 + x/ibc/handler.go | 31 +-- x/ibc/keeper/keeper.go | 9 +- x/ibc/mock/bank/alias.go | 12 +- x/ibc/mock/bank/client/cli/flags.go | 27 --- x/ibc/mock/bank/client/cli/tx.go | 57 +----- x/ibc/mock/bank/handler.go | 30 +-- x/ibc/mock/bank/internal/keeper/keeper.go | 161 ++------------- x/ibc/mock/bank/internal/types/codec.go | 13 +- x/ibc/mock/bank/internal/types/errors.go | 14 +- .../bank/internal/types/expected_keepers.go | 23 +-- x/ibc/mock/bank/internal/types/keys.go | 6 - x/ibc/mock/bank/internal/types/msgs.go | 96 +++------ x/ibc/mock/bank/internal/types/packet.go | 122 ------------ x/ibc/module.go | 4 + 34 files changed, 1100 insertions(+), 566 deletions(-) create mode 100644 x/ibc/20-transfer/alias.go create mode 100644 x/ibc/20-transfer/client/cli/tx.go create mode 100644 x/ibc/20-transfer/genesis.go create mode 100644 x/ibc/20-transfer/handler.go create mode 100644 x/ibc/20-transfer/keeper/callbacks.go create mode 100644 x/ibc/20-transfer/keeper/keeper.go create mode 100644 x/ibc/20-transfer/keeper/relay.go create mode 100644 x/ibc/20-transfer/module.go create mode 100644 x/ibc/20-transfer/types/codec.go create mode 100644 x/ibc/20-transfer/types/errors.go create mode 100644 x/ibc/20-transfer/types/events.go create mode 100644 x/ibc/20-transfer/types/expected_keepers.go create mode 100644 x/ibc/20-transfer/types/keys.go create mode 100644 x/ibc/20-transfer/types/msgs.go create mode 100644 x/ibc/20-transfer/types/packet.go delete mode 100644 x/ibc/mock/bank/client/cli/flags.go delete mode 100644 x/ibc/mock/bank/internal/types/packet.go diff --git a/simapp/app.go b/simapp/app.go index 750472533b57..347e32a687c2 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -23,6 +23,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/genutil" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/ibc" + ibctransfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/params" paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" @@ -60,12 +61,13 @@ var ( // module account permissions maccPerms = map[string][]string{ - auth.FeeCollectorName: nil, - distr.ModuleName: nil, - mint.ModuleName: {supply.Minter}, - staking.BondedPoolName: {supply.Burner, supply.Staking}, - staking.NotBondedPoolName: {supply.Burner, supply.Staking}, - gov.ModuleName: {supply.Burner}, + auth.FeeCollectorName: nil, + distr.ModuleName: nil, + mint.ModuleName: {supply.Minter}, + staking.BondedPoolName: {supply.Burner, supply.Staking}, + staking.NotBondedPoolName: {supply.Burner, supply.Staking}, + gov.ModuleName: {supply.Burner}, + ibctransfer.GetModuleAccountName(): {supply.Minter, supply.Burner}, } ) @@ -175,7 +177,7 @@ func NewSimApp( staking.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()), ) - app.IBCKeeper = ibc.NewKeeper(app.cdc, keys[ibc.StoreKey], ibc.DefaultCodespace) + app.IBCKeeper = ibc.NewKeeper(app.cdc, keys[ibc.StoreKey], ibc.DefaultCodespace, app.BankKeeper, app.SupplyKeeper) // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. diff --git a/x/ibc/04-channel/types/codec.go b/x/ibc/04-channel/types/codec.go index 4cfc1e773a1e..d3271d9c5610 100644 --- a/x/ibc/04-channel/types/codec.go +++ b/x/ibc/04-channel/types/codec.go @@ -9,6 +9,7 @@ var SubModuleCdc *codec.Codec func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*exported.PacketI)(nil), nil) + cdc.RegisterConcrete(Packet{}, "ibc/channel/Packet", nil) cdc.RegisterConcrete(OpaquePacket{}, "ibc/channel/OpaquePacket", nil) cdc.RegisterConcrete(MsgChannelOpenInit{}, "ibc/channel/MsgChannelOpenInit", nil) diff --git a/x/ibc/04-channel/types/events.go b/x/ibc/04-channel/types/events.go index 72d92cbf2237..b82b3e8700cf 100644 --- a/x/ibc/04-channel/types/events.go +++ b/x/ibc/04-channel/types/events.go @@ -12,7 +12,6 @@ const ( AttributeKeyReceiverPort = "receiver_port" AttributeKeyChannelID = "channel_id" AttributeKeySequence = "sequence" - AttributeKeyPacket = "packet" ) // IBC channel events vars diff --git a/x/ibc/20-transfer/alias.go b/x/ibc/20-transfer/alias.go new file mode 100644 index 000000000000..ba4008d57374 --- /dev/null +++ b/x/ibc/20-transfer/alias.go @@ -0,0 +1,61 @@ +package transfer + +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" +) + +const ( + DefaultPacketTimeout = keeper.DefaultPacketTimeout + DefaultCodespace = types.DefaultCodespace + CodeInvalidAddress = types.CodeInvalidAddress + CodeErrSendPacket = types.CodeErrSendPacket + CodeInvalidPacketData = types.CodeInvalidPacketData + CodeInvalidChannelOrder = types.CodeInvalidChannelOrder + CodeInvalidPort = types.CodeInvalidPort + CodeInvalidVersion = types.CodeInvalidVersion + AttributeKeyReceiver = types.AttributeKeyReceiver + SubModuleName = types.SubModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute + BoundPortID = types.BoundPortID +) + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper + RegisterCodec = types.RegisterCodec + ErrInvalidAddress = types.ErrInvalidAddress + ErrSendPacket = types.ErrSendPacket + ErrInvalidPacketData = types.ErrInvalidPacketData + ErrInvalidChannelOrder = types.ErrInvalidChannelOrder + ErrInvalidPort = types.ErrInvalidPort + ErrInvalidVersion = types.ErrInvalidVersion + GetEscrowAddress = types.GetEscrowAddress + GetDenomPrefix = types.GetDenomPrefix + GetModuleAccountName = types.GetModuleAccountName + NewMsgTransfer = types.NewMsgTransfer + + // variable aliases + ModuleCdc = types.ModuleCdc + AttributeValueCategory = types.AttributeValueCategory +) + +type ( + Keeper = keeper.Keeper + BankKeeper = types.BankKeeper + ChannelKeeper = types.ChannelKeeper + ClientKeeper = types.ClientKeeper + ConnectionKeeper = types.ConnectionKeeper + SupplyKeeper = types.SupplyKeeper + MsgTransfer = types.MsgTransfer + PacketData = types.PacketData + PacketDataAlias = types.PacketDataAlias +) diff --git a/x/ibc/20-transfer/client/cli/tx.go b/x/ibc/20-transfer/client/cli/tx.go new file mode 100644 index 000000000000..e9e12f28d4a8 --- /dev/null +++ b/x/ibc/20-transfer/client/cli/tx.go @@ -0,0 +1,70 @@ +package cli + +import ( + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "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/20-transfer/types" +) + +// IBC transfer flags +var ( + FlagSource = "source" +) + +// GetTxCmd returns the transaction commands for IBC fungible token transfer +func GetTxCmd(cdc *codec.Codec) *cobra.Command { + txCmd := &cobra.Command{ + Use: "transfer", + Short: "IBC fungible token transfer transaction subcommands", + } + txCmd.AddCommand( + GetTransferTxCmd(cdc), + ) + + return txCmd +} + +// GetTransferTxCmd returns the command to create a NewMsgTransfer transaction +func GetTransferTxCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "transfer [src-port] [src-channel] [receiver] [amount]", + Short: "Transfer fungible token through IBC", + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + ctx := context.NewCLIContext().WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) + + sender := ctx.GetFromAddress() + srcPort := args[0] + srcChannel := args[1] + receiver, err := sdk.AccAddressFromBech32(args[2]) + if err != nil { + return err + } + + // parse coin trying to be sent + coins, err := sdk.ParseCoins(args[3]) + if err != nil { + return err + } + + source := viper.GetBool(FlagSource) + + msg := types.NewMsgTransfer(srcPort, srcChannel, coins, sender, receiver, source) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return utils.GenerateOrBroadcastMsgs(ctx, txBldr, []sdk.Msg{msg}) + }, + } + cmd.Flags().Bool(FlagSource, false, "Pass flag for sending token from the source chain") + return cmd +} diff --git a/x/ibc/20-transfer/genesis.go b/x/ibc/20-transfer/genesis.go new file mode 100644 index 000000000000..facde722a27d --- /dev/null +++ b/x/ibc/20-transfer/genesis.go @@ -0,0 +1,17 @@ +package transfer + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" +) + +// InitGenesis sets distribution information for genesis +func InitGenesis(ctx sdk.Context, keeper Keeper) { + // check if the module account exists + moduleAcc := keeper.GetTransferAccount(ctx) + if moduleAcc == nil { + panic(fmt.Sprintf("%s module account has not been set", types.GetModuleAccountName())) + } +} diff --git a/x/ibc/20-transfer/handler.go b/x/ibc/20-transfer/handler.go new file mode 100644 index 000000000000..52f47fab9257 --- /dev/null +++ b/x/ibc/20-transfer/handler.go @@ -0,0 +1,24 @@ +package transfer + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" +) + +// HandleMsgTransfer defines the sdk.Handler for MsgTransfer +func HandleMsgTransfer(ctx sdk.Context, k Keeper, msg MsgTransfer) (res sdk.Result) { + err := k.SendTransfer(ctx, msg.SourcePort, msg.SourceChannel, msg.Amount, msg.Sender, msg.Receiver, msg.Source) + if err != nil { + return sdk.ResultFromError(err) + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), + sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver.String()), + )) + + return sdk.Result{Events: ctx.EventManager().Events()} +} diff --git a/x/ibc/20-transfer/keeper/callbacks.go b/x/ibc/20-transfer/keeper/callbacks.go new file mode 100644 index 000000000000..dad340f24ad2 --- /dev/null +++ b/x/ibc/20-transfer/keeper/callbacks.go @@ -0,0 +1,185 @@ +package keeper + +import ( + "fmt" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" +) + +// nolint: unused +func (k Keeper) onChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + counterparty channeltypes.Counterparty, + version string, +) error { + if order != channeltypes.UNORDERED { + return types.ErrInvalidChannelOrder(k.codespace, order.String()) + } + + if counterparty.PortID != types.BoundPortID { + return types.ErrInvalidPort(k.codespace, portID) + } + + if strings.TrimSpace(version) != "" { + return types.ErrInvalidVersion(k.codespace, fmt.Sprintf("invalid version: %s", version)) + } + + // TODO: + // channelEscrowAddresses[channelIdentifier] = newAddress() + return nil +} + +// nolint: unused +func (k Keeper) onChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + counterparty channeltypes.Counterparty, + version string, + counterpartyVersion string, +) error { + if order != channeltypes.UNORDERED { + return types.ErrInvalidChannelOrder(k.codespace, order.String()) + } + + if counterparty.PortID != types.BoundPortID { + return types.ErrInvalidPort(k.codespace, portID) + } + + if strings.TrimSpace(version) != "" { + return types.ErrInvalidVersion(k.codespace, fmt.Sprintf("invalid version: %s", version)) + } + + if strings.TrimSpace(counterpartyVersion) != "" { + return types.ErrInvalidVersion(k.codespace, fmt.Sprintf("invalid counterparty version: %s", version)) + } + + // TODO: + // channelEscrowAddresses[channelIdentifier] = newAddress() + + return nil +} + +// nolint: unused +func (k Keeper) onChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + version string, +) error { + if strings.TrimSpace(version) != "" { + return types.ErrInvalidVersion(k.codespace, fmt.Sprintf("invalid version: %s", version)) + } + + return nil +} + +// nolint: unused +func (k Keeper) onChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + // no-op + return nil +} + +// nolint: unused +func (k Keeper) onChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + // no-op + return nil +} + +// nolint: unused +func (k Keeper) onChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + // no-op + return nil +} + +// onRecvPacket is called when an FTTransfer packet is received +// nolint: unused +func (k Keeper) onRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, +) error { + var data types.PacketData + + err := data.UnmarshalJSON(packet.Data()) + if err != nil { + return types.ErrInvalidPacketData(k.codespace) + } + + return k.ReceiveTransfer( + ctx, packet.SourcePort(), packet.SourceChannel(), + packet.DestPort(), packet.DestChannel(), data, + ) +} + +// nolint: unused +func (k Keeper) onAcknowledgePacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, +) error { + // no-op + return nil +} + +// nolint: unused +func (k Keeper) onTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, +) error { + var data types.PacketData + + err := data.UnmarshalJSON(packet.Data()) + if err != nil { + return types.ErrInvalidPacketData(k.codespace) + } + + // check the denom prefix + prefix := types.GetDenomPrefix(packet.SourcePort(), packet.SourcePort()) + coins := make(sdk.Coins, len(data.Amount)) + for i, coin := range data.Amount { + coin := coin + if !strings.HasPrefix(coin.Denom, prefix) { + return sdk.ErrInvalidCoins(fmt.Sprintf("%s doesn't contain the prefix '%s'", coin.Denom, prefix)) + } + coins[i] = sdk.NewCoin(coin.Denom[len(prefix):], coin.Amount) + } + + if data.Source { + escrowAddress := types.GetEscrowAddress(packet.DestChannel()) + return k.bankKeeper.SendCoins(ctx, escrowAddress, data.Sender, coins) + } + + // mint from supply + err = k.supplyKeeper.MintCoins(ctx, types.GetModuleAccountName(), data.Amount) + if err != nil { + return err + } + + return k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.GetModuleAccountName(), data.Sender, data.Amount) +} + +// nolint: unused +func (k Keeper) onTimeoutPacketClose(_ sdk.Context, _ channeltypes.Packet) { + panic("can't happen, only unordered channels allowed") +} diff --git a/x/ibc/20-transfer/keeper/keeper.go b/x/ibc/20-transfer/keeper/keeper.go new file mode 100644 index 000000000000..87ce6b543af6 --- /dev/null +++ b/x/ibc/20-transfer/keeper/keeper.go @@ -0,0 +1,67 @@ +package keeper + +import ( + "fmt" + + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" + supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" +) + +// DefaultPacketTimeout is the default packet timeout relative to the current block height +const ( + DefaultPacketTimeout = 1000 // NOTE: in blocks +) + +// Keeper defines the IBC transfer keeper +type Keeper struct { + storeKey sdk.StoreKey + cdc *codec.Codec + codespace sdk.CodespaceType + prefix []byte // prefix bytes for accessing the store + + clientKeeper types.ClientKeeper + connectionKeeper types.ConnectionKeeper + channelKeeper types.ChannelKeeper + bankKeeper types.BankKeeper + supplyKeeper types.SupplyKeeper +} + +// NewKeeper creates a new IBC transfer Keeper instance +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType, + clientk types.ClientKeeper, connk types.ConnectionKeeper, + chank types.ChannelKeeper, bk types.BankKeeper, + sk types.SupplyKeeper, +) Keeper { + + // ensure ibc transfer module account is set + if addr := sk.GetModuleAddress(types.GetModuleAccountName()); addr == nil { + panic("the IBC transfer module account has not been set") + } + + return Keeper{ + storeKey: key, + cdc: cdc, + codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/transfer", + prefix: []byte(types.SubModuleName + "/"), // "transfer/" + clientKeeper: clientk, + connectionKeeper: connk, + channelKeeper: chank, + bankKeeper: bk, + supplyKeeper: sk, + } +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName)) +} + +// GetTransferAccount returns the ICS20 - transfers ModuleAccount +func (k Keeper) GetTransferAccount(ctx sdk.Context) supplyexported.ModuleAccountI { + return k.supplyKeeper.GetModuleAccount(ctx, types.GetModuleAccountName()) +} diff --git a/x/ibc/20-transfer/keeper/relay.go b/x/ibc/20-transfer/keeper/relay.go new file mode 100644 index 000000000000..b13f34f3ca8c --- /dev/null +++ b/x/ibc/20-transfer/keeper/relay.go @@ -0,0 +1,178 @@ +package keeper + +import ( + "fmt" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" +) + +// SendTransfer handles transfer sending logic +func (k Keeper) SendTransfer( + ctx sdk.Context, + sourcePort, + sourceChannel string, + amount sdk.Coins, + sender, + receiver sdk.AccAddress, + isSourceChain bool, +) error { + // get the port and channel of the counterparty + channel, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel) + if !found { + return channeltypes.ErrChannelNotFound(k.codespace, sourceChannel) + } + + destinationPort := channel.Counterparty.PortID + destinationChannel := channel.Counterparty.ChannelID + + // get the next sequence + sequence, found := k.channelKeeper.GetNextSequenceSend(ctx, sourcePort, sourceChannel) + if !found { + return channeltypes.ErrSequenceNotFound(k.codespace, "send") + } + + coins := make(sdk.Coins, len(amount)) + prefix := types.GetDenomPrefix(destinationPort, destinationChannel) + switch { + case isSourceChain: + // build the receiving denomination prefix + for i, coin := range amount { + coin := coin + coins[i] = sdk.NewCoin(prefix+coin.Denom, coin.Amount) + } + default: + coins = amount + } + + return k.createOutgoingPacket(ctx, sequence, sourcePort, sourceChannel, destinationPort, destinationChannel, coins, sender, receiver, isSourceChain) +} + +// ReceiveTransfer handles transfer receiving logic +func (k Keeper) ReceiveTransfer( + ctx sdk.Context, + sourcePort, + sourceChannel, + destinationPort, + destinationChannel string, + data types.PacketData, +) error { + if data.Source { + prefix := types.GetDenomPrefix(destinationPort, destinationChannel) + for _, coin := range data.Amount { + coin := coin + if !strings.HasPrefix(coin.Denom, prefix) { + return sdk.ErrInvalidCoins(fmt.Sprintf("%s doesn't contain the prefix '%s'", coin.Denom, prefix)) + } + } + + // mint new tokens if the source of the transfer is the same chain + err := k.supplyKeeper.MintCoins(ctx, types.GetModuleAccountName(), data.Amount) + if err != nil { + return err + } + + // send to receiver + return k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.GetModuleAccountName(), data.Receiver, data.Amount) + } + + // unescrow tokens + + // check the denom prefix + prefix := types.GetDenomPrefix(sourcePort, sourceChannel) + coins := make(sdk.Coins, len(data.Amount)) + for i, coin := range data.Amount { + coin := coin + if !strings.HasPrefix(coin.Denom, prefix) { + return sdk.ErrInvalidCoins(fmt.Sprintf("%s doesn't contain the prefix '%s'", coin.Denom, prefix)) + } + coins[i] = sdk.NewCoin(coin.Denom[len(prefix):], coin.Amount) + } + + escrowAddress := types.GetEscrowAddress(destinationChannel) + return k.bankKeeper.SendCoins(ctx, escrowAddress, data.Receiver, coins) + +} + +func (k Keeper) createOutgoingPacket( + ctx sdk.Context, + seq uint64, + sourcePort, + sourceChannel, + destinationPort, + destinationChannel string, + amount sdk.Coins, + sender sdk.AccAddress, + receiver sdk.AccAddress, + isSourceChain bool, +) error { + if isSourceChain { + // escrow tokens if the destination chain is the same as the sender's + escrowAddress := types.GetEscrowAddress(sourceChannel) + + prefix := types.GetDenomPrefix(destinationPort, destinationChannel) + coins := make(sdk.Coins, len(amount)) + for i, coin := range amount { + coin := coin + if !strings.HasPrefix(coin.Denom, prefix) { + return sdk.ErrInvalidCoins(fmt.Sprintf("%s doesn't contain the prefix '%s'", coin.Denom, prefix)) + } + coins[i] = sdk.NewCoin(coin.Denom[len(prefix):], coin.Amount) + } + + err := k.bankKeeper.SendCoins(ctx, sender, escrowAddress, coins) + if err != nil { + return err + } + + } else { + // burn vouchers from the sender's balance if the source is from another chain + prefix := types.GetDenomPrefix(sourcePort, sourceChannel) + for _, coin := range amount { + coin := coin + if !strings.HasPrefix(coin.Denom, prefix) { + return sdk.ErrInvalidCoins(fmt.Sprintf("%s doesn't contain the prefix '%s'", coin.Denom, prefix)) + } + } + + // transfer the coins to the module account and burn them + err := k.supplyKeeper.SendCoinsFromAccountToModule(ctx, sender, types.GetModuleAccountName(), amount) + if err != nil { + return err + } + + // burn from supply + err = k.supplyKeeper.BurnCoins(ctx, types.GetModuleAccountName(), amount) + if err != nil { + return err + } + } + + packetData := types.PacketData{ + Amount: amount, + Sender: sender, + Receiver: receiver, + Source: isSourceChain, + } + + packetDataBz, err := packetData.MarshalJSON() + if err != nil { + return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeInvalidPacketData, "invalid packet data") + } + + packet := channeltypes.NewPacket( + seq, + uint64(ctx.BlockHeight())+DefaultPacketTimeout, + sourcePort, + sourceChannel, + destinationPort, + destinationChannel, + packetDataBz, + ) + + // generate the capability key + key := sdk.NewKVStoreKey(types.BoundPortID) + return k.channelKeeper.SendPacket(ctx, packet, key) +} diff --git a/x/ibc/20-transfer/module.go b/x/ibc/20-transfer/module.go new file mode 100644 index 000000000000..269be2377f6e --- /dev/null +++ b/x/ibc/20-transfer/module.go @@ -0,0 +1,18 @@ +package transfer + +import ( + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/client/cli" +) + +// Name returns the IBC transfer ICS name +func Name() string { + return SubModuleName +} + +// GetTxCmd returns the root tx command for the IBC transfer. +func GetTxCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetTxCmd(cdc) +} diff --git a/x/ibc/20-transfer/types/codec.go b/x/ibc/20-transfer/types/codec.go new file mode 100644 index 000000000000..061c96e9d32a --- /dev/null +++ b/x/ibc/20-transfer/types/codec.go @@ -0,0 +1,20 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(MsgTransfer{}, "ibc/transfer/MsgTransfer", nil) + cdc.RegisterConcrete(PacketData{}, "ibc/transfer/PacketData", nil) +} + +var ModuleCdc = codec.New() + +func init() { + RegisterCodec(ModuleCdc) + channel.RegisterCodec(ModuleCdc) + commitment.RegisterCodec(ModuleCdc) +} diff --git a/x/ibc/20-transfer/types/errors.go b/x/ibc/20-transfer/types/errors.go new file mode 100644 index 000000000000..090804150095 --- /dev/null +++ b/x/ibc/20-transfer/types/errors.go @@ -0,0 +1,49 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// transfer error codes +const ( + DefaultCodespace sdk.CodespaceType = SubModuleName + + CodeInvalidAddress sdk.CodeType = 101 + CodeErrSendPacket sdk.CodeType = 102 + CodeInvalidPacketData sdk.CodeType = 103 + CodeInvalidChannelOrder sdk.CodeType = 104 + CodeInvalidPort sdk.CodeType = 105 + CodeInvalidVersion sdk.CodeType = 106 +) + +// ErrInvalidAddress implements sdk.Error +func ErrInvalidAddress(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidAddress, msg) +} + +// ErrSendPacket implements sdk.Error +func ErrSendPacket(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeErrSendPacket, "failed to send packet") +} + +// ErrInvalidPacketData implements sdk.Error +func ErrInvalidPacketData(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidPacketData, "invalid packet data") +} + +// ErrInvalidChannelOrder implements sdk.Error +func ErrInvalidChannelOrder(codespace sdk.CodespaceType, order string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidChannelOrder, fmt.Sprintf("invalid channel order: %s", order)) +} + +// ErrInvalidPort implements sdk.Error +func ErrInvalidPort(codespace sdk.CodespaceType, portID string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidPort, fmt.Sprintf("invalid port ID: %s", portID)) +} + +// ErrInvalidVersion implements sdk.Error +func ErrInvalidVersion(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidVersion, msg) +} diff --git a/x/ibc/20-transfer/types/events.go b/x/ibc/20-transfer/types/events.go new file mode 100644 index 000000000000..759548ae1827 --- /dev/null +++ b/x/ibc/20-transfer/types/events.go @@ -0,0 +1,17 @@ +package types + +import ( + "fmt" + + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// IBC transfer events +const ( + AttributeKeyReceiver = "receiver" +) + +// IBC transfer events vars +var ( + AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, SubModuleName) +) diff --git a/x/ibc/20-transfer/types/expected_keepers.go b/x/ibc/20-transfer/types/expected_keepers.go new file mode 100644 index 000000000000..2e855dfd8079 --- /dev/null +++ b/x/ibc/20-transfer/types/expected_keepers.go @@ -0,0 +1,42 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" +) + +// BankKeeper defines the expected bank keeper +type BankKeeper interface { + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error +} + +// ChannelKeeper defines the expected IBC channel keeper +type ChannelKeeper interface { + GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channel.Channel, found bool) + GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) + SendPacket(ctx sdk.Context, packet channelexported.PacketI, portCapability sdk.CapabilityKey) error +} + +// ClientKeeper defines the expected IBC client keeper +type ClientKeeper interface { + GetConsensusState(ctx sdk.Context, clientID string) (connection clientexported.ConsensusState, found bool) +} + +// ConnectionKeeper defines the expected IBC connection keeper +type ConnectionKeeper interface { + GetConnection(ctx sdk.Context, connectionID string) (connection connection.ConnectionEnd, found bool) +} + +// SupplyKeeper expected supply keeper +type SupplyKeeper interface { + GetModuleAddress(name string) sdk.AccAddress + GetModuleAccount(ctx sdk.Context, name string) supplyexported.ModuleAccountI + MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) sdk.Error + BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) sdk.Error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error +} diff --git a/x/ibc/20-transfer/types/keys.go b/x/ibc/20-transfer/types/keys.go new file mode 100644 index 000000000000..177982bd169c --- /dev/null +++ b/x/ibc/20-transfer/types/keys.go @@ -0,0 +1,42 @@ +package types + +import ( + "fmt" + + "github.com/tendermint/tendermint/crypto" + + sdk "github.com/cosmos/cosmos-sdk/types" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +const ( + // SubModuleName defines the IBC transfer name + SubModuleName = "transfer" + + // StoreKey is the store key string for IBC transfer + StoreKey = SubModuleName + + // RouterKey is the message route for IBC transfer + RouterKey = SubModuleName + + // QuerierRoute is the querier route for IBC transfer + QuerierRoute = SubModuleName + + // BoundPortID defines the name of the capability key + BoundPortID = "bank" +) + +// GetEscrowAddress returns the escrow address for the specified channel +func GetEscrowAddress(chanID string) sdk.AccAddress { + return sdk.AccAddress(crypto.AddressHash([]byte(chanID))) +} + +// GetDenomPrefix returns the receiving denomination prefix +func GetDenomPrefix(portID, channelID string) string { + return fmt.Sprintf("%s/%s", portID, channelID) +} + +// GetModuleAccountName returns the IBC transfer module account name for supply +func GetModuleAccountName() string { + return fmt.Sprintf("%s/%s", ibctypes.ModuleName, SubModuleName) +} diff --git a/x/ibc/20-transfer/types/msgs.go b/x/ibc/20-transfer/types/msgs.go new file mode 100644 index 000000000000..e2d4a725b6d1 --- /dev/null +++ b/x/ibc/20-transfer/types/msgs.go @@ -0,0 +1,75 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +type MsgTransfer struct { + SourcePort string `json:"source_port" yaml:"source_port"` // the port on which the packet will be sent + SourceChannel string `json:"source_channel" yaml:"source_channel"` // the channel by which the packet will be sent + Amount sdk.Coins `json:"amount" yaml:"amount"` // the tokens to be transferred + Sender sdk.AccAddress `json:"sender" yaml:"sender"` // the sender address + Receiver sdk.AccAddress `json:"receiver" yaml:"receiver"` // the recipient address on the destination chain + Source bool `json:"source" yaml:"source"` // indicates if the sending chain is the source chain of the tokens to be transferred +} + +// NewMsgTransfer creates a new MsgTransfer instance +func NewMsgTransfer( + sourcePort, sourceChannel string, amount sdk.Coins, sender, receiver sdk.AccAddress, source bool, +) MsgTransfer { + return MsgTransfer{ + SourcePort: sourcePort, + SourceChannel: sourceChannel, + Amount: amount, + Sender: sender, + Receiver: receiver, + Source: source, + } +} + +// Route implements sdk.Msg +func (MsgTransfer) Route() string { + return ibctypes.RouterKey +} + +// Type implements sdk.Msg +func (MsgTransfer) Type() string { + return "transfer" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgTransfer) ValidateBasic() sdk.Error { + if err := host.DefaultIdentifierValidator(msg.SourcePort); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) + } + if err := host.DefaultIdentifierValidator(msg.SourceChannel); err != nil { + return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) + } + if !msg.Amount.IsValid() { + return sdk.ErrInvalidCoins("transfer amount is invalid") + } + if !msg.Amount.IsAllPositive() { + return sdk.ErrInsufficientCoins("transfer amount must be positive") + } + if msg.Sender.Empty() { + return sdk.ErrInvalidAddress("missing sender address") + } + if msg.Receiver.Empty() { + return sdk.ErrInvalidAddress("missing recipient address") + } + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg MsgTransfer) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgTransfer) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Sender} +} diff --git a/x/ibc/20-transfer/types/packet.go b/x/ibc/20-transfer/types/packet.go new file mode 100644 index 000000000000..a9df673cc19f --- /dev/null +++ b/x/ibc/20-transfer/types/packet.go @@ -0,0 +1,70 @@ +package types + +import ( + "encoding/json" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// PacketData defines a struct for the packet payload +type PacketData struct { + Amount sdk.Coins `json:"amount" yaml:"amount"` // the tokens to be transferred + Sender sdk.AccAddress `json:"sender" yaml:"sender"` // the sender address + Receiver sdk.AccAddress `json:"receiver" yaml:"receiver"` // the recipient address on the destination chain + Source bool `json:"source" yaml:"source"` // indicates if the sending chain is the source chain of the tokens to be transferred +} + +func (pd PacketData) MarshalAmino() ([]byte, error) { + return ModuleCdc.MarshalBinaryBare(pd) +} + +func (pd *PacketData) UnmarshalAmino(bz []byte) (err error) { + return ModuleCdc.UnmarshalBinaryBare(bz, pd) +} + +func (pd PacketData) Marshal() []byte { + return ModuleCdc.MustMarshalBinaryBare(pd) +} + +type PacketDataAlias PacketData + +// MarshalJSON implements the json.Marshaler interface. +func (pd PacketData) MarshalJSON() ([]byte, error) { + return json.Marshal((PacketDataAlias)(pd)) +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (pd *PacketData) UnmarshalJSON(bz []byte) (err error) { + return json.Unmarshal(bz, (*PacketDataAlias)(pd)) +} + +func (pd PacketData) String() string { + return fmt.Sprintf(`PacketData: + Amount: %s + Sender: %s + Receiver: %s + Source: %v`, + pd.Amount.String(), + pd.Sender, + pd.Receiver, + pd.Source, + ) +} + +// ValidateBasic performs a basic check of the packet fields +func (pd PacketData) ValidateBasic() sdk.Error { + if !pd.Amount.IsValid() { + return sdk.ErrInvalidCoins("transfer amount is invalid") + } + if !pd.Amount.IsAllPositive() { + return sdk.ErrInsufficientCoins("transfer amount must be positive") + } + if pd.Sender.Empty() { + return sdk.ErrInvalidAddress("missing sender address") + } + if pd.Receiver.Empty() { + return sdk.ErrInvalidAddress("missing recipient address") + } + return nil +} diff --git a/x/ibc/ante.go b/x/ibc/ante.go index 720a76afd5b4..0e1f7f635d70 100644 --- a/x/ibc/ante.go +++ b/x/ibc/ante.go @@ -1,59 +1,51 @@ package ibc -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" -) - -// 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 NewAnteDecorator(channel channel.Manager) sdk.AnteDecorator { - return func(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - msgs, abort := ExtractMsgPackets(tx.GetMsgs()) - if abort { - return ctx, host.ErrInvalidPacket - } - - err := VerifyMsgPackets(ctx, channel, msgs) - if err != nil { - return ctx, sdkerrors.Wrap(host.ErrInvalidPacket, err.Error()) - } - - return next(ctx, tx, simulate) - } -} +// // 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 NewAnteDecorator(channel channel.Manager) sdk.AnteDecorator { +// return func(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { +// msgs, abort := ExtractMsgPackets(tx.GetMsgs()) +// if abort { +// return ctx, host.ErrInvalidPacket +// } + +// err := VerifyMsgPackets(ctx, channel, msgs) +// if err != nil { +// return ctx, sdkerrors.Wrap(host.ErrInvalidPacket, err.Error()) +// } + +// return next(ctx, tx, simulate) +// } +// } diff --git a/x/ibc/client/cli/cli.go b/x/ibc/client/cli/cli.go index e6163dfc7d57..5e58be761800 100644 --- a/x/ibc/client/cli/cli.go +++ b/x/ibc/client/cli/cli.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" mockbank "github.com/cosmos/cosmos-sdk/x/ibc/mock/bank" "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -24,6 +25,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ibcTxCmd.AddCommand( ibcclient.GetTxCmd(cdc, storeKey), connection.GetTxCmd(cdc, storeKey), + transfer.GetTxCmd(cdc), mockbank.GetTxCmd(cdc), ) return ibcTxCmd diff --git a/x/ibc/handler.go b/x/ibc/handler.go index d3f700a4d970..3e432e57e2c5 100644 --- a/x/ibc/handler.go +++ b/x/ibc/handler.go @@ -6,6 +6,7 @@ import ( 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" + transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" ) // NewHandler defines the IBC handler @@ -37,24 +38,28 @@ func NewHandler(k Keeper) sdk.Handler { case connection.MsgConnectionOpenConfirm: return connection.HandleMsgConnectionOpenConfirm(ctx, k.ConnectionKeeper, msg) - // // IBC channel msgs - // case channel.MsgChannelOpenInit: - // return channel.HandleMsgChannelOpenInit(ctx, k.ChannelKeeper, msg) + // // IBC channel msgs + // case channel.MsgChannelOpenInit: + // return channel.HandleMsgChannelOpenInit(ctx, k.ChannelKeeper, msg) - // case channel.MsgChannelOpenTry: - // return channel.HandleMsgChannelOpenTry(ctx, k.ChannelKeeper, msg) + // case channel.MsgChannelOpenTry: + // return channel.HandleMsgChannelOpenTry(ctx, k.ChannelKeeper, msg) - // case channel.MsgChannelOpenAck: - // return channel.HandleMsgChannelOpenAck(ctx, k.ChannelKeeper, msg) + // case channel.MsgChannelOpenAck: + // return channel.HandleMsgChannelOpenAck(ctx, k.ChannelKeeper, msg) - // case channel.MsgChannelOpenConfirm: - // return channel.HandleMsgChannelOpenConfirm(ctx, k.ChannelKeeper, msg) + // case channel.MsgChannelOpenConfirm: + // return channel.HandleMsgChannelOpenConfirm(ctx, k.ChannelKeeper, msg) - // case channel.MsgChannelCloseInit: - // return channel.HandleMsgChannelCloseInit(ctx, k.ChannelKeeper, msg) + // case channel.MsgChannelCloseInit: + // return channel.HandleMsgChannelCloseInit(ctx, k.ChannelKeeper, msg) - // case channel.MsgChannelCloseConfirm: - // return channel.HandleMsgChannelCloseConfirm(ctx, k.ChannelKeeper, msg) + // case channel.MsgChannelCloseConfirm: + // return channel.HandleMsgChannelCloseConfirm(ctx, k.ChannelKeeper, msg) + + // IBC transfer msgs + case transfer.MsgTransfer: + return transfer.HandleMsgTransfer(ctx, k.TransferKeeper, msg) default: errMsg := fmt.Sprintf("unrecognized IBC message type: %T", msg) diff --git a/x/ibc/keeper/keeper.go b/x/ibc/keeper/keeper.go index 52158b48b140..2145416efb55 100644 --- a/x/ibc/keeper/keeper.go +++ b/x/ibc/keeper/keeper.go @@ -7,6 +7,7 @@ import ( connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" port "github.com/cosmos/cosmos-sdk/x/ibc/05-port" + transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" ) // Keeper defines each ICS keeper for IBC @@ -15,19 +16,25 @@ type Keeper struct { ConnectionKeeper connection.Keeper ChannelKeeper channel.Keeper PortKeeper port.Keeper + TransferKeeper transfer.Keeper } // NewKeeper creates a new ibc Keeper -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) Keeper { +func NewKeeper( + cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType, + bk transfer.BankKeeper, sk transfer.SupplyKeeper, +) Keeper { clientKeeper := client.NewKeeper(cdc, key, codespace) connectionKeeper := connection.NewKeeper(cdc, key, codespace, clientKeeper) portKeeper := port.NewKeeper(cdc, key, codespace) channelKeeper := channel.NewKeeper(cdc, key, codespace, clientKeeper, connectionKeeper, portKeeper) + transferKeeper := transfer.NewKeeper(cdc, key, codespace, clientKeeper, connectionKeeper, channelKeeper, bk, sk) return Keeper{ ClientKeeper: clientKeeper, ConnectionKeeper: connectionKeeper, ChannelKeeper: channelKeeper, PortKeeper: portKeeper, + TransferKeeper: transferKeeper, } } diff --git a/x/ibc/mock/bank/alias.go b/x/ibc/mock/bank/alias.go index 230489e7099c..7447068ba7e7 100644 --- a/x/ibc/mock/bank/alias.go +++ b/x/ibc/mock/bank/alias.go @@ -5,17 +5,14 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/mock/bank/internal/types" ) -// nolint type ( - MsgTransfer = types.MsgTransfer - MsgRecvTransferPacket = types.MsgRecvTransferPacket - Keeper = keeper.Keeper + MsgRecvPacket = types.MsgRecvPacket + Keeper = keeper.Keeper ) const ( ModuleName = types.ModuleName StoreKey = types.StoreKey - TStoreKey = types.TStoreKey QuerierRoute = types.QuerierRoute RouterKey = types.RouterKey ) @@ -24,7 +21,6 @@ const ( var ( RegisterCdc = types.RegisterCodec - NewKeeper = keeper.NewKeeper - NewMsgTransfer = types.NewMsgTransfer - NewMsgRecvTransferPacket = types.NewMsgRecvTransferPacket + NewKeeper = keeper.NewKeeper + NewMsgRecvPacket = types.NewMsgRecvPacket ) diff --git a/x/ibc/mock/bank/client/cli/flags.go b/x/ibc/mock/bank/client/cli/flags.go deleted file mode 100644 index 24218867aa86..000000000000 --- a/x/ibc/mock/bank/client/cli/flags.go +++ /dev/null @@ -1,27 +0,0 @@ -package cli - -import ( - flag "github.com/spf13/pflag" -) - -const ( - FlagSrcPort = "src-port" - FlagSrcChannel = "src-channel" - FlagDenom = "denom" - FlagAmount = "amount" - FlagReceiver = "receiver" - FlagSource = "source" -) - -var ( - FsTransfer = flag.NewFlagSet("", flag.ContinueOnError) -) - -func init() { - FsTransfer.String(FlagSrcPort, "", "the source port ID") - FsTransfer.String(FlagSrcChannel, "", "the source channel ID") - FsTransfer.String(FlagDenom, "", "the denomination of the token to be transferred") - FsTransfer.String(FlagAmount, "", "the amount of the token to be transferred") - FsTransfer.String(FlagReceiver, "", "the recipient") - FsTransfer.Bool(FlagSource, true, "indicate if the sending chain is the source chain of the token") -} diff --git a/x/ibc/mock/bank/client/cli/tx.go b/x/ibc/mock/bank/client/cli/tx.go index a7d96935a0ff..4bb1fb2fc7d3 100644 --- a/x/ibc/mock/bank/client/cli/tx.go +++ b/x/ibc/mock/bank/client/cli/tx.go @@ -13,68 +13,24 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/client/utils" - ics23 "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" "github.com/cosmos/cosmos-sdk/x/ibc/mock/bank/internal/types" "github.com/spf13/cobra" - "github.com/spf13/viper" ) func GetTxCmd(cdc *codec.Codec) *cobra.Command { txCmd := &cobra.Command{ Use: "ibcmockbank", Short: "IBC mockbank module transaction subcommands", - // RunE: client.ValidateCmd, } txCmd.AddCommand( - GetTransferTxCmd(cdc), GetMsgRecvPacketCmd(cdc), ) return txCmd } -func GetTransferTxCmd(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "transfer --src-port --src-channel --denom --amount --receiver --source ", - Short: "Transfer tokens across chains through IBC", - RunE: func(cmd *cobra.Command, args []string) error { - txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - ctx := context.NewCLIContext().WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) - - sender := ctx.GetFromAddress() - receiver := viper.GetString(FlagReceiver) - denom := viper.GetString(FlagDenom) - srcPort := viper.GetString(FlagSrcPort) - srcChan := viper.GetString(FlagSrcChannel) - source := viper.GetBool(FlagSource) - - amount, ok := sdk.NewIntFromString(viper.GetString(FlagAmount)) - if !ok { - return fmt.Errorf("invalid amount") - } - - msg := types.NewMsgTransfer(srcPort, srcChan, denom, amount, sender, receiver, source) - if err := msg.ValidateBasic(); err != nil { - return err - } - - return utils.GenerateOrBroadcastMsgs(ctx, txBldr, []sdk.Msg{msg}) - }, - } - - cmd.Flags().AddFlagSet(FsTransfer) - - cmd.MarkFlagRequired(FlagSrcPort) - cmd.MarkFlagRequired(FlagSrcChannel) - cmd.MarkFlagRequired(FlagDenom) - cmd.MarkFlagRequired(FlagAmount) - cmd.MarkFlagRequired(FlagReceiver) - - cmd = client.PostCommands(cmd)[0] - - return cmd -} - // GetMsgRecvPacketCmd returns the command to create a MsgRecvTransferPacket transaction func GetMsgRecvPacketCmd(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ @@ -85,19 +41,20 @@ func GetMsgRecvPacketCmd(cdc *codec.Codec) *cobra.Command { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) - var packet types.Packet + var packet channel.Packet if err := cdc.UnmarshalJSON([]byte(args[0]), &packet); err != nil { fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...\n") contents, err := ioutil.ReadFile(args[0]) if err != nil { return fmt.Errorf("error opening packet file: %v", err) } - if err := packet.UnmarshalJSON(contents); err != nil { + + if err := cdc.UnmarshalJSON(contents, packet); err != nil { return fmt.Errorf("error unmarshalling packet file: %v", err) } } - var proof ics23.Proof + var proof commitment.Proof if err := cdc.UnmarshalJSON([]byte(args[1]), &proof); err != nil { fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...\n") contents, err := ioutil.ReadFile(args[1]) @@ -114,7 +71,7 @@ func GetMsgRecvPacketCmd(cdc *codec.Codec) *cobra.Command { return fmt.Errorf("error height: %v", err) } - msg := types.NewMsgRecvTransferPacket(packet, []ics23.Proof{proof}, height, cliCtx.GetFromAddress()) + msg := types.NewMsgRecvPacket(packet, []commitment.Proof{proof}, height, cliCtx.GetFromAddress()) if err := msg.ValidateBasic(); err != nil { return err } diff --git a/x/ibc/mock/bank/handler.go b/x/ibc/mock/bank/handler.go index efe2bf9f5f8b..2ed32c4c837e 100644 --- a/x/ibc/mock/bank/handler.go +++ b/x/ibc/mock/bank/handler.go @@ -2,42 +2,24 @@ package mockbank import ( sdk "github.com/cosmos/cosmos-sdk/types" - ics04 "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ) func NewHandler(k Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { - case MsgTransfer: - return handleMsgTransfer(ctx, k, msg) - case MsgRecvTransferPacket: - return handleMsgRecvTransferPacket(ctx, k, msg) + case MsgRecvPacket: + return handleMsgRecvPacket(ctx, k, msg) default: return sdk.ErrUnknownRequest("failed to parse message").Result() } } } -func handleMsgTransfer(ctx sdk.Context, k Keeper, msg MsgTransfer) (res sdk.Result) { - err := k.SendTransfer(ctx, msg.SrcPort, msg.SrcChannel, msg.Denomination, msg.Amount, msg.Sender, msg.Receiver, msg.Source) +// handleMsgRecvPacket defines the sdk.Handler for MsgRecvPacket +func handleMsgRecvPacket(ctx sdk.Context, k Keeper, msg MsgRecvPacket) (res sdk.Result) { + err := k.ReceivePacket(ctx, msg.Packet, msg.Proofs[0], msg.Height) if err != nil { - return err.Result() - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, ics04.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), - )) - - return sdk.Result{Events: ctx.EventManager().Events()} -} - -func handleMsgRecvTransferPacket(ctx sdk.Context, k Keeper, msg MsgRecvTransferPacket) (res sdk.Result) { - err := k.ReceiveTransfer(ctx, msg.Packet, msg.Proofs[0], msg.Height) - if err != nil { - return err.Result() + return sdk.ResultFromError(err) } return sdk.Result{Events: ctx.EventManager().Events()} diff --git a/x/ibc/mock/bank/internal/keeper/keeper.go b/x/ibc/mock/bank/internal/keeper/keeper.go index ceb4ae71fbae..bdcabcf53e94 100644 --- a/x/ibc/mock/bank/internal/keeper/keeper.go +++ b/x/ibc/mock/bank/internal/keeper/keeper.go @@ -1,30 +1,22 @@ package keeper import ( - "fmt" - "strings" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - ics04 "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/mock/bank/internal/types" - "github.com/tendermint/tendermint/crypto" -) - -const ( - DefaultPacketTimeout = 1000 // default packet timeout relative to the current block height ) type Keeper struct { cdc *codec.Codec key sdk.StoreKey ck types.ChannelKeeper - bk types.BankKeeper + bk types.IbcBankKeeper } -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ck types.ChannelKeeper, bk types.BankKeeper) Keeper { +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ck types.ChannelKeeper, bk types.IbcBankKeeper) Keeper { return Keeper{ cdc: cdc, key: key, @@ -33,149 +25,20 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ck types.ChannelKeeper, bk ty } } -// SendTransfer handles transfer sending logic -func (k Keeper) SendTransfer(ctx sdk.Context, srcPort, srcChan string, denom string, amount sdk.Int, sender sdk.AccAddress, receiver string, source bool) sdk.Error { - // get the port and channel of the counterparty - channel, ok := k.ck.GetChannel(ctx, srcPort, srcChan) - if !ok { - return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), ics04.CodeChannelNotFound, "failed to get channel") - } - - dstPort := channel.Counterparty.PortID - dstChan := channel.Counterparty.ChannelID - - // get the next sequence - sequence, ok := k.ck.GetNextSequenceSend(ctx, srcPort, srcChan) - if !ok { - return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), ics04.CodeSequenceNotFound, "failed to retrieve sequence") - } - - if source { - // build the receiving denomination prefix - prefix := fmt.Sprintf("%s/%s", dstPort, dstChan) - denom = prefix + denom - } - - return k.createOutgoingPacket(ctx, sequence, srcPort, srcChan, dstPort, dstChan, denom, amount, sender, receiver, source) -} - -// ReceiveTransfer handles transfer receiving logic -func (k Keeper) ReceiveTransfer(ctx sdk.Context, packet exported.PacketI, proof ics23.Proof, height uint64) sdk.Error { - _, err := k.ck.RecvPacket(ctx, packet, proof, height, nil) +// ReceivePacket handles receiving packet +func (k Keeper) ReceivePacket(ctx sdk.Context, packet channelexported.PacketI, proof commitment.ProofI, height uint64) error { + _, err := k.ck.RecvPacket(ctx, packet, proof, height, nil, k.key) if err != nil { return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeErrReceivePacket, "failed to receive packet") } - var data types.TransferPacketData + // only process ICS20 token transfer packet data now, + // that should be done in routing module. + var data transfer.PacketData err = data.UnmarshalJSON(packet.Data()) if err != nil { return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeInvalidPacketData, "invalid packet data") } - receiverAddr, err := sdk.AccAddressFromBech32(data.Receiver) - if err != nil { - return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeInvalidReceiver, "invalid receiver address") - } - - if data.Source { - // mint tokens - - // check the denom prefix - prefix := fmt.Sprintf("%s/%s", packet.DestPort(), packet.DestChannel()) - if !strings.HasPrefix(data.Denomination, prefix) { - return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeIncorrectDenom, "incorrect denomination") - } - - _, err := k.bk.AddCoins(ctx, receiverAddr, sdk.Coins{sdk.NewCoin(data.Denomination, data.Amount)}) - if err != nil { - return err - } - - } else { - // unescrow tokens - - // check the denom prefix - prefix := fmt.Sprintf("%s/%s", packet.SourcePort(), packet.SourceChannel()) - if !strings.HasPrefix(data.Denomination, prefix) { - return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeIncorrectDenom, "incorrect denomination") - } - - escrowAddress := k.GetEscrowAddress(packet.DestChannel()) - err := k.bk.SendCoins(ctx, escrowAddress, receiverAddr, sdk.Coins{sdk.NewCoin(data.Denomination[len(prefix):], data.Amount)}) - if err != nil { - return err - } - } - - return nil -} - -func (k Keeper) createOutgoingPacket(ctx sdk.Context, seq uint64, srcPort, srcChan, dstPort, dstChan string, denom string, amount sdk.Int, sender sdk.AccAddress, receiver string, source bool) sdk.Error { - if source { - // escrow tokens - - // get escrow address - escrowAddress := k.GetEscrowAddress(srcChan) - - // check the denom prefix - prefix := fmt.Sprintf("%s/%s", dstPort, dstChan) - if !strings.HasPrefix(denom, prefix) { - return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeIncorrectDenom, "incorrect denomination") - } - - err := k.bk.SendCoins(ctx, sender, escrowAddress, sdk.Coins{sdk.NewCoin(denom[len(prefix):], amount)}) - if err != nil { - return err - } - - } else { - // burn vouchers from sender - - // check the denom prefix - prefix := fmt.Sprintf("%s/%s", srcPort, srcChan) - if !strings.HasPrefix(denom, prefix) { - return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeIncorrectDenom, "incorrect denomination") - } - - _, err := k.bk.SubtractCoins(ctx, sender, sdk.Coins{sdk.NewCoin(denom, amount)}) - if err != nil { - return err - } - } - - // build packet - packetData := types.TransferPacketData{ - Denomination: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Source: source, - } - - packetDataBz, err := packetData.MarshalJSON() - if err != nil { - return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeInvalidPacketData, "invalid packet data") - } - - packet := types.NewPacket(seq, uint64(ctx.BlockHeight())+DefaultPacketTimeout, srcPort, srcChan, dstPort, dstChan, packetDataBz) - - err = k.ck.SendPacket(ctx, packet) - if err != nil { - return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeErrSendPacket, "failed to send packet") - } - - packetJson, _ := packet.MarshalJSON() - ctx.EventManager().EmitEvent(sdk.NewEvent( - ics04.EventTypeSendPacket, - sdk.NewAttribute(ics04.AttributeKeySenderPort, srcPort), - sdk.NewAttribute(ics04.AttributeKeyChannelID, srcChan), - sdk.NewAttribute(ics04.AttributeKeyPacket, string(packetJson)), - )) - - return nil -} - -// GetEscrowAddress returns the escrow address for the specified channel -func (k Keeper) GetEscrowAddress(chanID string) sdk.AccAddress { - return sdk.AccAddress(crypto.AddressHash([]byte(chanID))) + return k.bk.ReceiveTransfer(ctx, packet.SourcePort(), packet.SourceChannel(), packet.DestPort(), packet.DestChannel(), data) } diff --git a/x/ibc/mock/bank/internal/types/codec.go b/x/ibc/mock/bank/internal/types/codec.go index d20501ff5baa..ba05f5bb00f7 100644 --- a/x/ibc/mock/bank/internal/types/codec.go +++ b/x/ibc/mock/bank/internal/types/codec.go @@ -7,16 +7,13 @@ import ( ) func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(Packet{}, "ibcmockbank/Packet", nil) - cdc.RegisterConcrete(TransferPacketData{}, "ibcmockbank/TransferPacketData", nil) - cdc.RegisterConcrete(MsgTransfer{}, "ibcmockbank/MsgTransfer", nil) - cdc.RegisterConcrete(MsgRecvTransferPacket{}, "ibcmockbank/MsgRecvTransferPacket", nil) + cdc.RegisterConcrete(MsgRecvPacket{}, "ibcmockbank/MsgRecvPacket", nil) } -var MouduleCdc = codec.New() +var ModuleCdc = codec.New() func init() { - RegisterCodec(MouduleCdc) - channel.RegisterCodec(MouduleCdc) - commitment.RegisterCodec(MouduleCdc) + RegisterCodec(ModuleCdc) + channel.RegisterCodec(ModuleCdc) + commitment.RegisterCodec(ModuleCdc) } diff --git a/x/ibc/mock/bank/internal/types/errors.go b/x/ibc/mock/bank/internal/types/errors.go index 52582daccfe0..09cfc89784ff 100644 --- a/x/ibc/mock/bank/internal/types/errors.go +++ b/x/ibc/mock/bank/internal/types/errors.go @@ -6,12 +6,10 @@ import ( // ibcmockbank errors reserve 100 ~ 199. const ( - CodeIncorrectDenom sdk.CodeType = 101 - CodeInvalidAmount sdk.CodeType = 102 - CodeInvalidAddress sdk.CodeType = 103 - CodeInvalidReceiver sdk.CodeType = 104 - CodeErrSendPacket sdk.CodeType = 105 - CodeErrReceivePacket sdk.CodeType = 106 - CodeProofMissing sdk.CodeType = 107 - CodeInvalidPacketData sdk.CodeType = 108 + DefaultCodespace sdk.CodespaceType = ModuleName + + CodeInvalidAddress sdk.CodeType = 101 + CodeErrReceivePacket sdk.CodeType = 102 + CodeProofMissing sdk.CodeType = 103 + CodeInvalidPacketData sdk.CodeType = 104 ) diff --git a/x/ibc/mock/bank/internal/types/expected_keepers.go b/x/ibc/mock/bank/internal/types/expected_keepers.go index 45156d2675b5..4c6e8e149169 100644 --- a/x/ibc/mock/bank/internal/types/expected_keepers.go +++ b/x/ibc/mock/bank/internal/types/expected_keepers.go @@ -3,30 +3,23 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -type BankKeeper interface { - AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) - - SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - - SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) +// IbcBankKeeper expected IBC transfer keeper +type IbcBankKeeper interface { + ReceiveTransfer(ctx sdk.Context, srcPort, srcChannel, destPort, destChannel string, data transfer.PacketData) error } +// ChannelKeeper expected IBC channel keeper type ChannelKeeper interface { - GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) - - GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) - RecvPacket( ctx sdk.Context, packet exported.PacketI, - proof ics23.Proof, + proof commitment.ProofI, proofHeight uint64, acknowledgement []byte, + portCapability sdk.CapabilityKey, ) (exported.PacketI, error) - - SendPacket(ctx sdk.Context, packet exported.PacketI) error } diff --git a/x/ibc/mock/bank/internal/types/keys.go b/x/ibc/mock/bank/internal/types/keys.go index a5e764dfbb72..2ffaa38eaa29 100644 --- a/x/ibc/mock/bank/internal/types/keys.go +++ b/x/ibc/mock/bank/internal/types/keys.go @@ -7,15 +7,9 @@ const ( // StoreKey is the string store representation StoreKey = ModuleName - // TStoreKey is the string transient store representation - TStoreKey = "transient_" + ModuleName - // QuerierRoute is the querier route for the module QuerierRoute = ModuleName // RouterKey is the msg router key for the module RouterKey = ModuleName - - // codespace - DefaultCodespace = ModuleName ) diff --git a/x/ibc/mock/bank/internal/types/msgs.go b/x/ibc/mock/bank/internal/types/msgs.go index ad87c838c1b4..61d414591e34 100644 --- a/x/ibc/mock/bank/internal/types/msgs.go +++ b/x/ibc/mock/bank/internal/types/msgs.go @@ -2,73 +2,20 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" - ics04 "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - ics23 "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -const ( - TypeMsgTransfer = "transfer" - TypeMsgRecvTransferPacket = "recv-transfer-packet" -) - -type MsgTransfer struct { - SrcPort string `json:"src_port" yaml:"src_port"` - SrcChannel string `json:"src_channel" yaml:"src_channel"` - Denomination string `json:"denomination" yaml:"denomination"` - Amount sdk.Int `json:"amount" yaml:"amount"` - Sender sdk.AccAddress `json:"sender" yaml:"sender"` - Receiver string `json:"receiver" yaml:"receiver"` - Source bool `json:"source" yaml:"source"` -} -type MsgRecvTransferPacket struct { - Packet ics04.PacketI `json:"packet" yaml:"packet"` - Proofs []ics23.Proof `json:"proofs" yaml:"proofs"` - Height uint64 `json:"height" yaml:"height"` - Signer sdk.AccAddress `json:"signer" yaml:"signer"` -} - -func NewMsgTransfer(srcPort, srcChannel string, denom string, amount sdk.Int, sender sdk.AccAddress, receiver string, source bool) MsgTransfer { - return MsgTransfer{ - SrcPort: srcPort, - SrcChannel: srcChannel, - Denomination: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Source: source, - } -} - -func (MsgTransfer) Route() string { - return RouterKey -} - -func (MsgTransfer) Type() string { - return TypeMsgTransfer -} - -func (msg MsgTransfer) ValidateBasic() sdk.Error { - if !msg.Amount.IsPositive() { - return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeInvalidAmount, "invalid amount") - } - - if msg.Sender.Empty() || len(msg.Receiver) == 0 { - return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeInvalidAddress, "invalid address") - } - - return nil +type MsgRecvPacket struct { + Packet channel.PacketI `json:"packet" yaml:"packet"` + Proofs []commitment.Proof `json:"proofs" yaml:"proofs"` + Height uint64 `json:"height" yaml:"height"` + Signer sdk.AccAddress `json:"signer" yaml:"signer"` } -func (msg MsgTransfer) GetSignBytes() []byte { - return sdk.MustSortJSON(MouduleCdc.MustMarshalJSON(msg)) -} - -func (msg MsgTransfer) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Sender} -} - -func NewMsgRecvTransferPacket(packet ics04.PacketI, proofs []ics23.Proof, height uint64, signer sdk.AccAddress) MsgRecvTransferPacket { - return MsgRecvTransferPacket{ +// NewMsgRecvPacket creates a new MsgRecvPacket instance +func NewMsgRecvPacket(packet channel.PacketI, proofs []commitment.Proof, height uint64, signer sdk.AccAddress) MsgRecvPacket { + return MsgRecvPacket{ Packet: packet, Proofs: proofs, Height: height, @@ -76,15 +23,18 @@ func NewMsgRecvTransferPacket(packet ics04.PacketI, proofs []ics23.Proof, height } } -func (MsgRecvTransferPacket) Route() string { +// Route implements sdk.Msg +func (MsgRecvPacket) Route() string { return RouterKey } -func (MsgRecvTransferPacket) Type() string { - return TypeMsgRecvTransferPacket +// Type implements sdk.Msg +func (MsgRecvPacket) Type() string { + return "recv_packet" } -func (msg MsgRecvTransferPacket) ValidateBasic() sdk.Error { +// ValidateBasic implements sdk.Msg +func (msg MsgRecvPacket) ValidateBasic() sdk.Error { if msg.Proofs == nil { return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeProofMissing, "proof missing") } @@ -93,13 +43,19 @@ func (msg MsgRecvTransferPacket) ValidateBasic() sdk.Error { return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeInvalidAddress, "invalid signer") } + if err := msg.Packet.ValidateBasic(); err != nil { + return err + } + return nil } -func (msg MsgRecvTransferPacket) GetSignBytes() []byte { - return sdk.MustSortJSON(MouduleCdc.MustMarshalJSON(msg)) +// GetSignBytes implements sdk.Msg +func (msg MsgRecvPacket) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) } -func (msg MsgRecvTransferPacket) GetSigners() []sdk.AccAddress { +// GetSigners implements sdk.Msg +func (msg MsgRecvPacket) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } diff --git a/x/ibc/mock/bank/internal/types/packet.go b/x/ibc/mock/bank/internal/types/packet.go deleted file mode 100644 index c1b8fdbb9e6b..000000000000 --- a/x/ibc/mock/bank/internal/types/packet.go +++ /dev/null @@ -1,122 +0,0 @@ -package types - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" -) - -var _ exported.PacketI = Packet{} - -// Packet defines a type that carries data across different chains through IBC -type Packet struct { - sequence uint64 // number corresponds to the order of sends and receives, where a packet with an earlier sequence number must be sent and received before a packet with a later sequence number. - timeout uint64 // indicates a consensus height on the destination chain after which the packet will no longer be processed, and will instead count as having timed-out. - sourcePort string // identifies the port on the sending chain. - sourceChannel string // identifies the channel end on the sending chain. - destinationPort string // identifies the port on the receiving chain. - destinationChannel string // identifies the channel end on the receiving chain. - data []byte // opaque value which can be defined by the application logic of the associated modules. -} - -// newPacket creates a new Packet instance -func NewPacket( - sequence, timeout uint64, sourcePort, sourceChannel, - destinationPort, destinationChannel string, data []byte, -) Packet { - return Packet{ - sequence, - timeout, - sourcePort, - sourceChannel, - destinationPort, - destinationChannel, - data, - } -} - -// Sequence implements PacketI interface -func (p Packet) Sequence() uint64 { return p.sequence } - -// TimeoutHeight implements PacketI interface -func (p Packet) TimeoutHeight() uint64 { return p.timeout } - -// SourcePort implements PacketI interface -func (p Packet) SourcePort() string { return p.sourcePort } - -// SourceChannel implements PacketI interface -func (p Packet) SourceChannel() string { return p.sourceChannel } - -// DestPort implements PacketI interface -func (p Packet) DestPort() string { return p.destinationPort } - -// DestChannel implements PacketI interface -func (p Packet) DestChannel() string { return p.destinationChannel } - -// Data implements PacketI interface -func (p Packet) Data() []byte { return p.data } - -func (p Packet) MarshalJSON() ([]byte, error) { - return MouduleCdc.MarshalJSON(p) -} - -func (p *Packet) UnmarshalJSON(bz []byte) (err error) { - return MouduleCdc.UnmarshalJSON(bz, p) -} - -// TransferPacketData defines a struct for the packet payload -type TransferPacketData struct { - Denomination string `json:"denomination" yaml:"denomination"` - Amount sdk.Int `json:"amount" yaml:"amount"` - Sender sdk.AccAddress `json:"sender" yaml:"sender"` - Receiver string `json:"receiver" yaml:"receiver"` - Source bool `json:"source" yaml:"source"` -} - -func (tpd TransferPacketData) MarshalAmino() ([]byte, error) { - return MouduleCdc.MarshalBinaryBare(tpd) -} - -func (tpd *TransferPacketData) UnmarshalAmino(bz []byte) (err error) { - return MouduleCdc.UnmarshalBinaryBare(bz, tpd) -} - -func (tpd TransferPacketData) Marshal() []byte { - return MouduleCdc.MustMarshalBinaryBare(tpd) -} - -func (tpd TransferPacketData) MarshalJSON() ([]byte, error) { - return MouduleCdc.MarshalJSON(tpd) -} - -func (tpd *TransferPacketData) UnmarshalJSON(bz []byte) (err error) { - return MouduleCdc.UnmarshalJSON(bz, tpd) -} - -func (tpd TransferPacketData) String() string { - return fmt.Sprintf(`TransferPacketData: - Denomination %s - Amount: %s - Sender: %s - Receiver: %s - Source: %v`, - tpd.Denomination, - tpd.Amount.String(), - tpd.Sender.String(), - tpd.Receiver, - tpd.Source, - ) -} - -func (tpd TransferPacketData) Validate() error { - if !tpd.Amount.IsPositive() { - return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeInvalidAmount, "invalid amount") - } - - if tpd.Sender.Empty() || len(tpd.Receiver) == 0 { - return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeInvalidAddress, "invalid address") - } - - return nil -} diff --git a/x/ibc/module.go b/x/ibc/module.go index a09d8cb2bc3b..bdca95fc585d 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/client/cli" "github.com/cosmos/cosmos-sdk/x/ibc/types" @@ -40,6 +41,7 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { client.RegisterCodec(cdc) channel.RegisterCodec(cdc) commitment.RegisterCodec(cdc) + transfer.RegisterCodec(cdc) } // DefaultGenesis returns default genesis state as raw bytes for the staking @@ -114,6 +116,8 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { // InitGenesis performs genesis initialization for the staking module. It returns // no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { + // check if the IBC transfer module account is set + transfer.InitGenesis(ctx, am.keeper.TransferKeeper) return []abci.ValidatorUpdate{} } From 9742c1440ec34f9d058c1dac431bd2a68be2e3b2 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 29 Oct 2019 15:16:16 +0100 Subject: [PATCH 349/378] update ICS20 escrow address --- x/ibc/20-transfer/keeper/callbacks.go | 11 +++++------ x/ibc/20-transfer/keeper/keeper.go | 21 +++++++++++---------- x/ibc/20-transfer/keeper/relay.go | 4 ++-- x/ibc/20-transfer/types/keys.go | 8 ++++++-- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/x/ibc/20-transfer/keeper/callbacks.go b/x/ibc/20-transfer/keeper/callbacks.go index dad340f24ad2..bae2e96e073f 100644 --- a/x/ibc/20-transfer/keeper/callbacks.go +++ b/x/ibc/20-transfer/keeper/callbacks.go @@ -31,8 +31,8 @@ func (k Keeper) onChanOpenInit( return types.ErrInvalidVersion(k.codespace, fmt.Sprintf("invalid version: %s", version)) } - // TODO: - // channelEscrowAddresses[channelIdentifier] = newAddress() + // NOTE: as the escrow address is generated from both the port and channel IDs + // there's no need to store it on a map. return nil } @@ -63,9 +63,8 @@ func (k Keeper) onChanOpenTry( return types.ErrInvalidVersion(k.codespace, fmt.Sprintf("invalid counterparty version: %s", version)) } - // TODO: - // channelEscrowAddresses[channelIdentifier] = newAddress() - + // NOTE: as the escrow address is generated from both the port and channel IDs + // there's no need to store it on a map. return nil } @@ -166,7 +165,7 @@ func (k Keeper) onTimeoutPacket( } if data.Source { - escrowAddress := types.GetEscrowAddress(packet.DestChannel()) + escrowAddress := types.GetEscrowAddress(packet.DestPort(), packet.DestChannel()) return k.bankKeeper.SendCoins(ctx, escrowAddress, data.Sender, coins) } diff --git a/x/ibc/20-transfer/keeper/keeper.go b/x/ibc/20-transfer/keeper/keeper.go index 87ce6b543af6..95576d4609f3 100644 --- a/x/ibc/20-transfer/keeper/keeper.go +++ b/x/ibc/20-transfer/keeper/keeper.go @@ -32,14 +32,15 @@ type Keeper struct { } // NewKeeper creates a new IBC transfer Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType, - clientk types.ClientKeeper, connk types.ConnectionKeeper, - chank types.ChannelKeeper, bk types.BankKeeper, - sk types.SupplyKeeper, +func NewKeeper( + cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType, + clientKeeper types.ClientKeeper, connnectionKeeper types.ConnectionKeeper, + channelKeeper types.ChannelKeeper, bankKeeper types.BankKeeper, + supplyKeeper types.SupplyKeeper, ) Keeper { // ensure ibc transfer module account is set - if addr := sk.GetModuleAddress(types.GetModuleAccountName()); addr == nil { + if addr := supplyKeeper.GetModuleAddress(types.GetModuleAccountName()); addr == nil { panic("the IBC transfer module account has not been set") } @@ -48,11 +49,11 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType, cdc: cdc, codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/transfer", prefix: []byte(types.SubModuleName + "/"), // "transfer/" - clientKeeper: clientk, - connectionKeeper: connk, - channelKeeper: chank, - bankKeeper: bk, - supplyKeeper: sk, + clientKeeper: clientKeeper, + connectionKeeper: connnectionKeeper, + channelKeeper: channelKeeper, + bankKeeper: bankKeeper, + supplyKeeper: supplyKeeper, } } diff --git a/x/ibc/20-transfer/keeper/relay.go b/x/ibc/20-transfer/keeper/relay.go index b13f34f3ca8c..2b481299606a 100644 --- a/x/ibc/20-transfer/keeper/relay.go +++ b/x/ibc/20-transfer/keeper/relay.go @@ -91,7 +91,7 @@ func (k Keeper) ReceiveTransfer( coins[i] = sdk.NewCoin(coin.Denom[len(prefix):], coin.Amount) } - escrowAddress := types.GetEscrowAddress(destinationChannel) + escrowAddress := types.GetEscrowAddress(destinationPort, destinationChannel) return k.bankKeeper.SendCoins(ctx, escrowAddress, data.Receiver, coins) } @@ -110,7 +110,7 @@ func (k Keeper) createOutgoingPacket( ) error { if isSourceChain { // escrow tokens if the destination chain is the same as the sender's - escrowAddress := types.GetEscrowAddress(sourceChannel) + escrowAddress := types.GetEscrowAddress(sourcePort, sourceChannel) prefix := types.GetDenomPrefix(destinationPort, destinationChannel) coins := make(sdk.Coins, len(amount)) diff --git a/x/ibc/20-transfer/types/keys.go b/x/ibc/20-transfer/types/keys.go index 177982bd169c..d79eb89fc5ba 100644 --- a/x/ibc/20-transfer/types/keys.go +++ b/x/ibc/20-transfer/types/keys.go @@ -27,8 +27,12 @@ const ( ) // GetEscrowAddress returns the escrow address for the specified channel -func GetEscrowAddress(chanID string) sdk.AccAddress { - return sdk.AccAddress(crypto.AddressHash([]byte(chanID))) +// +// CONTRACT: this assumes that there's only one bank bridge module that owns the +// port associated with the channel ID so that the address created is actually +// unique. +func GetEscrowAddress(portID, channelID string) sdk.AccAddress { + return sdk.AccAddress(crypto.AddressHash([]byte(portID + channelID))) } // GetDenomPrefix returns the receiving denomination prefix From 90d0354bc73fb1377c96220d65f37034d5afd48f Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Tue, 29 Oct 2019 15:11:39 -0700 Subject: [PATCH 350/378] fix querier routes --- x/ibc/keeper/querier.go | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/x/ibc/keeper/querier.go b/x/ibc/keeper/querier.go index a9a36f18fa48..437ba393fdcd 100644 --- a/x/ibc/keeper/querier.go +++ b/x/ibc/keeper/querier.go @@ -13,18 +13,33 @@ import ( func NewQuerier(k Keeper) sdk.Querier { return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { switch path[0] { - case client.QueryClientState: - return client.QuerierClientState(ctx, req, k.ClientKeeper) - case client.QueryConsensusState: - return client.QuerierConsensusState(ctx, req, k.ClientKeeper) - case client.QueryVerifiedRoot: - return client.QuerierVerifiedRoot(ctx, req, k.ClientKeeper) - case connection.QueryConnection: - return connection.QuerierConnection(ctx, req, k.ConnectionKeeper) - case connection.QueryClientConnections: - return connection.QuerierClientConnections(ctx, req, k.ConnectionKeeper) - case channel.QueryChannel: - return channel.QuerierChannel(ctx, req, k.ChannelKeeper) + case "client": + switch path[1] { + case client.QueryClientState: + return client.QuerierClientState(ctx, req, k.ClientKeeper) + case client.QueryConsensusState: + return client.QuerierConsensusState(ctx, req, k.ClientKeeper) + case client.QueryVerifiedRoot: + return client.QuerierVerifiedRoot(ctx, req, k.ClientKeeper) + default: + return nil, sdk.ErrUnknownRequest("unknown IBC query endpoint") + } + case "connection": + switch path[1] { + case connection.QueryConnection: + return connection.QuerierConnection(ctx, req, k.ConnectionKeeper) + case connection.QueryClientConnections: + return connection.QuerierClientConnections(ctx, req, k.ConnectionKeeper) + default: + return nil, sdk.ErrUnknownRequest("unknown IBC query endpoint") + } + case "channel": + switch path[1] { + case channel.QueryChannel: + return channel.QuerierChannel(ctx, req, k.ChannelKeeper) + default: + return nil, sdk.ErrUnknownRequest("unknown IBC query endpoint") + } default: return nil, sdk.ErrUnknownRequest("unknown IBC query endpoint") } From 94ffaeb9f746d13b68678423d4aee0828f652fd4 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 29 Oct 2019 16:46:30 -0700 Subject: [PATCH 351/378] fix create client cli --- x/ibc/02-client/client/cli/query.go | 56 +++++++++++++++++++++++++++++ x/ibc/02-client/types/codec.go | 2 ++ x/ibc/04-channel/types/codec.go | 2 ++ 3 files changed, 60 insertions(+) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 9bd992b5d939..1fa7cccb3243 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -34,6 +34,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { GetCmdQueryHeader(cdc), GetCmdQueryClientState(queryRoute, cdc), GetCmdQueryRoot(queryRoute, cdc), + GetCmdNodeConsensusState(queryRoute, cdc), )...) return ics02ClientQueryCmd } @@ -218,3 +219,58 @@ $ %s query ibc client header }, } } + +// GetCmdQueryNodeConsensusState defines the command to query the latest consensus state of a node +// The result is feed to client creation +func GetCmdNodeConsensusState(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "node-state", + Short: "Query a node consensus state", + Long: strings.TrimSpace( + fmt.Sprintf(`Query node consensus state + +Example: +$ %s query ibc client node-state + `, version.ClientName), + ), + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + node, err := cliCtx.GetNode() + if err != nil { + return err + } + + info, err := node.ABCIInfo() + if err != nil { + return err + } + + height := info.Response.LastBlockHeight + prevHeight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return err + } + + validators, err := node.Validators(&prevHeight) + if err != nil { + return err + } + + var state exported.ConsensusState + state = tendermint.ConsensusState{ + ChainID: commit.ChainID, + Height: uint64(commit.Height), + Root: commitment.NewRoot(commit.AppHash), + NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + } + + fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) + + return nil + }, + } +} diff --git a/x/ibc/02-client/types/codec.go b/x/ibc/02-client/types/codec.go index eae86ec2b53d..047edfc2d6e2 100644 --- a/x/ibc/02-client/types/codec.go +++ b/x/ibc/02-client/types/codec.go @@ -21,4 +21,6 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(tendermint.ConsensusState{}, "ibc/client/tendermint/ConsensusState", nil) cdc.RegisterConcrete(tendermint.Header{}, "ibc/client/tendermint/Header", nil) + + SubModuleCdc = cdc } diff --git a/x/ibc/04-channel/types/codec.go b/x/ibc/04-channel/types/codec.go index d3271d9c5610..2f141078356d 100644 --- a/x/ibc/04-channel/types/codec.go +++ b/x/ibc/04-channel/types/codec.go @@ -18,6 +18,8 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgChannelOpenConfirm{}, "ibc/channel/MsgChannelOpenConfirm", nil) cdc.RegisterConcrete(MsgChannelCloseInit{}, "ibc/channel/MsgChannelCloseInit", nil) cdc.RegisterConcrete(MsgChannelCloseConfirm{}, "ibc/channel/MsgChannelCloseConfirm", nil) + + SetMsgChanCodec(cdc) } func SetMsgChanCodec(cdc *codec.Codec) { From 5a397db58e7a265ab9e73219ff4f5a386008bbb3 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 30 Oct 2019 12:25:47 +0100 Subject: [PATCH 352/378] minor updates --- x/ibc/02-client/client/cli/query.go | 8 +++----- x/ibc/keeper/querier.go | 14 ++++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 1fa7cccb3243..6b2dca09831e 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -220,14 +220,14 @@ $ %s query ibc client header } } -// GetCmdQueryNodeConsensusState defines the command to query the latest consensus state of a node +// GetCmdNodeConsensusState defines the command to query the latest consensus state of a node // The result is feed to client creation func GetCmdNodeConsensusState(queryRoute string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "node-state", Short: "Query a node consensus state", Long: strings.TrimSpace( - fmt.Sprintf(`Query node consensus state + fmt.Sprintf(`Query a node consensus state. This result is feed to the client creation transaction. Example: $ %s query ibc client node-state @@ -268,9 +268,7 @@ $ %s query ibc client node-state NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), } - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) - - return nil + return cliCtx.PrintOutput(state) }, } } diff --git a/x/ibc/keeper/querier.go b/x/ibc/keeper/querier.go index 437ba393fdcd..ee934fabd018 100644 --- a/x/ibc/keeper/querier.go +++ b/x/ibc/keeper/querier.go @@ -1,6 +1,8 @@ package keeper import ( + "fmt" + abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -13,7 +15,7 @@ import ( func NewQuerier(k Keeper) sdk.Querier { return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { switch path[0] { - case "client": + case client.SubModuleName: switch path[1] { case client.QueryClientState: return client.QuerierClientState(ctx, req, k.ClientKeeper) @@ -22,23 +24,23 @@ func NewQuerier(k Keeper) sdk.Querier { case client.QueryVerifiedRoot: return client.QuerierVerifiedRoot(ctx, req, k.ClientKeeper) default: - return nil, sdk.ErrUnknownRequest("unknown IBC query endpoint") + return nil, sdk.ErrUnknownRequest(fmt.Sprintf("unknown IBC %s query endpoint", client.SubModuleName)) } - case "connection": + case connection.SubModuleName: switch path[1] { case connection.QueryConnection: return connection.QuerierConnection(ctx, req, k.ConnectionKeeper) case connection.QueryClientConnections: return connection.QuerierClientConnections(ctx, req, k.ConnectionKeeper) default: - return nil, sdk.ErrUnknownRequest("unknown IBC query endpoint") + return nil, sdk.ErrUnknownRequest(fmt.Sprintf("unknown IBC %s query endpoint", connection.SubModuleName)) } - case "channel": + case channel.SubModuleName: switch path[1] { case channel.QueryChannel: return channel.QuerierChannel(ctx, req, k.ChannelKeeper) default: - return nil, sdk.ErrUnknownRequest("unknown IBC query endpoint") + return nil, sdk.ErrUnknownRequest(fmt.Sprintf("unknown IBC %s query endpoint", channel.SubModuleName)) } default: return nil, sdk.ErrUnknownRequest("unknown IBC query endpoint") From af6bed9fb1abbc17d7778bfcf928f6abb5f99fa0 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 30 Oct 2019 14:36:33 +0100 Subject: [PATCH 353/378] ibc querier test --- x/ibc/keeper/integration_test.go | 15 +++++ x/ibc/keeper/querier_test.go | 106 +++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 x/ibc/keeper/integration_test.go create mode 100644 x/ibc/keeper/querier_test.go diff --git a/x/ibc/keeper/integration_test.go b/x/ibc/keeper/integration_test.go new file mode 100644 index 000000000000..811d4c5d87ae --- /dev/null +++ b/x/ibc/keeper/integration_test.go @@ -0,0 +1,15 @@ +package keeper_test + +import ( + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// returns context and an app with updated mint keeper +func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) { + app := simapp.Setup(isCheckTx) + ctx := app.BaseApp.NewContext(isCheckTx, abci.Header{}) + return app, ctx +} diff --git a/x/ibc/keeper/querier_test.go b/x/ibc/keeper/querier_test.go new file mode 100644 index 000000000000..52b70f70b921 --- /dev/null +++ b/x/ibc/keeper/querier_test.go @@ -0,0 +1,106 @@ +package keeper_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + 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/keeper" + + abci "github.com/tendermint/tendermint/abci/types" +) + +// TestNewQuerier tests that the querier paths are correct. +// NOTE: the actuall testing functionallity are located on each ICS querier test. +func TestNewQuerier(t *testing.T) { + app, ctx := createTestApp(true) + querier := keeper.NewQuerier(app.IBCKeeper) + + query := abci.RequestQuery{ + Path: "", + Data: []byte{}, + } + + cases := []struct { + name string + path []string + expectsDefaultErr bool + errMsg string + }{ + {"client - QueryClientState", + []string{client.SubModuleName, client.QueryClientState}, + false, + "", + }, + { + "client - QueryConsensusState", + []string{client.SubModuleName, client.QueryConsensusState}, + false, + "", + }, + { + "client - QueryVerifiedRoot", + []string{client.SubModuleName, client.QueryVerifiedRoot}, + false, + "", + }, + { + "client - invalid query", + []string{client.SubModuleName, "foo"}, + true, + fmt.Sprintf("unknown IBC %s query endpoint", client.SubModuleName), + }, + { + "connection - QueryConnection", + []string{connection.SubModuleName, connection.QueryConnection}, + false, + "", + }, + { + "connection - QueryClientConnections", + []string{connection.SubModuleName, connection.QueryClientConnections}, + false, + "", + }, + { + "connection - invalid query", + []string{connection.SubModuleName, "foo"}, + true, + fmt.Sprintf("unknown IBC %s query endpoint", connection.SubModuleName), + }, + { + "channel - QueryChannel", + []string{channel.SubModuleName, channel.QueryChannel}, + false, + "", + }, + { + "channel - invalid query", + []string{channel.SubModuleName, "foo"}, + true, + fmt.Sprintf("unknown IBC %s query endpoint", channel.SubModuleName), + }, + { + "invalid query", + []string{"foo"}, + true, + "unknown IBC query endpoint", + }, + } + + for i, tc := range cases { + i, tc := i, tc + t.Run(tc.name, func(t *testing.T) { + _, err := querier(ctx, tc.path, query) + if tc.expectsDefaultErr { + require.Contains(t, err.Error(), tc.errMsg, "test case #%d", i) + } else { + require.Error(t, err, "test case #%d", i) + } + }) + } +} From 82d9124eb944c46709bacfc0c5ff8e8ac59233ef Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 30 Oct 2019 15:40:32 +0100 Subject: [PATCH 354/378] Refactor ibc/mock/bank into ICS 20 (#5264) * Most of code port from mock module to ICS 20 * A few minor fixes * Apply suggestions from code review Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * Fix suggestions from autolinter * Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Fix order of messages * Add invalid height error code, check non-nil proof * Fix linter error * Return the underlying error * Tendermint starts at height 1 * Apply suggestions from code review --- x/ibc/20-transfer/alias.go | 1 + x/ibc/20-transfer/client/cli/tx.go | 62 ++++++++++ x/ibc/20-transfer/handler.go | 10 ++ x/ibc/20-transfer/keeper/relay.go | 18 +++ x/ibc/20-transfer/types/errors.go | 2 + x/ibc/20-transfer/types/expected_keepers.go | 2 + x/ibc/20-transfer/types/msgs.go | 63 ++++++++++ x/ibc/client/cli/cli.go | 2 - x/ibc/handler.go | 3 + x/ibc/mock/bank/alias.go | 26 ----- x/ibc/mock/bank/client/cli/tx.go | 85 -------------- x/ibc/mock/bank/handler.go | 26 ----- x/ibc/mock/bank/internal/keeper/keeper.go | 44 ------- x/ibc/mock/bank/internal/types/codec.go | 19 --- x/ibc/mock/bank/internal/types/errors.go | 15 --- .../bank/internal/types/expected_keepers.go | 25 ---- x/ibc/mock/bank/internal/types/keys.go | 15 --- x/ibc/mock/bank/internal/types/msgs.go | 61 ---------- x/ibc/mock/bank/module.go | 110 ------------------ 19 files changed, 161 insertions(+), 428 deletions(-) delete mode 100644 x/ibc/mock/bank/alias.go delete mode 100644 x/ibc/mock/bank/client/cli/tx.go delete mode 100644 x/ibc/mock/bank/handler.go delete mode 100644 x/ibc/mock/bank/internal/keeper/keeper.go delete mode 100644 x/ibc/mock/bank/internal/types/codec.go delete mode 100644 x/ibc/mock/bank/internal/types/errors.go delete mode 100644 x/ibc/mock/bank/internal/types/expected_keepers.go delete mode 100644 x/ibc/mock/bank/internal/types/keys.go delete mode 100644 x/ibc/mock/bank/internal/types/msgs.go delete mode 100644 x/ibc/mock/bank/module.go diff --git a/x/ibc/20-transfer/alias.go b/x/ibc/20-transfer/alias.go index ba4008d57374..66028740581e 100644 --- a/x/ibc/20-transfer/alias.go +++ b/x/ibc/20-transfer/alias.go @@ -56,6 +56,7 @@ type ( ConnectionKeeper = types.ConnectionKeeper SupplyKeeper = types.SupplyKeeper MsgTransfer = types.MsgTransfer + MsgRecvPacket = types.MsgRecvPacket PacketData = types.PacketData PacketDataAlias = types.PacketDataAlias ) diff --git a/x/ibc/20-transfer/client/cli/tx.go b/x/ibc/20-transfer/client/cli/tx.go index e9e12f28d4a8..99be5e6387c3 100644 --- a/x/ibc/20-transfer/client/cli/tx.go +++ b/x/ibc/20-transfer/client/cli/tx.go @@ -1,16 +1,24 @@ package cli import ( + "fmt" + "io/ioutil" + "os" + "strconv" + "github.com/spf13/cobra" "github.com/spf13/viper" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" "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" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // IBC transfer flags @@ -26,6 +34,7 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command { } txCmd.AddCommand( GetTransferTxCmd(cdc), + GetMsgRecvPacketCmd(cdc), ) return txCmd @@ -68,3 +77,56 @@ func GetTransferTxCmd(cdc *codec.Codec) *cobra.Command { cmd.Flags().Bool(FlagSource, false, "Pass flag for sending token from the source chain") return cmd } + +// GetMsgRecvPacketCmd returns the command to create a MsgRecvTransferPacket transaction +func GetMsgRecvPacketCmd(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "recv-packet [/path/to/packet-data.json] [/path/to/proof.json] [height]", + Short: "Creates and sends a SendPacket message", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) + + var packet channelexported.PacketI + if err := cdc.UnmarshalJSON([]byte(args[0]), &packet); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...\n") + contents, err := ioutil.ReadFile(args[0]) + if err != nil { + return fmt.Errorf("error opening packet file: %v", err) + } + + if err := cdc.UnmarshalJSON(contents, packet); err != nil { + return fmt.Errorf("error unmarshalling packet file: %v", err) + } + } + + var proof commitment.Proof + if err := cdc.UnmarshalJSON([]byte(args[1]), &proof); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...\n") + contents, err := ioutil.ReadFile(args[1]) + if err != nil { + return fmt.Errorf("error opening proofs file: %v", err) + } + if err := cdc.UnmarshalJSON(contents, &proof); err != nil { + return fmt.Errorf("error unmarshalling proofs file: %v", err) + } + } + + height, err := strconv.ParseUint(args[2], 10, 64) + if err != nil { + return fmt.Errorf("error height: %v", err) + } + + msg := types.NewMsgRecvPacket(packet, []commitment.Proof{proof}, height, cliCtx.GetFromAddress()) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + + cmd = client.PostCommands(cmd)[0] + return cmd +} diff --git a/x/ibc/20-transfer/handler.go b/x/ibc/20-transfer/handler.go index 52f47fab9257..49fe077acbe2 100644 --- a/x/ibc/20-transfer/handler.go +++ b/x/ibc/20-transfer/handler.go @@ -5,6 +5,16 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" ) +// handleMsgRecvPacket defines the sdk.Handler for MsgRecvPacket +func HandleMsgRecvPacket(ctx sdk.Context, k Keeper, msg MsgRecvPacket) (res sdk.Result) { + err := k.ReceivePacket(ctx, msg.Packet, msg.Proofs[0], msg.Height) + if err != nil { + return sdk.ResultFromError(err) + } + + return sdk.Result{Events: ctx.EventManager().Events()} +} + // HandleMsgTransfer defines the sdk.Handler for MsgTransfer func HandleMsgTransfer(ctx sdk.Context, k Keeper, msg MsgTransfer) (res sdk.Result) { err := k.SendTransfer(ctx, msg.SourcePort, msg.SourceChannel, msg.Amount, msg.Sender, msg.Receiver, msg.Source) diff --git a/x/ibc/20-transfer/keeper/relay.go b/x/ibc/20-transfer/keeper/relay.go index 2b481299606a..9dbe829b10f1 100644 --- a/x/ibc/20-transfer/keeper/relay.go +++ b/x/ibc/20-transfer/keeper/relay.go @@ -5,8 +5,10 @@ import ( "strings" sdk "github.com/cosmos/cosmos-sdk/types" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // SendTransfer handles transfer sending logic @@ -50,6 +52,22 @@ func (k Keeper) SendTransfer( return k.createOutgoingPacket(ctx, sequence, sourcePort, sourceChannel, destinationPort, destinationChannel, coins, sender, receiver, isSourceChain) } +// ReceivePacket handles receiving packet +func (k Keeper) ReceivePacket(ctx sdk.Context, packet channelexported.PacketI, proof commitment.ProofI, height uint64) error { + _, err := k.channelKeeper.RecvPacket(ctx, packet, proof, height, nil, k.storeKey) + if err != nil { + return err + } + + var data types.PacketData + err = data.UnmarshalJSON(packet.Data()) + if err != nil { + return sdk.NewError(types.DefaultCodespace, types.CodeInvalidPacketData, "invalid packet data") + } + + return k.ReceiveTransfer(ctx, packet.SourcePort(), packet.SourceChannel(), packet.DestPort(), packet.DestChannel(), data) +} + // ReceiveTransfer handles transfer receiving logic func (k Keeper) ReceiveTransfer( ctx sdk.Context, diff --git a/x/ibc/20-transfer/types/errors.go b/x/ibc/20-transfer/types/errors.go index 090804150095..51f95d560a01 100644 --- a/x/ibc/20-transfer/types/errors.go +++ b/x/ibc/20-transfer/types/errors.go @@ -16,6 +16,8 @@ const ( CodeInvalidChannelOrder sdk.CodeType = 104 CodeInvalidPort sdk.CodeType = 105 CodeInvalidVersion sdk.CodeType = 106 + CodeProofMissing sdk.CodeType = 107 + CodeInvalidHeight sdk.CodeType = 108 ) // ErrInvalidAddress implements sdk.Error diff --git a/x/ibc/20-transfer/types/expected_keepers.go b/x/ibc/20-transfer/types/expected_keepers.go index 2e855dfd8079..252eb8060645 100644 --- a/x/ibc/20-transfer/types/expected_keepers.go +++ b/x/ibc/20-transfer/types/expected_keepers.go @@ -6,6 +6,7 @@ import ( connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" ) @@ -19,6 +20,7 @@ type ChannelKeeper interface { GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channel.Channel, found bool) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) SendPacket(ctx sdk.Context, packet channelexported.PacketI, portCapability sdk.CapabilityKey) error + RecvPacket(ctx sdk.Context, packet channelexported.PacketI, proof commitment.ProofI, proofHeight uint64, acknowledgement []byte, portCapability sdk.CapabilityKey) (channelexported.PacketI, error) } // ClientKeeper defines the expected IBC client keeper diff --git a/x/ibc/20-transfer/types/msgs.go b/x/ibc/20-transfer/types/msgs.go index e2d4a725b6d1..4df5cf270407 100644 --- a/x/ibc/20-transfer/types/msgs.go +++ b/x/ibc/20-transfer/types/msgs.go @@ -5,6 +5,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" + + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -73,3 +76,63 @@ func (msg MsgTransfer) GetSignBytes() []byte { func (msg MsgTransfer) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Sender} } + +type MsgRecvPacket struct { + Packet channelexported.PacketI `json:"packet" yaml:"packet"` + Proofs []commitment.Proof `json:"proofs" yaml:"proofs"` + Height uint64 `json:"height" yaml:"height"` + Signer sdk.AccAddress `json:"signer" yaml:"signer"` +} + +// NewMsgRecvPacket creates a new MsgRecvPacket instance +func NewMsgRecvPacket(packet channelexported.PacketI, proofs []commitment.Proof, height uint64, signer sdk.AccAddress) MsgRecvPacket { + return MsgRecvPacket{ + Packet: packet, + Proofs: proofs, + Height: height, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (MsgRecvPacket) Route() string { + return RouterKey +} + +// Type implements sdk.Msg +func (MsgRecvPacket) Type() string { + return "recv_packet" +} + +// ValidateBasic implements sdk.Msg +func (msg MsgRecvPacket) ValidateBasic() sdk.Error { + if msg.Height < 1 { + return sdk.NewError(DefaultCodespace, CodeInvalidHeight, "invalid height") + } + + if msg.Proofs == nil { + return sdk.NewError(DefaultCodespace, CodeProofMissing, "proof missing") + } + + for _, proof := range msg.Proofs { + if proof.Proof == nil { + return sdk.NewError(DefaultCodespace, CodeProofMissing, "proof missing") + } + } + + if msg.Signer.Empty() { + return sdk.NewError(DefaultCodespace, CodeInvalidAddress, "invalid signer") + } + + return msg.Packet.ValidateBasic() +} + +// GetSignBytes implements sdk.Msg +func (msg MsgRecvPacket) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgRecvPacket) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} diff --git a/x/ibc/client/cli/cli.go b/x/ibc/client/cli/cli.go index 5e58be761800..90ec11a8740f 100644 --- a/x/ibc/client/cli/cli.go +++ b/x/ibc/client/cli/cli.go @@ -8,7 +8,6 @@ import ( ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" - mockbank "github.com/cosmos/cosmos-sdk/x/ibc/mock/bank" "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -26,7 +25,6 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ibcclient.GetTxCmd(cdc, storeKey), connection.GetTxCmd(cdc, storeKey), transfer.GetTxCmd(cdc), - mockbank.GetTxCmd(cdc), ) return ibcTxCmd } diff --git a/x/ibc/handler.go b/x/ibc/handler.go index 3e432e57e2c5..a0af5394b667 100644 --- a/x/ibc/handler.go +++ b/x/ibc/handler.go @@ -61,6 +61,9 @@ func NewHandler(k Keeper) sdk.Handler { case transfer.MsgTransfer: return transfer.HandleMsgTransfer(ctx, k.TransferKeeper, msg) + case transfer.MsgRecvPacket: + return transfer.HandleMsgRecvPacket(ctx, k.TransferKeeper, msg) + default: errMsg := fmt.Sprintf("unrecognized IBC message type: %T", msg) return sdk.ErrUnknownRequest(errMsg).Result() diff --git a/x/ibc/mock/bank/alias.go b/x/ibc/mock/bank/alias.go deleted file mode 100644 index 7447068ba7e7..000000000000 --- a/x/ibc/mock/bank/alias.go +++ /dev/null @@ -1,26 +0,0 @@ -package mockbank - -import ( - "github.com/cosmos/cosmos-sdk/x/ibc/mock/bank/internal/keeper" - "github.com/cosmos/cosmos-sdk/x/ibc/mock/bank/internal/types" -) - -type ( - MsgRecvPacket = types.MsgRecvPacket - Keeper = keeper.Keeper -) - -const ( - ModuleName = types.ModuleName - StoreKey = types.StoreKey - QuerierRoute = types.QuerierRoute - RouterKey = types.RouterKey -) - -// nolint -var ( - RegisterCdc = types.RegisterCodec - - NewKeeper = keeper.NewKeeper - NewMsgRecvPacket = types.NewMsgRecvPacket -) diff --git a/x/ibc/mock/bank/client/cli/tx.go b/x/ibc/mock/bank/client/cli/tx.go deleted file mode 100644 index 4bb1fb2fc7d3..000000000000 --- a/x/ibc/mock/bank/client/cli/tx.go +++ /dev/null @@ -1,85 +0,0 @@ -package cli - -import ( - "fmt" - "io/ioutil" - "os" - "strconv" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/flags" - "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" - 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/mock/bank/internal/types" - "github.com/spf13/cobra" -) - -func GetTxCmd(cdc *codec.Codec) *cobra.Command { - txCmd := &cobra.Command{ - Use: "ibcmockbank", - Short: "IBC mockbank module transaction subcommands", - } - txCmd.AddCommand( - GetMsgRecvPacketCmd(cdc), - ) - - return txCmd -} - -// GetMsgRecvPacketCmd returns the command to create a MsgRecvTransferPacket transaction -func GetMsgRecvPacketCmd(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "recv-packet [/path/to/packet-data.json] [/path/to/proof.json] [height]", - Short: "Creates and sends a SendPacket message", - Args: cobra.ExactArgs(3), - RunE: func(cmd *cobra.Command, args []string) error { - txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContext().WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) - - var packet channel.Packet - if err := cdc.UnmarshalJSON([]byte(args[0]), &packet); err != nil { - fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...\n") - contents, err := ioutil.ReadFile(args[0]) - if err != nil { - return fmt.Errorf("error opening packet file: %v", err) - } - - if err := cdc.UnmarshalJSON(contents, packet); err != nil { - return fmt.Errorf("error unmarshalling packet file: %v", err) - } - } - - var proof commitment.Proof - if err := cdc.UnmarshalJSON([]byte(args[1]), &proof); err != nil { - fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...\n") - contents, err := ioutil.ReadFile(args[1]) - if err != nil { - return fmt.Errorf("error opening proofs file: %v", err) - } - if err := cdc.UnmarshalJSON(contents, &proof); err != nil { - return fmt.Errorf("error unmarshalling proofs file: %v", err) - } - } - - height, err := strconv.ParseUint(args[2], 10, 64) - if err != nil { - return fmt.Errorf("error height: %v", err) - } - - msg := types.NewMsgRecvPacket(packet, []commitment.Proof{proof}, height, cliCtx.GetFromAddress()) - if err := msg.ValidateBasic(); err != nil { - return err - } - - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) - }, - } - - cmd = client.PostCommands(cmd)[0] - return cmd -} diff --git a/x/ibc/mock/bank/handler.go b/x/ibc/mock/bank/handler.go deleted file mode 100644 index 2ed32c4c837e..000000000000 --- a/x/ibc/mock/bank/handler.go +++ /dev/null @@ -1,26 +0,0 @@ -package mockbank - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func NewHandler(k Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case MsgRecvPacket: - return handleMsgRecvPacket(ctx, k, msg) - default: - return sdk.ErrUnknownRequest("failed to parse message").Result() - } - } -} - -// handleMsgRecvPacket defines the sdk.Handler for MsgRecvPacket -func handleMsgRecvPacket(ctx sdk.Context, k Keeper, msg MsgRecvPacket) (res sdk.Result) { - err := k.ReceivePacket(ctx, msg.Packet, msg.Proofs[0], msg.Height) - if err != nil { - return sdk.ResultFromError(err) - } - - return sdk.Result{Events: ctx.EventManager().Events()} -} diff --git a/x/ibc/mock/bank/internal/keeper/keeper.go b/x/ibc/mock/bank/internal/keeper/keeper.go deleted file mode 100644 index bdcabcf53e94..000000000000 --- a/x/ibc/mock/bank/internal/keeper/keeper.go +++ /dev/null @@ -1,44 +0,0 @@ -package keeper - -import ( - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/cosmos/cosmos-sdk/x/ibc/mock/bank/internal/types" -) - -type Keeper struct { - cdc *codec.Codec - key sdk.StoreKey - ck types.ChannelKeeper - bk types.IbcBankKeeper -} - -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ck types.ChannelKeeper, bk types.IbcBankKeeper) Keeper { - return Keeper{ - cdc: cdc, - key: key, - ck: ck, - bk: bk, - } -} - -// ReceivePacket handles receiving packet -func (k Keeper) ReceivePacket(ctx sdk.Context, packet channelexported.PacketI, proof commitment.ProofI, height uint64) error { - _, err := k.ck.RecvPacket(ctx, packet, proof, height, nil, k.key) - if err != nil { - return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeErrReceivePacket, "failed to receive packet") - } - - // only process ICS20 token transfer packet data now, - // that should be done in routing module. - var data transfer.PacketData - err = data.UnmarshalJSON(packet.Data()) - if err != nil { - return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeInvalidPacketData, "invalid packet data") - } - - return k.bk.ReceiveTransfer(ctx, packet.SourcePort(), packet.SourceChannel(), packet.DestPort(), packet.DestChannel(), data) -} diff --git a/x/ibc/mock/bank/internal/types/codec.go b/x/ibc/mock/bank/internal/types/codec.go deleted file mode 100644 index ba05f5bb00f7..000000000000 --- a/x/ibc/mock/bank/internal/types/codec.go +++ /dev/null @@ -1,19 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" - channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(MsgRecvPacket{}, "ibcmockbank/MsgRecvPacket", nil) -} - -var ModuleCdc = codec.New() - -func init() { - RegisterCodec(ModuleCdc) - channel.RegisterCodec(ModuleCdc) - commitment.RegisterCodec(ModuleCdc) -} diff --git a/x/ibc/mock/bank/internal/types/errors.go b/x/ibc/mock/bank/internal/types/errors.go deleted file mode 100644 index 09cfc89784ff..000000000000 --- a/x/ibc/mock/bank/internal/types/errors.go +++ /dev/null @@ -1,15 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// ibcmockbank errors reserve 100 ~ 199. -const ( - DefaultCodespace sdk.CodespaceType = ModuleName - - CodeInvalidAddress sdk.CodeType = 101 - CodeErrReceivePacket sdk.CodeType = 102 - CodeProofMissing sdk.CodeType = 103 - CodeInvalidPacketData sdk.CodeType = 104 -) diff --git a/x/ibc/mock/bank/internal/types/expected_keepers.go b/x/ibc/mock/bank/internal/types/expected_keepers.go deleted file mode 100644 index 4c6e8e149169..000000000000 --- a/x/ibc/mock/bank/internal/types/expected_keepers.go +++ /dev/null @@ -1,25 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -// IbcBankKeeper expected IBC transfer keeper -type IbcBankKeeper interface { - ReceiveTransfer(ctx sdk.Context, srcPort, srcChannel, destPort, destChannel string, data transfer.PacketData) error -} - -// ChannelKeeper expected IBC channel keeper -type ChannelKeeper interface { - RecvPacket( - ctx sdk.Context, - packet exported.PacketI, - proof commitment.ProofI, - proofHeight uint64, - acknowledgement []byte, - portCapability sdk.CapabilityKey, - ) (exported.PacketI, error) -} diff --git a/x/ibc/mock/bank/internal/types/keys.go b/x/ibc/mock/bank/internal/types/keys.go deleted file mode 100644 index 2ffaa38eaa29..000000000000 --- a/x/ibc/mock/bank/internal/types/keys.go +++ /dev/null @@ -1,15 +0,0 @@ -package types - -const ( - // ModuleName is the name of the module - ModuleName = "ibcmockbank" - - // StoreKey is the string store representation - StoreKey = ModuleName - - // QuerierRoute is the querier route for the module - QuerierRoute = ModuleName - - // RouterKey is the msg router key for the module - RouterKey = ModuleName -) diff --git a/x/ibc/mock/bank/internal/types/msgs.go b/x/ibc/mock/bank/internal/types/msgs.go deleted file mode 100644 index 61d414591e34..000000000000 --- a/x/ibc/mock/bank/internal/types/msgs.go +++ /dev/null @@ -1,61 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -type MsgRecvPacket struct { - Packet channel.PacketI `json:"packet" yaml:"packet"` - Proofs []commitment.Proof `json:"proofs" yaml:"proofs"` - Height uint64 `json:"height" yaml:"height"` - Signer sdk.AccAddress `json:"signer" yaml:"signer"` -} - -// NewMsgRecvPacket creates a new MsgRecvPacket instance -func NewMsgRecvPacket(packet channel.PacketI, proofs []commitment.Proof, height uint64, signer sdk.AccAddress) MsgRecvPacket { - return MsgRecvPacket{ - Packet: packet, - Proofs: proofs, - Height: height, - Signer: signer, - } -} - -// Route implements sdk.Msg -func (MsgRecvPacket) Route() string { - return RouterKey -} - -// Type implements sdk.Msg -func (MsgRecvPacket) Type() string { - return "recv_packet" -} - -// ValidateBasic implements sdk.Msg -func (msg MsgRecvPacket) ValidateBasic() sdk.Error { - if msg.Proofs == nil { - return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeProofMissing, "proof missing") - } - - if msg.Signer.Empty() { - return sdk.NewError(sdk.CodespaceType(DefaultCodespace), CodeInvalidAddress, "invalid signer") - } - - if err := msg.Packet.ValidateBasic(); err != nil { - return err - } - - return nil -} - -// GetSignBytes implements sdk.Msg -func (msg MsgRecvPacket) GetSignBytes() []byte { - return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) -} - -// GetSigners implements sdk.Msg -func (msg MsgRecvPacket) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} diff --git a/x/ibc/mock/bank/module.go b/x/ibc/mock/bank/module.go deleted file mode 100644 index e033d1de5666..000000000000 --- a/x/ibc/mock/bank/module.go +++ /dev/null @@ -1,110 +0,0 @@ -package mockbank - -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/bank/client/cli" -) - -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) { - RegisterCdc(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 nil -} - -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{} -} - -// GetTxCmd returns the root tx command for the ibc-channel module. -func GetTxCmd(cdc *codec.Codec) *cobra.Command { - return cli.GetTxCmd(cdc) -} From d5363c083b010c4e5b8e968c4d1f7a8c7f1989f8 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 30 Oct 2019 16:07:54 +0100 Subject: [PATCH 355/378] setup ics20 test suite --- x/ibc/20-transfer/keeper/keeper_test.go | 35 +++++++++++++++++++++++++ x/ibc/20-transfer/keeper/relay_test.go | 6 +++++ 2 files changed, 41 insertions(+) create mode 100644 x/ibc/20-transfer/keeper/keeper_test.go create mode 100644 x/ibc/20-transfer/keeper/relay_test.go diff --git a/x/ibc/20-transfer/keeper/keeper_test.go b/x/ibc/20-transfer/keeper/keeper_test.go new file mode 100644 index 000000000000..77c423052098 --- /dev/null +++ b/x/ibc/20-transfer/keeper/keeper_test.go @@ -0,0 +1,35 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/keeper" +) + +type KeeperTestSuite struct { + suite.Suite + + cdc *codec.Codec + ctx sdk.Context + keeper *keeper.Keeper +} + +func (suite *KeeperTestSuite) SetupTest() { + isCheckTx := false + app := simapp.Setup(isCheckTx) + + suite.cdc = app.Codec() + suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{}) + suite.keeper = &app.IBCKeeper.TransferKeeper +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} diff --git a/x/ibc/20-transfer/keeper/relay_test.go b/x/ibc/20-transfer/keeper/relay_test.go new file mode 100644 index 000000000000..e6aa98f9eacd --- /dev/null +++ b/x/ibc/20-transfer/keeper/relay_test.go @@ -0,0 +1,6 @@ +package keeper_test + +func (suite *KeeperTestSuite) TestSendTransfer() { + err := suite.keeper.SendTransfer(suite.ctx, "", "", nil, nil, nil, true) + suite.Error(err) +} From b772c8e6dec276aeab16e447080de050b77c204a Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 30 Oct 2019 16:10:21 +0100 Subject: [PATCH 356/378] add event to MsgRecvPacket --- x/ibc/20-transfer/handler.go | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/x/ibc/20-transfer/handler.go b/x/ibc/20-transfer/handler.go index 49fe077acbe2..731a6c27e7f5 100644 --- a/x/ibc/20-transfer/handler.go +++ b/x/ibc/20-transfer/handler.go @@ -5,19 +5,28 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" ) -// handleMsgRecvPacket defines the sdk.Handler for MsgRecvPacket -func HandleMsgRecvPacket(ctx sdk.Context, k Keeper, msg MsgRecvPacket) (res sdk.Result) { - err := k.ReceivePacket(ctx, msg.Packet, msg.Proofs[0], msg.Height) +// HandleMsgTransfer defines the sdk.Handler for MsgTransfer +func HandleMsgTransfer(ctx sdk.Context, k Keeper, msg MsgTransfer) (res sdk.Result) { + err := k.SendTransfer(ctx, msg.SourcePort, msg.SourceChannel, msg.Amount, msg.Sender, msg.Receiver, msg.Source) if err != nil { return sdk.ResultFromError(err) } + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), + sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver.String()), + ), + ) + return sdk.Result{Events: ctx.EventManager().Events()} } -// HandleMsgTransfer defines the sdk.Handler for MsgTransfer -func HandleMsgTransfer(ctx sdk.Context, k Keeper, msg MsgTransfer) (res sdk.Result) { - err := k.SendTransfer(ctx, msg.SourcePort, msg.SourceChannel, msg.Amount, msg.Sender, msg.Receiver, msg.Source) +// HandleMsgRecvPacket defines the sdk.Handler for MsgRecvPacket +func HandleMsgRecvPacket(ctx sdk.Context, k Keeper, msg MsgRecvPacket) (res sdk.Result) { + err := k.ReceivePacket(ctx, msg.Packet, msg.Proofs[0], msg.Height) if err != nil { return sdk.ResultFromError(err) } @@ -26,9 +35,9 @@ func HandleMsgTransfer(ctx sdk.Context, k Keeper, msg MsgTransfer) (res sdk.Resu sdk.NewEvent( sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), - sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver.String()), - )) + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + ) return sdk.Result{Events: ctx.EventManager().Events()} } From 76552785abff41e733a36a4e53900dd9953fc2ab Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 30 Oct 2019 16:18:43 +0100 Subject: [PATCH 357/378] update ibc keeper test to use test suite --- x/ibc/keeper/integration_test.go | 15 ------------- x/ibc/keeper/keeper_test.go | 37 ++++++++++++++++++++++++++++++++ x/ibc/keeper/querier_test.go | 14 +++++------- 3 files changed, 42 insertions(+), 24 deletions(-) delete mode 100644 x/ibc/keeper/integration_test.go create mode 100644 x/ibc/keeper/keeper_test.go diff --git a/x/ibc/keeper/integration_test.go b/x/ibc/keeper/integration_test.go deleted file mode 100644 index 811d4c5d87ae..000000000000 --- a/x/ibc/keeper/integration_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package keeper_test - -import ( - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/simapp" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// returns context and an app with updated mint keeper -func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) { - app := simapp.Setup(isCheckTx) - ctx := app.BaseApp.NewContext(isCheckTx, abci.Header{}) - return app, ctx -} diff --git a/x/ibc/keeper/keeper_test.go b/x/ibc/keeper/keeper_test.go new file mode 100644 index 000000000000..4aee65b6db9e --- /dev/null +++ b/x/ibc/keeper/keeper_test.go @@ -0,0 +1,37 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/keeper" +) + +type KeeperTestSuite struct { + suite.Suite + + cdc *codec.Codec + ctx sdk.Context + keeper *keeper.Keeper + querier sdk.Querier +} + +func (suite *KeeperTestSuite) SetupTest() { + isCheckTx := false + app := simapp.Setup(isCheckTx) + + suite.cdc = app.Codec() + suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{}) + suite.keeper = &app.IBCKeeper + suite.querier = keeper.NewQuerier(app.IBCKeeper) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} diff --git a/x/ibc/keeper/querier_test.go b/x/ibc/keeper/querier_test.go index 52b70f70b921..62e37faac203 100644 --- a/x/ibc/keeper/querier_test.go +++ b/x/ibc/keeper/querier_test.go @@ -2,23 +2,19 @@ package keeper_test import ( "fmt" - "testing" "github.com/stretchr/testify/require" 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/keeper" abci "github.com/tendermint/tendermint/abci/types" ) // TestNewQuerier tests that the querier paths are correct. // NOTE: the actuall testing functionallity are located on each ICS querier test. -func TestNewQuerier(t *testing.T) { - app, ctx := createTestApp(true) - querier := keeper.NewQuerier(app.IBCKeeper) +func (suite *KeeperTestSuite) TestNewQuerier() { query := abci.RequestQuery{ Path: "", @@ -94,12 +90,12 @@ func TestNewQuerier(t *testing.T) { for i, tc := range cases { i, tc := i, tc - t.Run(tc.name, func(t *testing.T) { - _, err := querier(ctx, tc.path, query) + suite.Run(tc.name, func() { + _, err := suite.querier(suite.ctx, tc.path, query) if tc.expectsDefaultErr { - require.Contains(t, err.Error(), tc.errMsg, "test case #%d", i) + require.Contains(suite.T(), err.Error(), tc.errMsg, "test case #%d", i) } else { - require.Error(t, err, "test case #%d", i) + suite.Error(err, "test case #%d", i) } }) } From 64b09cbb9e6968608fcc28c6161158edc113b62e Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Wed, 30 Oct 2019 10:10:54 -0700 Subject: [PATCH 358/378] Add handshake commands --- x/ibc/02-client/client/cli/query.go | 4 +- x/ibc/03-connection/client/cli/tx.go | 233 +++++++++++++++++++++++++++ x/ibc/03-connection/module.go | 2 +- 3 files changed, 235 insertions(+), 4 deletions(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 1fa7cccb3243..c75ece2481d5 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -268,9 +268,7 @@ $ %s query ibc client node-state NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), } - fmt.Printf("%s\n", codec.MustMarshalJSONIndent(cdc, state)) - - return nil + return cliCtx.PrintOutput(state) }, } } diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index fd84a542f6ed..08960d74cc3b 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -259,3 +259,236 @@ func lastHeight(cliCtx context.CLIContext) (uint64, error) { return uint64(info.Response.LastBlockHeight), nil } + +// func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { +// cmd := &cobra.Command{ +// Use: "handshake [conn-id-chain-1] [client-id-chain-1] [path-chain-1] [conn-id-chain-2] [client-id-chain-2] [path-chain-2] ", +// Short: "initiate connection handshake between two chains", +// Args: cobra.ExactArgs(6), +// RunE: func(cmd *cobra.Command, args []string) error { +// // --chain-id values for each chain +// cid1 := viper.GetString(flags.FlagChainID) +// cid2 := viper.GetString(FlagChainID2) + +// // --from values for each wallet +// from1 := viper.GetString(FlagFrom1) +// from2 := viper.GetString(FlagFrom2) + +// // --node values for each RPC +// rpc1 := viper.GetString(FlagNode1) +// rpc2 := viper.GetString(FlagNode2) + +// // ibc connection-id for each chain +// connID1 := args[0] +// connID2 := args[3] + +// // ibc client-id for each chain +// clientID1 := args[1] +// clientID2 := args[4] + +// // Create txbldr, clictx, querier for cid1 +// viper.Set(flags.FlagChainID, cid1) +// txBldr1 := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) +// ctx1 := context.NewCLIContextIBC(from1, cid1, rpc1).WithCodec(cdc). +// WithBroadcastMode(flags.BroadcastBlock) +// q1 := storestate.NewCLIQuerier(ctx1) + +// // Create txbldr, clictx, querier for cid1 +// viper.Set(flags.FlagChainID, cid2) +// txBldr2 := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) +// ctx2 := context.NewCLIContextIBC(from2, cid2, rpc2).WithCodec(cdc). +// WithBroadcastMode(flags.BroadcastBlock) +// q2 := storestate.NewCLIQuerier(ctx2) + +// // get passphrase for key from1 +// passphrase1, err := keys.GetPassphrase(from1) +// if err != nil { +// return err +// } + +// // get passphrase for key from2 +// passphrase2, err := keys.GetPassphrase(from2) +// if err != nil { +// return err +// } + +// // read in path for cid1 +// path1, err := parsePath(ctx1.Codec, args[2]) +// if err != nil { +// return err +// } + +// // read in path for cid2 +// path2, err := parsePath(ctx1.Codec, args[5]) +// if err != nil { +// return err +// } + +// // Create connection objects for each chain +// conn1 := connection.NewConnection(clientID1, connID2, path1) +// conn2 := connection.NewConnection(clientID2, connID1, path2) + +// // Fetch handshake state object for cid1 +// hs1, err := handshakeState(q1, cdc, storeKey, version.DefaultPrefix(), connID1) +// if err != nil { +// return err +// } + +// // Fetch handshake state object for cid2 +// hs2, err := handshakeState(q2, cdc, storeKey, version.DefaultPrefix(), connID2) +// if err != nil { +// return err +// } + +// // TODO: check state and if not Idle continue existing process +// // Create and send msgOpenInit +// viper.Set(flags.FlagChainID, cid1) +// msgOpenInit := connection.NewMsgOpenInit(connID1, conn1, conn2.Client, 0, ctx1.GetFromAddress()) +// fmt.Printf("%v <- %-14v", cid1, msgOpenInit.Type()) +// res, err := utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgOpenInit}, passphrase1) +// if err != nil || !res.IsOK() { +// fmt.Println(res) +// return err +// } +// fmt.Printf(" [OK] txid(%v) client(%v) conn(%v)\n", res.TxHash, conn2.Client, connID1) + +// // Another block has to be passed after msgOpenInit 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 +// } + +// // Create and send msgUpdateClient +// viper.Set(flags.FlagChainID, cid2) +// msgUpdateClient := client.NewMsgUpdateClient(conn2.Client, header, ctx2.GetFromAddress()) +// fmt.Printf("%v <- %-14v", cid2, msgUpdateClient.Type()) +// res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}, passphrase2) +// if err != nil || !res.IsOK() { +// fmt.Println(res) +// return err +// } +// fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, conn2.Client) + +// // Fetch proofs from cid1 +// viper.Set(flags.FlagChainID, cid1) +// q1 = storestate.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) +// proofs, err := queryProofs(hs1, q1) +// if err != nil { +// return err +// } + +// // Create and send msgOpenTry +// viper.Set(flags.FlagChainID, cid2) +// msgOpenTry := connection.NewMsgOpenTry(connID2, conn2, conn1.Client, 0, 0, proofs, uint64(header.Height),ctx2.GetFromAddress()) +// fmt.Printf("%v <- %-14v", cid2, msgOpenTry.Type()) +// res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgOpenTry}, passphrase2) +// if err != nil || !res.IsOK() { +// fmt.Println(res) +// return err +// } +// fmt.Printf(" [OK] txid(%v) client(%v) connection(%v)\n", res.TxHash, conn1.Client, connID2) + +// // Another block has to be passed after msgOpenInit 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 +// } + +// // Update the client for cid2 on cid1 +// viper.Set(flags.FlagChainID, cid1) +// msgUpdateClient = client.NewMsgUpdateClient(conn1.Client, header, ctx1.GetFromAddress()) +// fmt.Printf("%v <- %-14v", cid1, msgUpdateClient.Type()) +// res, err = utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgUpdateClient}, passphrase1) +// if err != nil || !res.IsOK() { +// fmt.Println(res) +// return err +// } +// fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, conn1.Client) + +// // Fetch proofs from cid2 +// viper.Set(flags.FlagChainID, cid2) +// q2 = storestate.NewCLIQuerier(ctx2.WithHeight(header.Height - 1)) +// proofs, err = queryProofs(hs2, q2) +// if err != nil { +// return err +// } + +// // Create and send msgOpenAck +// viper.Set(flags.FlagChainID, cid1) +// msgOpenAck := connection.NewMsgOpenAck(connID1, 0, 0, proofs, uint64(header.Height), ctx1.GetFromAddress()) +// fmt.Printf("%v <- %-14v", cid1, msgOpenAck.Type()) +// res, err = utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgOpenAck}, passphrase1) +// if err != nil || !res.IsOK() { +// fmt.Println(res) +// return err +// } +// fmt.Printf(" [OK] txid(%v) connection(%v)\n", res.TxHash, connID1) + +// // Another block has to be passed after msgOpenInit 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 +// } + +// // Update client for cid1 on cid2 +// viper.Set(flags.FlagChainID, cid2) +// msgUpdateClient = client.NewMsgUpdateClient(conn2.Client, header, ctx2.GetFromAddress()) +// fmt.Printf("%v <- %-14v", cid2, msgUpdateClient.Type()) +// res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}, passphrase2) +// if err != nil || !res.IsOK() { +// fmt.Println(res) +// return err +// } +// fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, conn2.Client) + +// // Fetch proof from cid1 +// viper.Set(flags.FlagChainID, cid1) +// q1 = storestate.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) +// _, pstate, err := hs1.StageCLI(q1) +// if err != nil { +// return err +// } + +// // Create and send msgOpenConfirm +// viper.Set(flags.FlagChainID, cid2) +// msgOpenConfirm := connection.NewMsgOpenConfirm(connID2, 0, []commitment.Proof{pstate}, uint64(header.Height), ctx2.GetFromAddress()) +// fmt.Printf("%v <- %-14v", cid1, msgOpenConfirm.Type()) +// res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgOpenConfirm}, passphrase2) +// if err != nil || !res.IsOK() { +// return err +// } +// fmt.Printf(" [OK] txid(%v) connection(%v)\n", res.TxHash, connID2) + +// return nil +// }, +// } + +// cmd.Flags().String(FlagNode1, "tcp://localhost:26657", "RPC port for the first chain") +// cmd.Flags().String(FlagNode2, "tcp://localhost:26657", "RPC port for the second chain") +// cmd.Flags().String(FlagFrom1, "", "key in local keystore for first chain") +// cmd.Flags().String(FlagFrom2, "", "key in local keystore for second chain") +// cmd.Flags().String(FlagChainID2, "", "chain-id for the second chain") + +// cmd.MarkFlagRequired(FlagNode1) +// cmd.MarkFlagRequired(FlagNode2) +// cmd.MarkFlagRequired(FlagFrom1) +// cmd.MarkFlagRequired(FlagFrom2) +// cmd.MarkFlagRequired(FlagChainID2) + +// return cmd +// } diff --git a/x/ibc/03-connection/module.go b/x/ibc/03-connection/module.go index 5a7c83297c8f..713ed04d6c6b 100644 --- a/x/ibc/03-connection/module.go +++ b/x/ibc/03-connection/module.go @@ -6,7 +6,7 @@ import ( "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/cli" ) // Name returns the IBC connection ICS name From 600ab595e54de3da9ed43cd582a4a71a4087b438 Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Wed, 30 Oct 2019 12:32:20 -0700 Subject: [PATCH 359/378] WIP connection handshake --- client/context/context.go | 47 +++ types/result.go | 9 + x/auth/client/utils/tx.go | 39 ++ x/ibc/03-connection/client/cli/tx.go | 539 +++++++++++++++------------ 4 files changed, 402 insertions(+), 232 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index 2fd6ff66f8be..07168ecdf6ca 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -99,6 +99,53 @@ func NewCLIContextWithFrom(from string) CLIContext { return ctx.WithVerifier(verifier) } +// NewCLIContextIBC takes additional arguements +func NewCLIContextIBC(from string, chainID string, nodeURI string) CLIContext { + var rpc rpcclient.Client + + genOnly := viper.GetBool(flags.FlagGenerateOnly) + fromAddress, fromName, err := GetFromFields(from, genOnly) + if err != nil { + fmt.Printf("failed to get from fields: %v", err) + os.Exit(1) + } + + if !genOnly { + if nodeURI != "" { + rpc = rpcclient.NewHTTP(nodeURI, "/websocket") + } + } + + ctx := CLIContext{ + Client: rpc, + ChainID: chainID, + Output: os.Stdout, + NodeURI: nodeURI, + From: from, + OutputFormat: viper.GetString(cli.OutputFlag), + Height: viper.GetInt64(flags.FlagHeight), + HomeDir: viper.GetString(flags.FlagHome), + TrustNode: viper.GetBool(flags.FlagTrustNode), + UseLedger: viper.GetBool(flags.FlagUseLedger), + BroadcastMode: viper.GetString(flags.FlagBroadcastMode), + Simulate: viper.GetBool(flags.FlagDryRun), + GenerateOnly: genOnly, + FromAddress: fromAddress, + FromName: fromName, + Indent: viper.GetBool(flags.FlagIndentResponse), + SkipConfirm: viper.GetBool(flags.FlagSkipConfirmation), + } + + // create a verifier for the specific chain ID and RPC client + verifier, err := CreateVerifier(ctx, DefaultVerifierCacheSize) + if err != nil && viper.IsSet(flags.FlagTrustNode) { + fmt.Printf("failed to create verifier: %s\n", err) + os.Exit(1) + } + + return ctx.WithVerifier(verifier) +} + // NewCLIContext returns a new initialized CLIContext with parameters from the // command line using Viper. func NewCLIContext() CLIContext { return NewCLIContextWithFrom(viper.GetString(flags.FlagFrom)) } diff --git a/types/result.go b/types/result.go index 41a31b84ba3c..5821cab538bc 100644 --- a/types/result.go +++ b/types/result.go @@ -100,6 +100,15 @@ type TxResponse struct { Events StringEvents `json:"events,omitempty"` } +func (res TxResponse) IsOK() bool { + for _, lg := range res.Logs { + if !lg.Success { + return false + } + } + return true +} + // NewResponseResultTx returns a TxResponse given a ResultTx from tendermint func NewResponseResultTx(res *ctypes.ResultTx, tx Tx, timestamp string) TxResponse { if res == nil { diff --git a/x/auth/client/utils/tx.go b/x/auth/client/utils/tx.go index d2212a039ad4..ccba257d4ded 100644 --- a/x/auth/client/utils/tx.go +++ b/x/auth/client/utils/tx.go @@ -113,6 +113,45 @@ func CompleteAndBroadcastTxCLI(txBldr authtypes.TxBuilder, cliCtx context.CLICon return cliCtx.PrintOutput(res) } +// CompleteAndBroadcastTx implements a utility function that facilitates +// sending a series of messages in a signed transaction given a TxBuilder and a +// QueryContext. It ensures that the account exists, has a proper number and +// sequence set. In addition, it builds and signs a transaction non-interactively +// with the supplied messages. Finally, it broadcasts the signed transaction to a node. +func CompleteAndBroadcastTx(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg, passphrase string) (sdk.TxResponse, error) { + var res sdk.TxResponse + txBldr, err := PrepareTxBuilder(txBldr, cliCtx) + if err != nil { + return res, err + } + + fromName := cliCtx.GetFromName() + + if txBldr.SimulateAndExecute() || cliCtx.Simulate { + txBldr, err = EnrichWithGas(txBldr, cliCtx, msgs) + if err != nil { + return res, err + } + + gasEst := GasEstimateResponse{GasEstimate: txBldr.Gas()} + _, _ = fmt.Fprintf(os.Stderr, "%s\n", gasEst.String()) + } + + // build and sign the transaction + txBytes, err := txBldr.BuildAndSign(fromName, passphrase, msgs) + if err != nil { + return res, err + } + + // broadcast to a Tendermint node + res, err = cliCtx.BroadcastTx(txBytes) + if err != nil { + return res, err + } + + return res, err +} + // EnrichWithGas calculates the gas estimate that would be consumed by the // transaction and set the transaction's respective value accordingly. func EnrichWithGas(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (authtypes.TxBuilder, error) { diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index 08960d74cc3b..856d2c461371 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -3,7 +3,9 @@ package cli import ( "fmt" "io/ioutil" + "os" "strings" + "time" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -11,13 +13,26 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" +) + +const ( + FlagNode1 = "node1" + FlagNode2 = "node2" + FlagFrom1 = "from1" + FlagFrom2 = "from2" + FlagChainID2 = "chain-id2" ) // GetTxCmd returns the transaction commands for IBC Connections @@ -260,235 +275,295 @@ func lastHeight(cliCtx context.CLIContext) (uint64, error) { return uint64(info.Response.LastBlockHeight), nil } -// func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { -// cmd := &cobra.Command{ -// Use: "handshake [conn-id-chain-1] [client-id-chain-1] [path-chain-1] [conn-id-chain-2] [client-id-chain-2] [path-chain-2] ", -// Short: "initiate connection handshake between two chains", -// Args: cobra.ExactArgs(6), -// RunE: func(cmd *cobra.Command, args []string) error { -// // --chain-id values for each chain -// cid1 := viper.GetString(flags.FlagChainID) -// cid2 := viper.GetString(FlagChainID2) - -// // --from values for each wallet -// from1 := viper.GetString(FlagFrom1) -// from2 := viper.GetString(FlagFrom2) - -// // --node values for each RPC -// rpc1 := viper.GetString(FlagNode1) -// rpc2 := viper.GetString(FlagNode2) - -// // ibc connection-id for each chain -// connID1 := args[0] -// connID2 := args[3] - -// // ibc client-id for each chain -// clientID1 := args[1] -// clientID2 := args[4] - -// // Create txbldr, clictx, querier for cid1 -// viper.Set(flags.FlagChainID, cid1) -// txBldr1 := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) -// ctx1 := context.NewCLIContextIBC(from1, cid1, rpc1).WithCodec(cdc). -// WithBroadcastMode(flags.BroadcastBlock) -// q1 := storestate.NewCLIQuerier(ctx1) - -// // Create txbldr, clictx, querier for cid1 -// viper.Set(flags.FlagChainID, cid2) -// txBldr2 := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) -// ctx2 := context.NewCLIContextIBC(from2, cid2, rpc2).WithCodec(cdc). -// WithBroadcastMode(flags.BroadcastBlock) -// q2 := storestate.NewCLIQuerier(ctx2) - -// // get passphrase for key from1 -// passphrase1, err := keys.GetPassphrase(from1) -// if err != nil { -// return err -// } - -// // get passphrase for key from2 -// passphrase2, err := keys.GetPassphrase(from2) -// if err != nil { -// return err -// } - -// // read in path for cid1 -// path1, err := parsePath(ctx1.Codec, args[2]) -// if err != nil { -// return err -// } - -// // read in path for cid2 -// path2, err := parsePath(ctx1.Codec, args[5]) -// if err != nil { -// return err -// } - -// // Create connection objects for each chain -// conn1 := connection.NewConnection(clientID1, connID2, path1) -// conn2 := connection.NewConnection(clientID2, connID1, path2) - -// // Fetch handshake state object for cid1 -// hs1, err := handshakeState(q1, cdc, storeKey, version.DefaultPrefix(), connID1) -// if err != nil { -// return err -// } - -// // Fetch handshake state object for cid2 -// hs2, err := handshakeState(q2, cdc, storeKey, version.DefaultPrefix(), connID2) -// if err != nil { -// return err -// } - -// // TODO: check state and if not Idle continue existing process -// // Create and send msgOpenInit -// viper.Set(flags.FlagChainID, cid1) -// msgOpenInit := connection.NewMsgOpenInit(connID1, conn1, conn2.Client, 0, ctx1.GetFromAddress()) -// fmt.Printf("%v <- %-14v", cid1, msgOpenInit.Type()) -// res, err := utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgOpenInit}, passphrase1) -// if err != nil || !res.IsOK() { -// fmt.Println(res) -// return err -// } -// fmt.Printf(" [OK] txid(%v) client(%v) conn(%v)\n", res.TxHash, conn2.Client, connID1) - -// // Another block has to be passed after msgOpenInit 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 -// } - -// // Create and send msgUpdateClient -// viper.Set(flags.FlagChainID, cid2) -// msgUpdateClient := client.NewMsgUpdateClient(conn2.Client, header, ctx2.GetFromAddress()) -// fmt.Printf("%v <- %-14v", cid2, msgUpdateClient.Type()) -// res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}, passphrase2) -// if err != nil || !res.IsOK() { -// fmt.Println(res) -// return err -// } -// fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, conn2.Client) - -// // Fetch proofs from cid1 -// viper.Set(flags.FlagChainID, cid1) -// q1 = storestate.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) -// proofs, err := queryProofs(hs1, q1) -// if err != nil { -// return err -// } - -// // Create and send msgOpenTry -// viper.Set(flags.FlagChainID, cid2) -// msgOpenTry := connection.NewMsgOpenTry(connID2, conn2, conn1.Client, 0, 0, proofs, uint64(header.Height),ctx2.GetFromAddress()) -// fmt.Printf("%v <- %-14v", cid2, msgOpenTry.Type()) -// res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgOpenTry}, passphrase2) -// if err != nil || !res.IsOK() { -// fmt.Println(res) -// return err -// } -// fmt.Printf(" [OK] txid(%v) client(%v) connection(%v)\n", res.TxHash, conn1.Client, connID2) - -// // Another block has to be passed after msgOpenInit 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 -// } - -// // Update the client for cid2 on cid1 -// viper.Set(flags.FlagChainID, cid1) -// msgUpdateClient = client.NewMsgUpdateClient(conn1.Client, header, ctx1.GetFromAddress()) -// fmt.Printf("%v <- %-14v", cid1, msgUpdateClient.Type()) -// res, err = utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgUpdateClient}, passphrase1) -// if err != nil || !res.IsOK() { -// fmt.Println(res) -// return err -// } -// fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, conn1.Client) - -// // Fetch proofs from cid2 -// viper.Set(flags.FlagChainID, cid2) -// q2 = storestate.NewCLIQuerier(ctx2.WithHeight(header.Height - 1)) -// proofs, err = queryProofs(hs2, q2) -// if err != nil { -// return err -// } - -// // Create and send msgOpenAck -// viper.Set(flags.FlagChainID, cid1) -// msgOpenAck := connection.NewMsgOpenAck(connID1, 0, 0, proofs, uint64(header.Height), ctx1.GetFromAddress()) -// fmt.Printf("%v <- %-14v", cid1, msgOpenAck.Type()) -// res, err = utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgOpenAck}, passphrase1) -// if err != nil || !res.IsOK() { -// fmt.Println(res) -// return err -// } -// fmt.Printf(" [OK] txid(%v) connection(%v)\n", res.TxHash, connID1) - -// // Another block has to be passed after msgOpenInit 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 -// } - -// // Update client for cid1 on cid2 -// viper.Set(flags.FlagChainID, cid2) -// msgUpdateClient = client.NewMsgUpdateClient(conn2.Client, header, ctx2.GetFromAddress()) -// fmt.Printf("%v <- %-14v", cid2, msgUpdateClient.Type()) -// res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}, passphrase2) -// if err != nil || !res.IsOK() { -// fmt.Println(res) -// return err -// } -// fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, conn2.Client) - -// // Fetch proof from cid1 -// viper.Set(flags.FlagChainID, cid1) -// q1 = storestate.NewCLIQuerier(ctx1.WithHeight(header.Height - 1)) -// _, pstate, err := hs1.StageCLI(q1) -// if err != nil { -// return err -// } - -// // Create and send msgOpenConfirm -// viper.Set(flags.FlagChainID, cid2) -// msgOpenConfirm := connection.NewMsgOpenConfirm(connID2, 0, []commitment.Proof{pstate}, uint64(header.Height), ctx2.GetFromAddress()) -// fmt.Printf("%v <- %-14v", cid1, msgOpenConfirm.Type()) -// res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgOpenConfirm}, passphrase2) -// if err != nil || !res.IsOK() { -// return err -// } -// fmt.Printf(" [OK] txid(%v) connection(%v)\n", res.TxHash, connID2) - -// return nil -// }, -// } - -// cmd.Flags().String(FlagNode1, "tcp://localhost:26657", "RPC port for the first chain") -// cmd.Flags().String(FlagNode2, "tcp://localhost:26657", "RPC port for the second chain") -// cmd.Flags().String(FlagFrom1, "", "key in local keystore for first chain") -// cmd.Flags().String(FlagFrom2, "", "key in local keystore for second chain") -// cmd.Flags().String(FlagChainID2, "", "chain-id for the second chain") - -// cmd.MarkFlagRequired(FlagNode1) -// cmd.MarkFlagRequired(FlagNode2) -// cmd.MarkFlagRequired(FlagFrom1) -// cmd.MarkFlagRequired(FlagFrom2) -// cmd.MarkFlagRequired(FlagChainID2) - -// return cmd -// } +func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "handshake [conn-id-chain-1] [client-id-chain-1] [path-chain-1] [conn-id-chain-2] [client-id-chain-2] [path-chain-2] ", + Short: "initiate connection handshake between two chains", + Args: cobra.ExactArgs(6), + RunE: func(cmd *cobra.Command, args []string) error { + // --chain-id values for each chain + cid1 := viper.GetString(flags.FlagChainID) + cid2 := viper.GetString(FlagChainID2) + + // --from values for each wallet + from1 := viper.GetString(FlagFrom1) + from2 := viper.GetString(FlagFrom2) + + // --node values for each RPC + rpc1 := viper.GetString(FlagNode1) + rpc2 := viper.GetString(FlagNode2) + + // ibc connection-id for each chain + connID1 := args[0] + connID2 := args[3] + + // ibc client-id for each chain + clientID1 := args[1] + clientID2 := args[4] + + // Create txbldr, clictx, querier for cid1 + viper.Set(flags.FlagChainID, cid1) + txBldr1 := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + ctx1 := context.NewCLIContextIBC(from1, cid1, rpc1).WithCodec(cdc). + WithBroadcastMode(flags.BroadcastBlock) + + // Create txbldr, clictx, querier for cid1 + viper.Set(flags.FlagChainID, cid2) + txBldr2 := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + ctx2 := context.NewCLIContextIBC(from2, cid2, rpc2).WithCodec(cdc). + WithBroadcastMode(flags.BroadcastBlock) + + // read in path for cid1 + _, err := parsePath(ctx1.Codec, args[2]) + if err != nil { + return err + } + + // read in path for cid2 + path2, err := parsePath(ctx1.Codec, args[5]) + if err != nil { + return err + } + + // get passphrase for key from1 + passphrase1, err := keys.GetPassphrase(from1) + if err != nil { + return err + } + + // get passphrase for key from2 + passphrase2, err := keys.GetPassphrase(from2) + if err != nil { + return err + } + + viper.Set(flags.FlagChainID, cid1) + msgOpenInit := types.NewMsgConnectionOpenInit( + connID1, clientID1, connID2, clientID2, + path2, ctx1.GetFromAddress(), + ) + + fmt.Printf("%v <- %-14v", cid1, msgOpenInit.Type()) + res, err := utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgOpenInit}, passphrase1) + if err != nil || !res.IsOK() { + fmt.Println(res) + return err + } + fmt.Printf(" [OK] txid(%v) client(%v) conn(%v)\n", res.TxHash, clientID1, connID1) + + // Another block has to be passed after msgOpenInit 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 + } + + // Create and send msgUpdateClient + viper.Set(flags.FlagChainID, cid2) + msgUpdateClient := ibcclient.NewMsgUpdateClient(clientID1, header, ctx2.GetFromAddress()) + fmt.Printf("%v <- %-14v", cid2, msgUpdateClient.Type()) + res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}, passphrase2) + if err != nil || !res.IsOK() { + fmt.Println(res) + return err + } + fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, clientID1) + + // Fetch proofs from cid1 + viper.Set(flags.FlagChainID, cid1) + proofs, err := queryProofs(ctx1.WithHeight(header.Height-1), connID1, storeKey) + if err != nil { + return err + } + + // Create and send msgOpenTry + viper.Set(flags.FlagChainID, cid2) + msgOpenTry := types.NewMsgConnectionOpenTry(connID2, clientID2, connID1, clientID1, path2, []string{}, proofs.Proof, uint64(header.Height), uint64(header.Height), ctx2.GetFromAddress()) + fmt.Printf("%v <- %-14v", cid2, msgOpenTry.Type()) + res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgOpenTry}, passphrase2) + if err != nil || !res.IsOK() { + fmt.Println(res) + return err + } + fmt.Printf(" [OK] txid(%v) client(%v) connection(%v)\n", res.TxHash, clientID2, connID2) + + // Another block has to be passed after msgOpenInit 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 + } + + // Update the client for cid2 on cid1 + viper.Set(flags.FlagChainID, cid1) + msgUpdateClient = ibcclient.NewMsgUpdateClient(clientID2, header, ctx1.GetFromAddress()) + fmt.Printf("%v <- %-14v", cid1, msgUpdateClient.Type()) + res, err = utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgUpdateClient}, passphrase1) + if err != nil || !res.IsOK() { + fmt.Println(res) + return err + } + fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, clientID2) + + // Fetch proofs from cid2 + viper.Set(flags.FlagChainID, cid2) + proofs, err = queryProofs(ctx2.WithHeight(header.Height-1), connID2, storeKey) + if err != nil { + return err + } + + // Create and send msgOpenAck + viper.Set(flags.FlagChainID, cid1) + msgOpenAck := types.NewMsgConnectionOpenAck(connID1, proofs.Proof, uint64(header.Height), uint64(header.Height), "", ctx1.GetFromAddress()) + fmt.Printf("%v <- %-14v", cid1, msgOpenAck.Type()) + res, err = utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgOpenAck}, passphrase1) + if err != nil || !res.IsOK() { + fmt.Println(res) + return err + } + fmt.Printf(" [OK] txid(%v) connection(%v)\n", res.TxHash, connID1) + + // Another block has to be passed after msgOpenInit 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 + } + + // Update client for cid1 on cid2 + viper.Set(flags.FlagChainID, cid2) + msgUpdateClient = ibcclient.NewMsgUpdateClient(clientID1, header, ctx2.GetFromAddress()) + fmt.Printf("%v <- %-14v", cid2, msgUpdateClient.Type()) + res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}, passphrase2) + if err != nil || !res.IsOK() { + fmt.Println(res) + return err + } + fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, clientID1) + + // Fetch proof from cid1 + viper.Set(flags.FlagChainID, cid1) + proofs, err = queryProofs(ctx1.WithHeight(header.Height-1), connID1, storeKey) + if err != nil { + return err + } + + // Create and send msgOpenConfirm + viper.Set(flags.FlagChainID, cid2) + msgOpenConfirm := types.NewMsgConnectionOpenConfirm(connID2, proofs.Proof, uint64(header.Height), ctx2.GetFromAddress()) + fmt.Printf("%v <- %-14v", cid1, msgOpenConfirm.Type()) + res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgOpenConfirm}, passphrase2) + if err != nil || !res.IsOK() { + return err + } + fmt.Printf(" [OK] txid(%v) connection(%v)\n", res.TxHash, connID2) + + return nil + }, + } + + cmd.Flags().String(FlagNode1, "tcp://localhost:26657", "RPC port for the first chain") + cmd.Flags().String(FlagNode2, "tcp://localhost:26657", "RPC port for the second chain") + cmd.Flags().String(FlagFrom1, "", "key in local keystore for first chain") + cmd.Flags().String(FlagFrom2, "", "key in local keystore for second chain") + cmd.Flags().String(FlagChainID2, "", "chain-id for the second chain") + + cmd.MarkFlagRequired(FlagNode1) + cmd.MarkFlagRequired(FlagNode2) + cmd.MarkFlagRequired(FlagFrom1) + cmd.MarkFlagRequired(FlagFrom2) + cmd.MarkFlagRequired(FlagChainID2) + + return cmd +} + +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 queryProofs(ctx client.CLIContext, connectionID string, queryRoute string) (types.ConnectionResponse, error) { + var connRes types.ConnectionResponse + bz, err := ctx.Codec.MarshalJSON(types.NewQueryConnectionParams(connectionID)) + if err != nil { + return connRes, err + } + + req := abci.RequestQuery{ + Path: fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryConnection), + Data: bz, + Prove: viper.GetBool(flags.FlagProve), + } + + res, err := ctx.QueryABCI(req) + if err != nil { + return connRes, err + } + + var connection types.ConnectionEnd + if err := ctx.Codec.UnmarshalJSON(res.Value, &connection); err != nil { + return connRes, err + } + + return types.NewConnectionResponse(connectionID, connection, res.Proof, res.Height), nil +} + +func parsePath(cdc *codec.Codec, arg string) (commitment.Prefix, error) { + var path commitment.Prefix + if err := cdc.UnmarshalJSON([]byte(arg), &path); err != nil { + fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...") + contents, err := ioutil.ReadFile(arg) + if err != nil { + return path, fmt.Errorf("error opening path file: %v\n", err) + } + if err := cdc.UnmarshalJSON(contents, &path); err != nil { + return path, fmt.Errorf("error unmarshalling path file: %v\n", err) + } + } + return path, nil +} From 0d595c862ea0779e6855dfa6af4af92e1ed57e2d Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Wed, 30 Oct 2019 13:16:49 -0700 Subject: [PATCH 360/378] WIP Connection Handshake --- x/ibc/02-client/client/cli/query.go | 13 +++++++++++++ x/ibc/03-connection/client/cli/tx.go | 6 ++++-- x/ibc/03-connection/types/codec.go | 1 + x/ibc/module.go | 2 ++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 6b2dca09831e..25867297032a 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -35,6 +35,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { GetCmdQueryClientState(queryRoute, cdc), GetCmdQueryRoot(queryRoute, cdc), GetCmdNodeConsensusState(queryRoute, cdc), + GetCmdQueryPath(queryRoute, cdc), )...) return ics02ClientQueryCmd } @@ -272,3 +273,15 @@ $ %s query ibc client node-state }, } } + +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 { + ctx := context.NewCLIContext().WithCodec(cdc) + path := commitment.NewPrefix([]byte(storeName)) + return ctx.PrintOutput(path) + }, + } +} diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index 856d2c461371..e3a29cb55dec 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -47,6 +47,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { GetCmdConnectionOpenTry(storeKey, cdc), GetCmdConnectionOpenAck(storeKey, cdc), GetCmdConnectionOpenConfirm(storeKey, cdc), + GetCmdHandshakeState(storeKey, cdc), )...) return ics03ConnectionTxCmd @@ -314,7 +315,7 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { WithBroadcastMode(flags.BroadcastBlock) // read in path for cid1 - _, err := parsePath(ctx1.Codec, args[2]) + path1, err := parsePath(ctx1.Codec, args[2]) if err != nil { return err } @@ -365,6 +366,7 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // Create and send msgUpdateClient viper.Set(flags.FlagChainID, cid2) msgUpdateClient := ibcclient.NewMsgUpdateClient(clientID1, header, ctx2.GetFromAddress()) + fmt.Println("UPDATE CLIENT", msgUpdateClient) fmt.Printf("%v <- %-14v", cid2, msgUpdateClient.Type()) res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}, passphrase2) if err != nil || !res.IsOK() { @@ -382,7 +384,7 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // Create and send msgOpenTry viper.Set(flags.FlagChainID, cid2) - msgOpenTry := types.NewMsgConnectionOpenTry(connID2, clientID2, connID1, clientID1, path2, []string{}, proofs.Proof, uint64(header.Height), uint64(header.Height), ctx2.GetFromAddress()) + msgOpenTry := types.NewMsgConnectionOpenTry(connID2, clientID2, connID1, clientID1, path1, []string{}, proofs.Proof, uint64(header.Height), uint64(header.Height), ctx2.GetFromAddress()) fmt.Printf("%v <- %-14v", cid2, msgOpenTry.Type()) res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgOpenTry}, passphrase2) if err != nil || !res.IsOK() { diff --git a/x/ibc/03-connection/types/codec.go b/x/ibc/03-connection/types/codec.go index 5c197d6142b5..e0b7645c6dd1 100644 --- a/x/ibc/03-connection/types/codec.go +++ b/x/ibc/03-connection/types/codec.go @@ -12,6 +12,7 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgConnectionOpenAck{}, "ibc/connection/MsgConnectionOpenAck", nil) cdc.RegisterConcrete(MsgConnectionOpenConfirm{}, "ibc/connection/MsgConnectionOpenConfirm", nil) cdc.RegisterConcrete(ConnectionEnd{}, "ibc/connection/ConnectionEnd", nil) + SetMsgConnectionCodec(cdc) } func SetMsgConnectionCodec(cdc *codec.Codec) { diff --git a/x/ibc/module.go b/x/ibc/module.go index bdca95fc585d..2d5d0a3520f8 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -13,6 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" 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" transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" @@ -39,6 +40,7 @@ func (AppModuleBasic) Name() string { // RegisterCodec registers the staking module's types for the given codec. func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { client.RegisterCodec(cdc) + connection.RegisterCodec(cdc) channel.RegisterCodec(cdc) commitment.RegisterCodec(cdc) transfer.RegisterCodec(cdc) From 0a461b524fe44ffd564d6f079509055538eccab2 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Wed, 30 Oct 2019 14:52:42 -0700 Subject: [PATCH 361/378] use testsuite --- x/ibc/23-commitment/commitment_test.go | 37 +++++++++ x/ibc/23-commitment/merkle_test.go | 109 +++++++++++-------------- x/ibc/23-commitment/verify_test.go | 74 ----------------- 3 files changed, 83 insertions(+), 137 deletions(-) create mode 100644 x/ibc/23-commitment/commitment_test.go delete mode 100644 x/ibc/23-commitment/verify_test.go diff --git a/x/ibc/23-commitment/commitment_test.go b/x/ibc/23-commitment/commitment_test.go new file mode 100644 index 000000000000..2535f5705e29 --- /dev/null +++ b/x/ibc/23-commitment/commitment_test.go @@ -0,0 +1,37 @@ +package commitment_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/store/iavl" + "github.com/cosmos/cosmos-sdk/store/rootmulti" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + + dbm "github.com/tendermint/tm-db" +) + +type MerkleTestSuite struct { + suite.Suite + + store *rootmulti.Store + storeKey *storetypes.KVStoreKey + iavlStore *iavl.Store +} + +func (suite *MerkleTestSuite) SetupTest() { + db := dbm.NewMemDB() + suite.store = rootmulti.NewStore(db) + + suite.storeKey = storetypes.NewKVStoreKey("iavlStoreKey") + + suite.store.MountStoreWithDB(suite.storeKey, storetypes.StoreTypeIAVL, nil) + suite.store.LoadVersion(0) + + suite.iavlStore = suite.store.GetCommitStore(suite.storeKey).(*iavl.Store) +} + +func TestMerkleTestSuite(t *testing.T) { + suite.Run(t, new(MerkleTestSuite)) +} diff --git a/x/ibc/23-commitment/merkle_test.go b/x/ibc/23-commitment/merkle_test.go index 492169bcfca5..bfd2dc5a485c 100644 --- a/x/ibc/23-commitment/merkle_test.go +++ b/x/ibc/23-commitment/merkle_test.go @@ -1,122 +1,105 @@ package commitment_test import ( + "fmt" "testing" "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/store/iavl" - "github.com/cosmos/cosmos-sdk/store/rootmulti" - storetypes "github.com/cosmos/cosmos-sdk/store/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tm-db" ) -func TestVerifyMembership(t *testing.T) { - db := dbm.NewMemDB() - store := rootmulti.NewStore(db) +func (suite *MerkleTestSuite) TestVerifyMembership() { + suite.iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE")) + cid := suite.store.Commit() - iavlStoreKey := storetypes.NewKVStoreKey("iavlStoreKey") - - store.MountStoreWithDB(iavlStoreKey, storetypes.StoreTypeIAVL, nil) - store.LoadVersion(0) - - iavlStore := store.GetCommitStore(iavlStoreKey).(*iavl.Store) - iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE")) - cid := store.Commit() - - res := store.Query(abci.RequestQuery{ - Path: "/iavlStoreKey/key", // required path to get key/value+proof + res := suite.store.Query(abci.RequestQuery{ + Path: fmt.Sprintf("/%s/key", suite.storeKey.Name()), // required path to get key/value+proof Data: []byte("MYKEY"), Prove: true, }) - require.NotNil(t, res.Proof) + require.NotNil(suite.T(), res.Proof) proof := commitment.Proof{ Proof: res.Proof, } cases := []struct { + name string root []byte pathArr []string value []byte shouldPass bool - errString string }{ - {cid.Hash, []string{"iavlStoreKey", "MYKEY"}, []byte("MYVALUE"), true, "valid membership proof failed"}, // valid proof - {cid.Hash, []string{"iavlStoreKey", "MYKEY"}, []byte("WRONGVALUE"), false, "invalid membership proof with wrong value passed"}, // invalid proof with wrong value - {cid.Hash, []string{"iavlStoreKey", "MYKEY"}, []byte(nil), false, "invalid membership proof with wrong value passed"}, // invalid proof with nil value - {cid.Hash, []string{"iavlStoreKey", "NOTMYKEY"}, []byte("MYVALUE"), false, "invalid membership proof with wrong key passed"}, // invalid proof with wrong key - {cid.Hash, []string{"iavlStoreKey", "MYKEY", "MYKEY"}, []byte("MYVALUE"), false, "invalid membership proof with wrong path passed"}, // invalid proof with wrong path - {cid.Hash, []string{"iavlStoreKey"}, []byte("MYVALUE"), false, "invalid membership proof with wrong path passed"}, // invalid proof with wrong path - {cid.Hash, []string{"MYKEY"}, []byte("MYVALUE"), false, "invalid membership proof with wrong path passed"}, // invalid proof with wrong path - {cid.Hash, []string{"otherStoreKey", "MYKEY"}, []byte("MYVALUE"), false, "invalid membership proof with wrong store prefix passed"}, // invalid proof with wrong store prefix - {[]byte("WRONGROOT"), []string{"iavlStoreKey", "MYKEY"}, []byte("MYVALUE"), false, "invalid membership proof with wrong root passed"}, // invalid proof with wrong root - {[]byte(nil), []string{"iavlStoreKey", "MYKEY"}, []byte("MYVALUE"), false, "invalid membership proof with nil root passed"}, // invalid proof with nil root + {"valid proof", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, []byte("MYVALUE"), true}, // valid proof + {"wrong value", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, []byte("WRONGVALUE"), false}, // invalid proof with wrong value + {"nil value", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, []byte(nil), false}, // invalid proof with nil value + {"wrong key", cid.Hash, []string{suite.storeKey.Name(), "NOTMYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong key + {"wrong path 1", cid.Hash, []string{suite.storeKey.Name(), "MYKEY", "MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong path + {"wrong path 2", cid.Hash, []string{suite.storeKey.Name()}, []byte("MYVALUE"), false}, // invalid proof with wrong path + {"wrong path 3", cid.Hash, []string{"MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong path + {"wrong storekey", cid.Hash, []string{"otherStoreKey", "MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong store prefix + {"wrong root", []byte("WRONGROOT"), []string{suite.storeKey.Name(), "MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong root + {"nil root", []byte(nil), []string{suite.storeKey.Name(), "MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with nil root } for i, tc := range cases { - root := commitment.NewRoot(tc.root) - path := commitment.NewPath(tc.pathArr) + suite.Run(tc.name, func() { + root := commitment.NewRoot(tc.root) + path := commitment.NewPath(tc.pathArr) - ok := proof.VerifyMembership(root, path, tc.value) + ok := proof.VerifyMembership(root, path, tc.value) - require.True(t, ok == tc.shouldPass, "Test case %d failed: %s", i, tc.errString) + require.True(suite.T(), ok == tc.shouldPass, "Test case %d failed", i) + }) } } -func TestVerifyNonMembership(t *testing.T) { - db := dbm.NewMemDB() - store := rootmulti.NewStore(db) - - iavlStoreKey := storetypes.NewKVStoreKey("iavlStoreKey") - - store.MountStoreWithDB(iavlStoreKey, storetypes.StoreTypeIAVL, nil) - store.LoadVersion(0) - - iavlStore := store.GetCommitStore(iavlStoreKey).(*iavl.Store) - iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE")) - cid := store.Commit() +func (suite *MerkleTestSuite) TestVerifyNonMembership() { + suite.iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE")) + cid := suite.store.Commit() // Get Proof - res := store.Query(abci.RequestQuery{ - Path: "/iavlStoreKey/key", // required path to get key/value+proof + res := suite.store.Query(abci.RequestQuery{ + Path: fmt.Sprintf("/%s/key", suite.storeKey.Name()), // required path to get key/value+proof Data: []byte("MYABSENTKEY"), Prove: true, }) - require.NotNil(t, res.Proof) + require.NotNil(suite.T(), res.Proof) proof := commitment.Proof{ Proof: res.Proof, } cases := []struct { + name string root []byte pathArr []string shouldPass bool - errString string }{ - {cid.Hash, []string{"iavlStoreKey", "MYABSENTKEY"}, true, "valid non-membership proof failed"}, // valid proof - {cid.Hash, []string{"iavlStoreKey", "MYKEY"}, false, "invalid non-membership proof with wrong key passed"}, // invalid proof with existent key - {cid.Hash, []string{"iavlStoreKey", "MYKEY", "MYABSENTKEY"}, false, "invalid non-membership proof with wrong path passed"}, // invalid proof with wrong path - {cid.Hash, []string{"iavlStoreKey", "MYABSENTKEY", "MYKEY"}, false, "invalid non-membership proof with wrong path passed"}, // invalid proof with wrong path - {cid.Hash, []string{"iavlStoreKey"}, false, "invalid non-membership proof with wrong path passed"}, // invalid proof with wrong path - {cid.Hash, []string{"MYABSENTKEY"}, false, "invalid non-membership proof with wrong path passed"}, // invalid proof with wrong path - {cid.Hash, []string{"otherStoreKey", "MYABSENTKEY"}, false, "invalid non-membership proof with wrong store prefix passed"}, // invalid proof with wrong store prefix - {[]byte("WRONGROOT"), []string{"iavlStoreKey", "MYABSENTKEY"}, false, "invalid non-membership proof with wrong root passed"}, // invalid proof with wrong root - {[]byte(nil), []string{"iavlStoreKey", "MYABSENTKEY"}, false, "invalid non-membership proof with nil root passed"}, // invalid proof with nil root + {"valid proof", cid.Hash, []string{suite.storeKey.Name(), "MYABSENTKEY"}, true}, // valid proof + {"wrong key", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, false}, // invalid proof with existent key + {"wrong path 1", cid.Hash, []string{suite.storeKey.Name(), "MYKEY", "MYABSENTKEY"}, false}, // invalid proof with wrong path + {"wrong path 2", cid.Hash, []string{suite.storeKey.Name(), "MYABSENTKEY", "MYKEY"}, false}, // invalid proof with wrong path + {"wrong path 3", cid.Hash, []string{suite.storeKey.Name()}, false}, // invalid proof with wrong path + {"wrong path 4", cid.Hash, []string{"MYABSENTKEY"}, false}, // invalid proof with wrong path + {"wrong storeKey", cid.Hash, []string{"otherStoreKey", "MYABSENTKEY"}, false}, // invalid proof with wrong store prefix + {"wrong root", []byte("WRONGROOT"), []string{suite.storeKey.Name(), "MYABSENTKEY"}, false}, // invalid proof with wrong root + {"nil root", []byte(nil), []string{suite.storeKey.Name(), "MYABSENTKEY"}, false}, // invalid proof with nil root } for i, tc := range cases { - root := commitment.NewRoot(tc.root) - path := commitment.NewPath(tc.pathArr) + suite.Run(tc.name, func() { + root := commitment.NewRoot(tc.root) + path := commitment.NewPath(tc.pathArr) - ok := proof.VerifyNonMembership(root, path) + ok := proof.VerifyNonMembership(root, path) - require.True(t, ok == tc.shouldPass, "Test case %d failed: %s", i, tc.errString) + require.True(suite.T(), ok == tc.shouldPass, "Test case %d failed", i) + }) } } diff --git a/x/ibc/23-commitment/verify_test.go b/x/ibc/23-commitment/verify_test.go deleted file mode 100644 index 5b94160dfd1c..000000000000 --- a/x/ibc/23-commitment/verify_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package commitment_test - -import ( - "fmt" - "strings" - "testing" - - "github.com/cosmos/cosmos-sdk/store/iavl" - "github.com/cosmos/cosmos-sdk/store/rootmulti" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" -) - -func TestBatchVerifyMembership(t *testing.T) { - db := dbm.NewMemDB() - store := rootmulti.NewStore(db) - - iavlStoreKey := storetypes.NewKVStoreKey("iavlStoreKey") - - store.MountStoreWithDB(iavlStoreKey, storetypes.StoreTypeIAVL, nil) - store.LoadVersion(0) - - iavlStore := store.GetCommitStore(iavlStoreKey).(*iavl.Store) - for i := 0; i < 5; i++ { - iavlStore.Set([]byte(fmt.Sprintf("KEY:%d", i)), []byte(fmt.Sprintf("VAL:%d", i))) - } - cid := store.Commit() - - header := abci.Header{AppHash: cid.Hash} - ctx := sdk.NewContext(store, header, false, log.NewNopLogger()) - - res := store.Query(abci.RequestQuery{ - Path: "/iavlStoreKey/subspace", - Data: []byte("KEY:"), - Height: cid.Version, - Prove: true, - }) - require.NotNil(t, res.Proof) - - proof := commitment.Proof{ - Proof: res.Proof, - } - prefix := commitment.NewPrefix([]byte("iavlStoreKey")) - - keyBatches := [][]string{ - {"KEY:1"}, // batch verify one key - {"KEY:1", "KEY:2"}, // batch verify first 2 keys in subspace - {"KEY:2", "KEY:3", "KEY:4"}, // batch verify middle 3 keys in subspace - {"KEY:4", "KEY:5"}, // batch verify last 2 keys in subspace - {"KEY:3", "KEY:2"}, // batch verify keys in reverse order - {"KEY:4", "KEY:1"}, // batch verify non-contingous keys - {"KEY:2", "KEY:3", "KEY:4", "KEY:1", "KEY:5"}, // batch verify all keys in random order - } - - for i, batch := range keyBatches { - items := make(map[string][]byte) - - for _, key := range batch { - // key-pair must have form KEY:{str} => VAL:{str} - splitKey := strings.Split(key, ":") - items[key] = []byte(fmt.Sprintf("VAL:%s", splitKey[1])) - } - - ok := commitment.BatchVerifyMembership(ctx, proof, prefix, items) - - require.True(t, ok, "Test case %d failed on batch verify", i) - } -} From ccb405ae72da49d79e7bb3a0117d743ff2efbfb3 Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Wed, 30 Oct 2019 16:10:00 -0700 Subject: [PATCH 362/378] Add cliCtx.WaitForNBlocks --- client/context/query.go | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/client/context/query.go b/client/context/query.go index 81917a1c493c..9c204d7fcb94 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -3,6 +3,7 @@ package context import ( "fmt" "strings" + "time" "github.com/pkg/errors" @@ -12,6 +13,7 @@ import ( tmliteErr "github.com/tendermint/tendermint/lite/errors" tmliteProxy "github.com/tendermint/tendermint/lite/proxy" rpcclient "github.com/tendermint/tendermint/rpc/client" + ctypes "github.com/tendermint/tendermint/rpc/core/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/store/rootmulti" @@ -28,6 +30,55 @@ func (ctx CLIContext) GetNode() (rpcclient.Client, error) { return ctx.Client, nil } +// WaitForNBlocks blocks until the node defined on the context has advanced N blocks +func (ctx CLIContext) WaitForNBlocks(n int64) { + node, err := ctx.GetNode() + if err != nil { + panic(err) + } + + resBlock, err := node.Block(nil) + var height int64 + if err != nil || resBlock.Block == nil { + // wait for the first block to exist + ctx.waitForHeight(1) + height = 1 + n + } else { + height = resBlock.Block.Height + n + } + ctx.waitForHeight(height) +} + +func (ctx CLIContext) waitForHeight(height int64) { + node, err := ctx.GetNode() + if err != nil { + panic(err) + } + + for { + // get url, try a few times + var resBlock *ctypes.ResultBlock + var err error + INNER: + for i := 0; i < 5; i++ { + resBlock, err = node.Block(nil) + if err == nil { + break INNER + } + time.Sleep(time.Millisecond * 200) + } + if err != nil { + panic(err) + } + + if resBlock.Block != nil && resBlock.Block.Height >= height { + return + } + + time.Sleep(time.Millisecond * 100) + } +} + // Query performs a query to a Tendermint node with the provided path. // It returns the result and height of the query upon success or an error if // the query fails. From 89b58443a4fb4e9ad3550265b2dafd07df3c5945 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 30 Oct 2019 16:46:08 -0700 Subject: [PATCH 363/378] fix connection handshake in progress --- x/ibc/02-client/client/cli/query.go | 2 +- x/ibc/02-client/client/cli/tx.go | 4 +++- x/ibc/02-client/keeper/client.go | 1 + x/ibc/02-client/keeper/keeper.go | 11 +++++++++ x/ibc/02-client/types/state.go | 2 +- x/ibc/03-connection/client/cli/tx.go | 17 +++++++++----- x/ibc/03-connection/keeper/handshake.go | 30 +++++++++++++++++-------- x/ibc/03-connection/keeper/keeper.go | 8 ++++++- x/ibc/23-commitment/merkle.go | 2 ++ 9 files changed, 58 insertions(+), 19 deletions(-) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 25867297032a..6980feab0260 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -280,7 +280,7 @@ func GetCmdQueryPath(storeName string, cdc *codec.Codec) *cobra.Command { Short: "Query the commitment path of the running chain", RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCLIContext().WithCodec(cdc) - path := commitment.NewPrefix([]byte(storeName)) + path := commitment.NewPrefix([]byte("ibc")) return ctx.PrintOutput(path) }, } diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index fc92efb874ba..4cbc97b39842 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" @@ -51,7 +52,7 @@ $ %s tx ibc client create [client-id] [path/to/consensus_state.json] --from node Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContext().WithCodec(cdc) + cliCtx := context.NewCLIContext().WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) clientID := args[0] @@ -72,6 +73,7 @@ $ %s tx ibc client create [client-id] [path/to/consensus_state.json] --from node clientID, state.ClientType().String(), state, cliCtx.GetFromAddress(), ) + if err := msg.ValidateBasic(); err != nil { return err } diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go index e180919dec7c..bd3c81266f35 100644 --- a/x/ibc/02-client/keeper/client.go +++ b/x/ibc/02-client/keeper/client.go @@ -26,6 +26,7 @@ func (k Keeper) CreateClient( } clientState := k.initialize(ctx, clientID, consensusState) + fmt.Printf("clist %+v\n", clientState) k.SetVerifiedRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) k.SetClientState(ctx, clientState) k.SetClientType(ctx, clientID, clientType) diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index c9f7fbe1c9f7..20c86950afe2 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -44,9 +44,11 @@ func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (types.State, b store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := store.Get(types.KeyClientState(clientID)) if bz == nil { + fmt.Println("empty bytes") return types.State{}, false } + fmt.Println("getcs", []byte(bz)) var clientState types.State k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &clientState) return clientState, true @@ -56,16 +58,21 @@ func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (types.State, b func (k Keeper) SetClientState(ctx sdk.Context, clientState types.State) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := k.cdc.MustMarshalBinaryLengthPrefixed(clientState) + fmt.Println("setcs", []byte(bz)) store.Set(types.KeyClientState(clientState.ID()), bz) } // GetClientType gets the consensus type for a specific client func (k Keeper) GetClientType(ctx sdk.Context, clientID string) (exported.ClientType, bool) { + fmt.Println("get", clientID) store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := store.Get(types.KeyClientType(clientID)) + fmt.Println(string(bz), []byte(bz), len(bz)) + fmt.Println(clientID) if bz == nil { return 0, false } + fmt.Println(999) return exported.ClientType(bz[0]), true } @@ -73,6 +80,7 @@ func (k Keeper) GetClientType(ctx sdk.Context, clientID string) (exported.Client // SetClientType sets the specific client consensus type to the provable store func (k Keeper) SetClientType(ctx sdk.Context, clientID string, clientType exported.ClientType) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + fmt.Println("set", clientID, clientType) store.Set(types.KeyClientType(clientID), []byte{byte(clientType)}) } @@ -100,6 +108,7 @@ func (k Keeper) SetConsensusState(ctx sdk.Context, clientID string, consensusSta // a client func (k Keeper) GetVerifiedRoot(ctx sdk.Context, clientID string, height uint64) (commitment.RootI, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(types.KeyRoot(clientID, height)) if bz == nil { return nil, false @@ -162,11 +171,13 @@ func (k Keeper) VerifyMembership( value []byte, ) bool { if clientState.Frozen { + fmt.Println("false3") return false } root, found := k.GetVerifiedRoot(ctx, clientState.ID(), height) if !found { + fmt.Println("false4") return false } diff --git a/x/ibc/02-client/types/state.go b/x/ibc/02-client/types/state.go index 8c60260df0a2..ac9a803195fd 100644 --- a/x/ibc/02-client/types/state.go +++ b/x/ibc/02-client/types/state.go @@ -4,7 +4,7 @@ package types // Any actor holding the Stage can access on and modify that client information. type State struct { // Client ID - id string + id string `json:"id" yaml:"id"` // Boolean that states if the client is frozen when a misbehaviour proof is // submitted in the event of an equivocation. Frozen bool `json:"frozen" yaml:"frozen"` diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index e3a29cb55dec..dd843cca16b5 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -302,6 +302,9 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { clientID1 := args[1] clientID2 := args[4] + // Get default version + version := types.GetCompatibleVersions()[0] + // Create txbldr, clictx, querier for cid1 viper.Set(flags.FlagChainID, cid1) txBldr1 := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) @@ -350,6 +353,8 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { fmt.Println(res) return err } + + fmt.Println(res) fmt.Printf(" [OK] txid(%v) client(%v) conn(%v)\n", res.TxHash, clientID1, connID1) // Another block has to be passed after msgOpenInit is committed @@ -365,8 +370,7 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // Create and send msgUpdateClient viper.Set(flags.FlagChainID, cid2) - msgUpdateClient := ibcclient.NewMsgUpdateClient(clientID1, header, ctx2.GetFromAddress()) - fmt.Println("UPDATE CLIENT", msgUpdateClient) + msgUpdateClient := ibcclient.NewMsgUpdateClient(clientID2, header, ctx2.GetFromAddress()) fmt.Printf("%v <- %-14v", cid2, msgUpdateClient.Type()) res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}, passphrase2) if err != nil || !res.IsOK() { @@ -384,13 +388,14 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // Create and send msgOpenTry viper.Set(flags.FlagChainID, cid2) - msgOpenTry := types.NewMsgConnectionOpenTry(connID2, clientID2, connID1, clientID1, path1, []string{}, proofs.Proof, uint64(header.Height), uint64(header.Height), ctx2.GetFromAddress()) + msgOpenTry := types.NewMsgConnectionOpenTry(connID2, clientID2, connID1, clientID1, path1, []string{version}, proofs.Proof, uint64(header.Height), uint64(header.Height), ctx2.GetFromAddress()) fmt.Printf("%v <- %-14v", cid2, msgOpenTry.Type()) res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgOpenTry}, passphrase2) if err != nil || !res.IsOK() { fmt.Println(res) return err } + fmt.Printf(" [OK] txid(%v) client(%v) connection(%v)\n", res.TxHash, clientID2, connID2) // Another block has to be passed after msgOpenInit is committed @@ -406,7 +411,7 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // Update the client for cid2 on cid1 viper.Set(flags.FlagChainID, cid1) - msgUpdateClient = ibcclient.NewMsgUpdateClient(clientID2, header, ctx1.GetFromAddress()) + msgUpdateClient = ibcclient.NewMsgUpdateClient(clientID1, header, ctx1.GetFromAddress()) fmt.Printf("%v <- %-14v", cid1, msgUpdateClient.Type()) res, err = utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgUpdateClient}, passphrase1) if err != nil || !res.IsOK() { @@ -424,7 +429,7 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // Create and send msgOpenAck viper.Set(flags.FlagChainID, cid1) - msgOpenAck := types.NewMsgConnectionOpenAck(connID1, proofs.Proof, uint64(header.Height), uint64(header.Height), "", ctx1.GetFromAddress()) + msgOpenAck := types.NewMsgConnectionOpenAck(connID1, proofs.Proof, uint64(header.Height), uint64(header.Height), version, ctx1.GetFromAddress()) fmt.Printf("%v <- %-14v", cid1, msgOpenAck.Type()) res, err = utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgOpenAck}, passphrase1) if err != nil || !res.IsOK() { @@ -446,7 +451,7 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // Update client for cid1 on cid2 viper.Set(flags.FlagChainID, cid2) - msgUpdateClient = ibcclient.NewMsgUpdateClient(clientID1, header, ctx2.GetFromAddress()) + msgUpdateClient = ibcclient.NewMsgUpdateClient(clientID2, header, ctx2.GetFromAddress()) fmt.Printf("%v <- %-14v", cid2, msgUpdateClient.Type()) res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}, passphrase2) if err != nil || !res.IsOK() { diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index e833fb90656b..b85e5423899a 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -54,9 +54,12 @@ func (k Keeper) ConnOpenTry( proofHeight uint64, consensusHeight uint64, ) error { - if consensusHeight > uint64(ctx.BlockHeight()) { - return errors.New("invalid consensus height") // TODO: sdk.Error - } + // XXX: blocked by #5078 + /* + if consensusHeight > uint64(ctx.BlockHeight()) { + return errors.New("invalid consensus height") // TODO: sdk.Error + } + */ expectedConsensusState, found := k.clientKeeper.GetConsensusState(ctx, clientID) if !found { @@ -66,8 +69,8 @@ func (k Keeper) ConnOpenTry( // expectedConn defines Chain A's ConnectionEnd // NOTE: chain A's counterparty is chain B (i.e where this code is executed) prefix := k.GetCommitmentPrefix() - expectedCounterparty := types.NewCounterparty(counterparty.ClientID, connectionID, prefix) - expectedConn := types.NewConnectionEnd(types.INIT, clientID, expectedCounterparty, counterpartyVersions) + expectedCounterparty := types.NewCounterparty(clientID, connectionID, prefix) + expectedConn := types.NewConnectionEnd(types.INIT, counterparty.ClientID, expectedCounterparty, counterpartyVersions) // chain B picks a version from Chain A's available versions that is compatible // with the supported IBC versions @@ -80,6 +83,7 @@ func (k Keeper) ConnOpenTry( return err } + fmt.Println(666666) ok := k.VerifyMembership( ctx, connection, proofHeight, proofInit, types.ConnectionPath(connectionID), expConnBz, @@ -88,11 +92,14 @@ func (k Keeper) ConnOpenTry( return errors.New("couldn't verify connection membership on counterparty's client") // TODO: sdk.Error } + fmt.Println(777777) + expConsStateBz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedConsensusState) if err != nil { return err } + fmt.Println(888888) ok = k.VerifyMembership( ctx, connection, proofHeight, proofInit, clienttypes.ConsensusStatePath(counterparty.ClientID), expConsStateBz, @@ -105,6 +112,7 @@ func (k Keeper) ConnOpenTry( if found { return sdkerrors.Wrap(types.ErrConnectionExists(k.codespace, connectionID), "cannot relay connection attempt") } + fmt.Println(999999) connection.State = types.TRYOPEN err = k.addConnectionToClient(ctx, clientID, connectionID) @@ -112,6 +120,7 @@ func (k Keeper) ConnOpenTry( return sdkerrors.Wrap(err, "cannot relay connection attempt") } + fmt.Println(111) k.SetConnection(ctx, connectionID, connection) k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: NONE -> TRYOPEN ", connectionID)) return nil @@ -129,9 +138,12 @@ func (k Keeper) ConnOpenAck( proofHeight uint64, consensusHeight uint64, ) error { - if consensusHeight > uint64(ctx.BlockHeight()) { - return errors.New("invalid consensus height") // TODO: sdk.Error - } + // XXX: blocked by #5078 + /* + if consensusHeight > uint64(ctx.BlockHeight()) { + return errors.New("invalid consensus height") // TODO: sdk.Error + } + */ connection, found := k.GetConnection(ctx, connectionID) if !found { @@ -159,7 +171,7 @@ func (k Keeper) ConnOpenAck( prefix := k.GetCommitmentPrefix() expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, prefix) - expectedConn := types.NewConnectionEnd(types.TRYOPEN, connection.ClientID, expectedCounterparty, []string{version}) + expectedConn := types.NewConnectionEnd(types.TRYOPEN, connection.Counterparty.ClientID, expectedCounterparty, []string{version}) expConnBz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedConn) if err != nil { diff --git a/x/ibc/03-connection/keeper/keeper.go b/x/ibc/03-connection/keeper/keeper.go index 222ee0fc63e5..1dc601f00a1b 100644 --- a/x/ibc/03-connection/keeper/keeper.go +++ b/x/ibc/03-connection/keeper/keeper.go @@ -43,7 +43,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { // GetCommitmentPrefix returns the IBC connection store prefix as a commitment // Prefix func (k Keeper) GetCommitmentPrefix() commitment.PrefixI { - return commitment.NewPrefix(k.prefix) + return commitment.NewPrefix([]byte(k.storeKey.Name())) } // GetConnection returns a connection with a particular identifier @@ -63,6 +63,8 @@ func (k Keeper) GetConnection(ctx sdk.Context, connectionID string) (types.Conne func (k Keeper) SetConnection(ctx sdk.Context, connectionID string, connection types.ConnectionEnd) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := k.cdc.MustMarshalBinaryLengthPrefixed(connection) + fmt.Printf("%+v\n", connection) + fmt.Printf("bs: %X\n", bz) store.Set(types.KeyConnection(connectionID), bz) } @@ -132,10 +134,14 @@ func (k Keeper) VerifyMembership( ) bool { clientState, found := k.clientKeeper.GetClientState(ctx, connection.ClientID) if !found { + fmt.Println("false1") return false } + fmt.Printf("ddd\n%+v\n", clientState) + fmt.Printf("%+v\n", connection) path, err := commitment.ApplyPrefix(connection.Counterparty.Prefix, pathStr) if err != nil { + fmt.Println("false2") return false } diff --git a/x/ibc/23-commitment/merkle.go b/x/ibc/23-commitment/merkle.go index 8754823e0683..f820e7153fc2 100644 --- a/x/ibc/23-commitment/merkle.go +++ b/x/ibc/23-commitment/merkle.go @@ -2,6 +2,7 @@ package commitment import ( "errors" + "fmt" "strings" "github.com/tendermint/tendermint/crypto/merkle" @@ -140,6 +141,7 @@ func (Proof) GetCommitmentType() Type { func (proof Proof) VerifyMembership(root RootI, path PathI, value []byte) bool { runtime := rootmulti.DefaultProofRuntime() err := runtime.VerifyValue(proof.Proof, root.GetHash(), path.String(), value) + fmt.Println("verify", err) return err == nil } From 609883398c55ab490e576709df8f578e2f25f058 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 30 Oct 2019 20:20:21 -0700 Subject: [PATCH 364/378] fix connection handshake in progress --- x/ibc/02-client/keeper/keeper.go | 39 ++++++++----------- x/ibc/03-connection/client/cli/tx.go | 7 ---- x/ibc/03-connection/keeper/handshake.go | 6 --- x/ibc/03-connection/keeper/keeper.go | 30 +++++++------- x/ibc/03-connection/types/expected_keepers.go | 4 +- x/ibc/23-commitment/merkle.go | 2 - 6 files changed, 35 insertions(+), 53 deletions(-) diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index 20c86950afe2..09b9161b80be 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -44,11 +44,9 @@ func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (types.State, b store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := store.Get(types.KeyClientState(clientID)) if bz == nil { - fmt.Println("empty bytes") return types.State{}, false } - fmt.Println("getcs", []byte(bz)) var clientState types.State k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &clientState) return clientState, true @@ -58,21 +56,16 @@ func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (types.State, b func (k Keeper) SetClientState(ctx sdk.Context, clientState types.State) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := k.cdc.MustMarshalBinaryLengthPrefixed(clientState) - fmt.Println("setcs", []byte(bz)) store.Set(types.KeyClientState(clientState.ID()), bz) } // GetClientType gets the consensus type for a specific client func (k Keeper) GetClientType(ctx sdk.Context, clientID string) (exported.ClientType, bool) { - fmt.Println("get", clientID) store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) bz := store.Get(types.KeyClientType(clientID)) - fmt.Println(string(bz), []byte(bz), len(bz)) - fmt.Println(clientID) if bz == nil { return 0, false } - fmt.Println(999) return exported.ClientType(bz[0]), true } @@ -80,7 +73,6 @@ func (k Keeper) GetClientType(ctx sdk.Context, clientID string) (exported.Client // SetClientType sets the specific client consensus type to the provable store func (k Keeper) SetClientType(ctx sdk.Context, clientID string, clientType exported.ClientType) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) - fmt.Println("set", clientID, clientType) store.Set(types.KeyClientType(clientID), []byte{byte(clientType)}) } @@ -164,20 +156,21 @@ func (k Keeper) freeze(ctx sdk.Context, clientState types.State) (types.State, e // VerifyMembership state membership verification function defined by the client type func (k Keeper) VerifyMembership( ctx sdk.Context, - clientState types.State, + clientID string, height uint64, // sequence proof commitment.ProofI, path commitment.PathI, value []byte, ) bool { - if clientState.Frozen { - fmt.Println("false3") - return false - } - - root, found := k.GetVerifiedRoot(ctx, clientState.ID(), height) + // XXX: commented out for demo + /* + if clientState.Frozen { + return false + } + */ + + root, found := k.GetVerifiedRoot(ctx, clientID, height) if !found { - fmt.Println("false4") return false } @@ -187,16 +180,18 @@ func (k Keeper) VerifyMembership( // VerifyNonMembership state non-membership function defined by the client type func (k Keeper) VerifyNonMembership( ctx sdk.Context, - clientState types.State, + clientID string, height uint64, // sequence proof commitment.ProofI, path commitment.PathI, ) bool { - if clientState.Frozen { - return false - } - - root, found := k.GetVerifiedRoot(ctx, clientState.ID(), height) + // XXX: commented out for demo + /* + if clientState.Frozen { + return false + } + */ + root, found := k.GetVerifiedRoot(ctx, clientID, height) if !found { return false } diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index dd843cca16b5..d2ce7e06da1b 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -350,11 +350,9 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { fmt.Printf("%v <- %-14v", cid1, msgOpenInit.Type()) res, err := utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgOpenInit}, passphrase1) if err != nil || !res.IsOK() { - fmt.Println(res) return err } - fmt.Println(res) fmt.Printf(" [OK] txid(%v) client(%v) conn(%v)\n", res.TxHash, clientID1, connID1) // Another block has to be passed after msgOpenInit is committed @@ -374,7 +372,6 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { fmt.Printf("%v <- %-14v", cid2, msgUpdateClient.Type()) res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}, passphrase2) if err != nil || !res.IsOK() { - fmt.Println(res) return err } fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, clientID1) @@ -392,7 +389,6 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { fmt.Printf("%v <- %-14v", cid2, msgOpenTry.Type()) res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgOpenTry}, passphrase2) if err != nil || !res.IsOK() { - fmt.Println(res) return err } @@ -415,7 +411,6 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { fmt.Printf("%v <- %-14v", cid1, msgUpdateClient.Type()) res, err = utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgUpdateClient}, passphrase1) if err != nil || !res.IsOK() { - fmt.Println(res) return err } fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, clientID2) @@ -433,7 +428,6 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { fmt.Printf("%v <- %-14v", cid1, msgOpenAck.Type()) res, err = utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgOpenAck}, passphrase1) if err != nil || !res.IsOK() { - fmt.Println(res) return err } fmt.Printf(" [OK] txid(%v) connection(%v)\n", res.TxHash, connID1) @@ -455,7 +449,6 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { fmt.Printf("%v <- %-14v", cid2, msgUpdateClient.Type()) res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}, passphrase2) if err != nil || !res.IsOK() { - fmt.Println(res) return err } fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, clientID1) diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index b85e5423899a..95ddf7906da0 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -83,7 +83,6 @@ func (k Keeper) ConnOpenTry( return err } - fmt.Println(666666) ok := k.VerifyMembership( ctx, connection, proofHeight, proofInit, types.ConnectionPath(connectionID), expConnBz, @@ -92,14 +91,11 @@ func (k Keeper) ConnOpenTry( return errors.New("couldn't verify connection membership on counterparty's client") // TODO: sdk.Error } - fmt.Println(777777) - expConsStateBz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedConsensusState) if err != nil { return err } - fmt.Println(888888) ok = k.VerifyMembership( ctx, connection, proofHeight, proofInit, clienttypes.ConsensusStatePath(counterparty.ClientID), expConsStateBz, @@ -112,7 +108,6 @@ func (k Keeper) ConnOpenTry( if found { return sdkerrors.Wrap(types.ErrConnectionExists(k.codespace, connectionID), "cannot relay connection attempt") } - fmt.Println(999999) connection.State = types.TRYOPEN err = k.addConnectionToClient(ctx, clientID, connectionID) @@ -120,7 +115,6 @@ func (k Keeper) ConnOpenTry( return sdkerrors.Wrap(err, "cannot relay connection attempt") } - fmt.Println(111) k.SetConnection(ctx, connectionID, connection) k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: NONE -> TRYOPEN ", connectionID)) return nil diff --git a/x/ibc/03-connection/keeper/keeper.go b/x/ibc/03-connection/keeper/keeper.go index 1dc601f00a1b..d7ad6838f96f 100644 --- a/x/ibc/03-connection/keeper/keeper.go +++ b/x/ibc/03-connection/keeper/keeper.go @@ -132,20 +132,19 @@ func (k Keeper) VerifyMembership( pathStr string, value []byte, ) bool { - clientState, found := k.clientKeeper.GetClientState(ctx, connection.ClientID) - if !found { - fmt.Println("false1") - return false - } - fmt.Printf("ddd\n%+v\n", clientState) - fmt.Printf("%+v\n", connection) + // FIXME: commented out for demo + /* + clientState, found := k.clientKeeper.GetClientState(ctx, connection.ClientID) + if !found { + return false + } + */ path, err := commitment.ApplyPrefix(connection.Counterparty.Prefix, pathStr) if err != nil { - fmt.Println("false2") return false } - return k.clientKeeper.VerifyMembership(ctx, clientState, height, proof, path, value) + return k.clientKeeper.VerifyMembership(ctx, connection.ClientID, height, proof, path, value) } // VerifyNonMembership helper function for state non-membership verification @@ -156,15 +155,18 @@ func (k Keeper) VerifyNonMembership( proof commitment.ProofI, pathStr string, ) bool { - clientState, found := k.clientKeeper.GetClientState(ctx, connection.ClientID) - if !found { - return false - } + // FIXME: commented out for demo + /* + clientState, found := k.clientKeeper.GetClientState(ctx, connection.ClientID) + if !found { + return false + } + */ path, err := commitment.ApplyPrefix(connection.Counterparty.Prefix, pathStr) if err != nil { return false } - return k.clientKeeper.VerifyNonMembership(ctx, clientState, height, proof, path) + return k.clientKeeper.VerifyNonMembership(ctx, connection.ClientID, height, proof, path) } diff --git a/x/ibc/03-connection/types/expected_keepers.go b/x/ibc/03-connection/types/expected_keepers.go index 8af1beb2ba7a..1a114f6f8374 100644 --- a/x/ibc/03-connection/types/expected_keepers.go +++ b/x/ibc/03-connection/types/expected_keepers.go @@ -12,11 +12,11 @@ type ClientKeeper interface { GetConsensusState(ctx sdk.Context, clientID string) (clientexported.ConsensusState, bool) GetClientState(ctx sdk.Context, clientID string) (client.State, bool) VerifyMembership( - ctx sdk.Context, clientState client.State, height uint64, + ctx sdk.Context, clientID string, height uint64, proof commitment.ProofI, path commitment.PathI, value []byte, ) bool VerifyNonMembership( - ctx sdk.Context, clientState client.State, height uint64, + ctx sdk.Context, clientID string, height uint64, proof commitment.ProofI, path commitment.PathI, ) bool } diff --git a/x/ibc/23-commitment/merkle.go b/x/ibc/23-commitment/merkle.go index f820e7153fc2..8754823e0683 100644 --- a/x/ibc/23-commitment/merkle.go +++ b/x/ibc/23-commitment/merkle.go @@ -2,7 +2,6 @@ package commitment import ( "errors" - "fmt" "strings" "github.com/tendermint/tendermint/crypto/merkle" @@ -141,7 +140,6 @@ func (Proof) GetCommitmentType() Type { func (proof Proof) VerifyMembership(root RootI, path PathI, value []byte) bool { runtime := rootmulti.DefaultProofRuntime() err := runtime.VerifyValue(proof.Proof, root.GetHash(), path.String(), value) - fmt.Println("verify", err) return err == nil } From 7f9c166b3a77945f12ac1ed2b9da17199053f924 Mon Sep 17 00:00:00 2001 From: Aditya Date: Mon, 4 Nov 2019 08:50:07 -0500 Subject: [PATCH 365/378] Integrate Evidence Implementation into ICS-02 (#5258) * implement evidence in ics-02 * fix build errors and import cycles * address fede comments * remove unnecessary pubkey and fix init * add tests --- x/ibc/02-client/alias.go | 43 +++---- x/ibc/02-client/exported/exported.go | 2 + x/ibc/02-client/keeper/client.go | 15 +-- x/ibc/02-client/keeper/keeper.go | 34 +++--- x/ibc/02-client/keeper/querier.go | 7 +- x/ibc/02-client/types/codec.go | 7 +- x/ibc/02-client/types/{ => errors}/errors.go | 8 +- x/ibc/02-client/types/msgs.go | 12 +- x/ibc/02-client/types/tendermint/codec.go | 18 +++ .../types/tendermint/misbehaviour.go | 90 ++++++++++++++- .../types/tendermint/misbehaviour_test.go | 107 ++++++++++++++++++ x/ibc/24-host/errors.go | 3 + 12 files changed, 288 insertions(+), 58 deletions(-) rename x/ibc/02-client/types/{ => errors}/errors.go (94%) create mode 100644 x/ibc/02-client/types/tendermint/codec.go create mode 100644 x/ibc/02-client/types/tendermint/misbehaviour_test.go diff --git a/x/ibc/02-client/alias.go b/x/ibc/02-client/alias.go index aedc47bfdc76..00519d9da512 100644 --- a/x/ibc/02-client/alias.go +++ b/x/ibc/02-client/alias.go @@ -9,20 +9,21 @@ package client import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/errors" ) const ( - DefaultCodespace = types.DefaultCodespace - CodeClientExists = types.CodeClientExists - CodeClientNotFound = types.CodeClientNotFound - CodeClientFrozen = types.CodeClientFrozen - CodeConsensusStateNotFound = types.CodeConsensusStateNotFound - CodeInvalidConsensusState = types.CodeInvalidConsensusState - CodeClientTypeNotFound = types.CodeClientTypeNotFound - CodeInvalidClientType = types.CodeInvalidClientType - CodeRootNotFound = types.CodeRootNotFound - CodeInvalidHeader = types.CodeInvalidHeader - CodeInvalidEvidence = types.CodeInvalidEvidence + DefaultCodespace = errors.DefaultCodespace + CodeClientExists = errors.CodeClientExists + CodeClientNotFound = errors.CodeClientNotFound + CodeClientFrozen = errors.CodeClientFrozen + CodeConsensusStateNotFound = errors.CodeConsensusStateNotFound + CodeInvalidConsensusState = errors.CodeInvalidConsensusState + CodeClientTypeNotFound = errors.CodeClientTypeNotFound + CodeInvalidClientType = errors.CodeInvalidClientType + CodeRootNotFound = errors.CodeRootNotFound + CodeInvalidHeader = errors.CodeInvalidHeader + CodeInvalidEvidence = errors.CodeInvalidEvidence AttributeKeyClientID = types.AttributeKeyClientID SubModuleName = types.SubModuleName StoreKey = types.StoreKey @@ -40,16 +41,16 @@ var ( QuerierConsensusState = keeper.QuerierConsensusState QuerierVerifiedRoot = keeper.QuerierVerifiedRoot RegisterCodec = types.RegisterCodec - ErrClientExists = types.ErrClientExists - ErrClientNotFound = types.ErrClientNotFound - ErrClientFrozen = types.ErrClientFrozen - ErrConsensusStateNotFound = types.ErrConsensusStateNotFound - ErrInvalidConsensus = types.ErrInvalidConsensus - ErrClientTypeNotFound = types.ErrClientTypeNotFound - ErrInvalidClientType = types.ErrInvalidClientType - ErrRootNotFound = types.ErrRootNotFound - ErrInvalidHeader = types.ErrInvalidHeader - ErrInvalidEvidence = types.ErrInvalidEvidence + ErrClientExists = errors.ErrClientExists + ErrClientNotFound = errors.ErrClientNotFound + ErrClientFrozen = errors.ErrClientFrozen + ErrConsensusStateNotFound = errors.ErrConsensusStateNotFound + ErrInvalidConsensus = errors.ErrInvalidConsensus + ErrClientTypeNotFound = errors.ErrClientTypeNotFound + ErrInvalidClientType = errors.ErrInvalidClientType + ErrRootNotFound = errors.ErrRootNotFound + ErrInvalidHeader = errors.ErrInvalidHeader + ErrInvalidEvidence = errors.ErrInvalidEvidence ClientStatePath = types.ClientStatePath ClientTypePath = types.ClientTypePath ConsensusStatePath = types.ConsensusStatePath diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index ff5f586a75cb..e7d1ac5c5411 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + cmn "github.com/tendermint/tendermint/libs/common" ) // Blockchain is consensus algorithm which generates valid Headers. It generates @@ -37,6 +38,7 @@ type Evidence interface { Route() string Type() string String() string + Hash() cmn.HexBytes ValidateBasic() sdk.Error // The consensus address of the malicious validator at time of infraction diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go index e180919dec7c..aa1faf956625 100644 --- a/x/ibc/02-client/keeper/client.go +++ b/x/ibc/02-client/keeper/client.go @@ -7,6 +7,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/errors" ) // CreateClient creates a new client state and populates it with a given consensus @@ -17,7 +18,7 @@ func (k Keeper) CreateClient( ) (types.State, error) { _, found := k.GetClientState(ctx, clientID) if found { - return types.State{}, types.ErrClientExists(k.codespace, clientID) + return types.State{}, errors.ErrClientExists(k.codespace, clientID) } _, found = k.GetClientType(ctx, clientID) @@ -36,26 +37,26 @@ func (k Keeper) CreateClient( func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.Header) error { clientType, found := k.GetClientType(ctx, clientID) if !found { - return sdkerrors.Wrap(types.ErrClientTypeNotFound(k.codespace), "cannot update client") + return sdkerrors.Wrap(errors.ErrClientTypeNotFound(k.codespace), "cannot update client") } // check that the header consensus matches the client one if header.ClientType() != clientType { - return sdkerrors.Wrap(types.ErrInvalidConsensus(k.codespace), "cannot update client") + return sdkerrors.Wrap(errors.ErrInvalidConsensus(k.codespace), "cannot update client") } clientState, found := k.GetClientState(ctx, clientID) if !found { - return sdkerrors.Wrap(types.ErrClientNotFound(k.codespace, clientID), "cannot update client") + return sdkerrors.Wrap(errors.ErrClientNotFound(k.codespace, clientID), "cannot update client") } if clientState.Frozen { - return sdkerrors.Wrap(types.ErrClientFrozen(k.codespace, clientID), "cannot update client") + return sdkerrors.Wrap(errors.ErrClientFrozen(k.codespace, clientID), "cannot update client") } consensusState, found := k.GetConsensusState(ctx, clientID) if !found { - return sdkerrors.Wrap(types.ErrConsensusStateNotFound(k.codespace), "cannot update client") + return sdkerrors.Wrap(errors.ErrConsensusStateNotFound(k.codespace), "cannot update client") } if header.GetHeight() < consensusState.GetHeight() { @@ -83,7 +84,7 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, clientID string, evidence exported.Evidence) error { clientState, found := k.GetClientState(ctx, clientID) if !found { - sdk.ResultFromError(types.ErrClientNotFound(k.codespace, clientID)) + sdk.ResultFromError(errors.ErrClientNotFound(k.codespace, clientID)) } err := k.checkMisbehaviour(ctx, evidence) diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index c9f7fbe1c9f7..f753f88656d5 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -11,6 +11,8 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/errors" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -29,8 +31,8 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) return Keeper{ storeKey: key, cdc: cdc, - codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/client", - prefix: []byte(types.SubModuleName + "/"), // "client/" + codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, errors.DefaultCodespace)), // "ibc/client", + prefix: []byte(types.SubModuleName + "/"), // "client/" } } @@ -127,25 +129,27 @@ func (k Keeper) initialize(ctx sdk.Context, clientID string, consensusState expo } func (k Keeper) checkMisbehaviour(ctx sdk.Context, evidence exported.Evidence) error { - // switch evidence.H1().ClientType() { - // case exported.Tendermint: - // var tmEvidence tendermint.Evidence - // _, ok := evidence.(tendermint.Evidence) - // if !ok { - // return sdkerrors.Wrap(types.ErrInvalidClientType(k.codespace), "consensus type is not Tendermint") - // } - // // TODO: pass past consensus states - // return tendermint.CheckMisbehaviour(tmEvidence) - // default: - // panic("unregistered consensus type") - // } + switch evidence.Type() { + case exported.ClientTypeTendermint: + var tmEvidence tendermint.Evidence + _, ok := evidence.(tendermint.Evidence) + if !ok { + return errors.ErrInvalidClientType(k.codespace, "consensus type is not Tendermint") + } + err := tendermint.CheckMisbehaviour(tmEvidence) + if err != nil { + return errors.ErrInvalidEvidence(k.codespace, err.Error()) + } + default: + panic(fmt.Sprintf("unregistered evidence type: %s", evidence.Type())) + } return nil } // freeze updates the state of the client in the event of a misbehaviour func (k Keeper) freeze(ctx sdk.Context, clientState types.State) (types.State, error) { if clientState.Frozen { - return types.State{}, sdkerrors.Wrap(types.ErrClientFrozen(k.codespace, clientState.ID()), "already frozen") + return types.State{}, sdkerrors.Wrap(errors.ErrClientFrozen(k.codespace, clientState.ID()), "already frozen") } clientState.Frozen = true diff --git a/x/ibc/02-client/keeper/querier.go b/x/ibc/02-client/keeper/querier.go index 8c9ce5a263ef..5f56b8d6b01a 100644 --- a/x/ibc/02-client/keeper/querier.go +++ b/x/ibc/02-client/keeper/querier.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/errors" ) // QuerierClientState defines the sdk.Querier to query the IBC client state @@ -20,7 +21,7 @@ func QuerierClientState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byt clientState, found := k.GetClientState(ctx, params.ClientID) if !found { - return nil, types.ErrClientTypeNotFound(k.codespace) + return nil, errors.ErrClientTypeNotFound(k.codespace) } bz, err := types.SubModuleCdc.MarshalJSON(clientState) @@ -42,7 +43,7 @@ func QuerierConsensusState(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([] consensusState, found := k.GetConsensusState(ctx, params.ClientID) if !found { - return nil, types.ErrConsensusStateNotFound(k.codespace) + return nil, errors.ErrConsensusStateNotFound(k.codespace) } bz, err := types.SubModuleCdc.MarshalJSON(consensusState) @@ -64,7 +65,7 @@ func QuerierVerifiedRoot(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]by root, found := k.GetVerifiedRoot(ctx, params.ClientID, params.Height) if !found { - return nil, types.ErrRootNotFound(k.codespace) + return nil, errors.ErrRootNotFound(k.codespace) } bz, err := types.SubModuleCdc.MarshalJSON(root) diff --git a/x/ibc/02-client/types/codec.go b/x/ibc/02-client/types/codec.go index eae86ec2b53d..69985c6044b4 100644 --- a/x/ibc/02-client/types/codec.go +++ b/x/ibc/02-client/types/codec.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" ) -var SubModuleCdc *codec.Codec +var SubModuleCdc = codec.New() // RegisterCodec registers the IBC client interfaces and types func RegisterCodec(cdc *codec.Codec) { @@ -21,4 +21,9 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(tendermint.ConsensusState{}, "ibc/client/tendermint/ConsensusState", nil) cdc.RegisterConcrete(tendermint.Header{}, "ibc/client/tendermint/Header", nil) + cdc.RegisterConcrete(tendermint.Evidence{}, "ibc/client/tendermint/Evidence", nil) +} + +func init() { + RegisterCodec(SubModuleCdc) } diff --git a/x/ibc/02-client/types/errors.go b/x/ibc/02-client/types/errors/errors.go similarity index 94% rename from x/ibc/02-client/types/errors.go rename to x/ibc/02-client/types/errors/errors.go index d4e6e9bb5558..c133bcfef808 100644 --- a/x/ibc/02-client/types/errors.go +++ b/x/ibc/02-client/types/errors/errors.go @@ -1,4 +1,4 @@ -package types +package errors import ( "fmt" @@ -8,7 +8,7 @@ import ( // client error codes const ( - DefaultCodespace sdk.CodespaceType = SubModuleName + DefaultCodespace sdk.CodespaceType = "client" CodeClientExists sdk.CodeType = 101 CodeClientNotFound sdk.CodeType = 102 @@ -68,6 +68,6 @@ func ErrInvalidHeader(codespace sdk.CodespaceType) sdk.Error { } // ErrInvalidEvidence implements sdk.Error -func ErrInvalidEvidence(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidEvidence, "invalid evidence") +func ErrInvalidEvidence(codespace sdk.CodespaceType, msg string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidEvidence, "invalid evidence: %s", msg) } diff --git a/x/ibc/02-client/types/msgs.go b/x/ibc/02-client/types/msgs.go index c9d46cafa4db..17bd0786a91f 100644 --- a/x/ibc/02-client/types/msgs.go +++ b/x/ibc/02-client/types/msgs.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/errors" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -45,10 +46,10 @@ func (msg MsgCreateClient) ValidateBasic() sdk.Error { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid client ID: %s", err.Error())) } if _, err := exported.ClientTypeFromString(msg.ClientType); err != nil { - return ErrInvalidClientType(DefaultCodespace, err.Error()) + return errors.ErrInvalidClientType(errors.DefaultCodespace, err.Error()) } if msg.ConsensusState == nil { - return ErrInvalidConsensus(DefaultCodespace) + return errors.ErrInvalidConsensus(errors.DefaultCodespace) } if msg.Signer.Empty() { return sdk.ErrInvalidAddress("empty address") @@ -100,7 +101,7 @@ func (msg MsgUpdateClient) ValidateBasic() sdk.Error { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid client ID: %s", err.Error())) } if msg.Header == nil { - return ErrInvalidHeader(DefaultCodespace) + return errors.ErrInvalidHeader(errors.DefaultCodespace) } if msg.Signer.Empty() { return sdk.ErrInvalidAddress("empty address") @@ -150,7 +151,10 @@ func (msg MsgSubmitMisbehaviour) ValidateBasic() sdk.Error { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid client ID: %s", err.Error())) } if msg.Evidence == nil { - return ErrInvalidEvidence(DefaultCodespace) + return errors.ErrInvalidEvidence(errors.DefaultCodespace, "evidence is nil") + } + if err := msg.Evidence.ValidateBasic(); err != nil { + return errors.ErrInvalidEvidence(errors.DefaultCodespace, err.Error()) } if msg.Signer.Empty() { return sdk.ErrInvalidAddress("empty address") diff --git a/x/ibc/02-client/types/tendermint/codec.go b/x/ibc/02-client/types/tendermint/codec.go new file mode 100644 index 000000000000..46814fec2479 --- /dev/null +++ b/x/ibc/02-client/types/tendermint/codec.go @@ -0,0 +1,18 @@ +package tendermint + +import ( + "github.com/cosmos/cosmos-sdk/codec" +) + +var SubModuleCdc = codec.New() + +// RegisterCodec registers the Tendermint types +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(ConsensusState{}, "ibc/client/tendermint/ConsensusState", nil) + cdc.RegisterConcrete(Header{}, "ibc/client/tendermint/Header", nil) + cdc.RegisterConcrete(Evidence{}, "ibc/client/tendermint/Evidence", nil) +} + +func init() { + RegisterCodec(SubModuleCdc) +} diff --git a/x/ibc/02-client/types/tendermint/misbehaviour.go b/x/ibc/02-client/types/tendermint/misbehaviour.go index 229a0ab36967..512bb0f72161 100644 --- a/x/ibc/02-client/types/tendermint/misbehaviour.go +++ b/x/ibc/02-client/types/tendermint/misbehaviour.go @@ -1,12 +1,96 @@ package tendermint import ( + "fmt" + + yaml "gopkg.in/yaml.v2" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/errors" + + "github.com/tendermint/tendermint/crypto/tmhash" + cmn "github.com/tendermint/tendermint/libs/common" + tmtypes "github.com/tendermint/tendermint/types" ) -// CheckMisbehaviour checks if the evidence provided is a misbehaviour -func CheckMisbehaviour(evidence exported.Evidence) sdk.Error { - // TODO: check evidence +var _ exported.Evidence = Evidence{} + +// Evidence is a wrapper over tendermint's DuplicateVoteEvidence +// that implements Evidence interface expected by ICS-02 +type Evidence struct { + *tmtypes.DuplicateVoteEvidence + ChainID string `json:"chain_id" yaml:"chain_id"` + ValidatorPower int64 `json:"val_power" yaml:"val_power"` + TotalPower int64 `json:"total_power" yaml:"total_power"` +} + +// Type implements exported.Evidence interface +func (ev Evidence) Route() string { + return exported.ClientTypeTendermint +} + +// Type implements exported.Evidence interface +func (ev Evidence) Type() string { + return exported.ClientTypeTendermint +} + +// String implements exported.Evidence interface +func (ev Evidence) String() string { + bz, err := yaml.Marshal(ev) + if err != nil { + panic(err) + } + return string(bz) +} + +// Hash implements exported.Evidence interface +func (ev Evidence) Hash() cmn.HexBytes { + return tmhash.Sum(SubModuleCdc.MustMarshalBinaryBare(ev)) +} + +// ValidateBasic implements exported.Evidence interface +func (ev Evidence) ValidateBasic() sdk.Error { + if ev.DuplicateVoteEvidence == nil { + return errors.ErrInvalidEvidence(errors.DefaultCodespace, "duplicate evidence is nil") + } + err := ev.DuplicateVoteEvidence.ValidateBasic() + if err != nil { + return errors.ErrInvalidEvidence(errors.DefaultCodespace, err.Error()) + } + if ev.ChainID == "" { + return errors.ErrInvalidEvidence(errors.DefaultCodespace, "chainID is empty") + } + if ev.ValidatorPower <= 0 { + return errors.ErrInvalidEvidence(errors.DefaultCodespace, fmt.Sprintf("Invalid Validator Power: %d", ev.ValidatorPower)) + } + if ev.TotalPower < ev.ValidatorPower { + return errors.ErrInvalidEvidence(errors.DefaultCodespace, fmt.Sprintf("Invalid Total Power: %d", ev.TotalPower)) + } return nil } + +// GetConsensusAddress implements exported.Evidence interface +func (ev Evidence) GetConsensusAddress() sdk.ConsAddress { + return sdk.ConsAddress(ev.DuplicateVoteEvidence.Address()) +} + +// GetHeight implements exported.Evidence interface +func (ev Evidence) GetHeight() int64 { + return ev.DuplicateVoteEvidence.Height() +} + +// GetValidatorPower implements exported.Evidence interface +func (ev Evidence) GetValidatorPower() int64 { + return ev.ValidatorPower +} + +// GetTotalPower implements exported.Evidence interface +func (ev Evidence) GetTotalPower() int64 { + return ev.TotalPower +} + +// CheckMisbehaviour checks if the evidence provided is a misbehaviour +func CheckMisbehaviour(evidence Evidence) error { + return evidence.DuplicateVoteEvidence.Verify(evidence.ChainID, evidence.DuplicateVoteEvidence.PubKey) +} diff --git a/x/ibc/02-client/types/tendermint/misbehaviour_test.go b/x/ibc/02-client/types/tendermint/misbehaviour_test.go new file mode 100644 index 000000000000..fb432e32bcea --- /dev/null +++ b/x/ibc/02-client/types/tendermint/misbehaviour_test.go @@ -0,0 +1,107 @@ +package tendermint + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/crypto/tmhash" + tmtypes "github.com/tendermint/tendermint/types" + yaml "gopkg.in/yaml.v2" +) + +// Copied unimported test functions from tmtypes to use them here +func makeBlockID(hash []byte, partSetSize int, partSetHash []byte) tmtypes.BlockID { + return tmtypes.BlockID{ + Hash: hash, + PartsHeader: tmtypes.PartSetHeader{ + Total: partSetSize, + Hash: partSetHash, + }, + } + +} + +func makeVote(val tmtypes.PrivValidator, chainID string, valIndex int, height int64, round, step int, blockID tmtypes.BlockID) *tmtypes.Vote { + addr := val.GetPubKey().Address() + v := &tmtypes.Vote{ + ValidatorAddress: addr, + ValidatorIndex: valIndex, + Height: height, + Round: round, + Type: tmtypes.SignedMsgType(step), + BlockID: blockID, + } + err := val.SignVote(chainID, v) + if err != nil { + panic(err) + } + return v +} + +func randomDuplicatedVoteEvidence() *tmtypes.DuplicateVoteEvidence { + val := tmtypes.NewMockPV() + blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), 1000, tmhash.Sum([]byte("partshash"))) + blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), 1000, tmhash.Sum([]byte("partshash"))) + const chainID = "mychain" + return &tmtypes.DuplicateVoteEvidence{ + PubKey: val.GetPubKey(), + VoteA: makeVote(val, chainID, 0, 10, 2, 1, blockID), + VoteB: makeVote(val, chainID, 0, 10, 2, 1, blockID2), + } +} + +func TestString(t *testing.T) { + dupEv := randomDuplicatedVoteEvidence() + ev := Evidence{ + DuplicateVoteEvidence: dupEv, + ChainID: "mychain", + ValidatorPower: 10, + TotalPower: 50, + } + + byteStr, err := yaml.Marshal(ev) + require.Nil(t, err) + require.Equal(t, string(byteStr), ev.String(), "Evidence String method does not work as expected") + +} + +func TestValidateBasic(t *testing.T) { + dupEv := randomDuplicatedVoteEvidence() + + // good evidence + ev := Evidence{ + DuplicateVoteEvidence: dupEv, + ChainID: "mychain", + ValidatorPower: 10, + TotalPower: 50, + } + + err := ev.ValidateBasic() + require.Nil(t, err, "good evidence failed on ValidateBasic: %v", err) + + // invalid duplicate evidence + ev.DuplicateVoteEvidence.VoteA = nil + err = ev.ValidateBasic() + require.NotNil(t, err, "invalid duplicate evidence passed on ValidateBasic") + + // reset duplicate evidence to be valid, and set empty chainID + dupEv = randomDuplicatedVoteEvidence() + ev.DuplicateVoteEvidence = dupEv + ev.ChainID = "" + err = ev.ValidateBasic() + require.NotNil(t, err, "invalid chain-id passed on ValidateBasic") + + // reset chainID and set 0 validator power + ev.ChainID = "mychain" + ev.ValidatorPower = 0 + err = ev.ValidateBasic() + require.NotNil(t, err, "invalid validator power passed on ValidateBasic") + + // reset validator power and set invalid total power + ev.ValidatorPower = 10 + ev.TotalPower = 9 + err = ev.ValidateBasic() + require.NotNil(t, err, "invalid total power passed on ValidateBasic") + +} diff --git a/x/ibc/24-host/errors.go b/x/ibc/24-host/errors.go index e1fa5e0e7a08..1468e29d5725 100644 --- a/x/ibc/24-host/errors.go +++ b/x/ibc/24-host/errors.go @@ -13,4 +13,7 @@ var ( // ErrInvalidPath is returned if path string is invalid ErrInvalidPath = sdkerrors.Register(IBCCodeSpace, 2, "invalid path") + + // ErrInvalidEvidence is returned if evidence is invalid + ErrInvalidEvidence = sdkerrors.Register(IBCCodeSpace, 3, "invalid evidence") ) From 6d580aa1429b569de333cb08c83d8366c940dd6c Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Mon, 4 Nov 2019 16:10:22 -0800 Subject: [PATCH 366/378] finish tendermint tests --- .../types/tendermint/consensus_state_test.go | 52 +++++++++++ .../types/tendermint/tendermint_test.go | 87 +++++++++++++++++++ .../02-client/types/tendermint/test_utils.go | 16 ++++ 3 files changed, 155 insertions(+) create mode 100644 x/ibc/02-client/types/tendermint/consensus_state_test.go create mode 100644 x/ibc/02-client/types/tendermint/tendermint_test.go create mode 100644 x/ibc/02-client/types/tendermint/test_utils.go diff --git a/x/ibc/02-client/types/tendermint/consensus_state_test.go b/x/ibc/02-client/types/tendermint/consensus_state_test.go new file mode 100644 index 000000000000..2f4129226228 --- /dev/null +++ b/x/ibc/02-client/types/tendermint/consensus_state_test.go @@ -0,0 +1,52 @@ +package tendermint + +import ( + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/tmhash" + tmtypes "github.com/tendermint/tendermint/types" +) + +func (suite *TendermintTestSuite) TestCheckValidity() { + // valid header + err := suite.cs.checkValidity(suite.header) + require.Nil(suite.T(), err, "validity failed") + + // switch out header ValidatorsHash + suite.header.ValidatorsHash = tmhash.Sum([]byte("hello")) + err = suite.cs.checkValidity(suite.header) + require.NotNil(suite.T(), err, "validator hash is wrong") + + // reset suite and make header.NextValidatorSet different + // from NextValidatorSetHash + suite.SetupTest() + privVal := tmtypes.NewMockPV() + val := tmtypes.NewValidator(privVal.GetPubKey(), 5) + suite.header.NextValidatorSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{val}) + err = suite.cs.checkValidity(suite.header) + require.NotNil(suite.T(), err, "header's next validator set is not consistent with hash") + + // reset and make header fail validatebasic + suite.SetupTest() + suite.header.ChainID = "not_mychain" + err = suite.cs.checkValidity(suite.header) + require.NotNil(suite.T(), err, "invalid header should fail ValidateBasic") +} + +func (suite *TendermintTestSuite) TestCheckUpdate() { + // valid header should successfully update consensus state + cs, err := suite.cs.CheckValidityAndUpdateState(suite.header) + + require.Nil(suite.T(), err, "valid update failed") + require.Equal(suite.T(), suite.header.GetHeight(), cs.GetHeight(), "height not updated") + require.Equal(suite.T(), suite.header.AppHash.Bytes(), cs.GetRoot().GetHash(), "root not updated") + tmCS, _ := cs.(ConsensusState) + require.Equal(suite.T(), suite.header.NextValidatorSet, tmCS.NextValidatorSet, "validator set did not update") + + // make header invalid so update should be unsuccessful + suite.SetupTest() + suite.header.ChainID = "not_mychain" + + cs, err = suite.cs.CheckValidityAndUpdateState(suite.header) + require.NotNil(suite.T(), err) + require.Nil(suite.T(), cs) +} diff --git a/x/ibc/02-client/types/tendermint/tendermint_test.go b/x/ibc/02-client/types/tendermint/tendermint_test.go new file mode 100644 index 000000000000..11817f73e9ff --- /dev/null +++ b/x/ibc/02-client/types/tendermint/tendermint_test.go @@ -0,0 +1,87 @@ +package tendermint + +import ( + "math" + "testing" + "time" + + "github.com/stretchr/testify/suite" + + "github.com/tendermint/tendermint/crypto/tmhash" + tmtypes "github.com/tendermint/tendermint/types" + "github.com/tendermint/tendermint/version" + + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +type TendermintTestSuite struct { + suite.Suite + + privVal tmtypes.PrivValidator + valSet *tmtypes.ValidatorSet + header Header + cs ConsensusState +} + +func (suite *TendermintTestSuite) SetupTest() { + privVal := tmtypes.NewMockPV() + val := tmtypes.NewValidator(privVal.GetPubKey(), 10) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{val}) + vsetHash := valSet.Hash() + timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC) + tmHeader := tmtypes.Header{ + Version: version.Consensus{Block: 2, App: 2}, + ChainID: "mychain", + Height: 3, + Time: timestamp, + NumTxs: 100, + TotalTxs: 1000, + LastBlockID: makeBlockID(make([]byte, tmhash.Size), math.MaxInt64, make([]byte, tmhash.Size)), + LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), + DataHash: tmhash.Sum([]byte("data_hash")), + ValidatorsHash: vsetHash, + NextValidatorsHash: vsetHash, + ConsensusHash: tmhash.Sum([]byte("consensus_hash")), + AppHash: tmhash.Sum([]byte("app_hash")), + LastResultsHash: tmhash.Sum([]byte("last_results_hash")), + EvidenceHash: tmhash.Sum([]byte("evidence_hash")), + ProposerAddress: privVal.GetPubKey().Address(), + } + hhash := tmHeader.Hash() + blockID := makeBlockID(hhash, 3, tmhash.Sum([]byte("part_set"))) + voteSet := tmtypes.NewVoteSet("mychain", 3, 1, tmtypes.PrecommitType, valSet) + commit, err := tmtypes.MakeCommit(blockID, 3, 1, voteSet, []tmtypes.PrivValidator{privVal}) + if err != nil { + panic(err) + } + + signedHeader := tmtypes.SignedHeader{ + Header: &tmHeader, + Commit: commit, + } + + header := Header{ + SignedHeader: signedHeader, + ValidatorSet: valSet, + NextValidatorSet: valSet, + } + + root := commitment.NewRoot(tmhash.Sum([]byte("my root"))) + + cs := ConsensusState{ + ChainID: "mychain", + Height: 3, + Root: root, + NextValidatorSet: valSet, + } + + // set fields in suite + suite.privVal = privVal + suite.valSet = valSet + suite.header = header + suite.cs = cs +} + +func TestTendermintTestSuite(t *testing.T) { + suite.Run(t, new(TendermintTestSuite)) +} diff --git a/x/ibc/02-client/types/tendermint/test_utils.go b/x/ibc/02-client/types/tendermint/test_utils.go new file mode 100644 index 000000000000..c9f9b89f493e --- /dev/null +++ b/x/ibc/02-client/types/tendermint/test_utils.go @@ -0,0 +1,16 @@ +package tendermint + +import ( + tmtypes "github.com/tendermint/tendermint/types" +) + +func makeBlockID(hash []byte, partSetSize int, partSetHash []byte) tmtypes.BlockID { + return tmtypes.BlockID{ + Hash: hash, + PartsHeader: tmtypes.PartSetHeader{ + Total: partSetSize, + Hash: partSetHash, + }, + } + +} From e875ca76a33586b7c7d1e35bf656a5e23e0feb52 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Mon, 4 Nov 2019 16:12:44 -0800 Subject: [PATCH 367/378] complete merge --- .../types/tendermint/misbehaviour_test.go | 43 ------------------- .../02-client/types/tendermint/test_utils.go | 31 +++++++++++++ 2 files changed, 31 insertions(+), 43 deletions(-) diff --git a/x/ibc/02-client/types/tendermint/misbehaviour_test.go b/x/ibc/02-client/types/tendermint/misbehaviour_test.go index fb432e32bcea..f5e75e12f785 100644 --- a/x/ibc/02-client/types/tendermint/misbehaviour_test.go +++ b/x/ibc/02-client/types/tendermint/misbehaviour_test.go @@ -5,52 +5,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto/tmhash" - tmtypes "github.com/tendermint/tendermint/types" yaml "gopkg.in/yaml.v2" ) -// Copied unimported test functions from tmtypes to use them here -func makeBlockID(hash []byte, partSetSize int, partSetHash []byte) tmtypes.BlockID { - return tmtypes.BlockID{ - Hash: hash, - PartsHeader: tmtypes.PartSetHeader{ - Total: partSetSize, - Hash: partSetHash, - }, - } - -} - -func makeVote(val tmtypes.PrivValidator, chainID string, valIndex int, height int64, round, step int, blockID tmtypes.BlockID) *tmtypes.Vote { - addr := val.GetPubKey().Address() - v := &tmtypes.Vote{ - ValidatorAddress: addr, - ValidatorIndex: valIndex, - Height: height, - Round: round, - Type: tmtypes.SignedMsgType(step), - BlockID: blockID, - } - err := val.SignVote(chainID, v) - if err != nil { - panic(err) - } - return v -} - -func randomDuplicatedVoteEvidence() *tmtypes.DuplicateVoteEvidence { - val := tmtypes.NewMockPV() - blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), 1000, tmhash.Sum([]byte("partshash"))) - blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), 1000, tmhash.Sum([]byte("partshash"))) - const chainID = "mychain" - return &tmtypes.DuplicateVoteEvidence{ - PubKey: val.GetPubKey(), - VoteA: makeVote(val, chainID, 0, 10, 2, 1, blockID), - VoteB: makeVote(val, chainID, 0, 10, 2, 1, blockID2), - } -} - func TestString(t *testing.T) { dupEv := randomDuplicatedVoteEvidence() ev := Evidence{ diff --git a/x/ibc/02-client/types/tendermint/test_utils.go b/x/ibc/02-client/types/tendermint/test_utils.go index c9f9b89f493e..a88bd13d3b1c 100644 --- a/x/ibc/02-client/types/tendermint/test_utils.go +++ b/x/ibc/02-client/types/tendermint/test_utils.go @@ -1,9 +1,11 @@ package tendermint import ( + "github.com/tendermint/tendermint/crypto/tmhash" tmtypes "github.com/tendermint/tendermint/types" ) +// Copied unimported test functions from tmtypes to use them here func makeBlockID(hash []byte, partSetSize int, partSetHash []byte) tmtypes.BlockID { return tmtypes.BlockID{ Hash: hash, @@ -14,3 +16,32 @@ func makeBlockID(hash []byte, partSetSize int, partSetHash []byte) tmtypes.Block } } + +func makeVote(val tmtypes.PrivValidator, chainID string, valIndex int, height int64, round, step int, blockID tmtypes.BlockID) *tmtypes.Vote { + addr := val.GetPubKey().Address() + v := &tmtypes.Vote{ + ValidatorAddress: addr, + ValidatorIndex: valIndex, + Height: height, + Round: round, + Type: tmtypes.SignedMsgType(step), + BlockID: blockID, + } + err := val.SignVote(chainID, v) + if err != nil { + panic(err) + } + return v +} + +func randomDuplicatedVoteEvidence() *tmtypes.DuplicateVoteEvidence { + val := tmtypes.NewMockPV() + blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), 1000, tmhash.Sum([]byte("partshash"))) + blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), 1000, tmhash.Sum([]byte("partshash"))) + const chainID = "mychain" + return &tmtypes.DuplicateVoteEvidence{ + PubKey: val.GetPubKey(), + VoteA: makeVote(val, chainID, 0, 10, 2, 1, blockID), + VoteB: makeVote(val, chainID, 0, 10, 2, 1, blockID2), + } +} From cd0aa22bfc963fa7413126de2d1c069e632cdf98 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Mon, 4 Nov 2019 19:23:35 -0800 Subject: [PATCH 368/378] Add tests for msgs --- x/ibc/02-client/types/msgs_test.go | 138 +++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 x/ibc/02-client/types/msgs_test.go diff --git a/x/ibc/02-client/types/msgs_test.go b/x/ibc/02-client/types/msgs_test.go new file mode 100644 index 000000000000..8dc9a15d21c5 --- /dev/null +++ b/x/ibc/02-client/types/msgs_test.go @@ -0,0 +1,138 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/errors" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" + "github.com/tendermint/tendermint/crypto/secp256k1" + cmn "github.com/tendermint/tendermint/libs/common" +) + +func TestMsgCreateClientValidateBasic(t *testing.T) { + cs := tendermint.ConsensusState{} + privKey := secp256k1.GenPrivKey() + signer := sdk.AccAddress(privKey.PubKey().Address()) + testMsgs := []MsgCreateClient{ + NewMsgCreateClient(exported.ClientTypeTendermint, exported.ClientTypeTendermint, cs, signer), // valid msg + NewMsgCreateClient("badClient", exported.ClientTypeTendermint, cs, signer), // invalid client id + NewMsgCreateClient("goodChain", "bad_type", cs, signer), // invalid client type + NewMsgCreateClient("goodChain", exported.ClientTypeTendermint, nil, signer), // nil Consensus State + NewMsgCreateClient("goodChain", exported.ClientTypeTendermint, cs, sdk.AccAddress{}), // empty signer + } + + cases := []struct { + msg MsgCreateClient + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "invalid client id passed"}, + {testMsgs[2], false, "unregistered client type passed"}, + {testMsgs[3], false, "Nil Consensus State in msg passed"}, + {testMsgs[4], false, "Empty address passed"}, + } + + for i, tc := range cases { + err := tc.msg.ValidateBasic() + if tc.expPass { + require.Nil(t, err, "Msg %d failed: %v", i, err) + } else { + require.NotNil(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +func TestMsgUpdateClient(t *testing.T) { + privKey := secp256k1.GenPrivKey() + signer := sdk.AccAddress(privKey.PubKey().Address()) + testMsgs := []MsgUpdateClient{ + NewMsgUpdateClient(exported.ClientTypeTendermint, tendermint.Header{}, signer), // valid msg + NewMsgUpdateClient("badClient", tendermint.Header{}, signer), // bad client id + NewMsgUpdateClient(exported.ClientTypeTendermint, nil, signer), // nil Header + NewMsgUpdateClient(exported.ClientTypeTendermint, tendermint.Header{}, sdk.AccAddress{}), // empty address + } + + cases := []struct { + msg MsgUpdateClient + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "invalid client id passed"}, + {testMsgs[2], false, "Nil Header passed"}, + {testMsgs[3], false, "Empty address passed"}, + } + + for i, tc := range cases { + err := tc.msg.ValidateBasic() + if tc.expPass { + require.Nil(t, err, "Msg %d failed: %v", i, err) + } else { + require.NotNil(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +var _ exported.Evidence = mockEvidence{} + +// mock GoodEvidence +type mockEvidence struct{} + +// Implement Evidence interface +func (me mockEvidence) Route() string { return "mock" } +func (me mockEvidence) Type() string { return "mock" } +func (me mockEvidence) String() string { return "mock" } +func (me mockEvidence) Hash() cmn.HexBytes { return cmn.HexBytes([]byte("mock")) } +func (me mockEvidence) ValidateBasic() sdk.Error { return nil } +func (me mockEvidence) GetConsensusAddress() sdk.ConsAddress { return sdk.ConsAddress{} } +func (me mockEvidence) GetHeight() int64 { return 3 } +func (me mockEvidence) GetValidatorPower() int64 { return 3 } +func (me mockEvidence) GetTotalPower() int64 { return 5 } + +// mock bad evidence +type mockBadEvidence struct { + mockEvidence +} + +// Override ValidateBasic +func (mbe mockBadEvidence) ValidateBasic() sdk.Error { + return errors.ErrInvalidEvidence(errors.DefaultCodespace, "invalid evidence") +} + +func TestMsgSubmitMisbehaviour(t *testing.T) { + privKey := secp256k1.GenPrivKey() + signer := sdk.AccAddress(privKey.PubKey().Address()) + testMsgs := []MsgSubmitMisbehaviour{ + NewMsgSubmitMisbehaviour(exported.ClientTypeTendermint, mockEvidence{}, signer), // valid msg + NewMsgSubmitMisbehaviour("badClient", mockEvidence{}, signer), // bad client id + NewMsgSubmitMisbehaviour(exported.ClientTypeTendermint, nil, signer), // nil evidence + NewMsgSubmitMisbehaviour(exported.ClientTypeTendermint, mockBadEvidence{}, signer), // invalid evidence + NewMsgSubmitMisbehaviour(exported.ClientTypeTendermint, mockEvidence{}, sdk.AccAddress{}), // empty signer + } + + cases := []struct { + msg MsgSubmitMisbehaviour + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "invalid client id passed"}, + {testMsgs[2], false, "Nil Evidence passed"}, + {testMsgs[3], false, "Invalid Evidence passed"}, + {testMsgs[4], false, "Empty address passed"}, + } + + for i, tc := range cases { + err := tc.msg.ValidateBasic() + if tc.expPass { + require.Nil(t, err, "Msg %d failed: %v", i, err) + } else { + require.NotNil(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} From 0c8b759156dac6ce0510329c1b4e16802df719b4 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 5 Nov 2019 12:29:16 +0100 Subject: [PATCH 369/378] upstream changes --- x/ibc/02-client/client/cli/query.go | 59 +++++++++++++++++---- x/ibc/02-client/client/cli/tx.go | 4 +- x/ibc/02-client/client/utils/utils.go | 75 +++++++++++++++++++++++++++ x/ibc/02-client/keeper/client.go | 1 + x/ibc/02-client/keeper/keeper.go | 63 +++++++++++----------- x/ibc/02-client/types/codec.go | 1 + x/ibc/02-client/types/querier.go | 29 +++++++++++ 7 files changed, 191 insertions(+), 41 deletions(-) create mode 100644 x/ibc/02-client/client/utils/utils.go diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 9bd992b5d939..2f7166333899 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/utils" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" @@ -34,6 +35,8 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { GetCmdQueryHeader(cdc), GetCmdQueryClientState(queryRoute, cdc), GetCmdQueryRoot(queryRoute, cdc), + GetCmdNodeConsensusState(queryRoute, cdc), + GetCmdQueryPath(queryRoute, cdc), )...) return ics02ClientQueryCmd } @@ -166,7 +169,6 @@ $ %s query ibc client consensus-state [client-id] } // GetCmdQueryHeader defines the command to query the latest header on the chain -// TODO: do we really need this cmd ?? func GetCmdQueryHeader(cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "header", @@ -180,6 +182,33 @@ $ %s query ibc client header RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) + header, err := utils.GetTendermintHeader(cliCtx) + if err != nil { + return err + } + + return cliCtx.PrintOutput(header) + }, + } +} + +// GetCmdNodeConsensusState defines the command to query the latest consensus state of a node +// The result is feed to client creation +func GetCmdNodeConsensusState(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "node-state", + Short: "Query a node consensus state", + Long: strings.TrimSpace( + fmt.Sprintf(`Query a node consensus state. This result is feed to the client creation transaction. + +Example: +$ %s query ibc client node-state + `, version.ClientName), + ), + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + node, err := cliCtx.GetNode() if err != nil { return err @@ -203,18 +232,28 @@ $ %s query ibc client header return err } - nextValidators, err := node.Validators(&height) - if err != nil { - return err + var state exported.ConsensusState + state = tendermint.ConsensusState{ + ChainID: commit.ChainID, + Height: uint64(commit.Height), + Root: commitment.NewRoot(commit.AppHash), + NextValidatorSet: tmtypes.NewValidatorSet(validators.Validators), } - header := tendermint.Header{ - SignedHeader: commit.SignedHeader, - ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), - NextValidatorSet: tmtypes.NewValidatorSet(nextValidators.Validators), - } + return cliCtx.PrintOutput(state) + }, + } +} - return cliCtx.PrintOutput(header) +// GetCmdQueryPath defines the command to query the commitment path. +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 { + ctx := context.NewCLIContext().WithCodec(cdc) + path := commitment.NewPrefix([]byte("ibc")) + return ctx.PrintOutput(path) }, } } diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/02-client/client/cli/tx.go index fc92efb874ba..4cbc97b39842 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/02-client/client/cli/tx.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" @@ -51,7 +52,7 @@ $ %s tx ibc client create [client-id] [path/to/consensus_state.json] --from node Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - cliCtx := context.NewCLIContext().WithCodec(cdc) + cliCtx := context.NewCLIContext().WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) clientID := args[0] @@ -72,6 +73,7 @@ $ %s tx ibc client create [client-id] [path/to/consensus_state.json] --from node clientID, state.ClientType().String(), state, cliCtx.GetFromAddress(), ) + if err := msg.ValidateBasic(); err != nil { return err } diff --git a/x/ibc/02-client/client/utils/utils.go b/x/ibc/02-client/client/utils/utils.go new file mode 100644 index 000000000000..5d0786267373 --- /dev/null +++ b/x/ibc/02-client/client/utils/utils.go @@ -0,0 +1,75 @@ +package utils + +import ( + "fmt" + + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" +) + +// QueryConsensusStateProof queries the store to get the consensus state and a +// merkle proof. +func QueryConsensusStateProof(cliCtx client.CLIContext, clientID string) (types.ConsensusStateResponse, error) { + var conStateRes types.ConsensusStateResponse + req := abci.RequestQuery{ + Path: "store/ibc/key", + Data: []byte(fmt.Sprintf("clients/%s/consensusState", clientID)), + Prove: true, + } + + res, err := cliCtx.QueryABCI(req) + if err != nil { + return conStateRes, err + } + + var cs tendermint.ConsensusState + if err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &cs); err != nil { + return conStateRes, err + } + return types.NewConsensusStateResponse(clientID, cs, res.Proof, res.Height), nil +} + +// GetTendermintHeader takes a client context and returns the appropriate +// tendermint header +func GetTendermintHeader(cliCtx context.CLIContext) (tendermint.Header, error) { + node, err := cliCtx.GetNode() + if err != nil { + return tendermint.Header{}, err + } + + info, err := node.ABCIInfo() + if err != nil { + return tendermint.Header{}, err + } + + height := info.Response.LastBlockHeight + prevheight := height - 1 + + commit, err := node.Commit(&height) + if err != nil { + return tendermint.Header{}, err + } + + validators, err := node.Validators(&prevheight) + if err != nil { + return tendermint.Header{}, err + } + + nextvalidators, err := node.Validators(&height) + if err != nil { + return tendermint.Header{}, err + } + + header := tendermint.Header{ + SignedHeader: commit.SignedHeader, + ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), + NextValidatorSet: tmtypes.NewValidatorSet(nextvalidators.Validators), + } + + return header, nil +} diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go index aa1faf956625..b75f8174939a 100644 --- a/x/ibc/02-client/keeper/client.go +++ b/x/ibc/02-client/keeper/client.go @@ -30,6 +30,7 @@ func (k Keeper) CreateClient( k.SetVerifiedRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) k.SetClientState(ctx, clientState) k.SetClientType(ctx, clientID, clientType) + k.Logger(ctx).Info(fmt.Sprintf("client %s created at height %d", clientID, consensusState.GetHeight())) return clientState, nil } diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index f753f88656d5..2dc106d72d33 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -11,8 +11,6 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/errors" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -31,8 +29,9 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) return Keeper{ storeKey: key, cdc: cdc, - codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, errors.DefaultCodespace)), // "ibc/client", - prefix: []byte(types.SubModuleName + "/"), // "client/" + codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/client", + prefix: []byte{}, + // prefix: []byte(types.SubModuleName + "/"), // "client/" } } @@ -102,6 +101,7 @@ func (k Keeper) SetConsensusState(ctx sdk.Context, clientID string, consensusSta // a client func (k Keeper) GetVerifiedRoot(ctx sdk.Context, clientID string, height uint64) (commitment.RootI, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.prefix) + bz := store.Get(types.KeyRoot(clientID, height)) if bz == nil { return nil, false @@ -129,27 +129,25 @@ func (k Keeper) initialize(ctx sdk.Context, clientID string, consensusState expo } func (k Keeper) checkMisbehaviour(ctx sdk.Context, evidence exported.Evidence) error { - switch evidence.Type() { - case exported.ClientTypeTendermint: - var tmEvidence tendermint.Evidence - _, ok := evidence.(tendermint.Evidence) - if !ok { - return errors.ErrInvalidClientType(k.codespace, "consensus type is not Tendermint") - } - err := tendermint.CheckMisbehaviour(tmEvidence) - if err != nil { - return errors.ErrInvalidEvidence(k.codespace, err.Error()) - } - default: - panic(fmt.Sprintf("unregistered evidence type: %s", evidence.Type())) - } + // switch evidence.H1().ClientType() { + // case exported.Tendermint: + // var tmEvidence tendermint.Evidence + // _, ok := evidence.(tendermint.Evidence) + // if !ok { + // return sdkerrors.Wrap(types.ErrInvalidClientType(k.codespace), "consensus type is not Tendermint") + // } + // // TODO: pass past consensus states + // return tendermint.CheckMisbehaviour(tmEvidence) + // default: + // panic("unregistered consensus type") + // } return nil } // freeze updates the state of the client in the event of a misbehaviour func (k Keeper) freeze(ctx sdk.Context, clientState types.State) (types.State, error) { if clientState.Frozen { - return types.State{}, sdkerrors.Wrap(errors.ErrClientFrozen(k.codespace, clientState.ID()), "already frozen") + return types.State{}, sdkerrors.Wrap(types.ErrClientFrozen(k.codespace, clientState.ID()), "already frozen") } clientState.Frozen = true @@ -159,17 +157,20 @@ func (k Keeper) freeze(ctx sdk.Context, clientState types.State) (types.State, e // VerifyMembership state membership verification function defined by the client type func (k Keeper) VerifyMembership( ctx sdk.Context, - clientState types.State, + clientID string, height uint64, // sequence proof commitment.ProofI, path commitment.PathI, value []byte, ) bool { - if clientState.Frozen { - return false - } + // XXX: commented out for demo + /* + if clientState.Frozen { + return false + } + */ - root, found := k.GetVerifiedRoot(ctx, clientState.ID(), height) + root, found := k.GetVerifiedRoot(ctx, clientID, height) if !found { return false } @@ -180,16 +181,18 @@ func (k Keeper) VerifyMembership( // VerifyNonMembership state non-membership function defined by the client type func (k Keeper) VerifyNonMembership( ctx sdk.Context, - clientState types.State, + clientID string, height uint64, // sequence proof commitment.ProofI, path commitment.PathI, ) bool { - if clientState.Frozen { - return false - } - - root, found := k.GetVerifiedRoot(ctx, clientState.ID(), height) + // XXX: commented out for demo + /* + if clientState.Frozen { + return false + } + */ + root, found := k.GetVerifiedRoot(ctx, clientID, height) if !found { return false } diff --git a/x/ibc/02-client/types/codec.go b/x/ibc/02-client/types/codec.go index 69985c6044b4..7a141e811a0a 100644 --- a/x/ibc/02-client/types/codec.go +++ b/x/ibc/02-client/types/codec.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" ) +// SubModuleCdc defines the IBC client codec. var SubModuleCdc = codec.New() // RegisterCodec registers the IBC client interfaces and types diff --git a/x/ibc/02-client/types/querier.go b/x/ibc/02-client/types/querier.go index 2f5de5af0572..7638c0200882 100644 --- a/x/ibc/02-client/types/querier.go +++ b/x/ibc/02-client/types/querier.go @@ -1,5 +1,13 @@ package types +import ( + "strings" + + tmtypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/tendermint/tendermint/crypto/merkle" +) + // query routes supported by the IBC client Querier const ( QueryClientState = "client_state" @@ -35,3 +43,24 @@ func NewQueryCommitmentRootParams(id string, height uint64) QueryCommitmentRootP Height: height, } } + +// ConsensusStateResponse defines the client response for a Consensus state query. +// It includes the commitment proof and the height of the proof. +type ConsensusStateResponse struct { + ConsensusState tmtypes.ConsensusState + Proof commitment.Proof `json:"proof,omitempty" yaml:"proof,omitempty"` + ProofPath commitment.Path `json:"proof_path,omitempty" yaml:"proof_path,omitempty"` + ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` +} + +// NewConsensusStateResponse creates a new ConsensusStateResponse instance. +func NewConsensusStateResponse( + clientID string, cs tmtypes.ConsensusState, proof *merkle.Proof, height int64, +) ConsensusStateResponse { + return ConsensusStateResponse{ + ConsensusState: cs, + Proof: commitment.Proof{Proof: proof}, + ProofPath: commitment.NewPath(strings.Split(ConsensusStatePath(clientID), "/")), + ProofHeight: uint64(height), + } +} From c6fa07be197cefe0967706968c6ad58b6ae77a38 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 5 Nov 2019 12:35:53 +0100 Subject: [PATCH 370/378] fix --- x/ibc/02-client/keeper/keeper.go | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index 2dc106d72d33..ce0d54e99782 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -11,6 +11,8 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/errors" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -29,7 +31,7 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) return Keeper{ storeKey: key, cdc: cdc, - codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/client", + codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, errors.DefaultCodespace)), // "ibc/client", prefix: []byte{}, // prefix: []byte(types.SubModuleName + "/"), // "client/" } @@ -129,25 +131,27 @@ func (k Keeper) initialize(ctx sdk.Context, clientID string, consensusState expo } func (k Keeper) checkMisbehaviour(ctx sdk.Context, evidence exported.Evidence) error { - // switch evidence.H1().ClientType() { - // case exported.Tendermint: - // var tmEvidence tendermint.Evidence - // _, ok := evidence.(tendermint.Evidence) - // if !ok { - // return sdkerrors.Wrap(types.ErrInvalidClientType(k.codespace), "consensus type is not Tendermint") - // } - // // TODO: pass past consensus states - // return tendermint.CheckMisbehaviour(tmEvidence) - // default: - // panic("unregistered consensus type") - // } + switch evidence.Type() { + case exported.ClientTypeTendermint: + var tmEvidence tendermint.Evidence + _, ok := evidence.(tendermint.Evidence) + if !ok { + return errors.ErrInvalidClientType(k.codespace, "consensus type is not Tendermint") + } + err := tendermint.CheckMisbehaviour(tmEvidence) + if err != nil { + return errors.ErrInvalidEvidence(k.codespace, err.Error()) + } + default: + panic(fmt.Sprintf("unregistered evidence type: %s", evidence.Type())) + } return nil } // freeze updates the state of the client in the event of a misbehaviour func (k Keeper) freeze(ctx sdk.Context, clientState types.State) (types.State, error) { if clientState.Frozen { - return types.State{}, sdkerrors.Wrap(types.ErrClientFrozen(k.codespace, clientState.ID()), "already frozen") + return types.State{}, sdkerrors.Wrap(errors.ErrClientFrozen(k.codespace, clientState.ID()), "already frozen") } clientState.Frozen = true From 820482f030deb87f766ff0cf3f54928b68a38dd9 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 5 Nov 2019 12:42:37 +0100 Subject: [PATCH 371/378] upstream changes --- x/ibc/23-commitment/merkle.go | 10 +-------- x/ibc/24-host/errors.go | 3 +++ x/ibc/24-host/utils.go | 11 ++++++++++ x/ibc/24-host/validate.go | 38 ++++++++++++++++++++++++++++------- 4 files changed, 46 insertions(+), 16 deletions(-) create mode 100644 x/ibc/24-host/utils.go diff --git a/x/ibc/23-commitment/merkle.go b/x/ibc/23-commitment/merkle.go index 8754823e0683..ab428eeaf737 100644 --- a/x/ibc/23-commitment/merkle.go +++ b/x/ibc/23-commitment/merkle.go @@ -2,7 +2,6 @@ package commitment import ( "errors" - "strings" "github.com/tendermint/tendermint/crypto/merkle" @@ -111,14 +110,7 @@ func ApplyPrefix(prefix PrefixI, path string) (Path, error) { return Path{}, errors.New("prefix can't be empty") } - // Split paths by the separator - pathSlice := strings.Split(path, "/") - keyPath := merkle.KeyPath{} - commitmentPath := NewPath(pathSlice) - - keyPath = keyPath.AppendKey(prefix.Bytes(), merkle.KeyEncodingURL) - commitmentPath.KeyPath = append(keyPath, commitmentPath.KeyPath...) - return commitmentPath, nil + return NewPath([]string{string(prefix.Bytes()), path}), nil } var _ ProofI = Proof{} diff --git a/x/ibc/24-host/errors.go b/x/ibc/24-host/errors.go index e1fa5e0e7a08..afc1c26ea303 100644 --- a/x/ibc/24-host/errors.go +++ b/x/ibc/24-host/errors.go @@ -13,4 +13,7 @@ var ( // ErrInvalidPath is returned if path string is invalid ErrInvalidPath = sdkerrors.Register(IBCCodeSpace, 2, "invalid path") + + // ErrInvalidPacket is returned if packets embedded in msg are invalid + ErrInvalidPacket = sdkerrors.Register(IBCCodeSpace, 3, "invalid packet extracted from msg") ) diff --git a/x/ibc/24-host/utils.go b/x/ibc/24-host/utils.go new file mode 100644 index 000000000000..c75f356561f6 --- /dev/null +++ b/x/ibc/24-host/utils.go @@ -0,0 +1,11 @@ +package host + +// RemovePath is an util function to remove a path from a set. +func RemovePath(paths []string, path string) ([]string, bool) { + for i, p := range paths { + if p == path { + return append(paths[:i], paths[i+1:]...), true + } + } + return paths, false +} diff --git a/x/ibc/24-host/validate.go b/x/ibc/24-host/validate.go index 38128de234ae..6632d27c25c1 100644 --- a/x/ibc/24-host/validate.go +++ b/x/ibc/24-host/validate.go @@ -22,18 +22,14 @@ var isAlphaNumeric = regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString // ValidateFn function type to validate path and identifier bytestrings type ValidateFn func(string) error -// DefaultIdentifierValidator is the default validator function for Client, -// Connection and Channel identifiers. -// A valid Identifier must be between 10-20 characters and only contain lowercase -// alphabetic characters, -func DefaultIdentifierValidator(id string) error { +func defaultIdentifierValidator(id string, min, max int) error { // valid id MUST NOT contain "/" separator if strings.Contains(id, "/") { return sdkerrors.Wrap(ErrInvalidID, "identifier cannot contain separator: /") } // valid id must be between 10 and 20 characters - if len(id) < 10 || len(id) > 20 { - return sdkerrors.Wrapf(ErrInvalidID, "identifier has invalid length: %d, must be between 10-20 characters", len(id)) + if len(id) < min || len(id) > max { + return sdkerrors.Wrapf(ErrInvalidID, "identifier has invalid length: %d, must be between %d-%d characters", len(id), min, max) } // valid id must contain only lower alphabetic characters if !isAlphaLower(id) { @@ -42,6 +38,34 @@ func DefaultIdentifierValidator(id string) error { return nil } +// DefaultClientIdentifierValidator is the default validator function for Client identifiers +// A valid Identifier must be between 10-20 characters and only contain lowercase +// alphabetic characters, +func DefaultClientIdentifierValidator(id string) error { + return defaultIdentifierValidator(id, 10, 20) +} + +// DefaultConnectionIdentifierValidator is the default validator function for Connection identifiers +// A valid Identifier must be between 10-20 characters and only contain lowercase +// alphabetic characters, +func DefaultConnectionIdentifierValidator(id string) error { + return defaultIdentifierValidator(id, 10, 20) +} + +// DefaultChannelIdentifierValidator is the default validator function for Channel identifiers +// A valid Identifier must be between 10-20 characters and only contain lowercase +// alphabetic characters, +func DefaultChannelIdentifierValidator(id string) error { + return defaultIdentifierValidator(id, 10, 20) +} + +// DefaultPortIdentifierValidator is the default validator function for Port identifiers +// A valid Identifier must be between 2-20 characters and only contain lowercase +// alphabetic characters, +func DefaultPortIdentifierValidator(id string) error { + return defaultIdentifierValidator(id, 2, 20) +} + // NewPathValidator takes in a Identifier Validator function and returns // a Path Validator function which requires path only has valid identifiers // alphanumeric character strings, and "/" separators From b5442d341164bfcbc81245a68a775adfdf29068e Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 5 Nov 2019 12:52:34 +0100 Subject: [PATCH 372/378] fix cons state --- x/ibc/02-client/types/tendermint/consensus_state.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/ibc/02-client/types/tendermint/consensus_state.go b/x/ibc/02-client/types/tendermint/consensus_state.go index 74e8a9f42dfa..3ad0892a9ea8 100644 --- a/x/ibc/02-client/types/tendermint/consensus_state.go +++ b/x/ibc/02-client/types/tendermint/consensus_state.go @@ -75,8 +75,8 @@ func (cs ConsensusState) checkValidity(header Header) error { } // abortTransactionUnless(consensusState.publicKey.verify(header.signature)) - return cs.NextValidatorSet.VerifyFutureCommit( - header.ValidatorSet, cs.ChainID, header.Commit.BlockID, header.Height, header.Commit, + return header.ValidatorSet.VerifyFutureCommit( + cs.NextValidatorSet, cs.ChainID, header.Commit.BlockID, header.Height, header.Commit, ) } From 7c67236659ba14ae13b50dd22f655cd9161066b9 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 5 Nov 2019 12:55:29 +0100 Subject: [PATCH 373/378] context changes --- client/context/context.go | 47 ++++++++++++++++++++++++++++++++++ client/context/query.go | 53 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/client/context/context.go b/client/context/context.go index 2fd6ff66f8be..07168ecdf6ca 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -99,6 +99,53 @@ func NewCLIContextWithFrom(from string) CLIContext { return ctx.WithVerifier(verifier) } +// NewCLIContextIBC takes additional arguements +func NewCLIContextIBC(from string, chainID string, nodeURI string) CLIContext { + var rpc rpcclient.Client + + genOnly := viper.GetBool(flags.FlagGenerateOnly) + fromAddress, fromName, err := GetFromFields(from, genOnly) + if err != nil { + fmt.Printf("failed to get from fields: %v", err) + os.Exit(1) + } + + if !genOnly { + if nodeURI != "" { + rpc = rpcclient.NewHTTP(nodeURI, "/websocket") + } + } + + ctx := CLIContext{ + Client: rpc, + ChainID: chainID, + Output: os.Stdout, + NodeURI: nodeURI, + From: from, + OutputFormat: viper.GetString(cli.OutputFlag), + Height: viper.GetInt64(flags.FlagHeight), + HomeDir: viper.GetString(flags.FlagHome), + TrustNode: viper.GetBool(flags.FlagTrustNode), + UseLedger: viper.GetBool(flags.FlagUseLedger), + BroadcastMode: viper.GetString(flags.FlagBroadcastMode), + Simulate: viper.GetBool(flags.FlagDryRun), + GenerateOnly: genOnly, + FromAddress: fromAddress, + FromName: fromName, + Indent: viper.GetBool(flags.FlagIndentResponse), + SkipConfirm: viper.GetBool(flags.FlagSkipConfirmation), + } + + // create a verifier for the specific chain ID and RPC client + verifier, err := CreateVerifier(ctx, DefaultVerifierCacheSize) + if err != nil && viper.IsSet(flags.FlagTrustNode) { + fmt.Printf("failed to create verifier: %s\n", err) + os.Exit(1) + } + + return ctx.WithVerifier(verifier) +} + // NewCLIContext returns a new initialized CLIContext with parameters from the // command line using Viper. func NewCLIContext() CLIContext { return NewCLIContextWithFrom(viper.GetString(flags.FlagFrom)) } diff --git a/client/context/query.go b/client/context/query.go index 81917a1c493c..2a01a7577a0c 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -3,6 +3,7 @@ package context import ( "fmt" "strings" + "time" "github.com/pkg/errors" @@ -12,6 +13,7 @@ import ( tmliteErr "github.com/tendermint/tendermint/lite/errors" tmliteProxy "github.com/tendermint/tendermint/lite/proxy" rpcclient "github.com/tendermint/tendermint/rpc/client" + ctypes "github.com/tendermint/tendermint/rpc/core/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/store/rootmulti" @@ -28,6 +30,55 @@ func (ctx CLIContext) GetNode() (rpcclient.Client, error) { return ctx.Client, nil } +// WaitForNBlocks blocks until the node defined on the context has advanced N blocks +func (ctx CLIContext) WaitForNBlocks(n int64) { + node, err := ctx.GetNode() + if err != nil { + panic(err) + } + + resBlock, err := node.Block(nil) + var height int64 + if err != nil || resBlock.Block == nil { + // wait for the first block to exist + ctx.waitForHeight(1) + height = 1 + n + } else { + height = resBlock.Block.Height + n + } + ctx.waitForHeight(height) +} + +func (ctx CLIContext) waitForHeight(height int64) { + node, err := ctx.GetNode() + if err != nil { + panic(err) + } + + for { + // get url, try a few times + var resBlock *ctypes.ResultBlock + var err error + INNER: + for i := 0; i < 5; i++ { + resBlock, err = node.Block(nil) + if err == nil { + break INNER + } + time.Sleep(time.Millisecond * 200) + } + if err != nil { + panic(err) + } + + if resBlock.Block != nil && resBlock.Block.Height >= height { + return + } + + time.Sleep(time.Millisecond * 100) + } +} + // Query performs a query to a Tendermint node with the provided path. // It returns the result and height of the query upon success or an error if // the query fails. @@ -97,7 +148,7 @@ func (ctx CLIContext) queryABCI(req abci.RequestQuery) (resp abci.ResponseQuery, opts := rpcclient.ABCIQueryOptions{ Height: ctx.Height, - Prove: !ctx.TrustNode, + Prove: req.Prove || !ctx.TrustNode, } result, err := node.ABCIQueryWithOptions(req.Path, req.Data, opts) From df6bd66e38dde28d80ff8a22c985dcd30dc889ac Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 5 Nov 2019 13:24:57 +0100 Subject: [PATCH 374/378] fix cli tx --- x/ibc/03-connection/alias.go | 1 - x/ibc/03-connection/client/cli/tx.go | 110 ++++++++++++++++++--------- 2 files changed, 73 insertions(+), 38 deletions(-) diff --git a/x/ibc/03-connection/alias.go b/x/ibc/03-connection/alias.go index a131d0befe9c..27757d8163e5 100644 --- a/x/ibc/03-connection/alias.go +++ b/x/ibc/03-connection/alias.go @@ -47,7 +47,6 @@ var ( QuerierConnection = keeper.QuerierConnection QuerierClientConnections = keeper.QuerierClientConnections RegisterCodec = types.RegisterCodec - SetMsgConnectionCodec = types.SetMsgConnectionCodec NewConnectionEnd = types.NewConnectionEnd NewCounterparty = types.NewCounterparty StateFromString = types.StateFromString diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index 4d93a8998360..22ccf7777d31 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -15,7 +15,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" @@ -23,12 +22,12 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/client/utils" clientutils "github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/utils" clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" abci "github.com/tendermint/tendermint/abci/types" ) +// Connection Handshake flags const ( FlagNode1 = "node1" FlagNode2 = "node2" @@ -95,6 +94,10 @@ $ %s tx ibc connection open-init [connection-id] [client-id] [counterparty-conne counterpartyPrefix, cliCtx.GetFromAddress(), ) + if err := msg.ValidateBasic(); err != nil { + return err + } + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } @@ -165,6 +168,10 @@ $ %s tx ibc connection open-try connection-id] [client-id] consensusHeight, cliCtx.GetFromAddress(), ) + if err := msg.ValidateBasic(); err != nil { + return err + } + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } @@ -213,6 +220,10 @@ $ %s tx ibc connection open-ack [connection-id] [path/to/proof_try.json] [versio consensusHeight, version, cliCtx.GetFromAddress(), ) + if err := msg.ValidateBasic(); err != nil { + return err + } + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } @@ -257,6 +268,10 @@ $ %s tx ibc connection open-confirm [connection-id] [path/to/proof_ack.json] connectionID, proofAck, proofHeight, cliCtx.GetFromAddress(), ) + if err := msg.ValidateBasic(); err != nil { + return err + } + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } @@ -334,26 +349,18 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { return err } - // get passphrase for key from1 - passphrase1, err := keys.GetPassphrase(from1) - if err != nil { - return err - } - - // get passphrase for key from2 - passphrase2, err := keys.GetPassphrase(from2) - if err != nil { - return err - } - viper.Set(flags.FlagChainID, cid1) msgOpenInit := types.NewMsgConnectionOpenInit( connID1, clientID1, connID2, clientID2, path2, ctx1.GetFromAddress(), ) - res, err := utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgOpenInit}, passphrase1) - if err != nil || !res.IsOK() { + if err := msgOpenInit.ValidateBasic(); err != nil { + return err + } + + err = utils.CompleteAndBroadcastTxCLI(txBldr1, ctx1, []sdk.Msg{msgOpenInit}) + if err != nil { return err } @@ -363,7 +370,7 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // remove hardcoding this to 8 seconds. time.Sleep(8 * time.Second) - header, err := tendermint.GetHeader(ctx1) + header, err := clientutils.GetTendermintHeader(ctx1) if err != nil { return err } @@ -371,11 +378,16 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // Create and send msgUpdateClient viper.Set(flags.FlagChainID, cid2) msgUpdateClient := clienttypes.NewMsgUpdateClient(clientID2, header, ctx2.GetFromAddress()) - res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}, passphrase2) - if err != nil || !res.IsOK() { + + if err := msgUpdateClient.ValidateBasic(); err != nil { return err } - fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, clientID1) + + err = utils.CompleteAndBroadcastTxCLI(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}) + if err != nil { + return err + } + fmt.Printf(" [OK] client(%v)\n", clientID1) // Fetch proofs from cid1 viper.Set(flags.FlagChainID, cid1) @@ -393,12 +405,16 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { viper.Set(flags.FlagChainID, cid2) msgOpenTry := types.NewMsgConnectionOpenTry(connID2, clientID2, connID1, clientID1, path1, []string{version}, proofs.Proof, csProof.Proof, uint64(header.Height), uint64(header.Height), ctx2.GetFromAddress()) - res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgOpenTry}, passphrase2) - if err != nil || !res.IsOK() { + if err := msgOpenTry.ValidateBasic(); err != nil { return err } - fmt.Printf(" [OK] txid(%v) client(%v) connection(%v)\n", res.TxHash, clientID2, connID2) + err = utils.CompleteAndBroadcastTxCLI(txBldr2, ctx2, []sdk.Msg{msgOpenTry}) + if err != nil { + return err + } + + fmt.Printf(" [OK] client(%v) connection(%v)\n", clientID2, connID2) // Another block has to be passed after msgOpenInit is committed // to retrieve the correct proofs @@ -406,7 +422,7 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // remove hardcoding this to 8 seconds. time.Sleep(8 * time.Second) - header, err = tendermint.GetHeader(ctx2) + header, err = clientutils.GetTendermintHeader(ctx2) if err != nil { return err } @@ -414,11 +430,16 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // Update the client for cid2 on cid1 viper.Set(flags.FlagChainID, cid1) msgUpdateClient = clienttypes.NewMsgUpdateClient(clientID1, header, ctx1.GetFromAddress()) - res, err = utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgUpdateClient}, passphrase1) - if err != nil || !res.IsOK() { + + if err := msgUpdateClient.ValidateBasic(); err != nil { return err } - fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, clientID2) + + err = utils.CompleteAndBroadcastTxCLI(txBldr1, ctx1, []sdk.Msg{msgUpdateClient}) + if err != nil { + return err + } + fmt.Printf(" [OK] client(%v)\n", clientID2) // Fetch proofs from cid2 viper.Set(flags.FlagChainID, cid2) @@ -435,11 +456,16 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // Create and send msgOpenAck viper.Set(flags.FlagChainID, cid1) msgOpenAck := types.NewMsgConnectionOpenAck(connID1, proofs.Proof, csProof.Proof, uint64(header.Height), uint64(header.Height), version, ctx1.GetFromAddress()) - res, err = utils.CompleteAndBroadcastTx(txBldr1, ctx1, []sdk.Msg{msgOpenAck}, passphrase1) - if err != nil || !res.IsOK() { + + if err := msgOpenAck.ValidateBasic(); err != nil { + return err + } + + err = utils.CompleteAndBroadcastTxCLI(txBldr1, ctx1, []sdk.Msg{msgOpenAck}) + if err != nil { return err } - fmt.Printf(" [OK] txid(%v) connection(%v)\n", res.TxHash, connID1) + fmt.Printf(" [OK] connection(%v)\n", connID1) // Another block has to be passed after msgOpenInit is committed // to retrieve the correct proofs @@ -447,7 +473,7 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // remove hardcoding this to 8 seconds. time.Sleep(8 * time.Second) - header, err = tendermint.GetHeader(ctx1) + header, err = clientutils.GetTendermintHeader(ctx1) if err != nil { return err } @@ -455,11 +481,16 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // Update client for cid1 on cid2 viper.Set(flags.FlagChainID, cid2) msgUpdateClient = clienttypes.NewMsgUpdateClient(clientID2, header, ctx2.GetFromAddress()) - res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}, passphrase2) - if err != nil || !res.IsOK() { + + if err := msgUpdateClient.ValidateBasic(); err != nil { return err } - fmt.Printf(" [OK] txid(%v) client(%v)\n", res.TxHash, clientID1) + + err = utils.CompleteAndBroadcastTxCLI(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}) + if err != nil { + return err + } + fmt.Printf(" [OK] client(%v)\n", clientID1) // Fetch proof from cid1 viper.Set(flags.FlagChainID, cid1) @@ -471,11 +502,16 @@ func GetCmdHandshakeState(storeKey string, cdc *codec.Codec) *cobra.Command { // Create and send msgOpenConfirm viper.Set(flags.FlagChainID, cid2) msgOpenConfirm := types.NewMsgConnectionOpenConfirm(connID2, proofs.Proof, uint64(header.Height), ctx2.GetFromAddress()) - res, err = utils.CompleteAndBroadcastTx(txBldr2, ctx2, []sdk.Msg{msgOpenConfirm}, passphrase2) - if err != nil || !res.IsOK() { + + if err := msgOpenConfirm.ValidateBasic(); err != nil { + return err + } + + err = utils.CompleteAndBroadcastTxCLI(txBldr2, ctx2, []sdk.Msg{msgOpenConfirm}) + if err != nil { return err } - fmt.Printf(" [OK] txid(%v) connection(%v)\n", res.TxHash, connID2) + fmt.Printf(" [OK] connection(%v)\n", connID2) return nil }, From 024486c10fcf1c1c0c8af3ecf47122d2366b20c6 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 5 Nov 2019 14:13:19 +0100 Subject: [PATCH 375/378] upstream changes --- x/ibc/keeper/querier.go | 33 +++++++++++++++++++++++---------- x/ibc/module.go | 2 ++ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/x/ibc/keeper/querier.go b/x/ibc/keeper/querier.go index cb9b260d135a..43db6f574dc0 100644 --- a/x/ibc/keeper/querier.go +++ b/x/ibc/keeper/querier.go @@ -1,6 +1,8 @@ package keeper import ( + "fmt" + abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -12,16 +14,27 @@ import ( func NewQuerier(k Keeper) sdk.Querier { return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { switch path[0] { - case client.QueryClientState: - return client.QuerierClientState(ctx, req, k.ClientKeeper) - case client.QueryConsensusState: - return client.QuerierConsensusState(ctx, req, k.ClientKeeper) - case client.QueryVerifiedRoot: - return client.QuerierVerifiedRoot(ctx, req, k.ClientKeeper) - case connection.QueryConnection: - return connection.QuerierConnection(ctx, req, k.ConnectionKeeper) - case connection.QueryClientConnections: - return connection.QuerierClientConnections(ctx, req, k.ConnectionKeeper) + case client.SubModuleName: + switch path[1] { + case client.QueryClientState: + return client.QuerierClientState(ctx, req, k.ClientKeeper) + case client.QueryConsensusState: + return client.QuerierConsensusState(ctx, req, k.ClientKeeper) + case client.QueryVerifiedRoot: + return client.QuerierVerifiedRoot(ctx, req, k.ClientKeeper) + default: + return nil, sdk.ErrUnknownRequest(fmt.Sprintf("unknown IBC %s query endpoint", client.SubModuleName)) + } + + case connection.SubModuleName: + switch path[1] { + case connection.QueryConnection: + return connection.QuerierConnection(ctx, req, k.ConnectionKeeper) + case connection.QueryClientConnections: + return connection.QuerierClientConnections(ctx, req, k.ConnectionKeeper) + default: + return nil, sdk.ErrUnknownRequest(fmt.Sprintf("unknown IBC %s query endpoint", connection.SubModuleName)) + } default: return nil, sdk.ErrUnknownRequest("unknown IBC query endpoint") diff --git a/x/ibc/module.go b/x/ibc/module.go index 675b18aa1ddf..21ba001210de 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -13,6 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + 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/client/cli" "github.com/cosmos/cosmos-sdk/x/ibc/types" @@ -37,6 +38,7 @@ func (AppModuleBasic) Name() string { // RegisterCodec registers the staking module's types for the given codec. func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { client.RegisterCodec(cdc) + connection.RegisterCodec(cdc) commitment.RegisterCodec(cdc) } From ab506292b220a9ec7833303873bd8802d6e9df70 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 5 Nov 2019 14:16:15 +0100 Subject: [PATCH 376/378] upstream changes --- x/ibc/05-port/keeper/keeper.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/x/ibc/05-port/keeper/keeper.go b/x/ibc/05-port/keeper/keeper.go index c684700f7e71..5a7a9fb05bae 100644 --- a/x/ibc/05-port/keeper/keeper.go +++ b/x/ibc/05-port/keeper/keeper.go @@ -25,8 +25,9 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) storeKey: key, cdc: cdc, codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/port", - prefix: []byte(types.SubModuleName + "/"), // "port/" - ports: make(map[sdk.CapabilityKey]string), // map of capabilities to port ids + prefix: []byte{}, + // prefix: []byte(types.SubModuleName + "/"), // "port/" + ports: make(map[sdk.CapabilityKey]string), // map of capabilities to port ids } } @@ -47,7 +48,7 @@ func (k Keeper) GetPort(ck sdk.CapabilityKey) (string, bool) { // The capability must then be passed to a module which will need to pass // it as an extra parameter when calling functions on the IBC module. func (k Keeper) BindPort(portID string) sdk.CapabilityKey { - if err := host.DefaultIdentifierValidator(portID); err != nil { + if err := host.DefaultPortIdentifierValidator(portID); err != nil { panic(err.Error()) } @@ -68,7 +69,7 @@ func (k Keeper) BindPort(portID string) sdk.CapabilityKey { // generated and bound to the port (provided as a parameter) which the capability // is being authenticated against. func (k Keeper) Authenticate(key sdk.CapabilityKey, portID string) bool { - if err := host.DefaultIdentifierValidator(portID); err != nil { + if err := host.DefaultPortIdentifierValidator(portID); err != nil { panic(err.Error()) } From 6106861cd275c564ee0ddeee6e2960b37c06e70a Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 5 Nov 2019 14:26:52 +0100 Subject: [PATCH 377/378] upstream changes --- x/ibc/04-channel/alias.go | 1 - x/ibc/04-channel/client/cli/query.go | 35 +-- x/ibc/04-channel/client/cli/tx.go | 247 ++++++++++++++++++++- x/ibc/04-channel/client/utils/utils.go | 70 ++++++ x/ibc/04-channel/exported/exported.go | 14 +- x/ibc/04-channel/handler.go | 296 +++++++++++++------------ x/ibc/04-channel/keeper/handshake.go | 97 ++++++-- x/ibc/04-channel/keeper/keeper.go | 9 +- x/ibc/04-channel/keeper/packet.go | 107 ++++----- x/ibc/04-channel/keeper/querier.go | 2 +- x/ibc/04-channel/keeper/timeout.go | 66 +++--- x/ibc/04-channel/module.go | 25 +++ x/ibc/04-channel/types/channel.go | 16 +- x/ibc/04-channel/types/codec.go | 10 +- x/ibc/04-channel/types/errors.go | 6 +- x/ibc/04-channel/types/msgs.go | 24 +- x/ibc/04-channel/types/packet.go | 44 ++-- x/ibc/04-channel/types/querier.go | 21 ++ 18 files changed, 737 insertions(+), 353 deletions(-) create mode 100644 x/ibc/04-channel/client/utils/utils.go create mode 100644 x/ibc/04-channel/module.go diff --git a/x/ibc/04-channel/alias.go b/x/ibc/04-channel/alias.go index 01948305fd47..25f73b478565 100644 --- a/x/ibc/04-channel/alias.go +++ b/x/ibc/04-channel/alias.go @@ -57,7 +57,6 @@ var ( OrderFromString = types.OrderFromString StateFromString = types.StateFromString RegisterCodec = types.RegisterCodec - SetMsgChanCodec = types.SetMsgChanCodec ErrChannelExists = types.ErrChannelExists ErrChannelNotFound = types.ErrChannelNotFound ErrInvalidCounterpartyChannel = types.ErrInvalidCounterpartyChannel diff --git a/x/ibc/04-channel/client/cli/query.go b/x/ibc/04-channel/client/cli/query.go index 0078b9f00b4b..04bfcfcbbe92 100644 --- a/x/ibc/04-channel/client/cli/query.go +++ b/x/ibc/04-channel/client/cli/query.go @@ -5,16 +5,12 @@ import ( "strings" "github.com/spf13/cobra" - "github.com/spf13/viper" - - abci "github.com/tendermint/tendermint/abci/types" cli "github.com/cosmos/cosmos-sdk/client" "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/version" - "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/client/utils" ) // GetQueryCmd returns the query commands for IBC channels @@ -46,39 +42,14 @@ $ %s query ibc channel end [port-id] [channel-id] Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - portID := args[0] - channelID := args[1] - - bz, err := cdc.MarshalJSON(types.NewQueryChannelParams(portID, channelID)) - if err != nil { - return err - } - - req := abci.RequestQuery{ - Path: fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryChannel), - Data: bz, - Prove: viper.GetBool(flags.FlagProve), - } - res, err := cliCtx.QueryABCI(req) + ch, err := utils.QueryChannel(cliCtx, args[0], args[1], queryRoute) if err != nil { return err } - var channel types.Channel - if err := cdc.UnmarshalJSON(res.Value, &channel); err != nil { - return err - } - - if res.Proof == nil { - return cliCtx.PrintOutput(channel) - } - - channelRes := types.NewChannelResponse(portID, channelID, channel, res.Proof, res.Height) - return cliCtx.PrintOutput(channelRes) + return cliCtx.PrintOutput(ch) }, } - cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results") - return cmd } diff --git a/x/ibc/04-channel/client/cli/tx.go b/x/ibc/04-channel/client/cli/tx.go index 2bea84398bcc..833ed29af01c 100644 --- a/x/ibc/04-channel/client/cli/tx.go +++ b/x/ibc/04-channel/client/cli/tx.go @@ -6,31 +6,41 @@ import ( "os" "strconv" "strings" + "time" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + clientutils "github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/utils" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + abci "github.com/tendermint/tendermint/abci/types" ) -// IBC channel flags -var ( +const ( FlagOrdered = "ordered" FlagIBCVersion = "ibc-version" + FlagNode1 = "node1" + FlagNode2 = "node2" + FlagFrom1 = "from1" + FlagFrom2 = "from2" + FlagChainID2 = "chain-id2" ) // GetTxCmd returns the transaction commands for IBC Connections func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ics04ChannelTxCmd := &cobra.Command{ - Use: "connection", - Short: "IBC connection transaction subcommands", + Use: "channel", + Short: "IBC channel transaction subcommands", } ics04ChannelTxCmd.AddCommand(client.PostCommands( @@ -40,6 +50,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { GetMsgChannelOpenConfirmCmd(storeKey, cdc), GetMsgChannelCloseInitCmd(storeKey, cdc), GetMsgChannelCloseConfirmCmd(storeKey, cdc), + GetCmdHandshake(storeKey, cdc), )...) return ics04ChannelTxCmd @@ -288,6 +299,234 @@ func GetMsgChannelCloseConfirmCmd(storeKey string, cdc *codec.Codec) *cobra.Comm } } +func GetCmdHandshake(storeKey string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "handshake", + Short: "initiate connection handshake between two chains", + Long: strings.TrimSpace( + fmt.Sprintf(`initialize a connection on chain A with a given counterparty chain B: + +Example: +$ %s tx ibc channel handshake [client-id] [port-id] [chan-id] [conn-id] [cp-client-id] [cp-port-id] [cp-chain-id] [cp-conn-id] + `, version.ClientName)), + Args: cobra.ExactArgs(8), + // Args: []string{portid1, chanid1, connid1, portid2, chanid2, connid2} + RunE: func(cmd *cobra.Command, args []string) error { + // --chain-id values for each chain + cid1 := viper.GetString(flags.FlagChainID) + cid2 := viper.GetString(FlagChainID2) + + // --from values for each wallet + from1 := viper.GetString(FlagFrom1) + from2 := viper.GetString(FlagFrom2) + + // --node values for each RPC + node1 := viper.GetString(FlagNode1) + node2 := viper.GetString(FlagNode2) + + // client IDs + clientid1 := args[0] + clientid2 := args[4] + + // port IDs + portid1 := args[1] + portid2 := args[5] + + // channel IDs + chanid1 := args[2] + chanid2 := args[6] + + // connection IDs + connid1 := args[3] + connid2 := args[7] + + // Create txbldr, clictx, querier for cid1 + viper.Set(flags.FlagChainID, cid1) + txBldr1 := auth.NewTxBuilderFromCLI(). + WithTxEncoder(utils.GetTxEncoder(cdc)) + ctx1 := context.NewCLIContextIBC(from1, cid1, node1). + WithCodec(cdc). + WithBroadcastMode(flags.BroadcastBlock) + + // Create txbldr, clictx, querier for cid2 + viper.Set(flags.FlagChainID, cid2) + txBldr2 := auth.NewTxBuilderFromCLI(). + WithTxEncoder(utils.GetTxEncoder(cdc)) + ctx2 := context.NewCLIContextIBC(from2, cid2, node2). + WithCodec(cdc). + WithBroadcastMode(flags.BroadcastBlock) + + // // get passphrase for key from1 + // passphrase1, err := keys.GetPassphrase(from1) + // if err != nil { + // return err + // } + + // // get passphrase for key from2 + // passphrase2, err := keys.GetPassphrase(from2) + // if err != nil { + // return err + // } + + // TODO: check state and if not Idle continue existing process + viper.Set(flags.FlagChainID, cid1) + msgOpenInit := types.NewMsgChannelOpenInit(portid1, chanid1, "v1.0.0", channelOrder(), []string{connid1}, portid2, chanid2, ctx1.GetFromAddress()) + if err := msgOpenInit.ValidateBasic(); err != nil { + return err + } + + err := utils.CompleteAndBroadcastTxCLI(txBldr1, ctx1, []sdk.Msg{msgOpenInit}) + if err != nil { + return err + } + + // Another block has to be passed after msginit is committed + // to retrieve the correct proofs + time.Sleep(8 * time.Second) + + header, err := clientutils.GetTendermintHeader(ctx1) + if err != nil { + return err + } + + viper.Set(flags.FlagChainID, cid2) + msgUpdateClient := clienttypes.NewMsgUpdateClient(clientid2, header, ctx2.GetFromAddress()) + if err := msgUpdateClient.ValidateBasic(); err != nil { + return err + } + + err = utils.CompleteAndBroadcastTxCLI(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}) + if err != nil { + return err + } + + viper.Set(flags.FlagChainID, cid1) + proofs, err := queryProofs(ctx1.WithHeight(header.Height-1), portid1, chanid1, storeKey) + if err != nil { + return err + } + + msgOpenTry := types.NewMsgChannelOpenTry(portid2, chanid2, "v1.0.0", channelOrder(), []string{connid2}, portid1, chanid1, "v1.0.0", proofs.Proof, uint64(header.Height), ctx2.GetFromAddress()) + if err := msgUpdateClient.ValidateBasic(); err != nil { + return err + } + + err = utils.CompleteAndBroadcastTxCLI(txBldr2, ctx2, []sdk.Msg{msgOpenTry}) + if err != nil { + return err + } + + // Another block has to be passed after msginit is committed + // to retrieve the correct proofs + time.Sleep(8 * time.Second) + + header, err = clientutils.GetTendermintHeader(ctx2) + if err != nil { + return err + } + + viper.Set(flags.FlagChainID, cid1) + msgUpdateClient = clienttypes.NewMsgUpdateClient(clientid1, header, ctx1.GetFromAddress()) + if err := msgUpdateClient.ValidateBasic(); err != nil { + return err + } + + err = utils.CompleteAndBroadcastTxCLI(txBldr1, ctx1, []sdk.Msg{msgUpdateClient}) + if err != nil { + return err + } + + viper.Set(flags.FlagChainID, cid2) + proofs, err = queryProofs(ctx2.WithHeight(header.Height-1), portid2, chanid2, storeKey) + if err != nil { + return err + } + + viper.Set(flags.FlagChainID, cid1) + msgOpenAck := types.NewMsgChannelOpenAck(portid1, chanid1, "v1.0.0", proofs.Proof, uint64(header.Height), ctx1.GetFromAddress()) + if err := msgOpenAck.ValidateBasic(); err != nil { + return err + } + + err = utils.CompleteAndBroadcastTxCLI(txBldr1, ctx1, []sdk.Msg{msgOpenAck}) + if err != nil { + return err + } + + // Another block has to be passed after msginit is committed + // to retrieve the correct proofs + time.Sleep(8 * time.Second) + + header, err = clientutils.GetTendermintHeader(ctx1) + if err != nil { + return err + } + + viper.Set(flags.FlagChainID, cid2) + msgUpdateClient = clienttypes.NewMsgUpdateClient(clientid2, header, ctx2.GetFromAddress()) + if err := msgUpdateClient.ValidateBasic(); err != nil { + return err + } + + err = utils.CompleteAndBroadcastTxCLI(txBldr2, ctx2, []sdk.Msg{msgUpdateClient}) + if err != nil { + return err + } + + viper.Set(flags.FlagChainID, cid1) + proofs, err = queryProofs(ctx1.WithHeight(header.Height-1), portid1, chanid1, storeKey) + if err != nil { + return err + } + + msgOpenConfirm := types.NewMsgChannelOpenConfirm(portid2, chanid2, proofs.Proof, uint64(header.Height), ctx2.GetFromAddress()) + if err := msgOpenConfirm.ValidateBasic(); err != nil { + return err + } + + err = utils.CompleteAndBroadcastTxCLI(txBldr2, ctx2, []sdk.Msg{msgOpenConfirm}) + if err != nil { + return err + } + + return nil + }, + } + + cmd.Flags().String(FlagNode1, "tcp://localhost:26657", "RPC port for the first chain") + cmd.Flags().String(FlagNode2, "tcp://localhost:26657", "RPC port for the second chain") + cmd.Flags().String(FlagFrom1, "", "key in local keystore for first chain") + cmd.Flags().String(FlagFrom2, "", "key in local keystore for second chain") + cmd.Flags().String(FlagChainID2, "", "chain-id for the second chain") + cmd.Flags().Bool(FlagOrdered, true, "Pass flag for opening ordered channels") + + cmd.MarkFlagRequired(FlagFrom1) + cmd.MarkFlagRequired(FlagFrom2) + + return cmd +} + +func queryProofs(ctx client.CLIContext, portID string, channelID string, queryRoute string) (types.ChannelResponse, error) { + var connRes types.ChannelResponse + + req := abci.RequestQuery{ + Path: "store/ibc/key", + Data: types.KeyChannel(portID, channelID), + Prove: true, + } + + res, err := ctx.QueryABCI(req) + if res.Value == nil || err != nil { + return connRes, err + } + + var channel types.Channel + if err := ctx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &channel); err != nil { + return connRes, err + } + return types.NewChannelResponse(portID, channelID, channel, res.Proof, res.Height), nil +} + func channelOrder() types.Order { if viper.GetBool(FlagOrdered) { return types.ORDERED diff --git a/x/ibc/04-channel/client/utils/utils.go b/x/ibc/04-channel/client/utils/utils.go new file mode 100644 index 000000000000..580a2bf1fb83 --- /dev/null +++ b/x/ibc/04-channel/client/utils/utils.go @@ -0,0 +1,70 @@ +package utils + +import ( + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" +) + +// QueryPacket returns a packet from the store +func QueryPacket( + ctx client.CLIContext, portID, channelID string, + sequence, timeout uint64, queryRoute string, +) (types.PacketResponse, error) { + var packetRes types.PacketResponse + + req := abci.RequestQuery{ + Path: "store/ibc/key", + Data: types.KeyPacketCommitment(portID, channelID, sequence), + Prove: true, + } + + res, err := ctx.QueryABCI(req) + if err != nil { + return packetRes, err + } + + channel, err := QueryChannel(ctx, portID, channelID, queryRoute) + if err != nil { + return packetRes, err + } + + destPortID := channel.Channel.Counterparty.PortID + destChannelID := channel.Channel.Counterparty.ChannelID + + packet := types.NewPacket( + sequence, + timeout, + portID, + channelID, + destPortID, + destChannelID, + res.Value, + ) + + // FIXME: res.Height+1 is hack, fix later + return types.NewPacketResponse(portID, channelID, sequence, packet, res.Proof, res.Height+1), nil +} + +// QueryChannel returns a channel from the store +func QueryChannel(ctx client.CLIContext, portID string, channelID string, queryRoute string) (types.ChannelResponse, error) { + var connRes types.ChannelResponse + + req := abci.RequestQuery{ + Path: "store/ibc/key", + Data: types.KeyChannel(portID, channelID), + Prove: true, + } + + res, err := ctx.QueryABCI(req) + if res.Value == nil || err != nil { + return connRes, err + } + + var channel types.Channel + if err := ctx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &channel); err != nil { + return connRes, err + } + return types.NewChannelResponse(portID, channelID, channel, res.Proof, res.Height), nil +} diff --git a/x/ibc/04-channel/exported/exported.go b/x/ibc/04-channel/exported/exported.go index 9559db87ca25..8fb84f7c1c01 100644 --- a/x/ibc/04-channel/exported/exported.go +++ b/x/ibc/04-channel/exported/exported.go @@ -5,12 +5,12 @@ import ( ) type PacketI interface { - Sequence() uint64 - TimeoutHeight() uint64 - SourcePort() string - SourceChannel() string - DestPort() string - DestChannel() string - Data() []byte + GetSequence() uint64 + GetTimeoutHeight() uint64 + GetSourcePort() string + GetSourceChannel() string + GetDestPort() string + GetDestChannel() string + GetData() []byte ValidateBasic() sdk.Error } diff --git a/x/ibc/04-channel/handler.go b/x/ibc/04-channel/handler.go index 105f7ae1a9eb..31c97b668e1a 100644 --- a/x/ibc/04-channel/handler.go +++ b/x/ibc/04-channel/handler.go @@ -1,147 +1,153 @@ package channel -// // HandleMsgChannelOpenInit defines the sdk.Handler for MsgChannelOpenInit -// func HandleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenInit) sdk.Result { -// err := k.ChanOpenInit( -// ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, -// msg.Channel.Counterparty, msg.Channel.Version, -// ) -// if err != nil { -// return sdk.ResultFromError(err) -// } - -// ctx.EventManager().EmitEvents(sdk.Events{ -// sdk.NewEvent( -// types.EventTypeChannelOpenInit, -// sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), -// sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), -// ), -// sdk.NewEvent( -// sdk.EventTypeMessage, -// sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), -// sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), -// ), -// }) - -// return sdk.Result{Events: ctx.EventManager().Events()} -// } - -// // HandleMsgChannelOpenTry defines the sdk.Handler for MsgChannelOpenTry -// func HandleMsgChannelOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenTry) sdk.Result { -// err := k.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, -// msg.Channel.Counterparty, msg.Channel.Version, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, -// ) -// if err != nil { -// return sdk.ResultFromError(err) -// } - -// ctx.EventManager().EmitEvents(sdk.Events{ -// sdk.NewEvent( -// types.EventTypeChannelOpenTry, -// sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), -// sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), // TODO: double check sender and receiver -// sdk.NewAttribute(types.AttributeKeyReceiverPort, msg.Channel.Counterparty.PortID), -// ), -// sdk.NewEvent( -// sdk.EventTypeMessage, -// sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), -// sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), -// ), -// }) - -// return sdk.Result{Events: ctx.EventManager().Events()} -// } - -// // HandleMsgChannelOpenAck defines the sdk.Handler for MsgChannelOpenAck -// func HandleMsgChannelOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenAck) sdk.Result { -// err := k.ChanOpenAck( -// ctx, msg.PortID, msg.ChannelID, msg.CounterpartyVersion, msg.ProofTry, msg.ProofHeight, -// ) -// if err != nil { -// return sdk.ResultFromError(err) -// } - -// ctx.EventManager().EmitEvents(sdk.Events{ -// sdk.NewEvent( -// types.EventTypeChannelOpenAck, -// sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), -// sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), -// ), -// sdk.NewEvent( -// sdk.EventTypeMessage, -// sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), -// sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), -// ), -// }) - -// return sdk.Result{Events: ctx.EventManager().Events()} -// } - -// // HandleMsgChannelOpenConfirm defines the sdk.Handler for MsgChannelOpenConfirm -// func HandleMsgChannelOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenConfirm) sdk.Result { -// err := k.ChanOpenConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofAck, msg.ProofHeight) -// if err != nil { -// return sdk.ResultFromError(err) -// } - -// ctx.EventManager().EmitEvents(sdk.Events{ -// sdk.NewEvent( -// types.EventTypeChannelOpenConfirm, -// sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), -// sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), -// ), -// sdk.NewEvent( -// sdk.EventTypeMessage, -// sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), -// sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), -// ), -// }) - -// return sdk.Result{Events: ctx.EventManager().Events()} -// } - -// // HandleMsgChannelCloseInit defines the sdk.Handler for MsgChannelCloseInit -// func HandleMsgChannelCloseInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseInit) sdk.Result { -// err := k.ChanCloseInit(ctx, msg.PortID, msg.ChannelID) -// if err != nil { -// return sdk.ResultFromError(err) -// } - -// ctx.EventManager().EmitEvents(sdk.Events{ -// sdk.NewEvent( -// types.EventTypeChannelCloseInit, -// sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), -// sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), -// ), -// sdk.NewEvent( -// sdk.EventTypeMessage, -// sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), -// sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), -// ), -// }) - -// return sdk.Result{Events: ctx.EventManager().Events()} -// } - -// // HandleMsgChannelCloseConfirm defines the sdk.Handler for MsgChannelCloseConfirm -// func HandleMsgChannelCloseConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseConfirm) sdk.Result { -// err := k.ChanCloseConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofInit, msg.ProofHeight) -// if err != nil { -// return sdk.ResultFromError(err) -// } - -// ctx.EventManager().EmitEvents(sdk.Events{ -// sdk.NewEvent( -// types.EventTypeChannelCloseConfirm, -// sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), -// sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), -// ), -// sdk.NewEvent( -// sdk.EventTypeMessage, -// sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), -// sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), -// ), -// }) - -// return sdk.Result{Events: ctx.EventManager().Events()} -// } +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" +) + +// HandleMsgChannelOpenInit defines the sdk.Handler for MsgChannelOpenInit +func HandleMsgChannelOpenInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenInit) sdk.Result { + err := k.ChanOpenInit( + ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, + msg.Channel.Counterparty, msg.Channel.Version, + ) + if err != nil { + return sdk.ResultFromError(err) + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelOpenInit, + sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} +} + +// HandleMsgChannelOpenTry defines the sdk.Handler for MsgChannelOpenTry +func HandleMsgChannelOpenTry(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenTry) sdk.Result { + err := k.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortID, msg.ChannelID, + msg.Channel.Counterparty, msg.Channel.Version, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, + ) + if err != nil { + return sdk.ResultFromError(err) + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelOpenTry, + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), // TODO: double check sender and receiver + sdk.NewAttribute(types.AttributeKeyReceiverPort, msg.Channel.Counterparty.PortID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} +} + +// HandleMsgChannelOpenAck defines the sdk.Handler for MsgChannelOpenAck +func HandleMsgChannelOpenAck(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenAck) sdk.Result { + err := k.ChanOpenAck( + ctx, msg.PortID, msg.ChannelID, msg.CounterpartyVersion, msg.ProofTry, msg.ProofHeight, + ) + if err != nil { + return sdk.ResultFromError(err) + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelOpenAck, + sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} +} + +// HandleMsgChannelOpenConfirm defines the sdk.Handler for MsgChannelOpenConfirm +func HandleMsgChannelOpenConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelOpenConfirm) sdk.Result { + err := k.ChanOpenConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofAck, msg.ProofHeight) + if err != nil { + return sdk.ResultFromError(err) + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelOpenConfirm, + sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} +} + +// HandleMsgChannelCloseInit defines the sdk.Handler for MsgChannelCloseInit +func HandleMsgChannelCloseInit(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseInit) sdk.Result { + err := k.ChanCloseInit(ctx, msg.PortID, msg.ChannelID) + if err != nil { + return sdk.ResultFromError(err) + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelCloseInit, + sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} +} + +// HandleMsgChannelCloseConfirm defines the sdk.Handler for MsgChannelCloseConfirm +func HandleMsgChannelCloseConfirm(ctx sdk.Context, k keeper.Keeper, msg types.MsgChannelCloseConfirm) sdk.Result { + err := k.ChanCloseConfirm(ctx, msg.PortID, msg.ChannelID, msg.ProofInit, msg.ProofHeight) + if err != nil { + return sdk.ResultFromError(err) + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelCloseConfirm, + sdk.NewAttribute(types.AttributeKeySenderPort, msg.PortID), + sdk.NewAttribute(types.AttributeKeyChannelID, msg.ChannelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + ), + }) + + return sdk.Result{Events: ctx.EventManager().Events()} +} diff --git a/x/ibc/04-channel/keeper/handshake.go b/x/ibc/04-channel/keeper/handshake.go index d3ba56cfa081..f71115da4792 100644 --- a/x/ibc/04-channel/keeper/handshake.go +++ b/x/ibc/04-channel/keeper/handshake.go @@ -10,6 +10,20 @@ import ( commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) +// CounterpartyHops returns the connection hops of the counterparty channel. +// The counterparty hops are stored in the inverse order as the channel's. +func (k Keeper) CounterpartyHops(ctx sdk.Context, ch types.Channel) ([]string, bool) { + counterPartyHops := make([]string, len(ch.ConnectionHops)) + for i, hop := range ch.ConnectionHops { + connection, found := k.connectionKeeper.GetConnection(ctx, hop) + if !found { + return []string{}, false + } + counterPartyHops[len(counterPartyHops)-1-i] = connection.Counterparty.ConnectionID + } + return counterPartyHops, true +} + // ChanOpenInit is called by a module to initiate a channel opening handshake with // a module on another chain. func (k Keeper) ChanOpenInit( @@ -20,7 +34,6 @@ func (k Keeper) ChanOpenInit( channelID string, counterparty types.Counterparty, version string, - portCapability sdk.CapabilityKey, ) error { // TODO: abortTransactionUnless(validateChannelIdentifier(portIdentifier, channelIdentifier)) _, found := k.GetChannel(ctx, portID, channelID) @@ -40,10 +53,15 @@ func (k Keeper) ChanOpenInit( ) } - if !k.portKeeper.Authenticate(portCapability, portID) { - return errors.New("port is not valid") - } + /* + // TODO: Maybe not right + key := sdk.NewKVStoreKey(portID) + + if !k.portKeeper.Authenticate(key, portID) { + return errors.New("port is not valid") + } + */ channel := types.NewChannel(types.INIT, order, counterparty, connectionHops, version) k.SetChannel(ctx, portID, channelID, channel) @@ -67,14 +85,16 @@ func (k Keeper) ChanOpenTry( counterpartyVersion string, proofInit commitment.ProofI, proofHeight uint64, - portCapability sdk.CapabilityKey, ) error { _, found := k.GetChannel(ctx, portID, channelID) if found { return types.ErrChannelExists(k.codespace, channelID) } - if !k.portKeeper.Authenticate(portCapability, portID) { + // TODO: Maybe not right + key := sdk.NewKVStoreKey(portID) + + if !k.portKeeper.Authenticate(key, portID) { return errors.New("port is not valid") } @@ -94,12 +114,18 @@ func (k Keeper) ChanOpenTry( // hops channel := types.NewChannel(types.OPENTRY, order, counterparty, connectionHops, version) + counterpartyHops, found := k.CounterpartyHops(ctx, channel) + if !found { + // Should not reach here, connectionEnd was able to be retrieved above + panic("cannot find connection") + } + // expectedCounterpaty is the counterparty of the counterparty's channel end // (i.e self) expectedCounterparty := types.NewCounterparty(portID, channelID) expectedChannel := types.NewChannel( types.INIT, channel.Ordering, expectedCounterparty, - channel.CounterpartyHops(), channel.Version, + counterpartyHops, channel.Version, ) bz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedChannel) @@ -133,12 +159,10 @@ func (k Keeper) ChanOpenAck( counterpartyVersion string, proofTry commitment.ProofI, proofHeight uint64, - portCapability sdk.CapabilityKey, ) error { - channel, found := k.GetChannel(ctx, portID, channelID) if !found { - return types.ErrChannelNotFound(k.codespace, channelID) + return types.ErrChannelNotFound(k.codespace, portID, channelID) } if channel.State != types.INIT { @@ -148,7 +172,10 @@ func (k Keeper) ChanOpenAck( ) } - if !k.portKeeper.Authenticate(portCapability, portID) { + // TODO: Maybe not right + key := sdk.NewKVStoreKey(portID) + + if !k.portKeeper.Authenticate(key, portID) { return errors.New("port is not valid") } @@ -164,11 +191,17 @@ func (k Keeper) ChanOpenAck( ) } + counterpartyHops, found := k.CounterpartyHops(ctx, channel) + if !found { + // Should not reach here, connectionEnd was able to be retrieved above + panic("cannot find connection") + } + // counterparty of the counterparty channel end (i.e self) counterparty := types.NewCounterparty(portID, channelID) expectedChannel := types.NewChannel( types.OPENTRY, channel.Ordering, counterparty, - channel.CounterpartyHops(), channel.Version, + counterpartyHops, channel.Version, ) bz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedChannel) @@ -199,11 +232,10 @@ func (k Keeper) ChanOpenConfirm( channelID string, proofAck commitment.ProofI, proofHeight uint64, - portCapability sdk.CapabilityKey, ) error { channel, found := k.GetChannel(ctx, portID, channelID) if !found { - return types.ErrChannelNotFound(k.codespace, channelID) + return types.ErrChannelNotFound(k.codespace, portID, channelID) } if channel.State != types.OPENTRY { @@ -213,7 +245,10 @@ func (k Keeper) ChanOpenConfirm( ) } - if !k.portKeeper.Authenticate(portCapability, portID) { + // TODO: Maybe not right + key := sdk.NewKVStoreKey(portID) + + if !k.portKeeper.Authenticate(key, portID) { return errors.New("port is not valid") } @@ -229,10 +264,16 @@ func (k Keeper) ChanOpenConfirm( ) } + counterpartyHops, found := k.CounterpartyHops(ctx, channel) + if !found { + // Should not reach here, connectionEnd was able to be retrieved above + panic("cannot find connection") + } + counterparty := types.NewCounterparty(portID, channelID) expectedChannel := types.NewChannel( types.OPEN, channel.Ordering, counterparty, - channel.CounterpartyHops(), channel.Version, + counterpartyHops, channel.Version, ) bz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedChannel) @@ -265,15 +306,17 @@ func (k Keeper) ChanCloseInit( ctx sdk.Context, portID, channelID string, - portCapability sdk.CapabilityKey, ) error { - if !k.portKeeper.Authenticate(portCapability, portID) { + // TODO: Maybe not right + key := sdk.NewKVStoreKey(portID) + + if !k.portKeeper.Authenticate(key, portID) { return errors.New("port is not valid") } channel, found := k.GetChannel(ctx, portID, channelID) if !found { - return types.ErrChannelNotFound(k.codespace, channelID) + return types.ErrChannelNotFound(k.codespace, portID, channelID) } if channel.State == types.CLOSED { @@ -306,15 +349,17 @@ func (k Keeper) ChanCloseConfirm( channelID string, proofInit commitment.ProofI, proofHeight uint64, - portCapability sdk.CapabilityKey, ) error { - if !k.portKeeper.Authenticate(portCapability, portID) { + // TODO: Maybe not right + key := sdk.NewKVStoreKey(portID) + + if !k.portKeeper.Authenticate(key, portID) { return errors.New("port is not valid") } channel, found := k.GetChannel(ctx, portID, channelID) if !found { - return types.ErrChannelNotFound(k.codespace, channelID) + return types.ErrChannelNotFound(k.codespace, portID, channelID) } if channel.State == types.CLOSED { @@ -333,10 +378,16 @@ func (k Keeper) ChanCloseConfirm( ) } + counterpartyHops, found := k.CounterpartyHops(ctx, channel) + if !found { + // Should not reach here, connectionEnd was able to be retrieved above + panic("cannot find connection") + } + counterparty := types.NewCounterparty(portID, channelID) expectedChannel := types.NewChannel( types.CLOSED, channel.Ordering, counterparty, - channel.CounterpartyHops(), channel.Version, + counterpartyHops, channel.Version, ) bz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedChannel) diff --git a/x/ibc/04-channel/keeper/keeper.go b/x/ibc/04-channel/keeper/keeper.go index d28a11356485..6169c72ffc3a 100644 --- a/x/ibc/04-channel/keeper/keeper.go +++ b/x/ibc/04-channel/keeper/keeper.go @@ -32,10 +32,11 @@ func NewKeeper( portKeeper types.PortKeeper, ) Keeper { return Keeper{ - storeKey: key, - cdc: cdc, - codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/channel", - prefix: []byte(types.SubModuleName + "/"), // "channel/" + storeKey: key, + cdc: cdc, + codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/channel", + prefix: []byte{}, + // prefix: []byte(types.SubModuleName + "/"), // "channel/" clientKeeper: clientKeeper, connectionKeeper: connectionKeeper, portKeeper: portKeeper, diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go index f43bffc22704..0590f3cfd37c 100644 --- a/x/ibc/04-channel/keeper/packet.go +++ b/x/ibc/04-channel/keeper/packet.go @@ -32,9 +32,9 @@ func (k Keeper) CleanupPacket( acknowledgement []byte, portCapability sdk.CapabilityKey, ) (exported.PacketI, error) { - channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) + channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { - return nil, types.ErrChannelNotFound(k.codespace, packet.SourceChannel()) + return nil, types.ErrChannelNotFound(k.codespace, packet.GetSourcePort(), packet.GetSourceChannel()) } if channel.State != types.OPEN { @@ -44,19 +44,19 @@ func (k Keeper) CleanupPacket( ) } - _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) + _, found = k.GetChannelCapability(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { return nil, types.ErrChannelCapabilityNotFound(k.codespace) } - if !k.portKeeper.Authenticate(portCapability, packet.SourcePort()) { + if !k.portKeeper.Authenticate(portCapability, packet.GetSourcePort()) { return nil, errors.New("port is not valid") } - if packet.DestChannel() != channel.Counterparty.ChannelID { + if packet.GetDestChannel() != channel.Counterparty.ChannelID { return nil, types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.DestChannel(), channel.Counterparty.ChannelID), + fmt.Sprintf("packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.GetDestChannel(), channel.Counterparty.ChannelID), ) } @@ -65,19 +65,19 @@ func (k Keeper) CleanupPacket( return nil, connection.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } - if packet.DestPort() != channel.Counterparty.PortID { + if packet.GetDestPort() != channel.Counterparty.PortID { return nil, types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.DestPort(), channel.Counterparty.PortID), + fmt.Sprintf("packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.GetDestPort(), channel.Counterparty.PortID), ) } - if nextSequenceRecv >= packet.Sequence() { + if nextSequenceRecv >= packet.GetSequence() { return nil, types.ErrInvalidPacket(k.codespace, "packet already received") } - commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) - if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data + commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + if !bytes.Equal(commitment, packet.GetData()) { // TODO: hash packet data return nil, types.ErrInvalidPacket(k.codespace, "packet hasn't been sent") } @@ -86,13 +86,13 @@ func (k Keeper) CleanupPacket( case types.ORDERED: ok = k.connectionKeeper.VerifyMembership( ctx, connectionEnd, proofHeight, proof, - types.NextSequenceRecvPath(packet.DestPort(), packet.DestChannel()), + types.NextSequenceRecvPath(packet.GetDestPort(), packet.GetDestChannel()), sdk.Uint64ToBigEndian(nextSequenceRecv), ) case types.UNORDERED: ok = k.connectionKeeper.VerifyMembership( ctx, connectionEnd, proofHeight, proof, - types.PacketAcknowledgementPath(packet.DestPort(), packet.DestChannel(), packet.Sequence()), + types.PacketAcknowledgementPath(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()), acknowledgement, ) default: @@ -103,7 +103,7 @@ func (k Keeper) CleanupPacket( return nil, types.ErrInvalidPacket(k.codespace, "packet verification failed") } - k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) return packet, nil } @@ -119,9 +119,9 @@ func (k Keeper) SendPacket( return err } - channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) + channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { - return types.ErrChannelNotFound(k.codespace, packet.SourceChannel()) + return types.ErrChannelNotFound(k.codespace, packet.GetSourcePort(), packet.GetSourceChannel()) } if channel.State == types.CLOSED { @@ -131,21 +131,21 @@ func (k Keeper) SendPacket( ) } - if !k.portKeeper.Authenticate(portCapability, packet.SourcePort()) { + if !k.portKeeper.Authenticate(portCapability, packet.GetSourcePort()) { return errors.New("port is not valid") } - if packet.DestPort() != channel.Counterparty.PortID { + if packet.GetDestPort() != channel.Counterparty.PortID { return types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.DestPort(), channel.Counterparty.PortID), + fmt.Sprintf("packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.GetDestPort(), channel.Counterparty.PortID), ) } - if packet.DestChannel() != channel.Counterparty.ChannelID { + if packet.GetDestChannel() != channel.Counterparty.ChannelID { return types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.DestChannel(), channel.Counterparty.ChannelID), + fmt.Sprintf("packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.GetDestChannel(), channel.Counterparty.ChannelID), ) } @@ -166,25 +166,25 @@ func (k Keeper) SendPacket( return client.ErrConsensusStateNotFound(k.codespace) } - if consensusState.GetHeight() >= packet.TimeoutHeight() { + if consensusState.GetHeight() >= packet.GetTimeoutHeight() { return types.ErrPacketTimeout(k.codespace) } - nextSequenceSend, found := k.GetNextSequenceSend(ctx, packet.SourcePort(), packet.SourceChannel()) + nextSequenceSend, found := k.GetNextSequenceSend(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { return types.ErrSequenceNotFound(k.codespace, "send") } - if packet.Sequence() != nextSequenceSend { + if packet.GetSequence() != nextSequenceSend { return types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet sequence ≠ next send sequence (%d ≠ %d)", packet.Sequence(), nextSequenceSend), + fmt.Sprintf("packet sequence ≠ next send sequence (%d ≠ %d)", packet.GetSequence(), nextSequenceSend), ) } nextSequenceSend++ - k.SetNextSequenceSend(ctx, packet.SourcePort(), packet.SourceChannel(), nextSequenceSend) - k.SetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence(), packet.Data()) // TODO: hash packet data + k.SetNextSequenceSend(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), nextSequenceSend) + k.SetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), packet.GetData()) // TODO: hash packet data return nil } @@ -200,9 +200,9 @@ func (k Keeper) RecvPacket( portCapability sdk.CapabilityKey, ) (exported.PacketI, error) { - channel, found := k.GetChannel(ctx, packet.DestPort(), packet.DestChannel()) + channel, found := k.GetChannel(ctx, packet.GetDestPort(), packet.GetDestChannel()) if !found { - return nil, types.ErrChannelNotFound(k.codespace, packet.DestChannel()) + return nil, types.ErrChannelNotFound(k.codespace, packet.GetDestPort(), packet.GetDestChannel()) } if channel.State != types.OPEN { @@ -212,22 +212,22 @@ func (k Keeper) RecvPacket( ) } - if !k.portKeeper.Authenticate(portCapability, packet.DestPort()) { + if !k.portKeeper.Authenticate(portCapability, packet.GetDestPort()) { return nil, errors.New("port is not valid") } // packet must come from the channel's counterparty - if packet.SourcePort() != channel.Counterparty.PortID { + if packet.GetSourcePort() != channel.Counterparty.PortID { return nil, types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet source port doesn't match the counterparty's port (%s ≠ %s)", packet.SourcePort(), channel.Counterparty.PortID), + fmt.Sprintf("packet source port doesn't match the counterparty's port (%s ≠ %s)", packet.GetSourcePort(), channel.Counterparty.PortID), ) } - if packet.SourceChannel() != channel.Counterparty.ChannelID { + if packet.GetSourceChannel() != channel.Counterparty.ChannelID { return nil, types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet source channel doesn't match the counterparty's channel (%s ≠ %s)", packet.SourceChannel(), channel.Counterparty.ChannelID), + fmt.Sprintf("packet source channel doesn't match the counterparty's channel (%s ≠ %s)", packet.GetSourceChannel(), channel.Counterparty.ChannelID), ) } @@ -243,40 +243,41 @@ func (k Keeper) RecvPacket( ) } - if uint64(ctx.BlockHeight()) >= packet.TimeoutHeight() { + if uint64(ctx.BlockHeight()) >= packet.GetTimeoutHeight() { return nil, types.ErrPacketTimeout(k.codespace) } if !k.connectionKeeper.VerifyMembership( ctx, connectionEnd, proofHeight, proof, - types.PacketCommitmentPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), - packet.Data(), // TODO: hash data + types.PacketCommitmentPath(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()), + packet.GetData(), // TODO: hash data ) { return nil, errors.New("couldn't verify counterparty packet commitment") } if len(acknowledgement) > 0 || channel.Ordering == types.UNORDERED { k.SetPacketAcknowledgement( - ctx, packet.DestPort(), packet.DestChannel(), packet.Sequence(), + ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), acknowledgement, // TODO: hash ACK ) } if channel.Ordering == types.ORDERED { - nextSequenceRecv, found := k.GetNextSequenceRecv(ctx, packet.DestPort(), packet.DestChannel()) + nextSequenceRecv, found := k.GetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel()) if !found { return nil, types.ErrSequenceNotFound(k.codespace, "receive") } - if packet.Sequence() != nextSequenceRecv { + if packet.GetSequence() != nextSequenceRecv { return nil, types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet sequence ≠ next receive sequence (%d ≠ %d)", packet.Sequence(), nextSequenceRecv), + fmt.Sprintf("packet sequence ≠ next receive sequence (%d ≠ %d)", packet.GetSequence(), nextSequenceRecv), ) } nextSequenceRecv++ - k.SetNextSequenceRecv(ctx, packet.DestPort(), packet.DestChannel(), nextSequenceRecv) + + k.SetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel(), nextSequenceRecv) } return packet, nil @@ -295,9 +296,9 @@ func (k Keeper) AcknowledgePacket( proofHeight uint64, portCapability sdk.CapabilityKey, ) (exported.PacketI, error) { - channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) + channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { - return nil, types.ErrChannelNotFound(k.codespace, packet.SourceChannel()) + return nil, types.ErrChannelNotFound(k.codespace, packet.GetSourcePort(), packet.GetSourceChannel()) } if channel.State != types.OPEN { @@ -307,22 +308,22 @@ func (k Keeper) AcknowledgePacket( ) } - if !k.portKeeper.Authenticate(portCapability, packet.SourcePort()) { + if !k.portKeeper.Authenticate(portCapability, packet.GetSourcePort()) { return nil, errors.New("invalid capability key") } // packet must come from the channel's counterparty - if packet.SourcePort() != channel.Counterparty.PortID { + if packet.GetSourcePort() != channel.Counterparty.PortID { return nil, types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet source port doesn't match the counterparty's port (%s ≠ %s)", packet.SourcePort(), channel.Counterparty.PortID), + fmt.Sprintf("packet source port doesn't match the counterparty's port (%s ≠ %s)", packet.GetSourcePort(), channel.Counterparty.PortID), ) } - if packet.SourceChannel() != channel.Counterparty.ChannelID { + if packet.GetSourceChannel() != channel.Counterparty.ChannelID { return nil, types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet source channel doesn't match the counterparty's channel (%s ≠ %s)", packet.SourceChannel(), channel.Counterparty.ChannelID), + fmt.Sprintf("packet source channel doesn't match the counterparty's channel (%s ≠ %s)", packet.GetSourceChannel(), channel.Counterparty.ChannelID), ) } @@ -338,19 +339,19 @@ func (k Keeper) AcknowledgePacket( ) } - commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) - if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data + commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + if !bytes.Equal(commitment, packet.GetData()) { // TODO: hash packet data return nil, types.ErrInvalidPacket(k.codespace, "packet hasn't been sent") } if !k.connectionKeeper.VerifyMembership( ctx, connectionEnd, proofHeight, proof, - types.PacketAcknowledgementPath(packet.DestPort(), packet.DestChannel(), packet.Sequence()), + types.PacketAcknowledgementPath(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()), acknowledgement, // TODO: hash ACK ) { return nil, errors.New("invalid acknowledgement on counterparty chain") } - k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) return packet, nil } diff --git a/x/ibc/04-channel/keeper/querier.go b/x/ibc/04-channel/keeper/querier.go index 08a371f028c0..3618c5f29fd4 100644 --- a/x/ibc/04-channel/keeper/querier.go +++ b/x/ibc/04-channel/keeper/querier.go @@ -20,7 +20,7 @@ func QuerierChannel(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, s channel, found := k.GetChannel(ctx, params.PortID, params.ChannelID) if !found { - return nil, types.ErrChannelNotFound(k.codespace, params.ChannelID) + return nil, types.ErrChannelNotFound(k.codespace, params.PortID, params.ChannelID) } bz, err := types.SubModuleCdc.MarshalJSON(channel) diff --git a/x/ibc/04-channel/keeper/timeout.go b/x/ibc/04-channel/keeper/timeout.go index 232e60eb6de1..3ae481373de3 100644 --- a/x/ibc/04-channel/keeper/timeout.go +++ b/x/ibc/04-channel/keeper/timeout.go @@ -25,9 +25,9 @@ func (k Keeper) TimeoutPacket( nextSequenceRecv uint64, portCapability sdk.CapabilityKey, ) (exported.PacketI, error) { - channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) + channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { - return nil, types.ErrChannelNotFound(k.codespace, packet.SourceChannel()) + return nil, types.ErrChannelNotFound(k.codespace, packet.GetSourcePort(), packet.GetSourceChannel()) } if channel.State != types.OPEN { @@ -37,19 +37,19 @@ func (k Keeper) TimeoutPacket( ) } - _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) + _, found = k.GetChannelCapability(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { return nil, types.ErrChannelCapabilityNotFound(k.codespace) } - if !k.portKeeper.Authenticate(portCapability, packet.SourcePort()) { + if !k.portKeeper.Authenticate(portCapability, packet.GetSourcePort()) { return nil, errors.New("port is not valid") } - if packet.DestChannel() != channel.Counterparty.ChannelID { + if packet.GetDestChannel() != channel.Counterparty.ChannelID { return nil, types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.DestChannel(), channel.Counterparty.ChannelID), + fmt.Sprintf("packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.GetDestChannel(), channel.Counterparty.ChannelID), ) } @@ -58,23 +58,23 @@ func (k Keeper) TimeoutPacket( return nil, connection.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } - if packet.DestPort() != channel.Counterparty.PortID { + if packet.GetDestPort() != channel.Counterparty.PortID { return nil, types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.DestPort(), channel.Counterparty.PortID), + fmt.Sprintf("packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.GetDestPort(), channel.Counterparty.PortID), ) } - if proofHeight < packet.TimeoutHeight() { + if proofHeight < packet.GetTimeoutHeight() { return nil, types.ErrPacketTimeout(k.codespace) } - if nextSequenceRecv >= packet.Sequence() { + if nextSequenceRecv >= packet.GetSequence() { return nil, types.ErrInvalidPacket(k.codespace, "packet already received") } - commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) - if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data + commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + if !bytes.Equal(commitment, packet.GetData()) { // TODO: hash packet data return nil, types.ErrInvalidPacket(k.codespace, "packet hasn't been sent") } @@ -83,13 +83,13 @@ func (k Keeper) TimeoutPacket( case types.ORDERED: ok = k.connectionKeeper.VerifyMembership( ctx, connectionEnd, proofHeight, proof, - types.NextSequenceRecvPath(packet.DestPort(), packet.DestChannel()), + types.NextSequenceRecvPath(packet.GetDestPort(), packet.GetDestChannel()), sdk.Uint64ToBigEndian(nextSequenceRecv), ) case types.UNORDERED: ok = k.connectionKeeper.VerifyNonMembership( ctx, connectionEnd, proofHeight, proof, - types.PacketAcknowledgementPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), + types.PacketAcknowledgementPath(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()), ) default: panic(fmt.Sprintf("invalid channel ordering type %v", channel.Ordering)) @@ -99,11 +99,11 @@ func (k Keeper) TimeoutPacket( return nil, types.ErrInvalidPacket(k.codespace, "packet verification failed") } - k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) if channel.Ordering == types.ORDERED { channel.State = types.CLOSED - k.SetChannel(ctx, packet.SourcePort(), packet.SourceChannel(), channel) + k.SetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), channel) } return packet, nil @@ -120,24 +120,24 @@ func (k Keeper) TimeoutOnClose( proofHeight uint64, portCapability sdk.CapabilityKey, ) (exported.PacketI, error) { - channel, found := k.GetChannel(ctx, packet.SourcePort(), packet.SourceChannel()) + channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { - return nil, types.ErrChannelNotFound(k.codespace, packet.SourceChannel()) + return nil, types.ErrChannelNotFound(k.codespace, packet.GetSourcePort(), packet.GetSourceChannel()) } - _, found = k.GetChannelCapability(ctx, packet.SourcePort(), packet.SourceChannel()) + _, found = k.GetChannelCapability(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { return nil, types.ErrChannelCapabilityNotFound(k.codespace) } - if !k.portKeeper.Authenticate(portCapability, packet.SourcePort()) { + if !k.portKeeper.Authenticate(portCapability, packet.GetSourcePort()) { return nil, errors.New("port is not valid") } - if packet.DestChannel() != channel.Counterparty.ChannelID { + if packet.GetDestChannel() != channel.Counterparty.ChannelID { return nil, types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.DestChannel(), channel.Counterparty.ChannelID), + fmt.Sprintf("packet destination channel doesn't match the counterparty's channel (%s ≠ %s)", packet.GetDestChannel(), channel.Counterparty.ChannelID), ) } @@ -146,21 +146,27 @@ func (k Keeper) TimeoutOnClose( return nil, connection.ErrConnectionNotFound(k.codespace, channel.ConnectionHops[0]) } - if packet.DestPort() != channel.Counterparty.PortID { + if packet.GetDestPort() != channel.Counterparty.PortID { return nil, types.ErrInvalidPacket( k.codespace, - fmt.Sprintf("packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.DestPort(), channel.Counterparty.PortID), + fmt.Sprintf("packet destination port doesn't match the counterparty's port (%s ≠ %s)", packet.GetDestPort(), channel.Counterparty.PortID), ) } - commitment := k.GetPacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) - if !bytes.Equal(commitment, packet.Data()) { // TODO: hash packet data + commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + if !bytes.Equal(commitment, packet.GetData()) { // TODO: hash packet data return nil, types.ErrInvalidPacket(k.codespace, "packet hasn't been sent") } - counterparty := types.NewCounterparty(packet.SourcePort(), packet.SourceChannel()) + counterpartyHops, found := k.CounterpartyHops(ctx, channel) + if !found { + // Should not reach here, connectionEnd was able to be retrieved above + panic("cannot find connection") + } + + counterparty := types.NewCounterparty(packet.GetSourcePort(), packet.GetSourceChannel()) expectedChannel := types.NewChannel( - types.CLOSED, channel.Ordering, counterparty, channel.CounterpartyHops(), channel.Version, + types.CLOSED, channel.Ordering, counterparty, counterpartyHops, channel.Version, ) bz, err := k.cdc.MarshalBinaryLengthPrefixed(expectedChannel) @@ -178,12 +184,12 @@ func (k Keeper) TimeoutOnClose( if !k.connectionKeeper.VerifyNonMembership( ctx, connectionEnd, proofHeight, proofNonMembership, - types.PacketAcknowledgementPath(packet.SourcePort(), packet.SourceChannel(), packet.Sequence()), + types.PacketAcknowledgementPath(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()), ) { return nil, errors.New("cannot verify absence of acknowledgement at packet index") } - k.deletePacketCommitment(ctx, packet.SourcePort(), packet.SourceChannel(), packet.Sequence()) + k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) return packet, nil } diff --git a/x/ibc/04-channel/module.go b/x/ibc/04-channel/module.go new file mode 100644 index 000000000000..4f9b17b03144 --- /dev/null +++ b/x/ibc/04-channel/module.go @@ -0,0 +1,25 @@ +package channel + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/client/cli" +) + +// Name returns the IBC connection ICS name +func Name() string { + return SubModuleName +} + +// GetTxCmd returns the root tx command for the IBC connections. +func GetTxCmd(cdc *codec.Codec, storeKey string) *cobra.Command { + return cli.GetTxCmd(fmt.Sprintf("%s/%s", storeKey, SubModuleName), cdc) +} + +// GetQueryCmd returns no root query command for the IBC connections. +func GetQueryCmd(cdc *codec.Codec, queryRoute string) *cobra.Command { + return cli.GetQueryCmd(fmt.Sprintf("%s/%s", queryRoute, SubModuleName), cdc) +} diff --git a/x/ibc/04-channel/types/channel.go b/x/ibc/04-channel/types/channel.go index e57869c9ff36..98bbb9b44f1e 100644 --- a/x/ibc/04-channel/types/channel.go +++ b/x/ibc/04-channel/types/channel.go @@ -32,16 +32,6 @@ func NewChannel( } } -// CounterpartyHops returns the connection hops of the counterparty channel. -// The counterparty hops are stored in the inverse order as the channel's. -func (ch Channel) CounterpartyHops() []string { - counterPartyHops := make([]string, len(ch.ConnectionHops)) - for i, hop := range ch.ConnectionHops { - counterPartyHops[len(counterPartyHops)-1-i] = hop - } - return counterPartyHops -} - // ValidateBasic performs a basic validation of the channel fields func (ch Channel) ValidateBasic() sdk.Error { if ch.State.String() == "" { @@ -59,7 +49,7 @@ func (ch Channel) ValidateBasic() sdk.Error { if len(ch.ConnectionHops) != 1 { return ErrInvalidChannel(DefaultCodespace, "IBC v1 only supports one connection hop") } - if err := host.DefaultIdentifierValidator(ch.ConnectionHops[0]); err != nil { + if err := host.DefaultConnectionIdentifierValidator(ch.ConnectionHops[0]); err != nil { return ErrInvalidChannel(DefaultCodespace, errors.Wrap(err, "invalid connection hop ID").Error()) } if strings.TrimSpace(ch.Version) == "" { @@ -84,10 +74,10 @@ func NewCounterparty(portID, channelID string) Counterparty { // ValidateBasic performs a basic validation check of the identifiers func (c Counterparty) ValidateBasic() sdk.Error { - if err := host.DefaultIdentifierValidator(c.PortID); err != nil { + if err := host.DefaultPortIdentifierValidator(c.PortID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid counterparty connection ID: %s", err.Error())) } - if err := host.DefaultIdentifierValidator(c.ChannelID); err != nil { + if err := host.DefaultChannelIdentifierValidator(c.ChannelID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid counterparty client ID: %s", err.Error())) } return nil diff --git a/x/ibc/04-channel/types/codec.go b/x/ibc/04-channel/types/codec.go index 4cfc1e773a1e..0839edede775 100644 --- a/x/ibc/04-channel/types/codec.go +++ b/x/ibc/04-channel/types/codec.go @@ -5,10 +5,14 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" ) -var SubModuleCdc *codec.Codec +// SubModuleCdc defines the IBC channel codec. +var SubModuleCdc = codec.New() +// RegisterCodec registers all the necessary types and interfaces for the +// IBC channel. func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*exported.PacketI)(nil), nil) + cdc.RegisterConcrete(Packet{}, "ibc/channel/Packet", nil) cdc.RegisterConcrete(OpaquePacket{}, "ibc/channel/OpaquePacket", nil) cdc.RegisterConcrete(MsgChannelOpenInit{}, "ibc/channel/MsgChannelOpenInit", nil) @@ -19,6 +23,6 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgChannelCloseConfirm{}, "ibc/channel/MsgChannelCloseConfirm", nil) } -func SetMsgChanCodec(cdc *codec.Codec) { - SubModuleCdc = cdc +func init() { + RegisterCodec(SubModuleCdc) } diff --git a/x/ibc/04-channel/types/errors.go b/x/ibc/04-channel/types/errors.go index 92140b3aef2a..37d3925b513e 100644 --- a/x/ibc/04-channel/types/errors.go +++ b/x/ibc/04-channel/types/errors.go @@ -28,8 +28,8 @@ func ErrChannelExists(codespace sdk.CodespaceType, channelID string) sdk.Error { } // ErrChannelNotFound implements sdk.Error -func ErrChannelNotFound(codespace sdk.CodespaceType, channelID string) sdk.Error { - return sdk.NewError(codespace, CodeChannelNotFound, fmt.Sprintf("channel with ID %s not found", channelID)) +func ErrChannelNotFound(codespace sdk.CodespaceType, portID, channelID string) sdk.Error { + return sdk.NewError(codespace, CodeChannelNotFound, fmt.Sprintf("channel with ID %s on port %s not found", channelID, portID)) } // ErrInvalidCounterpartyChannel implements sdk.Error @@ -44,7 +44,7 @@ func ErrChannelCapabilityNotFound(codespace sdk.CodespaceType) sdk.Error { // ErrInvalidPacket implements sdk.Error func ErrInvalidPacket(codespace sdk.CodespaceType, msg string) sdk.Error { - return sdk.NewError(codespace, CodeInvalidPacket, "invalid packet sequence counter") + return sdk.NewError(codespace, CodeInvalidPacket, msg) } // ErrSequenceNotFound implements sdk.Error diff --git a/x/ibc/04-channel/types/msgs.go b/x/ibc/04-channel/types/msgs.go index 9f01bc04d2dc..a6d7d856e34f 100644 --- a/x/ibc/04-channel/types/msgs.go +++ b/x/ibc/04-channel/types/msgs.go @@ -46,10 +46,10 @@ func (msg MsgChannelOpenInit) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenInit) ValidateBasic() sdk.Error { - if err := host.DefaultIdentifierValidator(msg.PortID); err != nil { + if err := host.DefaultPortIdentifierValidator(msg.PortID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) } - if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { + if err := host.DefaultChannelIdentifierValidator(msg.ChannelID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } // Signer can be empty @@ -109,10 +109,10 @@ func (msg MsgChannelOpenTry) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenTry) ValidateBasic() sdk.Error { - if err := host.DefaultIdentifierValidator(msg.PortID); err != nil { + if err := host.DefaultPortIdentifierValidator(msg.PortID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) } - if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { + if err := host.DefaultChannelIdentifierValidator(msg.ChannelID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } if strings.TrimSpace(msg.CounterpartyVersion) == "" { @@ -176,10 +176,10 @@ func (msg MsgChannelOpenAck) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenAck) ValidateBasic() sdk.Error { - if err := host.DefaultIdentifierValidator(msg.PortID); err != nil { + if err := host.DefaultPortIdentifierValidator(msg.PortID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) } - if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { + if err := host.DefaultChannelIdentifierValidator(msg.ChannelID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } if strings.TrimSpace(msg.CounterpartyVersion) == "" { @@ -241,10 +241,10 @@ func (msg MsgChannelOpenConfirm) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgChannelOpenConfirm) ValidateBasic() sdk.Error { - if err := host.DefaultIdentifierValidator(msg.PortID); err != nil { + if err := host.DefaultPortIdentifierValidator(msg.PortID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) } - if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { + if err := host.DefaultChannelIdentifierValidator(msg.ChannelID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } if msg.ProofAck == nil { @@ -296,10 +296,10 @@ func (msg MsgChannelCloseInit) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgChannelCloseInit) ValidateBasic() sdk.Error { - if err := host.DefaultIdentifierValidator(msg.PortID); err != nil { + if err := host.DefaultPortIdentifierValidator(msg.PortID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) } - if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { + if err := host.DefaultChannelIdentifierValidator(msg.ChannelID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } // Signer can be empty @@ -352,10 +352,10 @@ func (msg MsgChannelCloseConfirm) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgChannelCloseConfirm) ValidateBasic() sdk.Error { - if err := host.DefaultIdentifierValidator(msg.PortID); err != nil { + if err := host.DefaultPortIdentifierValidator(msg.PortID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) } - if err := host.DefaultIdentifierValidator(msg.ChannelID); err != nil { + if err := host.DefaultChannelIdentifierValidator(msg.ChannelID); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } if msg.ProofInit == nil { diff --git a/x/ibc/04-channel/types/packet.go b/x/ibc/04-channel/types/packet.go index 29baa1c118e7..8d170cc62a9d 100644 --- a/x/ibc/04-channel/types/packet.go +++ b/x/ibc/04-channel/types/packet.go @@ -12,13 +12,13 @@ var _ exported.PacketI = Packet{} // Packet defines a type that carries data across different chains through IBC type Packet struct { - sequence uint64 `json:"sequence"` // number corresponds to the order of sends and receives, where a Packet with an earlier sequence number must be sent and received before a Packet with a later sequence number. - timeout uint64 `json:"timeout"` // indicates a consensus height on the destination chain after which the Packet will no longer be processed, and will instead count as having timed-out. - sourcePort string `json:"source_port"` // identifies the port on the sending chain. - sourceChannel string `json:"source_channel"` // identifies the channel end on the sending chain. - destinationPort string `json:"destination_port"` // identifies the port on the receiving chain. - destinationChannel string `json:"destination_channel"` // identifies the channel end on the receiving chain. - data []byte `json:"data"` // opaque value which can be defined by the application logic of the associated modules. + Sequence uint64 `json:"sequence"` // number corresponds to the order of sends and receives, where a Packet with an earlier sequence number must be sent and received before a Packet with a later sequence number. + Timeout uint64 `json:"timeout"` // indicates a consensus height on the destination chain after which the Packet will no longer be processed, and will instead count as having timed-out. + SourcePort string `json:"source_port"` // identifies the port on the sending chain. + SourceChannel string `json:"source_channel"` // identifies the channel end on the sending chain. + DestinationPort string `json:"destination_port"` // identifies the port on the receiving chain. + DestinationChannel string `json:"destination_channel"` // identifies the channel end on the receiving chain. + Data []byte `json:"data"` // opaque value which can be defined by the application logic of the associated modules. } // NewPacket creates a new Packet instance @@ -38,47 +38,47 @@ func NewPacket( } // Sequence implements PacketI interface -func (p Packet) Sequence() uint64 { return p.sequence } +func (p Packet) GetSequence() uint64 { return p.Sequence } // TimeoutHeight implements PacketI interface -func (p Packet) TimeoutHeight() uint64 { return p.timeout } +func (p Packet) GetTimeoutHeight() uint64 { return p.Timeout } // SourcePort implements PacketI interface -func (p Packet) SourcePort() string { return p.sourcePort } +func (p Packet) GetSourcePort() string { return p.SourcePort } // SourceChannel implements PacketI interface -func (p Packet) SourceChannel() string { return p.sourceChannel } +func (p Packet) GetSourceChannel() string { return p.SourceChannel } // DestPort implements PacketI interface -func (p Packet) DestPort() string { return p.destinationPort } +func (p Packet) GetDestPort() string { return p.DestinationPort } // DestChannel implements PacketI interface -func (p Packet) DestChannel() string { return p.destinationChannel } +func (p Packet) GetDestChannel() string { return p.DestinationChannel } // Data implements PacketI interface -func (p Packet) Data() []byte { return p.data } +func (p Packet) GetData() []byte { return p.Data } // ValidateBasic implements PacketI interface func (p Packet) ValidateBasic() sdk.Error { - if err := host.DefaultIdentifierValidator(p.sourcePort); err != nil { + if err := host.DefaultPortIdentifierValidator(p.SourcePort); err != nil { return ErrInvalidPacket(DefaultCodespace, fmt.Sprintf("invalid source port ID: %s", err.Error())) } - if err := host.DefaultIdentifierValidator(p.destinationPort); err != nil { + if err := host.DefaultPortIdentifierValidator(p.DestinationPort); err != nil { return ErrInvalidPacket(DefaultCodespace, fmt.Sprintf("invalid destination port ID: %s", err.Error())) } - if err := host.DefaultIdentifierValidator(p.sourceChannel); err != nil { + if err := host.DefaultChannelIdentifierValidator(p.SourceChannel); err != nil { return ErrInvalidPacket(DefaultCodespace, fmt.Sprintf("invalid source channel ID: %s", err.Error())) } - if err := host.DefaultIdentifierValidator(p.destinationChannel); err != nil { + if err := host.DefaultChannelIdentifierValidator(p.DestinationChannel); err != nil { return ErrInvalidPacket(DefaultCodespace, fmt.Sprintf("invalid destination channel ID: %s", err.Error())) } - if p.sequence == 0 { + if p.Sequence == 0 { return ErrInvalidPacket(DefaultCodespace, "packet sequence cannot be 0") } - if p.timeout == 0 { + if p.Timeout == 0 { return ErrPacketTimeout(DefaultCodespace) } - if len(p.data) == 0 { + if len(p.Data) == 0 { return ErrInvalidPacket(DefaultCodespace, "packet data cannot be empty") } return nil @@ -105,4 +105,4 @@ func NewOpaquePacket(sequence, timeout uint64, sourcePort, sourceChannel, } // Data implements PacketI interface -func (op OpaquePacket) Data() []byte { return nil } +func (op OpaquePacket) GetData() []byte { return nil } diff --git a/x/ibc/04-channel/types/querier.go b/x/ibc/04-channel/types/querier.go index f6960d663cfb..707e9076ca39 100644 --- a/x/ibc/04-channel/types/querier.go +++ b/x/ibc/04-channel/types/querier.go @@ -48,3 +48,24 @@ func NewQueryChannelParams(portID, channelID string) QueryChannelParams { ChannelID: channelID, } } + +// PacketResponse defines the client query response for a packet which also +// includes a proof, its path and the height form which the proof was retrieved +type PacketResponse struct { + Packet Packet `json:"packet" yaml:"packet"` + Proof commitment.Proof `json:"proof,omitempty" yaml:"proof,omitempty"` + ProofPath commitment.Path `json:"proof_path,omitempty" yaml:"proof_path,omitempty"` + ProofHeight uint64 `json:"proof_height,omitempty" yaml:"proof_height,omitempty"` +} + +// NewPacketResponse creates a new PacketResponswe instance +func NewPacketResponse( + portID, channelID string, sequence uint64, packet Packet, proof *merkle.Proof, height int64, +) PacketResponse { + return PacketResponse{ + Packet: packet, + Proof: commitment.Proof{Proof: proof}, + ProofPath: commitment.NewPath(strings.Split(PacketCommitmentPath(portID, channelID, sequence), "/")), + ProofHeight: uint64(height), + } +} From 8e669fe0a6f0686de6b18aee1e45577ce83e2b68 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 5 Nov 2019 14:47:59 +0100 Subject: [PATCH 378/378] upstream changes --- x/ibc/20-transfer/client/cli/query.go | 68 ++++++++++++++++++++++ x/ibc/20-transfer/client/cli/tx.go | 84 ++++++++++++++++----------- x/ibc/20-transfer/keeper/callbacks.go | 12 ++-- x/ibc/20-transfer/keeper/relay.go | 15 ++--- x/ibc/20-transfer/types/codec.go | 1 + x/ibc/20-transfer/types/keys.go | 2 +- x/ibc/20-transfer/types/msgs.go | 6 +- 7 files changed, 136 insertions(+), 52 deletions(-) create mode 100644 x/ibc/20-transfer/client/cli/query.go diff --git a/x/ibc/20-transfer/client/cli/query.go b/x/ibc/20-transfer/client/cli/query.go new file mode 100644 index 000000000000..1795e1919edb --- /dev/null +++ b/x/ibc/20-transfer/client/cli/query.go @@ -0,0 +1,68 @@ +package cli + +import ( + "encoding/binary" + "fmt" + "strings" + + "github.com/spf13/cobra" + + "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/version" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + abci "github.com/tendermint/tendermint/abci/types" +) + +// GetTxCmd returns the transaction commands for IBC fungible token transfer +func GetQueryCmd(cdc *codec.Codec, storeKey string) *cobra.Command { + queryCmd := &cobra.Command{ + Use: "transfer", + Short: "IBC fungible token transfer query subcommands", + } + + queryCmd.AddCommand( + GetCmdQueryNextSequence(cdc, storeKey), + ) + + return queryCmd +} + +// GetCmdQueryNextSequence defines the command to query a next receive sequence +func GetCmdQueryNextSequence(cdc *codec.Codec, queryRoute string) *cobra.Command { + cmd := &cobra.Command{ + Use: "next-recv [port-id] [channel-id]", + Short: "Query a next receive sequence", + Long: strings.TrimSpace(fmt.Sprintf(`Query an IBC channel end + +Example: +$ %s query ibc channel next-recv [port-id] [channel-id] + `, version.ClientName), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + portID := args[0] + channelID := args[1] + + req := abci.RequestQuery{ + Path: "store/ibc/key", + Data: channel.KeyNextSequenceRecv(portID, channelID), + Prove: true, + } + + res, err := cliCtx.QueryABCI(req) + if err != nil { + return err + } + + sequence := binary.BigEndian.Uint64(res.Value) + + return cliCtx.PrintOutput(sequence) + }, + } + cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results") + + return cmd +} diff --git a/x/ibc/20-transfer/client/cli/tx.go b/x/ibc/20-transfer/client/cli/tx.go index 99be5e6387c3..28870567b55c 100644 --- a/x/ibc/20-transfer/client/cli/tx.go +++ b/x/ibc/20-transfer/client/cli/tx.go @@ -1,29 +1,34 @@ package cli import ( - "fmt" - "io/ioutil" - "os" - "strconv" - "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/keys" "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" - channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + clientutils "github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/utils" + channelutils "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/client/utils" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // IBC transfer flags var ( - FlagSource = "source" + FlagSource = "source" + FlagNode1 = "node1" + FlagNode2 = "node2" + FlagFrom1 = "from1" + FlagFrom2 = "from2" + FlagChainId2 = "chain-id2" + FlagSequence = "packet-sequence" + FlagTimeout = "timeout" ) // GetTxCmd returns the transaction commands for IBC fungible token transfer @@ -75,58 +80,71 @@ func GetTransferTxCmd(cdc *codec.Codec) *cobra.Command { }, } cmd.Flags().Bool(FlagSource, false, "Pass flag for sending token from the source chain") + cmd.Flags().String(flags.FlagFrom, "", "key in local keystore to send from") return cmd } // GetMsgRecvPacketCmd returns the command to create a MsgRecvTransferPacket transaction func GetMsgRecvPacketCmd(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "recv-packet [/path/to/packet-data.json] [/path/to/proof.json] [height]", + Use: "recv-packet [sending-port-id] [sending-channel-id] [client-id]", Short: "Creates and sends a SendPacket message", Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) error { txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) cliCtx := context.NewCLIContext().WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) - var packet channelexported.PacketI - if err := cdc.UnmarshalJSON([]byte(args[0]), &packet); err != nil { - fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...\n") - contents, err := ioutil.ReadFile(args[0]) - if err != nil { - return fmt.Errorf("error opening packet file: %v", err) - } - - if err := cdc.UnmarshalJSON(contents, packet); err != nil { - return fmt.Errorf("error unmarshalling packet file: %v", err) - } + node2 := viper.GetString(FlagNode2) + cid1 := viper.GetString(flags.FlagChainID) + cid2 := viper.GetString(FlagChainId2) + cliCtx2 := context.NewCLIContextIBC(cliCtx.GetFromAddress().String(), cid2, node2). + WithCodec(cdc). + WithBroadcastMode(flags.BroadcastBlock) + + header, err := clientutils.GetTendermintHeader(cliCtx2) + if err != nil { + return err } - var proof commitment.Proof - if err := cdc.UnmarshalJSON([]byte(args[1]), &proof); err != nil { - fmt.Fprintf(os.Stderr, "failed to unmarshall input into struct, checking for file...\n") - contents, err := ioutil.ReadFile(args[1]) - if err != nil { - return fmt.Errorf("error opening proofs file: %v", err) - } - if err := cdc.UnmarshalJSON(contents, &proof); err != nil { - return fmt.Errorf("error unmarshalling proofs file: %v", err) - } + sourcePort, sourceChannel, clientid := args[0], args[1], args[2] + + passphrase, err := keys.GetPassphrase(viper.GetString(flags.FlagFrom)) + if err != nil { + return nil } - height, err := strconv.ParseUint(args[2], 10, 64) + viper.Set(flags.FlagChainID, cid1) + msgUpdateClient := clienttypes.NewMsgUpdateClient(clientid, header, cliCtx.GetFromAddress()) + if err := msgUpdateClient.ValidateBasic(); err != nil { + return err + } + + res, err := utils.CompleteAndBroadcastTx(txBldr, cliCtx, []sdk.Msg{msgUpdateClient}, passphrase) + if err != nil || !res.IsOK() { + return err + } + + viper.Set(flags.FlagChainID, cid2) + sequence := uint64(viper.GetInt(FlagSequence)) + packetRes, err := channelutils.QueryPacket(cliCtx2.WithHeight(header.Height-1), sourcePort, sourceChannel, sequence, uint64(viper.GetInt(FlagTimeout)), "ibc") if err != nil { - return fmt.Errorf("error height: %v", err) + return err } + viper.Set(flags.FlagChainID, cid1) - msg := types.NewMsgRecvPacket(packet, []commitment.Proof{proof}, height, cliCtx.GetFromAddress()) + msg := types.NewMsgRecvPacket(packetRes.Packet, []commitment.Proof{packetRes.Proof}, packetRes.ProofHeight, cliCtx.GetFromAddress()) if err := msg.ValidateBasic(); err != nil { return err } - return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) }, } cmd = client.PostCommands(cmd)[0] + cmd.Flags().Bool(FlagSource, false, "Pass flag for sending token from the source chain") + cmd.Flags().String(FlagNode2, "tcp://localhost:26657", "RPC port for the second chain") + cmd.Flags().String(FlagChainId2, "", "chain-id for the second chain") + cmd.Flags().String(FlagSequence, "", "sequence for the packet") + cmd.Flags().String(FlagTimeout, "", "timeout for the packet") return cmd } diff --git a/x/ibc/20-transfer/keeper/callbacks.go b/x/ibc/20-transfer/keeper/callbacks.go index bae2e96e073f..8594783e6456 100644 --- a/x/ibc/20-transfer/keeper/callbacks.go +++ b/x/ibc/20-transfer/keeper/callbacks.go @@ -120,14 +120,14 @@ func (k Keeper) onRecvPacket( ) error { var data types.PacketData - err := data.UnmarshalJSON(packet.Data()) + err := data.UnmarshalJSON(packet.GetData()) if err != nil { return types.ErrInvalidPacketData(k.codespace) } return k.ReceiveTransfer( - ctx, packet.SourcePort(), packet.SourceChannel(), - packet.DestPort(), packet.DestChannel(), data, + ctx, packet.GetSourcePort(), packet.GetSourceChannel(), + packet.GetDestPort(), packet.GetDestChannel(), data, ) } @@ -148,13 +148,13 @@ func (k Keeper) onTimeoutPacket( ) error { var data types.PacketData - err := data.UnmarshalJSON(packet.Data()) + err := data.UnmarshalJSON(packet.GetData()) if err != nil { return types.ErrInvalidPacketData(k.codespace) } // check the denom prefix - prefix := types.GetDenomPrefix(packet.SourcePort(), packet.SourcePort()) + prefix := types.GetDenomPrefix(packet.GetSourcePort(), packet.GetSourcePort()) coins := make(sdk.Coins, len(data.Amount)) for i, coin := range data.Amount { coin := coin @@ -165,7 +165,7 @@ func (k Keeper) onTimeoutPacket( } if data.Source { - escrowAddress := types.GetEscrowAddress(packet.DestPort(), packet.DestChannel()) + escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel()) return k.bankKeeper.SendCoins(ctx, escrowAddress, data.Sender, coins) } diff --git a/x/ibc/20-transfer/keeper/relay.go b/x/ibc/20-transfer/keeper/relay.go index 9dbe829b10f1..d87a589bbd80 100644 --- a/x/ibc/20-transfer/keeper/relay.go +++ b/x/ibc/20-transfer/keeper/relay.go @@ -24,7 +24,7 @@ func (k Keeper) SendTransfer( // get the port and channel of the counterparty channel, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel) if !found { - return channeltypes.ErrChannelNotFound(k.codespace, sourceChannel) + return channeltypes.ErrChannelNotFound(k.codespace, sourcePort, sourceChannel) } destinationPort := channel.Counterparty.PortID @@ -42,7 +42,6 @@ func (k Keeper) SendTransfer( case isSourceChain: // build the receiving denomination prefix for i, coin := range amount { - coin := coin coins[i] = sdk.NewCoin(prefix+coin.Denom, coin.Amount) } default: @@ -60,12 +59,12 @@ func (k Keeper) ReceivePacket(ctx sdk.Context, packet channelexported.PacketI, p } var data types.PacketData - err = data.UnmarshalJSON(packet.Data()) + err = data.UnmarshalJSON(packet.GetData()) if err != nil { return sdk.NewError(types.DefaultCodespace, types.CodeInvalidPacketData, "invalid packet data") } - return k.ReceiveTransfer(ctx, packet.SourcePort(), packet.SourceChannel(), packet.DestPort(), packet.DestChannel(), data) + return k.ReceiveTransfer(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetDestPort(), packet.GetDestChannel(), data) } // ReceiveTransfer handles transfer receiving logic @@ -80,7 +79,6 @@ func (k Keeper) ReceiveTransfer( if data.Source { prefix := types.GetDenomPrefix(destinationPort, destinationChannel) for _, coin := range data.Amount { - coin := coin if !strings.HasPrefix(coin.Denom, prefix) { return sdk.ErrInvalidCoins(fmt.Sprintf("%s doesn't contain the prefix '%s'", coin.Denom, prefix)) } @@ -102,7 +100,6 @@ func (k Keeper) ReceiveTransfer( prefix := types.GetDenomPrefix(sourcePort, sourceChannel) coins := make(sdk.Coins, len(data.Amount)) for i, coin := range data.Amount { - coin := coin if !strings.HasPrefix(coin.Denom, prefix) { return sdk.ErrInvalidCoins(fmt.Sprintf("%s doesn't contain the prefix '%s'", coin.Denom, prefix)) } @@ -133,7 +130,6 @@ func (k Keeper) createOutgoingPacket( prefix := types.GetDenomPrefix(destinationPort, destinationChannel) coins := make(sdk.Coins, len(amount)) for i, coin := range amount { - coin := coin if !strings.HasPrefix(coin.Denom, prefix) { return sdk.ErrInvalidCoins(fmt.Sprintf("%s doesn't contain the prefix '%s'", coin.Denom, prefix)) } @@ -149,7 +145,6 @@ func (k Keeper) createOutgoingPacket( // burn vouchers from the sender's balance if the source is from another chain prefix := types.GetDenomPrefix(sourcePort, sourceChannel) for _, coin := range amount { - coin := coin if !strings.HasPrefix(coin.Denom, prefix) { return sdk.ErrInvalidCoins(fmt.Sprintf("%s doesn't contain the prefix '%s'", coin.Denom, prefix)) } @@ -175,6 +170,7 @@ func (k Keeper) createOutgoingPacket( Source: isSourceChain, } + // TODO: This should be binary-marshaled and hashed (for the commitment in the store). packetDataBz, err := packetData.MarshalJSON() if err != nil { return sdk.NewError(sdk.CodespaceType(types.DefaultCodespace), types.CodeInvalidPacketData, "invalid packet data") @@ -190,7 +186,8 @@ func (k Keeper) createOutgoingPacket( packetDataBz, ) - // generate the capability key + // TODO: Remove this, capability keys are never generated when sending packets. Not sure why this is here. key := sdk.NewKVStoreKey(types.BoundPortID) + return k.channelKeeper.SendPacket(ctx, packet, key) } diff --git a/x/ibc/20-transfer/types/codec.go b/x/ibc/20-transfer/types/codec.go index 061c96e9d32a..ba018b3fc676 100644 --- a/x/ibc/20-transfer/types/codec.go +++ b/x/ibc/20-transfer/types/codec.go @@ -8,6 +8,7 @@ import ( func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgTransfer{}, "ibc/transfer/MsgTransfer", nil) + cdc.RegisterConcrete(MsgRecvPacket{}, "ibc/transfer/MsgRecvPacket", nil) cdc.RegisterConcrete(PacketData{}, "ibc/transfer/PacketData", nil) } diff --git a/x/ibc/20-transfer/types/keys.go b/x/ibc/20-transfer/types/keys.go index d79eb89fc5ba..09b54dcadea5 100644 --- a/x/ibc/20-transfer/types/keys.go +++ b/x/ibc/20-transfer/types/keys.go @@ -37,7 +37,7 @@ func GetEscrowAddress(portID, channelID string) sdk.AccAddress { // GetDenomPrefix returns the receiving denomination prefix func GetDenomPrefix(portID, channelID string) string { - return fmt.Sprintf("%s/%s", portID, channelID) + return fmt.Sprintf("%s/%s/", portID, channelID) } // GetModuleAccountName returns the IBC transfer module account name for supply diff --git a/x/ibc/20-transfer/types/msgs.go b/x/ibc/20-transfer/types/msgs.go index 4df5cf270407..506676e66d7e 100644 --- a/x/ibc/20-transfer/types/msgs.go +++ b/x/ibc/20-transfer/types/msgs.go @@ -46,10 +46,10 @@ func (MsgTransfer) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgTransfer) ValidateBasic() sdk.Error { - if err := host.DefaultIdentifierValidator(msg.SourcePort); err != nil { + if err := host.DefaultPortIdentifierValidator(msg.SourcePort); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid port ID: %s", err.Error())) } - if err := host.DefaultIdentifierValidator(msg.SourceChannel); err != nil { + if err := host.DefaultPortIdentifierValidator(msg.SourceChannel); err != nil { return sdk.NewError(host.IBCCodeSpace, 1, fmt.Sprintf("invalid channel ID: %s", err.Error())) } if !msg.Amount.IsValid() { @@ -96,7 +96,7 @@ func NewMsgRecvPacket(packet channelexported.PacketI, proofs []commitment.Proof, // Route implements sdk.Msg func (MsgRecvPacket) Route() string { - return RouterKey + return ibctypes.RouterKey } // Type implements sdk.Msg