From 861eb5da1c9eb74fb34d0af16862906515eb64e1 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 14 Mar 2018 19:20:15 +0100 Subject: [PATCH 1/2] revert & rebase; add stdlib and test --- tests/stdlib_test.go | 69 +++++++++++++ types/stdlib.go | 231 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 300 insertions(+) create mode 100644 tests/stdlib_test.go create mode 100644 types/stdlib.go diff --git a/tests/stdlib_test.go b/tests/stdlib_test.go new file mode 100644 index 0000000000..c2d47f6b52 --- /dev/null +++ b/tests/stdlib_test.go @@ -0,0 +1,69 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + dbm "github.com/tendermint/tmlibs/db" + + abci "github.com/tendermint/abci/types" + + "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 + B bool +} + +func defaultComponents(key sdk.StoreKey) (sdk.Context, *wire.Codec) { + db := dbm.NewMemDB() + cms := store.NewCommitMultiStore(db) + cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) + cms.LoadLatestVersion() + ctx := sdk.NewContext(cms, abci.Header{}, false, nil) + cdc := wire.NewCodec() + return ctx, cdc +} + +func TestListMapper(t *testing.T) { + key := sdk.NewKVStoreKey("list") + ctx, cdc := defaultComponents(key) + lm := sdk.NewListMapper(cdc, key) + + val := S{1, true} + var res S + + lm.Push(ctx, val) + assert.Equal(t, int64(1), lm.Len(ctx)) + lm.Get(ctx, int64(0), &res) + assert.Equal(t, val, res) + + val = S{2, false} + lm.Set(ctx, int64(0), val) + lm.Get(ctx, int64(0), &res) + assert.Equal(t, val, res) +} + +func TestQueueMapper(t *testing.T) { + key := sdk.NewKVStoreKey("queue") + ctx, cdc := defaultComponents(key) + qm := sdk.NewQueueMapper(cdc, key) + + val := S{1, true} + var res S + + qm.Push(ctx, val) + qm.Peek(ctx, &res) + assert.Equal(t, val, res) + + qm.Pop(ctx) + empty := qm.IsEmpty(ctx) + + assert.Equal(t, true, empty) + + assert.Panics(t, func() { qm.Peek(ctx, &res) }) +} diff --git a/types/stdlib.go b/types/stdlib.go new file mode 100644 index 0000000000..d6c6c3f424 --- /dev/null +++ b/types/stdlib.go @@ -0,0 +1,231 @@ +package types + +import ( + "errors" + + wire "github.com/cosmos/cosmos-sdk/wire" +) + +type ListMapper interface { // Solidity list like structure + Len(Context) int64 + Get(Context, int64, interface{}) + Set(Context, int64, interface{}) + Push(Context, interface{}) + Iterate(Context, interface{}, func(Context, int64)) +} + +type listMapper struct { + key StoreKey + cdc *wire.Codec + lk []byte +} + +func NewListMapper(cdc *wire.Codec, key StoreKey) ListMapper { + lk, err := cdc.MarshalBinary(int64(-1)) + if err != nil { + panic(err) + } + return listMapper{ + key: key, + cdc: cdc, + lk: lk, + } +} + +func (lm listMapper) Len(ctx Context) int64 { + store := ctx.KVStore(lm.key) + bz := store.Get(lm.lk) + if bz == nil { + zero, err := lm.cdc.MarshalBinary(0) + if err != nil { + panic(err) + } + store.Set(lm.lk, zero) + return 0 + } + var res int64 + if err := lm.cdc.UnmarshalBinary(bz, &res); err != nil { + panic(err) + } + return res +} + +func (lm listMapper) Get(ctx Context, index int64, ptr interface{}) { + if index < 0 { + panic(errors.New("")) + } + store := ctx.KVStore(lm.key) + bz := store.Get(marshalInt64(lm.cdc, index)) + if err := lm.cdc.UnmarshalBinary(bz, ptr); err != nil { + panic(err) + } +} + +func (lm listMapper) Set(ctx Context, index int64, value interface{}) { + if index < 0 { + panic(errors.New("")) + } + store := ctx.KVStore(lm.key) + bz, err := lm.cdc.MarshalBinary(value) + if err != nil { + panic(err) + } + store.Set(marshalInt64(lm.cdc, index), bz) +} + +func (lm listMapper) Push(ctx Context, value interface{}) { + length := lm.Len(ctx) + lm.Set(ctx, length, value) + + store := ctx.KVStore(lm.key) + store.Set(lm.lk, marshalInt64(lm.cdc, length+1)) +} + +func (lm listMapper) Iterate(ctx Context, ptr interface{}, fn func(Context, int64)) { + length := lm.Len(ctx) + for i := int64(0); i < length; i++ { + lm.Get(ctx, i, ptr) + fn(ctx, i) + } +} + +type QueueMapper interface { + Push(Context, interface{}) + Peek(Context, interface{}) + Pop(Context) + IsEmpty(Context) bool + Iterate(Context, interface{}, func(Context) bool) +} + +type queueMapper struct { + key StoreKey + cdc *wire.Codec + ik []byte +} + +func NewQueueMapper(cdc *wire.Codec, key StoreKey) QueueMapper { + ik, err := cdc.MarshalBinary(int64(-1)) + if err != nil { + panic(err) + } + return queueMapper{ + key: key, + cdc: cdc, + ik: ik, + } +} + +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 errors.New("") + } + return nil +} + +func (info queueInfo) isEmpty() bool { + return info.Begin == info.End +} + +func (qm queueMapper) getQueueInfo(store KVStore) queueInfo { + bz := store.Get(qm.ik) + if bz == nil { + store.Set(qm.ik, marshalQueueInfo(qm.cdc, queueInfo{0, 0})) + return queueInfo{0, 0} + } + var info queueInfo + if err := qm.cdc.UnmarshalBinary(bz, &info); err != nil { + panic(err) + } + if err := info.validateBasic(); err != nil { + panic(err) + } + return info +} + +func (qm queueMapper) setQueueInfo(store KVStore, info queueInfo) { + bz, err := qm.cdc.MarshalBinary(info) + if err != nil { + panic(err) + } + store.Set(qm.ik, bz) +} + +func (qm queueMapper) Push(ctx 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) + + info.End++ + qm.setQueueInfo(store, info) +} + +func (qm queueMapper) Peek(ctx 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) + } +} + +func (qm queueMapper) Pop(ctx Context) { + store := ctx.KVStore(qm.key) + info := qm.getQueueInfo(store) + store.Delete(marshalInt64(qm.cdc, info.Begin)) + info.Begin++ + qm.setQueueInfo(store, info) +} + +func (qm queueMapper) IsEmpty(ctx Context) bool { + store := ctx.KVStore(qm.key) + info := qm.getQueueInfo(store) + return info.isEmpty() +} + +func (qm queueMapper) Iterate(ctx Context, ptr interface{}, fn func(Context) bool) { + store := ctx.KVStore(qm.key) + info := qm.getQueueInfo(store) + + var i int64 + for i = info.Begin; i < info.End; i++ { + 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 + } + } + + info.Begin = i + qm.setQueueInfo(store, info) +} + +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 { + bz, err := cdc.MarshalBinary(i) + if err != nil { + panic(err) + } + return bz +} From 806b4b2603d610676322b2761022552a226e52be Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 15 Mar 2018 10:59:36 +0100 Subject: [PATCH 2/2] types/stdlib --- types/{ => stdlib}/stdlib.go | 53 +++++++++++++------------- {tests => types/stdlib}/stdlib_test.go | 4 +- 2 files changed, 29 insertions(+), 28 deletions(-) rename types/{ => stdlib}/stdlib.go (71%) rename {tests => types/stdlib}/stdlib_test.go (94%) diff --git a/types/stdlib.go b/types/stdlib/stdlib.go similarity index 71% rename from types/stdlib.go rename to types/stdlib/stdlib.go index d6c6c3f424..dd9f4efad1 100644 --- a/types/stdlib.go +++ b/types/stdlib/stdlib.go @@ -3,24 +3,25 @@ package types import ( "errors" + sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" ) type ListMapper interface { // Solidity list like structure - Len(Context) int64 - Get(Context, int64, interface{}) - Set(Context, int64, interface{}) - Push(Context, interface{}) - Iterate(Context, interface{}, func(Context, int64)) + Len(sdk.Context) int64 + Get(sdk.Context, int64, interface{}) + Set(sdk.Context, int64, interface{}) + Push(sdk.Context, interface{}) + Iterate(sdk.Context, interface{}, func(sdk.Context, int64)) } type listMapper struct { - key StoreKey + key sdk.StoreKey cdc *wire.Codec lk []byte } -func NewListMapper(cdc *wire.Codec, key StoreKey) ListMapper { +func NewListMapper(cdc *wire.Codec, key sdk.StoreKey) ListMapper { lk, err := cdc.MarshalBinary(int64(-1)) if err != nil { panic(err) @@ -32,7 +33,7 @@ func NewListMapper(cdc *wire.Codec, key StoreKey) ListMapper { } } -func (lm listMapper) Len(ctx Context) int64 { +func (lm listMapper) Len(ctx sdk.Context) int64 { store := ctx.KVStore(lm.key) bz := store.Get(lm.lk) if bz == nil { @@ -50,7 +51,7 @@ func (lm listMapper) Len(ctx Context) int64 { return res } -func (lm listMapper) Get(ctx Context, index int64, ptr interface{}) { +func (lm listMapper) Get(ctx sdk.Context, index int64, ptr interface{}) { if index < 0 { panic(errors.New("")) } @@ -61,7 +62,7 @@ func (lm listMapper) Get(ctx Context, index int64, ptr interface{}) { } } -func (lm listMapper) Set(ctx Context, index int64, value interface{}) { +func (lm listMapper) Set(ctx sdk.Context, index int64, value interface{}) { if index < 0 { panic(errors.New("")) } @@ -73,7 +74,7 @@ func (lm listMapper) Set(ctx Context, index int64, value interface{}) { store.Set(marshalInt64(lm.cdc, index), bz) } -func (lm listMapper) Push(ctx Context, value interface{}) { +func (lm listMapper) Push(ctx sdk.Context, value interface{}) { length := lm.Len(ctx) lm.Set(ctx, length, value) @@ -81,7 +82,7 @@ func (lm listMapper) Push(ctx Context, value interface{}) { store.Set(lm.lk, marshalInt64(lm.cdc, length+1)) } -func (lm listMapper) Iterate(ctx Context, ptr interface{}, fn func(Context, int64)) { +func (lm listMapper) Iterate(ctx sdk.Context, ptr interface{}, fn func(sdk.Context, int64)) { length := lm.Len(ctx) for i := int64(0); i < length; i++ { lm.Get(ctx, i, ptr) @@ -90,20 +91,20 @@ func (lm listMapper) Iterate(ctx Context, ptr interface{}, fn func(Context, int6 } type QueueMapper interface { - Push(Context, interface{}) - Peek(Context, interface{}) - Pop(Context) - IsEmpty(Context) bool - Iterate(Context, interface{}, func(Context) bool) + Push(sdk.Context, interface{}) + Peek(sdk.Context, interface{}) + Pop(sdk.Context) + IsEmpty(sdk.Context) bool + Iterate(sdk.Context, interface{}, func(sdk.Context) bool) } type queueMapper struct { - key StoreKey + key sdk.StoreKey cdc *wire.Codec ik []byte } -func NewQueueMapper(cdc *wire.Codec, key StoreKey) QueueMapper { +func NewQueueMapper(cdc *wire.Codec, key sdk.StoreKey) QueueMapper { ik, err := cdc.MarshalBinary(int64(-1)) if err != nil { panic(err) @@ -132,7 +133,7 @@ func (info queueInfo) isEmpty() bool { return info.Begin == info.End } -func (qm queueMapper) getQueueInfo(store KVStore) queueInfo { +func (qm queueMapper) getQueueInfo(store sdk.KVStore) queueInfo { bz := store.Get(qm.ik) if bz == nil { store.Set(qm.ik, marshalQueueInfo(qm.cdc, queueInfo{0, 0})) @@ -148,7 +149,7 @@ func (qm queueMapper) getQueueInfo(store KVStore) queueInfo { return info } -func (qm queueMapper) setQueueInfo(store KVStore, info queueInfo) { +func (qm queueMapper) setQueueInfo(store sdk.KVStore, info queueInfo) { bz, err := qm.cdc.MarshalBinary(info) if err != nil { panic(err) @@ -156,7 +157,7 @@ func (qm queueMapper) setQueueInfo(store KVStore, info queueInfo) { store.Set(qm.ik, bz) } -func (qm queueMapper) Push(ctx Context, value interface{}) { +func (qm queueMapper) Push(ctx sdk.Context, value interface{}) { store := ctx.KVStore(qm.key) info := qm.getQueueInfo(store) @@ -170,7 +171,7 @@ func (qm queueMapper) Push(ctx Context, value interface{}) { qm.setQueueInfo(store, info) } -func (qm queueMapper) Peek(ctx Context, ptr 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)) @@ -179,7 +180,7 @@ func (qm queueMapper) Peek(ctx Context, ptr interface{}) { } } -func (qm queueMapper) Pop(ctx Context) { +func (qm queueMapper) Pop(ctx sdk.Context) { store := ctx.KVStore(qm.key) info := qm.getQueueInfo(store) store.Delete(marshalInt64(qm.cdc, info.Begin)) @@ -187,13 +188,13 @@ func (qm queueMapper) Pop(ctx Context) { qm.setQueueInfo(store, info) } -func (qm queueMapper) IsEmpty(ctx Context) bool { +func (qm queueMapper) IsEmpty(ctx sdk.Context) bool { store := ctx.KVStore(qm.key) info := qm.getQueueInfo(store) return info.isEmpty() } -func (qm queueMapper) Iterate(ctx Context, ptr interface{}, fn func(Context) bool) { +func (qm queueMapper) Iterate(ctx sdk.Context, ptr interface{}, fn func(sdk.Context) bool) { store := ctx.KVStore(qm.key) info := qm.getQueueInfo(store) diff --git a/tests/stdlib_test.go b/types/stdlib/stdlib_test.go similarity index 94% rename from tests/stdlib_test.go rename to types/stdlib/stdlib_test.go index c2d47f6b52..7c871ccf3c 100644 --- a/tests/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 := sdk.NewListMapper(cdc, key) + lm := NewListMapper(cdc, key) val := S{1, true} var res S @@ -51,7 +51,7 @@ func TestListMapper(t *testing.T) { func TestQueueMapper(t *testing.T) { key := sdk.NewKVStoreKey("queue") ctx, cdc := defaultComponents(key) - qm := sdk.NewQueueMapper(cdc, key) + qm := NewQueueMapper(cdc, key) val := S{1, true} var res S