From bcc8234155e6c18d5fc91f38d92083b768660cc0 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Fri, 6 Sep 2019 19:00:04 +0300 Subject: [PATCH] vm: implement Array <-> Struct conversion Reference VM implementation supports convertation from Struct to Array via NEWARRAY and vice versa. https://github.com/neo-project/neo-vm/pull/91 --- pkg/vm/vm.go | 32 +++++++++++++++---- pkg/vm/vm_test.go | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 6 deletions(-) diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index e8d33afca..fae084ce3 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -569,14 +569,34 @@ func (v *VM) execute(ctx *Context, op Instruction) { // Object operations. case NEWARRAY: - n := v.estack.Pop().BigInt().Int64() - items := make([]StackItem, n) - v.estack.PushVal(&ArrayItem{items}) + item := v.estack.Pop() + switch t := item.value.(type) { + case *BigIntegerItem: + n := t.value.Int64() + items := make([]StackItem, n) + v.estack.PushVal(&ArrayItem{items}) + case *StructItem: + v.estack.PushVal(&ArrayItem{t.value}) + case *ArrayItem: + v.estack.PushVal(t) + default: + panic("NEWARRAY: invalid operand") + } case NEWSTRUCT: - n := v.estack.Pop().BigInt().Int64() - items := make([]StackItem, n) - v.estack.PushVal(&StructItem{items}) + item := v.estack.Pop() + switch t := item.value.(type) { + case *BigIntegerItem: + n := t.value.Int64() + items := make([]StackItem, n) + v.estack.PushVal(&StructItem{items}) + case *ArrayItem: + v.estack.PushVal(&StructItem{t.value}) + case *StructItem: + v.estack.PushVal(t) + default: + panic("NEWSTRUCT: invalid operand") + } case APPEND: itemElem := v.estack.Pop() diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index 61de7a16d..5324581e4 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -216,6 +216,86 @@ func TestINC(t *testing.T) { assert.Equal(t, big.NewInt(2), vm.estack.Pop().BigInt()) } +func TestNEWARRAYInteger(t *testing.T) { + prog := makeProgram(NEWARRAY) + vm := load(prog) + vm.estack.PushVal(1) + vm.Run() + assert.Equal(t, false, vm.state.HasFlag(faultState)) + assert.Equal(t, 1, vm.estack.Len()) + assert.Equal(t, &ArrayItem{make([]StackItem, 1)}, vm.estack.Pop().value) +} + +func TestNEWARRAYStruct(t *testing.T) { + prog := makeProgram(NEWARRAY) + vm := load(prog) + arr := []StackItem{makeStackItem(42)} + vm.estack.Push(&Element{value: &StructItem{arr}}) + vm.Run() + assert.Equal(t, false, vm.state.HasFlag(faultState)) + assert.Equal(t, 1, vm.estack.Len()) + assert.Equal(t, &ArrayItem{arr}, vm.estack.Pop().value) +} + +func TestNEWARRAYArray(t *testing.T) { + prog := makeProgram(NEWARRAY) + vm := load(prog) + arr := []StackItem{makeStackItem(42)} + vm.estack.Push(&Element{value: &ArrayItem{arr}}) + vm.Run() + assert.Equal(t, false, vm.state.HasFlag(faultState)) + assert.Equal(t, 1, vm.estack.Len()) + assert.Equal(t, &ArrayItem{arr}, vm.estack.Pop().value) +} + +func TestNEWARRAYWrongType(t *testing.T) { + prog := makeProgram(NEWARRAY) + vm := load(prog) + vm.estack.Push(NewElement([]byte{})) + vm.Run() + assert.Equal(t, true, vm.state.HasFlag(faultState)) +} + +func TestNEWSTRUCTInteger(t *testing.T) { + prog := makeProgram(NEWSTRUCT) + vm := load(prog) + vm.estack.PushVal(1) + vm.Run() + assert.Equal(t, false, vm.state.HasFlag(faultState)) + assert.Equal(t, 1, vm.estack.Len()) + assert.Equal(t, &StructItem{make([]StackItem, 1)}, vm.estack.Pop().value) +} + +func TestNEWSTRUCTArray(t *testing.T) { + prog := makeProgram(NEWSTRUCT) + vm := load(prog) + arr := []StackItem{makeStackItem(42)} + vm.estack.Push(&Element{value: &ArrayItem{arr}}) + vm.Run() + assert.Equal(t, false, vm.state.HasFlag(faultState)) + assert.Equal(t, 1, vm.estack.Len()) + assert.Equal(t, &StructItem{arr}, vm.estack.Pop().value) +} + +func TestNEWSTRUCTStruct(t *testing.T) { + prog := makeProgram(NEWSTRUCT) + vm := load(prog) + arr := []StackItem{makeStackItem(42)} + vm.estack.Push(&Element{value: &StructItem{arr}}) + vm.Run() + assert.Equal(t, false, vm.state.HasFlag(faultState)) + assert.Equal(t, 1, vm.estack.Len()) + assert.Equal(t, &StructItem{arr}, vm.estack.Pop().value) +} + +func TestNEWSTRUCTWrongType(t *testing.T) { + prog := makeProgram(NEWSTRUCT) + vm := load(prog) + vm.estack.Push(NewElement([]byte{})) + vm.Run() + assert.Equal(t, true, vm.state.HasFlag(faultState)) +} + func TestAppCall(t *testing.T) { prog := []byte{byte(APPCALL)} hash := util.Uint160{}