diff --git a/pkg/vm/stack/Int.go b/pkg/vm/stack/Int.go index ac9a4cdba..ebd83cea1 100644 --- a/pkg/vm/stack/Int.go +++ b/pkg/vm/stack/Int.go @@ -92,3 +92,15 @@ func (i *Int) Boolean() (*Boolean, error) { func (i *Int) Value() *big.Int { return i.val } + +// Abs returns a stack integer whose underlying value is +// the absolute value of the original stack integer. +func (i *Int) Abs() (*Int, error) { + a := big.NewInt(0).Abs(i.Value()) + b, err := NewInt(a) + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/pkg/vm/stack/boolean.go b/pkg/vm/stack/boolean.go index 66e3647e5..93fabd84e 100644 --- a/pkg/vm/stack/boolean.go +++ b/pkg/vm/stack/boolean.go @@ -24,3 +24,9 @@ func (b *Boolean) Boolean() (*Boolean, error) { func (b *Boolean) Value() bool { return b.val } + +// Not returns a Boolean whose underlying value is flipped. +// If the value is True, it is flipped to False and viceversa +func (b *Boolean) Not() *Boolean { + return NewBoolean(!b.Value()) +} diff --git a/pkg/vm/stack/stack.go b/pkg/vm/stack/stack.go index 8d1ac5b78..c832a9f79 100644 --- a/pkg/vm/stack/stack.go +++ b/pkg/vm/stack/stack.go @@ -148,3 +148,13 @@ func (ras *RandomAccess) PopByteArray() (*ByteArray, error) { } return item.ByteArray() } + +// PopBoolean will remove the last stack item that was added +// and cast it to a Boolean. +func (ras *RandomAccess) PopBoolean() (*Boolean, error) { + item, err := ras.Pop() + if err != nil { + return nil, err + } + return item.Boolean() +} diff --git a/pkg/vm/vm_ops.go b/pkg/vm/vm_ops.go index 9ba44ccbd..135936e05 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.ABS: Abs, + stack.NOT: Not, stack.SIGN: Sign, stack.NEGATE: Negate, stack.ADD: Add, diff --git a/pkg/vm/vm_ops_maths.go b/pkg/vm/vm_ops_maths.go index e15e25c3e..cbd82d670 100644 --- a/pkg/vm/vm_ops_maths.go +++ b/pkg/vm/vm_ops_maths.go @@ -94,6 +94,39 @@ func Dec(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rst 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) { + + i, err := ctx.Estack.PopInt() + if err != nil { + return FAULT, err + } + + a, err := i.Abs() + if err != nil { + return FAULT, err + } + + ctx.Estack.Push(a) + + return NONE, nil +} + +// Not flips the stack Item's value. +// If the value is True, it is flipped to False and viceversa. +func Not(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + b, err := ctx.Estack.PopBoolean() + if err != nil { + return FAULT, err + } + + ctx.Estack.Push(b.Not()) + + 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; diff --git a/pkg/vm/vm_ops_maths_test.go b/pkg/vm/vm_ops_maths_test.go index 4324aec97..68f7ae860 100644 --- a/pkg/vm/vm_ops_maths_test.go +++ b/pkg/vm/vm_ops_maths_test.go @@ -118,6 +118,53 @@ func TestSubOp(t *testing.T) { } +func TestAbsOp(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.ABS, 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()) +} + +func TestNotOp(t *testing.T) { + + v := VM{} + + b := stack.NewBoolean(false) + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(b) + + v.executeOp(stack.NOT, 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 TestSignOp(t *testing.T) { v := VM{}