diff --git a/pkg/vm/vm_ops.go b/pkg/vm/vm_ops.go index f2424d81a..bf9291933 100644 --- a/pkg/vm/vm_ops.go +++ b/pkg/vm/vm_ops.go @@ -2,11 +2,14 @@ package vm import "github.com/CityOfZion/neo-go/pkg/vm/stack" -var opFunc = map[stack.Instruction]func(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation) error{ +var opFunc = map[stack.Instruction]func(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation) (Vmstate, error){ stack.ADD: Add, stack.SUB: Sub, stack.PUSHBYTES1: PushNBytes, stack.PUSHBYTES75: PushNBytes, + stack.RET: RET, + stack.EQUAL: EQUAL, + stack.THROWIFNOT: THROWIFNOT, } func init() { diff --git a/pkg/vm/vm_ops_maths_test.go b/pkg/vm/vm_ops_maths_test.go index 6b0e13bbe..4964e6923 100644 --- a/pkg/vm/vm_ops_maths_test.go +++ b/pkg/vm/vm_ops_maths_test.go @@ -24,7 +24,7 @@ func TestAddOp(t *testing.T) { ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) - v.ExecuteOp(stack.ADD, ctx) + v.executeOp(stack.ADD, ctx) // Stack should have one item assert.Equal(t, 1, ctx.Estack.Len()) @@ -54,7 +54,7 @@ func TestSubOp(t *testing.T) { ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) - v.ExecuteOp(stack.SUB, ctx) + v.executeOp(stack.SUB, ctx) // Stack should have one item assert.Equal(t, 1, ctx.Estack.Len()) diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go new file mode 100644 index 000000000..db12c014c --- /dev/null +++ b/pkg/vm/vm_test.go @@ -0,0 +1,113 @@ +package vm + +import ( + "fmt" + "testing" + + "github.com/CityOfZion/neo-go/pkg/vm/stack" + "github.com/stretchr/testify/assert" +) + +func TestPushAdd(t *testing.T) { + builder := stack.NewBuilder() + + // PUSH TWO NUMBER + // ADD THEM TOGETHER + builder.EmitInt(20).EmitInt(34).EmitOpcode(stack.ADD) + + // Pass program to VM + vm := NewVM(builder.Bytes()) + + // Execute first OPCODE + // Should be PUSH(20) + state, err := vm.step() + assert.Equal(t, NONE, int(state)) + assert.Nil(t, err) + + // We should have the number 20 on stack + ok := peekTopEStackIsValue(t, vm, 20) + assert.True(t, ok) + + // Excute second OPCODE + // Should be PUSH(34) + state, err = vm.step() + assert.Equal(t, NONE, int(state)) + assert.Nil(t, err) + + // We should have the number 34 at the top of the stack + ok = peekTopEStackIsValue(t, vm, 34) + assert.True(t, ok) + + // Excute third OPCODE + // Should Add both values on the stack + state, err = vm.step() + assert.Equal(t, NONE, int(state)) + assert.Nil(t, err) + + // We should now have one value on the stack + //It should be equal to 20+34 = 54 + ok = EstackLen(t, vm, 1) + assert.True(t, ok) + ok = peekTopEStackIsValue(t, vm, 54) + assert.True(t, ok) + + // If we try to step again, we should get an error and HALT + // because we have gone over the instruction pointer + state, err = vm.step() + assert.Equal(t, HALT, int(state)) + assert.NotNil(t, err) + +} + +func TestSimpleRun(t *testing.T) { + + // Program pushes 20 and 34 to the stack + // Adds them together + // pushes 54 to the stack + // Checks if result of addition and 54 are equal + // Faults if not + + // Push(20) + // Push(34) + // Add + // Push(54) + // Equal + //THROWIFNOT + builder := stack.NewBuilder() + builder.EmitInt(20).EmitInt(34).EmitOpcode(stack.ADD) + builder.EmitInt(54).EmitOpcode(stack.EQUAL).EmitOpcode(stack.THROWIFNOT) + // Pass program to VM + vm := NewVM(builder.Bytes()) + + _, err := vm.Run() + assert.Nil(t, err) + +} + +// returns true if the value at the top of the evaluation stack is a integer +// and equals the value passed in +func peekTopEStackIsValue(t *testing.T, vm *VM, value int64) bool { + item := peakTopEstack(t, vm) + integer, err := item.Integer() + assert.Nil(t, err) + return value == integer.Value().Int64() +} + +// peaks the stack item on the top of the evaluation stack +// if the current context and returns it +func peakTopEstack(t *testing.T, vm *VM) stack.Item { + ctx, err := vm.InvocationStack.CurrentContext() + fmt.Println(err) + assert.Nil(t, err) + item, err := ctx.Estack.Peek(0) + assert.Nil(t, err) + return item +} + +// returns true if the total number of items on the evaluation stack +// is equal to value +func EstackLen(t *testing.T, vm *VM, value int) bool { + ctx, err := vm.InvocationStack.CurrentContext() + assert.Nil(t, err) + return value == ctx.Estack.Len() +}