forked from TrueCloudLab/neoneo-go
Merge pull request #907 from nspcc-dev/feature/compound
vm: implement Array/Struct/Map opcodes
This commit is contained in:
commit
aa8d4d2f57
12 changed files with 447 additions and 204 deletions
|
@ -398,7 +398,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
ast.Walk(c, n.High)
|
||||
} else {
|
||||
emit.Opcode(c.prog.BinWriter, opcode.OVER)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.ARRAYSIZE)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.SIZE)
|
||||
}
|
||||
|
||||
emit.Opcode(c.prog.BinWriter, opcode.OVER)
|
||||
|
@ -858,7 +858,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
|
||||
ast.Walk(c, n.X)
|
||||
|
||||
emit.Opcode(c.prog.BinWriter, opcode.ARRAYSIZE)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.SIZE)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.PUSH0)
|
||||
|
||||
c.pushStackLabel(label, 2)
|
||||
|
@ -1030,13 +1030,7 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
|||
|
||||
switch name {
|
||||
case "len":
|
||||
arg := expr.Args[0]
|
||||
typ := c.typeInfo.Types[arg].Type
|
||||
if isStringType(typ) {
|
||||
emit.Opcode(c.prog.BinWriter, opcode.SIZE)
|
||||
} else {
|
||||
emit.Opcode(c.prog.BinWriter, opcode.ARRAYSIZE)
|
||||
}
|
||||
emit.Opcode(c.prog.BinWriter, opcode.SIZE)
|
||||
case "append":
|
||||
arg := expr.Args[0]
|
||||
typ := c.typeInfo.Types[arg].Type
|
||||
|
|
|
@ -28,34 +28,34 @@ func TestInvocationScriptCreationGood(t *testing.T) {
|
|||
script: "0c023432676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{}}},
|
||||
script: "10c10c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "10c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.ByteArrayType, Value: Param{Type: StringT, Value: "50befd26fdf6e4d957c11e078b24ebce6291456f"}}}}}},
|
||||
script: "0c1450befd26fdf6e4d957c11e078b24ebce6291456f11c10c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c1450befd26fdf6e4d957c11e078b24ebce6291456f11c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.SignatureType, Value: Param{Type: StringT, Value: "4edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f"}}}}}},
|
||||
script: "0c404edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f11c10c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c404edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f11c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.StringType, Value: Param{Type: StringT, Value: "50befd26fdf6e4d957c11e078b24ebce6291456f"}}}}}},
|
||||
script: "0c283530626566643236666466366534643935376331316530373862323465626365363239313435366611c10c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c283530626566643236666466366534643935376331316530373862323465626365363239313435366611c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.Hash160Type, Value: Param{Type: StringT, Value: "50befd26fdf6e4d957c11e078b24ebce6291456f"}}}}}},
|
||||
script: "0c146f459162ceeb248b071ec157d9e4f6fd26fdbe5011c10c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c146f459162ceeb248b071ec157d9e4f6fd26fdbe5011c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.Hash256Type, Value: Param{Type: StringT, Value: "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"}}}}}},
|
||||
script: "0c20e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6011c10c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c20e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6011c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.PublicKeyType, Value: Param{Type: StringT, Value: "03c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c1"}}}}}},
|
||||
script: "0c2103c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c111c10c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c2103c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c111c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.IntegerType, Value: Param{Type: NumberT, Value: 42}}}}}},
|
||||
script: "002a11c10c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "002a11c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.BoolType, Value: Param{Type: StringT, Value: "true"}}}}}},
|
||||
script: "1111c10c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "1111c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.BoolType, Value: Param{Type: StringT, Value: "false"}}}}}},
|
||||
script: "1011c10c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "1011c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
}}
|
||||
for _, ps := range paramScripts {
|
||||
script, err := CreateFunctionInvocationScript(contract, ps.ps)
|
||||
|
|
|
@ -48,18 +48,18 @@ type rpcTestCase struct {
|
|||
check func(t *testing.T, e *executor, result interface{})
|
||||
}
|
||||
|
||||
const testContractHash = "6b9e88be61028590ebbb1296cbee09beed4ae75d"
|
||||
const testContractHash = "7858559a8405f4e4e1834fcff274ddf4f1b8f407"
|
||||
|
||||
var rpcTestCases = map[string][]rpcTestCase{
|
||||
"getapplicationlog": {
|
||||
{
|
||||
name: "positive",
|
||||
params: `["4459d8050e0abb0a42a9ec5a84dee1c5f8c449b11859265ef45a47c5ea369bc5"]`,
|
||||
params: `["4108062977676178e8453a8ef84a702e01bb35af8a65c7529d04704fcb5f1e0e"]`,
|
||||
result: func(e *executor) interface{} { return &result.ApplicationLog{} },
|
||||
check: func(t *testing.T, e *executor, acc interface{}) {
|
||||
res, ok := acc.(*result.ApplicationLog)
|
||||
require.True(t, ok)
|
||||
expectedTxHash, err := util.Uint256DecodeStringLE("4459d8050e0abb0a42a9ec5a84dee1c5f8c449b11859265ef45a47c5ea369bc5")
|
||||
expectedTxHash, err := util.Uint256DecodeStringLE("4108062977676178e8453a8ef84a702e01bb35af8a65c7529d04704fcb5f1e0e")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expectedTxHash, res.TxHash)
|
||||
assert.Equal(t, 1, len(res.Executions))
|
||||
|
|
BIN
pkg/rpc/server/testdata/test_contract.avm
vendored
BIN
pkg/rpc/server/testdata/test_contract.avm
vendored
Binary file not shown.
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
|
@ -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.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,
|
||||
|
@ -186,6 +186,9 @@ func (c *Context) TryInteger() (*big.Int, error) {
|
|||
return nil, errors.New("can't convert Context to Integer")
|
||||
}
|
||||
|
||||
// Type implements StackItem interface.
|
||||
func (c *Context) Type() StackItemType { panic("Context cannot appear on evaluation stack") }
|
||||
|
||||
// Equals implements StackItem interface.
|
||||
func (c *Context) Equals(s StackItem) bool {
|
||||
return c == s
|
||||
|
|
|
@ -98,7 +98,6 @@ const (
|
|||
SUBSTR Opcode = 0x7F
|
||||
LEFT Opcode = 0x80
|
||||
RIGHT Opcode = 0x81
|
||||
SIZE Opcode = 0x82
|
||||
|
||||
// Bitwise logic
|
||||
INVERT Opcode = 0x83
|
||||
|
@ -144,20 +143,27 @@ const (
|
|||
CHECKMULTISIG Opcode = 0xAE
|
||||
|
||||
// Advanced data structures (arrays, structures, maps)
|
||||
ARRAYSIZE Opcode = 0xC0
|
||||
PACK Opcode = 0xC1
|
||||
UNPACK Opcode = 0xC2
|
||||
PICKITEM Opcode = 0xC3
|
||||
SETITEM Opcode = 0xC4
|
||||
NEWARRAY Opcode = 0xC5
|
||||
NEWSTRUCT Opcode = 0xC6
|
||||
NEWMAP Opcode = 0xC7
|
||||
APPEND Opcode = 0xC8
|
||||
REVERSE Opcode = 0xC9
|
||||
REMOVE Opcode = 0xCA
|
||||
HASKEY Opcode = 0xCB
|
||||
KEYS Opcode = 0xCC
|
||||
VALUES Opcode = 0xCD
|
||||
PACK Opcode = 0xC0
|
||||
UNPACK Opcode = 0xC1
|
||||
NEWARRAY0 Opcode = 0xC2
|
||||
NEWARRAY Opcode = 0xC3
|
||||
NEWARRAYT Opcode = 0xC4
|
||||
NEWSTRUCT0 Opcode = 0xC5
|
||||
NEWSTRUCT Opcode = 0xC6
|
||||
NEWMAP Opcode = 0xC8
|
||||
SIZE Opcode = 0xCA
|
||||
HASKEY Opcode = 0xCB
|
||||
KEYS Opcode = 0xCC
|
||||
VALUES Opcode = 0xCD
|
||||
PICKITEM Opcode = 0xCE
|
||||
APPEND Opcode = 0xCF
|
||||
SETITEM Opcode = 0xD0
|
||||
REVERSEITEMS Opcode = 0xD1
|
||||
REMOVE Opcode = 0xD2
|
||||
CLEARITEMS Opcode = 0xD3
|
||||
|
||||
// Types
|
||||
ISTYPE Opcode = 0xD9
|
||||
|
||||
// Exceptions
|
||||
THROW Opcode = 0xF0
|
||||
|
|
|
@ -85,7 +85,6 @@ func _() {
|
|||
_ = x[SUBSTR-127]
|
||||
_ = x[LEFT-128]
|
||||
_ = x[RIGHT-129]
|
||||
_ = x[SIZE-130]
|
||||
_ = x[INVERT-131]
|
||||
_ = x[AND-132]
|
||||
_ = x[OR-133]
|
||||
|
@ -123,25 +122,30 @@ func _() {
|
|||
_ = x[CHECKSIG-172]
|
||||
_ = x[VERIFY-173]
|
||||
_ = x[CHECKMULTISIG-174]
|
||||
_ = x[ARRAYSIZE-192]
|
||||
_ = x[PACK-193]
|
||||
_ = x[UNPACK-194]
|
||||
_ = x[PICKITEM-195]
|
||||
_ = x[SETITEM-196]
|
||||
_ = x[NEWARRAY-197]
|
||||
_ = x[PACK-192]
|
||||
_ = x[UNPACK-193]
|
||||
_ = x[NEWARRAY0-194]
|
||||
_ = x[NEWARRAY-195]
|
||||
_ = x[NEWARRAYT-196]
|
||||
_ = x[NEWSTRUCT0-197]
|
||||
_ = x[NEWSTRUCT-198]
|
||||
_ = x[NEWMAP-199]
|
||||
_ = x[APPEND-200]
|
||||
_ = x[REVERSE-201]
|
||||
_ = x[REMOVE-202]
|
||||
_ = x[NEWMAP-200]
|
||||
_ = x[SIZE-202]
|
||||
_ = x[HASKEY-203]
|
||||
_ = x[KEYS-204]
|
||||
_ = x[VALUES-205]
|
||||
_ = x[PICKITEM-206]
|
||||
_ = x[APPEND-207]
|
||||
_ = x[SETITEM-208]
|
||||
_ = x[REVERSEITEMS-209]
|
||||
_ = x[REMOVE-210]
|
||||
_ = x[CLEARITEMS-211]
|
||||
_ = x[ISTYPE-217]
|
||||
_ = x[THROW-240]
|
||||
_ = x[THROWIFNOT-241]
|
||||
}
|
||||
|
||||
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMP_LJMPIFJMPIF_LJMPIFNOTJMPIFNOT_LJMPEQJMPEQ_LJMPNEJMPNE_LJMPGTJMPGT_LJMPGEJMPGE_LJMPLTJMPLT_LJMPLEJMPLE_LCALLCALL_LOLDPUSH1RETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPISNULLXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTSIZEINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINSHA1SHA256HASH160HASH256CHECKSIGVERIFYCHECKMULTISIGARRAYSIZEPACKUNPACKPICKITEMSETITEMNEWARRAYNEWSTRUCTNEWMAPAPPENDREVERSEREMOVEHASKEYKEYSVALUESTHROWTHROWIFNOT"
|
||||
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLOLDPUSH1RETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPISNULLXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINSHA1SHA256HASH160HASH256CHECKSIGVERIFYCHECKMULTISIGPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISTYPETHROWTHROWIFNOT"
|
||||
|
||||
var _Opcode_map = map[Opcode]string{
|
||||
0: _Opcode_name[0:8],
|
||||
|
@ -174,105 +178,109 @@ var _Opcode_map = map[Opcode]string{
|
|||
32: _Opcode_name[182:188],
|
||||
33: _Opcode_name[188:191],
|
||||
34: _Opcode_name[191:194],
|
||||
35: _Opcode_name[194:199],
|
||||
36: _Opcode_name[199:204],
|
||||
37: _Opcode_name[204:211],
|
||||
38: _Opcode_name[211:219],
|
||||
39: _Opcode_name[219:229],
|
||||
40: _Opcode_name[229:234],
|
||||
41: _Opcode_name[234:241],
|
||||
42: _Opcode_name[241:246],
|
||||
43: _Opcode_name[246:253],
|
||||
44: _Opcode_name[253:258],
|
||||
45: _Opcode_name[258:265],
|
||||
46: _Opcode_name[265:270],
|
||||
47: _Opcode_name[270:277],
|
||||
48: _Opcode_name[277:282],
|
||||
49: _Opcode_name[282:289],
|
||||
50: _Opcode_name[289:294],
|
||||
51: _Opcode_name[294:301],
|
||||
52: _Opcode_name[301:305],
|
||||
53: _Opcode_name[305:311],
|
||||
81: _Opcode_name[311:319],
|
||||
102: _Opcode_name[319:322],
|
||||
103: _Opcode_name[322:329],
|
||||
104: _Opcode_name[329:336],
|
||||
105: _Opcode_name[336:344],
|
||||
106: _Opcode_name[344:359],
|
||||
107: _Opcode_name[359:369],
|
||||
108: _Opcode_name[369:381],
|
||||
109: _Opcode_name[381:386],
|
||||
112: _Opcode_name[386:392],
|
||||
114: _Opcode_name[392:397],
|
||||
115: _Opcode_name[397:402],
|
||||
116: _Opcode_name[402:407],
|
||||
117: _Opcode_name[407:411],
|
||||
118: _Opcode_name[411:414],
|
||||
119: _Opcode_name[414:417],
|
||||
120: _Opcode_name[417:421],
|
||||
121: _Opcode_name[421:425],
|
||||
122: _Opcode_name[425:429],
|
||||
123: _Opcode_name[429:432],
|
||||
124: _Opcode_name[432:436],
|
||||
125: _Opcode_name[436:440],
|
||||
126: _Opcode_name[440:443],
|
||||
127: _Opcode_name[443:449],
|
||||
128: _Opcode_name[449:453],
|
||||
129: _Opcode_name[453:458],
|
||||
130: _Opcode_name[458:462],
|
||||
131: _Opcode_name[462:468],
|
||||
132: _Opcode_name[468:471],
|
||||
133: _Opcode_name[471:473],
|
||||
134: _Opcode_name[473:476],
|
||||
135: _Opcode_name[476:481],
|
||||
139: _Opcode_name[481:484],
|
||||
140: _Opcode_name[484:487],
|
||||
141: _Opcode_name[487:491],
|
||||
143: _Opcode_name[491:497],
|
||||
144: _Opcode_name[497:500],
|
||||
145: _Opcode_name[500:503],
|
||||
146: _Opcode_name[503:505],
|
||||
147: _Opcode_name[505:508],
|
||||
148: _Opcode_name[508:511],
|
||||
149: _Opcode_name[511:514],
|
||||
150: _Opcode_name[514:517],
|
||||
151: _Opcode_name[517:520],
|
||||
152: _Opcode_name[520:523],
|
||||
153: _Opcode_name[523:526],
|
||||
154: _Opcode_name[526:533],
|
||||
155: _Opcode_name[533:539],
|
||||
156: _Opcode_name[539:547],
|
||||
158: _Opcode_name[547:558],
|
||||
159: _Opcode_name[558:560],
|
||||
160: _Opcode_name[560:562],
|
||||
161: _Opcode_name[562:565],
|
||||
162: _Opcode_name[565:568],
|
||||
163: _Opcode_name[568:571],
|
||||
164: _Opcode_name[571:574],
|
||||
165: _Opcode_name[574:580],
|
||||
167: _Opcode_name[580:584],
|
||||
168: _Opcode_name[584:590],
|
||||
169: _Opcode_name[590:597],
|
||||
170: _Opcode_name[597:604],
|
||||
172: _Opcode_name[604:612],
|
||||
173: _Opcode_name[612:618],
|
||||
174: _Opcode_name[618:631],
|
||||
192: _Opcode_name[631:640],
|
||||
193: _Opcode_name[640:644],
|
||||
194: _Opcode_name[644:650],
|
||||
195: _Opcode_name[650:658],
|
||||
196: _Opcode_name[658:665],
|
||||
197: _Opcode_name[665:673],
|
||||
198: _Opcode_name[673:682],
|
||||
199: _Opcode_name[682:688],
|
||||
200: _Opcode_name[688:694],
|
||||
201: _Opcode_name[694:701],
|
||||
202: _Opcode_name[701:707],
|
||||
203: _Opcode_name[707:713],
|
||||
204: _Opcode_name[713:717],
|
||||
205: _Opcode_name[717:723],
|
||||
240: _Opcode_name[723:728],
|
||||
241: _Opcode_name[728:738],
|
||||
35: _Opcode_name[194:198],
|
||||
36: _Opcode_name[198:203],
|
||||
37: _Opcode_name[203:209],
|
||||
38: _Opcode_name[209:217],
|
||||
39: _Opcode_name[217:226],
|
||||
40: _Opcode_name[226:231],
|
||||
41: _Opcode_name[231:237],
|
||||
42: _Opcode_name[237:242],
|
||||
43: _Opcode_name[242:248],
|
||||
44: _Opcode_name[248:253],
|
||||
45: _Opcode_name[253:259],
|
||||
46: _Opcode_name[259:264],
|
||||
47: _Opcode_name[264:270],
|
||||
48: _Opcode_name[270:275],
|
||||
49: _Opcode_name[275:281],
|
||||
50: _Opcode_name[281:286],
|
||||
51: _Opcode_name[286:292],
|
||||
52: _Opcode_name[292:296],
|
||||
53: _Opcode_name[296:301],
|
||||
81: _Opcode_name[301:309],
|
||||
102: _Opcode_name[309:312],
|
||||
103: _Opcode_name[312:319],
|
||||
104: _Opcode_name[319:326],
|
||||
105: _Opcode_name[326:334],
|
||||
106: _Opcode_name[334:349],
|
||||
107: _Opcode_name[349:359],
|
||||
108: _Opcode_name[359:371],
|
||||
109: _Opcode_name[371:376],
|
||||
112: _Opcode_name[376:382],
|
||||
114: _Opcode_name[382:387],
|
||||
115: _Opcode_name[387:392],
|
||||
116: _Opcode_name[392:397],
|
||||
117: _Opcode_name[397:401],
|
||||
118: _Opcode_name[401:404],
|
||||
119: _Opcode_name[404:407],
|
||||
120: _Opcode_name[407:411],
|
||||
121: _Opcode_name[411:415],
|
||||
122: _Opcode_name[415:419],
|
||||
123: _Opcode_name[419:422],
|
||||
124: _Opcode_name[422:426],
|
||||
125: _Opcode_name[426:430],
|
||||
126: _Opcode_name[430:433],
|
||||
127: _Opcode_name[433:439],
|
||||
128: _Opcode_name[439:443],
|
||||
129: _Opcode_name[443:448],
|
||||
131: _Opcode_name[448:454],
|
||||
132: _Opcode_name[454:457],
|
||||
133: _Opcode_name[457:459],
|
||||
134: _Opcode_name[459:462],
|
||||
135: _Opcode_name[462:467],
|
||||
139: _Opcode_name[467:470],
|
||||
140: _Opcode_name[470:473],
|
||||
141: _Opcode_name[473:477],
|
||||
143: _Opcode_name[477:483],
|
||||
144: _Opcode_name[483:486],
|
||||
145: _Opcode_name[486:489],
|
||||
146: _Opcode_name[489:491],
|
||||
147: _Opcode_name[491:494],
|
||||
148: _Opcode_name[494:497],
|
||||
149: _Opcode_name[497:500],
|
||||
150: _Opcode_name[500:503],
|
||||
151: _Opcode_name[503:506],
|
||||
152: _Opcode_name[506:509],
|
||||
153: _Opcode_name[509:512],
|
||||
154: _Opcode_name[512:519],
|
||||
155: _Opcode_name[519:525],
|
||||
156: _Opcode_name[525:533],
|
||||
158: _Opcode_name[533:544],
|
||||
159: _Opcode_name[544:546],
|
||||
160: _Opcode_name[546:548],
|
||||
161: _Opcode_name[548:551],
|
||||
162: _Opcode_name[551:554],
|
||||
163: _Opcode_name[554:557],
|
||||
164: _Opcode_name[557:560],
|
||||
165: _Opcode_name[560:566],
|
||||
167: _Opcode_name[566:570],
|
||||
168: _Opcode_name[570:576],
|
||||
169: _Opcode_name[576:583],
|
||||
170: _Opcode_name[583:590],
|
||||
172: _Opcode_name[590:598],
|
||||
173: _Opcode_name[598:604],
|
||||
174: _Opcode_name[604:617],
|
||||
192: _Opcode_name[617:621],
|
||||
193: _Opcode_name[621:627],
|
||||
194: _Opcode_name[627:636],
|
||||
195: _Opcode_name[636:644],
|
||||
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 {
|
||||
|
|
|
@ -7,17 +7,61 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
)
|
||||
|
||||
type stackItemType byte
|
||||
// StackItemType represents type of the stack item.
|
||||
type StackItemType byte
|
||||
|
||||
// This block defines all known stack item types.
|
||||
const (
|
||||
byteArrayT stackItemType = 0x00
|
||||
booleanT stackItemType = 0x01
|
||||
integerT stackItemType = 0x02
|
||||
arrayT stackItemType = 0x80
|
||||
structT stackItemType = 0x81
|
||||
mapT stackItemType = 0x82
|
||||
AnyT StackItemType = 0x00
|
||||
PointerT StackItemType = 0x10
|
||||
BooleanT StackItemType = 0x20
|
||||
IntegerT StackItemType = 0x21
|
||||
ByteArrayT StackItemType = 0x28
|
||||
BufferT StackItemType = 0x30
|
||||
ArrayT StackItemType = 0x40
|
||||
StructT StackItemType = 0x41
|
||||
MapT StackItemType = 0x48
|
||||
InteropT StackItemType = 0x60
|
||||
)
|
||||
|
||||
// String implements fmt.Stringer interface.
|
||||
func (t StackItemType) String() string {
|
||||
switch t {
|
||||
case AnyT:
|
||||
return "Any"
|
||||
case PointerT:
|
||||
return "Pointer"
|
||||
case BooleanT:
|
||||
return "Boolean"
|
||||
case IntegerT:
|
||||
return "Integer"
|
||||
case ByteArrayT:
|
||||
return "ByteArray"
|
||||
case BufferT:
|
||||
return "Buffer"
|
||||
case ArrayT:
|
||||
return "Array"
|
||||
case StructT:
|
||||
return "Struct"
|
||||
case MapT:
|
||||
return "Map"
|
||||
case InteropT:
|
||||
return "Interop"
|
||||
default:
|
||||
return "INVALID"
|
||||
}
|
||||
}
|
||||
|
||||
// IsValid checks if s is a well defined stack item type.
|
||||
func (t StackItemType) IsValid() bool {
|
||||
switch t {
|
||||
case AnyT, PointerT, BooleanT, IntegerT, ByteArrayT, BufferT, ArrayT, StructT, MapT, InteropT:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// SerializeItem encodes given StackItem into the byte slice.
|
||||
func SerializeItem(item StackItem) ([]byte, error) {
|
||||
w := io.NewBufBinWriter()
|
||||
|
@ -43,13 +87,13 @@ func serializeItemTo(item StackItem, w *io.BinWriter, seen map[StackItem]bool) {
|
|||
|
||||
switch t := item.(type) {
|
||||
case *ByteArrayItem:
|
||||
w.WriteBytes([]byte{byte(byteArrayT)})
|
||||
w.WriteBytes([]byte{byte(ByteArrayT)})
|
||||
w.WriteVarBytes(t.value)
|
||||
case *BoolItem:
|
||||
w.WriteBytes([]byte{byte(booleanT)})
|
||||
w.WriteBytes([]byte{byte(BooleanT)})
|
||||
w.WriteBool(t.value)
|
||||
case *BigIntegerItem:
|
||||
w.WriteBytes([]byte{byte(integerT)})
|
||||
w.WriteBytes([]byte{byte(IntegerT)})
|
||||
w.WriteVarBytes(emit.IntToBytes(t.value))
|
||||
case *InteropItem:
|
||||
w.Err = errors.New("interop item can't be serialized")
|
||||
|
@ -58,9 +102,9 @@ func serializeItemTo(item StackItem, w *io.BinWriter, seen map[StackItem]bool) {
|
|||
|
||||
_, isArray := t.(*ArrayItem)
|
||||
if isArray {
|
||||
w.WriteBytes([]byte{byte(arrayT)})
|
||||
w.WriteBytes([]byte{byte(ArrayT)})
|
||||
} else {
|
||||
w.WriteBytes([]byte{byte(structT)})
|
||||
w.WriteBytes([]byte{byte(StructT)})
|
||||
}
|
||||
|
||||
arr := t.Value().([]StackItem)
|
||||
|
@ -71,7 +115,7 @@ func serializeItemTo(item StackItem, w *io.BinWriter, seen map[StackItem]bool) {
|
|||
case *MapItem:
|
||||
seen[item] = true
|
||||
|
||||
w.WriteBytes([]byte{byte(mapT)})
|
||||
w.WriteBytes([]byte{byte(MapT)})
|
||||
w.WriteVarUint(uint64(len(t.value)))
|
||||
for i := range t.value {
|
||||
serializeItemTo(t.value[i].Key, w, seen)
|
||||
|
@ -100,31 +144,31 @@ func DecodeBinaryStackItem(r *io.BinReader) StackItem {
|
|||
return nil
|
||||
}
|
||||
|
||||
switch stackItemType(t) {
|
||||
case byteArrayT:
|
||||
switch StackItemType(t) {
|
||||
case ByteArrayT:
|
||||
data := r.ReadVarBytes()
|
||||
return NewByteArrayItem(data)
|
||||
case booleanT:
|
||||
case BooleanT:
|
||||
var b = r.ReadBool()
|
||||
return NewBoolItem(b)
|
||||
case integerT:
|
||||
case IntegerT:
|
||||
data := r.ReadVarBytes()
|
||||
num := emit.BytesToInt(data)
|
||||
return &BigIntegerItem{
|
||||
value: num,
|
||||
}
|
||||
case arrayT, structT:
|
||||
case ArrayT, StructT:
|
||||
size := int(r.ReadVarUint())
|
||||
arr := make([]StackItem, size)
|
||||
for i := 0; i < size; i++ {
|
||||
arr[i] = DecodeBinaryStackItem(r)
|
||||
}
|
||||
|
||||
if stackItemType(t) == arrayT {
|
||||
if StackItemType(t) == ArrayT {
|
||||
return &ArrayItem{value: arr}
|
||||
}
|
||||
return &StructItem{value: arr}
|
||||
case mapT:
|
||||
case MapT:
|
||||
size := int(r.ReadVarUint())
|
||||
m := NewMapItem()
|
||||
for i := 0; i < size; i++ {
|
||||
|
|
|
@ -28,6 +28,8 @@ type StackItem interface {
|
|||
Equals(s StackItem) bool
|
||||
// ToContractParameter converts StackItem to smartcontract.Parameter
|
||||
ToContractParameter(map[StackItem]bool) smartcontract.Parameter
|
||||
// Type returns stack item type.
|
||||
Type() StackItemType
|
||||
}
|
||||
|
||||
func makeStackItem(v interface{}) StackItem {
|
||||
|
@ -177,6 +179,9 @@ func (i *StructItem) ToContractParameter(seen map[StackItem]bool) smartcontract.
|
|||
}
|
||||
}
|
||||
|
||||
// Type implements StackItem interface.
|
||||
func (i *StructItem) Type() StackItemType { return StructT }
|
||||
|
||||
// Clone returns a Struct with all Struct fields copied by value.
|
||||
// Array fields are still copied by reference.
|
||||
func (i *StructItem) Clone() *StructItem {
|
||||
|
@ -235,6 +240,9 @@ func (i NullItem) ToContractParameter(map[StackItem]bool) smartcontract.Paramete
|
|||
}
|
||||
}
|
||||
|
||||
// Type implements StackItem interface.
|
||||
func (i NullItem) Type() StackItemType { return AnyT }
|
||||
|
||||
// BigIntegerItem represents a big integer on the stack.
|
||||
type BigIntegerItem struct {
|
||||
value *big.Int
|
||||
|
@ -300,6 +308,9 @@ func (i *BigIntegerItem) ToContractParameter(map[StackItem]bool) smartcontract.P
|
|||
}
|
||||
}
|
||||
|
||||
// Type implements StackItem interface.
|
||||
func (i *BigIntegerItem) Type() StackItemType { return IntegerT }
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (i *BigIntegerItem) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.value)
|
||||
|
@ -380,6 +391,9 @@ func (i *BoolItem) ToContractParameter(map[StackItem]bool) smartcontract.Paramet
|
|||
}
|
||||
}
|
||||
|
||||
// Type implements StackItem interface.
|
||||
func (i *BoolItem) Type() StackItemType { return BooleanT }
|
||||
|
||||
// ByteArrayItem represents a byte array on the stack.
|
||||
type ByteArrayItem struct {
|
||||
value []byte
|
||||
|
@ -442,6 +456,9 @@ func (i *ByteArrayItem) ToContractParameter(map[StackItem]bool) smartcontract.Pa
|
|||
}
|
||||
}
|
||||
|
||||
// Type implements StackItem interface.
|
||||
func (i *ByteArrayItem) Type() StackItemType { return ByteArrayT }
|
||||
|
||||
// ArrayItem represents a new ArrayItem object.
|
||||
type ArrayItem struct {
|
||||
value []StackItem
|
||||
|
@ -506,6 +523,9 @@ func (i *ArrayItem) ToContractParameter(seen map[StackItem]bool) smartcontract.P
|
|||
}
|
||||
}
|
||||
|
||||
// Type implements StackItem interface.
|
||||
func (i *ArrayItem) Type() StackItemType { return ArrayT }
|
||||
|
||||
// MapElement is a key-value pair of StackItems.
|
||||
type MapElement struct {
|
||||
Key StackItem
|
||||
|
@ -591,6 +611,9 @@ func (i *MapItem) ToContractParameter(seen map[StackItem]bool) smartcontract.Par
|
|||
}
|
||||
}
|
||||
|
||||
// Type implements StackItem interface.
|
||||
func (i *MapItem) Type() StackItemType { return MapT }
|
||||
|
||||
// Add adds key-value pair to the map.
|
||||
func (i *MapItem) Add(key, value StackItem) {
|
||||
if !isValidMapKey(key) {
|
||||
|
@ -678,6 +701,9 @@ func (i *InteropItem) ToContractParameter(map[StackItem]bool) smartcontract.Para
|
|||
}
|
||||
}
|
||||
|
||||
// Type implements StackItem interface.
|
||||
func (i *InteropItem) Type() StackItemType { return InteropT }
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (i *InteropItem) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.value)
|
||||
|
|
69
pkg/vm/vm.go
69
pkg/vm/vm.go
|
@ -565,6 +565,10 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
res := v.estack.Pop().value.Equals(NullItem{})
|
||||
v.estack.PushVal(res)
|
||||
|
||||
case opcode.ISTYPE:
|
||||
res := v.estack.Pop().Item()
|
||||
v.estack.PushVal(res.Type() == StackItemType(parameter[0]))
|
||||
|
||||
// Stack operations.
|
||||
case opcode.TOALTSTACK:
|
||||
v.astack.Push(v.estack.Pop())
|
||||
|
@ -911,8 +915,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
x := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(x.Cmp(big.NewInt(0)) != 0)
|
||||
|
||||
// Object operations.
|
||||
case opcode.NEWARRAY:
|
||||
// Object operations
|
||||
case opcode.NEWARRAY0:
|
||||
v.estack.PushVal(&ArrayItem{[]StackItem{}})
|
||||
|
||||
case opcode.NEWARRAY, opcode.NEWARRAYT:
|
||||
item := v.estack.Pop()
|
||||
switch t := item.value.(type) {
|
||||
case *StructItem:
|
||||
|
@ -926,10 +933,17 @@ 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})
|
||||
}
|
||||
|
||||
case opcode.NEWSTRUCT0:
|
||||
v.estack.PushVal(&StructItem{[]StackItem{}})
|
||||
|
||||
case opcode.NEWSTRUCT:
|
||||
item := v.estack.Pop()
|
||||
switch t := item.value.(type) {
|
||||
|
@ -944,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})
|
||||
}
|
||||
|
||||
|
@ -1058,7 +1072,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
panic(fmt.Sprintf("SETITEM: invalid item type %s", t))
|
||||
}
|
||||
|
||||
case opcode.REVERSE:
|
||||
case opcode.REVERSEITEMS:
|
||||
a := v.estack.Pop().Array()
|
||||
if len(a) > 1 {
|
||||
for i, j := 0, len(a)-1; i <= j; i, j = i+1, j-1 {
|
||||
|
@ -1100,7 +1114,29 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
panic("REMOVE: invalid type")
|
||||
}
|
||||
|
||||
case opcode.ARRAYSIZE:
|
||||
case opcode.CLEARITEMS:
|
||||
elem := v.estack.Pop()
|
||||
switch t := elem.value.(type) {
|
||||
case *ArrayItem:
|
||||
for _, item := range t.value {
|
||||
v.estack.updateSizeRemove(item)
|
||||
}
|
||||
t.value = t.value[:0]
|
||||
case *StructItem:
|
||||
for _, item := range t.value {
|
||||
v.estack.updateSizeRemove(item)
|
||||
}
|
||||
t.value = t.value[:0]
|
||||
case *MapItem:
|
||||
for i := range t.value {
|
||||
v.estack.updateSizeRemove(t.value[i].Value)
|
||||
}
|
||||
t.value = t.value[:0]
|
||||
default:
|
||||
panic("CLEARITEMS: invalid type")
|
||||
}
|
||||
|
||||
case opcode.SIZE:
|
||||
elem := v.estack.Pop()
|
||||
// Cause there is no native (byte) item type here, hence we need to check
|
||||
// the type of the item for array size operations.
|
||||
|
@ -1113,11 +1149,6 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
v.estack.PushVal(len(elem.Bytes()))
|
||||
}
|
||||
|
||||
case opcode.SIZE:
|
||||
elem := v.estack.Pop()
|
||||
arr := elem.Bytes()
|
||||
v.estack.PushVal(len(arr))
|
||||
|
||||
case opcode.JMP, opcode.JMPL, opcode.JMPIF, opcode.JMPIFL, opcode.JMPIFNOT, opcode.JMPIFNOTL,
|
||||
opcode.JMPEQ, opcode.JMPEQL, opcode.JMPNE, opcode.JMPNEL,
|
||||
opcode.JMPGT, opcode.JMPGTL, opcode.JMPGE, opcode.JMPGEL,
|
||||
|
@ -1465,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
|
||||
}
|
||||
|
|
|
@ -216,6 +216,46 @@ func TestISNULL(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func testISTYPE(t *testing.T, result bool, typ StackItemType, item StackItem) {
|
||||
prog := []byte{byte(opcode.ISTYPE), byte(typ)}
|
||||
v := load(prog)
|
||||
v.estack.PushVal(item)
|
||||
runVM(t, v)
|
||||
require.Equal(t, 1, v.estack.Len())
|
||||
require.Equal(t, result, v.estack.Pop().Bool())
|
||||
}
|
||||
|
||||
func TestISTYPE(t *testing.T) {
|
||||
t.Run("Integer", func(t *testing.T) {
|
||||
testISTYPE(t, true, IntegerT, NewBigIntegerItem(big.NewInt(42)))
|
||||
testISTYPE(t, false, IntegerT, NewByteArrayItem([]byte{}))
|
||||
})
|
||||
t.Run("Boolean", func(t *testing.T) {
|
||||
testISTYPE(t, true, BooleanT, NewBoolItem(true))
|
||||
testISTYPE(t, false, BooleanT, NewByteArrayItem([]byte{}))
|
||||
})
|
||||
t.Run("ByteArray", func(t *testing.T) {
|
||||
testISTYPE(t, true, ByteArrayT, NewByteArrayItem([]byte{}))
|
||||
testISTYPE(t, false, ByteArrayT, NewBigIntegerItem(big.NewInt(42)))
|
||||
})
|
||||
t.Run("Array", func(t *testing.T) {
|
||||
testISTYPE(t, true, ArrayT, NewArrayItem([]StackItem{}))
|
||||
testISTYPE(t, false, ArrayT, NewByteArrayItem([]byte{}))
|
||||
})
|
||||
t.Run("Struct", func(t *testing.T) {
|
||||
testISTYPE(t, true, StructT, NewStructItem([]StackItem{}))
|
||||
testISTYPE(t, false, StructT, NewByteArrayItem([]byte{}))
|
||||
})
|
||||
t.Run("Map", func(t *testing.T) {
|
||||
testISTYPE(t, true, MapT, NewMapItem())
|
||||
testISTYPE(t, false, MapT, NewByteArrayItem([]byte{}))
|
||||
})
|
||||
t.Run("Interop", func(t *testing.T) {
|
||||
testISTYPE(t, true, InteropT, NewInteropItem(42))
|
||||
testISTYPE(t, false, InteropT, NewByteArrayItem([]byte{}))
|
||||
})
|
||||
}
|
||||
|
||||
// appendBigStruct returns a program which:
|
||||
// 1. pushes size Structs on stack
|
||||
// 2. packs them into a new struct
|
||||
|
@ -620,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})
|
||||
|
@ -685,7 +725,7 @@ func TestSerializeMap(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSerializeMapCompat(t *testing.T) {
|
||||
resHex := "820100036b6579000576616c7565"
|
||||
resHex := "480128036b6579280576616c7565"
|
||||
res, err := hex.DecodeString(resHex)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -1252,6 +1292,22 @@ func TestDECBigResult(t *testing.T) {
|
|||
checkVMFailed(t, vm)
|
||||
}
|
||||
|
||||
func TestNEWARRAY0(t *testing.T) {
|
||||
prog := makeProgram(opcode.NEWARRAY0)
|
||||
v := load(prog)
|
||||
runVM(t, v)
|
||||
require.Equal(t, 1, v.estack.Len())
|
||||
require.Equal(t, &ArrayItem{[]StackItem{}}, v.estack.Pop().value)
|
||||
}
|
||||
|
||||
func TestNEWSTRUCT0(t *testing.T) {
|
||||
prog := makeProgram(opcode.NEWSTRUCT0)
|
||||
v := load(prog)
|
||||
runVM(t, v)
|
||||
require.Equal(t, 1, v.estack.Len())
|
||||
require.Equal(t, &StructItem{[]StackItem{}}, v.estack.Pop().value)
|
||||
}
|
||||
|
||||
func TestNEWARRAYInteger(t *testing.T) {
|
||||
prog := makeProgram(opcode.NEWARRAY)
|
||||
vm := load(prog)
|
||||
|
@ -1281,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 {
|
||||
|
@ -1323,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)
|
||||
|
@ -1581,8 +1663,8 @@ func TestSIZEBool(t *testing.T) {
|
|||
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
|
||||
}
|
||||
|
||||
func TestARRAYSIZEArray(t *testing.T) {
|
||||
prog := makeProgram(opcode.ARRAYSIZE)
|
||||
func TestSIZEArray(t *testing.T) {
|
||||
prog := makeProgram(opcode.SIZE)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal([]StackItem{
|
||||
makeStackItem(1),
|
||||
|
@ -1593,8 +1675,8 @@ func TestARRAYSIZEArray(t *testing.T) {
|
|||
assert.Equal(t, makeStackItem(2), vm.estack.Pop().value)
|
||||
}
|
||||
|
||||
func TestARRAYSIZEMap(t *testing.T) {
|
||||
prog := makeProgram(opcode.ARRAYSIZE)
|
||||
func TestSIZEMap(t *testing.T) {
|
||||
prog := makeProgram(opcode.SIZE)
|
||||
vm := load(prog)
|
||||
|
||||
m := NewMapItem()
|
||||
|
@ -2534,19 +2616,19 @@ func TestUNPACKGood(t *testing.T) {
|
|||
assert.Equal(t, int64(1), vm.estack.Peek(len(elements)+1).BigInt().Int64())
|
||||
}
|
||||
|
||||
func TestREVERSEBadNotArray(t *testing.T) {
|
||||
prog := makeProgram(opcode.REVERSE)
|
||||
func TestREVERSEITEMSBadNotArray(t *testing.T) {
|
||||
prog := makeProgram(opcode.REVERSEITEMS)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(1)
|
||||
checkVMFailed(t, vm)
|
||||
}
|
||||
|
||||
func testREVERSEIssue437(t *testing.T, i1, i2 opcode.Opcode, reversed bool) {
|
||||
func testREVERSEITEMSIssue437(t *testing.T, i1, i2 opcode.Opcode, reversed bool) {
|
||||
prog := makeProgram(
|
||||
opcode.PUSH0, i1,
|
||||
opcode.DUP, opcode.PUSH1, opcode.APPEND,
|
||||
opcode.DUP, opcode.PUSH2, opcode.APPEND,
|
||||
opcode.DUP, i2, opcode.REVERSE)
|
||||
opcode.DUP, i2, opcode.REVERSEITEMS)
|
||||
vm := load(prog)
|
||||
vm.Run()
|
||||
|
||||
|
@ -2567,15 +2649,15 @@ func testREVERSEIssue437(t *testing.T, i1, i2 opcode.Opcode, reversed bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestREVERSEIssue437(t *testing.T) {
|
||||
t.Run("Array+Array", func(t *testing.T) { testREVERSEIssue437(t, opcode.NEWARRAY, opcode.NEWARRAY, true) })
|
||||
t.Run("Struct+Struct", func(t *testing.T) { testREVERSEIssue437(t, opcode.NEWSTRUCT, opcode.NEWSTRUCT, true) })
|
||||
t.Run("Array+Struct", func(t *testing.T) { testREVERSEIssue437(t, opcode.NEWARRAY, opcode.NEWSTRUCT, false) })
|
||||
t.Run("Struct+Array", func(t *testing.T) { testREVERSEIssue437(t, opcode.NEWSTRUCT, opcode.NEWARRAY, false) })
|
||||
func TestREVERSEITEMSIssue437(t *testing.T) {
|
||||
t.Run("Array+Array", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWARRAY, opcode.NEWARRAY, true) })
|
||||
t.Run("Struct+Struct", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWSTRUCT, opcode.NEWSTRUCT, true) })
|
||||
t.Run("Array+Struct", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWARRAY, opcode.NEWSTRUCT, false) })
|
||||
t.Run("Struct+Array", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWSTRUCT, opcode.NEWARRAY, false) })
|
||||
}
|
||||
|
||||
func TestREVERSEGoodOneElem(t *testing.T) {
|
||||
prog := makeProgram(opcode.DUP, opcode.REVERSE)
|
||||
func TestREVERSEITEMSGoodOneElem(t *testing.T) {
|
||||
prog := makeProgram(opcode.DUP, opcode.REVERSEITEMS)
|
||||
elements := []int{22}
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(1)
|
||||
|
@ -2588,13 +2670,13 @@ func TestREVERSEGoodOneElem(t *testing.T) {
|
|||
assert.Equal(t, int64(elements[0]), e.Int64())
|
||||
}
|
||||
|
||||
func TestREVERSEGoodStruct(t *testing.T) {
|
||||
func TestREVERSEITEMSGoodStruct(t *testing.T) {
|
||||
eodd := []int{22, 34, 42, 55, 81}
|
||||
even := []int{22, 34, 42, 55, 81, 99}
|
||||
eall := [][]int{eodd, even}
|
||||
|
||||
for _, elements := range eall {
|
||||
prog := makeProgram(opcode.DUP, opcode.REVERSE)
|
||||
prog := makeProgram(opcode.DUP, opcode.REVERSEITEMS)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(1)
|
||||
|
||||
|
@ -2616,13 +2698,13 @@ func TestREVERSEGoodStruct(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestREVERSEGood(t *testing.T) {
|
||||
func TestREVERSEITEMSGood(t *testing.T) {
|
||||
eodd := []int{22, 34, 42, 55, 81}
|
||||
even := []int{22, 34, 42, 55, 81, 99}
|
||||
eall := [][]int{eodd, even}
|
||||
|
||||
for _, elements := range eall {
|
||||
prog := makeProgram(opcode.DUP, opcode.REVERSE)
|
||||
prog := makeProgram(opcode.DUP, opcode.REVERSEITEMS)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(1)
|
||||
vm.estack.PushVal(elements)
|
||||
|
@ -2697,6 +2779,43 @@ func TestREMOVEMap(t *testing.T) {
|
|||
assert.Equal(t, makeStackItem(false), vm.estack.Pop().value)
|
||||
}
|
||||
|
||||
func testCLEARITEMS(t *testing.T, item StackItem) {
|
||||
prog := makeProgram(opcode.DUP, opcode.DUP, opcode.CLEARITEMS, opcode.SIZE)
|
||||
v := load(prog)
|
||||
v.estack.PushVal(item)
|
||||
runVM(t, v)
|
||||
require.Equal(t, 2, v.estack.Len())
|
||||
require.EqualValues(t, 2, v.size) // empty collection + it's size
|
||||
require.EqualValues(t, 0, v.estack.Pop().BigInt().Int64())
|
||||
}
|
||||
|
||||
func TestCLEARITEMS(t *testing.T) {
|
||||
arr := []StackItem{NewBigIntegerItem(big.NewInt(1)), NewByteArrayItem([]byte{1})}
|
||||
m := NewMapItem()
|
||||
m.Add(NewBigIntegerItem(big.NewInt(1)), NewByteArrayItem([]byte{}))
|
||||
m.Add(NewByteArrayItem([]byte{42}), NewBigIntegerItem(big.NewInt(2)))
|
||||
|
||||
testCases := map[string]StackItem{
|
||||
"empty Array": NewArrayItem([]StackItem{}),
|
||||
"filled Array": NewArrayItem(arr),
|
||||
"empty Struct": NewStructItem([]StackItem{}),
|
||||
"filled Struct": NewStructItem(arr),
|
||||
"empty Map": NewMapItem(),
|
||||
"filled Map": m,
|
||||
}
|
||||
|
||||
for name, item := range testCases {
|
||||
t.Run(name, func(t *testing.T) { testCLEARITEMS(t, item) })
|
||||
}
|
||||
|
||||
t.Run("Integer", func(t *testing.T) {
|
||||
prog := makeProgram(opcode.CLEARITEMS)
|
||||
v := load(prog)
|
||||
v.estack.PushVal(1)
|
||||
checkVMFailed(t, v)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSWAPGood(t *testing.T) {
|
||||
prog := makeProgram(opcode.SWAP)
|
||||
vm := load(prog)
|
||||
|
|
Loading…
Reference in a new issue