diff --git a/pkg/vm/context.go b/pkg/vm/context.go index bcc7194dd..4c610ee9e 100644 --- a/pkg/vm/context.go +++ b/pkg/vm/context.go @@ -111,7 +111,7 @@ func (c *Context) Next() (opcode.Opcode, []byte, error) { numtoread = 1 case opcode.JMPL, opcode.JMPIFL, opcode.JMPIFNOTL, opcode.JMPEQL, opcode.JMPNEL, opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLTL, opcode.JMPLEL, - opcode.CALLL, opcode.SYSCALL: + opcode.CALLL, opcode.SYSCALL, opcode.PUSHA: numtoread = 4 default: if instr <= opcode.PUSHINT256 { diff --git a/pkg/vm/opcode/opcode.go b/pkg/vm/opcode/opcode.go index b6fcc13a1..b6641747f 100644 --- a/pkg/vm/opcode/opcode.go +++ b/pkg/vm/opcode/opcode.go @@ -15,6 +15,7 @@ const ( PUSHINT128 Opcode = 0x04 PUSHINT256 Opcode = 0x05 + PUSHA Opcode = 0x0A PUSHNULL Opcode = 0x0B PUSHDATA1 Opcode = 0x0C @@ -64,6 +65,7 @@ const ( JMPLEL Opcode = 0x33 CALL Opcode = 0x34 CALLL Opcode = 0x35 + CALLA Opcode = 0x36 // Exceptions ABORT Opcode = 0x37 diff --git a/pkg/vm/opcode/opcode_string.go b/pkg/vm/opcode/opcode_string.go index 5ff84b7b5..ad726d7e0 100644 --- a/pkg/vm/opcode/opcode_string.go +++ b/pkg/vm/opcode/opcode_string.go @@ -14,6 +14,7 @@ func _() { _ = x[PUSHINT64-3] _ = x[PUSHINT128-4] _ = x[PUSHINT256-5] + _ = x[PUSHA-10] _ = x[PUSHNULL-11] _ = x[PUSHDATA1-12] _ = x[PUSHDATA2-13] @@ -59,6 +60,7 @@ func _() { _ = x[JMPLEL-51] _ = x[CALL-52] _ = x[CALLL-53] + _ = x[CALLA-54] _ = x[ABORT-55] _ = x[ASSERT-56] _ = x[THROW-58] @@ -141,7 +143,7 @@ func _() { _ = x[CONVERT-219] } -const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENDUPFROMALTSTACKTOALTSTACKFROMALTSTACKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT" +const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLCALLAABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENDUPFROMALTSTACKTOALTSTACKFROMALTSTACKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT" var _Opcode_map = map[Opcode]string{ 0: _Opcode_name[0:8], @@ -150,128 +152,130 @@ var _Opcode_map = map[Opcode]string{ 3: _Opcode_name[26:35], 4: _Opcode_name[35:45], 5: _Opcode_name[45:55], - 11: _Opcode_name[55:63], - 12: _Opcode_name[63:72], - 13: _Opcode_name[72:81], - 14: _Opcode_name[81:90], - 15: _Opcode_name[90:96], - 16: _Opcode_name[96:101], - 17: _Opcode_name[101:106], - 18: _Opcode_name[106:111], - 19: _Opcode_name[111:116], - 20: _Opcode_name[116:121], - 21: _Opcode_name[121:126], - 22: _Opcode_name[126:131], - 23: _Opcode_name[131:136], - 24: _Opcode_name[136:141], - 25: _Opcode_name[141:146], - 26: _Opcode_name[146:152], - 27: _Opcode_name[152:158], - 28: _Opcode_name[158:164], - 29: _Opcode_name[164:170], - 30: _Opcode_name[170:176], - 31: _Opcode_name[176:182], - 32: _Opcode_name[182:188], - 33: _Opcode_name[188:191], - 34: _Opcode_name[191:194], - 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], - 55: _Opcode_name[301:306], - 56: _Opcode_name[306:312], - 58: _Opcode_name[312:317], - 64: _Opcode_name[317:320], - 65: _Opcode_name[320:327], - 67: _Opcode_name[327:332], - 69: _Opcode_name[332:336], - 70: _Opcode_name[336:339], - 72: _Opcode_name[339:344], - 73: _Opcode_name[344:349], - 74: _Opcode_name[349:352], - 75: _Opcode_name[352:356], - 77: _Opcode_name[356:360], - 78: _Opcode_name[360:364], - 80: _Opcode_name[364:368], - 81: _Opcode_name[368:376], - 82: _Opcode_name[376:380], - 83: _Opcode_name[380:388], - 84: _Opcode_name[388:396], - 85: _Opcode_name[396:404], - 106: _Opcode_name[404:419], - 107: _Opcode_name[419:429], - 108: _Opcode_name[429:441], - 126: _Opcode_name[441:444], - 127: _Opcode_name[444:450], - 128: _Opcode_name[450:454], - 129: _Opcode_name[454:459], - 144: _Opcode_name[459:465], - 145: _Opcode_name[465:468], - 146: _Opcode_name[468:470], - 147: _Opcode_name[470:473], - 151: _Opcode_name[473:478], - 152: _Opcode_name[478:486], - 153: _Opcode_name[486:490], - 154: _Opcode_name[490:493], - 155: _Opcode_name[493:499], - 156: _Opcode_name[499:502], - 157: _Opcode_name[502:505], - 158: _Opcode_name[505:508], - 159: _Opcode_name[508:511], - 160: _Opcode_name[511:514], - 161: _Opcode_name[514:517], - 162: _Opcode_name[517:520], - 168: _Opcode_name[520:523], - 169: _Opcode_name[523:526], - 170: _Opcode_name[526:529], - 171: _Opcode_name[529:536], - 172: _Opcode_name[536:542], - 177: _Opcode_name[542:544], - 179: _Opcode_name[544:552], - 180: _Opcode_name[552:563], - 181: _Opcode_name[563:565], - 182: _Opcode_name[565:568], - 183: _Opcode_name[568:570], - 184: _Opcode_name[570:573], - 185: _Opcode_name[573:576], - 186: _Opcode_name[576:579], - 187: _Opcode_name[579:585], - 192: _Opcode_name[585:589], - 193: _Opcode_name[589:595], - 194: _Opcode_name[595:604], - 195: _Opcode_name[604:612], - 196: _Opcode_name[612:621], - 197: _Opcode_name[621:631], - 198: _Opcode_name[631:640], - 200: _Opcode_name[640:646], - 202: _Opcode_name[646:650], - 203: _Opcode_name[650:656], - 204: _Opcode_name[656:660], - 205: _Opcode_name[660:666], - 206: _Opcode_name[666:674], - 207: _Opcode_name[674:680], - 208: _Opcode_name[680:687], - 209: _Opcode_name[687:699], - 210: _Opcode_name[699:705], - 211: _Opcode_name[705:715], - 216: _Opcode_name[715:721], - 217: _Opcode_name[721:727], - 219: _Opcode_name[727:734], + 10: _Opcode_name[55:60], + 11: _Opcode_name[60:68], + 12: _Opcode_name[68:77], + 13: _Opcode_name[77:86], + 14: _Opcode_name[86:95], + 15: _Opcode_name[95:101], + 16: _Opcode_name[101:106], + 17: _Opcode_name[106:111], + 18: _Opcode_name[111:116], + 19: _Opcode_name[116:121], + 20: _Opcode_name[121:126], + 21: _Opcode_name[126:131], + 22: _Opcode_name[131:136], + 23: _Opcode_name[136:141], + 24: _Opcode_name[141:146], + 25: _Opcode_name[146:151], + 26: _Opcode_name[151:157], + 27: _Opcode_name[157:163], + 28: _Opcode_name[163:169], + 29: _Opcode_name[169:175], + 30: _Opcode_name[175:181], + 31: _Opcode_name[181:187], + 32: _Opcode_name[187:193], + 33: _Opcode_name[193:196], + 34: _Opcode_name[196:199], + 35: _Opcode_name[199:203], + 36: _Opcode_name[203:208], + 37: _Opcode_name[208:214], + 38: _Opcode_name[214:222], + 39: _Opcode_name[222:231], + 40: _Opcode_name[231:236], + 41: _Opcode_name[236:242], + 42: _Opcode_name[242:247], + 43: _Opcode_name[247:253], + 44: _Opcode_name[253:258], + 45: _Opcode_name[258:264], + 46: _Opcode_name[264:269], + 47: _Opcode_name[269:275], + 48: _Opcode_name[275:280], + 49: _Opcode_name[280:286], + 50: _Opcode_name[286:291], + 51: _Opcode_name[291:297], + 52: _Opcode_name[297:301], + 53: _Opcode_name[301:306], + 54: _Opcode_name[306:311], + 55: _Opcode_name[311:316], + 56: _Opcode_name[316:322], + 58: _Opcode_name[322:327], + 64: _Opcode_name[327:330], + 65: _Opcode_name[330:337], + 67: _Opcode_name[337:342], + 69: _Opcode_name[342:346], + 70: _Opcode_name[346:349], + 72: _Opcode_name[349:354], + 73: _Opcode_name[354:359], + 74: _Opcode_name[359:362], + 75: _Opcode_name[362:366], + 77: _Opcode_name[366:370], + 78: _Opcode_name[370:374], + 80: _Opcode_name[374:378], + 81: _Opcode_name[378:386], + 82: _Opcode_name[386:390], + 83: _Opcode_name[390:398], + 84: _Opcode_name[398:406], + 85: _Opcode_name[406:414], + 106: _Opcode_name[414:429], + 107: _Opcode_name[429:439], + 108: _Opcode_name[439:451], + 126: _Opcode_name[451:454], + 127: _Opcode_name[454:460], + 128: _Opcode_name[460:464], + 129: _Opcode_name[464:469], + 144: _Opcode_name[469:475], + 145: _Opcode_name[475:478], + 146: _Opcode_name[478:480], + 147: _Opcode_name[480:483], + 151: _Opcode_name[483:488], + 152: _Opcode_name[488:496], + 153: _Opcode_name[496:500], + 154: _Opcode_name[500:503], + 155: _Opcode_name[503:509], + 156: _Opcode_name[509:512], + 157: _Opcode_name[512:515], + 158: _Opcode_name[515:518], + 159: _Opcode_name[518:521], + 160: _Opcode_name[521:524], + 161: _Opcode_name[524:527], + 162: _Opcode_name[527:530], + 168: _Opcode_name[530:533], + 169: _Opcode_name[533:536], + 170: _Opcode_name[536:539], + 171: _Opcode_name[539:546], + 172: _Opcode_name[546:552], + 177: _Opcode_name[552:554], + 179: _Opcode_name[554:562], + 180: _Opcode_name[562:573], + 181: _Opcode_name[573:575], + 182: _Opcode_name[575:578], + 183: _Opcode_name[578:580], + 184: _Opcode_name[580:583], + 185: _Opcode_name[583:586], + 186: _Opcode_name[586:589], + 187: _Opcode_name[589:595], + 192: _Opcode_name[595:599], + 193: _Opcode_name[599:605], + 194: _Opcode_name[605:614], + 195: _Opcode_name[614:622], + 196: _Opcode_name[622:631], + 197: _Opcode_name[631:641], + 198: _Opcode_name[641:650], + 200: _Opcode_name[650:656], + 202: _Opcode_name[656:660], + 203: _Opcode_name[660:666], + 204: _Opcode_name[666:670], + 205: _Opcode_name[670:676], + 206: _Opcode_name[676:684], + 207: _Opcode_name[684:690], + 208: _Opcode_name[690:697], + 209: _Opcode_name[697:709], + 210: _Opcode_name[709:715], + 211: _Opcode_name[715:725], + 216: _Opcode_name[725:731], + 217: _Opcode_name[731:737], + 219: _Opcode_name[737:744], } func (i Opcode) String() string { diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index da444962b..694ae147c 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -198,6 +198,9 @@ func (v *VM) PrintOps() { case opcode.JMP, opcode.JMPIF, opcode.JMPIFNOT, opcode.CALL: offset := int16(binary.LittleEndian.Uint16(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: desc = fmt.Sprintf("%q", parameter) 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: 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: 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) 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: interopID := GetInteropID(parameter) ifunc := v.GetInteropByID(interopID) diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index a031fc2eb..5a313bfa5 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -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) { prog := makeProgram(opcode.NOT) t.Run("Bool", getTestFuncForVM(prog, true, false))