vm: implement NEWARRAYT opcode

This commit is contained in:
Evgenii Stratonikov 2020-04-24 13:48:19 +03:00
parent d3b9aef8e2
commit 7c3d7c0261
5 changed files with 75 additions and 29 deletions

View file

@ -101,7 +101,7 @@ func (c *Context) Next() (opcode.Opcode, []byte, error) {
}
case opcode.JMP, opcode.JMPIF, opcode.JMPIFNOT, opcode.JMPEQ, opcode.JMPNE,
opcode.JMPGT, opcode.JMPGE, opcode.JMPLT, opcode.JMPLE,
opcode.CALL, opcode.ISTYPE:
opcode.CALL, opcode.ISTYPE, opcode.NEWARRAYT:
numtoread = 1
case opcode.JMPL, opcode.JMPIFL, opcode.JMPIFNOTL, opcode.JMPEQL, opcode.JMPNEL,
opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLTL, opcode.JMPLEL,

View file

@ -143,11 +143,11 @@ const (
CHECKMULTISIG Opcode = 0xAE
// Advanced data structures (arrays, structures, maps)
PACK Opcode = 0xC0
UNPACK Opcode = 0xC1
NEWARRAY0 Opcode = 0xC2
NEWARRAY Opcode = 0xC3
// NEWARRAYT Opcode = 0xC4
PACK Opcode = 0xC0
UNPACK Opcode = 0xC1
NEWARRAY0 Opcode = 0xC2
NEWARRAY Opcode = 0xC3
NEWARRAYT Opcode = 0xC4
NEWSTRUCT0 Opcode = 0xC5
NEWSTRUCT Opcode = 0xC6
NEWMAP Opcode = 0xC8

View file

@ -126,6 +126,7 @@ func _() {
_ = x[UNPACK-193]
_ = x[NEWARRAY0-194]
_ = x[NEWARRAY-195]
_ = x[NEWARRAYT-196]
_ = x[NEWSTRUCT0-197]
_ = x[NEWSTRUCT-198]
_ = x[NEWMAP-200]
@ -139,11 +140,12 @@ func _() {
_ = x[REVERSEITEMS-209]
_ = x[REMOVE-210]
_ = x[CLEARITEMS-211]
_ = x[ISTYPE-217]
_ = x[THROW-240]
_ = x[THROWIFNOT-241]
}
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLOLDPUSH1RETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPISNULLXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINSHA1SHA256HASH160HASH256CHECKSIGVERIFYCHECKMULTISIGPACKUNPACKNEWARRAY0NEWARRAYNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSTHROWTHROWIFNOT"
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLOLDPUSH1RETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPISNULLXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINSHA1SHA256HASH160HASH256CHECKSIGVERIFYCHECKMULTISIGPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISTYPETHROWTHROWIFNOT"
var _Opcode_map = map[Opcode]string{
0: _Opcode_name[0:8],
@ -262,21 +264,23 @@ var _Opcode_map = map[Opcode]string{
193: _Opcode_name[621:627],
194: _Opcode_name[627:636],
195: _Opcode_name[636:644],
197: _Opcode_name[644:654],
198: _Opcode_name[654:663],
200: _Opcode_name[663:669],
202: _Opcode_name[669:673],
203: _Opcode_name[673:679],
204: _Opcode_name[679:683],
205: _Opcode_name[683:689],
206: _Opcode_name[689:697],
207: _Opcode_name[697:703],
208: _Opcode_name[703:710],
209: _Opcode_name[710:722],
210: _Opcode_name[722:728],
211: _Opcode_name[728:738],
240: _Opcode_name[738:743],
241: _Opcode_name[743:753],
196: _Opcode_name[644:653],
197: _Opcode_name[653:663],
198: _Opcode_name[663:672],
200: _Opcode_name[672:678],
202: _Opcode_name[678:682],
203: _Opcode_name[682:688],
204: _Opcode_name[688:692],
205: _Opcode_name[692:698],
206: _Opcode_name[698:706],
207: _Opcode_name[706:712],
208: _Opcode_name[712:719],
209: _Opcode_name[719:731],
210: _Opcode_name[731:737],
211: _Opcode_name[737:747],
217: _Opcode_name[747:753],
240: _Opcode_name[753:758],
241: _Opcode_name[758:768],
}
func (i Opcode) String() string {

View file

@ -919,7 +919,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
case opcode.NEWARRAY0:
v.estack.PushVal(&ArrayItem{[]StackItem{}})
case opcode.NEWARRAY:
case opcode.NEWARRAY, opcode.NEWARRAYT:
item := v.estack.Pop()
switch t := item.value.(type) {
case *StructItem:
@ -933,7 +933,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
if n > MaxArraySize {
panic("too long array")
}
items := makeArrayOfFalses(int(n))
typ := BooleanT
if op == opcode.NEWARRAYT {
typ = StackItemType(parameter[0])
}
items := makeArrayOfType(int(n), typ)
v.estack.PushVal(&ArrayItem{items})
}
@ -954,7 +958,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
if n > MaxArraySize {
panic("too long struct")
}
items := makeArrayOfFalses(int(n))
items := makeArrayOfType(int(n), BooleanT)
v.estack.PushVal(&StructItem{items})
}
@ -1492,10 +1496,22 @@ func cloneIfStruct(item StackItem) StackItem {
}
}
func makeArrayOfFalses(n int) []StackItem {
func makeArrayOfType(n int, typ StackItemType) []StackItem {
if !typ.IsValid() {
panic(fmt.Sprintf("invalid stack item type: %d", typ))
}
items := make([]StackItem, n)
for i := range items {
items[i] = &BoolItem{false}
switch typ {
case BooleanT:
items[i] = NewBoolItem(false)
case IntegerT:
items[i] = NewBigIntegerItem(big.NewInt(0))
case ByteArrayT:
items[i] = NewByteArrayItem([]byte{})
default:
items[i] = NullItem{}
}
}
return items
}

View file

@ -660,7 +660,7 @@ func TestSerializeArray(t *testing.T) {
func TestSerializeArrayBad(t *testing.T) {
vm := load(getSerializeProg())
item := NewArrayItem(makeArrayOfFalses(2))
item := NewArrayItem(makeArrayOfType(2, BooleanT))
item.value[1] = item
vm.estack.Push(&Element{value: item})
@ -1337,7 +1337,7 @@ func testNEWARRAYIssue437(t *testing.T, i1, i2 opcode.Opcode, appended bool) {
vm := load(prog)
vm.Run()
arr := makeArrayOfFalses(4)
arr := makeArrayOfType(4, BooleanT)
arr[2] = makeStackItem(3)
arr[3] = makeStackItem(4)
if appended {
@ -1379,6 +1379,32 @@ func TestNEWARRAYByteArray(t *testing.T) {
assert.Equal(t, &ArrayItem{[]StackItem{}}, vm.estack.Pop().value)
}
func testNEWARRAYT(t *testing.T, typ StackItemType, item StackItem) {
prog := makeProgram(opcode.NEWARRAYT, opcode.Opcode(typ), opcode.PUSH0, opcode.PICKITEM)
v := load(prog)
v.estack.PushVal(1)
if item == nil {
checkVMFailed(t, v)
return
}
runVM(t, v)
require.Equal(t, 1, v.estack.Len())
require.Equal(t, item, v.estack.Pop().Item())
}
func TestNEWARRAYT(t *testing.T) {
testCases := map[StackItemType]StackItem{
BooleanT: NewBoolItem(false),
IntegerT: NewBigIntegerItem(big.NewInt(0)),
ByteArrayT: NewByteArrayItem([]byte{}),
ArrayT: NullItem{},
0xFF: nil,
}
for typ, item := range testCases {
t.Run(typ.String(), func(t *testing.T) { testNEWARRAYT(t, typ, item) })
}
}
func TestNEWARRAYBadSize(t *testing.T) {
prog := makeProgram(opcode.NEWARRAY)
vm := load(prog)