diff --git a/pkg/vm/vm_ops.go b/pkg/vm/vm_ops.go index 238d300e0..cef46a199 100644 --- a/pkg/vm/vm_ops.go +++ b/pkg/vm/vm_ops.go @@ -5,6 +5,8 @@ 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.SHR: Shr, + stack.SHL: Shl, stack.INC: Inc, stack.DEC: Dec, stack.DIV: Div, diff --git a/pkg/vm/vm_ops_maths.go b/pkg/vm/vm_ops_maths.go index 345092eea..5cbe0552a 100644 --- a/pkg/vm/vm_ops_maths.go +++ b/pkg/vm/vm_ops_maths.go @@ -260,6 +260,46 @@ func popTwoIntegers(ctx *stack.Context) (*stack.Int, *stack.Int, error) { 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 +// or if the left shift operation cannot per performed with the two integer's value. +func Shl(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + a, b, err := popTwoIntegers(ctx) + if err != nil { + return FAULT, err + } + res, err := b.Lsh(a) + if err != nil { + return FAULT, err + } + + ctx.Estack.Push(res) + + return NONE, nil +} + +// Shr 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 right by a's value bits. +// Returns an error if either items cannot be casted to an integer +// or if the right shift operation cannot per performed with the two integer's value. +func Shr(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + a, b, err := popTwoIntegers(ctx) + if err != nil { + return FAULT, err + } + res, err := b.Rsh(a) + if err != nil { + return FAULT, err + } + + ctx.Estack.Push(res) + + return NONE, 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 613ddefea..b703751be 100644 --- a/pkg/vm/vm_ops_maths_test.go +++ b/pkg/vm/vm_ops_maths_test.go @@ -143,7 +143,7 @@ func TestDivOp(t *testing.T) { if err != nil { t.Fail() } - + assert.Equal(t, int64(2), item.Value().Int64()) } @@ -326,3 +326,71 @@ func TestNegateOp(t *testing.T) { assert.Equal(t, int64(20), item.Value().Int64()) } + +func TestShlOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(2)) + if err != nil { + t.Fail() + } + b, err := stack.NewInt(big.NewInt(3)) + if err != nil { + t.Fail() + } + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a).Push(b) + + // b is the first item pop. + // a is the second item pop. + // we perform a.Lsh(b) and place + // the result on top of the evaluation + // stack + v.executeOp(stack.SHL, 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(16), item.Value().Int64()) +} + +func TestShrOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(10)) + if err != nil { + t.Fail() + } + b, err := stack.NewInt(big.NewInt(2)) + if err != nil { + t.Fail() + } + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a).Push(b) + + // b is the first item pop. + // a is the second item pop. + // we perform a.Rsh(b) and place + // the result on top of the evaluation + // stack + v.executeOp(stack.SHR, 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()) +}