From bab5d370bba6be834477f1a49b8ed835239bed75 Mon Sep 17 00:00:00 2001 From: BlockChainDev Date: Mon, 18 Mar 2019 21:58:51 +0000 Subject: [PATCH 1/4] Interop --- .../csharp-interop-test/push/pushbytes1.json | 81 +++++++++++++++++++ pkg/vm/csharp-interop-test/readme.md | 6 ++ pkg/vm/csharp-interop-test/testStruct.go | 26 ++++++ 3 files changed, 113 insertions(+) create mode 100644 pkg/vm/csharp-interop-test/push/pushbytes1.json create mode 100644 pkg/vm/csharp-interop-test/readme.md create mode 100644 pkg/vm/csharp-interop-test/testStruct.go diff --git a/pkg/vm/csharp-interop-test/push/pushbytes1.json b/pkg/vm/csharp-interop-test/push/pushbytes1.json new file mode 100644 index 000000000..474944423 --- /dev/null +++ b/pkg/vm/csharp-interop-test/push/pushbytes1.json @@ -0,0 +1,81 @@ +{ + "category": "Push", + "name": "PUSHBYTES1", + "tests": + [ + { + "name": "Good definition", + "script": "0x0100", + "steps": + [ + { + "actions": + [ + "StepInto" + ], + "result": + { + "state": "Break", + "invocationStack": + [ + { + "scriptHash": "0xFBC22D517F38E7612798ECE8E5957CF6C41D8CAF", + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": + [ + { + "type": "ByteArray", + "value": "0x00" + } + ] + } + ] + } + }, + { + "actions": + [ + "StepInto" + ], + "result": + { + "state": "Halt", + "resultStack": + [ + { + "type": "ByteArray", + "value": "0x00" + } + ] + } + } + ] + }, + { + "name": "Wrong definition (without enough length)", + "script": "0x01", + "steps": + [ + { + "actions": + [ + "StepInto" + ], + "result": + { + "state": "Fault", + "invocationStack": + [ + { + "scriptHash": "0xC51B66BCED5E4491001BD702669770DCCF440982", + "instructionPointer": 1, + "nextInstruction": "RET" + } + ] + } + } + ] + } + ] +} \ No newline at end of file diff --git a/pkg/vm/csharp-interop-test/readme.md b/pkg/vm/csharp-interop-test/readme.md new file mode 100644 index 000000000..0e457c7c0 --- /dev/null +++ b/pkg/vm/csharp-interop-test/readme.md @@ -0,0 +1,6 @@ +## Package VM Interop + + +This package will use the tests in the neo-vm repo to test interopabilty + + diff --git a/pkg/vm/csharp-interop-test/testStruct.go b/pkg/vm/csharp-interop-test/testStruct.go new file mode 100644 index 000000000..c0da0112b --- /dev/null +++ b/pkg/vm/csharp-interop-test/testStruct.go @@ -0,0 +1,26 @@ +package csharpinterop + +// VMUnitTest is a struct for capturing the fields in the json files +type VMUnitTest struct { + Category string `json:"category"` + Name string `json:"name"` + Tests []struct { + Name string `json:"name"` + Script string `json:"script"` + Steps []struct { + Actions []string `json:"actions"` + Result struct { + State string `json:"state"` + InvocationStack []struct { + ScriptHash string `json:"scriptHash"` + InstructionPointer int `json:"instructionPointer"` + NextInstruction string `json:"nextInstruction"` + EvaluationStack []struct { + Type string `json:"type"` + Value string `json:"value"` + } `json:"evaluationStack"` + } `json:"invocationStack"` + } `json:"result"` + } `json:"steps"` + } `json:"tests"` +} From d818c162976043aca12ac3eb8bfc8a1622960386 Mon Sep 17 00:00:00 2001 From: DauTT Date: Fri, 29 Mar 2019 17:43:16 +0100 Subject: [PATCH 2/4] Implemented MIN, MAX WITHIN opcode --- pkg/vm/stack/Int.go | 26 +++++++++++ pkg/vm/vm_ops.go | 3 ++ pkg/vm/vm_ops_maths.go | 91 +++++++++++++++++++++++++++++++------ pkg/vm/vm_ops_maths_test.go | 82 +++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+), 13 deletions(-) diff --git a/pkg/vm/stack/Int.go b/pkg/vm/stack/Int.go index 52e6240d4..2c32a8b1d 100644 --- a/pkg/vm/stack/Int.go +++ b/pkg/vm/stack/Int.go @@ -111,3 +111,29 @@ func (i *Int) Abs() (*Int, error) { return b, nil } + +// Min returns the mininum between two integers. +func Min(a *Int, b *Int) *Int { + if a.Value().Cmp(b.Value()) == -1 { + return a + } + return b + +} + +// Max returns the maximun between two integers. +func Max(a *Int, b *Int) *Int { + if a.Value().Cmp(b.Value()) == 1 { + return a + } + return b +} + +// Within returns a bool whose value is true +// iff the value of the integer i is within the specified +// range [a,b) (left-inclusive). +func (i *Int) Within(a *Int, b *Int) bool { + // i >= a && i < b + return !(i.Value().Cmp(a.Value()) == -1) && i.Value().Cmp(b.Value()) == -1 + +} diff --git a/pkg/vm/vm_ops.go b/pkg/vm/vm_ops.go index cef46a199..bd2715d72 100644 --- a/pkg/vm/vm_ops.go +++ b/pkg/vm/vm_ops.go @@ -5,6 +5,9 @@ import "github.com/CityOfZion/neo-go/pkg/vm/stack" type stackInfo func(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) var opFunc = map[stack.Instruction]stackInfo{ + stack.MIN: Min, + stack.MAX: Max, + stack.WITHIN: Within, stack.SHR: Shr, stack.SHL: Shl, stack.INC: Inc, diff --git a/pkg/vm/vm_ops_maths.go b/pkg/vm/vm_ops_maths.go index 5cbe0552a..c1e362781 100644 --- a/pkg/vm/vm_ops_maths.go +++ b/pkg/vm/vm_ops_maths.go @@ -173,6 +173,54 @@ func Mul(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rst return NONE, nil } +// Min pops two integers, a and b, off of the stack and pushes an integer to the stack +// whose value is is the minum between a and b's value. +// Returns an error if either items cannot be casted to an integer +func Min(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + operandA, operandB, err := popTwoIntegers(ctx) + if err != nil { + return FAULT, err + } + res := stack.Min(operandA, operandB) + + ctx.Estack.Push(res) + + return NONE, nil +} + +// Max pops two integers, a and b, off of the stack and pushes an integer to the stack +// whose value is is the maximum between a and b's value. +// Returns an error if either items cannot be casted to an integer +func Max(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + operandA, operandB, err := popTwoIntegers(ctx) + if err != nil { + return FAULT, err + } + res := stack.Max(operandA, operandB) + + ctx.Estack.Push(res) + + return NONE, nil +} + +// Within pops three integers, a, b, and c off of the stack and pushes a boolean to the stack +// whose value is true iff c's value is within b's value (include) and a's value. +// Returns an error if at least one item cannot be casted to an boolean. +func Within(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + a, b, c, err := popThreeIntegers(ctx) + if err != nil { + return FAULT, err + } + res := stack.NewBoolean(c.Within(b, a)) + + ctx.Estack.Push(res) + + return NONE, nil +} + // Abs pops an integer off of the stack and pushes its absolute value onto the stack. // Returns an error if the popped value is not an integer or if the absolute value cannot be taken func Abs(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { @@ -247,19 +295,6 @@ func Negate(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, return NONE, nil } -func popTwoIntegers(ctx *stack.Context) (*stack.Int, *stack.Int, error) { - operandA, err := ctx.Estack.PopInt() - if err != nil { - return nil, nil, err - } - operandB, err := ctx.Estack.PopInt() - if err != nil { - return nil, nil, err - } - - return operandA, operandB, nil -} - // Shl pops two integers, a and b, off of the stack and pushes an integer to the stack // whose value is the b's value shift to the left by a's value bits. // Returns an error if either items cannot be casted to an integer @@ -300,6 +335,36 @@ func Shr(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rst return NONE, nil } +func popTwoIntegers(ctx *stack.Context) (*stack.Int, *stack.Int, error) { + operandA, err := ctx.Estack.PopInt() + if err != nil { + return nil, nil, err + } + operandB, err := ctx.Estack.PopInt() + if err != nil { + return nil, nil, err + } + + return operandA, operandB, nil +} + +func popThreeIntegers(ctx *stack.Context) (*stack.Int, *stack.Int, *stack.Int, error) { + operandA, err := ctx.Estack.PopInt() + if err != nil { + return nil, nil, nil, err + } + operandB, err := ctx.Estack.PopInt() + if err != nil { + return nil, nil, nil, err + } + operandC, err := ctx.Estack.PopInt() + if err != nil { + return nil, nil, nil, err + } + + return operandA, operandB, operandC, nil +} + func popTwoByteArrays(ctx *stack.Context) (*stack.ByteArray, *stack.ByteArray, error) { // Pop first stack item and cast as byte array ba1, err := ctx.Estack.PopByteArray() diff --git a/pkg/vm/vm_ops_maths_test.go b/pkg/vm/vm_ops_maths_test.go index b703751be..4671267f7 100644 --- a/pkg/vm/vm_ops_maths_test.go +++ b/pkg/vm/vm_ops_maths_test.go @@ -394,3 +394,85 @@ func TestShrOp(t *testing.T) { assert.Equal(t, int64(2), item.Value().Int64()) } + +func TestMinOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(10)) + assert.NoError(t, err) + + b, err := stack.NewInt(big.NewInt(2)) + assert.NoError(t, err) + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a).Push(b) + + v.executeOp(stack.MIN, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.PopInt() + assert.NoError(t, err) + + assert.Equal(t, int64(2), item.Value().Int64()) +} + +func TestMaxOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(10)) + assert.NoError(t, err) + + b, err := stack.NewInt(big.NewInt(2)) + assert.NoError(t, err) + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a).Push(b) + + v.executeOp(stack.MAX, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.PopInt() + assert.NoError(t, err) + + assert.Equal(t, int64(10), item.Value().Int64()) +} + +func TestWithinOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(5)) + assert.NoError(t, err) + + b, err := stack.NewInt(big.NewInt(2)) + assert.NoError(t, err) + + c, err := stack.NewInt(big.NewInt(10)) + assert.NoError(t, err) + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a).Push(b).Push(c) + + // c is the first item popped. + // b is the second item popped. + // a is the third item popped. + // if a is within [b, c) we place a boolean, + // whose value is true, on top of the evaluation + // stack. Otherwise we place a boolean with + // false value. + v.executeOp(stack.WITHIN, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.PopBoolean() + assert.NoError(t, err) + + assert.Equal(t, true, item.Value()) +} From c6cd0e0c21c0b4e5c61d882a1d9f7f63c3d4ce1c Mon Sep 17 00:00:00 2001 From: DauTT Date: Tue, 2 Apr 2019 22:38:41 +0200 Subject: [PATCH 3/4] Implemented Map Stack Item: 1) Added new file map.go, map_test.go 2) Added Map, Hash Method to Item interface 3) Implemented Hash Method for every stack items (Boolean, Array, Int, ...) --- pkg/vm/stack/Int.go | 11 ++- pkg/vm/stack/array.go | 23 +++++ pkg/vm/stack/boolean.go | 10 +++ pkg/vm/stack/bytearray.go | 12 +++ pkg/vm/stack/context.go | 7 ++ pkg/vm/stack/map.go | 166 ++++++++++++++++++++++++++++++++++++ pkg/vm/stack/map_test.go | 141 ++++++++++++++++++++++++++++++ pkg/vm/stack/stackitem.go | 12 +++ pkg/vm/stack/test_helper.go | 12 +++ 9 files changed, 393 insertions(+), 1 deletion(-) create mode 100644 pkg/vm/stack/map.go create mode 100644 pkg/vm/stack/map_test.go diff --git a/pkg/vm/stack/Int.go b/pkg/vm/stack/Int.go index 3226904ee..08e800e36 100644 --- a/pkg/vm/stack/Int.go +++ b/pkg/vm/stack/Int.go @@ -1,6 +1,9 @@ package stack -import "math/big" +import ( + "fmt" + "math/big" +) // Int represents an integer on the stack type Int struct { @@ -125,3 +128,9 @@ func (i *Int) Lt(s *Int) bool { func (i *Int) Gt(s *Int) bool { return i.Value().Cmp(s.Value()) == 1 } + +// Hash overrides the default abstract hash method. +func (i *Int) Hash() (string, error) { + data := fmt.Sprintf("%T %v", i, i.Value()) + return KeyGenerator([]byte(data)) +} diff --git a/pkg/vm/stack/array.go b/pkg/vm/stack/array.go index 96fe876a4..c11730b1d 100644 --- a/pkg/vm/stack/array.go +++ b/pkg/vm/stack/array.go @@ -1,5 +1,9 @@ package stack +import ( + "fmt" +) + // Array represents an Array of stackItems on the stack type Array struct { *abstractItem @@ -11,3 +15,22 @@ type Array struct { func (a *Array) Array() (*Array, error) { return a, nil } + +//Value returns the underlying Array's value +func (a *Array) Value() []Item { + return a.val +} + +// NewArray returns a new Array. +func NewArray(val []Item) *Array { + return &Array{ + &abstractItem{}, + val, + } +} + +// Hash overrides the default abstract hash method. +func (a *Array) Hash() (string, error) { + data := fmt.Sprintf("%T %v", a, a.Value()) + return KeyGenerator([]byte(data)) +} diff --git a/pkg/vm/stack/boolean.go b/pkg/vm/stack/boolean.go index 5a5a93207..5dc1e6e65 100644 --- a/pkg/vm/stack/boolean.go +++ b/pkg/vm/stack/boolean.go @@ -1,5 +1,9 @@ package stack +import ( + "fmt" +) + // Boolean represents a boolean value on the stack type Boolean struct { *abstractItem @@ -44,3 +48,9 @@ func (b *Boolean) Or(a *Boolean) *Boolean { c := b.Value() || a.Value() return NewBoolean(c) } + +// Hash overrides the default abstract hash method. +func (b *Boolean) Hash() (string, error) { + data := fmt.Sprintf("%T %v", b, b.Value()) + return KeyGenerator([]byte(data)) +} diff --git a/pkg/vm/stack/bytearray.go b/pkg/vm/stack/bytearray.go index 7d1c3c818..2b9c7f69f 100644 --- a/pkg/vm/stack/bytearray.go +++ b/pkg/vm/stack/bytearray.go @@ -3,6 +3,7 @@ package stack import ( "bytes" "errors" + "fmt" "math/big" "strconv" ) @@ -69,3 +70,14 @@ func reverse(b []byte) []byte { return dest } + +//Value returns the underlying ByteArray's value. +func (ba *ByteArray) Value() []byte { + return ba.val +} + +// Hash overrides the default abstract hash method. +func (ba *ByteArray) Hash() (string, error) { + data := fmt.Sprintf("%T %v", ba, ba.Value()) + return KeyGenerator([]byte(data)) +} diff --git a/pkg/vm/stack/context.go b/pkg/vm/stack/context.go index d381d74cb..0b8ed8bd2 100644 --- a/pkg/vm/stack/context.go +++ b/pkg/vm/stack/context.go @@ -3,6 +3,7 @@ package stack import ( "encoding/binary" "errors" + "fmt" ) // Context represent the current execution context of the VM. @@ -150,3 +151,9 @@ func (c *Context) readVarBytes() ([]byte, error) { } return c.ReadBytes(int(n)) } + +// Hash overrides the default abstract hash method. +func (c *Context) Hash() (string, error) { + data := c.String() + fmt.Sprintf(" %v-%v-%v-%v-%v", c.ip, c.prog, c.breakPoints, c.Estack, c.Astack) + return KeyGenerator([]byte(data)) +} diff --git a/pkg/vm/stack/map.go b/pkg/vm/stack/map.go new file mode 100644 index 000000000..b8e462c71 --- /dev/null +++ b/pkg/vm/stack/map.go @@ -0,0 +1,166 @@ +package stack + +import ( + "errors" + "fmt" + "sort" + + "github.com/CityOfZion/neo-go/pkg/crypto/hash" +) + +// Map represents a map of key, value pair on the stack. +// Both key and value are stack Items. +type Map struct { + *abstractItem + val map[Item]Item +} + +// NewMap returns a Map stack Item given +// a map whose keys and values are stack Items. +func NewMap(val map[Item]Item) (*Map, error) { + return &Map{ + abstractItem: &abstractItem{}, + val: val, + }, nil +} + +// Map will overwrite the default implementation +// to allow go to cast this item as an Map. +func (m *Map) Map() (*Map, error) { + return m, nil +} + +// Boolean overrides the default Boolean method +// to convert an Map into a Boolean StackItem +func (m *Map) Boolean() (*Boolean, error) { + return NewBoolean(true), nil +} + +// ContainsKey returns a boolean whose value is true +// iff the underlying map value contains the Item i +// as a key. +func (m *Map) ContainsKey(key Item) (*Boolean, error) { + for k := range m.Value() { + if ok, err := CompareHash(k, key); err != nil { + return nil, err + } else if ok.Value() == true { + return ok, nil + } + + } + return NewBoolean(false), nil +} + +// Value returns the underlying map's value +func (m *Map) Value() map[Item]Item { + return m.val +} + +// Remove removes the Item i from the +// underlying map's value. +func (m *Map) Remove(key Item) error { + var d Item + for k := range m.Value() { + if ok, err := CompareHash(k, key); err != nil { + return err + } else if ok.Value() == true { + d = k + } + + } + if d != nil { + delete(m.Value(), d) + } + return nil +} + +// Add inserts a new key, value pair of Items into +// the underlying map's value. +func (m *Map) Add(key Item, value Item) error { + for k := range m.Value() { + if ok, err := CompareHash(k, key); err != nil { + return err + } else if ok.Value() == true { + return errors.New("try to insert duplicate key! ") + } + } + m.Value()[key] = value + return nil +} + +// ValueOfKey tries to get the value of the key Item +// from the map's underlying value. +func (m *Map) ValueOfKey(key Item) (Item, error) { + for k, v := range m.Value() { + if ok, err := CompareHash(k, key); err != nil { + return nil, err + } else if ok.Value() == true { + return v, nil + } + + } + return nil, nil + +} + +// Clear empties the the underlying map's value. +func (m *Map) Clear() { + m.val = map[Item]Item{} +} + +// CompareHash compare the the Hashes of two items. +// If they are equal it returns a true boolean. Otherwise +// it returns false boolean. Item whose hashes are equal are +// to be considered equal. +func CompareHash(i1 Item, i2 Item) (*Boolean, error) { + hash1, err := i1.Hash() + if err != nil { + return nil, err + } + hash2, err := i2.Hash() + if err != nil { + return nil, err + } + if hash1 == hash2 { + return NewBoolean(true), nil + } + + return NewBoolean(false), nil +} + +// Hash overrides the default abstract hash method. +func (m *Map) Hash() (string, error) { + var hashSlice sort.StringSlice = []string{} + var data = fmt.Sprintf("%T ", m) + + for k, v := range m.Value() { + hk, err := k.Hash() + if err != nil { + return "", err + } + hv, err := v.Hash() + + if err != nil { + return "", err + } + + hashSlice = append(hashSlice, hk) + hashSlice = append(hashSlice, hv) + } + hashSlice.Sort() + + for _, h := range hashSlice { + data += h + } + + return KeyGenerator([]byte(data)) +} + +// KeyGenerator hashes a byte slice to obtain a unique identifier. +func KeyGenerator(data []byte) (string, error) { + h, err := hash.Sha256([]byte(data)) + if err != nil { + return "", err + } + return h.String(), nil +} diff --git a/pkg/vm/stack/map_test.go b/pkg/vm/stack/map_test.go new file mode 100644 index 000000000..2c2091dc4 --- /dev/null +++ b/pkg/vm/stack/map_test.go @@ -0,0 +1,141 @@ +package stack + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMap(t *testing.T) { + // define Map m for testing + var a Item = testMakeStackInt(t, 10) + var b Item = NewBoolean(true) + var c Item = NewByteArray([]byte{1, 2, 34}) + var d Item = testMakeStackMap(t, map[Item]Item{ + a: c, + b: a, + }) + var e = NewContext([]byte{1, 2, 3, 4}) + var f = NewArray([]Item{a, b}) + + val := map[Item]Item{ + a: c, + b: a, + c: b, + d: a, + e: d, + f: e, + } + m := testMakeStackMap(t, val) + + // test ValueOfKey + valueA, _ := m.ValueOfKey(testMakeStackInt(t, 10)) + assert.Equal(t, c, valueA) + + valueB, _ := m.ValueOfKey(b) + assert.Equal(t, a, valueB) + + valueC, _ := m.ValueOfKey(NewByteArray([]byte{1, 2, 34})) + assert.Equal(t, b, valueC) + + valueD, _ := m.ValueOfKey(testMakeStackMap(t, map[Item]Item{ + b: a, + a: c, + })) + assert.Equal(t, a, valueD) + + valueE, _ := m.ValueOfKey(NewContext([]byte{1, 2, 3, 4})) + assert.Equal(t, d, valueE) + + valueF, _ := m.ValueOfKey(NewArray([]Item{a, b})) + assert.Equal(t, e, valueF) + + valueX, _ := m.ValueOfKey(NewByteArray([]byte{1, 2, 35})) + assert.NotEqual(t, b, valueX) + + checkA, err := m.ContainsKey(a) + assert.Nil(t, err) + assert.Equal(t, true, checkA.Value()) + + //test ContainsKey + checkB, err := m.ContainsKey(b) + assert.Nil(t, err) + assert.Equal(t, true, checkB.Value()) + + checkC, err := m.ContainsKey(c) + assert.Nil(t, err) + assert.Equal(t, true, checkC.Value()) + + checkD, err := m.ContainsKey(d) + assert.Nil(t, err) + assert.Equal(t, true, checkD.Value()) + + checkE, err := m.ContainsKey(e) + assert.Nil(t, err) + assert.Equal(t, true, checkE.Value()) + + //test CompareHash + val2 := map[Item]Item{ + f: e, + e: d, + d: a, + c: b, + b: a, + a: c, + } + m2 := testMakeStackMap(t, val2) + checkMap, err := CompareHash(m, m2) + assert.Nil(t, err) + assert.Equal(t, true, checkMap.Value()) + + checkBoolean, err := CompareHash(b, NewBoolean(true)) + assert.Nil(t, err) + assert.Equal(t, true, checkBoolean.Value()) + + checkByteArray, err := CompareHash(c, NewByteArray([]byte{1, 2, 34})) + assert.Nil(t, err) + assert.Equal(t, true, checkByteArray.Value()) + + checkContext, err := CompareHash(e, NewContext([]byte{1, 2, 3, 4})) + assert.Nil(t, err) + assert.Equal(t, true, checkContext.Value()) + + checkArray, err := CompareHash(f, NewArray([]Item{a, b})) + assert.Nil(t, err) + assert.Equal(t, true, checkArray.Value()) +} + +func TestMapAdd(t *testing.T) { + var a Item = testMakeStackInt(t, 10) + var b Item = NewBoolean(true) + var m = testMakeStackMap(t, map[Item]Item{}) + + err := m.Add(a, a) + assert.Nil(t, err) + err = m.Add(b, a) + assert.Nil(t, err) + + assert.Equal(t, 2, len(m.Value())) + + expected := testMakeStackMap(t, map[Item]Item{b: a, a: a}) + check, err := CompareHash(m, expected) + assert.Nil(t, err) + assert.Equal(t, true, check.Value()) + +} + +func TestMapRemove(t *testing.T) { + var a Item = testMakeStackInt(t, 10) + var b Item = NewBoolean(true) + var m = testMakeStackMap(t, map[Item]Item{b: a, a: a}) + + err := m.Remove(a) + assert.Nil(t, err) + assert.Equal(t, 1, len(m.Value())) + + expected := testMakeStackMap(t, map[Item]Item{b: a}) + check, err := CompareHash(m, expected) + assert.Nil(t, err) + assert.Equal(t, true, check.Value()) + +} diff --git a/pkg/vm/stack/stackitem.go b/pkg/vm/stack/stackitem.go index beed13363..d9990adcb 100644 --- a/pkg/vm/stack/stackitem.go +++ b/pkg/vm/stack/stackitem.go @@ -11,6 +11,8 @@ type Item interface { ByteArray() (*ByteArray, error) Array() (*Array, error) Context() (*Context, error) + Map() (*Map, error) + Hash() (string, error) } // Represents an `abstract` stack item @@ -47,3 +49,13 @@ func (a *abstractItem) Array() (*Array, error) { func (a *abstractItem) Context() (*Context, error) { return nil, errors.New("This stack item is not of type context") } + +// Context is the default implementation for a stackItem +// Implements Item interface +func (a *abstractItem) Map() (*Map, error) { + return nil, errors.New("This stack item is not a map") +} + +func (a *abstractItem) Hash() (string, error) { + return "", errors.New("This stack item need to override the Hash Method") +} diff --git a/pkg/vm/stack/test_helper.go b/pkg/vm/stack/test_helper.go index 15c6f87de..b2615141e 100644 --- a/pkg/vm/stack/test_helper.go +++ b/pkg/vm/stack/test_helper.go @@ -42,3 +42,15 @@ func testReadInt64(data []byte) int64 { binary.Read(buf, binary.LittleEndian, &ret) return ret } + +func testMakeStackMap(t *testing.T, m map[Item]Item) *Map { + a, err := NewMap(m) + assert.Nil(t, err) + return a +} + +func testArray(t *testing.T, m map[Item]Item) *Map { + a, err := NewMap(m) + assert.Nil(t, err) + return a +} From 51f835172345ce15fab7410ef288c1a415ea21c1 Mon Sep 17 00:00:00 2001 From: DauTT Date: Fri, 5 Apr 2019 21:13:23 +0200 Subject: [PATCH 4/4] Used consistently assert.Nil for checking absence of error --- pkg/vm/vm_ops_maths_test.go | 209 ++++++++++++------------------------ 1 file changed, 67 insertions(+), 142 deletions(-) diff --git a/pkg/vm/vm_ops_maths_test.go b/pkg/vm/vm_ops_maths_test.go index d685d6cf0..14e8c88a3 100644 --- a/pkg/vm/vm_ops_maths_test.go +++ b/pkg/vm/vm_ops_maths_test.go @@ -13,9 +13,7 @@ func TestIncOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a) @@ -26,9 +24,7 @@ func TestIncOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(21), item.Value().Int64()) } @@ -38,9 +34,7 @@ func TestDecOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a) @@ -51,9 +45,7 @@ func TestDecOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(19), item.Value().Int64()) } @@ -63,13 +55,10 @@ func TestAddOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(23)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -80,9 +69,7 @@ func TestAddOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(43), item.Value().Int64()) @@ -93,13 +80,10 @@ func TestSubOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(30)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(40)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -110,9 +94,7 @@ func TestSubOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(-10), item.Value().Int64()) @@ -123,13 +105,10 @@ func TestDivOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(10)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(4)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -140,9 +119,7 @@ func TestDivOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(2), item.Value().Int64()) } @@ -152,13 +129,10 @@ func TestModOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(15)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(4)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -169,9 +143,7 @@ func TestModOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(3), item.Value().Int64()) } @@ -181,9 +153,7 @@ func TestNzOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a) @@ -194,9 +164,7 @@ func TestNzOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, true, item.Value()) } @@ -206,13 +174,10 @@ func TestMulOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -223,9 +188,7 @@ func TestMulOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(400), item.Value().Int64()) } @@ -235,9 +198,7 @@ func TestAbsOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(-20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a) @@ -248,9 +209,7 @@ func TestAbsOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(20), item.Value().Int64()) } @@ -270,9 +229,7 @@ func TestNotOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, true, item.Value()) } @@ -282,13 +239,10 @@ func TestNumEqual(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(6)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(6)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -299,9 +253,7 @@ func TestNumEqual(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, true, item.Value()) } @@ -311,13 +263,10 @@ func TestNumNotEqual(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(5)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(6)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -328,9 +277,7 @@ func TestNumNotEqual(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, true, item.Value()) } @@ -340,9 +287,7 @@ func TestSignOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(-20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a) @@ -353,9 +298,7 @@ func TestSignOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(-1), item.Value().Int64()) } @@ -365,9 +308,7 @@ func TestNegateOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(-20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a) @@ -378,9 +319,7 @@ func TestNegateOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(20), item.Value().Int64()) } @@ -448,13 +387,10 @@ func TestShlOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(2)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(3)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -470,9 +406,7 @@ func TestShlOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(16), item.Value().Int64()) } @@ -482,13 +416,10 @@ func TestShrOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(10)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(2)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -504,9 +435,7 @@ func TestShrOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(2), item.Value().Int64()) } @@ -527,9 +456,7 @@ func TestBoolAndOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, true, item.Value()) } @@ -550,9 +477,7 @@ func TestBoolOrOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, true, item.Value()) } @@ -562,10 +487,10 @@ func TestLtOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(10)) - assert.NoError(t, err) + assert.Nil(t, err) b, err := stack.NewInt(big.NewInt(2)) - assert.NoError(t, err) + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -581,7 +506,7 @@ func TestLtOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - assert.NoError(t, err) + assert.Nil(t, err) assert.Equal(t, false, item.Value()) } @@ -591,10 +516,10 @@ func TestGtOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(10)) - assert.NoError(t, err) + assert.Nil(t, err) b, err := stack.NewInt(big.NewInt(2)) - assert.NoError(t, err) + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -610,7 +535,7 @@ func TestGtOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - assert.NoError(t, err) + assert.Nil(t, err) assert.Equal(t, true, item.Value()) } @@ -620,10 +545,10 @@ func TestMinOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(10)) - assert.NoError(t, err) + assert.Nil(t, err) b, err := stack.NewInt(big.NewInt(2)) - assert.NoError(t, err) + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -634,7 +559,7 @@ func TestMinOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - assert.NoError(t, err) + assert.Nil(t, err) assert.Equal(t, int64(2), item.Value().Int64()) } @@ -644,10 +569,10 @@ func TestMaxOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(10)) - assert.NoError(t, err) + assert.Nil(t, err) b, err := stack.NewInt(big.NewInt(2)) - assert.NoError(t, err) + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -658,7 +583,7 @@ func TestMaxOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - assert.NoError(t, err) + assert.Nil(t, err) assert.Equal(t, int64(10), item.Value().Int64()) } @@ -668,13 +593,13 @@ func TestWithinOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(5)) - assert.NoError(t, err) + assert.Nil(t, err) b, err := stack.NewInt(big.NewInt(2)) - assert.NoError(t, err) + assert.Nil(t, err) c, err := stack.NewInt(big.NewInt(10)) - assert.NoError(t, err) + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b).Push(c) @@ -692,7 +617,7 @@ func TestWithinOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - assert.NoError(t, err) + assert.Nil(t, err) assert.Equal(t, true, item.Value()) }