From a5f6e0e53db7f97a023eb0e9098dc5fe777424eb Mon Sep 17 00:00:00 2001
From: Evgenii Stratonikov <evgeniy@nspcc.ru>
Date: Tue, 12 May 2020 14:53:17 +0300
Subject: [PATCH] vm: implement NEWBUFFER opcode

---
 pkg/vm/opcode/opcode.go        |   9 +--
 pkg/vm/opcode/opcode_string.go | 116 +++++++++++++++++----------------
 pkg/vm/vm.go                   |   7 ++
 pkg/vm/vm_test.go              |   7 ++
 4 files changed, 78 insertions(+), 61 deletions(-)

diff --git a/pkg/vm/opcode/opcode.go b/pkg/vm/opcode/opcode.go
index 026e1b01e..9afaf8af9 100644
--- a/pkg/vm/opcode/opcode.go
+++ b/pkg/vm/opcode/opcode.go
@@ -146,10 +146,11 @@ const (
 	STARG     Opcode = 0x87
 
 	// Splice
-	CAT    Opcode = 0x8B
-	SUBSTR Opcode = 0x8C
-	LEFT   Opcode = 0x8D
-	RIGHT  Opcode = 0x8E
+	NEWBUFFER Opcode = 0x88
+	CAT       Opcode = 0x8B
+	SUBSTR    Opcode = 0x8C
+	LEFT      Opcode = 0x8D
+	RIGHT     Opcode = 0x8E
 
 	// Bitwise logic
 	INVERT   Opcode = 0x90
diff --git a/pkg/vm/opcode/opcode_string.go b/pkg/vm/opcode/opcode_string.go
index 74852c03e..3cc0757f4 100644
--- a/pkg/vm/opcode/opcode_string.go
+++ b/pkg/vm/opcode/opcode_string.go
@@ -132,6 +132,7 @@ func _() {
 	_ = x[STARG5-133]
 	_ = x[STARG6-134]
 	_ = x[STARG-135]
+	_ = x[NEWBUFFER-136]
 	_ = x[CAT-139]
 	_ = x[SUBSTR-140]
 	_ = x[LEFT-141]
@@ -190,7 +191,7 @@ func _() {
 	_ = x[CONVERT-219]
 }
 
-const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLCALLAABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENINITSSLOTINITSLOTLDSFLD0LDSFLD1LDSFLD2LDSFLD3LDSFLD4LDSFLD5LDSFLD6LDSFLDSTSFLD0STSFLD1STSFLD2STSFLD3STSFLD4STSFLD5STSFLD6STSFLDLDLOC0LDLOC1LDLOC2LDLOC3LDLOC4LDLOC5LDLOC6LDLOCSTLOC0STLOC1STLOC2STLOC3STLOC4STLOC5STLOC6STLOCLDARG0LDARG1LDARG2LDARG3LDARG4LDARG5LDARG6LDARGSTARG0STARG1STARG2STARG3STARG4STARG5STARG6STARGCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT"
+const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLCALLAABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENINITSSLOTINITSLOTLDSFLD0LDSFLD1LDSFLD2LDSFLD3LDSFLD4LDSFLD5LDSFLD6LDSFLDSTSFLD0STSFLD1STSFLD2STSFLD3STSFLD4STSFLD5STSFLD6STSFLDLDLOC0LDLOC1LDLOC2LDLOC3LDLOC4LDLOC5LDLOC6LDLOCSTLOC0STLOC1STLOC2STLOC3STLOC4STLOC5STLOC6STLOCLDARG0LDARG1LDARG2LDARG3LDARG4LDARG5LDARG6LDARGSTARG0STARG1STARG2STARG3STARG4STARG5STARG6STARGNEWBUFFERCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT"
 
 var _Opcode_map = map[Opcode]string{
 	0:   _Opcode_name[0:8],
@@ -314,62 +315,63 @@ var _Opcode_map = map[Opcode]string{
 	133: _Opcode_name[712:718],
 	134: _Opcode_name[718:724],
 	135: _Opcode_name[724:729],
-	139: _Opcode_name[729:732],
-	140: _Opcode_name[732:738],
-	141: _Opcode_name[738:742],
-	142: _Opcode_name[742:747],
-	144: _Opcode_name[747:753],
-	145: _Opcode_name[753:756],
-	146: _Opcode_name[756:758],
-	147: _Opcode_name[758:761],
-	151: _Opcode_name[761:766],
-	152: _Opcode_name[766:774],
-	153: _Opcode_name[774:778],
-	154: _Opcode_name[778:781],
-	155: _Opcode_name[781:787],
-	156: _Opcode_name[787:790],
-	157: _Opcode_name[790:793],
-	158: _Opcode_name[793:796],
-	159: _Opcode_name[796:799],
-	160: _Opcode_name[799:802],
-	161: _Opcode_name[802:805],
-	162: _Opcode_name[805:808],
-	168: _Opcode_name[808:811],
-	169: _Opcode_name[811:814],
-	170: _Opcode_name[814:817],
-	171: _Opcode_name[817:824],
-	172: _Opcode_name[824:830],
-	177: _Opcode_name[830:832],
-	179: _Opcode_name[832:840],
-	180: _Opcode_name[840:851],
-	181: _Opcode_name[851:853],
-	182: _Opcode_name[853:856],
-	183: _Opcode_name[856:858],
-	184: _Opcode_name[858:861],
-	185: _Opcode_name[861:864],
-	186: _Opcode_name[864:867],
-	187: _Opcode_name[867:873],
-	192: _Opcode_name[873:877],
-	193: _Opcode_name[877:883],
-	194: _Opcode_name[883:892],
-	195: _Opcode_name[892:900],
-	196: _Opcode_name[900:909],
-	197: _Opcode_name[909:919],
-	198: _Opcode_name[919:928],
-	200: _Opcode_name[928:934],
-	202: _Opcode_name[934:938],
-	203: _Opcode_name[938:944],
-	204: _Opcode_name[944:948],
-	205: _Opcode_name[948:954],
-	206: _Opcode_name[954:962],
-	207: _Opcode_name[962:968],
-	208: _Opcode_name[968:975],
-	209: _Opcode_name[975:987],
-	210: _Opcode_name[987:993],
-	211: _Opcode_name[993:1003],
-	216: _Opcode_name[1003:1009],
-	217: _Opcode_name[1009:1015],
-	219: _Opcode_name[1015:1022],
+	136: _Opcode_name[729:738],
+	139: _Opcode_name[738:741],
+	140: _Opcode_name[741:747],
+	141: _Opcode_name[747:751],
+	142: _Opcode_name[751:756],
+	144: _Opcode_name[756:762],
+	145: _Opcode_name[762:765],
+	146: _Opcode_name[765:767],
+	147: _Opcode_name[767:770],
+	151: _Opcode_name[770:775],
+	152: _Opcode_name[775:783],
+	153: _Opcode_name[783:787],
+	154: _Opcode_name[787:790],
+	155: _Opcode_name[790:796],
+	156: _Opcode_name[796:799],
+	157: _Opcode_name[799:802],
+	158: _Opcode_name[802:805],
+	159: _Opcode_name[805:808],
+	160: _Opcode_name[808:811],
+	161: _Opcode_name[811:814],
+	162: _Opcode_name[814:817],
+	168: _Opcode_name[817:820],
+	169: _Opcode_name[820:823],
+	170: _Opcode_name[823:826],
+	171: _Opcode_name[826:833],
+	172: _Opcode_name[833:839],
+	177: _Opcode_name[839:841],
+	179: _Opcode_name[841:849],
+	180: _Opcode_name[849:860],
+	181: _Opcode_name[860:862],
+	182: _Opcode_name[862:865],
+	183: _Opcode_name[865:867],
+	184: _Opcode_name[867:870],
+	185: _Opcode_name[870:873],
+	186: _Opcode_name[873:876],
+	187: _Opcode_name[876:882],
+	192: _Opcode_name[882:886],
+	193: _Opcode_name[886:892],
+	194: _Opcode_name[892:901],
+	195: _Opcode_name[901:909],
+	196: _Opcode_name[909:918],
+	197: _Opcode_name[918:928],
+	198: _Opcode_name[928:937],
+	200: _Opcode_name[937:943],
+	202: _Opcode_name[943:947],
+	203: _Opcode_name[947:953],
+	204: _Opcode_name[953:957],
+	205: _Opcode_name[957:963],
+	206: _Opcode_name[963:971],
+	207: _Opcode_name[971:977],
+	208: _Opcode_name[977:984],
+	209: _Opcode_name[984:996],
+	210: _Opcode_name[996:1002],
+	211: _Opcode_name[1002:1012],
+	216: _Opcode_name[1012:1018],
+	217: _Opcode_name[1018:1024],
+	219: _Opcode_name[1024:1031],
 }
 
 func (i Opcode) String() string {
diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go
index 904433d88..3af2446ec 100644
--- a/pkg/vm/vm.go
+++ b/pkg/vm/vm.go
@@ -635,6 +635,13 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
 		item := v.estack.Pop().Item()
 		ctx.arguments.Set(int(parameter[0]), item)
 
+	case opcode.NEWBUFFER:
+		n := toInt(v.estack.Pop().BigInt())
+		if n < 0 || n > MaxItemSize {
+			panic("invalid size")
+		}
+		v.estack.PushVal(NewBufferItem(make([]byte, n)))
+
 	case opcode.CAT:
 		b := v.estack.Pop().Bytes()
 		a := v.estack.Pop().Bytes()
diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go
index 07601f169..112be1e27 100644
--- a/pkg/vm/vm_test.go
+++ b/pkg/vm/vm_test.go
@@ -1154,6 +1154,13 @@ func TestDECBigResult(t *testing.T) {
 	checkVMFailed(t, vm)
 }
 
+func TestNEWBUFFER(t *testing.T) {
+	prog := makeProgram(opcode.NEWBUFFER)
+	t.Run("Good", getTestFuncForVM(prog, NewBufferItem([]byte{0, 0, 0}), 3))
+	t.Run("Negative", getTestFuncForVM(prog, nil, -1))
+	t.Run("TooBig", getTestFuncForVM(prog, nil, MaxItemSize+1))
+}
+
 func TestNEWARRAY0(t *testing.T) {
 	prog := makeProgram(opcode.NEWARRAY0)
 	runWithArgs(t, prog, []StackItem{})