From 36c6f726909ec70dd381896f52fbbaa56caa24e8 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 15 Mar 2018 18:39:55 +0100 Subject: [PATCH 01/13] add comment & write test for Iterate()s --- types/stdlib/stdlib.go | 24 ++++++++++++++++++------ types/stdlib/stdlib_test.go | 25 ++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/types/stdlib/stdlib.go b/types/stdlib/stdlib.go index dd9f4efad1..71196fe0c3 100644 --- a/types/stdlib/stdlib.go +++ b/types/stdlib/stdlib.go @@ -1,15 +1,21 @@ -package types +package stdlib import ( - "errors" + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" ) -type ListMapper interface { // Solidity list like structure +// ListMapper is a Mapper interface that provides list-like functions +// It panics when the element type cannot be (un/)marshalled by the codec + +type ListMapper interface { + // ListMapper dosen't checks index out of range + // The user should check Len() before doing any actions Len(sdk.Context) int64 Get(sdk.Context, int64, interface{}) + // Setting element out of range is harmful; use Push() when adding new elements Set(sdk.Context, int64, interface{}) Push(sdk.Context, interface{}) Iterate(sdk.Context, interface{}, func(sdk.Context, int64)) @@ -53,7 +59,7 @@ func (lm listMapper) Len(ctx sdk.Context) int64 { func (lm listMapper) Get(ctx sdk.Context, index int64, ptr interface{}) { if index < 0 { - panic(errors.New("")) + panic(fmt.Errorf("Invalid index in ListMapper.Get(ctx, %d, ptr)", index)) } store := ctx.KVStore(lm.key) bz := store.Get(marshalInt64(lm.cdc, index)) @@ -64,7 +70,7 @@ func (lm listMapper) Get(ctx sdk.Context, index int64, ptr interface{}) { func (lm listMapper) Set(ctx sdk.Context, index int64, value interface{}) { if index < 0 { - panic(errors.New("")) + panic(fmt.Errorf("Invalid index in ListMapper.Set(ctx, %d, value)", index)) } store := ctx.KVStore(lm.key) bz, err := lm.cdc.MarshalBinary(value) @@ -90,11 +96,17 @@ func (lm listMapper) Iterate(ctx sdk.Context, ptr interface{}, fn func(sdk.Conte } } +// QueueMapper is a Mapper interface that provides queue-like functions +// It panics when the element type cannot be (un/)marshalled by the codec + type QueueMapper interface { Push(sdk.Context, interface{}) + // Popping/Peeking on an empty queue will cause panic + // The user should check IsEmpty() before doing any actions Peek(sdk.Context, interface{}) Pop(sdk.Context) IsEmpty(sdk.Context) bool + // Iterate() removes elements it processed; return true in the continuation to break Iterate(sdk.Context, interface{}, func(sdk.Context) bool) } @@ -124,7 +136,7 @@ type queueInfo struct { func (info queueInfo) validateBasic() error { if info.End < info.Begin || info.Begin < 0 || info.End < 0 { - return errors.New("") + return fmt.Errorf("Invalid queue information: {Begin: %d, End: %d}", info.Begin, info.End) } return nil } diff --git a/types/stdlib/stdlib_test.go b/types/stdlib/stdlib_test.go index 7c871ccf3c..25caa34fe0 100644 --- a/types/stdlib/stdlib_test.go +++ b/types/stdlib/stdlib_test.go @@ -1,4 +1,4 @@ -package types +package stdlib import ( "testing" @@ -46,6 +46,12 @@ func TestListMapper(t *testing.T) { lm.Set(ctx, int64(0), val) lm.Get(ctx, int64(0), &res) assert.Equal(t, val, res) + + lm.Iterate(ctx, &res, func(ctx sdk.Context, index int64) { + lm.Set(ctx, index, S{res.I + 1, !res.B}) + }) + lm.Get(ctx, int64(0), &res) + assert.Equal(t, S{3, true}, res) } func TestQueueMapper(t *testing.T) { @@ -63,7 +69,20 @@ func TestQueueMapper(t *testing.T) { qm.Pop(ctx) empty := qm.IsEmpty(ctx) - assert.Equal(t, true, empty) - + assert.True(t, empty) assert.Panics(t, func() { qm.Peek(ctx, &res) }) + + qm.Push(ctx, S{1, true}) + qm.Push(ctx, S{2, true}) + qm.Push(ctx, S{3, true}) + qm.Iterate(ctx, &res, func(ctx sdk.Context) (brk bool) { + if res.I == 3 { + brk = true + } + return + }) + + assert.False(t, qm.IsEmpty(ctx)) + qm.Pop(ctx) + assert.True(t, qm.IsEmpty(ctx)) } From cc07dce8f2cb453dea37afe57b51146d514e0c4a Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 19 Mar 2018 14:01:49 +0100 Subject: [PATCH 02/13] mock store --- mock/store.go | 104 ++++++++++++++++++++++++++++++++++++ types/stdlib/stdlib_test.go | 2 +- 2 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 mock/store.go diff --git a/mock/store.go b/mock/store.go new file mode 100644 index 0000000000..f7844e668f --- /dev/null +++ b/mock/store.go @@ -0,0 +1,104 @@ +package mock + +import ( + dbm "github.com/tendermint/tmlibs/db" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type multiStore struct { + kv map[sdk.StoreKey]kvStore +} + +func (ms multiStore) CacheMultiStore() sdk.CacheMultiStore { + panic("not implemented") +} + +func (ms multiStore) CacheWrap() sdk.CacheWrap { + panic("not implemented") +} + +func (ms multiStore) Commit() sdk.CommitID { + panic("not implemented") +} + +func (ms multiStore) LastCommitID() sdk.CommitID { + panic("not implemented") +} + +func (ms multiStore) GetCommitKVStore(key sdk.StoreKey) sdk.CommitKVStore { + panic("not implemented") +} + +func (ms multiStore) GetCommitStore(key sdk.StoreKey) sdk.CommitStore { + panic("not implemented") +} + +func (ms multiStore) MountStoreWithDB(key sdk.StoreKey, typ sdk.StoreType, db dbm.DB) { + ms.kv[key] = kvStore{store: make(map[string][]byte)} +} + +func (ms multiStore) LoadLatestVersion() error { + return nil +} + +func (md multiStore) LoadVersion(ver int64) error { + panic("not implemented") +} + +func (ms multiStore) GetKVStore(key sdk.StoreKey) sdk.KVStore { + return ms.kv[key] +} + +func (ms multiStore) GetStore(key sdk.StoreKey) sdk.Store { + panic("not implemented") +} + +func (ms multiStore) GetStoreType() sdk.StoreType { + panic("not implemented") +} + +type kvStore struct { + store map[string][]byte +} + +func (kv kvStore) CacheWrap() sdk.CacheWrap { + panic("not implemented") +} + +func (kv kvStore) GetStoreType() sdk.StoreType { + panic("not implemented") +} + +func (kv kvStore) Get(key []byte) []byte { + v, ok := kv.store[string(key)] + if !ok { + return nil + } + return v +} + +func (kv kvStore) Has(key []byte) bool { + _, ok := kv.store[string(key)] + return ok +} + +func (kv kvStore) Set(key, value []byte) { + kv.store[string(key)] = value +} + +func (kv kvStore) Delete(key []byte) { + delete(kv.store, string(key)) +} + +func (kv kvStore) Iterator(start, end []byte) sdk.Iterator { + panic("not implemented") +} + +func (kv kvStore) ReverseIterator(start, end []byte) sdk.Iterator { + panic("not implemented") +} + +func NewCommitMultiStore(db dbm.DB) sdk.CommitMultiStore { + return multiStore{kv: make(map[sdk.StoreKey]kvStore)} +} diff --git a/types/stdlib/stdlib_test.go b/types/stdlib/stdlib_test.go index 25caa34fe0..a225f148e1 100644 --- a/types/stdlib/stdlib_test.go +++ b/types/stdlib/stdlib_test.go @@ -9,7 +9,7 @@ import ( abci "github.com/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/store" + store "github.com/cosmos/cosmos-sdk/mock" sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" ) From 380fa78eae9beaa798f6c05ec845783daca04782 Mon Sep 17 00:00:00 2001 From: mossid Date: Mon, 19 Mar 2018 14:27:39 +0100 Subject: [PATCH 03/13] add test for mock/store.go --- mock/store_test.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 mock/store_test.go diff --git a/mock/store_test.go b/mock/store_test.go new file mode 100644 index 0000000000..e920609476 --- /dev/null +++ b/mock/store_test.go @@ -0,0 +1,33 @@ +package mock + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + dbm "github.com/tendermint/tmlibs/db" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestStore(t *testing.T) { + db := dbm.NewMemDB() + cms := NewCommitMultiStore(db) + + key := sdk.NewKVStoreKey("test") + cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) + err := cms.LoadLatestVersion() + assert.Nil(t, err) + + store := cms.GetKVStore(key) + assert.NotNil(t, store) + + k := []byte("hello") + v := []byte("world") + assert.False(t, store.Has(k)) + store.Set(k, v) + assert.True(t, store.Has(k)) + assert.Equal(t, v, store.Get(k)) + store.Delete(k) + assert.False(t, store.Has(k)) +} From 2c10c868f423361e25e0ab9b639ea148cbbf5bc6 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 12 Apr 2018 15:46:55 +0200 Subject: [PATCH 04/13] prefixed storekey --- types/stdlib/stdlib.go | 105 +++++++++++++++++++++--------------- types/stdlib/stdlib_test.go | 7 +-- 2 files changed, 66 insertions(+), 46 deletions(-) diff --git a/types/stdlib/stdlib.go b/types/stdlib/stdlib.go index 71196fe0c3..97948b876a 100644 --- a/types/stdlib/stdlib.go +++ b/types/stdlib/stdlib.go @@ -17,37 +17,40 @@ type ListMapper interface { Get(sdk.Context, int64, interface{}) // Setting element out of range is harmful; use Push() when adding new elements Set(sdk.Context, int64, interface{}) + Delete(sdk.Context, int64) Push(sdk.Context, interface{}) - Iterate(sdk.Context, interface{}, func(sdk.Context, int64)) + Iterate(sdk.Context, interface{}, func(sdk.Context, int64) bool) } type listMapper struct { - key sdk.StoreKey - cdc *wire.Codec - lk []byte + key sdk.StoreKey + cdc *wire.Codec + prefix string + lk []byte } -func NewListMapper(cdc *wire.Codec, key sdk.StoreKey) ListMapper { +func NewListMapper(cdc *wire.Codec, key sdk.StoreKey, prefix string) ListMapper { lk, err := cdc.MarshalBinary(int64(-1)) if err != nil { panic(err) } return listMapper{ - key: key, - cdc: cdc, - lk: lk, + key: key, + cdc: cdc, + prefix: prefix, + lk: lk, } } func (lm listMapper) Len(ctx sdk.Context) int64 { store := ctx.KVStore(lm.key) - bz := store.Get(lm.lk) + bz := store.Get(lm.LengthKey()) if bz == nil { zero, err := lm.cdc.MarshalBinary(0) if err != nil { panic(err) } - store.Set(lm.lk, zero) + store.Set(lm.LengthKey(), zero) return 0 } var res int64 @@ -62,7 +65,7 @@ func (lm listMapper) Get(ctx sdk.Context, index int64, ptr interface{}) { panic(fmt.Errorf("Invalid index in ListMapper.Get(ctx, %d, ptr)", index)) } store := ctx.KVStore(lm.key) - bz := store.Get(marshalInt64(lm.cdc, index)) + bz := store.Get(lm.ElemKey(index)) if err := lm.cdc.UnmarshalBinary(bz, ptr); err != nil { panic(err) } @@ -77,7 +80,15 @@ func (lm listMapper) Set(ctx sdk.Context, index int64, value interface{}) { if err != nil { panic(err) } - store.Set(marshalInt64(lm.cdc, index), bz) + store.Set(lm.ElemKey(index), bz) +} + +func (lm listMapper) Delete(ctx sdk.Context, index int64) { + if index < 0 { + panic(fmt.Errorf("Invalid index in ListMapper.Delete(ctx, %d)", index)) + } + store := ctx.KVStore(lm.key) + store.Delete(lm.ElemKey(index)) } func (lm listMapper) Push(ctx sdk.Context, value interface{}) { @@ -85,17 +96,27 @@ func (lm listMapper) Push(ctx sdk.Context, value interface{}) { lm.Set(ctx, length, value) store := ctx.KVStore(lm.key) - store.Set(lm.lk, marshalInt64(lm.cdc, length+1)) + store.Set(lm.LengthKey(), marshalInt64(lm.cdc, length+1)) } -func (lm listMapper) Iterate(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, int64)) { +func (lm listMapper) Iterate(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, int64) bool) { length := lm.Len(ctx) for i := int64(0); i < length; i++ { lm.Get(ctx, i, ptr) - fn(ctx, i) + if fn(ctx, i) { + break + } } } +func (lm listMapper) LengthKey() []byte { + return []byte(fmt.Sprintf("%s/%d", lm.prefix, lm.lk)) +} + +func (lm listMapper) ElemKey(i int64) []byte { + return []byte(fmt.Sprintf("%s/%d", lm.prefix, i)) +} + // QueueMapper is a Mapper interface that provides queue-like functions // It panics when the element type cannot be (un/)marshalled by the codec @@ -111,20 +132,24 @@ type QueueMapper interface { } type queueMapper struct { - key sdk.StoreKey - cdc *wire.Codec - ik []byte + key sdk.StoreKey + cdc *wire.Codec + prefix string + lm ListMapper + lk []byte + ik []byte } -func NewQueueMapper(cdc *wire.Codec, key sdk.StoreKey) QueueMapper { - ik, err := cdc.MarshalBinary(int64(-1)) - if err != nil { - panic(err) - } +func NewQueueMapper(cdc *wire.Codec, key sdk.StoreKey, prefix string) QueueMapper { + lk := []byte("list") + ik := []byte("info") return queueMapper{ - key: key, - cdc: cdc, - ik: ik, + key: key, + cdc: cdc, + prefix: prefix, + lm: NewListMapper(cdc, key, prefix+string(lk)), + lk: lk, + ik: ik, } } @@ -146,9 +171,9 @@ func (info queueInfo) isEmpty() bool { } func (qm queueMapper) getQueueInfo(store sdk.KVStore) queueInfo { - bz := store.Get(qm.ik) + bz := store.Get(qm.InfoKey()) if bz == nil { - store.Set(qm.ik, marshalQueueInfo(qm.cdc, queueInfo{0, 0})) + store.Set(qm.InfoKey(), marshalQueueInfo(qm.cdc, queueInfo{0, 0})) return queueInfo{0, 0} } var info queueInfo @@ -166,18 +191,14 @@ func (qm queueMapper) setQueueInfo(store sdk.KVStore, info queueInfo) { if err != nil { panic(err) } - store.Set(qm.ik, bz) + store.Set(qm.InfoKey(), bz) } func (qm queueMapper) Push(ctx sdk.Context, value interface{}) { store := ctx.KVStore(qm.key) info := qm.getQueueInfo(store) - bz, err := qm.cdc.MarshalBinary(value) - if err != nil { - panic(err) - } - store.Set(marshalInt64(qm.cdc, info.End), bz) + qm.lm.Set(ctx, info.End, value) info.End++ qm.setQueueInfo(store, info) @@ -186,16 +207,13 @@ func (qm queueMapper) Push(ctx sdk.Context, value interface{}) { func (qm queueMapper) Peek(ctx sdk.Context, ptr interface{}) { store := ctx.KVStore(qm.key) info := qm.getQueueInfo(store) - bz := store.Get(marshalInt64(qm.cdc, info.Begin)) - if err := qm.cdc.UnmarshalBinary(bz, ptr); err != nil { - panic(err) - } + qm.lm.Get(ctx, info.Begin, ptr) } func (qm queueMapper) Pop(ctx sdk.Context) { store := ctx.KVStore(qm.key) info := qm.getQueueInfo(store) - store.Delete(marshalInt64(qm.cdc, info.Begin)) + qm.lm.Delete(ctx, info.Begin) info.Begin++ qm.setQueueInfo(store, info) } @@ -212,11 +230,8 @@ func (qm queueMapper) Iterate(ctx sdk.Context, ptr interface{}, fn func(sdk.Cont var i int64 for i = info.Begin; i < info.End; i++ { + qm.lm.Get(ctx, i, ptr) key := marshalInt64(qm.cdc, i) - bz := store.Get(key) - if err := qm.cdc.UnmarshalBinary(bz, ptr); err != nil { - panic(err) - } store.Delete(key) if fn(ctx) { break @@ -227,6 +242,10 @@ func (qm queueMapper) Iterate(ctx sdk.Context, ptr interface{}, fn func(sdk.Cont qm.setQueueInfo(store, info) } +func (qm queueMapper) InfoKey() []byte { + return []byte(fmt.Sprintf("%s/%s", qm.prefix, qm.ik)) +} + func marshalQueueInfo(cdc *wire.Codec, info queueInfo) []byte { bz, err := cdc.MarshalBinary(info) if err != nil { diff --git a/types/stdlib/stdlib_test.go b/types/stdlib/stdlib_test.go index a225f148e1..7cce1bdf6d 100644 --- a/types/stdlib/stdlib_test.go +++ b/types/stdlib/stdlib_test.go @@ -32,7 +32,7 @@ func defaultComponents(key sdk.StoreKey) (sdk.Context, *wire.Codec) { func TestListMapper(t *testing.T) { key := sdk.NewKVStoreKey("list") ctx, cdc := defaultComponents(key) - lm := NewListMapper(cdc, key) + lm := NewListMapper(cdc, key, "data") val := S{1, true} var res S @@ -47,8 +47,9 @@ func TestListMapper(t *testing.T) { lm.Get(ctx, int64(0), &res) assert.Equal(t, val, res) - lm.Iterate(ctx, &res, func(ctx sdk.Context, index int64) { + lm.Iterate(ctx, &res, func(ctx sdk.Context, index int64) (brk bool) { lm.Set(ctx, index, S{res.I + 1, !res.B}) + return }) lm.Get(ctx, int64(0), &res) assert.Equal(t, S{3, true}, res) @@ -57,7 +58,7 @@ func TestListMapper(t *testing.T) { func TestQueueMapper(t *testing.T) { key := sdk.NewKVStoreKey("queue") ctx, cdc := defaultComponents(key) - qm := NewQueueMapper(cdc, key) + qm := NewQueueMapper(cdc, key, "data") val := S{1, true} var res S From 775668d12d4ce9b17a688a6f8c6cd625efda1a8b Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 12 Apr 2018 15:59:24 +0200 Subject: [PATCH 05/13] now pass ci --- mock/store.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mock/store.go b/mock/store.go index f7844e668f..e518aa26a3 100644 --- a/mock/store.go +++ b/mock/store.go @@ -99,6 +99,14 @@ func (kv kvStore) ReverseIterator(start, end []byte) sdk.Iterator { panic("not implemented") } +func (kv kvStore) SubspaceIterator(prefix []byte) sdk.Iterator { + panic("not implemented") +} + +func (kv kvStore) ReverseSubspaceIterator(prefix []byte) sdk.Iterator { + panic("not implemented") +} + func NewCommitMultiStore(db dbm.DB) sdk.CommitMultiStore { return multiStore{kv: make(map[sdk.StoreKey]kvStore)} } From fbfdbd4266e069e7e67911abea1dce830e072634 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 12 Apr 2018 16:07:58 +0200 Subject: [PATCH 06/13] stdlib -> lib --- types/{stdlib => lib}/stdlib.go | 0 types/{stdlib => lib}/stdlib_test.go | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename types/{stdlib => lib}/stdlib.go (100%) rename types/{stdlib => lib}/stdlib_test.go (100%) diff --git a/types/stdlib/stdlib.go b/types/lib/stdlib.go similarity index 100% rename from types/stdlib/stdlib.go rename to types/lib/stdlib.go diff --git a/types/stdlib/stdlib_test.go b/types/lib/stdlib_test.go similarity index 100% rename from types/stdlib/stdlib_test.go rename to types/lib/stdlib_test.go From 373e408fadeb5fcf23d28bba282f4dd9e946278c Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 12 Apr 2018 18:19:28 +0200 Subject: [PATCH 07/13] expose QueueInfo --- types/lib/stdlib.go | 30 ++++++++++++++++++------------ types/lib/stdlib_test.go | 4 +++- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/types/lib/stdlib.go b/types/lib/stdlib.go index 97948b876a..caf426585f 100644 --- a/types/lib/stdlib.go +++ b/types/lib/stdlib.go @@ -1,4 +1,4 @@ -package stdlib +package lib import ( "fmt" @@ -129,6 +129,7 @@ type QueueMapper interface { IsEmpty(sdk.Context) bool // Iterate() removes elements it processed; return true in the continuation to break Iterate(sdk.Context, interface{}, func(sdk.Context) bool) + Info(sdk.Context) QueueInfo } type queueMapper struct { @@ -153,30 +154,30 @@ func NewQueueMapper(cdc *wire.Codec, key sdk.StoreKey, prefix string) QueueMappe } } -type queueInfo struct { +type QueueInfo struct { // begin <= elems < end Begin int64 End int64 } -func (info queueInfo) validateBasic() error { +func (info QueueInfo) validateBasic() error { if info.End < info.Begin || info.Begin < 0 || info.End < 0 { return fmt.Errorf("Invalid queue information: {Begin: %d, End: %d}", info.Begin, info.End) } return nil } -func (info queueInfo) isEmpty() bool { +func (info QueueInfo) isEmpty() bool { return info.Begin == info.End } -func (qm queueMapper) getQueueInfo(store sdk.KVStore) queueInfo { +func (qm queueMapper) getQueueInfo(store sdk.KVStore) QueueInfo { bz := store.Get(qm.InfoKey()) if bz == nil { - store.Set(qm.InfoKey(), marshalQueueInfo(qm.cdc, queueInfo{0, 0})) - return queueInfo{0, 0} + store.Set(qm.InfoKey(), marshalQueueInfo(qm.cdc, QueueInfo{0, 0})) + return QueueInfo{0, 0} } - var info queueInfo + var info QueueInfo if err := qm.cdc.UnmarshalBinary(bz, &info); err != nil { panic(err) } @@ -186,7 +187,7 @@ func (qm queueMapper) getQueueInfo(store sdk.KVStore) queueInfo { return info } -func (qm queueMapper) setQueueInfo(store sdk.KVStore, info queueInfo) { +func (qm queueMapper) setQueueInfo(store sdk.KVStore, info QueueInfo) { bz, err := qm.cdc.MarshalBinary(info) if err != nil { panic(err) @@ -231,8 +232,7 @@ func (qm queueMapper) Iterate(ctx sdk.Context, ptr interface{}, fn func(sdk.Cont var i int64 for i = info.Begin; i < info.End; i++ { qm.lm.Get(ctx, i, ptr) - key := marshalInt64(qm.cdc, i) - store.Delete(key) + qm.lm.Delete(ctx, i) if fn(ctx) { break } @@ -242,11 +242,17 @@ func (qm queueMapper) Iterate(ctx sdk.Context, ptr interface{}, fn func(sdk.Cont qm.setQueueInfo(store, info) } +func (qm queueMapper) Info(ctx sdk.Context) QueueInfo { + store := ctx.KVStore(qm.key) + + return qm.getQueueInfo(store) +} + func (qm queueMapper) InfoKey() []byte { return []byte(fmt.Sprintf("%s/%s", qm.prefix, qm.ik)) } -func marshalQueueInfo(cdc *wire.Codec, info queueInfo) []byte { +func marshalQueueInfo(cdc *wire.Codec, info QueueInfo) []byte { bz, err := cdc.MarshalBinary(info) if err != nil { panic(err) diff --git a/types/lib/stdlib_test.go b/types/lib/stdlib_test.go index 7cce1bdf6d..197e6cbe43 100644 --- a/types/lib/stdlib_test.go +++ b/types/lib/stdlib_test.go @@ -1,4 +1,4 @@ -package stdlib +package lib import ( "testing" @@ -84,6 +84,8 @@ func TestQueueMapper(t *testing.T) { }) assert.False(t, qm.IsEmpty(ctx)) + assert.Equal(t, QueueInfo{3, 4}, qm.Info(ctx)) + qm.Pop(ctx) assert.True(t, qm.IsEmpty(ctx)) } From 1b72a6c40d6e8785af2008dd8d799527f87784d8 Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 13 Apr 2018 14:10:55 +0200 Subject: [PATCH 08/13] apply requests --- types/lib/stdlib.go | 224 ++++++++++++++++++--------------------- types/lib/stdlib_test.go | 40 +++++-- 2 files changed, 133 insertions(+), 131 deletions(-) diff --git a/types/lib/stdlib.go b/types/lib/stdlib.go index caf426585f..f075ce3ffd 100644 --- a/types/lib/stdlib.go +++ b/types/lib/stdlib.go @@ -2,6 +2,8 @@ package lib import ( "fmt" + "strconv" + "strings" sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" @@ -11,38 +13,45 @@ import ( // It panics when the element type cannot be (un/)marshalled by the codec type ListMapper interface { - // ListMapper dosen't checks index out of range + // ListMapper dosen't check if an index is in bounds // The user should check Len() before doing any actions - Len(sdk.Context) int64 - Get(sdk.Context, int64, interface{}) - // Setting element out of range is harmful; use Push() when adding new elements - Set(sdk.Context, int64, interface{}) - Delete(sdk.Context, int64) + Len(sdk.Context) uint64 + + Get(sdk.Context, uint64, interface{}) error + + // Setting element out of range is harmful + // Use Push() instead of Set() to append a new element + Set(sdk.Context, uint64, interface{}) + + Delete(sdk.Context, uint64) + Push(sdk.Context, interface{}) - Iterate(sdk.Context, interface{}, func(sdk.Context, int64) bool) + + // Iterate*() is used to iterate over all existing elements in the list + // Return true in the continuation to break + + // CONTRACT: No writes may happen within a domain while an iterator exists over it. + IterateRead(sdk.Context, interface{}, func(sdk.Context, uint64) bool) + + // IterateWrite() is safe to write over the domain + IterateWrite(sdk.Context, interface{}, func(sdk.Context, uint64) bool) } type listMapper struct { key sdk.StoreKey cdc *wire.Codec prefix string - lk []byte } func NewListMapper(cdc *wire.Codec, key sdk.StoreKey, prefix string) ListMapper { - lk, err := cdc.MarshalBinary(int64(-1)) - if err != nil { - panic(err) - } return listMapper{ key: key, cdc: cdc, prefix: prefix, - lk: lk, } } -func (lm listMapper) Len(ctx sdk.Context) int64 { +func (lm listMapper) Len(ctx sdk.Context) uint64 { store := ctx.KVStore(lm.key) bz := store.Get(lm.LengthKey()) if bz == nil { @@ -53,28 +62,20 @@ func (lm listMapper) Len(ctx sdk.Context) int64 { store.Set(lm.LengthKey(), zero) return 0 } - var res int64 + var res uint64 if err := lm.cdc.UnmarshalBinary(bz, &res); err != nil { panic(err) } return res } -func (lm listMapper) Get(ctx sdk.Context, index int64, ptr interface{}) { - if index < 0 { - panic(fmt.Errorf("Invalid index in ListMapper.Get(ctx, %d, ptr)", index)) - } +func (lm listMapper) Get(ctx sdk.Context, index uint64, ptr interface{}) error { store := ctx.KVStore(lm.key) bz := store.Get(lm.ElemKey(index)) - if err := lm.cdc.UnmarshalBinary(bz, ptr); err != nil { - panic(err) - } + return lm.cdc.UnmarshalBinary(bz, ptr) } -func (lm listMapper) Set(ctx sdk.Context, index int64, value interface{}) { - if index < 0 { - panic(fmt.Errorf("Invalid index in ListMapper.Set(ctx, %d, value)", index)) - } +func (lm listMapper) Set(ctx sdk.Context, index uint64, value interface{}) { store := ctx.KVStore(lm.key) bz, err := lm.cdc.MarshalBinary(value) if err != nil { @@ -83,10 +84,7 @@ func (lm listMapper) Set(ctx sdk.Context, index int64, value interface{}) { store.Set(lm.ElemKey(index), bz) } -func (lm listMapper) Delete(ctx sdk.Context, index int64) { - if index < 0 { - panic(fmt.Errorf("Invalid index in ListMapper.Delete(ctx, %d)", index)) - } +func (lm listMapper) Delete(ctx sdk.Context, index uint64) { store := ctx.KVStore(lm.key) store.Delete(lm.ElemKey(index)) } @@ -96,13 +94,38 @@ func (lm listMapper) Push(ctx sdk.Context, value interface{}) { lm.Set(ctx, length, value) store := ctx.KVStore(lm.key) - store.Set(lm.LengthKey(), marshalInt64(lm.cdc, length+1)) + store.Set(lm.LengthKey(), marshalUint64(lm.cdc, length+1)) } -func (lm listMapper) Iterate(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, int64) bool) { +func (lm listMapper) IterateRead(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { + store := ctx.KVStore(lm.key) + start, end := subspace([]byte(fmt.Sprintf("%s/elem/", lm.prefix))) + iter := store.Iterator(start, end) + for ; iter.Valid(); iter.Next() { + v := iter.Value() + if err := lm.cdc.UnmarshalBinary(v, ptr); err != nil { + panic(err) + } + s := strings.Split(string(iter.Key()), "/") + index, err := strconv.ParseUint(s[len(s)-1], 10, 64) + if err != nil { + panic(err) + } + if fn(ctx, index) { + break + } + } + + iter.Close() +} + +func (lm listMapper) IterateWrite(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { length := lm.Len(ctx) - for i := int64(0); i < length; i++ { - lm.Get(ctx, i, ptr) + + for i := uint64(0); i < length; i++ { + if err := lm.Get(ctx, i, ptr); err != nil { + continue + } if fn(ctx, i) { break } @@ -110,11 +133,11 @@ func (lm listMapper) Iterate(ctx sdk.Context, ptr interface{}, fn func(sdk.Conte } func (lm listMapper) LengthKey() []byte { - return []byte(fmt.Sprintf("%s/%d", lm.prefix, lm.lk)) + return []byte(fmt.Sprintf("%s/length", lm.prefix)) } -func (lm listMapper) ElemKey(i int64) []byte { - return []byte(fmt.Sprintf("%s/%d", lm.prefix, i)) +func (lm listMapper) ElemKey(i uint64) []byte { + return []byte(fmt.Sprintf("%s/elem/%020d", lm.prefix, i)) } // QueueMapper is a Mapper interface that provides queue-like functions @@ -124,12 +147,14 @@ type QueueMapper interface { Push(sdk.Context, interface{}) // Popping/Peeking on an empty queue will cause panic // The user should check IsEmpty() before doing any actions - Peek(sdk.Context, interface{}) + Peek(sdk.Context, interface{}) error Pop(sdk.Context) IsEmpty(sdk.Context) bool - // Iterate() removes elements it processed; return true in the continuation to break - Iterate(sdk.Context, interface{}, func(sdk.Context) bool) - Info(sdk.Context) QueueInfo + // Iterate() removes elements it processed + // Return true in the continuation to break + // The interface{} is unmarshalled before the continuation is called + // Starts from the top(head) of the queue + Flush(sdk.Context, interface{}, func(sdk.Context) bool) } type queueMapper struct { @@ -137,100 +162,67 @@ type queueMapper struct { cdc *wire.Codec prefix string lm ListMapper - lk []byte - ik []byte } func NewQueueMapper(cdc *wire.Codec, key sdk.StoreKey, prefix string) QueueMapper { - lk := []byte("list") - ik := []byte("info") return queueMapper{ key: key, cdc: cdc, prefix: prefix, - lm: NewListMapper(cdc, key, prefix+string(lk)), - lk: lk, - ik: ik, + lm: NewListMapper(cdc, key, prefix+"list"), } } -type QueueInfo struct { - // begin <= elems < end - Begin int64 - End int64 -} - -func (info QueueInfo) validateBasic() error { - if info.End < info.Begin || info.Begin < 0 || info.End < 0 { - return fmt.Errorf("Invalid queue information: {Begin: %d, End: %d}", info.Begin, info.End) - } - return nil -} - -func (info QueueInfo) isEmpty() bool { - return info.Begin == info.End -} - -func (qm queueMapper) getQueueInfo(store sdk.KVStore) QueueInfo { - bz := store.Get(qm.InfoKey()) +func (qm queueMapper) getTop(store sdk.KVStore) (res uint64) { + bz := store.Get(qm.TopKey()) if bz == nil { - store.Set(qm.InfoKey(), marshalQueueInfo(qm.cdc, QueueInfo{0, 0})) - return QueueInfo{0, 0} + store.Set(qm.TopKey(), marshalUint64(qm.cdc, 0)) + return 0 } - var info QueueInfo - if err := qm.cdc.UnmarshalBinary(bz, &info); err != nil { + + if err := qm.cdc.UnmarshalBinary(bz, &res); err != nil { panic(err) } - if err := info.validateBasic(); err != nil { - panic(err) - } - return info + + return } -func (qm queueMapper) setQueueInfo(store sdk.KVStore, info QueueInfo) { - bz, err := qm.cdc.MarshalBinary(info) - if err != nil { - panic(err) - } - store.Set(qm.InfoKey(), bz) +func (qm queueMapper) setTop(store sdk.KVStore, top uint64) { + bz := marshalUint64(qm.cdc, top) + store.Set(qm.TopKey(), bz) } func (qm queueMapper) Push(ctx sdk.Context, value interface{}) { - store := ctx.KVStore(qm.key) - info := qm.getQueueInfo(store) - - qm.lm.Set(ctx, info.End, value) - - info.End++ - qm.setQueueInfo(store, info) + qm.lm.Push(ctx, value) } -func (qm queueMapper) Peek(ctx sdk.Context, ptr interface{}) { +func (qm queueMapper) Peek(ctx sdk.Context, ptr interface{}) error { store := ctx.KVStore(qm.key) - info := qm.getQueueInfo(store) - qm.lm.Get(ctx, info.Begin, ptr) + top := qm.getTop(store) + return qm.lm.Get(ctx, top, ptr) } func (qm queueMapper) Pop(ctx sdk.Context) { store := ctx.KVStore(qm.key) - info := qm.getQueueInfo(store) - qm.lm.Delete(ctx, info.Begin) - info.Begin++ - qm.setQueueInfo(store, info) + top := qm.getTop(store) + qm.lm.Delete(ctx, top) + qm.setTop(store, top+1) } func (qm queueMapper) IsEmpty(ctx sdk.Context) bool { store := ctx.KVStore(qm.key) - info := qm.getQueueInfo(store) - return info.isEmpty() + top := qm.getTop(store) + length := qm.lm.Len(ctx) + return top >= length } -func (qm queueMapper) Iterate(ctx sdk.Context, ptr interface{}, fn func(sdk.Context) bool) { +func (qm queueMapper) Flush(ctx sdk.Context, ptr interface{}, fn func(sdk.Context) bool) { store := ctx.KVStore(qm.key) - info := qm.getQueueInfo(store) + top := qm.getTop(store) + length := qm.lm.Len(ctx) - var i int64 - for i = info.Begin; i < info.End; i++ { + var i uint64 + for i = top; i < length; i++ { qm.lm.Get(ctx, i, ptr) qm.lm.Delete(ctx, i) if fn(ctx) { @@ -238,32 +230,24 @@ func (qm queueMapper) Iterate(ctx sdk.Context, ptr interface{}, fn func(sdk.Cont } } - info.Begin = i - qm.setQueueInfo(store, info) + qm.setTop(store, i) } -func (qm queueMapper) Info(ctx sdk.Context) QueueInfo { - store := ctx.KVStore(qm.key) - - return qm.getQueueInfo(store) +func (qm queueMapper) TopKey() []byte { + return []byte(fmt.Sprintf("%s/top", qm.prefix)) } -func (qm queueMapper) InfoKey() []byte { - return []byte(fmt.Sprintf("%s/%s", qm.prefix, qm.ik)) -} - -func marshalQueueInfo(cdc *wire.Codec, info QueueInfo) []byte { - bz, err := cdc.MarshalBinary(info) - if err != nil { - panic(err) - } - return bz -} - -func marshalInt64(cdc *wire.Codec, i int64) []byte { +func marshalUint64(cdc *wire.Codec, i uint64) []byte { bz, err := cdc.MarshalBinary(i) if err != nil { panic(err) } return bz } + +func subspace(prefix []byte) (start, end []byte) { + end = make([]byte, len(prefix)) + copy(end, prefix) + end[len(end)-1]++ + return prefix, end +} diff --git a/types/lib/stdlib_test.go b/types/lib/stdlib_test.go index 197e6cbe43..1058fed6ed 100644 --- a/types/lib/stdlib_test.go +++ b/types/lib/stdlib_test.go @@ -9,13 +9,13 @@ import ( abci "github.com/tendermint/abci/types" - store "github.com/cosmos/cosmos-sdk/mock" + "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" ) type S struct { - I int64 + I uint64 B bool } @@ -38,20 +38,39 @@ func TestListMapper(t *testing.T) { var res S lm.Push(ctx, val) - assert.Equal(t, int64(1), lm.Len(ctx)) - lm.Get(ctx, int64(0), &res) + assert.Equal(t, uint64(1), lm.Len(ctx)) + lm.Get(ctx, uint64(0), &res) assert.Equal(t, val, res) val = S{2, false} - lm.Set(ctx, int64(0), val) - lm.Get(ctx, int64(0), &res) + lm.Set(ctx, uint64(0), val) + lm.Get(ctx, uint64(0), &res) assert.Equal(t, val, res) - lm.Iterate(ctx, &res, func(ctx sdk.Context, index int64) (brk bool) { + val = S{100, false} + lm.Push(ctx, val) + assert.Equal(t, uint64(2), lm.Len(ctx)) + lm.Get(ctx, uint64(1), &res) + assert.Equal(t, val, res) + + lm.Delete(ctx, uint64(1)) + assert.Equal(t, uint64(2), lm.Len(ctx)) + + lm.IterateRead(ctx, &res, func(ctx sdk.Context, index uint64) (brk bool) { + var temp S + lm.Get(ctx, index, &temp) + assert.Equal(t, temp, res) + + assert.True(t, index != 1) + return + }) + + lm.IterateWrite(ctx, &res, func(ctx sdk.Context, index uint64) (brk bool) { lm.Set(ctx, index, S{res.I + 1, !res.B}) return }) - lm.Get(ctx, int64(0), &res) + + lm.Get(ctx, uint64(0), &res) assert.Equal(t, S{3, true}, res) } @@ -71,12 +90,12 @@ func TestQueueMapper(t *testing.T) { empty := qm.IsEmpty(ctx) assert.True(t, empty) - assert.Panics(t, func() { qm.Peek(ctx, &res) }) + assert.NotNil(t, qm.Peek(ctx, &res)) qm.Push(ctx, S{1, true}) qm.Push(ctx, S{2, true}) qm.Push(ctx, S{3, true}) - qm.Iterate(ctx, &res, func(ctx sdk.Context) (brk bool) { + qm.Flush(ctx, &res, func(ctx sdk.Context) (brk bool) { if res.I == 3 { brk = true } @@ -84,7 +103,6 @@ func TestQueueMapper(t *testing.T) { }) assert.False(t, qm.IsEmpty(ctx)) - assert.Equal(t, QueueInfo{3, 4}, qm.Info(ctx)) qm.Pop(ctx) assert.True(t, qm.IsEmpty(ctx)) From e00d03aabde2cd84e169e3dada7f271c6129595e Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 18 Apr 2018 16:56:39 +0200 Subject: [PATCH 09/13] in progress --- types/lib/stdlib.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/types/lib/stdlib.go b/types/lib/stdlib.go index f075ce3ffd..7f812033b2 100644 --- a/types/lib/stdlib.go +++ b/types/lib/stdlib.go @@ -27,6 +27,10 @@ type ListMapper interface { Push(sdk.Context, interface{}) + // Getter/Setter for meta information - can be customized + GetMeta(sdk.Context, interface{}) error + SetMeta(sdk.Context, interface{}) + // Iterate*() is used to iterate over all existing elements in the list // Return true in the continuation to break @@ -97,6 +101,21 @@ func (lm listMapper) Push(ctx sdk.Context, value interface{}) { store.Set(lm.LengthKey(), marshalUint64(lm.cdc, length+1)) } +func (lm listMapper) GetMeta(ctx sdk.Context, ptr interface{}) error { + store := ctx.KVStore(lm.key) + bz := store.Get(lm.MetaKey()) + return lm.cdc.UnmarshalBinary(bz, ptr) +} + +func (lm listMapper) SetMeta(ctx sdk.Context, value interface{}) { + store := ctx.KVStore(lm.key) + bz, err := lm.cdc.MarshalBinary(value) + if err != nil { + panic(err) + } + store.Set(lm.MetaKey(), bz) +} + func (lm listMapper) IterateRead(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { store := ctx.KVStore(lm.key) start, end := subspace([]byte(fmt.Sprintf("%s/elem/", lm.prefix))) @@ -140,6 +159,8 @@ func (lm listMapper) ElemKey(i uint64) []byte { return []byte(fmt.Sprintf("%s/elem/%020d", lm.prefix, i)) } +func (lm listMapper) + // QueueMapper is a Mapper interface that provides queue-like functions // It panics when the element type cannot be (un/)marshalled by the codec From 91767fc6d30549b1876a9e431b7ade7f140be149 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 18 Apr 2018 17:55:40 +0200 Subject: [PATCH 10/13] add GenericMapper --- types/lib/{stdlib.go => mapper.go} | 88 ++++++++++---------- types/lib/{stdlib_test.go => mapper_test.go} | 0 2 files changed, 45 insertions(+), 43 deletions(-) rename types/lib/{stdlib.go => mapper.go} (73%) rename types/lib/{stdlib_test.go => mapper_test.go} (100%) diff --git a/types/lib/stdlib.go b/types/lib/mapper.go similarity index 73% rename from types/lib/stdlib.go rename to types/lib/mapper.go index 7f812033b2..e168eec2b0 100644 --- a/types/lib/stdlib.go +++ b/types/lib/mapper.go @@ -9,6 +9,12 @@ import ( wire "github.com/cosmos/cosmos-sdk/wire" ) +type GenericMapper struct { + key sdk.StoreKey + cdc *wire.Codec + prefix string +} + // ListMapper is a Mapper interface that provides list-like functions // It panics when the element type cannot be (un/)marshalled by the codec @@ -39,23 +45,26 @@ type ListMapper interface { // IterateWrite() is safe to write over the domain IterateWrite(sdk.Context, interface{}, func(sdk.Context, uint64) bool) -} -type listMapper struct { - key sdk.StoreKey - cdc *wire.Codec - prefix string + // Key for the length of the list + LengthKey() []byte + + // Key for getting elements + ElemKey(uint64) []byte + + // Key for additional meta information of the list + MetaKey() []byte } func NewListMapper(cdc *wire.Codec, key sdk.StoreKey, prefix string) ListMapper { - return listMapper{ + return GenericMapper{ key: key, cdc: cdc, prefix: prefix, } } -func (lm listMapper) Len(ctx sdk.Context) uint64 { +func (lm GenericMapper) Len(ctx sdk.Context) uint64 { store := ctx.KVStore(lm.key) bz := store.Get(lm.LengthKey()) if bz == nil { @@ -73,13 +82,13 @@ func (lm listMapper) Len(ctx sdk.Context) uint64 { return res } -func (lm listMapper) Get(ctx sdk.Context, index uint64, ptr interface{}) error { +func (lm GenericMapper) Get(ctx sdk.Context, index uint64, ptr interface{}) error { store := ctx.KVStore(lm.key) bz := store.Get(lm.ElemKey(index)) return lm.cdc.UnmarshalBinary(bz, ptr) } -func (lm listMapper) Set(ctx sdk.Context, index uint64, value interface{}) { +func (lm GenericMapper) Set(ctx sdk.Context, index uint64, value interface{}) { store := ctx.KVStore(lm.key) bz, err := lm.cdc.MarshalBinary(value) if err != nil { @@ -88,12 +97,12 @@ func (lm listMapper) Set(ctx sdk.Context, index uint64, value interface{}) { store.Set(lm.ElemKey(index), bz) } -func (lm listMapper) Delete(ctx sdk.Context, index uint64) { +func (lm GenericMapper) Delete(ctx sdk.Context, index uint64) { store := ctx.KVStore(lm.key) store.Delete(lm.ElemKey(index)) } -func (lm listMapper) Push(ctx sdk.Context, value interface{}) { +func (lm GenericMapper) Push(ctx sdk.Context, value interface{}) { length := lm.Len(ctx) lm.Set(ctx, length, value) @@ -101,13 +110,13 @@ func (lm listMapper) Push(ctx sdk.Context, value interface{}) { store.Set(lm.LengthKey(), marshalUint64(lm.cdc, length+1)) } -func (lm listMapper) GetMeta(ctx sdk.Context, ptr interface{}) error { +func (lm GenericMapper) GetMeta(ctx sdk.Context, ptr interface{}) error { store := ctx.KVStore(lm.key) bz := store.Get(lm.MetaKey()) return lm.cdc.UnmarshalBinary(bz, ptr) } -func (lm listMapper) SetMeta(ctx sdk.Context, value interface{}) { +func (lm GenericMapper) SetMeta(ctx sdk.Context, value interface{}) { store := ctx.KVStore(lm.key) bz, err := lm.cdc.MarshalBinary(value) if err != nil { @@ -116,7 +125,7 @@ func (lm listMapper) SetMeta(ctx sdk.Context, value interface{}) { store.Set(lm.MetaKey(), bz) } -func (lm listMapper) IterateRead(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { +func (lm GenericMapper) IterateRead(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { store := ctx.KVStore(lm.key) start, end := subspace([]byte(fmt.Sprintf("%s/elem/", lm.prefix))) iter := store.Iterator(start, end) @@ -138,7 +147,7 @@ func (lm listMapper) IterateRead(ctx sdk.Context, ptr interface{}, fn func(sdk.C iter.Close() } -func (lm listMapper) IterateWrite(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { +func (lm GenericMapper) IterateWrite(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { length := lm.Len(ctx) for i := uint64(0); i < length; i++ { @@ -151,15 +160,17 @@ func (lm listMapper) IterateWrite(ctx sdk.Context, ptr interface{}, fn func(sdk. } } -func (lm listMapper) LengthKey() []byte { +func (lm GenericMapper) LengthKey() []byte { return []byte(fmt.Sprintf("%s/length", lm.prefix)) } -func (lm listMapper) ElemKey(i uint64) []byte { +func (lm GenericMapper) ElemKey(i uint64) []byte { return []byte(fmt.Sprintf("%s/elem/%020d", lm.prefix, i)) } -func (lm listMapper) +func (lm GenericMapper) MetaKey() []byte { + return []byte(fmt.Sprintf("%s/meta", lm.prefix)) +} // QueueMapper is a Mapper interface that provides queue-like functions // It panics when the element type cannot be (un/)marshalled by the codec @@ -176,25 +187,20 @@ type QueueMapper interface { // The interface{} is unmarshalled before the continuation is called // Starts from the top(head) of the queue Flush(sdk.Context, interface{}, func(sdk.Context) bool) -} -type queueMapper struct { - key sdk.StoreKey - cdc *wire.Codec - prefix string - lm ListMapper + // Key for the index of top element + TopKey() []byte } func NewQueueMapper(cdc *wire.Codec, key sdk.StoreKey, prefix string) QueueMapper { - return queueMapper{ + return GenericMapper{ key: key, cdc: cdc, prefix: prefix, - lm: NewListMapper(cdc, key, prefix+"list"), } } -func (qm queueMapper) getTop(store sdk.KVStore) (res uint64) { +func (qm GenericMapper) getTop(store sdk.KVStore) (res uint64) { bz := store.Get(qm.TopKey()) if bz == nil { store.Set(qm.TopKey(), marshalUint64(qm.cdc, 0)) @@ -208,44 +214,40 @@ func (qm queueMapper) getTop(store sdk.KVStore) (res uint64) { return } -func (qm queueMapper) setTop(store sdk.KVStore, top uint64) { +func (qm GenericMapper) setTop(store sdk.KVStore, top uint64) { bz := marshalUint64(qm.cdc, top) store.Set(qm.TopKey(), bz) } -func (qm queueMapper) Push(ctx sdk.Context, value interface{}) { - qm.lm.Push(ctx, value) -} - -func (qm queueMapper) Peek(ctx sdk.Context, ptr interface{}) error { +func (qm GenericMapper) Peek(ctx sdk.Context, ptr interface{}) error { store := ctx.KVStore(qm.key) top := qm.getTop(store) - return qm.lm.Get(ctx, top, ptr) + return qm.Get(ctx, top, ptr) } -func (qm queueMapper) Pop(ctx sdk.Context) { +func (qm GenericMapper) Pop(ctx sdk.Context) { store := ctx.KVStore(qm.key) top := qm.getTop(store) - qm.lm.Delete(ctx, top) + qm.Delete(ctx, top) qm.setTop(store, top+1) } -func (qm queueMapper) IsEmpty(ctx sdk.Context) bool { +func (qm GenericMapper) IsEmpty(ctx sdk.Context) bool { store := ctx.KVStore(qm.key) top := qm.getTop(store) - length := qm.lm.Len(ctx) + length := qm.Len(ctx) return top >= length } -func (qm queueMapper) Flush(ctx sdk.Context, ptr interface{}, fn func(sdk.Context) bool) { +func (qm GenericMapper) Flush(ctx sdk.Context, ptr interface{}, fn func(sdk.Context) bool) { store := ctx.KVStore(qm.key) top := qm.getTop(store) - length := qm.lm.Len(ctx) + length := qm.Len(ctx) var i uint64 for i = top; i < length; i++ { - qm.lm.Get(ctx, i, ptr) - qm.lm.Delete(ctx, i) + qm.Get(ctx, i, ptr) + qm.Delete(ctx, i) if fn(ctx) { break } @@ -254,7 +256,7 @@ func (qm queueMapper) Flush(ctx sdk.Context, ptr interface{}, fn func(sdk.Contex qm.setTop(store, i) } -func (qm queueMapper) TopKey() []byte { +func (qm GenericMapper) TopKey() []byte { return []byte(fmt.Sprintf("%s/top", qm.prefix)) } diff --git a/types/lib/stdlib_test.go b/types/lib/mapper_test.go similarity index 100% rename from types/lib/stdlib_test.go rename to types/lib/mapper_test.go From 88a11ec0bbc19aa27abbd58c3854f78ac574574b Mon Sep 17 00:00:00 2001 From: mossid Date: Fri, 20 Apr 2018 23:25:43 +0200 Subject: [PATCH 11/13] apply requests --- types/lib/mapper.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/types/lib/mapper.go b/types/lib/mapper.go index e168eec2b0..18b3cf5fd5 100644 --- a/types/lib/mapper.go +++ b/types/lib/mapper.go @@ -3,7 +3,6 @@ package lib import ( "fmt" "strconv" - "strings" sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" @@ -25,24 +24,27 @@ type ListMapper interface { Get(sdk.Context, uint64, interface{}) error - // Setting element out of range is harmful + // Setting element out of range will break length counting // Use Push() instead of Set() to append a new element Set(sdk.Context, uint64, interface{}) + // Other elements' indices are preserved after deletion Delete(sdk.Context, uint64) Push(sdk.Context, interface{}) // Getter/Setter for meta information - can be customized + // Use this space for storing relevant information about the list GetMeta(sdk.Context, interface{}) error SetMeta(sdk.Context, interface{}) // Iterate*() is used to iterate over all existing elements in the list // Return true in the continuation to break - // CONTRACT: No writes may happen within a domain while an iterator exists over it. + // CONTRACT: No writes may happen within a domain while iterating over it. IterateRead(sdk.Context, interface{}, func(sdk.Context, uint64) bool) + // CONTRACT: No deletion may happend whihin a domain while iterating over it. // IterateWrite() is safe to write over the domain IterateWrite(sdk.Context, interface{}, func(sdk.Context, uint64) bool) @@ -134,8 +136,8 @@ func (lm GenericMapper) IterateRead(ctx sdk.Context, ptr interface{}, fn func(sd if err := lm.cdc.UnmarshalBinary(v, ptr); err != nil { panic(err) } - s := strings.Split(string(iter.Key()), "/") - index, err := strconv.ParseUint(s[len(s)-1], 10, 64) + s := string(iter.Key()[len(lm.prefix)+6:]) + index, err := strconv.ParseUint(s, 10, 64) if err != nil { panic(err) } @@ -182,10 +184,12 @@ type QueueMapper interface { Peek(sdk.Context, interface{}) error Pop(sdk.Context) IsEmpty(sdk.Context) bool - // Iterate() removes elements it processed + + // Flush() removes elements it processed // Return true in the continuation to break // The interface{} is unmarshalled before the continuation is called // Starts from the top(head) of the queue + // CONTRACT: Pop() or Push() should not be performed while flushing Flush(sdk.Context, interface{}, func(sdk.Context) bool) // Key for the index of top element From 87edaa80d4d55305e11c631982b9edf61eb05e9b Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 25 Apr 2018 13:44:29 +0200 Subject: [PATCH 12/13] add comments, clarify Iterate() --- types/lib/mapper.go | 71 +++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 47 deletions(-) diff --git a/types/lib/mapper.go b/types/lib/mapper.go index 18b3cf5fd5..4286917788 100644 --- a/types/lib/mapper.go +++ b/types/lib/mapper.go @@ -8,7 +8,7 @@ import ( wire "github.com/cosmos/cosmos-sdk/wire" ) -type GenericMapper struct { +type Mapper struct { key sdk.StoreKey cdc *wire.Codec prefix string @@ -29,22 +29,21 @@ type ListMapper interface { Set(sdk.Context, uint64, interface{}) // Other elements' indices are preserved after deletion + // Panics when the index is out of range Delete(sdk.Context, uint64) + // Push will increase the length when it is called + // The other methods does not modify the length Push(sdk.Context, interface{}) - // Getter/Setter for meta information - can be customized - // Use this space for storing relevant information about the list - GetMeta(sdk.Context, interface{}) error - SetMeta(sdk.Context, interface{}) - // Iterate*() is used to iterate over all existing elements in the list // Return true in the continuation to break + // The second element of the continuation will indicate the position of the element + // Using it with Get() will return the same one with the provided element // CONTRACT: No writes may happen within a domain while iterating over it. IterateRead(sdk.Context, interface{}, func(sdk.Context, uint64) bool) - // CONTRACT: No deletion may happend whihin a domain while iterating over it. // IterateWrite() is safe to write over the domain IterateWrite(sdk.Context, interface{}, func(sdk.Context, uint64) bool) @@ -53,20 +52,17 @@ type ListMapper interface { // Key for getting elements ElemKey(uint64) []byte - - // Key for additional meta information of the list - MetaKey() []byte } func NewListMapper(cdc *wire.Codec, key sdk.StoreKey, prefix string) ListMapper { - return GenericMapper{ + return Mapper{ key: key, cdc: cdc, prefix: prefix, } } -func (lm GenericMapper) Len(ctx sdk.Context) uint64 { +func (lm Mapper) Len(ctx sdk.Context) uint64 { store := ctx.KVStore(lm.key) bz := store.Get(lm.LengthKey()) if bz == nil { @@ -84,13 +80,13 @@ func (lm GenericMapper) Len(ctx sdk.Context) uint64 { return res } -func (lm GenericMapper) Get(ctx sdk.Context, index uint64, ptr interface{}) error { +func (lm Mapper) Get(ctx sdk.Context, index uint64, ptr interface{}) error { store := ctx.KVStore(lm.key) bz := store.Get(lm.ElemKey(index)) return lm.cdc.UnmarshalBinary(bz, ptr) } -func (lm GenericMapper) Set(ctx sdk.Context, index uint64, value interface{}) { +func (lm Mapper) Set(ctx sdk.Context, index uint64, value interface{}) { store := ctx.KVStore(lm.key) bz, err := lm.cdc.MarshalBinary(value) if err != nil { @@ -99,12 +95,12 @@ func (lm GenericMapper) Set(ctx sdk.Context, index uint64, value interface{}) { store.Set(lm.ElemKey(index), bz) } -func (lm GenericMapper) Delete(ctx sdk.Context, index uint64) { +func (lm Mapper) Delete(ctx sdk.Context, index uint64) { store := ctx.KVStore(lm.key) store.Delete(lm.ElemKey(index)) } -func (lm GenericMapper) Push(ctx sdk.Context, value interface{}) { +func (lm Mapper) Push(ctx sdk.Context, value interface{}) { length := lm.Len(ctx) lm.Set(ctx, length, value) @@ -112,22 +108,7 @@ func (lm GenericMapper) Push(ctx sdk.Context, value interface{}) { store.Set(lm.LengthKey(), marshalUint64(lm.cdc, length+1)) } -func (lm GenericMapper) GetMeta(ctx sdk.Context, ptr interface{}) error { - store := ctx.KVStore(lm.key) - bz := store.Get(lm.MetaKey()) - return lm.cdc.UnmarshalBinary(bz, ptr) -} - -func (lm GenericMapper) SetMeta(ctx sdk.Context, value interface{}) { - store := ctx.KVStore(lm.key) - bz, err := lm.cdc.MarshalBinary(value) - if err != nil { - panic(err) - } - store.Set(lm.MetaKey(), bz) -} - -func (lm GenericMapper) IterateRead(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { +func (lm Mapper) IterateRead(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { store := ctx.KVStore(lm.key) start, end := subspace([]byte(fmt.Sprintf("%s/elem/", lm.prefix))) iter := store.Iterator(start, end) @@ -149,7 +130,7 @@ func (lm GenericMapper) IterateRead(ctx sdk.Context, ptr interface{}, fn func(sd iter.Close() } -func (lm GenericMapper) IterateWrite(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { +func (lm Mapper) IterateWrite(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { length := lm.Len(ctx) for i := uint64(0); i < length; i++ { @@ -162,18 +143,14 @@ func (lm GenericMapper) IterateWrite(ctx sdk.Context, ptr interface{}, fn func(s } } -func (lm GenericMapper) LengthKey() []byte { +func (lm Mapper) LengthKey() []byte { return []byte(fmt.Sprintf("%s/length", lm.prefix)) } -func (lm GenericMapper) ElemKey(i uint64) []byte { +func (lm Mapper) ElemKey(i uint64) []byte { return []byte(fmt.Sprintf("%s/elem/%020d", lm.prefix, i)) } -func (lm GenericMapper) MetaKey() []byte { - return []byte(fmt.Sprintf("%s/meta", lm.prefix)) -} - // QueueMapper is a Mapper interface that provides queue-like functions // It panics when the element type cannot be (un/)marshalled by the codec @@ -197,14 +174,14 @@ type QueueMapper interface { } func NewQueueMapper(cdc *wire.Codec, key sdk.StoreKey, prefix string) QueueMapper { - return GenericMapper{ + return Mapper{ key: key, cdc: cdc, prefix: prefix, } } -func (qm GenericMapper) getTop(store sdk.KVStore) (res uint64) { +func (qm Mapper) getTop(store sdk.KVStore) (res uint64) { bz := store.Get(qm.TopKey()) if bz == nil { store.Set(qm.TopKey(), marshalUint64(qm.cdc, 0)) @@ -218,32 +195,32 @@ func (qm GenericMapper) getTop(store sdk.KVStore) (res uint64) { return } -func (qm GenericMapper) setTop(store sdk.KVStore, top uint64) { +func (qm Mapper) setTop(store sdk.KVStore, top uint64) { bz := marshalUint64(qm.cdc, top) store.Set(qm.TopKey(), bz) } -func (qm GenericMapper) Peek(ctx sdk.Context, ptr interface{}) error { +func (qm Mapper) Peek(ctx sdk.Context, ptr interface{}) error { store := ctx.KVStore(qm.key) top := qm.getTop(store) return qm.Get(ctx, top, ptr) } -func (qm GenericMapper) Pop(ctx sdk.Context) { +func (qm Mapper) Pop(ctx sdk.Context) { store := ctx.KVStore(qm.key) top := qm.getTop(store) qm.Delete(ctx, top) qm.setTop(store, top+1) } -func (qm GenericMapper) IsEmpty(ctx sdk.Context) bool { +func (qm Mapper) IsEmpty(ctx sdk.Context) bool { store := ctx.KVStore(qm.key) top := qm.getTop(store) length := qm.Len(ctx) return top >= length } -func (qm GenericMapper) Flush(ctx sdk.Context, ptr interface{}, fn func(sdk.Context) bool) { +func (qm Mapper) Flush(ctx sdk.Context, ptr interface{}, fn func(sdk.Context) bool) { store := ctx.KVStore(qm.key) top := qm.getTop(store) length := qm.Len(ctx) @@ -260,7 +237,7 @@ func (qm GenericMapper) Flush(ctx sdk.Context, ptr interface{}, fn func(sdk.Cont qm.setTop(store, i) } -func (qm GenericMapper) TopKey() []byte { +func (qm Mapper) TopKey() []byte { return []byte(fmt.Sprintf("%s/top", qm.prefix)) } From 06d47bebedb8bd739ac5952f469040d2185b5959 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 25 Apr 2018 14:45:22 +0200 Subject: [PATCH 13/13] add comments for golint --- mock/store.go | 2 +- types/lib/mapper.go | 163 ++++++++++++++++++++++++++------------------ 2 files changed, 97 insertions(+), 68 deletions(-) diff --git a/mock/store.go b/mock/store.go index e518aa26a3..329eb250bb 100644 --- a/mock/store.go +++ b/mock/store.go @@ -42,7 +42,7 @@ func (ms multiStore) LoadLatestVersion() error { return nil } -func (md multiStore) LoadVersion(ver int64) error { +func (ms multiStore) LoadVersion(ver int64) error { panic("not implemented") } diff --git a/types/lib/mapper.go b/types/lib/mapper.go index 4286917788..ca90200773 100644 --- a/types/lib/mapper.go +++ b/types/lib/mapper.go @@ -8,6 +8,7 @@ import ( wire "github.com/cosmos/cosmos-sdk/wire" ) +// Mapper defines a primitive mapper type type Mapper struct { key sdk.StoreKey cdc *wire.Codec @@ -16,24 +17,29 @@ type Mapper struct { // ListMapper is a Mapper interface that provides list-like functions // It panics when the element type cannot be (un/)marshalled by the codec - type ListMapper interface { + + // Len() returns the length of the list + // The length is only increased by Push() and not decreased // ListMapper dosen't check if an index is in bounds // The user should check Len() before doing any actions Len(sdk.Context) uint64 + // Get() returns the element by its index Get(sdk.Context, uint64, interface{}) error + // Set() stores the element to the given position // Setting element out of range will break length counting // Use Push() instead of Set() to append a new element Set(sdk.Context, uint64, interface{}) + // Delete() deletes the element in the given position // Other elements' indices are preserved after deletion // Panics when the index is out of range Delete(sdk.Context, uint64) - // Push will increase the length when it is called - // The other methods does not modify the length + // Push() inserts the element to the end of the list + // It will increase the length when it is called Push(sdk.Context, interface{}) // Iterate*() is used to iterate over all existing elements in the list @@ -54,6 +60,7 @@ type ListMapper interface { ElemKey(uint64) []byte } +// NewListMapper constructs new ListMapper func NewListMapper(cdc *wire.Codec, key sdk.StoreKey, prefix string) ListMapper { return Mapper{ key: key, @@ -62,62 +69,68 @@ func NewListMapper(cdc *wire.Codec, key sdk.StoreKey, prefix string) ListMapper } } -func (lm Mapper) Len(ctx sdk.Context) uint64 { - store := ctx.KVStore(lm.key) - bz := store.Get(lm.LengthKey()) +// Len implements ListMapper +func (m Mapper) Len(ctx sdk.Context) uint64 { + store := ctx.KVStore(m.key) + bz := store.Get(m.LengthKey()) if bz == nil { - zero, err := lm.cdc.MarshalBinary(0) + zero, err := m.cdc.MarshalBinary(0) if err != nil { panic(err) } - store.Set(lm.LengthKey(), zero) + store.Set(m.LengthKey(), zero) return 0 } var res uint64 - if err := lm.cdc.UnmarshalBinary(bz, &res); err != nil { + if err := m.cdc.UnmarshalBinary(bz, &res); err != nil { panic(err) } return res } -func (lm Mapper) Get(ctx sdk.Context, index uint64, ptr interface{}) error { - store := ctx.KVStore(lm.key) - bz := store.Get(lm.ElemKey(index)) - return lm.cdc.UnmarshalBinary(bz, ptr) +// Get implements ListMapper +func (m Mapper) Get(ctx sdk.Context, index uint64, ptr interface{}) error { + store := ctx.KVStore(m.key) + bz := store.Get(m.ElemKey(index)) + return m.cdc.UnmarshalBinary(bz, ptr) } -func (lm Mapper) Set(ctx sdk.Context, index uint64, value interface{}) { - store := ctx.KVStore(lm.key) - bz, err := lm.cdc.MarshalBinary(value) +// Set implements ListMapper +func (m Mapper) Set(ctx sdk.Context, index uint64, value interface{}) { + store := ctx.KVStore(m.key) + bz, err := m.cdc.MarshalBinary(value) if err != nil { panic(err) } - store.Set(lm.ElemKey(index), bz) + store.Set(m.ElemKey(index), bz) } -func (lm Mapper) Delete(ctx sdk.Context, index uint64) { - store := ctx.KVStore(lm.key) - store.Delete(lm.ElemKey(index)) +// Delete implements ListMapper +func (m Mapper) Delete(ctx sdk.Context, index uint64) { + store := ctx.KVStore(m.key) + store.Delete(m.ElemKey(index)) } -func (lm Mapper) Push(ctx sdk.Context, value interface{}) { - length := lm.Len(ctx) - lm.Set(ctx, length, value) +// Push implements ListMapper +func (m Mapper) Push(ctx sdk.Context, value interface{}) { + length := m.Len(ctx) + m.Set(ctx, length, value) - store := ctx.KVStore(lm.key) - store.Set(lm.LengthKey(), marshalUint64(lm.cdc, length+1)) + store := ctx.KVStore(m.key) + store.Set(m.LengthKey(), marshalUint64(m.cdc, length+1)) } -func (lm Mapper) IterateRead(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { - store := ctx.KVStore(lm.key) - start, end := subspace([]byte(fmt.Sprintf("%s/elem/", lm.prefix))) +// IterateRead implements ListMapper +func (m Mapper) IterateRead(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { + store := ctx.KVStore(m.key) + start, end := subspace([]byte(fmt.Sprintf("%s/elem/", m.prefix))) iter := store.Iterator(start, end) for ; iter.Valid(); iter.Next() { v := iter.Value() - if err := lm.cdc.UnmarshalBinary(v, ptr); err != nil { + if err := m.cdc.UnmarshalBinary(v, ptr); err != nil { panic(err) } - s := string(iter.Key()[len(lm.prefix)+6:]) + s := string(iter.Key()[len(m.prefix)+6:]) index, err := strconv.ParseUint(s, 10, 64) if err != nil { panic(err) @@ -130,11 +143,12 @@ func (lm Mapper) IterateRead(ctx sdk.Context, ptr interface{}, fn func(sdk.Conte iter.Close() } -func (lm Mapper) IterateWrite(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { - length := lm.Len(ctx) +// IterateWrite implements ListMapper +func (m Mapper) IterateWrite(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, uint64) bool) { + length := m.Len(ctx) for i := uint64(0); i < length; i++ { - if err := lm.Get(ctx, i, ptr); err != nil { + if err := m.Get(ctx, i, ptr); err != nil { continue } if fn(ctx, i) { @@ -143,23 +157,32 @@ func (lm Mapper) IterateWrite(ctx sdk.Context, ptr interface{}, fn func(sdk.Cont } } -func (lm Mapper) LengthKey() []byte { - return []byte(fmt.Sprintf("%s/length", lm.prefix)) +// LengthKey implements ListMapper +func (m Mapper) LengthKey() []byte { + return []byte(fmt.Sprintf("%s/length", m.prefix)) } -func (lm Mapper) ElemKey(i uint64) []byte { - return []byte(fmt.Sprintf("%s/elem/%020d", lm.prefix, i)) +// ElemKey implements ListMapper +func (m Mapper) ElemKey(i uint64) []byte { + return []byte(fmt.Sprintf("%s/elem/%020d", m.prefix, i)) } // QueueMapper is a Mapper interface that provides queue-like functions // It panics when the element type cannot be (un/)marshalled by the codec - type QueueMapper interface { + // Push() inserts the elements to the rear of the queue Push(sdk.Context, interface{}) + // Popping/Peeking on an empty queue will cause panic // The user should check IsEmpty() before doing any actions + + // Peek() returns the element at the front of the queue without removing it Peek(sdk.Context, interface{}) error + + // Pop() returns the element at the front of the queue and removes it Pop(sdk.Context) + + // IsEmpty() checks if the queue is empty IsEmpty(sdk.Context) bool // Flush() removes elements it processed @@ -173,6 +196,7 @@ type QueueMapper interface { TopKey() []byte } +// NewQueueMapper constructs new QueueMapper func NewQueueMapper(cdc *wire.Codec, key sdk.StoreKey, prefix string) QueueMapper { return Mapper{ key: key, @@ -181,64 +205,69 @@ func NewQueueMapper(cdc *wire.Codec, key sdk.StoreKey, prefix string) QueueMappe } } -func (qm Mapper) getTop(store sdk.KVStore) (res uint64) { - bz := store.Get(qm.TopKey()) +func (m Mapper) getTop(store sdk.KVStore) (res uint64) { + bz := store.Get(m.TopKey()) if bz == nil { - store.Set(qm.TopKey(), marshalUint64(qm.cdc, 0)) + store.Set(m.TopKey(), marshalUint64(m.cdc, 0)) return 0 } - if err := qm.cdc.UnmarshalBinary(bz, &res); err != nil { + if err := m.cdc.UnmarshalBinary(bz, &res); err != nil { panic(err) } return } -func (qm Mapper) setTop(store sdk.KVStore, top uint64) { - bz := marshalUint64(qm.cdc, top) - store.Set(qm.TopKey(), bz) +func (m Mapper) setTop(store sdk.KVStore, top uint64) { + bz := marshalUint64(m.cdc, top) + store.Set(m.TopKey(), bz) } -func (qm Mapper) Peek(ctx sdk.Context, ptr interface{}) error { - store := ctx.KVStore(qm.key) - top := qm.getTop(store) - return qm.Get(ctx, top, ptr) +// Peek implements QueueMapper +func (m Mapper) Peek(ctx sdk.Context, ptr interface{}) error { + store := ctx.KVStore(m.key) + top := m.getTop(store) + return m.Get(ctx, top, ptr) } -func (qm Mapper) Pop(ctx sdk.Context) { - store := ctx.KVStore(qm.key) - top := qm.getTop(store) - qm.Delete(ctx, top) - qm.setTop(store, top+1) +// Pop implements QueueMapper +func (m Mapper) Pop(ctx sdk.Context) { + store := ctx.KVStore(m.key) + top := m.getTop(store) + m.Delete(ctx, top) + m.setTop(store, top+1) } -func (qm Mapper) IsEmpty(ctx sdk.Context) bool { - store := ctx.KVStore(qm.key) - top := qm.getTop(store) - length := qm.Len(ctx) +// IsEmpty implements QueueMapper +func (m Mapper) IsEmpty(ctx sdk.Context) bool { + store := ctx.KVStore(m.key) + top := m.getTop(store) + length := m.Len(ctx) return top >= length } -func (qm Mapper) Flush(ctx sdk.Context, ptr interface{}, fn func(sdk.Context) bool) { - store := ctx.KVStore(qm.key) - top := qm.getTop(store) - length := qm.Len(ctx) +// Flush implements QueueMapper +func (m Mapper) Flush(ctx sdk.Context, ptr interface{}, fn func(sdk.Context) bool) { + store := ctx.KVStore(m.key) + top := m.getTop(store) + length := m.Len(ctx) var i uint64 for i = top; i < length; i++ { - qm.Get(ctx, i, ptr) - qm.Delete(ctx, i) + m.Get(ctx, i, ptr) + m.Delete(ctx, i) if fn(ctx) { break } } - qm.setTop(store, i) + m.setTop(store, i) } -func (qm Mapper) TopKey() []byte { - return []byte(fmt.Sprintf("%s/top", qm.prefix)) +// TopKey implements QueueMapper +func (m Mapper) TopKey() []byte { + return []byte(fmt.Sprintf("%s/top", m.prefix)) } func marshalUint64(cdc *wire.Codec, i uint64) []byte {