From 139b770712246e9a630c9da950d5fbcf0395e73d Mon Sep 17 00:00:00 2001 From: dauTT <30392990+dauTT@users.noreply.github.com> Date: Thu, 28 Mar 2019 20:47:47 +0100 Subject: [PATCH] Implemented NZ, MUL opcode (#235) --- pkg/vm/vm_ops.go | 2 ++ pkg/vm/vm_ops_maths.go | 41 +++++++++++++++++++++++++++ pkg/vm/vm_ops_maths_test.go | 56 +++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/pkg/vm/vm_ops.go b/pkg/vm/vm_ops.go index 135936e05..5b199baa1 100644 --- a/pkg/vm/vm_ops.go +++ b/pkg/vm/vm_ops.go @@ -7,6 +7,8 @@ type stackInfo func(op stack.Instruction, ctx *stack.Context, istack *stack.Invo var opFunc = map[stack.Instruction]stackInfo{ stack.INC: Inc, stack.DEC: Dec, + stack.NZ: Nz, + stack.MUL: Mul, stack.ABS: Abs, stack.NOT: Not, stack.SIGN: Sign, diff --git a/pkg/vm/vm_ops_maths.go b/pkg/vm/vm_ops_maths.go index cbd82d670..65d6b4af1 100644 --- a/pkg/vm/vm_ops_maths.go +++ b/pkg/vm/vm_ops_maths.go @@ -94,6 +94,47 @@ func Dec(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rst return NONE, nil } +// Nz pops an integer from the stack. +// Then pushes a boolean to the stack which evaluates to true +// iff the integer was not zero. +// Returns an error if the popped item cannot be casted to an integer +// or if we cannot create a boolean. +func Nz(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + i, err := ctx.Estack.PopInt() + if err != nil { + return FAULT, err + } + + b, err := i.Boolean() + if err != nil { + return FAULT, err + } + + ctx.Estack.Push(b) + + return NONE, nil +} + +// Mul multiplies two stack Items together. +// Returns an error if either items cannot be casted to an integer +// or if integers cannot be multiplied together. +func Mul(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, err := operandA.Mul(operandB) + if err != nil { + return FAULT, err + } + + 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) { diff --git a/pkg/vm/vm_ops_maths_test.go b/pkg/vm/vm_ops_maths_test.go index 68f7ae860..700f17bcb 100644 --- a/pkg/vm/vm_ops_maths_test.go +++ b/pkg/vm/vm_ops_maths_test.go @@ -118,6 +118,62 @@ func TestSubOp(t *testing.T) { } +func TestNzOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(20)) + if err != nil { + t.Fail() + } + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a) + + v.executeOp(stack.NZ, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.PopBoolean() + if err != nil { + t.Fail() + } + + assert.Equal(t, true, item.Value()) + +} + +func TestMulOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(20)) + if err != nil { + t.Fail() + } + b, err := stack.NewInt(big.NewInt(20)) + if err != nil { + t.Fail() + } + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a).Push(b) + + v.executeOp(stack.MUL, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.PopInt() + if err != nil { + t.Fail() + } + + assert.Equal(t, int64(400), item.Value().Int64()) + +} + func TestAbsOp(t *testing.T) { v := VM{}