From 55394987370a250b8fd247f63cded4eb479591f6 Mon Sep 17 00:00:00 2001 From: blushi Date: Thu, 8 Jul 2021 12:40:54 +0200 Subject: [PATCH 01/26] WIP on adding table/indexable --- store/table/index.go | 37 ++++++ store/table/iterator.go | 182 +++++++++++++++++++++++++++ store/table/table.go | 265 ++++++++++++++++++++++++++++++++++++++++ store/table/types.go | 114 +++++++++++++++++ 4 files changed, 598 insertions(+) create mode 100644 store/table/index.go create mode 100644 store/table/iterator.go create mode 100644 store/table/table.go create mode 100644 store/table/types.go diff --git a/store/table/index.go b/store/table/index.go new file mode 100644 index 000000000000..375a957f1989 --- /dev/null +++ b/store/table/index.go @@ -0,0 +1,37 @@ +package table + +// PrefixRange turns a prefix into a (start, end) range. The start is the given prefix value and +// the end is calculated by adding 1 bit to the start value. Nil is not allowed as prefix. +// Example: []byte{1, 3, 4} becomes []byte{1, 3, 5} +// []byte{15, 42, 255, 255} becomes []byte{15, 43, 0, 0} +// +// In case of an overflow the end is set to nil. +// Example: []byte{255, 255, 255, 255} becomes nil +// +func PrefixRange(prefix []byte) ([]byte, []byte) { + if prefix == nil { + panic("nil key not allowed") + } + // special case: no prefix is whole range + if len(prefix) == 0 { + return nil, nil + } + + // copy the prefix and update last byte + end := make([]byte, len(prefix)) + copy(end, prefix) + l := len(end) - 1 + end[l]++ + + // wait, what if that overflowed?.... + for end[l] == 0 && l > 0 { + l-- + end[l]++ + } + + // okay, funny guy, you gave us FFF, no end to this range... + if l == 0 && end[0] == 0 { + end = nil + } + return prefix, end +} diff --git a/store/table/iterator.go b/store/table/iterator.go new file mode 100644 index 000000000000..681a3c3379be --- /dev/null +++ b/store/table/iterator.go @@ -0,0 +1,182 @@ +package table + +import ( + "reflect" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/types/errors" +) + +// IteratorFunc is a function type that satisfies the Iterator interface +// The passed function is called on LoadNext operations. +type IteratorFunc func(dest codec.ProtoMarshaler) (RowID, error) + +// LoadNext loads the next value in the sequence into the pointer passed as dest and returns the key. If there +// are no more items the ErrIteratorDone error is returned +// The key is the rowID and not any MultiKeyIndex key. +func (i IteratorFunc) LoadNext(dest codec.ProtoMarshaler) (RowID, error) { + return i(dest) +} + +// Close always returns nil +func (i IteratorFunc) Close() error { + return nil +} + +func NewSingleValueIterator(rowID RowID, val []byte) Iterator { + var closed bool + return IteratorFunc(func(dest codec.ProtoMarshaler) (RowID, error) { + if dest == nil { + return nil, errors.Wrap(ErrArgument, "destination object must not be nil") + } + if closed || val == nil { + return nil, ErrIteratorDone + } + closed = true + return rowID, dest.Unmarshal(val) + }) +} + +// Iterator that return ErrIteratorInvalid only. +func NewInvalidIterator() Iterator { + return IteratorFunc(func(dest codec.ProtoMarshaler) (RowID, error) { + return nil, ErrIteratorInvalid + }) +} + +// LimitedIterator returns up to defined maximum number of elements. +type LimitedIterator struct { + remainingCount int + parentIterator Iterator +} + +// LimitIterator returns a new iterator that returns max number of elements. +// The parent iterator must not be nil +// max can be 0 or any positive number +func LimitIterator(parent Iterator, max int) *LimitedIterator { + if max < 0 { + panic("quantity must not be negative") + } + if parent == nil { + panic("parent iterator must not be nil") + } + return &LimitedIterator{remainingCount: max, parentIterator: parent} +} + +// LoadNext loads the next value in the sequence into the pointer passed as dest and returns the key. If there +// are no more items or the defined max number of elements was returned the `ErrIteratorDone` error is returned +// The key is the rowID and not any MultiKeyIndex key. +func (i *LimitedIterator) LoadNext(dest codec.ProtoMarshaler) (RowID, error) { + if i.remainingCount == 0 { + return nil, ErrIteratorDone + } + i.remainingCount-- + return i.parentIterator.LoadNext(dest) +} + +// Close releases the iterator and should be called at the end of iteration +func (i LimitedIterator) Close() error { + return i.parentIterator.Close() +} + +// First loads the first element into the given destination type and closes the iterator. +// When the iterator is closed or has no elements the according error is passed as return value. +func First(it Iterator, dest codec.ProtoMarshaler) (RowID, error) { + if it == nil { + return nil, errors.Wrap(ErrArgument, "iterator must not be nil") + } + defer it.Close() + binKey, err := it.LoadNext(dest) + if err != nil { + return nil, err + } + return binKey, nil +} + +// ModelSlicePtr represents a pointer to a slice of models. Think of it as +// *[]Model Because of Go's type system, using []Model type would not work for us. +// Instead we use a placeholder type and the validation is done during the +// runtime. +type ModelSlicePtr interface{} + +// ReadAll consumes all values for the iterator and stores them in a new slice at the passed ModelSlicePtr. +// The slice can be empty when the iterator does not return any values but not nil. The iterator +// is closed afterwards. +// Example: +// var loaded []testdata.GroupInfo +// rowIDs, err := ReadAll(it, &loaded) +// require.NoError(t, err) +// +func ReadAll(it Iterator, dest ModelSlicePtr) ([]RowID, error) { + if it == nil { + return nil, errors.Wrap(ErrArgument, "iterator must not be nil") + } + defer it.Close() + + var destRef, tmpSlice reflect.Value + elemType, err := assertDest(dest, &destRef, &tmpSlice) + if err != nil { + return nil, err + } + + var rowIDs []RowID + for { + obj := reflect.New(elemType) + val := obj.Elem() + model := obj + if elemType.Kind() == reflect.Ptr { + val.Set(reflect.New(elemType.Elem())) + model = val + } + + binKey, err := it.LoadNext(model.Interface().(codec.ProtoMarshaler)) + switch { + case err == nil: + tmpSlice = reflect.Append(tmpSlice, val) + case ErrIteratorDone.Is(err): + destRef.Set(tmpSlice) + return rowIDs, nil + default: + return nil, err + } + rowIDs = append(rowIDs, binKey) + } +} + +// assertDest checks that the provided dest is not nil and a pointer to a slice. +// It also verifies that the slice elements implement *codec.ProtoMarshaler. +// It overwrites destRef and tmpSlice using reflection. +func assertDest(dest ModelSlicePtr, destRef *reflect.Value, tmpSlice *reflect.Value) (reflect.Type, error) { + if dest == nil { + return nil, errors.Wrap(ErrArgument, "destination must not be nil") + } + tp := reflect.ValueOf(dest) + if tp.Kind() != reflect.Ptr { + return nil, errors.Wrap(ErrArgument, "destination must be a pointer to a slice") + } + if tp.Elem().Kind() != reflect.Slice { + return nil, errors.Wrap(ErrArgument, "destination must point to a slice") + } + + // Since dest is just an interface{}, we overwrite destRef using reflection + // to have an assignable copy of it. + *destRef = tp.Elem() + // We need to verify that we can call Set() on destRef. + if !destRef.CanSet() { + return nil, errors.Wrap(ErrArgument, "destination not assignable") + } + + elemType := reflect.TypeOf(dest).Elem().Elem() + + protoMarshaler := reflect.TypeOf((*codec.ProtoMarshaler)(nil)).Elem() + if !elemType.Implements(protoMarshaler) && + !reflect.PtrTo(elemType).Implements(protoMarshaler) { + return nil, errors.Wrapf(ErrArgument, "unsupported type :%s", elemType) + } + + // tmpSlice is a slice value for the specified type + // that we'll use for appending new elements. + *tmpSlice = reflect.MakeSlice(reflect.SliceOf(elemType), 0, 0) + + return elemType, nil +} diff --git a/store/table/table.go b/store/table/table.go new file mode 100644 index 000000000000..66635d4638e0 --- /dev/null +++ b/store/table/table.go @@ -0,0 +1,265 @@ +package table + +import ( + "bytes" + "reflect" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/errors" +) + +var _ Indexable = &TableBuilder{} + +type TableBuilder struct { + model reflect.Type + prefixData byte + indexKeyCodec IndexKeyCodec + afterSave []AfterSaveInterceptor + afterDelete []AfterDeleteInterceptor + cdc codec.Codec +} + +// NewTableBuilder creates a builder to setup a Table object. +func NewTableBuilder(prefixData byte, model codec.ProtoMarshaler, idxKeyCodec IndexKeyCodec, cdc codec.Codec) *TableBuilder { + if model == nil { + panic("Model must not be nil") + } + if idxKeyCodec == nil { + panic("IndexKeyCodec must not be nil") + } + tp := reflect.TypeOf(model) + if tp.Kind() == reflect.Ptr { + tp = tp.Elem() + } + return &TableBuilder{ + prefixData: prefixData, + model: tp, + indexKeyCodec: idxKeyCodec, + cdc: cdc, + } +} + +func (a TableBuilder) IndexKeyCodec() IndexKeyCodec { + return a.indexKeyCodec +} + +// RowGetter returns a type safe RowGetter. +func (a TableBuilder) RowGetter() RowGetter { + return NewTypeSafeRowGetter(a.prefixData, a.model, a.cdc) +} + +// Build creates a new Table object. +func (a TableBuilder) Build() Table { + return Table{ + model: a.model, + prefix: a.prefixData, + afterSave: a.afterSave, + afterDelete: a.afterDelete, + cdc: a.cdc, + } +} + +// AddAfterSaveInterceptor can be used to register a callback function that is executed after an object is created and/or updated. +func (a *TableBuilder) AddAfterSaveInterceptor(interceptor AfterSaveInterceptor) { + a.afterSave = append(a.afterSave, interceptor) +} + +// AddAfterDeleteInterceptor can be used to register a callback function that is executed after an object is deleted. +func (a *TableBuilder) AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) { + a.afterDelete = append(a.afterDelete, interceptor) +} + +// var _ TableExportable = &Table{} + +// Table is the high level object to storage mapper functionality. Persistent entities are stored by an unique identifier +// called `RowID`. +// The Table struct does not enforce uniqueness of the `RowID` but expects this to be satisfied by the callers and conditions +// to optimize Gas usage. +type Table struct { + model reflect.Type + prefix byte + afterSave []AfterSaveInterceptor + afterDelete []AfterDeleteInterceptor + cdc codec.Codec +} + +// Create persists the given object under the rowID key. It does not check if the +// key already exists. Any caller must either make sure that this contract is fulfilled +// by providing a universal unique ID or sequence that is guaranteed to not exist yet or +// by checking the state via `Has` function before. +// +// Create iterates though the registered callbacks and may add secondary index keys by them. +func (a Table) Create(store sdk.KVStore, rowID RowID, obj codec.ProtoMarshaler) error { + if err := assertCorrectType(a.model, obj); err != nil { + return err + } + if err := assertValid(obj); err != nil { + return err + } + pStore := prefix.NewStore(store, []byte{a.prefix}) + v, err := a.cdc.Marshal(obj) + if err != nil { + return errors.Wrapf(err, "failed to serialize %T", obj) + } + pStore.Set(rowID, v) + for i, itc := range a.afterSave { + if err := itc(store, rowID, obj, nil); err != nil { + return errors.Wrapf(err, "interceptor %d failed", i) + } + } + return nil +} + +// Save updates the given object under the rowID key. It expects the key to exist already +// and fails with an `ErrNotFound` otherwise. Any caller must therefore make sure that this contract +// is fulfilled. Parameters must not be nil. +// +// Save iterates though the registered callbacks and may add or remove secondary index keys by them. +func (a Table) Save(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler) error { + if err := assertCorrectType(a.model, newValue); err != nil { + return err + } + if err := assertValid(newValue); err != nil { + return err + } + + pStore := prefix.NewStore(store, []byte{a.prefix}) + var oldValue = reflect.New(a.model).Interface().(codec.ProtoMarshaler) + + if err := a.GetOne(store, rowID, oldValue); err != nil { + return errors.Wrap(err, "load old value") + } + newValueEncoded, err := a.cdc.Marshal(newValue) + if err != nil { + return errors.Wrapf(err, "failed to serialize %T", newValue) + } + + pStore.Set(rowID, newValueEncoded) + for i, itc := range a.afterSave { + if err := itc(store, rowID, newValue, oldValue); err != nil { + return errors.Wrapf(err, "interceptor %d failed", i) + } + } + return nil +} + +func assertValid(obj codec.ProtoMarshaler) error { + if v, ok := obj.(Validateable); ok { + if err := v.ValidateBasic(); err != nil { + return err + } + } + return nil +} + +// Delete removes the object under the rowID key. It expects the key to exists already +// and fails with a `ErrNotFound` otherwise. Any caller must therefore make sure that this contract +// is fulfilled. +// +// Delete iterates though the registered callbacks and removes secondary index keys by them. +func (a Table) Delete(store sdk.KVStore, rowID RowID) error { + pStore := prefix.NewStore(store, []byte{a.prefix}) + + var oldValue = reflect.New(a.model).Interface().(codec.ProtoMarshaler) + if err := a.GetOne(store, rowID, oldValue); err != nil { + return errors.Wrap(err, "load old value") + } + pStore.Delete(rowID) + + for i, itc := range a.afterDelete { + if err := itc(store, rowID, oldValue); err != nil { + return errors.Wrapf(err, "delete interceptor %d failed", i) + } + } + return nil +} + +// Has checks if a key exists. Panics on nil key. +func (a Table) Has(store sdk.KVStore, rowID RowID) bool { + Store := prefix.NewStore(store, []byte{a.prefix}) + it := Store.Iterator(PrefixRange(rowID)) + defer it.Close() + return it.Valid() +} + +// GetOne load the object persisted for the given RowID into the dest parameter. +// If none exists `ErrNotFound` is returned instead. Parameters must not be nil. +func (a Table) GetOne(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error { + x := NewTypeSafeRowGetter(a.prefix, a.model, a.cdc) + return x(store, rowID, dest) +} + +// PrefixScan returns an Iterator over a domain of keys in ascending order. End is exclusive. +// Start is an MultiKeyIndex key or prefix. It must be less than end, or the Iterator is invalid. +// Iterator must be closed by caller. +// To iterate over entire domain, use PrefixScan(nil, nil) +// +// WARNING: The use of a PrefixScan can be very expensive in terms of Gas. Please make sure you do not expose +// this as an endpoint to the public without further limits. +// Example: +// it, err := idx.PrefixScan(ctx, start, end) +// if err !=nil { +// return err +// } +// const defaultLimit = 20 +// it = LimitIterator(it, defaultLimit) +// +// CONTRACT: No writes may happen within a domain while an iterator exists over it. +func (a Table) PrefixScan(store sdk.KVStore, start, end RowID) (Iterator, error) { + if start != nil && end != nil && bytes.Compare(start, end) >= 0 { + return NewInvalidIterator(), errors.Wrap(ErrArgument, "start must be before end") + } + pStore := prefix.NewStore(store, []byte{a.prefix}) + return &typeSafeIterator{ + rowGetter: NewTypeSafeRowGetter(a.prefix, a.model, a.cdc), + it: pStore.Iterator(start, end), + }, nil +} + +// ReversePrefixScan returns an Iterator over a domain of keys in descending order. End is exclusive. +// Start is an MultiKeyIndex key or prefix. It must be less than end, or the Iterator is invalid and error is returned. +// Iterator must be closed by caller. +// To iterate over entire domain, use PrefixScan(nil, nil) +// +// WARNING: The use of a ReversePrefixScan can be very expensive in terms of Gas. Please make sure you do not expose +// this as an endpoint to the public without further limits. See `LimitIterator` +// +// CONTRACT: No writes may happen within a domain while an iterator exists over it. +func (a Table) ReversePrefixScan(store sdk.KVStore, start, end RowID) (Iterator, error) { + if start != nil && end != nil && bytes.Compare(start, end) >= 0 { + return NewInvalidIterator(), errors.Wrap(ErrArgument, "start must be before end") + } + pStore := prefix.NewStore(store, []byte{a.prefix}) + return &typeSafeIterator{ + rowGetter: NewTypeSafeRowGetter(a.prefix, a.model, a.cdc), + it: pStore.ReverseIterator(start, end), + }, nil +} + +func (a Table) Table() Table { + return a +} + +// typeSafeIterator is initialized with a type safe RowGetter only. +type typeSafeIterator struct { + store sdk.KVStore + rowGetter RowGetter + it types.Iterator +} + +func (i typeSafeIterator) LoadNext(dest codec.ProtoMarshaler) (RowID, error) { + if !i.it.Valid() { + return nil, ErrIteratorDone + } + rowID := i.it.Key() + i.it.Next() + return rowID, i.rowGetter(i.store, rowID, dest) +} + +func (i typeSafeIterator) Close() error { + i.it.Close() + return nil +} diff --git a/store/table/types.go b/store/table/types.go new file mode 100644 index 000000000000..f3e81e36c936 --- /dev/null +++ b/store/table/types.go @@ -0,0 +1,114 @@ +/* +Package orm is a convenient object to data store mapper. +*/ +package table + +import ( + "io" + "reflect" + + "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/types/errors" +) + +const ormCodespace = "orm" + +var ( + ErrNotFound = errors.Register(ormCodespace, 100, "not found") + ErrIteratorDone = errors.Register(ormCodespace, 101, "iterator done") + ErrIteratorInvalid = errors.Register(ormCodespace, 102, "iterator invalid") + ErrType = errors.Register(ormCodespace, 110, "invalid type") + ErrUniqueConstraint = errors.Register(ormCodespace, 111, "unique constraint violation") + ErrArgument = errors.Register(ormCodespace, 112, "invalid argument") + ErrIndexKeyMaxLength = errors.Register(ormCodespace, 113, "index key exceeds max length") +) + +// HasKVStore is a subset of the cosmos-sdk context defined for loose coupling and simpler test setups. +type HasKVStore interface { + KVStore(key sdk.StoreKey) sdk.KVStore +} + +// Unique identifier of a persistent table. +type RowID []byte + +// Bytes returns raw bytes. +func (r RowID) Bytes() []byte { + return r +} + +// Validateable is an interface that Persistent types can implement and is called on any orm save or update operation. +type Validateable interface { + // ValidateBasic is a sanity check on the data. Any error returned prevents create or updates. + ValidateBasic() error +} + +// Iterator allows iteration through a sequence of key value pairs +type Iterator interface { + // LoadNext loads the next value in the sequence into the pointer passed as dest and returns the key. If there + // are no more items the ErrIteratorDone error is returned + // The key is the rowID and not any MultiKeyIndex key. + LoadNext(dest codec.ProtoMarshaler) (RowID, error) + // Close releases the iterator and should be called at the end of iteration + io.Closer +} + +// IndexKeyCodec defines the encoding/ decoding methods for building/ splitting index keys. +type IndexKeyCodec interface { + // BuildIndexKey encodes a searchable key and the target RowID. + BuildIndexKey(searchableKey []byte, rowID RowID) []byte + // StripRowID returns the RowID from the combined persistentIndexKey. It is the reverse operation to BuildIndexKey + // but with the searchableKey dropped. + StripRowID(persistentIndexKey []byte) RowID +} + +// Indexable types are used to setup new tables. +// This interface provides a set of functions that can be called by indexes to register and interact with the tables. +type Indexable interface { + RowGetter() RowGetter + IndexKeyCodec() IndexKeyCodec + AddAfterSaveInterceptor(interceptor AfterSaveInterceptor) + AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) +} + +// AfterSaveInterceptor defines a callback function to be called on Create + Update. +type AfterSaveInterceptor func(store sdk.KVStore, rowID RowID, newValue, oldValue codec.ProtoMarshaler) error + +// AfterDeleteInterceptor defines a callback function to be called on Delete operations. +type AfterDeleteInterceptor func(store sdk.KVStore, rowID RowID, value codec.ProtoMarshaler) error + +// RowGetter loads a persistent object by row ID into the destination object. The dest parameter must therefore be a pointer. +// Any implementation must return `ErrNotFound` when no object for the rowID exists +type RowGetter func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error + +// NewTypeSafeRowGetter returns a `RowGetter` with type check on the dest parameter. +func NewTypeSafeRowGetter(prefixKey byte, model reflect.Type, cdc codec.Codec) RowGetter { + return func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error { + if len(rowID) == 0 { + return errors.Wrap(ErrArgument, "key must not be nil") + } + if err := assertCorrectType(model, dest); err != nil { + return err + } + + pStore := prefix.NewStore(store, []byte{prefixKey}) + it := pStore.Iterator(PrefixRange(rowID)) + defer it.Close() + if !it.Valid() { + return ErrNotFound + } + return cdc.Unmarshal(it.Value(), dest) + } +} + +func assertCorrectType(model reflect.Type, obj codec.ProtoMarshaler) error { + tp := reflect.TypeOf(obj) + if tp.Kind() != reflect.Ptr { + return errors.Wrap(ErrType, "model destination must be a pointer") + } + if model != tp.Elem() { + return errors.Wrapf(ErrType, "can not use %T with this bucket", obj) + } + return nil +} From 10a3bec7888380f5c7eefc11d438365d671649f0 Mon Sep 17 00:00:00 2001 From: blushi Date: Tue, 20 Jul 2021 09:33:23 +0200 Subject: [PATCH 02/26] Add some tests --- go.sum | 2 - store/table/index_key_codec.go | 68 ++++++++ store/table/index_key_codec_test.go | 115 +++++++++++++ store/table/table_test.go | 131 ++++++++++++++ store/table/testsupport.go | 32 ++++ store/table/types.go | 2 +- testutil/testdata/table.go | 14 ++ testutil/testdata/testdata.pb.go | 255 +++++++++++++++++++++++++--- testutil/testdata/testdata.proto | 5 + 9 files changed, 597 insertions(+), 27 deletions(-) create mode 100644 store/table/index_key_codec.go create mode 100644 store/table/index_key_codec_test.go create mode 100644 store/table/table_test.go create mode 100644 store/table/testsupport.go create mode 100644 testutil/testdata/table.go diff --git a/go.sum b/go.sum index 705f4b847055..f10b9e9f87b2 100644 --- a/go.sum +++ b/go.sum @@ -874,7 +874,6 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1092,7 +1091,6 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/store/table/index_key_codec.go b/store/table/index_key_codec.go new file mode 100644 index 000000000000..95b51e2f1a52 --- /dev/null +++ b/store/table/index_key_codec.go @@ -0,0 +1,68 @@ +package table + +// Max255DynamicLengthIndexKeyCodec works with up to 255 byte dynamic size RowIDs. +// They are encoded as `concat(searchableKey, rowID, len(rowID)[0])` and can be used +// with PrimaryKey or external Key tables for example. +type Max255DynamicLengthIndexKeyCodec struct{} + +// BuildIndexKey builds the index key by appending searchableKey with rowID and length int. +// The RowID length must not be greater than 255. +func (Max255DynamicLengthIndexKeyCodec) BuildIndexKey(searchableKey []byte, rowID RowID) []byte { + rowIDLen := len(rowID) + switch { + case rowIDLen == 0: + panic("Empty RowID") + case rowIDLen > 255: + panic("RowID exceeds max size") + } + + searchableKeyLen := len(searchableKey) + res := make([]byte, searchableKeyLen+rowIDLen+1) + copy(res, searchableKey) + copy(res[searchableKeyLen:], rowID) + res[searchableKeyLen+rowIDLen] = byte(rowIDLen) + return res +} + +// StripRowID returns the RowID from the combined persistentIndexKey. It is the reverse operation to BuildIndexKey +// but with the searchableKey and length int dropped. +func (Max255DynamicLengthIndexKeyCodec) StripRowID(persistentIndexKey []byte) RowID { + n := len(persistentIndexKey) + searchableKeyLen := persistentIndexKey[n-1] + return persistentIndexKey[n-int(searchableKeyLen)-1 : n-1] +} + +// FixLengthIndexKeyCodec expects the RowID to always have the same length with all entries. +// They are encoded as `concat(searchableKey, rowID)` and can be used +// with AutoUint64Tables and length EncodedSeqLength for example. +type FixLengthIndexKeyCodec struct { + rowIDLength int +} + +// FixLengthIndexKeys is a constructor for FixLengthIndexKeyCodec. +func FixLengthIndexKeys(rowIDLength int) *FixLengthIndexKeyCodec { + return &FixLengthIndexKeyCodec{rowIDLength: rowIDLength} +} + +// BuildIndexKey builds the index key by appending searchableKey with rowID. +// The RowID length must not be greater than what is defined by rowIDLength in construction. +func (c FixLengthIndexKeyCodec) BuildIndexKey(searchableKey []byte, rowID RowID) []byte { + switch n := len(rowID); { + case n == 0: + panic("Empty RowID") + case n > c.rowIDLength: + panic("RowID exceeds max size") + } + n := len(searchableKey) + res := make([]byte, n+c.rowIDLength) + copy(res, searchableKey) + copy(res[n:], rowID) + return res +} + +// StripRowID returns the RowID from the combined persistentIndexKey. It is the reverse operation to BuildIndexKey +// but with the searchableKey dropped. +func (c FixLengthIndexKeyCodec) StripRowID(persistentIndexKey []byte) RowID { + n := len(persistentIndexKey) + return persistentIndexKey[n-c.rowIDLength:] +} diff --git a/store/table/index_key_codec_test.go b/store/table/index_key_codec_test.go new file mode 100644 index 000000000000..b3c88c82b9a3 --- /dev/null +++ b/store/table/index_key_codec_test.go @@ -0,0 +1,115 @@ +package table + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestEncodeIndexKey(t *testing.T) { + specs := map[string]struct { + srcKey []byte + srcRowID RowID + enc IndexKeyCodec + expKey []byte + expPanic bool + }{ + "dynamic length example 1": { + srcKey: []byte{0x0, 0x1, 0x2}, + srcRowID: []byte{0x3, 0x4}, + enc: Max255DynamicLengthIndexKeyCodec{}, + expKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x2}, + }, + "dynamic length example 2": { + srcKey: []byte{0x0, 0x1}, + srcRowID: []byte{0x2, 0x3, 0x4}, + enc: Max255DynamicLengthIndexKeyCodec{}, + expKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x3}, + }, + "dynamic length max row ID": { + srcKey: []byte{0x0, 0x1}, + srcRowID: []byte(strings.Repeat("a", 255)), + enc: Max255DynamicLengthIndexKeyCodec{}, + expKey: append(append([]byte{0x0, 0x1}, []byte(strings.Repeat("a", 255))...), 0xff), + }, + "dynamic length panics with empty rowID": { + srcKey: []byte{0x0, 0x1}, + srcRowID: []byte{}, + enc: Max255DynamicLengthIndexKeyCodec{}, + expPanic: true, + }, + "dynamic length exceeds max row ID": { + srcKey: []byte{0x0, 0x1}, + srcRowID: []byte(strings.Repeat("a", 256)), + enc: Max255DynamicLengthIndexKeyCodec{}, + expPanic: true, + }, + "uint64 example": { + srcKey: []byte{0x0, 0x1, 0x2}, + srcRowID: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, + enc: FixLengthIndexKeys(8), + expKey: []byte{0x0, 0x1, 0x2, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, + }, + "uint64 panics with empty rowID": { + srcKey: []byte{0x0, 0x1}, + srcRowID: []byte{}, + enc: FixLengthIndexKeys(8), + expPanic: true, + }, + "uint64 exceeds max bytes in rowID": { + srcKey: []byte{0x0, 0x1}, + srcRowID: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}, + enc: FixLengthIndexKeys(8), + expPanic: true, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + if spec.expPanic { + require.Panics(t, + func() { + _ = spec.enc.BuildIndexKey(spec.srcKey, spec.srcRowID) + }) + return + } + got := spec.enc.BuildIndexKey(spec.srcKey, spec.srcRowID) + assert.Equal(t, spec.expKey, got) + }) + } +} +func TestDecodeIndexKey(t *testing.T) { + specs := map[string]struct { + srcKey []byte + enc IndexKeyCodec + expRowID RowID + }{ + "dynamic length example 1": { + srcKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x2}, + enc: Max255DynamicLengthIndexKeyCodec{}, + expRowID: []byte{0x3, 0x4}, + }, + "dynamic length example 2": { + srcKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x3}, + enc: Max255DynamicLengthIndexKeyCodec{}, + expRowID: []byte{0x2, 0x3, 0x4}, + }, + "dynamic length max row ID": { + srcKey: append(append([]byte{0x0, 0x1}, []byte(strings.Repeat("a", 255))...), 0xff), + enc: Max255DynamicLengthIndexKeyCodec{}, + expRowID: []byte(strings.Repeat("a", 255)), + }, + "uint64 example": { + srcKey: []byte{0x0, 0x1, 0x2, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, + expRowID: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, + enc: FixLengthIndexKeys(8), + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + gotRow := spec.enc.StripRowID(spec.srcKey) + assert.Equal(t, spec.expRowID, gotRow) + }) + } +} diff --git a/store/table/table_test.go b/store/table/table_test.go new file mode 100644 index 000000000000..1411d6353213 --- /dev/null +++ b/store/table/table_test.go @@ -0,0 +1,131 @@ +package table + +import ( + "fmt" + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCreate(t *testing.T) { + specs := map[string]struct { + src codec.ProtoMarshaler + expErr *errors.Error + }{ + "happy path": { + src: &testdata.GroupInfo{ + Description: "my group", + Admin: sdk.AccAddress([]byte("my-admin-address")), + }, + }, + "wrong type": { + src: &testdata.GroupMember{ + Group: sdk.AccAddress(EncodeSequence(1)), + Member: sdk.AccAddress([]byte("member-address")), + Weight: 10, + }, + expErr: ErrType, + }, + "model validation fails": { + src: &testdata.GroupInfo{Description: "invalid"}, + expErr: testdata.ErrTest, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + + storeKey := sdk.NewKVStoreKey("test") + const anyPrefix = 0x10 + tableBuilder := NewTableBuilder(anyPrefix, storeKey, &testdata.GroupInfo{}, Max255DynamicLengthIndexKeyCodec{}, cdc) + myTable := tableBuilder.Build() + + ctx := NewMockContext() + err := myTable.Create(ctx, []byte("my-id"), spec.src) + + require.True(t, spec.expErr.Is(err), err) + shouldExists := spec.expErr == nil + assert.Equal(t, shouldExists, myTable.Has(ctx, []byte("my-id")), fmt.Sprintf("expected %v", shouldExists)) + + // then + var loaded testdata.GroupInfo + err = myTable.GetOne(ctx, []byte("my-id"), &loaded) + if spec.expErr != nil { + require.True(t, ErrNotFound.Is(err)) + return + } + require.NoError(t, err) + assert.Equal(t, spec.src, &loaded) + }) + } +} + +func TestUpdate(t *testing.T) { + specs := map[string]struct { + src codec.ProtoMarshaler + expErr *errors.Error + }{ + "happy path": { + src: &testdata.TableModel{ + Id: 1, + Name: "some name", + }, + }, + "wrong type": { + src: &testdata.Cat{ + Moniker: "cat moniker", + Lives: 10, + }, + expErr: ErrType, + }, + "model validation fails": { + src: &testdata.TableModel{ + Id: 1, + Name: "", + }, + expErr: testdata.ErrTest, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + + ctx := NewMockContext() + store := ctx.KVStore(sdk.NewKVStoreKey("test")) + + const anyPrefix = 0x10 + tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, Max255DynamicLengthIndexKeyCodec{}, cdc) + myTable := tableBuilder.Build() + + initValue := testdata.TableModel{ + Id: 1, + Name: "old name", + } + + err := myTable.Create(store, []byte("1"), &initValue) + require.NoError(t, err) + + // when + err = myTable.Save(store, []byte("1"), spec.src) + require.True(t, spec.expErr.Is(err), "got ", err) + + // then + var loaded testdata.TableModel + require.NoError(t, myTable.GetOne(store, []byte("1"), &loaded)) + if spec.expErr == nil { + assert.Equal(t, spec.src, &loaded) + } else { + assert.Equal(t, initValue, loaded) + } + }) + } + +} diff --git a/store/table/testsupport.go b/store/table/testsupport.go new file mode 100644 index 000000000000..60878101f654 --- /dev/null +++ b/store/table/testsupport.go @@ -0,0 +1,32 @@ +package table + +import ( + "github.com/cosmos/cosmos-sdk/store" + "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + dbm "github.com/tendermint/tm-db" +) + +type MockContext struct { + db *dbm.MemDB + store types.CommitMultiStore +} + +func NewMockContext() *MockContext { + db := dbm.NewMemDB() + return &MockContext{ + db: dbm.NewMemDB(), + store: store.NewCommitMultiStore(db), + } +} + +func (m MockContext) KVStore(key sdk.StoreKey) sdk.KVStore { + if s := m.store.GetCommitKVStore(key); s != nil { + return s + } + m.store.MountStoreWithDB(key, sdk.StoreTypeIAVL, m.db) + if err := m.store.LoadLatestVersion(); err != nil { + panic(err) + } + return m.store.GetCommitKVStore(key) +} diff --git a/store/table/types.go b/store/table/types.go index f3e81e36c936..12415ce84118 100644 --- a/store/table/types.go +++ b/store/table/types.go @@ -54,7 +54,7 @@ type Iterator interface { io.Closer } -// IndexKeyCodec defines the encoding/ decoding methods for building/ splitting index keys. +// IndexKeyCodec defines the encoding/decoding methods for building/splitting index keys. type IndexKeyCodec interface { // BuildIndexKey encodes a searchable key and the target RowID. BuildIndexKey(searchableKey []byte, rowID RowID) []byte diff --git a/testutil/testdata/table.go b/testutil/testdata/table.go new file mode 100644 index 000000000000..592e9e88354b --- /dev/null +++ b/testutil/testdata/table.go @@ -0,0 +1,14 @@ +package testutil + +import "github.com/cosmos/cosmos-sdk/types/errors" + +var ( + ErrTest = errors.Register("table_testdata", 2, "test") +) + +func (g TableModel) ValidateBasic() error { + if g.Name == "" { + return errors.Wrap(ErrTest, "name") + } + return nil +} diff --git a/testutil/testdata/testdata.pb.go b/testutil/testdata/testdata.pb.go index 400e64936810..4894d5ec9fef 100644 --- a/testutil/testdata/testdata.pb.go +++ b/testutil/testdata/testdata.pb.go @@ -322,6 +322,58 @@ func (m *BadMultiSignature) GetMaliciousField() []byte { return nil } +type TableModel struct { + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` +} + +func (m *TableModel) Reset() { *m = TableModel{} } +func (m *TableModel) String() string { return proto.CompactTextString(m) } +func (*TableModel) ProtoMessage() {} +func (*TableModel) Descriptor() ([]byte, []int) { + return fileDescriptor_40c4782d007dfce9, []int{6} +} +func (m *TableModel) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TableModel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TableModel.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TableModel) XXX_Merge(src proto.Message) { + xxx_messageInfo_TableModel.Merge(m, src) +} +func (m *TableModel) XXX_Size() int { + return m.Size() +} +func (m *TableModel) XXX_DiscardUnknown() { + xxx_messageInfo_TableModel.DiscardUnknown(m) +} + +var xxx_messageInfo_TableModel proto.InternalMessageInfo + +func (m *TableModel) GetId() uint64 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *TableModel) GetName() string { + if m != nil { + return m.Name + } + return "" +} + func init() { proto.RegisterType((*Dog)(nil), "testdata.Dog") proto.RegisterType((*Cat)(nil), "testdata.Cat") @@ -329,35 +381,38 @@ func init() { proto.RegisterType((*HasHasAnimal)(nil), "testdata.HasHasAnimal") proto.RegisterType((*HasHasHasAnimal)(nil), "testdata.HasHasHasAnimal") proto.RegisterType((*BadMultiSignature)(nil), "testdata.BadMultiSignature") + proto.RegisterType((*TableModel)(nil), "testdata.TableModel") } func init() { proto.RegisterFile("testdata.proto", fileDescriptor_40c4782d007dfce9) } var fileDescriptor_40c4782d007dfce9 = []byte{ - // 365 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x31, 0x4f, 0xc2, 0x40, - 0x18, 0x86, 0x39, 0x0b, 0x28, 0x9f, 0x0d, 0xc4, 0x0b, 0x43, 0x65, 0xa8, 0xa4, 0x8b, 0x0c, 0xd2, - 0x26, 0x12, 0x17, 0x36, 0xc0, 0x28, 0x0b, 0x4b, 0xdd, 0x5c, 0xc8, 0x95, 0x1e, 0xed, 0x85, 0xb6, - 0x67, 0xb8, 0xab, 0x01, 0x7f, 0x85, 0x7f, 0xc1, 0x7f, 0xe3, 0xc8, 0xe8, 0x68, 0xe0, 0x8f, 0x98, - 0x5e, 0xa9, 0x30, 0x32, 0xf5, 0x7d, 0xdf, 0xaf, 0xef, 0x93, 0xef, 0x92, 0x0f, 0xea, 0x92, 0x0a, - 0xe9, 0x13, 0x49, 0xec, 0xb7, 0x25, 0x97, 0x1c, 0x5f, 0x14, 0xbe, 0xd5, 0x0c, 0x78, 0xc0, 0x55, - 0xe8, 0x64, 0x2a, 0x9f, 0xb7, 0xae, 0x03, 0xce, 0x83, 0x88, 0x3a, 0xca, 0x79, 0xe9, 0xdc, 0x21, - 0xc9, 0x3a, 0x1f, 0x59, 0x5d, 0xd0, 0x1e, 0x79, 0x80, 0x31, 0x94, 0x05, 0xfb, 0xa0, 0x06, 0x6a, - 0xa3, 0x4e, 0xcd, 0x55, 0x3a, 0xcb, 0x12, 0x12, 0x53, 0xe3, 0x2c, 0xcf, 0x32, 0x6d, 0x3d, 0x80, - 0x36, 0x22, 0x12, 0x1b, 0x70, 0x1e, 0xf3, 0x84, 0x2d, 0xe8, 0x72, 0xdf, 0x28, 0x2c, 0x6e, 0x42, - 0x25, 0x62, 0xef, 0x54, 0xa8, 0x56, 0xc5, 0xcd, 0x8d, 0xf5, 0x0c, 0xb5, 0x31, 0x11, 0x83, 0x84, - 0xc5, 0x24, 0xc2, 0x77, 0x50, 0x25, 0x4a, 0xa9, 0xee, 0xe5, 0x7d, 0xd3, 0xce, 0xd7, 0xb3, 0x8b, - 0xf5, 0xec, 0x41, 0xb2, 0x76, 0xf7, 0xff, 0x60, 0x1d, 0xd0, 0x4a, 0xc1, 0x34, 0x17, 0xad, 0xac, - 0x11, 0xe8, 0x63, 0x22, 0x0e, 0xac, 0x1e, 0x40, 0x48, 0xc4, 0xf4, 0x04, 0x5e, 0x2d, 0x2c, 0x4a, - 0xd6, 0x04, 0x1a, 0x39, 0xe4, 0xc0, 0xe9, 0x43, 0x3d, 0xe3, 0x9c, 0xc8, 0xd2, 0xc3, 0xa3, 0xae, - 0xe5, 0xc1, 0xd5, 0x90, 0xf8, 0x93, 0x34, 0x92, 0xec, 0x85, 0x05, 0x09, 0x91, 0xe9, 0x92, 0x62, - 0x13, 0x40, 0x14, 0x46, 0x18, 0xa8, 0xad, 0x75, 0x74, 0xf7, 0x28, 0xc1, 0xb7, 0xd0, 0x88, 0x49, - 0xc4, 0x66, 0x8c, 0xa7, 0x62, 0x3a, 0x67, 0x34, 0xf2, 0x8d, 0x4a, 0x1b, 0x75, 0x74, 0xb7, 0xfe, - 0x1f, 0x3f, 0x65, 0x69, 0xbf, 0xbc, 0xf9, 0xba, 0x41, 0xc3, 0xf1, 0xf7, 0xd6, 0x44, 0x9b, 0xad, - 0x89, 0x7e, 0xb7, 0x26, 0xfa, 0xdc, 0x99, 0xa5, 0xcd, 0xce, 0x2c, 0xfd, 0xec, 0xcc, 0xd2, 0xab, - 0x1d, 0x30, 0x19, 0xa6, 0x9e, 0x3d, 0xe3, 0xb1, 0x33, 0xe3, 0x22, 0xe6, 0x62, 0xff, 0xe9, 0x0a, - 0x7f, 0xe1, 0x64, 0x87, 0x91, 0x4a, 0x16, 0x39, 0xc5, 0x85, 0x78, 0x55, 0xf5, 0x92, 0xde, 0x5f, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xa3, 0x51, 0x62, 0x40, 0x44, 0x02, 0x00, 0x00, + // 393 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xb1, 0x8e, 0xda, 0x40, + 0x14, 0x45, 0x19, 0x0c, 0x24, 0xbc, 0x58, 0x46, 0x19, 0x51, 0x38, 0x14, 0x0e, 0x72, 0x13, 0x8a, + 0x60, 0x47, 0x41, 0x69, 0xe8, 0x80, 0x28, 0xa1, 0xa1, 0x71, 0x52, 0xa5, 0x41, 0x63, 0x3c, 0xd8, + 0x23, 0xc6, 0x9e, 0x88, 0x19, 0x47, 0x90, 0xaf, 0xd8, 0x5f, 0xd8, 0xbf, 0xd9, 0x92, 0x72, 0xcb, + 0x15, 0xfc, 0xc8, 0xca, 0x63, 0xbc, 0x50, 0x6c, 0x41, 0xe5, 0x7b, 0xef, 0xf3, 0x3d, 0x7a, 0x96, + 0x1f, 0x58, 0x8a, 0x4a, 0x15, 0x11, 0x45, 0xbc, 0xbf, 0x5b, 0xa1, 0x04, 0x7e, 0x5b, 0xf9, 0x5e, + 0x37, 0x16, 0xb1, 0xd0, 0xa1, 0x5f, 0xa8, 0x72, 0xde, 0xfb, 0x10, 0x0b, 0x11, 0x73, 0xea, 0x6b, + 0x17, 0xe6, 0x6b, 0x9f, 0x64, 0xfb, 0x72, 0xe4, 0x0e, 0xc1, 0xf8, 0x2e, 0x62, 0x8c, 0xa1, 0x21, + 0xd9, 0x7f, 0x6a, 0xa3, 0x3e, 0x1a, 0xb4, 0x03, 0xad, 0x8b, 0x2c, 0x23, 0x29, 0xb5, 0xeb, 0x65, + 0x56, 0x68, 0xf7, 0x1b, 0x18, 0x33, 0xa2, 0xb0, 0x0d, 0x6f, 0x52, 0x91, 0xb1, 0x0d, 0xdd, 0x9e, + 0x1b, 0x95, 0xc5, 0x5d, 0x68, 0x72, 0xf6, 0x8f, 0x4a, 0xdd, 0x6a, 0x06, 0xa5, 0x71, 0x7f, 0x42, + 0x7b, 0x4e, 0xe4, 0x24, 0x63, 0x29, 0xe1, 0xf8, 0x33, 0xb4, 0x88, 0x56, 0xba, 0xfb, 0xee, 0x6b, + 0xd7, 0x2b, 0xd7, 0xf3, 0xaa, 0xf5, 0xbc, 0x49, 0xb6, 0x0f, 0xce, 0xef, 0x60, 0x13, 0xd0, 0x4e, + 0xc3, 0x8c, 0x00, 0xed, 0xdc, 0x19, 0x98, 0x73, 0x22, 0x2f, 0xac, 0x11, 0x40, 0x42, 0xe4, 0xf2, + 0x06, 0x5e, 0x3b, 0xa9, 0x4a, 0xee, 0x02, 0x3a, 0x25, 0xe4, 0xc2, 0x19, 0x83, 0x55, 0x70, 0x6e, + 0x64, 0x99, 0xc9, 0x55, 0xd7, 0x0d, 0xe1, 0xfd, 0x94, 0x44, 0x8b, 0x9c, 0x2b, 0xf6, 0x8b, 0xc5, + 0x19, 0x51, 0xf9, 0x96, 0x62, 0x07, 0x40, 0x56, 0x46, 0xda, 0xa8, 0x6f, 0x0c, 0xcc, 0xe0, 0x2a, + 0xc1, 0x9f, 0xa0, 0x93, 0x12, 0xce, 0x56, 0x4c, 0xe4, 0x72, 0xb9, 0x66, 0x94, 0x47, 0x76, 0xb3, + 0x8f, 0x06, 0x66, 0x60, 0xbd, 0xc4, 0x3f, 0x8a, 0x74, 0xdc, 0x38, 0xdc, 0x7f, 0x44, 0xee, 0x17, + 0x80, 0xdf, 0x24, 0xe4, 0x74, 0x21, 0x22, 0xca, 0xb1, 0x05, 0x75, 0x16, 0xe9, 0x0d, 0x1b, 0x41, + 0x9d, 0x45, 0xaf, 0xfd, 0xa9, 0xe9, 0xfc, 0xe1, 0xe8, 0xa0, 0xc3, 0xd1, 0x41, 0x4f, 0x47, 0x07, + 0xdd, 0x9d, 0x9c, 0xda, 0xe1, 0xe4, 0xd4, 0x1e, 0x4f, 0x4e, 0xed, 0x8f, 0x17, 0x33, 0x95, 0xe4, + 0xa1, 0xb7, 0x12, 0xa9, 0xbf, 0x12, 0x32, 0x15, 0xf2, 0xfc, 0x18, 0xca, 0x68, 0xe3, 0x17, 0xa7, + 0x94, 0x2b, 0xc6, 0xfd, 0xea, 0xa6, 0xc2, 0x96, 0xfe, 0xf6, 0xd1, 0x73, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x7a, 0x9a, 0x17, 0x6f, 0x76, 0x02, 0x00, 0x00, } func (m *Dog) Marshal() (dAtA []byte, err error) { @@ -585,6 +640,41 @@ func (m *BadMultiSignature) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *TableModel) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TableModel) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TableModel) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintTestdata(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if m.Id != 0 { + i = encodeVarintTestdata(dAtA, i, uint64(m.Id)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintTestdata(dAtA []byte, offset int, v uint64) int { offset -= sovTestdata(v) base := offset @@ -693,6 +783,22 @@ func (m *BadMultiSignature) Size() (n int) { return n } +func (m *TableModel) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Id != 0 { + n += 1 + sovTestdata(uint64(m.Id)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovTestdata(uint64(l)) + } + return n +} + func sovTestdata(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1308,6 +1414,107 @@ func (m *BadMultiSignature) Unmarshal(dAtA []byte) error { } return nil } +func (m *TableModel) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTestdata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TableModel: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TableModel: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + m.Id = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTestdata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Id |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTestdata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTestdata + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTestdata + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTestdata(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTestdata + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTestdata(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/testutil/testdata/testdata.proto b/testutil/testdata/testdata.proto index 585c2303c139..1da9aef16e8e 100644 --- a/testutil/testdata/testdata.proto +++ b/testutil/testdata/testdata.proto @@ -35,3 +35,8 @@ message BadMultiSignature { repeated bytes signatures = 1; bytes malicious_field = 5; } + +message TableModel { + uint64 id = 1; + string name = 2; +} From 86a5ac612daf2432c57538ae991949bec8197d54 Mon Sep 17 00:00:00 2001 From: blushi Date: Thu, 22 Jul 2021 12:04:11 +0200 Subject: [PATCH 03/26] Add more tests --- store/table/index_key_codec.go | 6 +- store/table/index_test.go | 39 +++++++ store/table/iterator.go | 182 ------------------------------- store/table/table.go | 76 ------------- store/table/table_test.go | 133 ++++++++++++++++++---- store/table/types.go | 27 ++--- store/table/types_test.go | 78 +++++++++++++ testutil/testdata/table.go | 2 +- testutil/testdata/testdata.pb.go | 90 ++++++++------- testutil/testdata/testdata.proto | 2 +- 10 files changed, 297 insertions(+), 338 deletions(-) create mode 100644 store/table/index_test.go delete mode 100644 store/table/iterator.go create mode 100644 store/table/types_test.go diff --git a/store/table/index_key_codec.go b/store/table/index_key_codec.go index 95b51e2f1a52..def3ef409b87 100644 --- a/store/table/index_key_codec.go +++ b/store/table/index_key_codec.go @@ -1,8 +1,7 @@ package table // Max255DynamicLengthIndexKeyCodec works with up to 255 byte dynamic size RowIDs. -// They are encoded as `concat(searchableKey, rowID, len(rowID)[0])` and can be used -// with PrimaryKey or external Key tables for example. +// They are encoded as `concat(searchableKey, rowID, len(rowID)[0])`. type Max255DynamicLengthIndexKeyCodec struct{} // BuildIndexKey builds the index key by appending searchableKey with rowID and length int. @@ -33,8 +32,7 @@ func (Max255DynamicLengthIndexKeyCodec) StripRowID(persistentIndexKey []byte) Ro } // FixLengthIndexKeyCodec expects the RowID to always have the same length with all entries. -// They are encoded as `concat(searchableKey, rowID)` and can be used -// with AutoUint64Tables and length EncodedSeqLength for example. +// They are encoded as `concat(searchableKey, rowID)`. type FixLengthIndexKeyCodec struct { rowIDLength int } diff --git a/store/table/index_test.go b/store/table/index_test.go new file mode 100644 index 000000000000..b512fd246cc4 --- /dev/null +++ b/store/table/index_test.go @@ -0,0 +1,39 @@ +package table + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPrefixRange(t *testing.T) { + cases := map[string]struct { + src []byte + expStart []byte + expEnd []byte + expPanic bool + }{ + "normal": {src: []byte{1, 3, 4}, expStart: []byte{1, 3, 4}, expEnd: []byte{1, 3, 5}}, + "normal short": {src: []byte{79}, expStart: []byte{79}, expEnd: []byte{80}}, + "empty case": {src: []byte{}}, + "roll-over example 1": {src: []byte{17, 28, 255}, expStart: []byte{17, 28, 255}, expEnd: []byte{17, 29, 0}}, + "roll-over example 2": {src: []byte{15, 42, 255, 255}, expStart: []byte{15, 42, 255, 255}, expEnd: []byte{15, 43, 0, 0}}, + "pathological roll-over": {src: []byte{255, 255, 255, 255}, expStart: []byte{255, 255, 255, 255}}, + "nil prohibited": {expPanic: true}, + } + + for testName, tc := range cases { + t.Run(testName, func(t *testing.T) { + if tc.expPanic { + require.Panics(t, func() { + PrefixRange(tc.src) + }) + return + } + start, end := PrefixRange(tc.src) + assert.Equal(t, tc.expStart, start) + assert.Equal(t, tc.expEnd, end) + }) + } +} diff --git a/store/table/iterator.go b/store/table/iterator.go deleted file mode 100644 index 681a3c3379be..000000000000 --- a/store/table/iterator.go +++ /dev/null @@ -1,182 +0,0 @@ -package table - -import ( - "reflect" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/types/errors" -) - -// IteratorFunc is a function type that satisfies the Iterator interface -// The passed function is called on LoadNext operations. -type IteratorFunc func(dest codec.ProtoMarshaler) (RowID, error) - -// LoadNext loads the next value in the sequence into the pointer passed as dest and returns the key. If there -// are no more items the ErrIteratorDone error is returned -// The key is the rowID and not any MultiKeyIndex key. -func (i IteratorFunc) LoadNext(dest codec.ProtoMarshaler) (RowID, error) { - return i(dest) -} - -// Close always returns nil -func (i IteratorFunc) Close() error { - return nil -} - -func NewSingleValueIterator(rowID RowID, val []byte) Iterator { - var closed bool - return IteratorFunc(func(dest codec.ProtoMarshaler) (RowID, error) { - if dest == nil { - return nil, errors.Wrap(ErrArgument, "destination object must not be nil") - } - if closed || val == nil { - return nil, ErrIteratorDone - } - closed = true - return rowID, dest.Unmarshal(val) - }) -} - -// Iterator that return ErrIteratorInvalid only. -func NewInvalidIterator() Iterator { - return IteratorFunc(func(dest codec.ProtoMarshaler) (RowID, error) { - return nil, ErrIteratorInvalid - }) -} - -// LimitedIterator returns up to defined maximum number of elements. -type LimitedIterator struct { - remainingCount int - parentIterator Iterator -} - -// LimitIterator returns a new iterator that returns max number of elements. -// The parent iterator must not be nil -// max can be 0 or any positive number -func LimitIterator(parent Iterator, max int) *LimitedIterator { - if max < 0 { - panic("quantity must not be negative") - } - if parent == nil { - panic("parent iterator must not be nil") - } - return &LimitedIterator{remainingCount: max, parentIterator: parent} -} - -// LoadNext loads the next value in the sequence into the pointer passed as dest and returns the key. If there -// are no more items or the defined max number of elements was returned the `ErrIteratorDone` error is returned -// The key is the rowID and not any MultiKeyIndex key. -func (i *LimitedIterator) LoadNext(dest codec.ProtoMarshaler) (RowID, error) { - if i.remainingCount == 0 { - return nil, ErrIteratorDone - } - i.remainingCount-- - return i.parentIterator.LoadNext(dest) -} - -// Close releases the iterator and should be called at the end of iteration -func (i LimitedIterator) Close() error { - return i.parentIterator.Close() -} - -// First loads the first element into the given destination type and closes the iterator. -// When the iterator is closed or has no elements the according error is passed as return value. -func First(it Iterator, dest codec.ProtoMarshaler) (RowID, error) { - if it == nil { - return nil, errors.Wrap(ErrArgument, "iterator must not be nil") - } - defer it.Close() - binKey, err := it.LoadNext(dest) - if err != nil { - return nil, err - } - return binKey, nil -} - -// ModelSlicePtr represents a pointer to a slice of models. Think of it as -// *[]Model Because of Go's type system, using []Model type would not work for us. -// Instead we use a placeholder type and the validation is done during the -// runtime. -type ModelSlicePtr interface{} - -// ReadAll consumes all values for the iterator and stores them in a new slice at the passed ModelSlicePtr. -// The slice can be empty when the iterator does not return any values but not nil. The iterator -// is closed afterwards. -// Example: -// var loaded []testdata.GroupInfo -// rowIDs, err := ReadAll(it, &loaded) -// require.NoError(t, err) -// -func ReadAll(it Iterator, dest ModelSlicePtr) ([]RowID, error) { - if it == nil { - return nil, errors.Wrap(ErrArgument, "iterator must not be nil") - } - defer it.Close() - - var destRef, tmpSlice reflect.Value - elemType, err := assertDest(dest, &destRef, &tmpSlice) - if err != nil { - return nil, err - } - - var rowIDs []RowID - for { - obj := reflect.New(elemType) - val := obj.Elem() - model := obj - if elemType.Kind() == reflect.Ptr { - val.Set(reflect.New(elemType.Elem())) - model = val - } - - binKey, err := it.LoadNext(model.Interface().(codec.ProtoMarshaler)) - switch { - case err == nil: - tmpSlice = reflect.Append(tmpSlice, val) - case ErrIteratorDone.Is(err): - destRef.Set(tmpSlice) - return rowIDs, nil - default: - return nil, err - } - rowIDs = append(rowIDs, binKey) - } -} - -// assertDest checks that the provided dest is not nil and a pointer to a slice. -// It also verifies that the slice elements implement *codec.ProtoMarshaler. -// It overwrites destRef and tmpSlice using reflection. -func assertDest(dest ModelSlicePtr, destRef *reflect.Value, tmpSlice *reflect.Value) (reflect.Type, error) { - if dest == nil { - return nil, errors.Wrap(ErrArgument, "destination must not be nil") - } - tp := reflect.ValueOf(dest) - if tp.Kind() != reflect.Ptr { - return nil, errors.Wrap(ErrArgument, "destination must be a pointer to a slice") - } - if tp.Elem().Kind() != reflect.Slice { - return nil, errors.Wrap(ErrArgument, "destination must point to a slice") - } - - // Since dest is just an interface{}, we overwrite destRef using reflection - // to have an assignable copy of it. - *destRef = tp.Elem() - // We need to verify that we can call Set() on destRef. - if !destRef.CanSet() { - return nil, errors.Wrap(ErrArgument, "destination not assignable") - } - - elemType := reflect.TypeOf(dest).Elem().Elem() - - protoMarshaler := reflect.TypeOf((*codec.ProtoMarshaler)(nil)).Elem() - if !elemType.Implements(protoMarshaler) && - !reflect.PtrTo(elemType).Implements(protoMarshaler) { - return nil, errors.Wrapf(ErrArgument, "unsupported type :%s", elemType) - } - - // tmpSlice is a slice value for the specified type - // that we'll use for appending new elements. - *tmpSlice = reflect.MakeSlice(reflect.SliceOf(elemType), 0, 0) - - return elemType, nil -} diff --git a/store/table/table.go b/store/table/table.go index 66635d4638e0..1f536fe7904a 100644 --- a/store/table/table.go +++ b/store/table/table.go @@ -1,12 +1,10 @@ package table import ( - "bytes" "reflect" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" - "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -72,8 +70,6 @@ func (a *TableBuilder) AddAfterDeleteInterceptor(interceptor AfterDeleteIntercep a.afterDelete = append(a.afterDelete, interceptor) } -// var _ TableExportable = &Table{} - // Table is the high level object to storage mapper functionality. Persistent entities are stored by an unique identifier // called `RowID`. // The Table struct does not enforce uniqueness of the `RowID` but expects this to be satisfied by the callers and conditions @@ -191,75 +187,3 @@ func (a Table) GetOne(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) x := NewTypeSafeRowGetter(a.prefix, a.model, a.cdc) return x(store, rowID, dest) } - -// PrefixScan returns an Iterator over a domain of keys in ascending order. End is exclusive. -// Start is an MultiKeyIndex key or prefix. It must be less than end, or the Iterator is invalid. -// Iterator must be closed by caller. -// To iterate over entire domain, use PrefixScan(nil, nil) -// -// WARNING: The use of a PrefixScan can be very expensive in terms of Gas. Please make sure you do not expose -// this as an endpoint to the public without further limits. -// Example: -// it, err := idx.PrefixScan(ctx, start, end) -// if err !=nil { -// return err -// } -// const defaultLimit = 20 -// it = LimitIterator(it, defaultLimit) -// -// CONTRACT: No writes may happen within a domain while an iterator exists over it. -func (a Table) PrefixScan(store sdk.KVStore, start, end RowID) (Iterator, error) { - if start != nil && end != nil && bytes.Compare(start, end) >= 0 { - return NewInvalidIterator(), errors.Wrap(ErrArgument, "start must be before end") - } - pStore := prefix.NewStore(store, []byte{a.prefix}) - return &typeSafeIterator{ - rowGetter: NewTypeSafeRowGetter(a.prefix, a.model, a.cdc), - it: pStore.Iterator(start, end), - }, nil -} - -// ReversePrefixScan returns an Iterator over a domain of keys in descending order. End is exclusive. -// Start is an MultiKeyIndex key or prefix. It must be less than end, or the Iterator is invalid and error is returned. -// Iterator must be closed by caller. -// To iterate over entire domain, use PrefixScan(nil, nil) -// -// WARNING: The use of a ReversePrefixScan can be very expensive in terms of Gas. Please make sure you do not expose -// this as an endpoint to the public without further limits. See `LimitIterator` -// -// CONTRACT: No writes may happen within a domain while an iterator exists over it. -func (a Table) ReversePrefixScan(store sdk.KVStore, start, end RowID) (Iterator, error) { - if start != nil && end != nil && bytes.Compare(start, end) >= 0 { - return NewInvalidIterator(), errors.Wrap(ErrArgument, "start must be before end") - } - pStore := prefix.NewStore(store, []byte{a.prefix}) - return &typeSafeIterator{ - rowGetter: NewTypeSafeRowGetter(a.prefix, a.model, a.cdc), - it: pStore.ReverseIterator(start, end), - }, nil -} - -func (a Table) Table() Table { - return a -} - -// typeSafeIterator is initialized with a type safe RowGetter only. -type typeSafeIterator struct { - store sdk.KVStore - rowGetter RowGetter - it types.Iterator -} - -func (i typeSafeIterator) LoadNext(dest codec.ProtoMarshaler) (RowID, error) { - if !i.it.Valid() { - return nil, ErrIteratorDone - } - rowID := i.it.Key() - i.it.Next() - return rowID, i.rowGetter(i.store, rowID, dest) -} - -func (i typeSafeIterator) Close() error { - i.it.Close() - return nil -} diff --git a/store/table/table_test.go b/store/table/table_test.go index 1411d6353213..fff399189ef8 100644 --- a/store/table/table_test.go +++ b/store/table/table_test.go @@ -13,27 +13,67 @@ import ( "github.com/stretchr/testify/require" ) +func TestNewTableBuilder(t *testing.T) { + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + const anyPrefix = 0x10 + + specs := map[string]struct { + model codec.ProtoMarshaler + idxKeyCodec IndexKeyCodec + expPanic bool + }{ + "happy path": { + model: &testdata.TableModel{}, + idxKeyCodec: Max255DynamicLengthIndexKeyCodec{}, + }, + "nil model": { + idxKeyCodec: Max255DynamicLengthIndexKeyCodec{}, + expPanic: true, + }, + "nil idxKeyCodec": { + model: &testdata.TableModel{}, + expPanic: true, + }, + } + + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + f := func() { + NewTableBuilder(anyPrefix, spec.model, spec.idxKeyCodec, cdc) + } + if spec.expPanic { + require.Panics(t, f) + } else { + require.NotPanics(t, f) + } + }) + } +} + func TestCreate(t *testing.T) { specs := map[string]struct { src codec.ProtoMarshaler expErr *errors.Error }{ "happy path": { - src: &testdata.GroupInfo{ - Description: "my group", - Admin: sdk.AccAddress([]byte("my-admin-address")), + src: &testdata.TableModel{ + Id: "my-id", + Name: "some name", }, }, "wrong type": { - src: &testdata.GroupMember{ - Group: sdk.AccAddress(EncodeSequence(1)), - Member: sdk.AccAddress([]byte("member-address")), - Weight: 10, + src: &testdata.Cat{ + Moniker: "cat moniker", + Lives: 10, }, expErr: ErrType, }, "model validation fails": { - src: &testdata.GroupInfo{Description: "invalid"}, + src: &testdata.TableModel{ + Id: "my-id", + Name: "", + }, expErr: testdata.ErrTest, }, } @@ -42,21 +82,22 @@ func TestCreate(t *testing.T) { interfaceRegistry := types.NewInterfaceRegistry() cdc := codec.NewProtoCodec(interfaceRegistry) - storeKey := sdk.NewKVStoreKey("test") + ctx := NewMockContext() + store := ctx.KVStore(sdk.NewKVStoreKey("test")) + const anyPrefix = 0x10 - tableBuilder := NewTableBuilder(anyPrefix, storeKey, &testdata.GroupInfo{}, Max255DynamicLengthIndexKeyCodec{}, cdc) + tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, Max255DynamicLengthIndexKeyCodec{}, cdc) myTable := tableBuilder.Build() - ctx := NewMockContext() - err := myTable.Create(ctx, []byte("my-id"), spec.src) + err := myTable.Create(store, []byte("my-id"), spec.src) require.True(t, spec.expErr.Is(err), err) shouldExists := spec.expErr == nil - assert.Equal(t, shouldExists, myTable.Has(ctx, []byte("my-id")), fmt.Sprintf("expected %v", shouldExists)) + assert.Equal(t, shouldExists, myTable.Has(store, []byte("my-id")), fmt.Sprintf("expected %v", shouldExists)) // then - var loaded testdata.GroupInfo - err = myTable.GetOne(ctx, []byte("my-id"), &loaded) + var loaded testdata.TableModel + err = myTable.GetOne(store, []byte("my-id"), &loaded) if spec.expErr != nil { require.True(t, ErrNotFound.Is(err)) return @@ -74,7 +115,7 @@ func TestUpdate(t *testing.T) { }{ "happy path": { src: &testdata.TableModel{ - Id: 1, + Id: "my-id", Name: "some name", }, }, @@ -87,7 +128,7 @@ func TestUpdate(t *testing.T) { }, "model validation fails": { src: &testdata.TableModel{ - Id: 1, + Id: "my-id", Name: "", }, expErr: testdata.ErrTest, @@ -106,20 +147,20 @@ func TestUpdate(t *testing.T) { myTable := tableBuilder.Build() initValue := testdata.TableModel{ - Id: 1, + Id: "my-id", Name: "old name", } - err := myTable.Create(store, []byte("1"), &initValue) + err := myTable.Create(store, []byte("my-id"), &initValue) require.NoError(t, err) // when - err = myTable.Save(store, []byte("1"), spec.src) + err = myTable.Save(store, []byte("my-id"), spec.src) require.True(t, spec.expErr.Is(err), "got ", err) // then var loaded testdata.TableModel - require.NoError(t, myTable.GetOne(store, []byte("1"), &loaded)) + require.NoError(t, myTable.GetOne(store, []byte("my-id"), &loaded)) if spec.expErr == nil { assert.Equal(t, spec.src, &loaded) } else { @@ -127,5 +168,55 @@ func TestUpdate(t *testing.T) { } }) } +} + +func TestDelete(t *testing.T) { + specs := map[string]struct { + rowId []byte + expErr *errors.Error + }{ + "happy path": { + rowId: []byte("my-id"), + }, + "not found": { + rowId: []byte("not-found"), + expErr: ErrNotFound, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + + ctx := NewMockContext() + store := ctx.KVStore(sdk.NewKVStoreKey("test")) + + const anyPrefix = 0x10 + tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, Max255DynamicLengthIndexKeyCodec{}, cdc) + myTable := tableBuilder.Build() + + initValue := testdata.TableModel{ + Id: "my-id", + Name: "some name", + } + err := myTable.Create(store, []byte("my-id"), &initValue) + require.NoError(t, err) + + // when + err = myTable.Delete(store, spec.rowId) + require.True(t, spec.expErr.Is(err), "got ", err) + + // then + var loaded testdata.TableModel + if spec.expErr == ErrNotFound { + require.NoError(t, myTable.GetOne(store, []byte("my-id"), &loaded)) + assert.Equal(t, initValue, loaded) + } else { + err := myTable.GetOne(store, []byte("my-id"), &loaded) + require.Error(t, err) + require.Equal(t, err, ErrNotFound) + } + }) + } } diff --git a/store/table/types.go b/store/table/types.go index 12415ce84118..01496e764566 100644 --- a/store/table/types.go +++ b/store/table/types.go @@ -1,5 +1,5 @@ /* -Package orm is a convenient object to data store mapper. +Package store/table is a convenient object to data store mapper. */ package table @@ -13,23 +13,18 @@ import ( "github.com/cosmos/cosmos-sdk/types/errors" ) -const ormCodespace = "orm" +const tableCodespace = "table" var ( - ErrNotFound = errors.Register(ormCodespace, 100, "not found") - ErrIteratorDone = errors.Register(ormCodespace, 101, "iterator done") - ErrIteratorInvalid = errors.Register(ormCodespace, 102, "iterator invalid") - ErrType = errors.Register(ormCodespace, 110, "invalid type") - ErrUniqueConstraint = errors.Register(ormCodespace, 111, "unique constraint violation") - ErrArgument = errors.Register(ormCodespace, 112, "invalid argument") - ErrIndexKeyMaxLength = errors.Register(ormCodespace, 113, "index key exceeds max length") + ErrNotFound = errors.Register(tableCodespace, 100, "not found") + ErrIteratorDone = errors.Register(tableCodespace, 101, "iterator done") + ErrIteratorInvalid = errors.Register(tableCodespace, 102, "iterator invalid") + ErrType = errors.Register(tableCodespace, 110, "invalid type") + ErrUniqueConstraint = errors.Register(tableCodespace, 111, "unique constraint violation") + ErrArgument = errors.Register(tableCodespace, 112, "invalid argument") + ErrIndexKeyMaxLength = errors.Register(tableCodespace, 113, "index key exceeds max length") ) -// HasKVStore is a subset of the cosmos-sdk context defined for loose coupling and simpler test setups. -type HasKVStore interface { - KVStore(key sdk.StoreKey) sdk.KVStore -} - // Unique identifier of a persistent table. type RowID []byte @@ -38,7 +33,7 @@ func (r RowID) Bytes() []byte { return r } -// Validateable is an interface that Persistent types can implement and is called on any orm save or update operation. +// Validateable is an interface that ProtoMarshaler types can implement and is called on any orm save or update operation. type Validateable interface { // ValidateBasic is a sanity check on the data. Any error returned prevents create or updates. ValidateBasic() error @@ -48,7 +43,7 @@ type Validateable interface { type Iterator interface { // LoadNext loads the next value in the sequence into the pointer passed as dest and returns the key. If there // are no more items the ErrIteratorDone error is returned - // The key is the rowID and not any MultiKeyIndex key. + // The key is the rowID. LoadNext(dest codec.ProtoMarshaler) (RowID, error) // Close releases the iterator and should be called at the end of iteration io.Closer diff --git a/store/table/types_test.go b/store/table/types_test.go new file mode 100644 index 000000000000..6d31e584e52f --- /dev/null +++ b/store/table/types_test.go @@ -0,0 +1,78 @@ +package table + +import ( + "reflect" + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/store/prefix" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTypeSafeRowGetter(t *testing.T) { + storeKey := sdk.NewKVStoreKey("test") + ctx := NewMockContext() + const prefixKey = 0x2 + store := prefix.NewStore(ctx.KVStore(storeKey), []byte{prefixKey}) + md := testdata.TableModel{ + Id: "my-id", + Name: "some name", + } + bz, err := md.Marshal() + require.NoError(t, err) + store.Set([]byte("my-id"), bz) + + specs := map[string]struct { + srcRowID RowID + srcModelType reflect.Type + expObj interface{} + expErr *errors.Error + }{ + "happy path": { + srcRowID: []byte("my-id"), + srcModelType: reflect.TypeOf(testdata.TableModel{}), + expObj: md, + }, + "unknown rowID should return ErrNotFound": { + srcRowID: []byte("unknown"), + srcModelType: reflect.TypeOf(testdata.TableModel{}), + expErr: ErrNotFound, + }, + "wrong type should cause ErrType": { + srcRowID: []byte("my-id"), + srcModelType: reflect.TypeOf(testdata.Cat{}), + expErr: ErrType, + }, + "empty rowID not allowed": { + srcRowID: []byte{}, + srcModelType: reflect.TypeOf(testdata.TableModel{}), + expErr: ErrArgument, + }, + "nil rowID not allowed": { + srcModelType: reflect.TypeOf(testdata.TableModel{}), + expErr: ErrArgument, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + + getter := NewTypeSafeRowGetter(prefixKey, spec.srcModelType, cdc) + var loadedObj testdata.TableModel + + err := getter(ctx.KVStore(storeKey), spec.srcRowID, &loadedObj) + if spec.expErr != nil { + require.True(t, spec.expErr.Is(err), err) + return + } + require.NoError(t, err) + assert.Equal(t, spec.expObj, loadedObj) + }) + } +} diff --git a/testutil/testdata/table.go b/testutil/testdata/table.go index 592e9e88354b..576b911f3f0d 100644 --- a/testutil/testdata/table.go +++ b/testutil/testdata/table.go @@ -1,4 +1,4 @@ -package testutil +package testdata import "github.com/cosmos/cosmos-sdk/types/errors" diff --git a/testutil/testdata/testdata.pb.go b/testutil/testdata/testdata.pb.go index 4894d5ec9fef..d21261462669 100644 --- a/testutil/testdata/testdata.pb.go +++ b/testutil/testdata/testdata.pb.go @@ -323,7 +323,7 @@ func (m *BadMultiSignature) GetMaliciousField() []byte { } type TableModel struct { - Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` } @@ -360,11 +360,11 @@ func (m *TableModel) XXX_DiscardUnknown() { var xxx_messageInfo_TableModel proto.InternalMessageInfo -func (m *TableModel) GetId() uint64 { +func (m *TableModel) GetId() string { if m != nil { return m.Id } - return 0 + return "" } func (m *TableModel) GetName() string { @@ -387,32 +387,32 @@ func init() { func init() { proto.RegisterFile("testdata.proto", fileDescriptor_40c4782d007dfce9) } var fileDescriptor_40c4782d007dfce9 = []byte{ - // 393 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xb1, 0x8e, 0xda, 0x40, - 0x14, 0x45, 0x19, 0x0c, 0x24, 0xbc, 0x58, 0x46, 0x19, 0x51, 0x38, 0x14, 0x0e, 0x72, 0x13, 0x8a, - 0x60, 0x47, 0x41, 0x69, 0xe8, 0x80, 0x28, 0xa1, 0xa1, 0x71, 0x52, 0xa5, 0x41, 0x63, 0x3c, 0xd8, - 0x23, 0xc6, 0x9e, 0x88, 0x19, 0x47, 0x90, 0xaf, 0xd8, 0x5f, 0xd8, 0xbf, 0xd9, 0x92, 0x72, 0xcb, - 0x15, 0xfc, 0xc8, 0xca, 0x63, 0xbc, 0x50, 0x6c, 0x41, 0xe5, 0x7b, 0xef, 0xf3, 0x3d, 0x7a, 0x96, - 0x1f, 0x58, 0x8a, 0x4a, 0x15, 0x11, 0x45, 0xbc, 0xbf, 0x5b, 0xa1, 0x04, 0x7e, 0x5b, 0xf9, 0x5e, - 0x37, 0x16, 0xb1, 0xd0, 0xa1, 0x5f, 0xa8, 0x72, 0xde, 0xfb, 0x10, 0x0b, 0x11, 0x73, 0xea, 0x6b, - 0x17, 0xe6, 0x6b, 0x9f, 0x64, 0xfb, 0x72, 0xe4, 0x0e, 0xc1, 0xf8, 0x2e, 0x62, 0x8c, 0xa1, 0x21, - 0xd9, 0x7f, 0x6a, 0xa3, 0x3e, 0x1a, 0xb4, 0x03, 0xad, 0x8b, 0x2c, 0x23, 0x29, 0xb5, 0xeb, 0x65, - 0x56, 0x68, 0xf7, 0x1b, 0x18, 0x33, 0xa2, 0xb0, 0x0d, 0x6f, 0x52, 0x91, 0xb1, 0x0d, 0xdd, 0x9e, - 0x1b, 0x95, 0xc5, 0x5d, 0x68, 0x72, 0xf6, 0x8f, 0x4a, 0xdd, 0x6a, 0x06, 0xa5, 0x71, 0x7f, 0x42, - 0x7b, 0x4e, 0xe4, 0x24, 0x63, 0x29, 0xe1, 0xf8, 0x33, 0xb4, 0x88, 0x56, 0xba, 0xfb, 0xee, 0x6b, - 0xd7, 0x2b, 0xd7, 0xf3, 0xaa, 0xf5, 0xbc, 0x49, 0xb6, 0x0f, 0xce, 0xef, 0x60, 0x13, 0xd0, 0x4e, - 0xc3, 0x8c, 0x00, 0xed, 0xdc, 0x19, 0x98, 0x73, 0x22, 0x2f, 0xac, 0x11, 0x40, 0x42, 0xe4, 0xf2, - 0x06, 0x5e, 0x3b, 0xa9, 0x4a, 0xee, 0x02, 0x3a, 0x25, 0xe4, 0xc2, 0x19, 0x83, 0x55, 0x70, 0x6e, - 0x64, 0x99, 0xc9, 0x55, 0xd7, 0x0d, 0xe1, 0xfd, 0x94, 0x44, 0x8b, 0x9c, 0x2b, 0xf6, 0x8b, 0xc5, - 0x19, 0x51, 0xf9, 0x96, 0x62, 0x07, 0x40, 0x56, 0x46, 0xda, 0xa8, 0x6f, 0x0c, 0xcc, 0xe0, 0x2a, - 0xc1, 0x9f, 0xa0, 0x93, 0x12, 0xce, 0x56, 0x4c, 0xe4, 0x72, 0xb9, 0x66, 0x94, 0x47, 0x76, 0xb3, - 0x8f, 0x06, 0x66, 0x60, 0xbd, 0xc4, 0x3f, 0x8a, 0x74, 0xdc, 0x38, 0xdc, 0x7f, 0x44, 0xee, 0x17, - 0x80, 0xdf, 0x24, 0xe4, 0x74, 0x21, 0x22, 0xca, 0xb1, 0x05, 0x75, 0x16, 0xe9, 0x0d, 0x1b, 0x41, - 0x9d, 0x45, 0xaf, 0xfd, 0xa9, 0xe9, 0xfc, 0xe1, 0xe8, 0xa0, 0xc3, 0xd1, 0x41, 0x4f, 0x47, 0x07, - 0xdd, 0x9d, 0x9c, 0xda, 0xe1, 0xe4, 0xd4, 0x1e, 0x4f, 0x4e, 0xed, 0x8f, 0x17, 0x33, 0x95, 0xe4, - 0xa1, 0xb7, 0x12, 0xa9, 0xbf, 0x12, 0x32, 0x15, 0xf2, 0xfc, 0x18, 0xca, 0x68, 0xe3, 0x17, 0xa7, - 0x94, 0x2b, 0xc6, 0xfd, 0xea, 0xa6, 0xc2, 0x96, 0xfe, 0xf6, 0xd1, 0x73, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x7a, 0x9a, 0x17, 0x6f, 0x76, 0x02, 0x00, 0x00, + // 391 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xb1, 0xae, 0xda, 0x30, + 0x18, 0x85, 0x31, 0x01, 0x5a, 0xfe, 0x46, 0x41, 0xb5, 0x18, 0x52, 0x86, 0x14, 0x65, 0x29, 0x43, + 0x49, 0xaa, 0xa2, 0x2e, 0x6c, 0x40, 0xd5, 0xb2, 0xb0, 0xa4, 0x9d, 0xba, 0x20, 0x87, 0x98, 0xc4, + 0xc2, 0x89, 0x2b, 0xec, 0x54, 0xd0, 0xa7, 0xe8, 0x2b, 0xf4, 0x6d, 0x3a, 0x32, 0x76, 0xbc, 0x82, + 0x17, 0xb9, 0x8a, 0x93, 0x5c, 0x18, 0xee, 0xc0, 0x94, 0x73, 0x8e, 0x73, 0x3e, 0xfd, 0x89, 0x7f, + 0xb0, 0x14, 0x95, 0x2a, 0x22, 0x8a, 0x78, 0x3f, 0xf7, 0x42, 0x09, 0xfc, 0xb2, 0xf6, 0x83, 0x7e, + 0x2c, 0x62, 0xa1, 0x43, 0xbf, 0x50, 0xe5, 0xf9, 0xe0, 0x4d, 0x2c, 0x44, 0xcc, 0xa9, 0xaf, 0x5d, + 0x98, 0x6f, 0x7d, 0x92, 0x1d, 0xcb, 0x23, 0x77, 0x0c, 0xc6, 0x67, 0x11, 0x63, 0x0c, 0x2d, 0xc9, + 0x7e, 0x53, 0x1b, 0x0d, 0xd1, 0xa8, 0x1b, 0x68, 0x5d, 0x64, 0x19, 0x49, 0xa9, 0xdd, 0x2c, 0xb3, + 0x42, 0xbb, 0x9f, 0xc0, 0x58, 0x10, 0x85, 0x6d, 0x78, 0x91, 0x8a, 0x8c, 0xed, 0xe8, 0xbe, 0x6a, + 0xd4, 0x16, 0xf7, 0xa1, 0xcd, 0xd9, 0x2f, 0x2a, 0x75, 0xab, 0x1d, 0x94, 0xc6, 0xfd, 0x0a, 0xdd, + 0x25, 0x91, 0xb3, 0x8c, 0xa5, 0x84, 0xe3, 0xf7, 0xd0, 0x21, 0x5a, 0xe9, 0xee, 0xab, 0x8f, 0x7d, + 0xaf, 0x1c, 0xcf, 0xab, 0xc7, 0xf3, 0x66, 0xd9, 0x31, 0xa8, 0xde, 0xc1, 0x26, 0xa0, 0x83, 0x86, + 0x19, 0x01, 0x3a, 0xb8, 0x0b, 0x30, 0x97, 0x44, 0x5e, 0x59, 0x13, 0x80, 0x84, 0xc8, 0xf5, 0x1d, + 0xbc, 0x6e, 0x52, 0x97, 0xdc, 0x15, 0xf4, 0x4a, 0xc8, 0x95, 0x33, 0x05, 0xab, 0xe0, 0xdc, 0xc9, + 0x32, 0x93, 0x9b, 0xae, 0x1b, 0xc2, 0xeb, 0x39, 0x89, 0x56, 0x39, 0x57, 0xec, 0x1b, 0x8b, 0x33, + 0xa2, 0xf2, 0x3d, 0xc5, 0x0e, 0x80, 0xac, 0x8d, 0xb4, 0xd1, 0xd0, 0x18, 0x99, 0xc1, 0x4d, 0x82, + 0xdf, 0x41, 0x2f, 0x25, 0x9c, 0x6d, 0x98, 0xc8, 0xe5, 0x7a, 0xcb, 0x28, 0x8f, 0xec, 0xf6, 0x10, + 0x8d, 0xcc, 0xc0, 0x7a, 0x8a, 0xbf, 0x14, 0xe9, 0xb4, 0x75, 0xfa, 0xfb, 0x16, 0xb9, 0x1f, 0x00, + 0xbe, 0x93, 0x90, 0xd3, 0x95, 0x88, 0x28, 0xc7, 0x16, 0x34, 0x59, 0x54, 0xfd, 0xf9, 0x26, 0x8b, + 0x9e, 0xbb, 0xa9, 0xf9, 0xf2, 0xdf, 0xd9, 0x41, 0xa7, 0xb3, 0x83, 0x1e, 0xce, 0x0e, 0xfa, 0x73, + 0x71, 0x1a, 0xa7, 0x8b, 0xd3, 0xf8, 0x7f, 0x71, 0x1a, 0x3f, 0xbc, 0x98, 0xa9, 0x24, 0x0f, 0xbd, + 0x8d, 0x48, 0xfd, 0x8d, 0x90, 0xa9, 0x90, 0xd5, 0x63, 0x2c, 0xa3, 0x9d, 0x5f, 0xac, 0x52, 0xae, + 0x18, 0xf7, 0xeb, 0x9d, 0x0a, 0x3b, 0xfa, 0xdb, 0x27, 0x8f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xfa, + 0xe5, 0x40, 0xb7, 0x76, 0x02, 0x00, 0x00, } func (m *Dog) Marshal() (dAtA []byte, err error) { @@ -667,10 +667,12 @@ func (m *TableModel) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if m.Id != 0 { - i = encodeVarintTestdata(dAtA, i, uint64(m.Id)) + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = encodeVarintTestdata(dAtA, i, uint64(len(m.Id))) i-- - dAtA[i] = 0x8 + dAtA[i] = 0xa } return len(dAtA) - i, nil } @@ -789,8 +791,9 @@ func (m *TableModel) Size() (n int) { } var l int _ = l - if m.Id != 0 { - n += 1 + sovTestdata(uint64(m.Id)) + l = len(m.Id) + if l > 0 { + n += 1 + l + sovTestdata(uint64(l)) } l = len(m.Name) if l > 0 { @@ -1444,10 +1447,10 @@ func (m *TableModel) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 0 { + if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) } - m.Id = 0 + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTestdata @@ -1457,11 +1460,24 @@ func (m *TableModel) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Id |= uint64(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTestdata + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTestdata + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) diff --git a/testutil/testdata/testdata.proto b/testutil/testdata/testdata.proto index 1da9aef16e8e..1f14edcb37c0 100644 --- a/testutil/testdata/testdata.proto +++ b/testutil/testdata/testdata.proto @@ -37,6 +37,6 @@ message BadMultiSignature { } message TableModel { - uint64 id = 1; + string id = 1; string name = 2; } From 580c41b4d9a4eaf5525d14645279fb3cbf6a83a8 Mon Sep 17 00:00:00 2001 From: blushi Date: Thu, 22 Jul 2021 12:57:44 +0200 Subject: [PATCH 04/26] Add sequence --- store/table/sequence.go | 81 ++++++++++++++++++++++++++++++++++++ store/table/sequence_test.go | 25 +++++++++++ store/table/table.go | 2 +- 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 store/table/sequence.go create mode 100644 store/table/sequence_test.go diff --git a/store/table/sequence.go b/store/table/sequence.go new file mode 100644 index 000000000000..80129e766d10 --- /dev/null +++ b/store/table/sequence.go @@ -0,0 +1,81 @@ +package table + +import ( + "encoding/binary" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/errors" +) + +// sequenceStorageKey is a fix key to read/ write data on the storage layer +var sequenceStorageKey = []byte{0x1} + +// sequence is a persistent unique key generator based on a counter. +type Sequence struct { + prefix byte +} + +func NewSequence(prefix byte) Sequence { + return Sequence{ + prefix: prefix, + } +} + +// NextVal increments and persists the counter by one and returns the value. +func (s Sequence) NextVal(store sdk.KVStore) uint64 { + pStore := prefix.NewStore(store, []byte{s.prefix}) + v := pStore.Get(sequenceStorageKey) + seq := DecodeSequence(v) + seq++ + pStore.Set(sequenceStorageKey, EncodeSequence(seq)) + return seq +} + +// CurVal returns the last value used. 0 if none. +func (s Sequence) CurVal(store sdk.KVStore) uint64 { + pStore := prefix.NewStore(store, []byte{s.prefix}) + v := pStore.Get(sequenceStorageKey) + return DecodeSequence(v) +} + +// PeekNextVal returns the CurVal + increment step. Not persistent. +func (s Sequence) PeekNextVal(store sdk.KVStore) uint64 { + pStore := prefix.NewStore(store, []byte{s.prefix}) + v := pStore.Get(sequenceStorageKey) + return DecodeSequence(v) + 1 +} + +// InitVal sets the start value for the sequence. It must be called only once on an empty DB. +// Otherwise an error is returned when the key exists. The given start value is stored as current +// value. +// +// It is recommended to call this method only for a sequence start value other than `1` as the +// method consumes unnecessary gas otherwise. A scenario would be an import from genesis. +func (s Sequence) InitVal(store sdk.KVStore, seq uint64) error { + pStore := prefix.NewStore(store, []byte{s.prefix}) + if pStore.Has(sequenceStorageKey) { + return errors.Wrap(ErrUniqueConstraint, "already initialized") + } + pStore.Set(sequenceStorageKey, EncodeSequence(seq)) + return nil +} + +// DecodeSequence converts the binary representation into an Uint64 value. +func DecodeSequence(bz []byte) uint64 { + if bz == nil { + return 0 + } + val := binary.BigEndian.Uint64(bz) + return val +} + +// EncodedSeqLength number of bytes used for the binary representation of a sequence value. +const EncodedSeqLength = 8 + +// EncodeSequence converts the sequence value into the binary representation. +func EncodeSequence(val uint64) []byte { + bz := make([]byte, EncodedSeqLength) + binary.BigEndian.PutUint64(bz, val) + return bz +} diff --git a/store/table/sequence_test.go b/store/table/sequence_test.go new file mode 100644 index 000000000000..eb4c4e77340c --- /dev/null +++ b/store/table/sequence_test.go @@ -0,0 +1,25 @@ +package table + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" +) + +func TestSequenceIncrements(t *testing.T) { + ctx := NewMockContext() + store := ctx.KVStore(sdk.NewKVStoreKey("test")) + + seq := NewSequence(0x1) + var i uint64 + for i = 1; i < 10; i++ { + autoID := seq.NextVal(store) + assert.Equal(t, i, autoID) + assert.Equal(t, i, seq.CurVal(store)) + } + + seq = NewSequence(0x1) + assert.Equal(t, uint64(10), seq.PeekNextVal(store)) + assert.Equal(t, uint64(9), seq.CurVal(store)) +} diff --git a/store/table/table.go b/store/table/table.go index 1f536fe7904a..adf588d7b109 100644 --- a/store/table/table.go +++ b/store/table/table.go @@ -70,7 +70,7 @@ func (a *TableBuilder) AddAfterDeleteInterceptor(interceptor AfterDeleteIntercep a.afterDelete = append(a.afterDelete, interceptor) } -// Table is the high level object to storage mapper functionality. Persistent entities are stored by an unique identifier +// Table is the high level object for storage mapper functionality. Persistent entities are stored by an unique identifier // called `RowID`. // The Table struct does not enforce uniqueness of the `RowID` but expects this to be satisfied by the callers and conditions // to optimize Gas usage. From d0a77b635fe15d9d211d766145034c1afe5b32b5 Mon Sep 17 00:00:00 2001 From: blushi Date: Thu, 22 Jul 2021 13:06:13 +0200 Subject: [PATCH 05/26] Update testdata --- store/table/table_test.go | 32 ++++++------ store/table/types_test.go | 10 ++-- testutil/testdata/testdata.pb.go | 90 +++++++++++++------------------- testutil/testdata/testdata.proto | 2 +- 4 files changed, 59 insertions(+), 75 deletions(-) diff --git a/store/table/table_test.go b/store/table/table_test.go index fff399189ef8..b5af651b4476 100644 --- a/store/table/table_test.go +++ b/store/table/table_test.go @@ -58,7 +58,7 @@ func TestCreate(t *testing.T) { }{ "happy path": { src: &testdata.TableModel{ - Id: "my-id", + Id: 1, Name: "some name", }, }, @@ -71,7 +71,7 @@ func TestCreate(t *testing.T) { }, "model validation fails": { src: &testdata.TableModel{ - Id: "my-id", + Id: 1, Name: "", }, expErr: testdata.ErrTest, @@ -89,15 +89,15 @@ func TestCreate(t *testing.T) { tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, Max255DynamicLengthIndexKeyCodec{}, cdc) myTable := tableBuilder.Build() - err := myTable.Create(store, []byte("my-id"), spec.src) + err := myTable.Create(store, EncodeSequence(1), spec.src) require.True(t, spec.expErr.Is(err), err) shouldExists := spec.expErr == nil - assert.Equal(t, shouldExists, myTable.Has(store, []byte("my-id")), fmt.Sprintf("expected %v", shouldExists)) + assert.Equal(t, shouldExists, myTable.Has(store, EncodeSequence(1)), fmt.Sprintf("expected %v", shouldExists)) // then var loaded testdata.TableModel - err = myTable.GetOne(store, []byte("my-id"), &loaded) + err = myTable.GetOne(store, EncodeSequence(1), &loaded) if spec.expErr != nil { require.True(t, ErrNotFound.Is(err)) return @@ -115,7 +115,7 @@ func TestUpdate(t *testing.T) { }{ "happy path": { src: &testdata.TableModel{ - Id: "my-id", + Id: 1, Name: "some name", }, }, @@ -128,7 +128,7 @@ func TestUpdate(t *testing.T) { }, "model validation fails": { src: &testdata.TableModel{ - Id: "my-id", + Id: 1, Name: "", }, expErr: testdata.ErrTest, @@ -147,20 +147,20 @@ func TestUpdate(t *testing.T) { myTable := tableBuilder.Build() initValue := testdata.TableModel{ - Id: "my-id", + Id: 1, Name: "old name", } - err := myTable.Create(store, []byte("my-id"), &initValue) + err := myTable.Create(store, EncodeSequence(1), &initValue) require.NoError(t, err) // when - err = myTable.Save(store, []byte("my-id"), spec.src) + err = myTable.Save(store, EncodeSequence(1), spec.src) require.True(t, spec.expErr.Is(err), "got ", err) // then var loaded testdata.TableModel - require.NoError(t, myTable.GetOne(store, []byte("my-id"), &loaded)) + require.NoError(t, myTable.GetOne(store, EncodeSequence(1), &loaded)) if spec.expErr == nil { assert.Equal(t, spec.src, &loaded) } else { @@ -176,7 +176,7 @@ func TestDelete(t *testing.T) { expErr *errors.Error }{ "happy path": { - rowId: []byte("my-id"), + rowId: EncodeSequence(1), }, "not found": { rowId: []byte("not-found"), @@ -196,11 +196,11 @@ func TestDelete(t *testing.T) { myTable := tableBuilder.Build() initValue := testdata.TableModel{ - Id: "my-id", + Id: 1, Name: "some name", } - err := myTable.Create(store, []byte("my-id"), &initValue) + err := myTable.Create(store, EncodeSequence(1), &initValue) require.NoError(t, err) // when @@ -210,10 +210,10 @@ func TestDelete(t *testing.T) { // then var loaded testdata.TableModel if spec.expErr == ErrNotFound { - require.NoError(t, myTable.GetOne(store, []byte("my-id"), &loaded)) + require.NoError(t, myTable.GetOne(store, EncodeSequence(1), &loaded)) assert.Equal(t, initValue, loaded) } else { - err := myTable.GetOne(store, []byte("my-id"), &loaded) + err := myTable.GetOne(store, EncodeSequence(1), &loaded) require.Error(t, err) require.Equal(t, err, ErrNotFound) } diff --git a/store/table/types_test.go b/store/table/types_test.go index 6d31e584e52f..48d184c70328 100644 --- a/store/table/types_test.go +++ b/store/table/types_test.go @@ -20,12 +20,12 @@ func TestTypeSafeRowGetter(t *testing.T) { const prefixKey = 0x2 store := prefix.NewStore(ctx.KVStore(storeKey), []byte{prefixKey}) md := testdata.TableModel{ - Id: "my-id", + Id: 1, Name: "some name", } bz, err := md.Marshal() require.NoError(t, err) - store.Set([]byte("my-id"), bz) + store.Set(EncodeSequence(1), bz) specs := map[string]struct { srcRowID RowID @@ -34,17 +34,17 @@ func TestTypeSafeRowGetter(t *testing.T) { expErr *errors.Error }{ "happy path": { - srcRowID: []byte("my-id"), + srcRowID: EncodeSequence(1), srcModelType: reflect.TypeOf(testdata.TableModel{}), expObj: md, }, "unknown rowID should return ErrNotFound": { - srcRowID: []byte("unknown"), + srcRowID: EncodeSequence(2), srcModelType: reflect.TypeOf(testdata.TableModel{}), expErr: ErrNotFound, }, "wrong type should cause ErrType": { - srcRowID: []byte("my-id"), + srcRowID: EncodeSequence(1), srcModelType: reflect.TypeOf(testdata.Cat{}), expErr: ErrType, }, diff --git a/testutil/testdata/testdata.pb.go b/testutil/testdata/testdata.pb.go index d21261462669..4894d5ec9fef 100644 --- a/testutil/testdata/testdata.pb.go +++ b/testutil/testdata/testdata.pb.go @@ -323,7 +323,7 @@ func (m *BadMultiSignature) GetMaliciousField() []byte { } type TableModel struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` } @@ -360,11 +360,11 @@ func (m *TableModel) XXX_DiscardUnknown() { var xxx_messageInfo_TableModel proto.InternalMessageInfo -func (m *TableModel) GetId() string { +func (m *TableModel) GetId() uint64 { if m != nil { return m.Id } - return "" + return 0 } func (m *TableModel) GetName() string { @@ -387,32 +387,32 @@ func init() { func init() { proto.RegisterFile("testdata.proto", fileDescriptor_40c4782d007dfce9) } var fileDescriptor_40c4782d007dfce9 = []byte{ - // 391 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xb1, 0xae, 0xda, 0x30, - 0x18, 0x85, 0x31, 0x01, 0x5a, 0xfe, 0x46, 0x41, 0xb5, 0x18, 0x52, 0x86, 0x14, 0x65, 0x29, 0x43, - 0x49, 0xaa, 0xa2, 0x2e, 0x6c, 0x40, 0xd5, 0xb2, 0xb0, 0xa4, 0x9d, 0xba, 0x20, 0x87, 0x98, 0xc4, - 0xc2, 0x89, 0x2b, 0xec, 0x54, 0xd0, 0xa7, 0xe8, 0x2b, 0xf4, 0x6d, 0x3a, 0x32, 0x76, 0xbc, 0x82, - 0x17, 0xb9, 0x8a, 0x93, 0x5c, 0x18, 0xee, 0xc0, 0x94, 0x73, 0x8e, 0x73, 0x3e, 0xfd, 0x89, 0x7f, - 0xb0, 0x14, 0x95, 0x2a, 0x22, 0x8a, 0x78, 0x3f, 0xf7, 0x42, 0x09, 0xfc, 0xb2, 0xf6, 0x83, 0x7e, - 0x2c, 0x62, 0xa1, 0x43, 0xbf, 0x50, 0xe5, 0xf9, 0xe0, 0x4d, 0x2c, 0x44, 0xcc, 0xa9, 0xaf, 0x5d, - 0x98, 0x6f, 0x7d, 0x92, 0x1d, 0xcb, 0x23, 0x77, 0x0c, 0xc6, 0x67, 0x11, 0x63, 0x0c, 0x2d, 0xc9, - 0x7e, 0x53, 0x1b, 0x0d, 0xd1, 0xa8, 0x1b, 0x68, 0x5d, 0x64, 0x19, 0x49, 0xa9, 0xdd, 0x2c, 0xb3, - 0x42, 0xbb, 0x9f, 0xc0, 0x58, 0x10, 0x85, 0x6d, 0x78, 0x91, 0x8a, 0x8c, 0xed, 0xe8, 0xbe, 0x6a, - 0xd4, 0x16, 0xf7, 0xa1, 0xcd, 0xd9, 0x2f, 0x2a, 0x75, 0xab, 0x1d, 0x94, 0xc6, 0xfd, 0x0a, 0xdd, - 0x25, 0x91, 0xb3, 0x8c, 0xa5, 0x84, 0xe3, 0xf7, 0xd0, 0x21, 0x5a, 0xe9, 0xee, 0xab, 0x8f, 0x7d, - 0xaf, 0x1c, 0xcf, 0xab, 0xc7, 0xf3, 0x66, 0xd9, 0x31, 0xa8, 0xde, 0xc1, 0x26, 0xa0, 0x83, 0x86, - 0x19, 0x01, 0x3a, 0xb8, 0x0b, 0x30, 0x97, 0x44, 0x5e, 0x59, 0x13, 0x80, 0x84, 0xc8, 0xf5, 0x1d, - 0xbc, 0x6e, 0x52, 0x97, 0xdc, 0x15, 0xf4, 0x4a, 0xc8, 0x95, 0x33, 0x05, 0xab, 0xe0, 0xdc, 0xc9, - 0x32, 0x93, 0x9b, 0xae, 0x1b, 0xc2, 0xeb, 0x39, 0x89, 0x56, 0x39, 0x57, 0xec, 0x1b, 0x8b, 0x33, - 0xa2, 0xf2, 0x3d, 0xc5, 0x0e, 0x80, 0xac, 0x8d, 0xb4, 0xd1, 0xd0, 0x18, 0x99, 0xc1, 0x4d, 0x82, - 0xdf, 0x41, 0x2f, 0x25, 0x9c, 0x6d, 0x98, 0xc8, 0xe5, 0x7a, 0xcb, 0x28, 0x8f, 0xec, 0xf6, 0x10, - 0x8d, 0xcc, 0xc0, 0x7a, 0x8a, 0xbf, 0x14, 0xe9, 0xb4, 0x75, 0xfa, 0xfb, 0x16, 0xb9, 0x1f, 0x00, - 0xbe, 0x93, 0x90, 0xd3, 0x95, 0x88, 0x28, 0xc7, 0x16, 0x34, 0x59, 0x54, 0xfd, 0xf9, 0x26, 0x8b, - 0x9e, 0xbb, 0xa9, 0xf9, 0xf2, 0xdf, 0xd9, 0x41, 0xa7, 0xb3, 0x83, 0x1e, 0xce, 0x0e, 0xfa, 0x73, - 0x71, 0x1a, 0xa7, 0x8b, 0xd3, 0xf8, 0x7f, 0x71, 0x1a, 0x3f, 0xbc, 0x98, 0xa9, 0x24, 0x0f, 0xbd, - 0x8d, 0x48, 0xfd, 0x8d, 0x90, 0xa9, 0x90, 0xd5, 0x63, 0x2c, 0xa3, 0x9d, 0x5f, 0xac, 0x52, 0xae, - 0x18, 0xf7, 0xeb, 0x9d, 0x0a, 0x3b, 0xfa, 0xdb, 0x27, 0x8f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xfa, - 0xe5, 0x40, 0xb7, 0x76, 0x02, 0x00, 0x00, + // 393 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xb1, 0x8e, 0xda, 0x40, + 0x14, 0x45, 0x19, 0x0c, 0x24, 0xbc, 0x58, 0x46, 0x19, 0x51, 0x38, 0x14, 0x0e, 0x72, 0x13, 0x8a, + 0x60, 0x47, 0x41, 0x69, 0xe8, 0x80, 0x28, 0xa1, 0xa1, 0x71, 0x52, 0xa5, 0x41, 0x63, 0x3c, 0xd8, + 0x23, 0xc6, 0x9e, 0x88, 0x19, 0x47, 0x90, 0xaf, 0xd8, 0x5f, 0xd8, 0xbf, 0xd9, 0x92, 0x72, 0xcb, + 0x15, 0xfc, 0xc8, 0xca, 0x63, 0xbc, 0x50, 0x6c, 0x41, 0xe5, 0x7b, 0xef, 0xf3, 0x3d, 0x7a, 0x96, + 0x1f, 0x58, 0x8a, 0x4a, 0x15, 0x11, 0x45, 0xbc, 0xbf, 0x5b, 0xa1, 0x04, 0x7e, 0x5b, 0xf9, 0x5e, + 0x37, 0x16, 0xb1, 0xd0, 0xa1, 0x5f, 0xa8, 0x72, 0xde, 0xfb, 0x10, 0x0b, 0x11, 0x73, 0xea, 0x6b, + 0x17, 0xe6, 0x6b, 0x9f, 0x64, 0xfb, 0x72, 0xe4, 0x0e, 0xc1, 0xf8, 0x2e, 0x62, 0x8c, 0xa1, 0x21, + 0xd9, 0x7f, 0x6a, 0xa3, 0x3e, 0x1a, 0xb4, 0x03, 0xad, 0x8b, 0x2c, 0x23, 0x29, 0xb5, 0xeb, 0x65, + 0x56, 0x68, 0xf7, 0x1b, 0x18, 0x33, 0xa2, 0xb0, 0x0d, 0x6f, 0x52, 0x91, 0xb1, 0x0d, 0xdd, 0x9e, + 0x1b, 0x95, 0xc5, 0x5d, 0x68, 0x72, 0xf6, 0x8f, 0x4a, 0xdd, 0x6a, 0x06, 0xa5, 0x71, 0x7f, 0x42, + 0x7b, 0x4e, 0xe4, 0x24, 0x63, 0x29, 0xe1, 0xf8, 0x33, 0xb4, 0x88, 0x56, 0xba, 0xfb, 0xee, 0x6b, + 0xd7, 0x2b, 0xd7, 0xf3, 0xaa, 0xf5, 0xbc, 0x49, 0xb6, 0x0f, 0xce, 0xef, 0x60, 0x13, 0xd0, 0x4e, + 0xc3, 0x8c, 0x00, 0xed, 0xdc, 0x19, 0x98, 0x73, 0x22, 0x2f, 0xac, 0x11, 0x40, 0x42, 0xe4, 0xf2, + 0x06, 0x5e, 0x3b, 0xa9, 0x4a, 0xee, 0x02, 0x3a, 0x25, 0xe4, 0xc2, 0x19, 0x83, 0x55, 0x70, 0x6e, + 0x64, 0x99, 0xc9, 0x55, 0xd7, 0x0d, 0xe1, 0xfd, 0x94, 0x44, 0x8b, 0x9c, 0x2b, 0xf6, 0x8b, 0xc5, + 0x19, 0x51, 0xf9, 0x96, 0x62, 0x07, 0x40, 0x56, 0x46, 0xda, 0xa8, 0x6f, 0x0c, 0xcc, 0xe0, 0x2a, + 0xc1, 0x9f, 0xa0, 0x93, 0x12, 0xce, 0x56, 0x4c, 0xe4, 0x72, 0xb9, 0x66, 0x94, 0x47, 0x76, 0xb3, + 0x8f, 0x06, 0x66, 0x60, 0xbd, 0xc4, 0x3f, 0x8a, 0x74, 0xdc, 0x38, 0xdc, 0x7f, 0x44, 0xee, 0x17, + 0x80, 0xdf, 0x24, 0xe4, 0x74, 0x21, 0x22, 0xca, 0xb1, 0x05, 0x75, 0x16, 0xe9, 0x0d, 0x1b, 0x41, + 0x9d, 0x45, 0xaf, 0xfd, 0xa9, 0xe9, 0xfc, 0xe1, 0xe8, 0xa0, 0xc3, 0xd1, 0x41, 0x4f, 0x47, 0x07, + 0xdd, 0x9d, 0x9c, 0xda, 0xe1, 0xe4, 0xd4, 0x1e, 0x4f, 0x4e, 0xed, 0x8f, 0x17, 0x33, 0x95, 0xe4, + 0xa1, 0xb7, 0x12, 0xa9, 0xbf, 0x12, 0x32, 0x15, 0xf2, 0xfc, 0x18, 0xca, 0x68, 0xe3, 0x17, 0xa7, + 0x94, 0x2b, 0xc6, 0xfd, 0xea, 0xa6, 0xc2, 0x96, 0xfe, 0xf6, 0xd1, 0x73, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x7a, 0x9a, 0x17, 0x6f, 0x76, 0x02, 0x00, 0x00, } func (m *Dog) Marshal() (dAtA []byte, err error) { @@ -667,12 +667,10 @@ func (m *TableModel) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if len(m.Id) > 0 { - i -= len(m.Id) - copy(dAtA[i:], m.Id) - i = encodeVarintTestdata(dAtA, i, uint64(len(m.Id))) + if m.Id != 0 { + i = encodeVarintTestdata(dAtA, i, uint64(m.Id)) i-- - dAtA[i] = 0xa + dAtA[i] = 0x8 } return len(dAtA) - i, nil } @@ -791,9 +789,8 @@ func (m *TableModel) Size() (n int) { } var l int _ = l - l = len(m.Id) - if l > 0 { - n += 1 + l + sovTestdata(uint64(l)) + if m.Id != 0 { + n += 1 + sovTestdata(uint64(m.Id)) } l = len(m.Name) if l > 0 { @@ -1447,10 +1444,10 @@ func (m *TableModel) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 2 { + if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) } - var stringLen uint64 + m.Id = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTestdata @@ -1460,24 +1457,11 @@ func (m *TableModel) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.Id |= uint64(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTestdata - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTestdata - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Id = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) diff --git a/testutil/testdata/testdata.proto b/testutil/testdata/testdata.proto index 1f14edcb37c0..1da9aef16e8e 100644 --- a/testutil/testdata/testdata.proto +++ b/testutil/testdata/testdata.proto @@ -37,6 +37,6 @@ message BadMultiSignature { } message TableModel { - string id = 1; + uint64 id = 1; string name = 2; } From fc72796756671138597aac051674eb933799aa17 Mon Sep 17 00:00:00 2001 From: blushi Date: Thu, 22 Jul 2021 13:20:36 +0200 Subject: [PATCH 06/26] Lint --- store/table/table.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/store/table/table.go b/store/table/table.go index adf588d7b109..c861aa1b458c 100644 --- a/store/table/table.go +++ b/store/table/table.go @@ -9,9 +9,9 @@ import ( "github.com/cosmos/cosmos-sdk/types/errors" ) -var _ Indexable = &TableBuilder{} +var _ Indexable = &Builder{} -type TableBuilder struct { +type Builder struct { model reflect.Type prefixData byte indexKeyCodec IndexKeyCodec @@ -21,7 +21,7 @@ type TableBuilder struct { } // NewTableBuilder creates a builder to setup a Table object. -func NewTableBuilder(prefixData byte, model codec.ProtoMarshaler, idxKeyCodec IndexKeyCodec, cdc codec.Codec) *TableBuilder { +func NewTableBuilder(prefixData byte, model codec.ProtoMarshaler, idxKeyCodec IndexKeyCodec, cdc codec.Codec) *Builder { if model == nil { panic("Model must not be nil") } @@ -32,7 +32,7 @@ func NewTableBuilder(prefixData byte, model codec.ProtoMarshaler, idxKeyCodec In if tp.Kind() == reflect.Ptr { tp = tp.Elem() } - return &TableBuilder{ + return &Builder{ prefixData: prefixData, model: tp, indexKeyCodec: idxKeyCodec, @@ -40,17 +40,17 @@ func NewTableBuilder(prefixData byte, model codec.ProtoMarshaler, idxKeyCodec In } } -func (a TableBuilder) IndexKeyCodec() IndexKeyCodec { +func (a Builder) IndexKeyCodec() IndexKeyCodec { return a.indexKeyCodec } // RowGetter returns a type safe RowGetter. -func (a TableBuilder) RowGetter() RowGetter { +func (a Builder) RowGetter() RowGetter { return NewTypeSafeRowGetter(a.prefixData, a.model, a.cdc) } // Build creates a new Table object. -func (a TableBuilder) Build() Table { +func (a Builder) Build() Table { return Table{ model: a.model, prefix: a.prefixData, @@ -61,12 +61,12 @@ func (a TableBuilder) Build() Table { } // AddAfterSaveInterceptor can be used to register a callback function that is executed after an object is created and/or updated. -func (a *TableBuilder) AddAfterSaveInterceptor(interceptor AfterSaveInterceptor) { +func (a *Builder) AddAfterSaveInterceptor(interceptor AfterSaveInterceptor) { a.afterSave = append(a.afterSave, interceptor) } // AddAfterDeleteInterceptor can be used to register a callback function that is executed after an object is deleted. -func (a *TableBuilder) AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) { +func (a *Builder) AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) { a.afterDelete = append(a.afterDelete, interceptor) } From a4a4e09d9d55bd63b0ec03ebeab56b19973cc236 Mon Sep 17 00:00:00 2001 From: blushi Date: Thu, 22 Jul 2021 13:56:03 +0200 Subject: [PATCH 07/26] Add docs --- docs/core/store.md | 18 ++++++++++++++++++ store/README.md | 20 ++++++++++++++++++++ store/table/table_test.go | 10 +++++----- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/docs/core/store.md b/docs/core/store.md index a469b77ebfd3..5d1287d36a7a 100644 --- a/docs/core/store.md +++ b/docs/core/store.md @@ -222,6 +222,24 @@ When `Store.{Get, Set}()` is called, the store forwards the call to its parent, When `Store.Iterator()` is called, it does not simply prefix the `Store.prefix`, since it does not work as intended. In that case, some of the elements are traversed even they are not starting with the prefix. +## Table Store + +The table-store package provides a framework for creating relational database tables with primary and secondary keys. + +```go +type Table struct { + model reflect.Type + prefix byte + afterSave []AfterSaveInterceptor + afterDelete []AfterDeleteInterceptor + cdc codec.Codec +} +``` + +Such table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling. +In the prefix store, entities are stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter or dynamic size bytes. +Regular CRUD operations can be performed on a table. + ## Next {hide} Learn about [encoding](./encoding.md) {hide} diff --git a/store/README.md b/store/README.md index 8541f69673ad..34f2788c74c1 100644 --- a/store/README.md +++ b/store/README.md @@ -127,3 +127,23 @@ type Store struct { ``` `Store.Store` is a `dbadapter.Store` with a `dbm.NewMemDB()`. All `KVStore` methods are reused. When `Store.Commit()` is called, new `dbadapter.Store` is assigned, discarding previous reference and making it garbage collected. + +## Table + +The table-store package provides a framework for creating relational database tables with primary and secondary keys. + +```go +type Table struct { + model reflect.Type + prefix byte + afterSave []AfterSaveInterceptor + afterDelete []AfterDeleteInterceptor + cdc codec.Codec +} +``` + +Such table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling. +In the prefix store, entities are stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter or dynamic size bytes. +Regular CRUD operations can be performed on a table. + + diff --git a/store/table/table_test.go b/store/table/table_test.go index b5af651b4476..b37aef50eb24 100644 --- a/store/table/table_test.go +++ b/store/table/table_test.go @@ -25,10 +25,10 @@ func TestNewTableBuilder(t *testing.T) { }{ "happy path": { model: &testdata.TableModel{}, - idxKeyCodec: Max255DynamicLengthIndexKeyCodec{}, + idxKeyCodec: FixLengthIndexKeys(EncodedSeqLength), }, "nil model": { - idxKeyCodec: Max255DynamicLengthIndexKeyCodec{}, + idxKeyCodec: FixLengthIndexKeys(EncodedSeqLength), expPanic: true, }, "nil idxKeyCodec": { @@ -86,7 +86,7 @@ func TestCreate(t *testing.T) { store := ctx.KVStore(sdk.NewKVStoreKey("test")) const anyPrefix = 0x10 - tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, Max255DynamicLengthIndexKeyCodec{}, cdc) + tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) myTable := tableBuilder.Build() err := myTable.Create(store, EncodeSequence(1), spec.src) @@ -143,7 +143,7 @@ func TestUpdate(t *testing.T) { store := ctx.KVStore(sdk.NewKVStoreKey("test")) const anyPrefix = 0x10 - tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, Max255DynamicLengthIndexKeyCodec{}, cdc) + tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) myTable := tableBuilder.Build() initValue := testdata.TableModel{ @@ -192,7 +192,7 @@ func TestDelete(t *testing.T) { store := ctx.KVStore(sdk.NewKVStoreKey("test")) const anyPrefix = 0x10 - tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, Max255DynamicLengthIndexKeyCodec{}, cdc) + tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) myTable := tableBuilder.Build() initValue := testdata.TableModel{ From b6f2d08b642c17793043b302b81f1c13f2c746ca Mon Sep 17 00:00:00 2001 From: blushi Date: Thu, 22 Jul 2021 14:30:18 +0200 Subject: [PATCH 08/26] Update docs --- docs/core/store.md | 2 +- store/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/core/store.md b/docs/core/store.md index 5d1287d36a7a..455c17df5191 100644 --- a/docs/core/store.md +++ b/docs/core/store.md @@ -238,7 +238,7 @@ type Table struct { Such table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling. In the prefix store, entities are stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter or dynamic size bytes. -Regular CRUD operations can be performed on a table. +Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store. ## Next {hide} diff --git a/store/README.md b/store/README.md index 34f2788c74c1..37b3f5b44ddb 100644 --- a/store/README.md +++ b/store/README.md @@ -144,6 +144,6 @@ type Table struct { Such table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling. In the prefix store, entities are stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter or dynamic size bytes. -Regular CRUD operations can be performed on a table. +Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store. From ed2a1d2ac48fe6d3cb4fc475d120671cea7dd9e1 Mon Sep 17 00:00:00 2001 From: blushi Date: Wed, 28 Jul 2021 13:11:42 +0200 Subject: [PATCH 09/26] Use Update instead of Save --- store/table/table.go | 6 +++--- store/table/table_test.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/store/table/table.go b/store/table/table.go index c861aa1b458c..a038634c9a2b 100644 --- a/store/table/table.go +++ b/store/table/table.go @@ -109,12 +109,12 @@ func (a Table) Create(store sdk.KVStore, rowID RowID, obj codec.ProtoMarshaler) return nil } -// Save updates the given object under the rowID key. It expects the key to exist already +// Update updates the given object under the rowID key. It expects the key to exist already // and fails with an `ErrNotFound` otherwise. Any caller must therefore make sure that this contract // is fulfilled. Parameters must not be nil. // -// Save iterates though the registered callbacks and may add or remove secondary index keys by them. -func (a Table) Save(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler) error { +// Update iterates though the registered callbacks and may add or remove secondary index keys by them. +func (a Table) Update(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler) error { if err := assertCorrectType(a.model, newValue); err != nil { return err } diff --git a/store/table/table_test.go b/store/table/table_test.go index b37aef50eb24..3f694893114f 100644 --- a/store/table/table_test.go +++ b/store/table/table_test.go @@ -155,7 +155,7 @@ func TestUpdate(t *testing.T) { require.NoError(t, err) // when - err = myTable.Save(store, EncodeSequence(1), spec.src) + err = myTable.Update(store, EncodeSequence(1), spec.src) require.True(t, spec.expErr.Is(err), "got ", err) // then From 30c765b20ee661bca25efbbe68b824b4a37df86a Mon Sep 17 00:00:00 2001 From: blushi Date: Wed, 11 Aug 2021 11:13:05 +0200 Subject: [PATCH 10/26] Move orm to x/group --- docs/core/store.md | 18 --- store/README.md | 17 --- store/table/index.go | 37 ----- store/table/index_key_codec.go | 66 --------- store/table/index_key_codec_test.go | 115 -------------- store/table/index_test.go | 39 ----- store/table/sequence.go | 81 ---------- store/table/sequence_test.go | 25 ---- store/table/table.go | 189 ----------------------- store/table/table_test.go | 222 ---------------------------- store/table/testsupport.go | 32 ---- store/table/types.go | 109 -------------- store/table/types_test.go | 78 ---------- 13 files changed, 1028 deletions(-) delete mode 100644 store/table/index.go delete mode 100644 store/table/index_key_codec.go delete mode 100644 store/table/index_key_codec_test.go delete mode 100644 store/table/index_test.go delete mode 100644 store/table/sequence.go delete mode 100644 store/table/sequence_test.go delete mode 100644 store/table/table.go delete mode 100644 store/table/table_test.go delete mode 100644 store/table/testsupport.go delete mode 100644 store/table/types.go delete mode 100644 store/table/types_test.go diff --git a/docs/core/store.md b/docs/core/store.md index 455c17df5191..a469b77ebfd3 100644 --- a/docs/core/store.md +++ b/docs/core/store.md @@ -222,24 +222,6 @@ When `Store.{Get, Set}()` is called, the store forwards the call to its parent, When `Store.Iterator()` is called, it does not simply prefix the `Store.prefix`, since it does not work as intended. In that case, some of the elements are traversed even they are not starting with the prefix. -## Table Store - -The table-store package provides a framework for creating relational database tables with primary and secondary keys. - -```go -type Table struct { - model reflect.Type - prefix byte - afterSave []AfterSaveInterceptor - afterDelete []AfterDeleteInterceptor - cdc codec.Codec -} -``` - -Such table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling. -In the prefix store, entities are stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter or dynamic size bytes. -Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store. - ## Next {hide} Learn about [encoding](./encoding.md) {hide} diff --git a/store/README.md b/store/README.md index 37b3f5b44ddb..1b50239a7f81 100644 --- a/store/README.md +++ b/store/README.md @@ -128,22 +128,5 @@ type Store struct { `Store.Store` is a `dbadapter.Store` with a `dbm.NewMemDB()`. All `KVStore` methods are reused. When `Store.Commit()` is called, new `dbadapter.Store` is assigned, discarding previous reference and making it garbage collected. -## Table - -The table-store package provides a framework for creating relational database tables with primary and secondary keys. - -```go -type Table struct { - model reflect.Type - prefix byte - afterSave []AfterSaveInterceptor - afterDelete []AfterDeleteInterceptor - cdc codec.Codec -} -``` - -Such table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling. -In the prefix store, entities are stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter or dynamic size bytes. -Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store. diff --git a/store/table/index.go b/store/table/index.go deleted file mode 100644 index 375a957f1989..000000000000 --- a/store/table/index.go +++ /dev/null @@ -1,37 +0,0 @@ -package table - -// PrefixRange turns a prefix into a (start, end) range. The start is the given prefix value and -// the end is calculated by adding 1 bit to the start value. Nil is not allowed as prefix. -// Example: []byte{1, 3, 4} becomes []byte{1, 3, 5} -// []byte{15, 42, 255, 255} becomes []byte{15, 43, 0, 0} -// -// In case of an overflow the end is set to nil. -// Example: []byte{255, 255, 255, 255} becomes nil -// -func PrefixRange(prefix []byte) ([]byte, []byte) { - if prefix == nil { - panic("nil key not allowed") - } - // special case: no prefix is whole range - if len(prefix) == 0 { - return nil, nil - } - - // copy the prefix and update last byte - end := make([]byte, len(prefix)) - copy(end, prefix) - l := len(end) - 1 - end[l]++ - - // wait, what if that overflowed?.... - for end[l] == 0 && l > 0 { - l-- - end[l]++ - } - - // okay, funny guy, you gave us FFF, no end to this range... - if l == 0 && end[0] == 0 { - end = nil - } - return prefix, end -} diff --git a/store/table/index_key_codec.go b/store/table/index_key_codec.go deleted file mode 100644 index def3ef409b87..000000000000 --- a/store/table/index_key_codec.go +++ /dev/null @@ -1,66 +0,0 @@ -package table - -// Max255DynamicLengthIndexKeyCodec works with up to 255 byte dynamic size RowIDs. -// They are encoded as `concat(searchableKey, rowID, len(rowID)[0])`. -type Max255DynamicLengthIndexKeyCodec struct{} - -// BuildIndexKey builds the index key by appending searchableKey with rowID and length int. -// The RowID length must not be greater than 255. -func (Max255DynamicLengthIndexKeyCodec) BuildIndexKey(searchableKey []byte, rowID RowID) []byte { - rowIDLen := len(rowID) - switch { - case rowIDLen == 0: - panic("Empty RowID") - case rowIDLen > 255: - panic("RowID exceeds max size") - } - - searchableKeyLen := len(searchableKey) - res := make([]byte, searchableKeyLen+rowIDLen+1) - copy(res, searchableKey) - copy(res[searchableKeyLen:], rowID) - res[searchableKeyLen+rowIDLen] = byte(rowIDLen) - return res -} - -// StripRowID returns the RowID from the combined persistentIndexKey. It is the reverse operation to BuildIndexKey -// but with the searchableKey and length int dropped. -func (Max255DynamicLengthIndexKeyCodec) StripRowID(persistentIndexKey []byte) RowID { - n := len(persistentIndexKey) - searchableKeyLen := persistentIndexKey[n-1] - return persistentIndexKey[n-int(searchableKeyLen)-1 : n-1] -} - -// FixLengthIndexKeyCodec expects the RowID to always have the same length with all entries. -// They are encoded as `concat(searchableKey, rowID)`. -type FixLengthIndexKeyCodec struct { - rowIDLength int -} - -// FixLengthIndexKeys is a constructor for FixLengthIndexKeyCodec. -func FixLengthIndexKeys(rowIDLength int) *FixLengthIndexKeyCodec { - return &FixLengthIndexKeyCodec{rowIDLength: rowIDLength} -} - -// BuildIndexKey builds the index key by appending searchableKey with rowID. -// The RowID length must not be greater than what is defined by rowIDLength in construction. -func (c FixLengthIndexKeyCodec) BuildIndexKey(searchableKey []byte, rowID RowID) []byte { - switch n := len(rowID); { - case n == 0: - panic("Empty RowID") - case n > c.rowIDLength: - panic("RowID exceeds max size") - } - n := len(searchableKey) - res := make([]byte, n+c.rowIDLength) - copy(res, searchableKey) - copy(res[n:], rowID) - return res -} - -// StripRowID returns the RowID from the combined persistentIndexKey. It is the reverse operation to BuildIndexKey -// but with the searchableKey dropped. -func (c FixLengthIndexKeyCodec) StripRowID(persistentIndexKey []byte) RowID { - n := len(persistentIndexKey) - return persistentIndexKey[n-c.rowIDLength:] -} diff --git a/store/table/index_key_codec_test.go b/store/table/index_key_codec_test.go deleted file mode 100644 index b3c88c82b9a3..000000000000 --- a/store/table/index_key_codec_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package table - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestEncodeIndexKey(t *testing.T) { - specs := map[string]struct { - srcKey []byte - srcRowID RowID - enc IndexKeyCodec - expKey []byte - expPanic bool - }{ - "dynamic length example 1": { - srcKey: []byte{0x0, 0x1, 0x2}, - srcRowID: []byte{0x3, 0x4}, - enc: Max255DynamicLengthIndexKeyCodec{}, - expKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x2}, - }, - "dynamic length example 2": { - srcKey: []byte{0x0, 0x1}, - srcRowID: []byte{0x2, 0x3, 0x4}, - enc: Max255DynamicLengthIndexKeyCodec{}, - expKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x3}, - }, - "dynamic length max row ID": { - srcKey: []byte{0x0, 0x1}, - srcRowID: []byte(strings.Repeat("a", 255)), - enc: Max255DynamicLengthIndexKeyCodec{}, - expKey: append(append([]byte{0x0, 0x1}, []byte(strings.Repeat("a", 255))...), 0xff), - }, - "dynamic length panics with empty rowID": { - srcKey: []byte{0x0, 0x1}, - srcRowID: []byte{}, - enc: Max255DynamicLengthIndexKeyCodec{}, - expPanic: true, - }, - "dynamic length exceeds max row ID": { - srcKey: []byte{0x0, 0x1}, - srcRowID: []byte(strings.Repeat("a", 256)), - enc: Max255DynamicLengthIndexKeyCodec{}, - expPanic: true, - }, - "uint64 example": { - srcKey: []byte{0x0, 0x1, 0x2}, - srcRowID: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, - enc: FixLengthIndexKeys(8), - expKey: []byte{0x0, 0x1, 0x2, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, - }, - "uint64 panics with empty rowID": { - srcKey: []byte{0x0, 0x1}, - srcRowID: []byte{}, - enc: FixLengthIndexKeys(8), - expPanic: true, - }, - "uint64 exceeds max bytes in rowID": { - srcKey: []byte{0x0, 0x1}, - srcRowID: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}, - enc: FixLengthIndexKeys(8), - expPanic: true, - }, - } - for msg, spec := range specs { - t.Run(msg, func(t *testing.T) { - if spec.expPanic { - require.Panics(t, - func() { - _ = spec.enc.BuildIndexKey(spec.srcKey, spec.srcRowID) - }) - return - } - got := spec.enc.BuildIndexKey(spec.srcKey, spec.srcRowID) - assert.Equal(t, spec.expKey, got) - }) - } -} -func TestDecodeIndexKey(t *testing.T) { - specs := map[string]struct { - srcKey []byte - enc IndexKeyCodec - expRowID RowID - }{ - "dynamic length example 1": { - srcKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x2}, - enc: Max255DynamicLengthIndexKeyCodec{}, - expRowID: []byte{0x3, 0x4}, - }, - "dynamic length example 2": { - srcKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x3}, - enc: Max255DynamicLengthIndexKeyCodec{}, - expRowID: []byte{0x2, 0x3, 0x4}, - }, - "dynamic length max row ID": { - srcKey: append(append([]byte{0x0, 0x1}, []byte(strings.Repeat("a", 255))...), 0xff), - enc: Max255DynamicLengthIndexKeyCodec{}, - expRowID: []byte(strings.Repeat("a", 255)), - }, - "uint64 example": { - srcKey: []byte{0x0, 0x1, 0x2, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, - expRowID: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, - enc: FixLengthIndexKeys(8), - }, - } - for msg, spec := range specs { - t.Run(msg, func(t *testing.T) { - gotRow := spec.enc.StripRowID(spec.srcKey) - assert.Equal(t, spec.expRowID, gotRow) - }) - } -} diff --git a/store/table/index_test.go b/store/table/index_test.go deleted file mode 100644 index b512fd246cc4..000000000000 --- a/store/table/index_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package table - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestPrefixRange(t *testing.T) { - cases := map[string]struct { - src []byte - expStart []byte - expEnd []byte - expPanic bool - }{ - "normal": {src: []byte{1, 3, 4}, expStart: []byte{1, 3, 4}, expEnd: []byte{1, 3, 5}}, - "normal short": {src: []byte{79}, expStart: []byte{79}, expEnd: []byte{80}}, - "empty case": {src: []byte{}}, - "roll-over example 1": {src: []byte{17, 28, 255}, expStart: []byte{17, 28, 255}, expEnd: []byte{17, 29, 0}}, - "roll-over example 2": {src: []byte{15, 42, 255, 255}, expStart: []byte{15, 42, 255, 255}, expEnd: []byte{15, 43, 0, 0}}, - "pathological roll-over": {src: []byte{255, 255, 255, 255}, expStart: []byte{255, 255, 255, 255}}, - "nil prohibited": {expPanic: true}, - } - - for testName, tc := range cases { - t.Run(testName, func(t *testing.T) { - if tc.expPanic { - require.Panics(t, func() { - PrefixRange(tc.src) - }) - return - } - start, end := PrefixRange(tc.src) - assert.Equal(t, tc.expStart, start) - assert.Equal(t, tc.expEnd, end) - }) - } -} diff --git a/store/table/sequence.go b/store/table/sequence.go deleted file mode 100644 index 80129e766d10..000000000000 --- a/store/table/sequence.go +++ /dev/null @@ -1,81 +0,0 @@ -package table - -import ( - "encoding/binary" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/errors" -) - -// sequenceStorageKey is a fix key to read/ write data on the storage layer -var sequenceStorageKey = []byte{0x1} - -// sequence is a persistent unique key generator based on a counter. -type Sequence struct { - prefix byte -} - -func NewSequence(prefix byte) Sequence { - return Sequence{ - prefix: prefix, - } -} - -// NextVal increments and persists the counter by one and returns the value. -func (s Sequence) NextVal(store sdk.KVStore) uint64 { - pStore := prefix.NewStore(store, []byte{s.prefix}) - v := pStore.Get(sequenceStorageKey) - seq := DecodeSequence(v) - seq++ - pStore.Set(sequenceStorageKey, EncodeSequence(seq)) - return seq -} - -// CurVal returns the last value used. 0 if none. -func (s Sequence) CurVal(store sdk.KVStore) uint64 { - pStore := prefix.NewStore(store, []byte{s.prefix}) - v := pStore.Get(sequenceStorageKey) - return DecodeSequence(v) -} - -// PeekNextVal returns the CurVal + increment step. Not persistent. -func (s Sequence) PeekNextVal(store sdk.KVStore) uint64 { - pStore := prefix.NewStore(store, []byte{s.prefix}) - v := pStore.Get(sequenceStorageKey) - return DecodeSequence(v) + 1 -} - -// InitVal sets the start value for the sequence. It must be called only once on an empty DB. -// Otherwise an error is returned when the key exists. The given start value is stored as current -// value. -// -// It is recommended to call this method only for a sequence start value other than `1` as the -// method consumes unnecessary gas otherwise. A scenario would be an import from genesis. -func (s Sequence) InitVal(store sdk.KVStore, seq uint64) error { - pStore := prefix.NewStore(store, []byte{s.prefix}) - if pStore.Has(sequenceStorageKey) { - return errors.Wrap(ErrUniqueConstraint, "already initialized") - } - pStore.Set(sequenceStorageKey, EncodeSequence(seq)) - return nil -} - -// DecodeSequence converts the binary representation into an Uint64 value. -func DecodeSequence(bz []byte) uint64 { - if bz == nil { - return 0 - } - val := binary.BigEndian.Uint64(bz) - return val -} - -// EncodedSeqLength number of bytes used for the binary representation of a sequence value. -const EncodedSeqLength = 8 - -// EncodeSequence converts the sequence value into the binary representation. -func EncodeSequence(val uint64) []byte { - bz := make([]byte, EncodedSeqLength) - binary.BigEndian.PutUint64(bz, val) - return bz -} diff --git a/store/table/sequence_test.go b/store/table/sequence_test.go deleted file mode 100644 index eb4c4e77340c..000000000000 --- a/store/table/sequence_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package table - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/assert" -) - -func TestSequenceIncrements(t *testing.T) { - ctx := NewMockContext() - store := ctx.KVStore(sdk.NewKVStoreKey("test")) - - seq := NewSequence(0x1) - var i uint64 - for i = 1; i < 10; i++ { - autoID := seq.NextVal(store) - assert.Equal(t, i, autoID) - assert.Equal(t, i, seq.CurVal(store)) - } - - seq = NewSequence(0x1) - assert.Equal(t, uint64(10), seq.PeekNextVal(store)) - assert.Equal(t, uint64(9), seq.CurVal(store)) -} diff --git a/store/table/table.go b/store/table/table.go deleted file mode 100644 index a038634c9a2b..000000000000 --- a/store/table/table.go +++ /dev/null @@ -1,189 +0,0 @@ -package table - -import ( - "reflect" - - "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/types/errors" -) - -var _ Indexable = &Builder{} - -type Builder struct { - model reflect.Type - prefixData byte - indexKeyCodec IndexKeyCodec - afterSave []AfterSaveInterceptor - afterDelete []AfterDeleteInterceptor - cdc codec.Codec -} - -// NewTableBuilder creates a builder to setup a Table object. -func NewTableBuilder(prefixData byte, model codec.ProtoMarshaler, idxKeyCodec IndexKeyCodec, cdc codec.Codec) *Builder { - if model == nil { - panic("Model must not be nil") - } - if idxKeyCodec == nil { - panic("IndexKeyCodec must not be nil") - } - tp := reflect.TypeOf(model) - if tp.Kind() == reflect.Ptr { - tp = tp.Elem() - } - return &Builder{ - prefixData: prefixData, - model: tp, - indexKeyCodec: idxKeyCodec, - cdc: cdc, - } -} - -func (a Builder) IndexKeyCodec() IndexKeyCodec { - return a.indexKeyCodec -} - -// RowGetter returns a type safe RowGetter. -func (a Builder) RowGetter() RowGetter { - return NewTypeSafeRowGetter(a.prefixData, a.model, a.cdc) -} - -// Build creates a new Table object. -func (a Builder) Build() Table { - return Table{ - model: a.model, - prefix: a.prefixData, - afterSave: a.afterSave, - afterDelete: a.afterDelete, - cdc: a.cdc, - } -} - -// AddAfterSaveInterceptor can be used to register a callback function that is executed after an object is created and/or updated. -func (a *Builder) AddAfterSaveInterceptor(interceptor AfterSaveInterceptor) { - a.afterSave = append(a.afterSave, interceptor) -} - -// AddAfterDeleteInterceptor can be used to register a callback function that is executed after an object is deleted. -func (a *Builder) AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) { - a.afterDelete = append(a.afterDelete, interceptor) -} - -// Table is the high level object for storage mapper functionality. Persistent entities are stored by an unique identifier -// called `RowID`. -// The Table struct does not enforce uniqueness of the `RowID` but expects this to be satisfied by the callers and conditions -// to optimize Gas usage. -type Table struct { - model reflect.Type - prefix byte - afterSave []AfterSaveInterceptor - afterDelete []AfterDeleteInterceptor - cdc codec.Codec -} - -// Create persists the given object under the rowID key. It does not check if the -// key already exists. Any caller must either make sure that this contract is fulfilled -// by providing a universal unique ID or sequence that is guaranteed to not exist yet or -// by checking the state via `Has` function before. -// -// Create iterates though the registered callbacks and may add secondary index keys by them. -func (a Table) Create(store sdk.KVStore, rowID RowID, obj codec.ProtoMarshaler) error { - if err := assertCorrectType(a.model, obj); err != nil { - return err - } - if err := assertValid(obj); err != nil { - return err - } - pStore := prefix.NewStore(store, []byte{a.prefix}) - v, err := a.cdc.Marshal(obj) - if err != nil { - return errors.Wrapf(err, "failed to serialize %T", obj) - } - pStore.Set(rowID, v) - for i, itc := range a.afterSave { - if err := itc(store, rowID, obj, nil); err != nil { - return errors.Wrapf(err, "interceptor %d failed", i) - } - } - return nil -} - -// Update updates the given object under the rowID key. It expects the key to exist already -// and fails with an `ErrNotFound` otherwise. Any caller must therefore make sure that this contract -// is fulfilled. Parameters must not be nil. -// -// Update iterates though the registered callbacks and may add or remove secondary index keys by them. -func (a Table) Update(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler) error { - if err := assertCorrectType(a.model, newValue); err != nil { - return err - } - if err := assertValid(newValue); err != nil { - return err - } - - pStore := prefix.NewStore(store, []byte{a.prefix}) - var oldValue = reflect.New(a.model).Interface().(codec.ProtoMarshaler) - - if err := a.GetOne(store, rowID, oldValue); err != nil { - return errors.Wrap(err, "load old value") - } - newValueEncoded, err := a.cdc.Marshal(newValue) - if err != nil { - return errors.Wrapf(err, "failed to serialize %T", newValue) - } - - pStore.Set(rowID, newValueEncoded) - for i, itc := range a.afterSave { - if err := itc(store, rowID, newValue, oldValue); err != nil { - return errors.Wrapf(err, "interceptor %d failed", i) - } - } - return nil -} - -func assertValid(obj codec.ProtoMarshaler) error { - if v, ok := obj.(Validateable); ok { - if err := v.ValidateBasic(); err != nil { - return err - } - } - return nil -} - -// Delete removes the object under the rowID key. It expects the key to exists already -// and fails with a `ErrNotFound` otherwise. Any caller must therefore make sure that this contract -// is fulfilled. -// -// Delete iterates though the registered callbacks and removes secondary index keys by them. -func (a Table) Delete(store sdk.KVStore, rowID RowID) error { - pStore := prefix.NewStore(store, []byte{a.prefix}) - - var oldValue = reflect.New(a.model).Interface().(codec.ProtoMarshaler) - if err := a.GetOne(store, rowID, oldValue); err != nil { - return errors.Wrap(err, "load old value") - } - pStore.Delete(rowID) - - for i, itc := range a.afterDelete { - if err := itc(store, rowID, oldValue); err != nil { - return errors.Wrapf(err, "delete interceptor %d failed", i) - } - } - return nil -} - -// Has checks if a key exists. Panics on nil key. -func (a Table) Has(store sdk.KVStore, rowID RowID) bool { - Store := prefix.NewStore(store, []byte{a.prefix}) - it := Store.Iterator(PrefixRange(rowID)) - defer it.Close() - return it.Valid() -} - -// GetOne load the object persisted for the given RowID into the dest parameter. -// If none exists `ErrNotFound` is returned instead. Parameters must not be nil. -func (a Table) GetOne(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error { - x := NewTypeSafeRowGetter(a.prefix, a.model, a.cdc) - return x(store, rowID, dest) -} diff --git a/store/table/table_test.go b/store/table/table_test.go deleted file mode 100644 index 3f694893114f..000000000000 --- a/store/table/table_test.go +++ /dev/null @@ -1,222 +0,0 @@ -package table - -import ( - "fmt" - "testing" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestNewTableBuilder(t *testing.T) { - interfaceRegistry := types.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(interfaceRegistry) - const anyPrefix = 0x10 - - specs := map[string]struct { - model codec.ProtoMarshaler - idxKeyCodec IndexKeyCodec - expPanic bool - }{ - "happy path": { - model: &testdata.TableModel{}, - idxKeyCodec: FixLengthIndexKeys(EncodedSeqLength), - }, - "nil model": { - idxKeyCodec: FixLengthIndexKeys(EncodedSeqLength), - expPanic: true, - }, - "nil idxKeyCodec": { - model: &testdata.TableModel{}, - expPanic: true, - }, - } - - for msg, spec := range specs { - t.Run(msg, func(t *testing.T) { - f := func() { - NewTableBuilder(anyPrefix, spec.model, spec.idxKeyCodec, cdc) - } - if spec.expPanic { - require.Panics(t, f) - } else { - require.NotPanics(t, f) - } - }) - } -} - -func TestCreate(t *testing.T) { - specs := map[string]struct { - src codec.ProtoMarshaler - expErr *errors.Error - }{ - "happy path": { - src: &testdata.TableModel{ - Id: 1, - Name: "some name", - }, - }, - "wrong type": { - src: &testdata.Cat{ - Moniker: "cat moniker", - Lives: 10, - }, - expErr: ErrType, - }, - "model validation fails": { - src: &testdata.TableModel{ - Id: 1, - Name: "", - }, - expErr: testdata.ErrTest, - }, - } - for msg, spec := range specs { - t.Run(msg, func(t *testing.T) { - interfaceRegistry := types.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(interfaceRegistry) - - ctx := NewMockContext() - store := ctx.KVStore(sdk.NewKVStoreKey("test")) - - const anyPrefix = 0x10 - tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) - myTable := tableBuilder.Build() - - err := myTable.Create(store, EncodeSequence(1), spec.src) - - require.True(t, spec.expErr.Is(err), err) - shouldExists := spec.expErr == nil - assert.Equal(t, shouldExists, myTable.Has(store, EncodeSequence(1)), fmt.Sprintf("expected %v", shouldExists)) - - // then - var loaded testdata.TableModel - err = myTable.GetOne(store, EncodeSequence(1), &loaded) - if spec.expErr != nil { - require.True(t, ErrNotFound.Is(err)) - return - } - require.NoError(t, err) - assert.Equal(t, spec.src, &loaded) - }) - } -} - -func TestUpdate(t *testing.T) { - specs := map[string]struct { - src codec.ProtoMarshaler - expErr *errors.Error - }{ - "happy path": { - src: &testdata.TableModel{ - Id: 1, - Name: "some name", - }, - }, - "wrong type": { - src: &testdata.Cat{ - Moniker: "cat moniker", - Lives: 10, - }, - expErr: ErrType, - }, - "model validation fails": { - src: &testdata.TableModel{ - Id: 1, - Name: "", - }, - expErr: testdata.ErrTest, - }, - } - for msg, spec := range specs { - t.Run(msg, func(t *testing.T) { - interfaceRegistry := types.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(interfaceRegistry) - - ctx := NewMockContext() - store := ctx.KVStore(sdk.NewKVStoreKey("test")) - - const anyPrefix = 0x10 - tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) - myTable := tableBuilder.Build() - - initValue := testdata.TableModel{ - Id: 1, - Name: "old name", - } - - err := myTable.Create(store, EncodeSequence(1), &initValue) - require.NoError(t, err) - - // when - err = myTable.Update(store, EncodeSequence(1), spec.src) - require.True(t, spec.expErr.Is(err), "got ", err) - - // then - var loaded testdata.TableModel - require.NoError(t, myTable.GetOne(store, EncodeSequence(1), &loaded)) - if spec.expErr == nil { - assert.Equal(t, spec.src, &loaded) - } else { - assert.Equal(t, initValue, loaded) - } - }) - } -} - -func TestDelete(t *testing.T) { - specs := map[string]struct { - rowId []byte - expErr *errors.Error - }{ - "happy path": { - rowId: EncodeSequence(1), - }, - "not found": { - rowId: []byte("not-found"), - expErr: ErrNotFound, - }, - } - for msg, spec := range specs { - t.Run(msg, func(t *testing.T) { - interfaceRegistry := types.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(interfaceRegistry) - - ctx := NewMockContext() - store := ctx.KVStore(sdk.NewKVStoreKey("test")) - - const anyPrefix = 0x10 - tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) - myTable := tableBuilder.Build() - - initValue := testdata.TableModel{ - Id: 1, - Name: "some name", - } - - err := myTable.Create(store, EncodeSequence(1), &initValue) - require.NoError(t, err) - - // when - err = myTable.Delete(store, spec.rowId) - require.True(t, spec.expErr.Is(err), "got ", err) - - // then - var loaded testdata.TableModel - if spec.expErr == ErrNotFound { - require.NoError(t, myTable.GetOne(store, EncodeSequence(1), &loaded)) - assert.Equal(t, initValue, loaded) - } else { - err := myTable.GetOne(store, EncodeSequence(1), &loaded) - require.Error(t, err) - require.Equal(t, err, ErrNotFound) - } - }) - } -} diff --git a/store/table/testsupport.go b/store/table/testsupport.go deleted file mode 100644 index 60878101f654..000000000000 --- a/store/table/testsupport.go +++ /dev/null @@ -1,32 +0,0 @@ -package table - -import ( - "github.com/cosmos/cosmos-sdk/store" - "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - dbm "github.com/tendermint/tm-db" -) - -type MockContext struct { - db *dbm.MemDB - store types.CommitMultiStore -} - -func NewMockContext() *MockContext { - db := dbm.NewMemDB() - return &MockContext{ - db: dbm.NewMemDB(), - store: store.NewCommitMultiStore(db), - } -} - -func (m MockContext) KVStore(key sdk.StoreKey) sdk.KVStore { - if s := m.store.GetCommitKVStore(key); s != nil { - return s - } - m.store.MountStoreWithDB(key, sdk.StoreTypeIAVL, m.db) - if err := m.store.LoadLatestVersion(); err != nil { - panic(err) - } - return m.store.GetCommitKVStore(key) -} diff --git a/store/table/types.go b/store/table/types.go deleted file mode 100644 index 01496e764566..000000000000 --- a/store/table/types.go +++ /dev/null @@ -1,109 +0,0 @@ -/* -Package store/table is a convenient object to data store mapper. -*/ -package table - -import ( - "io" - "reflect" - - "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/types/errors" -) - -const tableCodespace = "table" - -var ( - ErrNotFound = errors.Register(tableCodespace, 100, "not found") - ErrIteratorDone = errors.Register(tableCodespace, 101, "iterator done") - ErrIteratorInvalid = errors.Register(tableCodespace, 102, "iterator invalid") - ErrType = errors.Register(tableCodespace, 110, "invalid type") - ErrUniqueConstraint = errors.Register(tableCodespace, 111, "unique constraint violation") - ErrArgument = errors.Register(tableCodespace, 112, "invalid argument") - ErrIndexKeyMaxLength = errors.Register(tableCodespace, 113, "index key exceeds max length") -) - -// Unique identifier of a persistent table. -type RowID []byte - -// Bytes returns raw bytes. -func (r RowID) Bytes() []byte { - return r -} - -// Validateable is an interface that ProtoMarshaler types can implement and is called on any orm save or update operation. -type Validateable interface { - // ValidateBasic is a sanity check on the data. Any error returned prevents create or updates. - ValidateBasic() error -} - -// Iterator allows iteration through a sequence of key value pairs -type Iterator interface { - // LoadNext loads the next value in the sequence into the pointer passed as dest and returns the key. If there - // are no more items the ErrIteratorDone error is returned - // The key is the rowID. - LoadNext(dest codec.ProtoMarshaler) (RowID, error) - // Close releases the iterator and should be called at the end of iteration - io.Closer -} - -// IndexKeyCodec defines the encoding/decoding methods for building/splitting index keys. -type IndexKeyCodec interface { - // BuildIndexKey encodes a searchable key and the target RowID. - BuildIndexKey(searchableKey []byte, rowID RowID) []byte - // StripRowID returns the RowID from the combined persistentIndexKey. It is the reverse operation to BuildIndexKey - // but with the searchableKey dropped. - StripRowID(persistentIndexKey []byte) RowID -} - -// Indexable types are used to setup new tables. -// This interface provides a set of functions that can be called by indexes to register and interact with the tables. -type Indexable interface { - RowGetter() RowGetter - IndexKeyCodec() IndexKeyCodec - AddAfterSaveInterceptor(interceptor AfterSaveInterceptor) - AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) -} - -// AfterSaveInterceptor defines a callback function to be called on Create + Update. -type AfterSaveInterceptor func(store sdk.KVStore, rowID RowID, newValue, oldValue codec.ProtoMarshaler) error - -// AfterDeleteInterceptor defines a callback function to be called on Delete operations. -type AfterDeleteInterceptor func(store sdk.KVStore, rowID RowID, value codec.ProtoMarshaler) error - -// RowGetter loads a persistent object by row ID into the destination object. The dest parameter must therefore be a pointer. -// Any implementation must return `ErrNotFound` when no object for the rowID exists -type RowGetter func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error - -// NewTypeSafeRowGetter returns a `RowGetter` with type check on the dest parameter. -func NewTypeSafeRowGetter(prefixKey byte, model reflect.Type, cdc codec.Codec) RowGetter { - return func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error { - if len(rowID) == 0 { - return errors.Wrap(ErrArgument, "key must not be nil") - } - if err := assertCorrectType(model, dest); err != nil { - return err - } - - pStore := prefix.NewStore(store, []byte{prefixKey}) - it := pStore.Iterator(PrefixRange(rowID)) - defer it.Close() - if !it.Valid() { - return ErrNotFound - } - return cdc.Unmarshal(it.Value(), dest) - } -} - -func assertCorrectType(model reflect.Type, obj codec.ProtoMarshaler) error { - tp := reflect.TypeOf(obj) - if tp.Kind() != reflect.Ptr { - return errors.Wrap(ErrType, "model destination must be a pointer") - } - if model != tp.Elem() { - return errors.Wrapf(ErrType, "can not use %T with this bucket", obj) - } - return nil -} diff --git a/store/table/types_test.go b/store/table/types_test.go deleted file mode 100644 index 48d184c70328..000000000000 --- a/store/table/types_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package table - -import ( - "reflect" - "testing" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/store/prefix" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestTypeSafeRowGetter(t *testing.T) { - storeKey := sdk.NewKVStoreKey("test") - ctx := NewMockContext() - const prefixKey = 0x2 - store := prefix.NewStore(ctx.KVStore(storeKey), []byte{prefixKey}) - md := testdata.TableModel{ - Id: 1, - Name: "some name", - } - bz, err := md.Marshal() - require.NoError(t, err) - store.Set(EncodeSequence(1), bz) - - specs := map[string]struct { - srcRowID RowID - srcModelType reflect.Type - expObj interface{} - expErr *errors.Error - }{ - "happy path": { - srcRowID: EncodeSequence(1), - srcModelType: reflect.TypeOf(testdata.TableModel{}), - expObj: md, - }, - "unknown rowID should return ErrNotFound": { - srcRowID: EncodeSequence(2), - srcModelType: reflect.TypeOf(testdata.TableModel{}), - expErr: ErrNotFound, - }, - "wrong type should cause ErrType": { - srcRowID: EncodeSequence(1), - srcModelType: reflect.TypeOf(testdata.Cat{}), - expErr: ErrType, - }, - "empty rowID not allowed": { - srcRowID: []byte{}, - srcModelType: reflect.TypeOf(testdata.TableModel{}), - expErr: ErrArgument, - }, - "nil rowID not allowed": { - srcModelType: reflect.TypeOf(testdata.TableModel{}), - expErr: ErrArgument, - }, - } - for msg, spec := range specs { - t.Run(msg, func(t *testing.T) { - interfaceRegistry := types.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(interfaceRegistry) - - getter := NewTypeSafeRowGetter(prefixKey, spec.srcModelType, cdc) - var loadedObj testdata.TableModel - - err := getter(ctx.KVStore(storeKey), spec.srcRowID, &loadedObj) - if spec.expErr != nil { - require.True(t, spec.expErr.Is(err), err) - return - } - require.NoError(t, err) - assert.Equal(t, spec.expObj, loadedObj) - }) - } -} From 5e715738d58e2547e2c8983a942526e1cc33e224 Mon Sep 17 00:00:00 2001 From: blushi Date: Wed, 11 Aug 2021 11:13:23 +0200 Subject: [PATCH 11/26] Add orm --- x/group/orm/index.go | 37 +++++ x/group/orm/index_key_codec.go | 66 +++++++++ x/group/orm/index_key_codec_test.go | 115 ++++++++++++++ x/group/orm/index_test.go | 39 +++++ x/group/orm/sequence.go | 81 ++++++++++ x/group/orm/sequence_test.go | 25 ++++ x/group/orm/spec/README.md | 17 +++ x/group/orm/table.go | 189 +++++++++++++++++++++++ x/group/orm/table_test.go | 222 ++++++++++++++++++++++++++++ x/group/orm/testsupport.go | 32 ++++ x/group/orm/types.go | 109 ++++++++++++++ x/group/orm/types_test.go | 78 ++++++++++ 12 files changed, 1010 insertions(+) create mode 100644 x/group/orm/index.go create mode 100644 x/group/orm/index_key_codec.go create mode 100644 x/group/orm/index_key_codec_test.go create mode 100644 x/group/orm/index_test.go create mode 100644 x/group/orm/sequence.go create mode 100644 x/group/orm/sequence_test.go create mode 100644 x/group/orm/spec/README.md create mode 100644 x/group/orm/table.go create mode 100644 x/group/orm/table_test.go create mode 100644 x/group/orm/testsupport.go create mode 100644 x/group/orm/types.go create mode 100644 x/group/orm/types_test.go diff --git a/x/group/orm/index.go b/x/group/orm/index.go new file mode 100644 index 000000000000..375a957f1989 --- /dev/null +++ b/x/group/orm/index.go @@ -0,0 +1,37 @@ +package table + +// PrefixRange turns a prefix into a (start, end) range. The start is the given prefix value and +// the end is calculated by adding 1 bit to the start value. Nil is not allowed as prefix. +// Example: []byte{1, 3, 4} becomes []byte{1, 3, 5} +// []byte{15, 42, 255, 255} becomes []byte{15, 43, 0, 0} +// +// In case of an overflow the end is set to nil. +// Example: []byte{255, 255, 255, 255} becomes nil +// +func PrefixRange(prefix []byte) ([]byte, []byte) { + if prefix == nil { + panic("nil key not allowed") + } + // special case: no prefix is whole range + if len(prefix) == 0 { + return nil, nil + } + + // copy the prefix and update last byte + end := make([]byte, len(prefix)) + copy(end, prefix) + l := len(end) - 1 + end[l]++ + + // wait, what if that overflowed?.... + for end[l] == 0 && l > 0 { + l-- + end[l]++ + } + + // okay, funny guy, you gave us FFF, no end to this range... + if l == 0 && end[0] == 0 { + end = nil + } + return prefix, end +} diff --git a/x/group/orm/index_key_codec.go b/x/group/orm/index_key_codec.go new file mode 100644 index 000000000000..def3ef409b87 --- /dev/null +++ b/x/group/orm/index_key_codec.go @@ -0,0 +1,66 @@ +package table + +// Max255DynamicLengthIndexKeyCodec works with up to 255 byte dynamic size RowIDs. +// They are encoded as `concat(searchableKey, rowID, len(rowID)[0])`. +type Max255DynamicLengthIndexKeyCodec struct{} + +// BuildIndexKey builds the index key by appending searchableKey with rowID and length int. +// The RowID length must not be greater than 255. +func (Max255DynamicLengthIndexKeyCodec) BuildIndexKey(searchableKey []byte, rowID RowID) []byte { + rowIDLen := len(rowID) + switch { + case rowIDLen == 0: + panic("Empty RowID") + case rowIDLen > 255: + panic("RowID exceeds max size") + } + + searchableKeyLen := len(searchableKey) + res := make([]byte, searchableKeyLen+rowIDLen+1) + copy(res, searchableKey) + copy(res[searchableKeyLen:], rowID) + res[searchableKeyLen+rowIDLen] = byte(rowIDLen) + return res +} + +// StripRowID returns the RowID from the combined persistentIndexKey. It is the reverse operation to BuildIndexKey +// but with the searchableKey and length int dropped. +func (Max255DynamicLengthIndexKeyCodec) StripRowID(persistentIndexKey []byte) RowID { + n := len(persistentIndexKey) + searchableKeyLen := persistentIndexKey[n-1] + return persistentIndexKey[n-int(searchableKeyLen)-1 : n-1] +} + +// FixLengthIndexKeyCodec expects the RowID to always have the same length with all entries. +// They are encoded as `concat(searchableKey, rowID)`. +type FixLengthIndexKeyCodec struct { + rowIDLength int +} + +// FixLengthIndexKeys is a constructor for FixLengthIndexKeyCodec. +func FixLengthIndexKeys(rowIDLength int) *FixLengthIndexKeyCodec { + return &FixLengthIndexKeyCodec{rowIDLength: rowIDLength} +} + +// BuildIndexKey builds the index key by appending searchableKey with rowID. +// The RowID length must not be greater than what is defined by rowIDLength in construction. +func (c FixLengthIndexKeyCodec) BuildIndexKey(searchableKey []byte, rowID RowID) []byte { + switch n := len(rowID); { + case n == 0: + panic("Empty RowID") + case n > c.rowIDLength: + panic("RowID exceeds max size") + } + n := len(searchableKey) + res := make([]byte, n+c.rowIDLength) + copy(res, searchableKey) + copy(res[n:], rowID) + return res +} + +// StripRowID returns the RowID from the combined persistentIndexKey. It is the reverse operation to BuildIndexKey +// but with the searchableKey dropped. +func (c FixLengthIndexKeyCodec) StripRowID(persistentIndexKey []byte) RowID { + n := len(persistentIndexKey) + return persistentIndexKey[n-c.rowIDLength:] +} diff --git a/x/group/orm/index_key_codec_test.go b/x/group/orm/index_key_codec_test.go new file mode 100644 index 000000000000..b3c88c82b9a3 --- /dev/null +++ b/x/group/orm/index_key_codec_test.go @@ -0,0 +1,115 @@ +package table + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestEncodeIndexKey(t *testing.T) { + specs := map[string]struct { + srcKey []byte + srcRowID RowID + enc IndexKeyCodec + expKey []byte + expPanic bool + }{ + "dynamic length example 1": { + srcKey: []byte{0x0, 0x1, 0x2}, + srcRowID: []byte{0x3, 0x4}, + enc: Max255DynamicLengthIndexKeyCodec{}, + expKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x2}, + }, + "dynamic length example 2": { + srcKey: []byte{0x0, 0x1}, + srcRowID: []byte{0x2, 0x3, 0x4}, + enc: Max255DynamicLengthIndexKeyCodec{}, + expKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x3}, + }, + "dynamic length max row ID": { + srcKey: []byte{0x0, 0x1}, + srcRowID: []byte(strings.Repeat("a", 255)), + enc: Max255DynamicLengthIndexKeyCodec{}, + expKey: append(append([]byte{0x0, 0x1}, []byte(strings.Repeat("a", 255))...), 0xff), + }, + "dynamic length panics with empty rowID": { + srcKey: []byte{0x0, 0x1}, + srcRowID: []byte{}, + enc: Max255DynamicLengthIndexKeyCodec{}, + expPanic: true, + }, + "dynamic length exceeds max row ID": { + srcKey: []byte{0x0, 0x1}, + srcRowID: []byte(strings.Repeat("a", 256)), + enc: Max255DynamicLengthIndexKeyCodec{}, + expPanic: true, + }, + "uint64 example": { + srcKey: []byte{0x0, 0x1, 0x2}, + srcRowID: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, + enc: FixLengthIndexKeys(8), + expKey: []byte{0x0, 0x1, 0x2, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, + }, + "uint64 panics with empty rowID": { + srcKey: []byte{0x0, 0x1}, + srcRowID: []byte{}, + enc: FixLengthIndexKeys(8), + expPanic: true, + }, + "uint64 exceeds max bytes in rowID": { + srcKey: []byte{0x0, 0x1}, + srcRowID: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}, + enc: FixLengthIndexKeys(8), + expPanic: true, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + if spec.expPanic { + require.Panics(t, + func() { + _ = spec.enc.BuildIndexKey(spec.srcKey, spec.srcRowID) + }) + return + } + got := spec.enc.BuildIndexKey(spec.srcKey, spec.srcRowID) + assert.Equal(t, spec.expKey, got) + }) + } +} +func TestDecodeIndexKey(t *testing.T) { + specs := map[string]struct { + srcKey []byte + enc IndexKeyCodec + expRowID RowID + }{ + "dynamic length example 1": { + srcKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x2}, + enc: Max255DynamicLengthIndexKeyCodec{}, + expRowID: []byte{0x3, 0x4}, + }, + "dynamic length example 2": { + srcKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x3}, + enc: Max255DynamicLengthIndexKeyCodec{}, + expRowID: []byte{0x2, 0x3, 0x4}, + }, + "dynamic length max row ID": { + srcKey: append(append([]byte{0x0, 0x1}, []byte(strings.Repeat("a", 255))...), 0xff), + enc: Max255DynamicLengthIndexKeyCodec{}, + expRowID: []byte(strings.Repeat("a", 255)), + }, + "uint64 example": { + srcKey: []byte{0x0, 0x1, 0x2, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, + expRowID: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, + enc: FixLengthIndexKeys(8), + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + gotRow := spec.enc.StripRowID(spec.srcKey) + assert.Equal(t, spec.expRowID, gotRow) + }) + } +} diff --git a/x/group/orm/index_test.go b/x/group/orm/index_test.go new file mode 100644 index 000000000000..b512fd246cc4 --- /dev/null +++ b/x/group/orm/index_test.go @@ -0,0 +1,39 @@ +package table + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPrefixRange(t *testing.T) { + cases := map[string]struct { + src []byte + expStart []byte + expEnd []byte + expPanic bool + }{ + "normal": {src: []byte{1, 3, 4}, expStart: []byte{1, 3, 4}, expEnd: []byte{1, 3, 5}}, + "normal short": {src: []byte{79}, expStart: []byte{79}, expEnd: []byte{80}}, + "empty case": {src: []byte{}}, + "roll-over example 1": {src: []byte{17, 28, 255}, expStart: []byte{17, 28, 255}, expEnd: []byte{17, 29, 0}}, + "roll-over example 2": {src: []byte{15, 42, 255, 255}, expStart: []byte{15, 42, 255, 255}, expEnd: []byte{15, 43, 0, 0}}, + "pathological roll-over": {src: []byte{255, 255, 255, 255}, expStart: []byte{255, 255, 255, 255}}, + "nil prohibited": {expPanic: true}, + } + + for testName, tc := range cases { + t.Run(testName, func(t *testing.T) { + if tc.expPanic { + require.Panics(t, func() { + PrefixRange(tc.src) + }) + return + } + start, end := PrefixRange(tc.src) + assert.Equal(t, tc.expStart, start) + assert.Equal(t, tc.expEnd, end) + }) + } +} diff --git a/x/group/orm/sequence.go b/x/group/orm/sequence.go new file mode 100644 index 000000000000..80129e766d10 --- /dev/null +++ b/x/group/orm/sequence.go @@ -0,0 +1,81 @@ +package table + +import ( + "encoding/binary" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/errors" +) + +// sequenceStorageKey is a fix key to read/ write data on the storage layer +var sequenceStorageKey = []byte{0x1} + +// sequence is a persistent unique key generator based on a counter. +type Sequence struct { + prefix byte +} + +func NewSequence(prefix byte) Sequence { + return Sequence{ + prefix: prefix, + } +} + +// NextVal increments and persists the counter by one and returns the value. +func (s Sequence) NextVal(store sdk.KVStore) uint64 { + pStore := prefix.NewStore(store, []byte{s.prefix}) + v := pStore.Get(sequenceStorageKey) + seq := DecodeSequence(v) + seq++ + pStore.Set(sequenceStorageKey, EncodeSequence(seq)) + return seq +} + +// CurVal returns the last value used. 0 if none. +func (s Sequence) CurVal(store sdk.KVStore) uint64 { + pStore := prefix.NewStore(store, []byte{s.prefix}) + v := pStore.Get(sequenceStorageKey) + return DecodeSequence(v) +} + +// PeekNextVal returns the CurVal + increment step. Not persistent. +func (s Sequence) PeekNextVal(store sdk.KVStore) uint64 { + pStore := prefix.NewStore(store, []byte{s.prefix}) + v := pStore.Get(sequenceStorageKey) + return DecodeSequence(v) + 1 +} + +// InitVal sets the start value for the sequence. It must be called only once on an empty DB. +// Otherwise an error is returned when the key exists. The given start value is stored as current +// value. +// +// It is recommended to call this method only for a sequence start value other than `1` as the +// method consumes unnecessary gas otherwise. A scenario would be an import from genesis. +func (s Sequence) InitVal(store sdk.KVStore, seq uint64) error { + pStore := prefix.NewStore(store, []byte{s.prefix}) + if pStore.Has(sequenceStorageKey) { + return errors.Wrap(ErrUniqueConstraint, "already initialized") + } + pStore.Set(sequenceStorageKey, EncodeSequence(seq)) + return nil +} + +// DecodeSequence converts the binary representation into an Uint64 value. +func DecodeSequence(bz []byte) uint64 { + if bz == nil { + return 0 + } + val := binary.BigEndian.Uint64(bz) + return val +} + +// EncodedSeqLength number of bytes used for the binary representation of a sequence value. +const EncodedSeqLength = 8 + +// EncodeSequence converts the sequence value into the binary representation. +func EncodeSequence(val uint64) []byte { + bz := make([]byte, EncodedSeqLength) + binary.BigEndian.PutUint64(bz, val) + return bz +} diff --git a/x/group/orm/sequence_test.go b/x/group/orm/sequence_test.go new file mode 100644 index 000000000000..eb4c4e77340c --- /dev/null +++ b/x/group/orm/sequence_test.go @@ -0,0 +1,25 @@ +package table + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" +) + +func TestSequenceIncrements(t *testing.T) { + ctx := NewMockContext() + store := ctx.KVStore(sdk.NewKVStoreKey("test")) + + seq := NewSequence(0x1) + var i uint64 + for i = 1; i < 10; i++ { + autoID := seq.NextVal(store) + assert.Equal(t, i, autoID) + assert.Equal(t, i, seq.CurVal(store)) + } + + seq = NewSequence(0x1) + assert.Equal(t, uint64(10), seq.PeekNextVal(store)) + assert.Equal(t, uint64(9), seq.CurVal(store)) +} diff --git a/x/group/orm/spec/README.md b/x/group/orm/spec/README.md new file mode 100644 index 000000000000..015df77c8195 --- /dev/null +++ b/x/group/orm/spec/README.md @@ -0,0 +1,17 @@ +## Abstract + +The orm package provides a framework for creating relational database tables with primary and secondary keys. + +```go +type Table struct { + model reflect.Type + prefix byte + afterSave []AfterSaveInterceptor + afterDelete []AfterDeleteInterceptor + cdc codec.Codec +} +``` + +Such table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling. +In the prefix store, entities are stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter or dynamic size bytes. +Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store. \ No newline at end of file diff --git a/x/group/orm/table.go b/x/group/orm/table.go new file mode 100644 index 000000000000..a038634c9a2b --- /dev/null +++ b/x/group/orm/table.go @@ -0,0 +1,189 @@ +package table + +import ( + "reflect" + + "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/types/errors" +) + +var _ Indexable = &Builder{} + +type Builder struct { + model reflect.Type + prefixData byte + indexKeyCodec IndexKeyCodec + afterSave []AfterSaveInterceptor + afterDelete []AfterDeleteInterceptor + cdc codec.Codec +} + +// NewTableBuilder creates a builder to setup a Table object. +func NewTableBuilder(prefixData byte, model codec.ProtoMarshaler, idxKeyCodec IndexKeyCodec, cdc codec.Codec) *Builder { + if model == nil { + panic("Model must not be nil") + } + if idxKeyCodec == nil { + panic("IndexKeyCodec must not be nil") + } + tp := reflect.TypeOf(model) + if tp.Kind() == reflect.Ptr { + tp = tp.Elem() + } + return &Builder{ + prefixData: prefixData, + model: tp, + indexKeyCodec: idxKeyCodec, + cdc: cdc, + } +} + +func (a Builder) IndexKeyCodec() IndexKeyCodec { + return a.indexKeyCodec +} + +// RowGetter returns a type safe RowGetter. +func (a Builder) RowGetter() RowGetter { + return NewTypeSafeRowGetter(a.prefixData, a.model, a.cdc) +} + +// Build creates a new Table object. +func (a Builder) Build() Table { + return Table{ + model: a.model, + prefix: a.prefixData, + afterSave: a.afterSave, + afterDelete: a.afterDelete, + cdc: a.cdc, + } +} + +// AddAfterSaveInterceptor can be used to register a callback function that is executed after an object is created and/or updated. +func (a *Builder) AddAfterSaveInterceptor(interceptor AfterSaveInterceptor) { + a.afterSave = append(a.afterSave, interceptor) +} + +// AddAfterDeleteInterceptor can be used to register a callback function that is executed after an object is deleted. +func (a *Builder) AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) { + a.afterDelete = append(a.afterDelete, interceptor) +} + +// Table is the high level object for storage mapper functionality. Persistent entities are stored by an unique identifier +// called `RowID`. +// The Table struct does not enforce uniqueness of the `RowID` but expects this to be satisfied by the callers and conditions +// to optimize Gas usage. +type Table struct { + model reflect.Type + prefix byte + afterSave []AfterSaveInterceptor + afterDelete []AfterDeleteInterceptor + cdc codec.Codec +} + +// Create persists the given object under the rowID key. It does not check if the +// key already exists. Any caller must either make sure that this contract is fulfilled +// by providing a universal unique ID or sequence that is guaranteed to not exist yet or +// by checking the state via `Has` function before. +// +// Create iterates though the registered callbacks and may add secondary index keys by them. +func (a Table) Create(store sdk.KVStore, rowID RowID, obj codec.ProtoMarshaler) error { + if err := assertCorrectType(a.model, obj); err != nil { + return err + } + if err := assertValid(obj); err != nil { + return err + } + pStore := prefix.NewStore(store, []byte{a.prefix}) + v, err := a.cdc.Marshal(obj) + if err != nil { + return errors.Wrapf(err, "failed to serialize %T", obj) + } + pStore.Set(rowID, v) + for i, itc := range a.afterSave { + if err := itc(store, rowID, obj, nil); err != nil { + return errors.Wrapf(err, "interceptor %d failed", i) + } + } + return nil +} + +// Update updates the given object under the rowID key. It expects the key to exist already +// and fails with an `ErrNotFound` otherwise. Any caller must therefore make sure that this contract +// is fulfilled. Parameters must not be nil. +// +// Update iterates though the registered callbacks and may add or remove secondary index keys by them. +func (a Table) Update(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler) error { + if err := assertCorrectType(a.model, newValue); err != nil { + return err + } + if err := assertValid(newValue); err != nil { + return err + } + + pStore := prefix.NewStore(store, []byte{a.prefix}) + var oldValue = reflect.New(a.model).Interface().(codec.ProtoMarshaler) + + if err := a.GetOne(store, rowID, oldValue); err != nil { + return errors.Wrap(err, "load old value") + } + newValueEncoded, err := a.cdc.Marshal(newValue) + if err != nil { + return errors.Wrapf(err, "failed to serialize %T", newValue) + } + + pStore.Set(rowID, newValueEncoded) + for i, itc := range a.afterSave { + if err := itc(store, rowID, newValue, oldValue); err != nil { + return errors.Wrapf(err, "interceptor %d failed", i) + } + } + return nil +} + +func assertValid(obj codec.ProtoMarshaler) error { + if v, ok := obj.(Validateable); ok { + if err := v.ValidateBasic(); err != nil { + return err + } + } + return nil +} + +// Delete removes the object under the rowID key. It expects the key to exists already +// and fails with a `ErrNotFound` otherwise. Any caller must therefore make sure that this contract +// is fulfilled. +// +// Delete iterates though the registered callbacks and removes secondary index keys by them. +func (a Table) Delete(store sdk.KVStore, rowID RowID) error { + pStore := prefix.NewStore(store, []byte{a.prefix}) + + var oldValue = reflect.New(a.model).Interface().(codec.ProtoMarshaler) + if err := a.GetOne(store, rowID, oldValue); err != nil { + return errors.Wrap(err, "load old value") + } + pStore.Delete(rowID) + + for i, itc := range a.afterDelete { + if err := itc(store, rowID, oldValue); err != nil { + return errors.Wrapf(err, "delete interceptor %d failed", i) + } + } + return nil +} + +// Has checks if a key exists. Panics on nil key. +func (a Table) Has(store sdk.KVStore, rowID RowID) bool { + Store := prefix.NewStore(store, []byte{a.prefix}) + it := Store.Iterator(PrefixRange(rowID)) + defer it.Close() + return it.Valid() +} + +// GetOne load the object persisted for the given RowID into the dest parameter. +// If none exists `ErrNotFound` is returned instead. Parameters must not be nil. +func (a Table) GetOne(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error { + x := NewTypeSafeRowGetter(a.prefix, a.model, a.cdc) + return x(store, rowID, dest) +} diff --git a/x/group/orm/table_test.go b/x/group/orm/table_test.go new file mode 100644 index 000000000000..3f694893114f --- /dev/null +++ b/x/group/orm/table_test.go @@ -0,0 +1,222 @@ +package table + +import ( + "fmt" + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewTableBuilder(t *testing.T) { + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + const anyPrefix = 0x10 + + specs := map[string]struct { + model codec.ProtoMarshaler + idxKeyCodec IndexKeyCodec + expPanic bool + }{ + "happy path": { + model: &testdata.TableModel{}, + idxKeyCodec: FixLengthIndexKeys(EncodedSeqLength), + }, + "nil model": { + idxKeyCodec: FixLengthIndexKeys(EncodedSeqLength), + expPanic: true, + }, + "nil idxKeyCodec": { + model: &testdata.TableModel{}, + expPanic: true, + }, + } + + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + f := func() { + NewTableBuilder(anyPrefix, spec.model, spec.idxKeyCodec, cdc) + } + if spec.expPanic { + require.Panics(t, f) + } else { + require.NotPanics(t, f) + } + }) + } +} + +func TestCreate(t *testing.T) { + specs := map[string]struct { + src codec.ProtoMarshaler + expErr *errors.Error + }{ + "happy path": { + src: &testdata.TableModel{ + Id: 1, + Name: "some name", + }, + }, + "wrong type": { + src: &testdata.Cat{ + Moniker: "cat moniker", + Lives: 10, + }, + expErr: ErrType, + }, + "model validation fails": { + src: &testdata.TableModel{ + Id: 1, + Name: "", + }, + expErr: testdata.ErrTest, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + + ctx := NewMockContext() + store := ctx.KVStore(sdk.NewKVStoreKey("test")) + + const anyPrefix = 0x10 + tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) + myTable := tableBuilder.Build() + + err := myTable.Create(store, EncodeSequence(1), spec.src) + + require.True(t, spec.expErr.Is(err), err) + shouldExists := spec.expErr == nil + assert.Equal(t, shouldExists, myTable.Has(store, EncodeSequence(1)), fmt.Sprintf("expected %v", shouldExists)) + + // then + var loaded testdata.TableModel + err = myTable.GetOne(store, EncodeSequence(1), &loaded) + if spec.expErr != nil { + require.True(t, ErrNotFound.Is(err)) + return + } + require.NoError(t, err) + assert.Equal(t, spec.src, &loaded) + }) + } +} + +func TestUpdate(t *testing.T) { + specs := map[string]struct { + src codec.ProtoMarshaler + expErr *errors.Error + }{ + "happy path": { + src: &testdata.TableModel{ + Id: 1, + Name: "some name", + }, + }, + "wrong type": { + src: &testdata.Cat{ + Moniker: "cat moniker", + Lives: 10, + }, + expErr: ErrType, + }, + "model validation fails": { + src: &testdata.TableModel{ + Id: 1, + Name: "", + }, + expErr: testdata.ErrTest, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + + ctx := NewMockContext() + store := ctx.KVStore(sdk.NewKVStoreKey("test")) + + const anyPrefix = 0x10 + tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) + myTable := tableBuilder.Build() + + initValue := testdata.TableModel{ + Id: 1, + Name: "old name", + } + + err := myTable.Create(store, EncodeSequence(1), &initValue) + require.NoError(t, err) + + // when + err = myTable.Update(store, EncodeSequence(1), spec.src) + require.True(t, spec.expErr.Is(err), "got ", err) + + // then + var loaded testdata.TableModel + require.NoError(t, myTable.GetOne(store, EncodeSequence(1), &loaded)) + if spec.expErr == nil { + assert.Equal(t, spec.src, &loaded) + } else { + assert.Equal(t, initValue, loaded) + } + }) + } +} + +func TestDelete(t *testing.T) { + specs := map[string]struct { + rowId []byte + expErr *errors.Error + }{ + "happy path": { + rowId: EncodeSequence(1), + }, + "not found": { + rowId: []byte("not-found"), + expErr: ErrNotFound, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + + ctx := NewMockContext() + store := ctx.KVStore(sdk.NewKVStoreKey("test")) + + const anyPrefix = 0x10 + tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) + myTable := tableBuilder.Build() + + initValue := testdata.TableModel{ + Id: 1, + Name: "some name", + } + + err := myTable.Create(store, EncodeSequence(1), &initValue) + require.NoError(t, err) + + // when + err = myTable.Delete(store, spec.rowId) + require.True(t, spec.expErr.Is(err), "got ", err) + + // then + var loaded testdata.TableModel + if spec.expErr == ErrNotFound { + require.NoError(t, myTable.GetOne(store, EncodeSequence(1), &loaded)) + assert.Equal(t, initValue, loaded) + } else { + err := myTable.GetOne(store, EncodeSequence(1), &loaded) + require.Error(t, err) + require.Equal(t, err, ErrNotFound) + } + }) + } +} diff --git a/x/group/orm/testsupport.go b/x/group/orm/testsupport.go new file mode 100644 index 000000000000..60878101f654 --- /dev/null +++ b/x/group/orm/testsupport.go @@ -0,0 +1,32 @@ +package table + +import ( + "github.com/cosmos/cosmos-sdk/store" + "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + dbm "github.com/tendermint/tm-db" +) + +type MockContext struct { + db *dbm.MemDB + store types.CommitMultiStore +} + +func NewMockContext() *MockContext { + db := dbm.NewMemDB() + return &MockContext{ + db: dbm.NewMemDB(), + store: store.NewCommitMultiStore(db), + } +} + +func (m MockContext) KVStore(key sdk.StoreKey) sdk.KVStore { + if s := m.store.GetCommitKVStore(key); s != nil { + return s + } + m.store.MountStoreWithDB(key, sdk.StoreTypeIAVL, m.db) + if err := m.store.LoadLatestVersion(); err != nil { + panic(err) + } + return m.store.GetCommitKVStore(key) +} diff --git a/x/group/orm/types.go b/x/group/orm/types.go new file mode 100644 index 000000000000..01496e764566 --- /dev/null +++ b/x/group/orm/types.go @@ -0,0 +1,109 @@ +/* +Package store/table is a convenient object to data store mapper. +*/ +package table + +import ( + "io" + "reflect" + + "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/types/errors" +) + +const tableCodespace = "table" + +var ( + ErrNotFound = errors.Register(tableCodespace, 100, "not found") + ErrIteratorDone = errors.Register(tableCodespace, 101, "iterator done") + ErrIteratorInvalid = errors.Register(tableCodespace, 102, "iterator invalid") + ErrType = errors.Register(tableCodespace, 110, "invalid type") + ErrUniqueConstraint = errors.Register(tableCodespace, 111, "unique constraint violation") + ErrArgument = errors.Register(tableCodespace, 112, "invalid argument") + ErrIndexKeyMaxLength = errors.Register(tableCodespace, 113, "index key exceeds max length") +) + +// Unique identifier of a persistent table. +type RowID []byte + +// Bytes returns raw bytes. +func (r RowID) Bytes() []byte { + return r +} + +// Validateable is an interface that ProtoMarshaler types can implement and is called on any orm save or update operation. +type Validateable interface { + // ValidateBasic is a sanity check on the data. Any error returned prevents create or updates. + ValidateBasic() error +} + +// Iterator allows iteration through a sequence of key value pairs +type Iterator interface { + // LoadNext loads the next value in the sequence into the pointer passed as dest and returns the key. If there + // are no more items the ErrIteratorDone error is returned + // The key is the rowID. + LoadNext(dest codec.ProtoMarshaler) (RowID, error) + // Close releases the iterator and should be called at the end of iteration + io.Closer +} + +// IndexKeyCodec defines the encoding/decoding methods for building/splitting index keys. +type IndexKeyCodec interface { + // BuildIndexKey encodes a searchable key and the target RowID. + BuildIndexKey(searchableKey []byte, rowID RowID) []byte + // StripRowID returns the RowID from the combined persistentIndexKey. It is the reverse operation to BuildIndexKey + // but with the searchableKey dropped. + StripRowID(persistentIndexKey []byte) RowID +} + +// Indexable types are used to setup new tables. +// This interface provides a set of functions that can be called by indexes to register and interact with the tables. +type Indexable interface { + RowGetter() RowGetter + IndexKeyCodec() IndexKeyCodec + AddAfterSaveInterceptor(interceptor AfterSaveInterceptor) + AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) +} + +// AfterSaveInterceptor defines a callback function to be called on Create + Update. +type AfterSaveInterceptor func(store sdk.KVStore, rowID RowID, newValue, oldValue codec.ProtoMarshaler) error + +// AfterDeleteInterceptor defines a callback function to be called on Delete operations. +type AfterDeleteInterceptor func(store sdk.KVStore, rowID RowID, value codec.ProtoMarshaler) error + +// RowGetter loads a persistent object by row ID into the destination object. The dest parameter must therefore be a pointer. +// Any implementation must return `ErrNotFound` when no object for the rowID exists +type RowGetter func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error + +// NewTypeSafeRowGetter returns a `RowGetter` with type check on the dest parameter. +func NewTypeSafeRowGetter(prefixKey byte, model reflect.Type, cdc codec.Codec) RowGetter { + return func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error { + if len(rowID) == 0 { + return errors.Wrap(ErrArgument, "key must not be nil") + } + if err := assertCorrectType(model, dest); err != nil { + return err + } + + pStore := prefix.NewStore(store, []byte{prefixKey}) + it := pStore.Iterator(PrefixRange(rowID)) + defer it.Close() + if !it.Valid() { + return ErrNotFound + } + return cdc.Unmarshal(it.Value(), dest) + } +} + +func assertCorrectType(model reflect.Type, obj codec.ProtoMarshaler) error { + tp := reflect.TypeOf(obj) + if tp.Kind() != reflect.Ptr { + return errors.Wrap(ErrType, "model destination must be a pointer") + } + if model != tp.Elem() { + return errors.Wrapf(ErrType, "can not use %T with this bucket", obj) + } + return nil +} diff --git a/x/group/orm/types_test.go b/x/group/orm/types_test.go new file mode 100644 index 000000000000..48d184c70328 --- /dev/null +++ b/x/group/orm/types_test.go @@ -0,0 +1,78 @@ +package table + +import ( + "reflect" + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/store/prefix" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTypeSafeRowGetter(t *testing.T) { + storeKey := sdk.NewKVStoreKey("test") + ctx := NewMockContext() + const prefixKey = 0x2 + store := prefix.NewStore(ctx.KVStore(storeKey), []byte{prefixKey}) + md := testdata.TableModel{ + Id: 1, + Name: "some name", + } + bz, err := md.Marshal() + require.NoError(t, err) + store.Set(EncodeSequence(1), bz) + + specs := map[string]struct { + srcRowID RowID + srcModelType reflect.Type + expObj interface{} + expErr *errors.Error + }{ + "happy path": { + srcRowID: EncodeSequence(1), + srcModelType: reflect.TypeOf(testdata.TableModel{}), + expObj: md, + }, + "unknown rowID should return ErrNotFound": { + srcRowID: EncodeSequence(2), + srcModelType: reflect.TypeOf(testdata.TableModel{}), + expErr: ErrNotFound, + }, + "wrong type should cause ErrType": { + srcRowID: EncodeSequence(1), + srcModelType: reflect.TypeOf(testdata.Cat{}), + expErr: ErrType, + }, + "empty rowID not allowed": { + srcRowID: []byte{}, + srcModelType: reflect.TypeOf(testdata.TableModel{}), + expErr: ErrArgument, + }, + "nil rowID not allowed": { + srcModelType: reflect.TypeOf(testdata.TableModel{}), + expErr: ErrArgument, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + + getter := NewTypeSafeRowGetter(prefixKey, spec.srcModelType, cdc) + var loadedObj testdata.TableModel + + err := getter(ctx.KVStore(storeKey), spec.srcRowID, &loadedObj) + if spec.expErr != nil { + require.True(t, spec.expErr.Is(err), err) + return + } + require.NoError(t, err) + assert.Equal(t, spec.expObj, loadedObj) + }) + } +} From 0151b74772d2bcf1650b97467d34afc59cbfd531 Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 8 Oct 2021 11:11:15 +0200 Subject: [PATCH 12/26] Update orm with latest changes --- container/main/graph.svg | 234 ++++++++++++++++++++++++ container/main/main.go | 127 +++++++++++++ x/group/go.mod | 10 +- x/group/go.sum | 249 ++++++++++++++++++++++++++ x/group/orm/index.go | 2 +- x/group/orm/index_key_codec.go | 66 ------- x/group/orm/index_key_codec_test.go | 115 ------------ x/group/orm/index_property_test.go | 60 +++++++ x/group/orm/index_test.go | 2 +- x/group/orm/sequence.go | 2 +- x/group/orm/sequence_property_test.go | 68 +++++++ x/group/orm/sequence_test.go | 13 +- x/group/orm/spec/README.md | 6 +- x/group/orm/table.go | 166 +++++++++-------- x/group/orm/table_test.go | 69 ++++--- x/group/orm/testsupport.go | 2 +- x/group/orm/types.go | 28 ++- x/group/orm/types_test.go | 2 +- 18 files changed, 898 insertions(+), 323 deletions(-) create mode 100644 container/main/graph.svg create mode 100644 container/main/main.go delete mode 100644 x/group/orm/index_key_codec.go delete mode 100644 x/group/orm/index_key_codec_test.go create mode 100644 x/group/orm/index_property_test.go create mode 100644 x/group/orm/sequence_property_test.go diff --git a/container/main/graph.svg b/container/main/graph.svg new file mode 100644 index 000000000000..8c374f8e8997 --- /dev/null +++ b/container/main/graph.svg @@ -0,0 +1,234 @@ + + + + + + + + +cluster_b + +Scope: b + + +cluster_a + +Scope: a + + + + +[]main.Command + +[]main.Command + + + +main.main.func1 + +main.main.func1 + + + +[]main.Command->main.main.func1 + + + + + + +map[string]main.Handler + +map[string]main.Handler + + + +map[string]main.Handler->main.main.func1 + + + + + +main.ProvideKVStoreKey + +main.ProvideKVStoreKey + + + +main.KVStoreKey + +main.KVStoreKey + + + +main.ProvideKVStoreKey->main.KVStoreKey + + + + + +container.Scope + +container.Scope + + + +container.Scope->main.ProvideKVStoreKey + + + + + +main.ProvideModuleKey + +main.ProvideModuleKey + + + +container.Scope->main.ProvideModuleKey + + + + + +main.ProvideMsgClientA + +main.ProvideMsgClientA + + + +container.Scope->main.ProvideMsgClientA + + + + + +main.ModuleB.Provide + +main.ModuleB.Provide + + + +container.Scope->main.ModuleB.Provide + + + + + +main.ModuleA.Provide + +main.ModuleA.Provide + + + +main.KVStoreKey->main.ModuleA.Provide + + + + + +main.KVStoreKey->main.ModuleB.Provide + + + + + +main.ModuleKey + +main.ModuleKey + + + +main.ProvideModuleKey->main.ModuleKey + + + + + +main.ModuleKey->main.ProvideMsgClientA + + + + + +main.MsgClientA + +main.MsgClientA + + + +main.ProvideMsgClientA->main.MsgClientA + + + + + +main.MsgClientA->main.ModuleB.Provide + + + + + +main.ModuleA.Provide->[]main.Command + + + + + +main.ModuleA.Provide->map[string]main.Handler + + + + + +main.KeeperA + +main.KeeperA + + + +main.ModuleA.Provide->main.KeeperA + + + + + +main.KeeperA->main.main.func1 + + + + + +main.ModuleB.Provide->[]main.Command + + + + + +main.ModuleB.Provide->map[string]main.Handler + + + + + +main.KeeperB + +main.KeeperB + + + +main.ModuleB.Provide->main.KeeperB + + + + + +main.KeeperB->main.main.func1 + + + + + diff --git a/container/main/main.go b/container/main/main.go new file mode 100644 index 000000000000..d86eab0911f6 --- /dev/null +++ b/container/main/main.go @@ -0,0 +1,127 @@ +package main + +import ( + "reflect" + + "github.com/cosmos/cosmos-sdk/container" +) + +type KVStoreKey struct { + name string +} + +type ModuleKey string + +type MsgClientA struct { + key ModuleKey +} + +type KeeperA struct { + key KVStoreKey +} + +type KeeperB struct { + key KVStoreKey + msgClientA MsgClientA +} + +type Handler struct { + Handle func() +} + +type Command struct { + Run func() +} + +func ProvideKVStoreKey(scope container.Scope) KVStoreKey { + return KVStoreKey{name: scope.Name()} +} + +func ProvideModuleKey(scope container.Scope) (ModuleKey, error) { + return ModuleKey(scope.Name()), nil +} + +func ProvideMsgClientA(_ container.Scope, key ModuleKey) MsgClientA { + return MsgClientA{key} +} + +type ModuleA struct{} + +func (ModuleA) Provide(key KVStoreKey) (KeeperA, Handler, Command) { + return KeeperA{key}, Handler{}, Command{} +} + +type ModuleB struct{} + +type BDependencies struct { + container.In + + Key KVStoreKey + A MsgClientA +} + +type BProvides struct { + container.Out + + KeeperB KeeperB + Commands []Command +} + +func (ModuleB) Provide(dependencies BDependencies, _ container.Scope) (BProvides, Handler, error) { + return BProvides{ + KeeperB: KeeperB{ + key: dependencies.Key, + msgClientA: dependencies.A, + }, + Commands: []Command{{}, {}}, + }, Handler{}, nil +} + +func main() { + container.Run( + func(handlers map[string]Handler, commands []Command, a KeeperA, b KeeperB) { + // require.Len(t, handlers, 2) + // require.Equal(t, Handler{}, handlers["a"]) + // require.Equal(t, Handler{}, handlers["b"]) + // require.Len(t, commands, 3) + // require.Equal(t, KeeperA{ + // key: KVStoreKey{name: "a"}, + // }, a) + // require.Equal(t, KeeperB{ + // key: KVStoreKey{name: "b"}, + // msgClientA: MsgClientA{ + // key: "b", + // }, + // }, b) + }, + container.AutoGroupTypes(reflect.TypeOf(Command{})), + container.OnePerScopeTypes(reflect.TypeOf(Handler{})), + container.Provide( + ProvideKVStoreKey, + ProvideModuleKey, + ProvideMsgClientA, + ), + container.ProvideWithScope("a", wrapMethod0(ModuleA{})), + container.ProvideWithScope("b", wrapMethod0(ModuleB{})), + container.Visualizer(func(g string) { + }), + container.LogVisualizer(), + container.FileVisualizer("graph", "svg"), + container.StdoutLogger(), + ) +} + +func wrapMethod0(module interface{}) interface{} { + methodFn := reflect.TypeOf(module).Method(0).Func.Interface() + ctrInfo, err := container.ExtractProviderDescriptor(methodFn) + if err != nil { + panic(err) + } + + ctrInfo.Inputs = ctrInfo.Inputs[1:] + fn := ctrInfo.Fn + ctrInfo.Fn = func(values []reflect.Value) ([]reflect.Value, error) { + return fn(append([]reflect.Value{reflect.ValueOf(module)}, values...)) + } + return ctrInfo +} diff --git a/x/group/go.mod b/x/group/go.mod index fbb2b0c8c3eb..51d5548064f5 100644 --- a/x/group/go.mod +++ b/x/group/go.mod @@ -8,7 +8,7 @@ require ( github.com/gogo/protobuf v1.3.3 github.com/regen-network/cosmos-proto v0.3.1 github.com/stretchr/testify v1.7.0 - google.golang.org/grpc v1.40.0 + google.golang.org/grpc v1.41.0 google.golang.org/protobuf v1.27.1 pgregory.net/rapid v0.4.7 ) @@ -27,11 +27,9 @@ require ( github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25 // indirect - github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/go-kit/kit v0.10.0 // indirect github.com/go-logfmt/logfmt v0.5.0 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 // indirect github.com/google/btree v1.0.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/gtank/merlin v0.1.1 // indirect @@ -44,8 +42,6 @@ require ( github.com/magiconair/properties v1.8.5 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect - github.com/mitchellh/mapstructure v1.4.1 // indirect - github.com/pelletier/go-toml v1.9.3 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -59,7 +55,6 @@ require ( github.com/spf13/cobra v1.2.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.8.1 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect @@ -67,12 +62,9 @@ require ( github.com/tendermint/tendermint v0.34.13 // indirect github.com/tendermint/tm-db v0.6.4 // indirect go.etcd.io/bbolt v1.3.5 // indirect - golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f // indirect golang.org/x/sys v0.0.0-20210903071746-97244b99971b // indirect golang.org/x/text v0.3.6 // indirect - google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect - gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/x/group/go.sum b/x/group/go.sum index 763a2e850bdf..4b750b372775 100644 --- a/x/group/go.sum +++ b/x/group/go.sum @@ -18,6 +18,11 @@ cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmW cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -27,6 +32,7 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -38,9 +44,24 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-beta.2 h1:/BZRNzm8N4K4eWfK28dL4yescorxtO7YG1yun8fy+pI= +filippo.io/edwards25519 v1.0.0-beta.2/go.mod h1:X+pm78QAUPtFLi1z9PYIlS/bdDnvbCOGKtZ+ACWEf7o= github.com/99designs/keyring v1.1.6 h1:kVDC2uCgVwecxCk+9zoCt2uEL6dt+dfVzMvGgnVcIuM= +github.com/99designs/keyring v1.1.6/go.mod h1:16e0ds7LGQQcT59QqkTg72Hh5ShM51Byv5PEmW6uoRU= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= @@ -57,10 +78,13 @@ github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/Workiva/go-datastructures v1.0.52 h1:PLSK6pwn8mYdaoaCZEMsXBpBotr4HHn9abU0yMQt0NI= github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= +github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20201201074141-dd0ecada1be6/go.mod h1:eSYp2T6f0apnuW8TzhV3f6Aff2SE8Dwio++U4ha4yEM= github.com/adlio/schema v1.1.13/go.mod h1:L5Z7tw+7lRK1Fnpi/LT/ooCP1elkXn0krMWBQHUhEDE= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= @@ -69,17 +93,21 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -91,11 +119,16 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= +github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0= +github.com/btcsuite/btcd v0.0.0-20190315201642-aa6e0f35703c/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= @@ -110,6 +143,7 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= @@ -122,12 +156,14 @@ github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go v0.6.10 h1:rgHD/nHjxLh0lMEdfGDqpTtlvtSBwULqrrZ2qPdNaCM= +github.com/coinbase/rosetta-sdk-go v0.6.10/go.mod h1:J/JFMsfcePrjJZkwQFLh+hJErkAmdm9Iyy3D5Y0LfXo= github.com/confio/ics23/go v0.0.0-20200817220745-f173e6211efb/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= github.com/confio/ics23/go v0.6.3/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= github.com/confio/ics23/go v0.6.6 h1:pkOy18YxxJ/r0XFDCnrl4Bjv6h4LkBSpLS6F38mrKL8= @@ -146,26 +182,35 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cosmos/cosmos-proto v0.0.0-20210914142853-23ed61ac79ce/go.mod h1:g2Q3cd94kOBVRAv7ahdtO27yUc4cpNuHGnI40qanl1k= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= +github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/iavl v0.15.0-rc3.0.20201009144442-230e9bdf52cd/go.mod h1:3xOIaNNX19p0QrX0VqWa6voPRoJRGGYtny+DH8NEPvE= github.com/cosmos/iavl v0.15.0-rc5/go.mod h1:WqoPL9yPTQ85QBMT45OOUzPxG/U/JcJoN7uMjgxke/I= github.com/cosmos/iavl v0.15.3/go.mod h1:OLjQiAQ4fGD2KDZooyJG9yz+p2ao2IAYSbke8mVvSA4= github.com/cosmos/iavl v0.17.1 h1:b/Cl8h1PRMvsu24+TYNlKchIu7W6tmxIBGe6E9u2Ybw= +github.com/cosmos/iavl v0.17.1/go.mod h1:7aisPZK8yCpQdy3PMvKeO+bhq1NwDjUwjzxwwROUxFk= github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= +github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= +github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= +github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/dgraph-io/badger/v2 v2.2007.1/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= @@ -177,28 +222,40 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b h1:HBah4D48ypg3J7Np4N+HY/ZR76fx3HEUGxDU6Uk39oQ= +github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= +github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25 h1:2vLKys4RBU4pn2T/hjXMbvwTr1Cvy5THHrQkbeY9HRk= github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25/go.mod h1:hTr8+TLQmkUkgcuh3mcr5fjrT9c64ZzsBCdCEC6UppY= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= @@ -207,7 +264,11 @@ github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -220,10 +281,21 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0= github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic= @@ -241,6 +313,7 @@ github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -264,6 +337,7 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 h1:ur2rms48b3Ep1dxh7aUV2FZEQ8jEVO2F6ILKx8ofkAg= github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -279,12 +353,15 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -298,28 +375,40 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.1/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= @@ -328,6 +417,7 @@ github.com/grpc-ecosystem/grpc-gateway v1.14.7/go.mod h1:oYZKL012gGh6LMyg/xA7Q2y github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= @@ -335,17 +425,22 @@ github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uM github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -361,19 +456,31 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 h1:uUjLpLt6bVvZ72SQc/B4dXcPBw4Vgd7soowdRl52qEM= +github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87/go.mod h1:XGsKKeXxeRr95aEOgipvluMPlgjr7dGlk9ZTWOjcUcg= +github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/improbable-eng/grpc-web v0.14.1 h1:NrN4PY71A6tAz2sKDvC5JCauENWp0ykG8Oq1H3cpFvw= +github.com/improbable-eng/grpc-web v0.14.1/go.mod h1:zEjGHa8DAlkoOXmswrNvhUGEYQA9UI7DhrGeHR1DMGU= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.9.0/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= @@ -390,46 +497,72 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= +github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0= github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -438,8 +571,10 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -447,8 +582,12 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= +github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= @@ -456,24 +595,32 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -495,11 +642,14 @@ github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIw github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= @@ -513,6 +663,7 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= @@ -538,6 +689,7 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.30.0 h1:JEkYlQnpzrzQFxi6gnukFPdQ+ac82oRhzMcIduJu/Ug= github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= @@ -548,10 +700,13 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= +github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -559,21 +714,29 @@ github.com/regen-network/cosmos-proto v0.3.1 h1:rV7iM4SSFAagvy8RiyhiACbWEGotmqzy github.com/regen-network/cosmos-proto v0.3.1/go.mod h1:jO0sVX6a1B36nmE8C9xBFXpNwWejXC7QqCOnH3O0+YM= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= +github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= +github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.25.0 h1:Rj7XygbUHKUlDPcVdoLyR91fJBsduXj5fRxyqIQj/II= +github.com/rs/zerolog v1.25.0/go.mod h1:7KHcEGe0QZPOm2IE4Kpb5rTh6n1h2hIgS5OOnu1rUaI= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= +github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -617,14 +780,20 @@ github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= +github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -636,7 +805,9 @@ github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKk github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= +github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI= +github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tendermint/tendermint v0.34.0-rc4/go.mod h1:yotsojf2C1QBOw4dZrTcxbyxmPUrT4hNuOQWX9XUwB4= @@ -648,23 +819,36 @@ github.com/tendermint/tm-db v0.6.2/go.mod h1:GYtQ67SUvATOcoY8/+x6ylk8Qo02BQyLrAs github.com/tendermint/tm-db v0.6.3/go.mod h1:lfA1dL9/Y/Y8wwyPp2NMLyn5P5Ptr/gvDFNWtrCWSf8= github.com/tendermint/tm-db v0.6.4 h1:3N2jlnYQkXNQclQwd/eKV/NzlqPlfK21cpRRIx80XXQ= github.com/tendermint/tm-db v0.6.4/go.mod h1:dptYhIpJ2M5kUuenLr+Yyf3zQOv1SgBZcl8/BmWlMBw= +github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= +github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/sjson v1.1.4/go.mod h1:wXpKXu8CtDjKAZ+3DrKY5ROCorDFahq8l0tey/Lx1fg= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vmihailenco/msgpack/v5 v5.1.4/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI= +github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= +github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= @@ -698,24 +882,30 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= @@ -739,10 +929,12 @@ golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -751,6 +943,7 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -788,6 +981,7 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -797,6 +991,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f h1:w6wWR0H+nyVpbSAQbzVEIACVyr/h8l/BEkY6Sokc7Eg= golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -813,6 +1009,9 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -834,6 +1033,7 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -843,12 +1043,15 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -857,7 +1060,9 @@ golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -874,6 +1079,7 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -881,6 +1087,7 @@ golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -892,8 +1099,14 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210903071746-97244b99971b h1:3Dq0eVHn0uaQJmPO+/aYPI/fRMqdrVDbu7MQcku54gg= golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -925,6 +1138,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -938,6 +1152,7 @@ golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -952,8 +1167,10 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -961,10 +1178,15 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -993,6 +1215,12 @@ google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjR google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1041,15 +1269,28 @@ google.golang.org/genproto v0.0.0-20201119123407-9b1e624d6bc4/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1060,8 +1301,10 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -1078,9 +1321,13 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1104,10 +1351,12 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/x/group/orm/index.go b/x/group/orm/index.go index 375a957f1989..871d5e415fd9 100644 --- a/x/group/orm/index.go +++ b/x/group/orm/index.go @@ -1,4 +1,4 @@ -package table +package orm // PrefixRange turns a prefix into a (start, end) range. The start is the given prefix value and // the end is calculated by adding 1 bit to the start value. Nil is not allowed as prefix. diff --git a/x/group/orm/index_key_codec.go b/x/group/orm/index_key_codec.go deleted file mode 100644 index def3ef409b87..000000000000 --- a/x/group/orm/index_key_codec.go +++ /dev/null @@ -1,66 +0,0 @@ -package table - -// Max255DynamicLengthIndexKeyCodec works with up to 255 byte dynamic size RowIDs. -// They are encoded as `concat(searchableKey, rowID, len(rowID)[0])`. -type Max255DynamicLengthIndexKeyCodec struct{} - -// BuildIndexKey builds the index key by appending searchableKey with rowID and length int. -// The RowID length must not be greater than 255. -func (Max255DynamicLengthIndexKeyCodec) BuildIndexKey(searchableKey []byte, rowID RowID) []byte { - rowIDLen := len(rowID) - switch { - case rowIDLen == 0: - panic("Empty RowID") - case rowIDLen > 255: - panic("RowID exceeds max size") - } - - searchableKeyLen := len(searchableKey) - res := make([]byte, searchableKeyLen+rowIDLen+1) - copy(res, searchableKey) - copy(res[searchableKeyLen:], rowID) - res[searchableKeyLen+rowIDLen] = byte(rowIDLen) - return res -} - -// StripRowID returns the RowID from the combined persistentIndexKey. It is the reverse operation to BuildIndexKey -// but with the searchableKey and length int dropped. -func (Max255DynamicLengthIndexKeyCodec) StripRowID(persistentIndexKey []byte) RowID { - n := len(persistentIndexKey) - searchableKeyLen := persistentIndexKey[n-1] - return persistentIndexKey[n-int(searchableKeyLen)-1 : n-1] -} - -// FixLengthIndexKeyCodec expects the RowID to always have the same length with all entries. -// They are encoded as `concat(searchableKey, rowID)`. -type FixLengthIndexKeyCodec struct { - rowIDLength int -} - -// FixLengthIndexKeys is a constructor for FixLengthIndexKeyCodec. -func FixLengthIndexKeys(rowIDLength int) *FixLengthIndexKeyCodec { - return &FixLengthIndexKeyCodec{rowIDLength: rowIDLength} -} - -// BuildIndexKey builds the index key by appending searchableKey with rowID. -// The RowID length must not be greater than what is defined by rowIDLength in construction. -func (c FixLengthIndexKeyCodec) BuildIndexKey(searchableKey []byte, rowID RowID) []byte { - switch n := len(rowID); { - case n == 0: - panic("Empty RowID") - case n > c.rowIDLength: - panic("RowID exceeds max size") - } - n := len(searchableKey) - res := make([]byte, n+c.rowIDLength) - copy(res, searchableKey) - copy(res[n:], rowID) - return res -} - -// StripRowID returns the RowID from the combined persistentIndexKey. It is the reverse operation to BuildIndexKey -// but with the searchableKey dropped. -func (c FixLengthIndexKeyCodec) StripRowID(persistentIndexKey []byte) RowID { - n := len(persistentIndexKey) - return persistentIndexKey[n-c.rowIDLength:] -} diff --git a/x/group/orm/index_key_codec_test.go b/x/group/orm/index_key_codec_test.go deleted file mode 100644 index b3c88c82b9a3..000000000000 --- a/x/group/orm/index_key_codec_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package table - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestEncodeIndexKey(t *testing.T) { - specs := map[string]struct { - srcKey []byte - srcRowID RowID - enc IndexKeyCodec - expKey []byte - expPanic bool - }{ - "dynamic length example 1": { - srcKey: []byte{0x0, 0x1, 0x2}, - srcRowID: []byte{0x3, 0x4}, - enc: Max255DynamicLengthIndexKeyCodec{}, - expKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x2}, - }, - "dynamic length example 2": { - srcKey: []byte{0x0, 0x1}, - srcRowID: []byte{0x2, 0x3, 0x4}, - enc: Max255DynamicLengthIndexKeyCodec{}, - expKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x3}, - }, - "dynamic length max row ID": { - srcKey: []byte{0x0, 0x1}, - srcRowID: []byte(strings.Repeat("a", 255)), - enc: Max255DynamicLengthIndexKeyCodec{}, - expKey: append(append([]byte{0x0, 0x1}, []byte(strings.Repeat("a", 255))...), 0xff), - }, - "dynamic length panics with empty rowID": { - srcKey: []byte{0x0, 0x1}, - srcRowID: []byte{}, - enc: Max255DynamicLengthIndexKeyCodec{}, - expPanic: true, - }, - "dynamic length exceeds max row ID": { - srcKey: []byte{0x0, 0x1}, - srcRowID: []byte(strings.Repeat("a", 256)), - enc: Max255DynamicLengthIndexKeyCodec{}, - expPanic: true, - }, - "uint64 example": { - srcKey: []byte{0x0, 0x1, 0x2}, - srcRowID: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, - enc: FixLengthIndexKeys(8), - expKey: []byte{0x0, 0x1, 0x2, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, - }, - "uint64 panics with empty rowID": { - srcKey: []byte{0x0, 0x1}, - srcRowID: []byte{}, - enc: FixLengthIndexKeys(8), - expPanic: true, - }, - "uint64 exceeds max bytes in rowID": { - srcKey: []byte{0x0, 0x1}, - srcRowID: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}, - enc: FixLengthIndexKeys(8), - expPanic: true, - }, - } - for msg, spec := range specs { - t.Run(msg, func(t *testing.T) { - if spec.expPanic { - require.Panics(t, - func() { - _ = spec.enc.BuildIndexKey(spec.srcKey, spec.srcRowID) - }) - return - } - got := spec.enc.BuildIndexKey(spec.srcKey, spec.srcRowID) - assert.Equal(t, spec.expKey, got) - }) - } -} -func TestDecodeIndexKey(t *testing.T) { - specs := map[string]struct { - srcKey []byte - enc IndexKeyCodec - expRowID RowID - }{ - "dynamic length example 1": { - srcKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x2}, - enc: Max255DynamicLengthIndexKeyCodec{}, - expRowID: []byte{0x3, 0x4}, - }, - "dynamic length example 2": { - srcKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x3}, - enc: Max255DynamicLengthIndexKeyCodec{}, - expRowID: []byte{0x2, 0x3, 0x4}, - }, - "dynamic length max row ID": { - srcKey: append(append([]byte{0x0, 0x1}, []byte(strings.Repeat("a", 255))...), 0xff), - enc: Max255DynamicLengthIndexKeyCodec{}, - expRowID: []byte(strings.Repeat("a", 255)), - }, - "uint64 example": { - srcKey: []byte{0x0, 0x1, 0x2, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, - expRowID: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, - enc: FixLengthIndexKeys(8), - }, - } - for msg, spec := range specs { - t.Run(msg, func(t *testing.T) { - gotRow := spec.enc.StripRowID(spec.srcKey) - assert.Equal(t, spec.expRowID, gotRow) - }) - } -} diff --git a/x/group/orm/index_property_test.go b/x/group/orm/index_property_test.go new file mode 100644 index 000000000000..48b2cc02ef66 --- /dev/null +++ b/x/group/orm/index_property_test.go @@ -0,0 +1,60 @@ +package orm + +import ( + "testing" + + "pgregory.net/rapid" + + "github.com/stretchr/testify/require" +) + +func TestPrefixRangeProperty(t *testing.T) { + t.Run("TestPrefixRange", rapid.MakeCheck(func(t *rapid.T) { + prefix := rapid.SliceOf(rapid.Byte()).Draw(t, "prefix").([]byte) + + start, end := PrefixRange(prefix) + + // len(prefix) == 0 => start == nil && end == nil + if len(prefix) == 0 { + require.Nil(t, start) + require.Nil(t, end) + } else { + // start == prefix + require.Equal(t, prefix, start) + + // Would overflow if all bytes are 255 + wouldOverflow := true + for _, b := range prefix { + if b != 255 { + wouldOverflow = false + } + } + + // Overflow => end == nil + if wouldOverflow { + require.Nil(t, end) + } else { + require.Equal(t, len(start), len(end)) + + // Scan back and find last value that isn't 255 + overflowIndex := len(start) - 1 + for overflowIndex > 0 && prefix[overflowIndex] == 255 { + overflowIndex-- + } + + // bytes should be the same up to overflow + // index, one greater at overflow and 0 from + // then on + for i, b := range start { + if i < overflowIndex { + require.Equal(t, b, end[i]) + } else if i == overflowIndex { + require.Equal(t, b+1, end[i]) + } else { + require.Equal(t, uint8(0), end[i]) + } + } + } + } + })) +} diff --git a/x/group/orm/index_test.go b/x/group/orm/index_test.go index b512fd246cc4..01e43a221a21 100644 --- a/x/group/orm/index_test.go +++ b/x/group/orm/index_test.go @@ -1,4 +1,4 @@ -package table +package orm import ( "testing" diff --git a/x/group/orm/sequence.go b/x/group/orm/sequence.go index 80129e766d10..d60555a423ab 100644 --- a/x/group/orm/sequence.go +++ b/x/group/orm/sequence.go @@ -1,4 +1,4 @@ -package table +package orm import ( "encoding/binary" diff --git a/x/group/orm/sequence_property_test.go b/x/group/orm/sequence_property_test.go new file mode 100644 index 000000000000..e27c8ed140e4 --- /dev/null +++ b/x/group/orm/sequence_property_test.go @@ -0,0 +1,68 @@ +package orm + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "pgregory.net/rapid" +) + +func TestSequence(t *testing.T) { + rapid.Check(t, rapid.Run(&sequenceMachine{})) +} + +// sequenceMachine is a state machine model of Sequence. It simply uses a uint64 +// as the model of the sequence. +type sequenceMachine struct { + store sdk.KVStore + seq *orm.Sequence + state uint64 +} + +// Init sets up the real Sequence, including choosing a random initial value, +// and intialises the model state +func (m *sequenceMachine) Init(t *rapid.T) { + // Create context and KV store + ctx := NewMockContext() + m.store := ctx.KVStore(sdk.NewKVStoreKey("test")) + + // Create primary key table + seq := orm.NewSequence(0x1) + m.seq = &seq + + // Choose initial sequence value + initSeqVal := rapid.Uint64().Draw(t, "initSeqVal").(uint64) + err := m.seq.InitVal(m.store, initSeqVal) + require.NoError(t, err) + + // Create model state + m.state = initSeqVal +} + +// Check does nothing, because all our invariants are captured in the commands +func (m *sequenceMachine) Check(t *rapid.T) {} + +// NextVal is one of the model commands. It checks that the next value of the +// sequence matches the model and increments the model state. +func (m *sequenceMachine) NextVal(t *rapid.T) { + // Check that the next value in the sequence matches the model + require.Equal(t, m.state+1, m.seq.NextVal(m.store)) + + // Increment the model state + m.state++ +} + +// CurVal is one of the model commands. It checks that the current value of the +// sequence matches the model. +func (m *sequenceMachine) CurVal(t *rapid.T) { + // Check the the current value matches the model + require.Equal(t, m.state, m.seq.CurVal(m.store)) +} + +// PeekNextVal is one of the model commands. It checks that the next value of +// the sequence matches the model without modifying the state. +func (m *sequenceMachine) PeekNextVal(t *rapid.T) { + // Check that the next value in the sequence matches the model + require.Equal(t, m.state+1, m.seq.PeekNextVal(m.store)) +} diff --git a/x/group/orm/sequence_test.go b/x/group/orm/sequence_test.go index eb4c4e77340c..f398eb3f491b 100644 --- a/x/group/orm/sequence_test.go +++ b/x/group/orm/sequence_test.go @@ -1,4 +1,4 @@ -package table +package orm import ( "testing" @@ -7,6 +7,17 @@ import ( "github.com/stretchr/testify/assert" ) +func TestSequenceUniqueConstraint(t *testing.T) { + ctx := NewMockContext() + store := ctx.KVStore(sdk.NewKVStoreKey("test")) + + seq := NewSequence(0x1) + err := seq.InitVal(store, 2) + require.NoError(t, err) + err = seq.InitVal(store, 3) + require.True(t, ErrUniqueConstraint.Is(err)) +} + func TestSequenceIncrements(t *testing.T) { ctx := NewMockContext() store := ctx.KVStore(sdk.NewKVStoreKey("test")) diff --git a/x/group/orm/spec/README.md b/x/group/orm/spec/README.md index 015df77c8195..ad70dd1f2133 100644 --- a/x/group/orm/spec/README.md +++ b/x/group/orm/spec/README.md @@ -3,7 +3,7 @@ The orm package provides a framework for creating relational database tables with primary and secondary keys. ```go -type Table struct { +type table struct { model reflect.Type prefix byte afterSave []AfterSaveInterceptor @@ -13,5 +13,5 @@ type Table struct { ``` Such table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling. -In the prefix store, entities are stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter or dynamic size bytes. -Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store. \ No newline at end of file +In the prefix store, entities are stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter, string or dynamic size bytes. +Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store. diff --git a/x/group/orm/table.go b/x/group/orm/table.go index a038634c9a2b..f7c9aa06f5b8 100644 --- a/x/group/orm/table.go +++ b/x/group/orm/table.go @@ -1,4 +1,4 @@ -package table +package orm import ( "reflect" @@ -9,49 +9,40 @@ import ( "github.com/cosmos/cosmos-sdk/types/errors" ) -var _ Indexable = &Builder{} +var _ Indexable = &tableBuilder{} -type Builder struct { - model reflect.Type - prefixData byte - indexKeyCodec IndexKeyCodec - afterSave []AfterSaveInterceptor - afterDelete []AfterDeleteInterceptor - cdc codec.Codec +type tableBuilder struct { + model reflect.Type + prefixData byte + afterSave []AfterSaveInterceptor + afterDelete []AfterDeleteInterceptor + cdc codec.Codec } -// NewTableBuilder creates a builder to setup a Table object. -func NewTableBuilder(prefixData byte, model codec.ProtoMarshaler, idxKeyCodec IndexKeyCodec, cdc codec.Codec) *Builder { +// newTableBuilder creates a builder to setup a table object. +func newTableBuilder(prefixData byte, model codec.ProtoMarshaler, cdc codec.Codec) (*tableBuilder, error) { if model == nil { - panic("Model must not be nil") - } - if idxKeyCodec == nil { - panic("IndexKeyCodec must not be nil") + return nil, ErrArgument.Wrap("Model must not be nil") } tp := reflect.TypeOf(model) if tp.Kind() == reflect.Ptr { tp = tp.Elem() } - return &Builder{ - prefixData: prefixData, - model: tp, - indexKeyCodec: idxKeyCodec, - cdc: cdc, + return &tableBuilder{ + prefixData: prefixData, + model: tp, + cdc: cdc, } } -func (a Builder) IndexKeyCodec() IndexKeyCodec { - return a.indexKeyCodec -} - // RowGetter returns a type safe RowGetter. -func (a Builder) RowGetter() RowGetter { +func (a tableBuilder) RowGetter() RowGetter { return NewTypeSafeRowGetter(a.prefixData, a.model, a.cdc) } -// Build creates a new Table object. -func (a Builder) Build() Table { - return Table{ +// Build creates a new table object. +func (a tableBuilder) Build() table { + return table{ model: a.model, prefix: a.prefixData, afterSave: a.afterSave, @@ -61,20 +52,26 @@ func (a Builder) Build() Table { } // AddAfterSaveInterceptor can be used to register a callback function that is executed after an object is created and/or updated. -func (a *Builder) AddAfterSaveInterceptor(interceptor AfterSaveInterceptor) { +func (a *tableBuilder) AddAfterSaveInterceptor(interceptor AfterSaveInterceptor) { a.afterSave = append(a.afterSave, interceptor) } // AddAfterDeleteInterceptor can be used to register a callback function that is executed after an object is deleted. -func (a *Builder) AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) { +func (a *tableBuilder) AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) { a.afterDelete = append(a.afterDelete, interceptor) } -// Table is the high level object for storage mapper functionality. Persistent entities are stored by an unique identifier -// called `RowID`. -// The Table struct does not enforce uniqueness of the `RowID` but expects this to be satisfied by the callers and conditions -// to optimize Gas usage. -type Table struct { +// table is the high level object to storage mapper functionality. Persistent +// entities are stored by an unique identifier called `RowID`. The table struct +// does not: +// - enforce uniqueness of the `RowID` +// - enforce prefix uniqueness of keys, i.e. not allowing one key to be a prefix +// of another +// - optimize Gas usage conditions +// The caller must ensure that these things are handled. The table struct is +// private, so that we only have custom tables built on top of table, that do satisfy +// these requirements. +type table struct { model reflect.Type prefix byte afterSave []AfterSaveInterceptor @@ -82,39 +79,43 @@ type Table struct { cdc codec.Codec } -// Create persists the given object under the rowID key. It does not check if the -// key already exists. Any caller must either make sure that this contract is fulfilled -// by providing a universal unique ID or sequence that is guaranteed to not exist yet or -// by checking the state via `Has` function before. +// Create persists the given object under the rowID key, returning an +// ErrUniqueConstraint if a value already exists at that key. // -// Create iterates though the registered callbacks and may add secondary index keys by them. -func (a Table) Create(store sdk.KVStore, rowID RowID, obj codec.ProtoMarshaler) error { - if err := assertCorrectType(a.model, obj); err != nil { - return err +// Create iterates through the registered callbacks that may add secondary index +// keys. +func (a table) Create(store sdk.KVStore, rowID RowID, obj codec.ProtoMarshaler) error { + if a.Has(store, rowID) { + return ErrUniqueConstraint } - if err := assertValid(obj); err != nil { - return err - } - pStore := prefix.NewStore(store, []byte{a.prefix}) - v, err := a.cdc.Marshal(obj) - if err != nil { - return errors.Wrapf(err, "failed to serialize %T", obj) - } - pStore.Set(rowID, v) - for i, itc := range a.afterSave { - if err := itc(store, rowID, obj, nil); err != nil { - return errors.Wrapf(err, "interceptor %d failed", i) - } + + return a.Set(store, rowID, obj) +} + +// Update updates the given object under the rowID key. It expects the key to +// exists already and fails with an `ErrNotFound` otherwise. Any caller must +// therefore make sure that this contract is fulfilled. Parameters must not be +// nil. +// +// Update iterates through the registered callbacks that may add or remove +// secondary index keys. +func (a table) Update(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler) error { + if !a.Has(store, rowID) { + return ErrNotFound } - return nil + + return a.Set(store, rowID, newValue) } -// Update updates the given object under the rowID key. It expects the key to exist already -// and fails with an `ErrNotFound` otherwise. Any caller must therefore make sure that this contract -// is fulfilled. Parameters must not be nil. +// Set persists the given object under the rowID key. It does not check if the +// key already exists and overwrites the value if it does. // -// Update iterates though the registered callbacks and may add or remove secondary index keys by them. -func (a Table) Update(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler) error { +// Set iterates through the registered callbacks that may add secondary index +// keys. +func (a table) Set(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler) error { + if len(rowID) == 0 { + return ErrEmptyKey + } if err := assertCorrectType(a.model, newValue); err != nil { return err } @@ -123,18 +124,20 @@ func (a Table) Update(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarsha } pStore := prefix.NewStore(store, []byte{a.prefix}) - var oldValue = reflect.New(a.model).Interface().(codec.ProtoMarshaler) - if err := a.GetOne(store, rowID, oldValue); err != nil { - return errors.Wrap(err, "load old value") + var oldValue codec.ProtoMarshaler + if a.Has(ctx, rowID) { + oldValue = reflect.New(a.model).Interface().(codec.ProtoMarshaler) + a.GetOne(ctx, rowID, oldValue) } + newValueEncoded, err := a.cdc.Marshal(newValue) if err != nil { return errors.Wrapf(err, "failed to serialize %T", newValue) } pStore.Set(rowID, newValueEncoded) - for i, itc := range a.afterSave { + for i, itc := range a.afterSet { if err := itc(store, rowID, newValue, oldValue); err != nil { return errors.Wrapf(err, "interceptor %d failed", i) } @@ -151,12 +154,13 @@ func assertValid(obj codec.ProtoMarshaler) error { return nil } -// Delete removes the object under the rowID key. It expects the key to exists already -// and fails with a `ErrNotFound` otherwise. Any caller must therefore make sure that this contract -// is fulfilled. +// Delete removes the object under the rowID key. It expects the key to exists +// already and fails with a `ErrNotFound` otherwise. Any caller must therefore +// make sure that this contract is fulfilled. // -// Delete iterates though the registered callbacks and removes secondary index keys by them. -func (a Table) Delete(store sdk.KVStore, rowID RowID) error { +// Delete iterates through the registered callbacks that remove secondary index +// keys. +func (a table) Delete(store sdk.KVStore, rowID RowID) error { pStore := prefix.NewStore(store, []byte{a.prefix}) var oldValue = reflect.New(a.model).Interface().(codec.ProtoMarshaler) @@ -173,17 +177,25 @@ func (a Table) Delete(store sdk.KVStore, rowID RowID) error { return nil } -// Has checks if a key exists. Panics on nil key. -func (a Table) Has(store sdk.KVStore, rowID RowID) bool { - Store := prefix.NewStore(store, []byte{a.prefix}) - it := Store.Iterator(PrefixRange(rowID)) +// Has checks if a key exists. Returns false when the key is empty or nil +// because we don't allow creation of values without a key. +func (a table) Has(store sdk.KVStore, key RowID) bool { + if len(key) == 0 { + return false + } + pStore := prefix.NewStore(store, []byte{a.prefix}) + it := pStore.Iterator(PrefixRange(key)) defer it.Close() return it.Valid() } // GetOne load the object persisted for the given RowID into the dest parameter. -// If none exists `ErrNotFound` is returned instead. Parameters must not be nil. -func (a Table) GetOne(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error { +// If none exists or `rowID==nil` then `ErrNotFound` is returned instead. +// Parameters must not be nil - we don't allow creation of values with empty keys. +func (a table) GetOne(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error { + if len(rowID) == 0 { + return ErrNotFound + } x := NewTypeSafeRowGetter(a.prefix, a.model, a.cdc) return x(store, rowID, dest) } diff --git a/x/group/orm/table_test.go b/x/group/orm/table_test.go index 3f694893114f..f67ffb949c52 100644 --- a/x/group/orm/table_test.go +++ b/x/group/orm/table_test.go @@ -1,4 +1,4 @@ -package table +package orm import ( "fmt" @@ -16,36 +16,35 @@ import ( func TestNewTableBuilder(t *testing.T) { interfaceRegistry := types.NewInterfaceRegistry() cdc := codec.NewProtoCodec(interfaceRegistry) - const anyPrefix = 0x10 - specs := map[string]struct { + testCases := []struct { + name string model codec.ProtoMarshaler - idxKeyCodec IndexKeyCodec - expPanic bool + expectErr bool + expectedErr string }{ - "happy path": { - model: &testdata.TableModel{}, - idxKeyCodec: FixLengthIndexKeys(EncodedSeqLength), - }, - "nil model": { - idxKeyCodec: FixLengthIndexKeys(EncodedSeqLength), - expPanic: true, + { + name: "nil model", + model: nil, + expectErr: true, + expectedErr: "Model must not be nil", }, - "nil idxKeyCodec": { - model: &testdata.TableModel{}, - expPanic: true, + { + name: "all not nil", + model: &testdata.GroupInfo{}, + expectErr: false, }, } - for msg, spec := range specs { - t.Run(msg, func(t *testing.T) { - f := func() { - NewTableBuilder(anyPrefix, spec.model, spec.idxKeyCodec, cdc) - } - if spec.expPanic { - require.Panics(t, f) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + builder, err := newTableBuilder(0x1, tc.model, cdc) + if tc.expectErr { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expectedErr) } else { - require.NotPanics(t, f) + require.NoError(t, err) + require.NotNil(t, builder) } }) } @@ -53,16 +52,27 @@ func TestNewTableBuilder(t *testing.T) { func TestCreate(t *testing.T) { specs := map[string]struct { + rowID orm.RowID src codec.ProtoMarshaler expErr *errors.Error }{ + "empty rowID": { + rowID: []byte{}, + src: &testdata.TableModel{ + Id: 1, + Name: "some name", + }, + expErr: orm.ErrEmptyKey, + }, "happy path": { + rowID: EncodeSequence(1), src: &testdata.TableModel{ Id: 1, Name: "some name", }, }, "wrong type": { + rowID: EncodeSequence(1), src: &testdata.Cat{ Moniker: "cat moniker", Lives: 10, @@ -70,6 +80,7 @@ func TestCreate(t *testing.T) { expErr: ErrType, }, "model validation fails": { + rowID: EncodeSequence(1), src: &testdata.TableModel{ Id: 1, Name: "", @@ -86,18 +97,18 @@ func TestCreate(t *testing.T) { store := ctx.KVStore(sdk.NewKVStoreKey("test")) const anyPrefix = 0x10 - tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) + tableBuilder := newTableBuilder(anyPrefix, &testdata.TableModel{}, cdc) myTable := tableBuilder.Build() - err := myTable.Create(store, EncodeSequence(1), spec.src) + err := myTable.Create(store, spec.rowID, spec.src) require.True(t, spec.expErr.Is(err), err) shouldExists := spec.expErr == nil - assert.Equal(t, shouldExists, myTable.Has(store, EncodeSequence(1)), fmt.Sprintf("expected %v", shouldExists)) + assert.Equal(t, shouldExists, myTable.Has(store, spec.rowID), fmt.Sprintf("expected %v", shouldExists)) // then var loaded testdata.TableModel - err = myTable.GetOne(store, EncodeSequence(1), &loaded) + err = myTable.GetOne(store, spec.rowID, &loaded) if spec.expErr != nil { require.True(t, ErrNotFound.Is(err)) return @@ -143,7 +154,7 @@ func TestUpdate(t *testing.T) { store := ctx.KVStore(sdk.NewKVStoreKey("test")) const anyPrefix = 0x10 - tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) + tableBuilder := newTableBuilder(anyPrefix, &testdata.TableModel{}, cdc) myTable := tableBuilder.Build() initValue := testdata.TableModel{ @@ -192,7 +203,7 @@ func TestDelete(t *testing.T) { store := ctx.KVStore(sdk.NewKVStoreKey("test")) const anyPrefix = 0x10 - tableBuilder := NewTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) + tableBuilder := newTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) myTable := tableBuilder.Build() initValue := testdata.TableModel{ diff --git a/x/group/orm/testsupport.go b/x/group/orm/testsupport.go index 60878101f654..72b05ea92b5d 100644 --- a/x/group/orm/testsupport.go +++ b/x/group/orm/testsupport.go @@ -1,4 +1,4 @@ -package table +package orm import ( "github.com/cosmos/cosmos-sdk/store" diff --git a/x/group/orm/types.go b/x/group/orm/types.go index 01496e764566..3365468196ef 100644 --- a/x/group/orm/types.go +++ b/x/group/orm/types.go @@ -1,7 +1,7 @@ /* -Package store/table is a convenient object to data store mapper. +Package orm is a convenient object to data store mapper. */ -package table +package orm import ( "io" @@ -16,13 +16,14 @@ import ( const tableCodespace = "table" var ( - ErrNotFound = errors.Register(tableCodespace, 100, "not found") - ErrIteratorDone = errors.Register(tableCodespace, 101, "iterator done") - ErrIteratorInvalid = errors.Register(tableCodespace, 102, "iterator invalid") - ErrType = errors.Register(tableCodespace, 110, "invalid type") - ErrUniqueConstraint = errors.Register(tableCodespace, 111, "unique constraint violation") - ErrArgument = errors.Register(tableCodespace, 112, "invalid argument") - ErrIndexKeyMaxLength = errors.Register(tableCodespace, 113, "index key exceeds max length") + ErrNotFound = errors.Register(ormCodespace, 100, "not found") + ErrIteratorDone = errors.Register(ormCodespace, 101, "iterator done") + ErrIteratorInvalid = errors.Register(ormCodespace, 102, "iterator invalid") + ErrType = errors.Register(ormCodespace, 110, "invalid type") + ErrUniqueConstraint = errors.Register(ormCodespace, 111, "unique constraint violation") + ErrArgument = errors.Register(ormCodespace, 112, "invalid argument") + ErrIndexKeyMaxLength = errors.Register(ormCodespace, 113, "index key exceeds max length") + ErrEmptyKey = errors.Register(ormCodespace, 114, "cannot use empty key") ) // Unique identifier of a persistent table. @@ -49,15 +50,6 @@ type Iterator interface { io.Closer } -// IndexKeyCodec defines the encoding/decoding methods for building/splitting index keys. -type IndexKeyCodec interface { - // BuildIndexKey encodes a searchable key and the target RowID. - BuildIndexKey(searchableKey []byte, rowID RowID) []byte - // StripRowID returns the RowID from the combined persistentIndexKey. It is the reverse operation to BuildIndexKey - // but with the searchableKey dropped. - StripRowID(persistentIndexKey []byte) RowID -} - // Indexable types are used to setup new tables. // This interface provides a set of functions that can be called by indexes to register and interact with the tables. type Indexable interface { diff --git a/x/group/orm/types_test.go b/x/group/orm/types_test.go index 48d184c70328..afeaf76d7b2c 100644 --- a/x/group/orm/types_test.go +++ b/x/group/orm/types_test.go @@ -1,4 +1,4 @@ -package table +package orm import ( "reflect" From 4d2486ae52d8f5637e9587f3d26b8b61de4129c9 Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 8 Oct 2021 11:12:21 +0200 Subject: [PATCH 13/26] Mv orm to x/group/internal --- x/group/{ => internal}/orm/index.go | 0 x/group/{ => internal}/orm/index_property_test.go | 0 x/group/{ => internal}/orm/index_test.go | 0 x/group/{ => internal}/orm/sequence.go | 0 x/group/{ => internal}/orm/sequence_property_test.go | 0 x/group/{ => internal}/orm/sequence_test.go | 0 x/group/{ => internal}/orm/spec/README.md | 0 x/group/{ => internal}/orm/table.go | 0 x/group/{ => internal}/orm/table_test.go | 0 x/group/{ => internal}/orm/testsupport.go | 0 x/group/{ => internal}/orm/types.go | 0 x/group/{ => internal}/orm/types_test.go | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename x/group/{ => internal}/orm/index.go (100%) rename x/group/{ => internal}/orm/index_property_test.go (100%) rename x/group/{ => internal}/orm/index_test.go (100%) rename x/group/{ => internal}/orm/sequence.go (100%) rename x/group/{ => internal}/orm/sequence_property_test.go (100%) rename x/group/{ => internal}/orm/sequence_test.go (100%) rename x/group/{ => internal}/orm/spec/README.md (100%) rename x/group/{ => internal}/orm/table.go (100%) rename x/group/{ => internal}/orm/table_test.go (100%) rename x/group/{ => internal}/orm/testsupport.go (100%) rename x/group/{ => internal}/orm/types.go (100%) rename x/group/{ => internal}/orm/types_test.go (100%) diff --git a/x/group/orm/index.go b/x/group/internal/orm/index.go similarity index 100% rename from x/group/orm/index.go rename to x/group/internal/orm/index.go diff --git a/x/group/orm/index_property_test.go b/x/group/internal/orm/index_property_test.go similarity index 100% rename from x/group/orm/index_property_test.go rename to x/group/internal/orm/index_property_test.go diff --git a/x/group/orm/index_test.go b/x/group/internal/orm/index_test.go similarity index 100% rename from x/group/orm/index_test.go rename to x/group/internal/orm/index_test.go diff --git a/x/group/orm/sequence.go b/x/group/internal/orm/sequence.go similarity index 100% rename from x/group/orm/sequence.go rename to x/group/internal/orm/sequence.go diff --git a/x/group/orm/sequence_property_test.go b/x/group/internal/orm/sequence_property_test.go similarity index 100% rename from x/group/orm/sequence_property_test.go rename to x/group/internal/orm/sequence_property_test.go diff --git a/x/group/orm/sequence_test.go b/x/group/internal/orm/sequence_test.go similarity index 100% rename from x/group/orm/sequence_test.go rename to x/group/internal/orm/sequence_test.go diff --git a/x/group/orm/spec/README.md b/x/group/internal/orm/spec/README.md similarity index 100% rename from x/group/orm/spec/README.md rename to x/group/internal/orm/spec/README.md diff --git a/x/group/orm/table.go b/x/group/internal/orm/table.go similarity index 100% rename from x/group/orm/table.go rename to x/group/internal/orm/table.go diff --git a/x/group/orm/table_test.go b/x/group/internal/orm/table_test.go similarity index 100% rename from x/group/orm/table_test.go rename to x/group/internal/orm/table_test.go diff --git a/x/group/orm/testsupport.go b/x/group/internal/orm/testsupport.go similarity index 100% rename from x/group/orm/testsupport.go rename to x/group/internal/orm/testsupport.go diff --git a/x/group/orm/types.go b/x/group/internal/orm/types.go similarity index 100% rename from x/group/orm/types.go rename to x/group/internal/orm/types.go diff --git a/x/group/orm/types_test.go b/x/group/internal/orm/types_test.go similarity index 100% rename from x/group/orm/types_test.go rename to x/group/internal/orm/types_test.go From a368554fccc06c8c4cf8bc692064949255c3c27d Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 8 Oct 2021 12:10:12 +0200 Subject: [PATCH 14/26] Update go.mod and fix tests --- x/group/go.mod | 19 ++++++++++-- x/group/go.sum | 29 +++++++++---------- .../internal/orm/sequence_property_test.go | 6 ++-- x/group/internal/orm/sequence_test.go | 1 + x/group/internal/orm/spec/README.md | 2 +- x/group/internal/orm/table.go | 18 ++++++------ x/group/internal/orm/table_test.go | 21 ++++++++------ x/group/internal/orm/types.go | 9 +++--- 8 files changed, 60 insertions(+), 45 deletions(-) diff --git a/x/group/go.mod b/x/group/go.mod index 51d5548064f5..60a02b83d07b 100644 --- a/x/group/go.mod +++ b/x/group/go.mod @@ -6,13 +6,17 @@ require ( github.com/cockroachdb/apd/v2 v2.0.2 github.com/cosmos/cosmos-sdk v0.44.0 github.com/gogo/protobuf v1.3.3 - github.com/regen-network/cosmos-proto v0.3.1 github.com/stretchr/testify v1.7.0 google.golang.org/grpc v1.41.0 google.golang.org/protobuf v1.27.1 pgregory.net/rapid v0.4.7 ) +require ( + github.com/cosmos/cosmos-proto v0.0.0-20210914142853-23ed61ac79ce + github.com/tendermint/tm-db v0.6.4 +) + require ( github.com/DataDog/zstd v1.4.5 // indirect github.com/armon/go-metrics v0.3.9 // indirect @@ -21,16 +25,20 @@ require ( github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect github.com/confio/ics23/go v0.6.6 // indirect + github.com/cosmos/iavl v0.17.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/badger/v2 v2.2007.2 // indirect github.com/dgraph-io/ristretto v0.0.3 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25 // indirect + github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/go-kit/kit v0.10.0 // indirect github.com/go-logfmt/logfmt v0.5.0 // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.3 // indirect github.com/google/btree v1.0.0 // indirect + github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/hashicorp/go-immutable-radix v1.0.0 // indirect @@ -42,6 +50,9 @@ require ( github.com/magiconair/properties v1.8.5 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect + github.com/mitchellh/mapstructure v1.4.2 // indirect + github.com/nxadm/tail v1.4.8 // indirect + github.com/pelletier/go-toml v1.9.4 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -55,18 +66,22 @@ require ( github.com/spf13/cobra v1.2.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.9.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tendermint/tendermint v0.34.13 // indirect - github.com/tendermint/tm-db v0.6.4 // indirect go.etcd.io/bbolt v1.3.5 // indirect + golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f // indirect golang.org/x/sys v0.0.0-20210903071746-97244b99971b // indirect golang.org/x/text v0.3.6 // indirect + google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71 // indirect + gopkg.in/ini.v1 v1.63.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) replace google.golang.org/grpc => google.golang.org/grpc v1.33.2 diff --git a/x/group/go.sum b/x/group/go.sum index 4b750b372775..03da6ae2de72 100644 --- a/x/group/go.sum +++ b/x/group/go.sum @@ -182,6 +182,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cosmos/cosmos-proto v0.0.0-20210914142853-23ed61ac79ce h1:nin7WtIMETZ8LezEYa5e9/iqyEgQka1x0cQYqgUeTGM= github.com/cosmos/cosmos-proto v0.0.0-20210914142853-23ed61ac79ce/go.mod h1:g2Q3cd94kOBVRAv7ahdtO27yUc4cpNuHGnI40qanl1k= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= @@ -262,8 +263,8 @@ github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVB github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -335,8 +336,8 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 h1:ur2rms48b3Ep1dxh7aUV2FZEQ8jEVO2F6ILKx8ofkAg= github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= @@ -351,12 +352,12 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -385,7 +386,6 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -495,7 +495,6 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -572,8 +571,8 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -599,8 +598,8 @@ github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= @@ -645,8 +644,8 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= @@ -744,9 +743,7 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -778,8 +775,8 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk= github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= @@ -899,8 +896,7 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1276,7 +1272,6 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= @@ -1287,6 +1282,7 @@ google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKr google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71 h1:z+ErRPu0+KS02Td3fOAgdX+lnPDh/VyaABEJPD4JRQs= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= @@ -1319,8 +1315,8 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c= gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= @@ -1358,5 +1354,6 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/x/group/internal/orm/sequence_property_test.go b/x/group/internal/orm/sequence_property_test.go index e27c8ed140e4..c0e7dce2ebf4 100644 --- a/x/group/internal/orm/sequence_property_test.go +++ b/x/group/internal/orm/sequence_property_test.go @@ -16,7 +16,7 @@ func TestSequence(t *testing.T) { // as the model of the sequence. type sequenceMachine struct { store sdk.KVStore - seq *orm.Sequence + seq *Sequence state uint64 } @@ -25,10 +25,10 @@ type sequenceMachine struct { func (m *sequenceMachine) Init(t *rapid.T) { // Create context and KV store ctx := NewMockContext() - m.store := ctx.KVStore(sdk.NewKVStoreKey("test")) + m.store = ctx.KVStore(sdk.NewKVStoreKey("test")) // Create primary key table - seq := orm.NewSequence(0x1) + seq := NewSequence(0x1) m.seq = &seq // Choose initial sequence value diff --git a/x/group/internal/orm/sequence_test.go b/x/group/internal/orm/sequence_test.go index f398eb3f491b..a7e1f750c80a 100644 --- a/x/group/internal/orm/sequence_test.go +++ b/x/group/internal/orm/sequence_test.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestSequenceUniqueConstraint(t *testing.T) { diff --git a/x/group/internal/orm/spec/README.md b/x/group/internal/orm/spec/README.md index ad70dd1f2133..686ffaec6a86 100644 --- a/x/group/internal/orm/spec/README.md +++ b/x/group/internal/orm/spec/README.md @@ -6,7 +6,7 @@ The orm package provides a framework for creating relational database tables wit type table struct { model reflect.Type prefix byte - afterSave []AfterSaveInterceptor + afterSet []AfterSetInterceptor afterDelete []AfterDeleteInterceptor cdc codec.Codec } diff --git a/x/group/internal/orm/table.go b/x/group/internal/orm/table.go index f7c9aa06f5b8..4a336415b026 100644 --- a/x/group/internal/orm/table.go +++ b/x/group/internal/orm/table.go @@ -14,7 +14,7 @@ var _ Indexable = &tableBuilder{} type tableBuilder struct { model reflect.Type prefixData byte - afterSave []AfterSaveInterceptor + afterSet []AfterSetInterceptor afterDelete []AfterDeleteInterceptor cdc codec.Codec } @@ -32,7 +32,7 @@ func newTableBuilder(prefixData byte, model codec.ProtoMarshaler, cdc codec.Code prefixData: prefixData, model: tp, cdc: cdc, - } + }, nil } // RowGetter returns a type safe RowGetter. @@ -45,15 +45,15 @@ func (a tableBuilder) Build() table { return table{ model: a.model, prefix: a.prefixData, - afterSave: a.afterSave, + afterSet: a.afterSet, afterDelete: a.afterDelete, cdc: a.cdc, } } -// AddAfterSaveInterceptor can be used to register a callback function that is executed after an object is created and/or updated. -func (a *tableBuilder) AddAfterSaveInterceptor(interceptor AfterSaveInterceptor) { - a.afterSave = append(a.afterSave, interceptor) +// AddafterSetInterceptor can be used to register a callback function that is executed after an object is created and/or updated. +func (a *tableBuilder) AddafterSetInterceptor(interceptor AfterSetInterceptor) { + a.afterSet = append(a.afterSet, interceptor) } // AddAfterDeleteInterceptor can be used to register a callback function that is executed after an object is deleted. @@ -74,7 +74,7 @@ func (a *tableBuilder) AddAfterDeleteInterceptor(interceptor AfterDeleteIntercep type table struct { model reflect.Type prefix byte - afterSave []AfterSaveInterceptor + afterSet []AfterSetInterceptor afterDelete []AfterDeleteInterceptor cdc codec.Codec } @@ -126,9 +126,9 @@ func (a table) Set(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler pStore := prefix.NewStore(store, []byte{a.prefix}) var oldValue codec.ProtoMarshaler - if a.Has(ctx, rowID) { + if a.Has(store, rowID) { oldValue = reflect.New(a.model).Interface().(codec.ProtoMarshaler) - a.GetOne(ctx, rowID, oldValue) + a.GetOne(store, rowID, oldValue) } newValueEncoded, err := a.cdc.Marshal(newValue) diff --git a/x/group/internal/orm/table_test.go b/x/group/internal/orm/table_test.go index f67ffb949c52..81bd08cc3547 100644 --- a/x/group/internal/orm/table_test.go +++ b/x/group/internal/orm/table_test.go @@ -31,7 +31,7 @@ func TestNewTableBuilder(t *testing.T) { }, { name: "all not nil", - model: &testdata.GroupInfo{}, + model: &testdata.TableModel{}, expectErr: false, }, } @@ -52,7 +52,7 @@ func TestNewTableBuilder(t *testing.T) { func TestCreate(t *testing.T) { specs := map[string]struct { - rowID orm.RowID + rowID RowID src codec.ProtoMarshaler expErr *errors.Error }{ @@ -62,7 +62,7 @@ func TestCreate(t *testing.T) { Id: 1, Name: "some name", }, - expErr: orm.ErrEmptyKey, + expErr: ErrEmptyKey, }, "happy path": { rowID: EncodeSequence(1), @@ -97,10 +97,11 @@ func TestCreate(t *testing.T) { store := ctx.KVStore(sdk.NewKVStoreKey("test")) const anyPrefix = 0x10 - tableBuilder := newTableBuilder(anyPrefix, &testdata.TableModel{}, cdc) + tableBuilder, err := newTableBuilder(anyPrefix, &testdata.TableModel{}, cdc) + require.NoError(t, err) myTable := tableBuilder.Build() - err := myTable.Create(store, spec.rowID, spec.src) + err = myTable.Create(store, spec.rowID, spec.src) require.True(t, spec.expErr.Is(err), err) shouldExists := spec.expErr == nil @@ -154,7 +155,8 @@ func TestUpdate(t *testing.T) { store := ctx.KVStore(sdk.NewKVStoreKey("test")) const anyPrefix = 0x10 - tableBuilder := newTableBuilder(anyPrefix, &testdata.TableModel{}, cdc) + tableBuilder, err := newTableBuilder(anyPrefix, &testdata.TableModel{}, cdc) + require.NoError(t, err) myTable := tableBuilder.Build() initValue := testdata.TableModel{ @@ -162,7 +164,7 @@ func TestUpdate(t *testing.T) { Name: "old name", } - err := myTable.Create(store, EncodeSequence(1), &initValue) + err = myTable.Create(store, EncodeSequence(1), &initValue) require.NoError(t, err) // when @@ -203,7 +205,8 @@ func TestDelete(t *testing.T) { store := ctx.KVStore(sdk.NewKVStoreKey("test")) const anyPrefix = 0x10 - tableBuilder := newTableBuilder(anyPrefix, &testdata.TableModel{}, FixLengthIndexKeys(EncodedSeqLength), cdc) + tableBuilder, err := newTableBuilder(anyPrefix, &testdata.TableModel{}, cdc) + require.NoError(t, err) myTable := tableBuilder.Build() initValue := testdata.TableModel{ @@ -211,7 +214,7 @@ func TestDelete(t *testing.T) { Name: "some name", } - err := myTable.Create(store, EncodeSequence(1), &initValue) + err = myTable.Create(store, EncodeSequence(1), &initValue) require.NoError(t, err) // when diff --git a/x/group/internal/orm/types.go b/x/group/internal/orm/types.go index 3365468196ef..5f323327ad5b 100644 --- a/x/group/internal/orm/types.go +++ b/x/group/internal/orm/types.go @@ -13,7 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/errors" ) -const tableCodespace = "table" +const ormCodespace = "orm" var ( ErrNotFound = errors.Register(ormCodespace, 100, "not found") @@ -54,13 +54,12 @@ type Iterator interface { // This interface provides a set of functions that can be called by indexes to register and interact with the tables. type Indexable interface { RowGetter() RowGetter - IndexKeyCodec() IndexKeyCodec - AddAfterSaveInterceptor(interceptor AfterSaveInterceptor) + AddafterSetInterceptor(interceptor AfterSetInterceptor) AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) } -// AfterSaveInterceptor defines a callback function to be called on Create + Update. -type AfterSaveInterceptor func(store sdk.KVStore, rowID RowID, newValue, oldValue codec.ProtoMarshaler) error +// AfterSetInterceptor defines a callback function to be called on Create + Update. +type AfterSetInterceptor func(store sdk.KVStore, rowID RowID, newValue, oldValue codec.ProtoMarshaler) error // AfterDeleteInterceptor defines a callback function to be called on Delete operations. type AfterDeleteInterceptor func(store sdk.KVStore, rowID RowID, value codec.ProtoMarshaler) error From ce212523d059a0e4493cc6c4b2b428f1822680a1 Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 8 Oct 2021 12:21:33 +0200 Subject: [PATCH 15/26] Update README --- x/group/internal/orm/spec/README.md | 13 +++++++++++-- x/group/internal/orm/table.go | 4 ++-- x/group/internal/orm/types.go | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/x/group/internal/orm/spec/README.md b/x/group/internal/orm/spec/README.md index 686ffaec6a86..c56cde5b3e3e 100644 --- a/x/group/internal/orm/spec/README.md +++ b/x/group/internal/orm/spec/README.md @@ -2,6 +2,8 @@ The orm package provides a framework for creating relational database tables with primary and secondary keys. +### Tables + ```go type table struct { model reflect.Type @@ -12,6 +14,13 @@ type table struct { } ``` -Such table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling. -In the prefix store, entities are stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter, string or dynamic size bytes. +A table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling. +In the prefix store, entities should be stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter, string or dynamic size bytes. Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store. + +The `table` struct does not: + - enforce uniqueness of the `RowID` + - enforce prefix uniqueness of keys, i.e. not allowing one key to be a prefix + of another + - optimize Gas usage conditions +The `table` struct is private, so that we only have custom tables built on top of it, that do satisfy these requirements. \ No newline at end of file diff --git a/x/group/internal/orm/table.go b/x/group/internal/orm/table.go index 4a336415b026..3d784f5e66d7 100644 --- a/x/group/internal/orm/table.go +++ b/x/group/internal/orm/table.go @@ -51,8 +51,8 @@ func (a tableBuilder) Build() table { } } -// AddafterSetInterceptor can be used to register a callback function that is executed after an object is created and/or updated. -func (a *tableBuilder) AddafterSetInterceptor(interceptor AfterSetInterceptor) { +// AddAfterSetInterceptor can be used to register a callback function that is executed after an object is created and/or updated. +func (a *tableBuilder) AddAfterSetInterceptor(interceptor AfterSetInterceptor) { a.afterSet = append(a.afterSet, interceptor) } diff --git a/x/group/internal/orm/types.go b/x/group/internal/orm/types.go index 5f323327ad5b..e6d05a2081b5 100644 --- a/x/group/internal/orm/types.go +++ b/x/group/internal/orm/types.go @@ -54,7 +54,7 @@ type Iterator interface { // This interface provides a set of functions that can be called by indexes to register and interact with the tables. type Indexable interface { RowGetter() RowGetter - AddafterSetInterceptor(interceptor AfterSetInterceptor) + AddAfterSetInterceptor(interceptor AfterSetInterceptor) AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) } From 560662e579092f85b0476f3f7fc0da985ec0ceb8 Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 8 Oct 2021 12:39:12 +0200 Subject: [PATCH 16/26] Fix tests --- x/group/internal/orm/testsupport.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x/group/internal/orm/testsupport.go b/x/group/internal/orm/testsupport.go index 72b05ea92b5d..07316145404c 100644 --- a/x/group/internal/orm/testsupport.go +++ b/x/group/internal/orm/testsupport.go @@ -3,6 +3,7 @@ package orm import ( "github.com/cosmos/cosmos-sdk/store" "github.com/cosmos/cosmos-sdk/store/types" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" dbm "github.com/tendermint/tm-db" ) @@ -20,11 +21,11 @@ func NewMockContext() *MockContext { } } -func (m MockContext) KVStore(key sdk.StoreKey) sdk.KVStore { +func (m MockContext) KVStore(key storetypes.StoreKey) sdk.KVStore { if s := m.store.GetCommitKVStore(key); s != nil { return s } - m.store.MountStoreWithDB(key, sdk.StoreTypeIAVL, m.db) + m.store.MountStoreWithDB(key, storetypes.StoreTypeIAVL, m.db) if err := m.store.LoadLatestVersion(); err != nil { panic(err) } From bb495f7328d82594b448c405b45b4fac1a5bea87 Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 8 Oct 2021 13:04:11 +0200 Subject: [PATCH 17/26] Use [2]byte for table prefix key --- x/group/internal/orm/table.go | 22 +++++++++++----------- x/group/internal/orm/table_test.go | 8 ++++---- x/group/internal/orm/types.go | 4 ++-- x/group/internal/orm/types_test.go | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/x/group/internal/orm/table.go b/x/group/internal/orm/table.go index 3d784f5e66d7..c3a829728ec0 100644 --- a/x/group/internal/orm/table.go +++ b/x/group/internal/orm/table.go @@ -13,14 +13,14 @@ var _ Indexable = &tableBuilder{} type tableBuilder struct { model reflect.Type - prefixData byte + prefix [2]byte afterSet []AfterSetInterceptor afterDelete []AfterDeleteInterceptor cdc codec.Codec } // newTableBuilder creates a builder to setup a table object. -func newTableBuilder(prefixData byte, model codec.ProtoMarshaler, cdc codec.Codec) (*tableBuilder, error) { +func newTableBuilder(prefix [2]byte, model codec.ProtoMarshaler, cdc codec.Codec) (*tableBuilder, error) { if model == nil { return nil, ErrArgument.Wrap("Model must not be nil") } @@ -29,22 +29,22 @@ func newTableBuilder(prefixData byte, model codec.ProtoMarshaler, cdc codec.Code tp = tp.Elem() } return &tableBuilder{ - prefixData: prefixData, - model: tp, - cdc: cdc, + prefix: prefix, + model: tp, + cdc: cdc, }, nil } // RowGetter returns a type safe RowGetter. func (a tableBuilder) RowGetter() RowGetter { - return NewTypeSafeRowGetter(a.prefixData, a.model, a.cdc) + return NewTypeSafeRowGetter(a.prefix, a.model, a.cdc) } // Build creates a new table object. func (a tableBuilder) Build() table { return table{ model: a.model, - prefix: a.prefixData, + prefix: a.prefix, afterSet: a.afterSet, afterDelete: a.afterDelete, cdc: a.cdc, @@ -73,7 +73,7 @@ func (a *tableBuilder) AddAfterDeleteInterceptor(interceptor AfterDeleteIntercep // these requirements. type table struct { model reflect.Type - prefix byte + prefix [2]byte afterSet []AfterSetInterceptor afterDelete []AfterDeleteInterceptor cdc codec.Codec @@ -123,7 +123,7 @@ func (a table) Set(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler return err } - pStore := prefix.NewStore(store, []byte{a.prefix}) + pStore := prefix.NewStore(store, a.prefix[:]) var oldValue codec.ProtoMarshaler if a.Has(store, rowID) { @@ -161,7 +161,7 @@ func assertValid(obj codec.ProtoMarshaler) error { // Delete iterates through the registered callbacks that remove secondary index // keys. func (a table) Delete(store sdk.KVStore, rowID RowID) error { - pStore := prefix.NewStore(store, []byte{a.prefix}) + pStore := prefix.NewStore(store, a.prefix[:]) var oldValue = reflect.New(a.model).Interface().(codec.ProtoMarshaler) if err := a.GetOne(store, rowID, oldValue); err != nil { @@ -183,7 +183,7 @@ func (a table) Has(store sdk.KVStore, key RowID) bool { if len(key) == 0 { return false } - pStore := prefix.NewStore(store, []byte{a.prefix}) + pStore := prefix.NewStore(store, a.prefix[:]) it := pStore.Iterator(PrefixRange(key)) defer it.Close() return it.Valid() diff --git a/x/group/internal/orm/table_test.go b/x/group/internal/orm/table_test.go index 81bd08cc3547..ebc012c216f9 100644 --- a/x/group/internal/orm/table_test.go +++ b/x/group/internal/orm/table_test.go @@ -38,7 +38,7 @@ func TestNewTableBuilder(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - builder, err := newTableBuilder(0x1, tc.model, cdc) + builder, err := newTableBuilder([2]byte{0x1}, tc.model, cdc) if tc.expectErr { require.Error(t, err) require.Contains(t, err.Error(), tc.expectedErr) @@ -96,7 +96,7 @@ func TestCreate(t *testing.T) { ctx := NewMockContext() store := ctx.KVStore(sdk.NewKVStoreKey("test")) - const anyPrefix = 0x10 + var anyPrefix = [2]byte{0x10} tableBuilder, err := newTableBuilder(anyPrefix, &testdata.TableModel{}, cdc) require.NoError(t, err) myTable := tableBuilder.Build() @@ -154,7 +154,7 @@ func TestUpdate(t *testing.T) { ctx := NewMockContext() store := ctx.KVStore(sdk.NewKVStoreKey("test")) - const anyPrefix = 0x10 + var anyPrefix = [2]byte{0x10} tableBuilder, err := newTableBuilder(anyPrefix, &testdata.TableModel{}, cdc) require.NoError(t, err) myTable := tableBuilder.Build() @@ -204,7 +204,7 @@ func TestDelete(t *testing.T) { ctx := NewMockContext() store := ctx.KVStore(sdk.NewKVStoreKey("test")) - const anyPrefix = 0x10 + var anyPrefix = [2]byte{0x10} tableBuilder, err := newTableBuilder(anyPrefix, &testdata.TableModel{}, cdc) require.NoError(t, err) myTable := tableBuilder.Build() diff --git a/x/group/internal/orm/types.go b/x/group/internal/orm/types.go index e6d05a2081b5..3e4be48a4a83 100644 --- a/x/group/internal/orm/types.go +++ b/x/group/internal/orm/types.go @@ -69,7 +69,7 @@ type AfterDeleteInterceptor func(store sdk.KVStore, rowID RowID, value codec.Pro type RowGetter func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error // NewTypeSafeRowGetter returns a `RowGetter` with type check on the dest parameter. -func NewTypeSafeRowGetter(prefixKey byte, model reflect.Type, cdc codec.Codec) RowGetter { +func NewTypeSafeRowGetter(prefixKey [2]byte, model reflect.Type, cdc codec.Codec) RowGetter { return func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error { if len(rowID) == 0 { return errors.Wrap(ErrArgument, "key must not be nil") @@ -78,7 +78,7 @@ func NewTypeSafeRowGetter(prefixKey byte, model reflect.Type, cdc codec.Codec) R return err } - pStore := prefix.NewStore(store, []byte{prefixKey}) + pStore := prefix.NewStore(store, prefixKey[:]) it := pStore.Iterator(PrefixRange(rowID)) defer it.Close() if !it.Valid() { diff --git a/x/group/internal/orm/types_test.go b/x/group/internal/orm/types_test.go index afeaf76d7b2c..e00e2fdde243 100644 --- a/x/group/internal/orm/types_test.go +++ b/x/group/internal/orm/types_test.go @@ -17,8 +17,8 @@ import ( func TestTypeSafeRowGetter(t *testing.T) { storeKey := sdk.NewKVStoreKey("test") ctx := NewMockContext() - const prefixKey = 0x2 - store := prefix.NewStore(ctx.KVStore(storeKey), []byte{prefixKey}) + var prefixKey = [2]byte{0x2} + store := prefix.NewStore(ctx.KVStore(storeKey), prefixKey[:]) md := testdata.TableModel{ Id: 1, Name: "some name", From 915d734a27d8fb0cba728a43bd56b565b9f66a93 Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 8 Oct 2021 13:04:40 +0200 Subject: [PATCH 18/26] Update docs --- x/group/internal/orm/spec/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/group/internal/orm/spec/README.md b/x/group/internal/orm/spec/README.md index c56cde5b3e3e..edf57ce74f27 100644 --- a/x/group/internal/orm/spec/README.md +++ b/x/group/internal/orm/spec/README.md @@ -7,7 +7,7 @@ The orm package provides a framework for creating relational database tables wit ```go type table struct { model reflect.Type - prefix byte + prefix [2]byte afterSet []AfterSetInterceptor afterDelete []AfterDeleteInterceptor cdc codec.Codec From e3aa3e8d84ba23f1ea0a2e6c2e4ef8bf8de7ba2f Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 8 Oct 2021 13:21:34 +0200 Subject: [PATCH 19/26] Rm file --- container/main/graph.svg | 234 --------------------------------------- 1 file changed, 234 deletions(-) delete mode 100644 container/main/graph.svg diff --git a/container/main/graph.svg b/container/main/graph.svg deleted file mode 100644 index 8c374f8e8997..000000000000 --- a/container/main/graph.svg +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - -cluster_b - -Scope: b - - -cluster_a - -Scope: a - - - - -[]main.Command - -[]main.Command - - - -main.main.func1 - -main.main.func1 - - - -[]main.Command->main.main.func1 - - - - - - -map[string]main.Handler - -map[string]main.Handler - - - -map[string]main.Handler->main.main.func1 - - - - - -main.ProvideKVStoreKey - -main.ProvideKVStoreKey - - - -main.KVStoreKey - -main.KVStoreKey - - - -main.ProvideKVStoreKey->main.KVStoreKey - - - - - -container.Scope - -container.Scope - - - -container.Scope->main.ProvideKVStoreKey - - - - - -main.ProvideModuleKey - -main.ProvideModuleKey - - - -container.Scope->main.ProvideModuleKey - - - - - -main.ProvideMsgClientA - -main.ProvideMsgClientA - - - -container.Scope->main.ProvideMsgClientA - - - - - -main.ModuleB.Provide - -main.ModuleB.Provide - - - -container.Scope->main.ModuleB.Provide - - - - - -main.ModuleA.Provide - -main.ModuleA.Provide - - - -main.KVStoreKey->main.ModuleA.Provide - - - - - -main.KVStoreKey->main.ModuleB.Provide - - - - - -main.ModuleKey - -main.ModuleKey - - - -main.ProvideModuleKey->main.ModuleKey - - - - - -main.ModuleKey->main.ProvideMsgClientA - - - - - -main.MsgClientA - -main.MsgClientA - - - -main.ProvideMsgClientA->main.MsgClientA - - - - - -main.MsgClientA->main.ModuleB.Provide - - - - - -main.ModuleA.Provide->[]main.Command - - - - - -main.ModuleA.Provide->map[string]main.Handler - - - - - -main.KeeperA - -main.KeeperA - - - -main.ModuleA.Provide->main.KeeperA - - - - - -main.KeeperA->main.main.func1 - - - - - -main.ModuleB.Provide->[]main.Command - - - - - -main.ModuleB.Provide->map[string]main.Handler - - - - - -main.KeeperB - -main.KeeperB - - - -main.ModuleB.Provide->main.KeeperB - - - - - -main.KeeperB->main.main.func1 - - - - - From df0c30466b821bdaf33b1a3fc8c8d455fc85ba52 Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 8 Oct 2021 13:22:35 +0200 Subject: [PATCH 20/26] Rm file --- container/main/main.go | 127 ----------------------------------------- 1 file changed, 127 deletions(-) delete mode 100644 container/main/main.go diff --git a/container/main/main.go b/container/main/main.go deleted file mode 100644 index d86eab0911f6..000000000000 --- a/container/main/main.go +++ /dev/null @@ -1,127 +0,0 @@ -package main - -import ( - "reflect" - - "github.com/cosmos/cosmos-sdk/container" -) - -type KVStoreKey struct { - name string -} - -type ModuleKey string - -type MsgClientA struct { - key ModuleKey -} - -type KeeperA struct { - key KVStoreKey -} - -type KeeperB struct { - key KVStoreKey - msgClientA MsgClientA -} - -type Handler struct { - Handle func() -} - -type Command struct { - Run func() -} - -func ProvideKVStoreKey(scope container.Scope) KVStoreKey { - return KVStoreKey{name: scope.Name()} -} - -func ProvideModuleKey(scope container.Scope) (ModuleKey, error) { - return ModuleKey(scope.Name()), nil -} - -func ProvideMsgClientA(_ container.Scope, key ModuleKey) MsgClientA { - return MsgClientA{key} -} - -type ModuleA struct{} - -func (ModuleA) Provide(key KVStoreKey) (KeeperA, Handler, Command) { - return KeeperA{key}, Handler{}, Command{} -} - -type ModuleB struct{} - -type BDependencies struct { - container.In - - Key KVStoreKey - A MsgClientA -} - -type BProvides struct { - container.Out - - KeeperB KeeperB - Commands []Command -} - -func (ModuleB) Provide(dependencies BDependencies, _ container.Scope) (BProvides, Handler, error) { - return BProvides{ - KeeperB: KeeperB{ - key: dependencies.Key, - msgClientA: dependencies.A, - }, - Commands: []Command{{}, {}}, - }, Handler{}, nil -} - -func main() { - container.Run( - func(handlers map[string]Handler, commands []Command, a KeeperA, b KeeperB) { - // require.Len(t, handlers, 2) - // require.Equal(t, Handler{}, handlers["a"]) - // require.Equal(t, Handler{}, handlers["b"]) - // require.Len(t, commands, 3) - // require.Equal(t, KeeperA{ - // key: KVStoreKey{name: "a"}, - // }, a) - // require.Equal(t, KeeperB{ - // key: KVStoreKey{name: "b"}, - // msgClientA: MsgClientA{ - // key: "b", - // }, - // }, b) - }, - container.AutoGroupTypes(reflect.TypeOf(Command{})), - container.OnePerScopeTypes(reflect.TypeOf(Handler{})), - container.Provide( - ProvideKVStoreKey, - ProvideModuleKey, - ProvideMsgClientA, - ), - container.ProvideWithScope("a", wrapMethod0(ModuleA{})), - container.ProvideWithScope("b", wrapMethod0(ModuleB{})), - container.Visualizer(func(g string) { - }), - container.LogVisualizer(), - container.FileVisualizer("graph", "svg"), - container.StdoutLogger(), - ) -} - -func wrapMethod0(module interface{}) interface{} { - methodFn := reflect.TypeOf(module).Method(0).Func.Interface() - ctrInfo, err := container.ExtractProviderDescriptor(methodFn) - if err != nil { - panic(err) - } - - ctrInfo.Inputs = ctrInfo.Inputs[1:] - fn := ctrInfo.Fn - ctrInfo.Fn = func(values []reflect.Value) ([]reflect.Value, error) { - return fn(append([]reflect.Value{reflect.ValueOf(module)}, values...)) - } - return ctrInfo -} From 661d4496257c3d6846a0b26862fd831cedf09903 Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 8 Oct 2021 13:23:41 +0200 Subject: [PATCH 21/26] Revert store/README --- store/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/store/README.md b/store/README.md index 1b50239a7f81..8541f69673ad 100644 --- a/store/README.md +++ b/store/README.md @@ -127,6 +127,3 @@ type Store struct { ``` `Store.Store` is a `dbadapter.Store` with a `dbm.NewMemDB()`. All `KVStore` methods are reused. When `Store.Commit()` is called, new `dbadapter.Store` is assigned, discarding previous reference and making it garbage collected. - - - From b47264d928678534d7dbdf281e15bead04f9016e Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 8 Oct 2021 13:46:30 +0200 Subject: [PATCH 22/26] Register errors in types/errors --- types/errors/errors.go | 21 +++++++++++++++++++++ x/group/errors.go | 2 +- x/group/internal/orm/sequence.go | 2 +- x/group/internal/orm/sequence_test.go | 3 ++- x/group/internal/orm/table.go | 18 +++++++++--------- x/group/internal/orm/table_test.go | 14 +++++++------- x/group/internal/orm/types.go | 23 +++++------------------ x/group/internal/orm/types_test.go | 12 ++++++------ 8 files changed, 52 insertions(+), 43 deletions(-) diff --git a/types/errors/errors.go b/types/errors/errors.go index 50b1311099ad..7b1f6f4c34a7 100644 --- a/types/errors/errors.go +++ b/types/errors/errors.go @@ -16,6 +16,9 @@ const UndefinedCodespace = "undefined" // mathCodespace is the codespace for all errors defined in math package const mathCodespace = "math" +// mathCodespace is the codespace for all errors defined in orm package +const ormCodespace = "orm" + var ( // errInternal should never be exposed, but we reserve this code for non-specified errors errInternal = Register(UndefinedCodespace, 1, "internal") @@ -153,6 +156,24 @@ var ( // ErrInvalidDecString defines an error for an invalid decimal string ErrInvalidDecString = Register(mathCodespace, 41, "invalid decimal string") + + // ErrIteratorDone defines an error when an iterator is done + ErrIteratorDone = Register(ormCodespace, 42, "iterator done") + + // ErrInvalidIterator defines an error for an invalid iterator + ErrInvalidIterator = Register(ormCodespace, 43, "invalid iterator") + + // ErrUniqueConstraint defines an error when a value already exists at a given key + ErrUniqueConstraint = Register(ormCodespace, 44, "unique constraint violation") + + // ErrEmptyModel defines an error when an empty model is provided for building a table + ErrEmptyModel = Register(ormCodespace, 45, "invalid argument") + + // ErrIndexKeyMaxLength defines an error when a key exceeds max length + ErrKeyMaxLength = Register(ormCodespace, 46, "index key exceeds max length") + + // ErrEmptyModel defines an error for an empty key + ErrEmptyKey = Register(ormCodespace, 47, "cannot use empty key") ) // Register returns an error instance that should be used as the base for diff --git a/x/group/errors.go b/x/group/errors.go index fee486c49607..2cf0e2ce1949 100644 --- a/x/group/errors.go +++ b/x/group/errors.go @@ -8,7 +8,7 @@ var ( ErrEmpty = errors.Register(ModuleName, 2, "value is empty") ErrDuplicate = errors.Register(ModuleName, 3, "duplicate value") ErrMaxLimit = errors.Register(ModuleName, 4, "limit exceeded") - ErrType = errors.Register(ModuleName, 5, "invalid type") + errors.ErrInvalidType = errors.Register(ModuleName, 5, "invalid type") ErrInvalid = errors.Register(ModuleName, 6, "invalid value") ErrUnauthorized = errors.Register(ModuleName, 7, "unauthorized") ErrModified = errors.Register(ModuleName, 8, "modified") diff --git a/x/group/internal/orm/sequence.go b/x/group/internal/orm/sequence.go index d60555a423ab..dbec3ee75b6b 100644 --- a/x/group/internal/orm/sequence.go +++ b/x/group/internal/orm/sequence.go @@ -55,7 +55,7 @@ func (s Sequence) PeekNextVal(store sdk.KVStore) uint64 { func (s Sequence) InitVal(store sdk.KVStore, seq uint64) error { pStore := prefix.NewStore(store, []byte{s.prefix}) if pStore.Has(sequenceStorageKey) { - return errors.Wrap(ErrUniqueConstraint, "already initialized") + return errors.Wrap(errors.ErrUniqueConstraint, "already initialized") } pStore.Set(sequenceStorageKey, EncodeSequence(seq)) return nil diff --git a/x/group/internal/orm/sequence_test.go b/x/group/internal/orm/sequence_test.go index a7e1f750c80a..5d3d256cf8e3 100644 --- a/x/group/internal/orm/sequence_test.go +++ b/x/group/internal/orm/sequence_test.go @@ -4,6 +4,7 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -16,7 +17,7 @@ func TestSequenceUniqueConstraint(t *testing.T) { err := seq.InitVal(store, 2) require.NoError(t, err) err = seq.InitVal(store, 3) - require.True(t, ErrUniqueConstraint.Is(err)) + require.True(t, errors.ErrUniqueConstraint.Is(err)) } func TestSequenceIncrements(t *testing.T) { diff --git a/x/group/internal/orm/table.go b/x/group/internal/orm/table.go index c3a829728ec0..13e2f61005db 100644 --- a/x/group/internal/orm/table.go +++ b/x/group/internal/orm/table.go @@ -22,7 +22,7 @@ type tableBuilder struct { // newTableBuilder creates a builder to setup a table object. func newTableBuilder(prefix [2]byte, model codec.ProtoMarshaler, cdc codec.Codec) (*tableBuilder, error) { if model == nil { - return nil, ErrArgument.Wrap("Model must not be nil") + return nil, errors.ErrEmptyModel.Wrap("Model must not be nil") } tp := reflect.TypeOf(model) if tp.Kind() == reflect.Ptr { @@ -80,20 +80,20 @@ type table struct { } // Create persists the given object under the rowID key, returning an -// ErrUniqueConstraint if a value already exists at that key. +// errors.ErrUniqueConstraint if a value already exists at that key. // // Create iterates through the registered callbacks that may add secondary index // keys. func (a table) Create(store sdk.KVStore, rowID RowID, obj codec.ProtoMarshaler) error { if a.Has(store, rowID) { - return ErrUniqueConstraint + return errors.ErrUniqueConstraint } return a.Set(store, rowID, obj) } // Update updates the given object under the rowID key. It expects the key to -// exists already and fails with an `ErrNotFound` otherwise. Any caller must +// exists already and fails with an `errors.ErrNotFound` otherwise. Any caller must // therefore make sure that this contract is fulfilled. Parameters must not be // nil. // @@ -101,7 +101,7 @@ func (a table) Create(store sdk.KVStore, rowID RowID, obj codec.ProtoMarshaler) // secondary index keys. func (a table) Update(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler) error { if !a.Has(store, rowID) { - return ErrNotFound + return errors.ErrNotFound } return a.Set(store, rowID, newValue) @@ -114,7 +114,7 @@ func (a table) Update(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarsha // keys. func (a table) Set(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler) error { if len(rowID) == 0 { - return ErrEmptyKey + return errors.ErrEmptyKey } if err := assertCorrectType(a.model, newValue); err != nil { return err @@ -155,7 +155,7 @@ func assertValid(obj codec.ProtoMarshaler) error { } // Delete removes the object under the rowID key. It expects the key to exists -// already and fails with a `ErrNotFound` otherwise. Any caller must therefore +// already and fails with a `errors.ErrNotFound` otherwise. Any caller must therefore // make sure that this contract is fulfilled. // // Delete iterates through the registered callbacks that remove secondary index @@ -190,11 +190,11 @@ func (a table) Has(store sdk.KVStore, key RowID) bool { } // GetOne load the object persisted for the given RowID into the dest parameter. -// If none exists or `rowID==nil` then `ErrNotFound` is returned instead. +// If none exists or `rowID==nil` then `errors.ErrNotFound` is returned instead. // Parameters must not be nil - we don't allow creation of values with empty keys. func (a table) GetOne(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error { if len(rowID) == 0 { - return ErrNotFound + return errors.ErrNotFound } x := NewTypeSafeRowGetter(a.prefix, a.model, a.cdc) return x(store, rowID, dest) diff --git a/x/group/internal/orm/table_test.go b/x/group/internal/orm/table_test.go index ebc012c216f9..bf5d69c2fa58 100644 --- a/x/group/internal/orm/table_test.go +++ b/x/group/internal/orm/table_test.go @@ -62,7 +62,7 @@ func TestCreate(t *testing.T) { Id: 1, Name: "some name", }, - expErr: ErrEmptyKey, + expErr: errors.ErrEmptyKey, }, "happy path": { rowID: EncodeSequence(1), @@ -77,7 +77,7 @@ func TestCreate(t *testing.T) { Moniker: "cat moniker", Lives: 10, }, - expErr: ErrType, + expErr: errors.ErrInvalidType, }, "model validation fails": { rowID: EncodeSequence(1), @@ -111,7 +111,7 @@ func TestCreate(t *testing.T) { var loaded testdata.TableModel err = myTable.GetOne(store, spec.rowID, &loaded) if spec.expErr != nil { - require.True(t, ErrNotFound.Is(err)) + require.True(t, errors.ErrNotFound.Is(err)) return } require.NoError(t, err) @@ -136,7 +136,7 @@ func TestUpdate(t *testing.T) { Moniker: "cat moniker", Lives: 10, }, - expErr: ErrType, + expErr: errors.ErrInvalidType, }, "model validation fails": { src: &testdata.TableModel{ @@ -193,7 +193,7 @@ func TestDelete(t *testing.T) { }, "not found": { rowId: []byte("not-found"), - expErr: ErrNotFound, + expErr: errors.ErrNotFound, }, } for msg, spec := range specs { @@ -223,13 +223,13 @@ func TestDelete(t *testing.T) { // then var loaded testdata.TableModel - if spec.expErr == ErrNotFound { + if spec.expErr == errors.ErrNotFound { require.NoError(t, myTable.GetOne(store, EncodeSequence(1), &loaded)) assert.Equal(t, initValue, loaded) } else { err := myTable.GetOne(store, EncodeSequence(1), &loaded) require.Error(t, err) - require.Equal(t, err, ErrNotFound) + require.Equal(t, err, errors.ErrNotFound) } }) } diff --git a/x/group/internal/orm/types.go b/x/group/internal/orm/types.go index 3e4be48a4a83..35b1f0f4f5dd 100644 --- a/x/group/internal/orm/types.go +++ b/x/group/internal/orm/types.go @@ -13,19 +13,6 @@ import ( "github.com/cosmos/cosmos-sdk/types/errors" ) -const ormCodespace = "orm" - -var ( - ErrNotFound = errors.Register(ormCodespace, 100, "not found") - ErrIteratorDone = errors.Register(ormCodespace, 101, "iterator done") - ErrIteratorInvalid = errors.Register(ormCodespace, 102, "iterator invalid") - ErrType = errors.Register(ormCodespace, 110, "invalid type") - ErrUniqueConstraint = errors.Register(ormCodespace, 111, "unique constraint violation") - ErrArgument = errors.Register(ormCodespace, 112, "invalid argument") - ErrIndexKeyMaxLength = errors.Register(ormCodespace, 113, "index key exceeds max length") - ErrEmptyKey = errors.Register(ormCodespace, 114, "cannot use empty key") -) - // Unique identifier of a persistent table. type RowID []byte @@ -65,14 +52,14 @@ type AfterSetInterceptor func(store sdk.KVStore, rowID RowID, newValue, oldValue type AfterDeleteInterceptor func(store sdk.KVStore, rowID RowID, value codec.ProtoMarshaler) error // RowGetter loads a persistent object by row ID into the destination object. The dest parameter must therefore be a pointer. -// Any implementation must return `ErrNotFound` when no object for the rowID exists +// Any implementation must return `errors.ErrNotFound` when no object for the rowID exists type RowGetter func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error // NewTypeSafeRowGetter returns a `RowGetter` with type check on the dest parameter. func NewTypeSafeRowGetter(prefixKey [2]byte, model reflect.Type, cdc codec.Codec) RowGetter { return func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error { if len(rowID) == 0 { - return errors.Wrap(ErrArgument, "key must not be nil") + return errors.Wrap(errors.ErrEmptyKey, "key must not be nil") } if err := assertCorrectType(model, dest); err != nil { return err @@ -82,7 +69,7 @@ func NewTypeSafeRowGetter(prefixKey [2]byte, model reflect.Type, cdc codec.Codec it := pStore.Iterator(PrefixRange(rowID)) defer it.Close() if !it.Valid() { - return ErrNotFound + return errors.ErrNotFound } return cdc.Unmarshal(it.Value(), dest) } @@ -91,10 +78,10 @@ func NewTypeSafeRowGetter(prefixKey [2]byte, model reflect.Type, cdc codec.Codec func assertCorrectType(model reflect.Type, obj codec.ProtoMarshaler) error { tp := reflect.TypeOf(obj) if tp.Kind() != reflect.Ptr { - return errors.Wrap(ErrType, "model destination must be a pointer") + return errors.Wrap(errors.ErrInvalidType, "model destination must be a pointer") } if model != tp.Elem() { - return errors.Wrapf(ErrType, "can not use %T with this bucket", obj) + return errors.Wrapf(errors.ErrInvalidType, "can not use %T with this bucket", obj) } return nil } diff --git a/x/group/internal/orm/types_test.go b/x/group/internal/orm/types_test.go index e00e2fdde243..e5ef4ecf5ab1 100644 --- a/x/group/internal/orm/types_test.go +++ b/x/group/internal/orm/types_test.go @@ -38,24 +38,24 @@ func TestTypeSafeRowGetter(t *testing.T) { srcModelType: reflect.TypeOf(testdata.TableModel{}), expObj: md, }, - "unknown rowID should return ErrNotFound": { + "unknown rowID should return errors.ErrNotFound": { srcRowID: EncodeSequence(2), srcModelType: reflect.TypeOf(testdata.TableModel{}), - expErr: ErrNotFound, + expErr: errors.ErrNotFound, }, - "wrong type should cause ErrType": { + "wrong type should cause errors.ErrInvalidType": { srcRowID: EncodeSequence(1), srcModelType: reflect.TypeOf(testdata.Cat{}), - expErr: ErrType, + expErr: errors.ErrInvalidType, }, "empty rowID not allowed": { srcRowID: []byte{}, srcModelType: reflect.TypeOf(testdata.TableModel{}), - expErr: ErrArgument, + expErr: errors.ErrEmptyKey, }, "nil rowID not allowed": { srcModelType: reflect.TypeOf(testdata.TableModel{}), - expErr: ErrArgument, + expErr: errors.ErrEmptyKey, }, } for msg, spec := range specs { From 00b97d8691e43b75d3250467a99817811faf4ebd Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 8 Oct 2021 13:48:12 +0200 Subject: [PATCH 23/26] Fix group err --- x/group/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/group/errors.go b/x/group/errors.go index 2cf0e2ce1949..fee486c49607 100644 --- a/x/group/errors.go +++ b/x/group/errors.go @@ -8,7 +8,7 @@ var ( ErrEmpty = errors.Register(ModuleName, 2, "value is empty") ErrDuplicate = errors.Register(ModuleName, 3, "duplicate value") ErrMaxLimit = errors.Register(ModuleName, 4, "limit exceeded") - errors.ErrInvalidType = errors.Register(ModuleName, 5, "invalid type") + ErrType = errors.Register(ModuleName, 5, "invalid type") ErrInvalid = errors.Register(ModuleName, 6, "invalid value") ErrUnauthorized = errors.Register(ModuleName, 7, "unauthorized") ErrModified = errors.Register(ModuleName, 8, "modified") From a8b57d2b11282045e124aaeeeae3e2a9d81b8cc3 Mon Sep 17 00:00:00 2001 From: blushi Date: Thu, 21 Oct 2021 10:48:06 +0200 Subject: [PATCH 24/26] Simplify table creation --- x/group/internal/orm/table.go | 55 ++++++++++-------------------- x/group/internal/orm/table_test.go | 15 ++++---- 2 files changed, 24 insertions(+), 46 deletions(-) diff --git a/x/group/internal/orm/table.go b/x/group/internal/orm/table.go index 13e2f61005db..0be3ca50ce72 100644 --- a/x/group/internal/orm/table.go +++ b/x/group/internal/orm/table.go @@ -9,9 +9,19 @@ import ( "github.com/cosmos/cosmos-sdk/types/errors" ) -var _ Indexable = &tableBuilder{} +var _ Indexable = &table{} -type tableBuilder struct { +// table is the high level object to storage mapper functionality. Persistent +// entities are stored by an unique identifier called `RowID`. The table struct +// does not: +// - enforce uniqueness of the `RowID` +// - enforce prefix uniqueness of keys, i.e. not allowing one key to be a prefix +// of another +// - optimize Gas usage conditions +// The caller must ensure that these things are handled. The table struct is +// private, so that we only have custom tables built on top of table, that do satisfy +// these requirements. +type table struct { model reflect.Type prefix [2]byte afterSet []AfterSetInterceptor @@ -19,8 +29,8 @@ type tableBuilder struct { cdc codec.Codec } -// newTableBuilder creates a builder to setup a table object. -func newTableBuilder(prefix [2]byte, model codec.ProtoMarshaler, cdc codec.Codec) (*tableBuilder, error) { +// newTable creates a new table +func newTable(prefix [2]byte, model codec.ProtoMarshaler, cdc codec.Codec) (*table, error) { if model == nil { return nil, errors.ErrEmptyModel.Wrap("Model must not be nil") } @@ -28,7 +38,7 @@ func newTableBuilder(prefix [2]byte, model codec.ProtoMarshaler, cdc codec.Codec if tp.Kind() == reflect.Ptr { tp = tp.Elem() } - return &tableBuilder{ + return &table{ prefix: prefix, model: tp, cdc: cdc, @@ -36,49 +46,20 @@ func newTableBuilder(prefix [2]byte, model codec.ProtoMarshaler, cdc codec.Codec } // RowGetter returns a type safe RowGetter. -func (a tableBuilder) RowGetter() RowGetter { +func (a table) RowGetter() RowGetter { return NewTypeSafeRowGetter(a.prefix, a.model, a.cdc) } -// Build creates a new table object. -func (a tableBuilder) Build() table { - return table{ - model: a.model, - prefix: a.prefix, - afterSet: a.afterSet, - afterDelete: a.afterDelete, - cdc: a.cdc, - } -} - // AddAfterSetInterceptor can be used to register a callback function that is executed after an object is created and/or updated. -func (a *tableBuilder) AddAfterSetInterceptor(interceptor AfterSetInterceptor) { +func (a *table) AddAfterSetInterceptor(interceptor AfterSetInterceptor) { a.afterSet = append(a.afterSet, interceptor) } // AddAfterDeleteInterceptor can be used to register a callback function that is executed after an object is deleted. -func (a *tableBuilder) AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) { +func (a *table) AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) { a.afterDelete = append(a.afterDelete, interceptor) } -// table is the high level object to storage mapper functionality. Persistent -// entities are stored by an unique identifier called `RowID`. The table struct -// does not: -// - enforce uniqueness of the `RowID` -// - enforce prefix uniqueness of keys, i.e. not allowing one key to be a prefix -// of another -// - optimize Gas usage conditions -// The caller must ensure that these things are handled. The table struct is -// private, so that we only have custom tables built on top of table, that do satisfy -// these requirements. -type table struct { - model reflect.Type - prefix [2]byte - afterSet []AfterSetInterceptor - afterDelete []AfterDeleteInterceptor - cdc codec.Codec -} - // Create persists the given object under the rowID key, returning an // errors.ErrUniqueConstraint if a value already exists at that key. // diff --git a/x/group/internal/orm/table_test.go b/x/group/internal/orm/table_test.go index bf5d69c2fa58..511a328ce5cf 100644 --- a/x/group/internal/orm/table_test.go +++ b/x/group/internal/orm/table_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestNewTableBuilder(t *testing.T) { +func TestNewTable(t *testing.T) { interfaceRegistry := types.NewInterfaceRegistry() cdc := codec.NewProtoCodec(interfaceRegistry) @@ -38,13 +38,13 @@ func TestNewTableBuilder(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - builder, err := newTableBuilder([2]byte{0x1}, tc.model, cdc) + table, err := newTable([2]byte{0x1}, tc.model, cdc) if tc.expectErr { require.Error(t, err) require.Contains(t, err.Error(), tc.expectedErr) } else { require.NoError(t, err) - require.NotNil(t, builder) + require.NotNil(t, table) } }) } @@ -97,9 +97,8 @@ func TestCreate(t *testing.T) { store := ctx.KVStore(sdk.NewKVStoreKey("test")) var anyPrefix = [2]byte{0x10} - tableBuilder, err := newTableBuilder(anyPrefix, &testdata.TableModel{}, cdc) + myTable, err := newTable(anyPrefix, &testdata.TableModel{}, cdc) require.NoError(t, err) - myTable := tableBuilder.Build() err = myTable.Create(store, spec.rowID, spec.src) @@ -155,9 +154,8 @@ func TestUpdate(t *testing.T) { store := ctx.KVStore(sdk.NewKVStoreKey("test")) var anyPrefix = [2]byte{0x10} - tableBuilder, err := newTableBuilder(anyPrefix, &testdata.TableModel{}, cdc) + myTable, err := newTable(anyPrefix, &testdata.TableModel{}, cdc) require.NoError(t, err) - myTable := tableBuilder.Build() initValue := testdata.TableModel{ Id: 1, @@ -205,9 +203,8 @@ func TestDelete(t *testing.T) { store := ctx.KVStore(sdk.NewKVStoreKey("test")) var anyPrefix = [2]byte{0x10} - tableBuilder, err := newTableBuilder(anyPrefix, &testdata.TableModel{}, cdc) + myTable, err := newTable(anyPrefix, &testdata.TableModel{}, cdc) require.NoError(t, err) - myTable := tableBuilder.Build() initValue := testdata.TableModel{ Id: 1, From 87fc7b0eaa9dc3015d2142b32905905c2137b770 Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Thu, 21 Oct 2021 11:47:26 +0200 Subject: [PATCH 25/26] Update x/group/internal/orm/table.go Co-authored-by: Robert Zaremba --- x/group/internal/orm/table.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x/group/internal/orm/table.go b/x/group/internal/orm/table.go index 0be3ca50ce72..5883640e0c3c 100644 --- a/x/group/internal/orm/table.go +++ b/x/group/internal/orm/table.go @@ -78,8 +78,7 @@ func (a table) Create(store sdk.KVStore, rowID RowID, obj codec.ProtoMarshaler) // therefore make sure that this contract is fulfilled. Parameters must not be // nil. // -// Update iterates through the registered callbacks that may add or remove -// secondary index keys. +// Update triggers all "after set" hooks that may add or remove secondary index keys. func (a table) Update(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler) error { if !a.Has(store, rowID) { return errors.ErrNotFound From d2f9a522fc80bf0a8579269afb9708b46bab9418 Mon Sep 17 00:00:00 2001 From: blushi Date: Thu, 21 Oct 2021 12:10:27 +0200 Subject: [PATCH 26/26] Address review comments --- types/errors/errors.go | 24 ++++++++++++------------ x/group/internal/orm/sequence.go | 2 +- x/group/internal/orm/sequence_test.go | 2 +- x/group/internal/orm/table.go | 8 ++++---- x/group/internal/orm/table_test.go | 2 +- x/group/internal/orm/types.go | 4 ++-- x/group/internal/orm/types_test.go | 4 ++-- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/types/errors/errors.go b/types/errors/errors.go index 7b1f6f4c34a7..29ba3195f146 100644 --- a/types/errors/errors.go +++ b/types/errors/errors.go @@ -157,23 +157,23 @@ var ( // ErrInvalidDecString defines an error for an invalid decimal string ErrInvalidDecString = Register(mathCodespace, 41, "invalid decimal string") - // ErrIteratorDone defines an error when an iterator is done - ErrIteratorDone = Register(ormCodespace, 42, "iterator done") + // ErrORMIteratorDone defines an error when an iterator is done + ErrORMIteratorDone = Register(ormCodespace, 42, "iterator done") - // ErrInvalidIterator defines an error for an invalid iterator - ErrInvalidIterator = Register(ormCodespace, 43, "invalid iterator") + // ErrORMInvalidIterator defines an error for an invalid iterator + ErrORMInvalidIterator = Register(ormCodespace, 43, "invalid iterator") - // ErrUniqueConstraint defines an error when a value already exists at a given key - ErrUniqueConstraint = Register(ormCodespace, 44, "unique constraint violation") + // ErrORMUniqueConstraint defines an error when a value already exists at a given key + ErrORMUniqueConstraint = Register(ormCodespace, 44, "unique constraint violation") - // ErrEmptyModel defines an error when an empty model is provided for building a table - ErrEmptyModel = Register(ormCodespace, 45, "invalid argument") + // ErrORMEmptyModel defines an error when an empty model is provided for building a table + ErrORMEmptyModel = Register(ormCodespace, 45, "invalid argument") - // ErrIndexKeyMaxLength defines an error when a key exceeds max length - ErrKeyMaxLength = Register(ormCodespace, 46, "index key exceeds max length") + // ErrORMKeyMaxLength defines an error when a key exceeds max length + ErrORMKeyMaxLength = Register(ormCodespace, 46, "index key exceeds max length") - // ErrEmptyModel defines an error for an empty key - ErrEmptyKey = Register(ormCodespace, 47, "cannot use empty key") + // ErrORMEmptyKey defines an error for an empty key + ErrORMEmptyKey = Register(ormCodespace, 47, "cannot use empty key") ) // Register returns an error instance that should be used as the base for diff --git a/x/group/internal/orm/sequence.go b/x/group/internal/orm/sequence.go index dbec3ee75b6b..a8d70f7243ac 100644 --- a/x/group/internal/orm/sequence.go +++ b/x/group/internal/orm/sequence.go @@ -55,7 +55,7 @@ func (s Sequence) PeekNextVal(store sdk.KVStore) uint64 { func (s Sequence) InitVal(store sdk.KVStore, seq uint64) error { pStore := prefix.NewStore(store, []byte{s.prefix}) if pStore.Has(sequenceStorageKey) { - return errors.Wrap(errors.ErrUniqueConstraint, "already initialized") + return errors.Wrap(errors.ErrORMUniqueConstraint, "already initialized") } pStore.Set(sequenceStorageKey, EncodeSequence(seq)) return nil diff --git a/x/group/internal/orm/sequence_test.go b/x/group/internal/orm/sequence_test.go index 5d3d256cf8e3..023f7318dae2 100644 --- a/x/group/internal/orm/sequence_test.go +++ b/x/group/internal/orm/sequence_test.go @@ -17,7 +17,7 @@ func TestSequenceUniqueConstraint(t *testing.T) { err := seq.InitVal(store, 2) require.NoError(t, err) err = seq.InitVal(store, 3) - require.True(t, errors.ErrUniqueConstraint.Is(err)) + require.True(t, errors.ErrORMUniqueConstraint.Is(err)) } func TestSequenceIncrements(t *testing.T) { diff --git a/x/group/internal/orm/table.go b/x/group/internal/orm/table.go index 5883640e0c3c..f3611850045e 100644 --- a/x/group/internal/orm/table.go +++ b/x/group/internal/orm/table.go @@ -32,7 +32,7 @@ type table struct { // newTable creates a new table func newTable(prefix [2]byte, model codec.ProtoMarshaler, cdc codec.Codec) (*table, error) { if model == nil { - return nil, errors.ErrEmptyModel.Wrap("Model must not be nil") + return nil, errors.ErrORMEmptyModel.Wrap("Model must not be nil") } tp := reflect.TypeOf(model) if tp.Kind() == reflect.Ptr { @@ -61,13 +61,13 @@ func (a *table) AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) { } // Create persists the given object under the rowID key, returning an -// errors.ErrUniqueConstraint if a value already exists at that key. +// errors.ErrORMUniqueConstraint if a value already exists at that key. // // Create iterates through the registered callbacks that may add secondary index // keys. func (a table) Create(store sdk.KVStore, rowID RowID, obj codec.ProtoMarshaler) error { if a.Has(store, rowID) { - return errors.ErrUniqueConstraint + return errors.ErrORMUniqueConstraint } return a.Set(store, rowID, obj) @@ -94,7 +94,7 @@ func (a table) Update(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarsha // keys. func (a table) Set(store sdk.KVStore, rowID RowID, newValue codec.ProtoMarshaler) error { if len(rowID) == 0 { - return errors.ErrEmptyKey + return errors.ErrORMEmptyKey } if err := assertCorrectType(a.model, newValue); err != nil { return err diff --git a/x/group/internal/orm/table_test.go b/x/group/internal/orm/table_test.go index 511a328ce5cf..aff91e22417e 100644 --- a/x/group/internal/orm/table_test.go +++ b/x/group/internal/orm/table_test.go @@ -62,7 +62,7 @@ func TestCreate(t *testing.T) { Id: 1, Name: "some name", }, - expErr: errors.ErrEmptyKey, + expErr: errors.ErrORMEmptyKey, }, "happy path": { rowID: EncodeSequence(1), diff --git a/x/group/internal/orm/types.go b/x/group/internal/orm/types.go index 35b1f0f4f5dd..48e2f631839d 100644 --- a/x/group/internal/orm/types.go +++ b/x/group/internal/orm/types.go @@ -30,7 +30,7 @@ type Validateable interface { // Iterator allows iteration through a sequence of key value pairs type Iterator interface { // LoadNext loads the next value in the sequence into the pointer passed as dest and returns the key. If there - // are no more items the ErrIteratorDone error is returned + // are no more items the ErrORMIteratorDone error is returned // The key is the rowID. LoadNext(dest codec.ProtoMarshaler) (RowID, error) // Close releases the iterator and should be called at the end of iteration @@ -59,7 +59,7 @@ type RowGetter func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) e func NewTypeSafeRowGetter(prefixKey [2]byte, model reflect.Type, cdc codec.Codec) RowGetter { return func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error { if len(rowID) == 0 { - return errors.Wrap(errors.ErrEmptyKey, "key must not be nil") + return errors.Wrap(errors.ErrORMEmptyKey, "key must not be nil") } if err := assertCorrectType(model, dest); err != nil { return err diff --git a/x/group/internal/orm/types_test.go b/x/group/internal/orm/types_test.go index e5ef4ecf5ab1..bf8e3648c913 100644 --- a/x/group/internal/orm/types_test.go +++ b/x/group/internal/orm/types_test.go @@ -51,11 +51,11 @@ func TestTypeSafeRowGetter(t *testing.T) { "empty rowID not allowed": { srcRowID: []byte{}, srcModelType: reflect.TypeOf(testdata.TableModel{}), - expErr: errors.ErrEmptyKey, + expErr: errors.ErrORMEmptyKey, }, "nil rowID not allowed": { srcModelType: reflect.TypeOf(testdata.TableModel{}), - expErr: errors.ErrEmptyKey, + expErr: errors.ErrORMEmptyKey, }, } for msg, spec := range specs {