vm: implement PUSHA/CALLA opcodes

This commit is contained in:
Evgenii Stratonikov 2020-05-06 16:55:30 +03:00
parent 7fcd537b09
commit 1d3fb3d6f5
5 changed files with 167 additions and 124 deletions

View file

@ -111,7 +111,7 @@ func (c *Context) Next() (opcode.Opcode, []byte, error) {
numtoread = 1 numtoread = 1
case opcode.JMPL, opcode.JMPIFL, opcode.JMPIFNOTL, opcode.JMPEQL, opcode.JMPNEL, case opcode.JMPL, opcode.JMPIFL, opcode.JMPIFNOTL, opcode.JMPEQL, opcode.JMPNEL,
opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLTL, opcode.JMPLEL, opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLTL, opcode.JMPLEL,
opcode.CALLL, opcode.SYSCALL: opcode.CALLL, opcode.SYSCALL, opcode.PUSHA:
numtoread = 4 numtoread = 4
default: default:
if instr <= opcode.PUSHINT256 { if instr <= opcode.PUSHINT256 {

View file

@ -15,6 +15,7 @@ const (
PUSHINT128 Opcode = 0x04 PUSHINT128 Opcode = 0x04
PUSHINT256 Opcode = 0x05 PUSHINT256 Opcode = 0x05
PUSHA Opcode = 0x0A
PUSHNULL Opcode = 0x0B PUSHNULL Opcode = 0x0B
PUSHDATA1 Opcode = 0x0C PUSHDATA1 Opcode = 0x0C
@ -64,6 +65,7 @@ const (
JMPLEL Opcode = 0x33 JMPLEL Opcode = 0x33
CALL Opcode = 0x34 CALL Opcode = 0x34
CALLL Opcode = 0x35 CALLL Opcode = 0x35
CALLA Opcode = 0x36
// Exceptions // Exceptions
ABORT Opcode = 0x37 ABORT Opcode = 0x37

View file

@ -14,6 +14,7 @@ func _() {
_ = x[PUSHINT64-3] _ = x[PUSHINT64-3]
_ = x[PUSHINT128-4] _ = x[PUSHINT128-4]
_ = x[PUSHINT256-5] _ = x[PUSHINT256-5]
_ = x[PUSHA-10]
_ = x[PUSHNULL-11] _ = x[PUSHNULL-11]
_ = x[PUSHDATA1-12] _ = x[PUSHDATA1-12]
_ = x[PUSHDATA2-13] _ = x[PUSHDATA2-13]
@ -59,6 +60,7 @@ func _() {
_ = x[JMPLEL-51] _ = x[JMPLEL-51]
_ = x[CALL-52] _ = x[CALL-52]
_ = x[CALLL-53] _ = x[CALLL-53]
_ = x[CALLA-54]
_ = x[ABORT-55] _ = x[ABORT-55]
_ = x[ASSERT-56] _ = x[ASSERT-56]
_ = x[THROW-58] _ = x[THROW-58]
@ -141,7 +143,7 @@ func _() {
_ = x[CONVERT-219] _ = x[CONVERT-219]
} }
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENDUPFROMALTSTACKTOALTSTACKFROMALTSTACKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT" const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLCALLAABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENDUPFROMALTSTACKTOALTSTACKFROMALTSTACKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT"
var _Opcode_map = map[Opcode]string{ var _Opcode_map = map[Opcode]string{
0: _Opcode_name[0:8], 0: _Opcode_name[0:8],
@ -150,128 +152,130 @@ var _Opcode_map = map[Opcode]string{
3: _Opcode_name[26:35], 3: _Opcode_name[26:35],
4: _Opcode_name[35:45], 4: _Opcode_name[35:45],
5: _Opcode_name[45:55], 5: _Opcode_name[45:55],
11: _Opcode_name[55:63], 10: _Opcode_name[55:60],
12: _Opcode_name[63:72], 11: _Opcode_name[60:68],
13: _Opcode_name[72:81], 12: _Opcode_name[68:77],
14: _Opcode_name[81:90], 13: _Opcode_name[77:86],
15: _Opcode_name[90:96], 14: _Opcode_name[86:95],
16: _Opcode_name[96:101], 15: _Opcode_name[95:101],
17: _Opcode_name[101:106], 16: _Opcode_name[101:106],
18: _Opcode_name[106:111], 17: _Opcode_name[106:111],
19: _Opcode_name[111:116], 18: _Opcode_name[111:116],
20: _Opcode_name[116:121], 19: _Opcode_name[116:121],
21: _Opcode_name[121:126], 20: _Opcode_name[121:126],
22: _Opcode_name[126:131], 21: _Opcode_name[126:131],
23: _Opcode_name[131:136], 22: _Opcode_name[131:136],
24: _Opcode_name[136:141], 23: _Opcode_name[136:141],
25: _Opcode_name[141:146], 24: _Opcode_name[141:146],
26: _Opcode_name[146:152], 25: _Opcode_name[146:151],
27: _Opcode_name[152:158], 26: _Opcode_name[151:157],
28: _Opcode_name[158:164], 27: _Opcode_name[157:163],
29: _Opcode_name[164:170], 28: _Opcode_name[163:169],
30: _Opcode_name[170:176], 29: _Opcode_name[169:175],
31: _Opcode_name[176:182], 30: _Opcode_name[175:181],
32: _Opcode_name[182:188], 31: _Opcode_name[181:187],
33: _Opcode_name[188:191], 32: _Opcode_name[187:193],
34: _Opcode_name[191:194], 33: _Opcode_name[193:196],
35: _Opcode_name[194:198], 34: _Opcode_name[196:199],
36: _Opcode_name[198:203], 35: _Opcode_name[199:203],
37: _Opcode_name[203:209], 36: _Opcode_name[203:208],
38: _Opcode_name[209:217], 37: _Opcode_name[208:214],
39: _Opcode_name[217:226], 38: _Opcode_name[214:222],
40: _Opcode_name[226:231], 39: _Opcode_name[222:231],
41: _Opcode_name[231:237], 40: _Opcode_name[231:236],
42: _Opcode_name[237:242], 41: _Opcode_name[236:242],
43: _Opcode_name[242:248], 42: _Opcode_name[242:247],
44: _Opcode_name[248:253], 43: _Opcode_name[247:253],
45: _Opcode_name[253:259], 44: _Opcode_name[253:258],
46: _Opcode_name[259:264], 45: _Opcode_name[258:264],
47: _Opcode_name[264:270], 46: _Opcode_name[264:269],
48: _Opcode_name[270:275], 47: _Opcode_name[269:275],
49: _Opcode_name[275:281], 48: _Opcode_name[275:280],
50: _Opcode_name[281:286], 49: _Opcode_name[280:286],
51: _Opcode_name[286:292], 50: _Opcode_name[286:291],
52: _Opcode_name[292:296], 51: _Opcode_name[291:297],
53: _Opcode_name[296:301], 52: _Opcode_name[297:301],
55: _Opcode_name[301:306], 53: _Opcode_name[301:306],
56: _Opcode_name[306:312], 54: _Opcode_name[306:311],
58: _Opcode_name[312:317], 55: _Opcode_name[311:316],
64: _Opcode_name[317:320], 56: _Opcode_name[316:322],
65: _Opcode_name[320:327], 58: _Opcode_name[322:327],
67: _Opcode_name[327:332], 64: _Opcode_name[327:330],
69: _Opcode_name[332:336], 65: _Opcode_name[330:337],
70: _Opcode_name[336:339], 67: _Opcode_name[337:342],
72: _Opcode_name[339:344], 69: _Opcode_name[342:346],
73: _Opcode_name[344:349], 70: _Opcode_name[346:349],
74: _Opcode_name[349:352], 72: _Opcode_name[349:354],
75: _Opcode_name[352:356], 73: _Opcode_name[354:359],
77: _Opcode_name[356:360], 74: _Opcode_name[359:362],
78: _Opcode_name[360:364], 75: _Opcode_name[362:366],
80: _Opcode_name[364:368], 77: _Opcode_name[366:370],
81: _Opcode_name[368:376], 78: _Opcode_name[370:374],
82: _Opcode_name[376:380], 80: _Opcode_name[374:378],
83: _Opcode_name[380:388], 81: _Opcode_name[378:386],
84: _Opcode_name[388:396], 82: _Opcode_name[386:390],
85: _Opcode_name[396:404], 83: _Opcode_name[390:398],
106: _Opcode_name[404:419], 84: _Opcode_name[398:406],
107: _Opcode_name[419:429], 85: _Opcode_name[406:414],
108: _Opcode_name[429:441], 106: _Opcode_name[414:429],
126: _Opcode_name[441:444], 107: _Opcode_name[429:439],
127: _Opcode_name[444:450], 108: _Opcode_name[439:451],
128: _Opcode_name[450:454], 126: _Opcode_name[451:454],
129: _Opcode_name[454:459], 127: _Opcode_name[454:460],
144: _Opcode_name[459:465], 128: _Opcode_name[460:464],
145: _Opcode_name[465:468], 129: _Opcode_name[464:469],
146: _Opcode_name[468:470], 144: _Opcode_name[469:475],
147: _Opcode_name[470:473], 145: _Opcode_name[475:478],
151: _Opcode_name[473:478], 146: _Opcode_name[478:480],
152: _Opcode_name[478:486], 147: _Opcode_name[480:483],
153: _Opcode_name[486:490], 151: _Opcode_name[483:488],
154: _Opcode_name[490:493], 152: _Opcode_name[488:496],
155: _Opcode_name[493:499], 153: _Opcode_name[496:500],
156: _Opcode_name[499:502], 154: _Opcode_name[500:503],
157: _Opcode_name[502:505], 155: _Opcode_name[503:509],
158: _Opcode_name[505:508], 156: _Opcode_name[509:512],
159: _Opcode_name[508:511], 157: _Opcode_name[512:515],
160: _Opcode_name[511:514], 158: _Opcode_name[515:518],
161: _Opcode_name[514:517], 159: _Opcode_name[518:521],
162: _Opcode_name[517:520], 160: _Opcode_name[521:524],
168: _Opcode_name[520:523], 161: _Opcode_name[524:527],
169: _Opcode_name[523:526], 162: _Opcode_name[527:530],
170: _Opcode_name[526:529], 168: _Opcode_name[530:533],
171: _Opcode_name[529:536], 169: _Opcode_name[533:536],
172: _Opcode_name[536:542], 170: _Opcode_name[536:539],
177: _Opcode_name[542:544], 171: _Opcode_name[539:546],
179: _Opcode_name[544:552], 172: _Opcode_name[546:552],
180: _Opcode_name[552:563], 177: _Opcode_name[552:554],
181: _Opcode_name[563:565], 179: _Opcode_name[554:562],
182: _Opcode_name[565:568], 180: _Opcode_name[562:573],
183: _Opcode_name[568:570], 181: _Opcode_name[573:575],
184: _Opcode_name[570:573], 182: _Opcode_name[575:578],
185: _Opcode_name[573:576], 183: _Opcode_name[578:580],
186: _Opcode_name[576:579], 184: _Opcode_name[580:583],
187: _Opcode_name[579:585], 185: _Opcode_name[583:586],
192: _Opcode_name[585:589], 186: _Opcode_name[586:589],
193: _Opcode_name[589:595], 187: _Opcode_name[589:595],
194: _Opcode_name[595:604], 192: _Opcode_name[595:599],
195: _Opcode_name[604:612], 193: _Opcode_name[599:605],
196: _Opcode_name[612:621], 194: _Opcode_name[605:614],
197: _Opcode_name[621:631], 195: _Opcode_name[614:622],
198: _Opcode_name[631:640], 196: _Opcode_name[622:631],
200: _Opcode_name[640:646], 197: _Opcode_name[631:641],
202: _Opcode_name[646:650], 198: _Opcode_name[641:650],
203: _Opcode_name[650:656], 200: _Opcode_name[650:656],
204: _Opcode_name[656:660], 202: _Opcode_name[656:660],
205: _Opcode_name[660:666], 203: _Opcode_name[660:666],
206: _Opcode_name[666:674], 204: _Opcode_name[666:670],
207: _Opcode_name[674:680], 205: _Opcode_name[670:676],
208: _Opcode_name[680:687], 206: _Opcode_name[676:684],
209: _Opcode_name[687:699], 207: _Opcode_name[684:690],
210: _Opcode_name[699:705], 208: _Opcode_name[690:697],
211: _Opcode_name[705:715], 209: _Opcode_name[697:709],
216: _Opcode_name[715:721], 210: _Opcode_name[709:715],
217: _Opcode_name[721:727], 211: _Opcode_name[715:725],
219: _Opcode_name[727:734], 216: _Opcode_name[725:731],
217: _Opcode_name[731:737],
219: _Opcode_name[737:744],
} }
func (i Opcode) String() string { func (i Opcode) String() string {

View file

@ -198,6 +198,9 @@ func (v *VM) PrintOps() {
case opcode.JMP, opcode.JMPIF, opcode.JMPIFNOT, opcode.CALL: case opcode.JMP, opcode.JMPIF, opcode.JMPIFNOT, opcode.CALL:
offset := int16(binary.LittleEndian.Uint16(parameter)) offset := int16(binary.LittleEndian.Uint16(parameter))
desc = fmt.Sprintf("%d (%d/%x)", ctx.ip+int(offset), offset, parameter) desc = fmt.Sprintf("%d (%d/%x)", ctx.ip+int(offset), offset, parameter)
case opcode.PUSHA:
offset := int32(binary.LittleEndian.Uint32(parameter))
desc = fmt.Sprintf("%d (%x)", offset, parameter)
case opcode.SYSCALL: case opcode.SYSCALL:
desc = fmt.Sprintf("%q", parameter) desc = fmt.Sprintf("%q", parameter)
default: default:
@ -529,6 +532,14 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
case opcode.PUSHDATA1, opcode.PUSHDATA2, opcode.PUSHDATA4: case opcode.PUSHDATA1, opcode.PUSHDATA2, opcode.PUSHDATA4:
v.estack.PushVal(parameter) v.estack.PushVal(parameter)
case opcode.PUSHA:
n := int32(binary.LittleEndian.Uint32(parameter))
if n < 0 || int(n) > len(ctx.prog) {
panic(fmt.Sprintf("invalid pointer offset (%d)", n))
}
ptr := NewPointerItem(int(n), ctx.prog)
v.estack.PushVal(ptr)
case opcode.PUSHNULL: case opcode.PUSHNULL:
v.estack.PushVal(NullItem{}) v.estack.PushVal(NullItem{})
@ -1134,6 +1145,17 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
offset := v.getJumpOffset(newCtx, parameter, 0) offset := v.getJumpOffset(newCtx, parameter, 0)
v.jumpIf(newCtx, offset, true) v.jumpIf(newCtx, offset, true)
case opcode.CALLA:
ptr := v.estack.Pop().Item().(*PointerItem)
if ptr.hash != ctx.ScriptHash() {
panic("invalid script in pointer")
}
newCtx := ctx.Copy()
newCtx.rvcount = -1
v.istack.PushVal(newCtx)
v.jumpIf(newCtx, ptr.pos, true)
case opcode.SYSCALL: case opcode.SYSCALL:
interopID := GetInteropID(parameter) interopID := GetInteropID(parameter)
ifunc := v.GetInteropByID(interopID) ifunc := v.GetInteropByID(interopID)

View file

@ -909,6 +909,21 @@ func TestJMPs(t *testing.T) {
} }
} }
func TestPUSHA(t *testing.T) {
t.Run("Negative", getTestFuncForVM(makeProgram(opcode.PUSHA, 0xFF, 0xFF, 0xFF, 0xFF), nil))
t.Run("TooBig", getTestFuncForVM(makeProgram(opcode.PUSHA, 10, 0, 0, 0), nil))
t.Run("Good", func(t *testing.T) {
prog := makeProgram(opcode.PUSHA, 2, 0, 0, 0)
runWithArgs(t, prog, NewPointerItem(2, prog))
})
}
func TestCALLA(t *testing.T) {
prog := makeProgram(opcode.CALLA, opcode.PUSH2, opcode.ADD, opcode.RET, opcode.PUSH3, opcode.RET)
t.Run("InvalidScript", getTestFuncForVM(prog, nil, NewPointerItem(4, []byte{1})))
t.Run("Good", getTestFuncForVM(prog, 5, NewPointerItem(4, prog)))
}
func TestNOT(t *testing.T) { func TestNOT(t *testing.T) {
prog := makeProgram(opcode.NOT) prog := makeProgram(opcode.NOT)
t.Run("Bool", getTestFuncForVM(prog, true, false)) t.Run("Bool", getTestFuncForVM(prog, true, false))