From 14e0ab48dd471c2bf8e4465ab90de0524ac5161c Mon Sep 17 00:00:00 2001 From: dauTT <30392990+dauTT@users.noreply.github.com> Date: Thu, 28 Mar 2019 19:30:36 +0100 Subject: [PATCH] VM: Implemented SIGN, NEGATE opcode (#232) * Implemented SIGN, NEGATE opcode --- pkg/vm/vm_ops.go | 2 ++ pkg/vm/vm_ops_maths.go | 45 +++++++++++++++++++++++++++++++-- pkg/vm/vm_ops_maths_test.go | 50 +++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/pkg/vm/vm_ops.go b/pkg/vm/vm_ops.go index 016c96389..9ba44ccbd 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.SIGN: Sign, + stack.NEGATE: Negate, stack.ADD: Add, stack.SUB: Sub, stack.PUSHBYTES1: PushNBytes, diff --git a/pkg/vm/vm_ops_maths.go b/pkg/vm/vm_ops_maths.go index 77a4c2622..e15e25c3e 100644 --- a/pkg/vm/vm_ops_maths.go +++ b/pkg/vm/vm_ops_maths.go @@ -46,7 +46,7 @@ func Sub(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rst // Inc increments the stack Item's value by 1. // Returns an error if the item cannot be casted to an integer -// or if 1 cannot be added to the item +// or if 1 cannot be added to the item. func Inc(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { i, err := ctx.Estack.PopInt() @@ -71,7 +71,7 @@ func Inc(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rst // Dec decrements the stack Item's value by 1. // Returns an error if the item cannot be casted to an integer -// or if 1 cannot be subtracted to the item +// or if 1 cannot be subtracted to the item. func Dec(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { i, err := ctx.Estack.PopInt() @@ -94,6 +94,47 @@ func Dec(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rst return NONE, nil } +// Sign puts the sign of the top stack Item on top of the stack. +// If value is negative, put -1; +// If positive, put 1; +// If value is zero, put 0. +func Sign(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 + } + + s := int64(i.Value().Sign()) + sign, err := stack.NewInt(big.NewInt(s)) + if err != nil { + return FAULT, err + } + + ctx.Estack.Push(sign) + + return NONE, nil +} + +// Negate flips the sign of the stack Item. +func Negate(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 + } + + a := big.NewInt(0).Neg(i.Value()) + b, err := stack.NewInt(a) + if err != nil { + return FAULT, err + } + + ctx.Estack.Push(b) + + return NONE, nil +} + func popTwoIntegers(ctx *stack.Context) (*stack.Int, *stack.Int, error) { operandA, err := ctx.Estack.PopInt() if err != nil { diff --git a/pkg/vm/vm_ops_maths_test.go b/pkg/vm/vm_ops_maths_test.go index f50c27916..4324aec97 100644 --- a/pkg/vm/vm_ops_maths_test.go +++ b/pkg/vm/vm_ops_maths_test.go @@ -117,3 +117,53 @@ func TestSubOp(t *testing.T) { assert.Equal(t, int64(-10), item.Value().Int64()) } + +func TestSignOp(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.SIGN, 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(-1), item.Value().Int64()) +} + +func TestNegateOp(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.NEGATE, 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(20), item.Value().Int64()) +}