diff --git a/pkg/vm/stack/Int.go b/pkg/vm/stack/Int.go index ebd83cea1..52e6240d4 100644 --- a/pkg/vm/stack/Int.go +++ b/pkg/vm/stack/Int.go @@ -46,6 +46,13 @@ func (i *Int) Mul(s *Int) (*Int, error) { }, nil } +// Div will divide one stackInteger by an other. +func (i *Int) Div(s *Int) (*Int, error) { + return &Int{ + val: new(big.Int).Div(i.val, s.val), + }, nil +} + // Mod will take the mod of two stackIntegers together func (i *Int) Mod(s *Int) (*Int, error) { return &Int{ diff --git a/pkg/vm/vm_ops.go b/pkg/vm/vm_ops.go index 5b199baa1..238d300e0 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.DIV: Div, + stack.MOD: Mod, stack.NZ: Nz, stack.MUL: Mul, stack.ABS: Abs, diff --git a/pkg/vm/vm_ops_maths.go b/pkg/vm/vm_ops_maths.go index 65d6b4af1..345092eea 100644 --- a/pkg/vm/vm_ops_maths.go +++ b/pkg/vm/vm_ops_maths.go @@ -94,6 +94,44 @@ func Dec(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rst return NONE, nil } +// Div divides one stack Item by an other. +// Returns an error if either items cannot be casted to an integer +// or if the division of the integers cannot be performed. +func Div(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 := operandB.Div(operandA) + if err != nil { + return FAULT, err + } + + ctx.Estack.Push(res) + + return NONE, nil +} + +// Mod returns the mod of two stack Items. +// Returns an error if either items cannot be casted to an integer +// or if the mode of the integers cannot be performed. +func Mod(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 := operandB.Mod(operandA) + if err != nil { + return FAULT, err + } + + ctx.Estack.Push(res) + + 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. diff --git a/pkg/vm/vm_ops_maths_test.go b/pkg/vm/vm_ops_maths_test.go index 700f17bcb..613ddefea 100644 --- a/pkg/vm/vm_ops_maths_test.go +++ b/pkg/vm/vm_ops_maths_test.go @@ -118,6 +118,64 @@ func TestSubOp(t *testing.T) { } +func TestDivOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(10)) + if err != nil { + t.Fail() + } + b, err := stack.NewInt(big.NewInt(4)) + if err != nil { + t.Fail() + } + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a).Push(b) + + v.executeOp(stack.DIV, 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(2), item.Value().Int64()) +} + +func TestModOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(15)) + if err != nil { + t.Fail() + } + b, err := stack.NewInt(big.NewInt(4)) + if err != nil { + t.Fail() + } + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a).Push(b) + + v.executeOp(stack.MOD, 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(3), item.Value().Int64()) +} + func TestNzOp(t *testing.T) { v := VM{} @@ -141,7 +199,6 @@ func TestNzOp(t *testing.T) { } assert.Equal(t, true, item.Value()) - } func TestMulOp(t *testing.T) { @@ -171,7 +228,6 @@ func TestMulOp(t *testing.T) { } assert.Equal(t, int64(400), item.Value().Int64()) - } func TestAbsOp(t *testing.T) {