vm: implement POW opcode

This commit is contained in:
Evgeniy Stratonikov 2021-03-01 12:22:22 +03:00
parent 347212c0c5
commit 6496782736
5 changed files with 61 additions and 38 deletions

View file

@ -162,6 +162,7 @@ var coefficients = map[opcode.Opcode]int64{
opcode.MUL: 1 << 3, opcode.MUL: 1 << 3,
opcode.DIV: 1 << 3, opcode.DIV: 1 << 3,
opcode.MOD: 1 << 3, opcode.MOD: 1 << 3,
opcode.POW: 1 << 6,
opcode.SHL: 1 << 3, opcode.SHL: 1 << 3,
opcode.SHR: 1 << 3, opcode.SHR: 1 << 3,
opcode.NOT: 1 << 2, opcode.NOT: 1 << 2,

View file

@ -177,6 +177,7 @@ const (
MUL Opcode = 0xA0 MUL Opcode = 0xA0
DIV Opcode = 0xA1 DIV Opcode = 0xA1
MOD Opcode = 0xA2 MOD Opcode = 0xA2
POW Opcode = 0xA3
SHL Opcode = 0xA8 SHL Opcode = 0xA8
SHR Opcode = 0xA9 SHR Opcode = 0xA9
NOT Opcode = 0xAA NOT Opcode = 0xAA

View file

@ -159,6 +159,7 @@ func _() {
_ = x[MUL-160] _ = x[MUL-160]
_ = x[DIV-161] _ = x[DIV-161]
_ = x[MOD-162] _ = x[MOD-162]
_ = x[POW-163]
_ = x[SHL-168] _ = x[SHL-168]
_ = x[SHR-169] _ = x[SHR-169]
_ = x[NOT-170] _ = x[NOT-170]
@ -198,7 +199,7 @@ func _() {
_ = x[CONVERT-219] _ = x[CONVERT-219]
} }
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMP_LJMPIFJMPIF_LJMPIFNOTJMPIFNOT_LJMPEQJMPEQ_LJMPNEJMPNE_LJMPGTJMPGT_LJMPGEJMPGE_LJMPLTJMPLT_LJMPLEJMPLE_LCALLCALL_LCALLACALLTABORTASSERTTHROWTRYTRY_LENDTRYENDTRY_LENDFINALLYRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPROTROLLREVERSE3REVERSE4REVERSENINITSSLOTINITSLOTLDSFLD0LDSFLD1LDSFLD2LDSFLD3LDSFLD4LDSFLD5LDSFLD6LDSFLDSTSFLD0STSFLD1STSFLD2STSFLD3STSFLD4STSFLD5STSFLD6STSFLDLDLOC0LDLOC1LDLOC2LDLOC3LDLOC4LDLOC5LDLOC6LDLOCSTLOC0STLOC1STLOC2STLOC3STLOC4STLOC5STLOC6STLOCLDARG0LDARG1LDARG2LDARG3LDARG4LDARG5LDARG6LDARGSTARG0STARG1STARG2STARG3STARG4STARG5STARG6STARGNEWBUFFERMEMCPYCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAY_TNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSPOPITEMISNULLISTYPECONVERT" const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMP_LJMPIFJMPIF_LJMPIFNOTJMPIFNOT_LJMPEQJMPEQ_LJMPNEJMPNE_LJMPGTJMPGT_LJMPGEJMPGE_LJMPLTJMPLT_LJMPLEJMPLE_LCALLCALL_LCALLACALLTABORTASSERTTHROWTRYTRY_LENDTRYENDTRY_LENDFINALLYRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPROTROLLREVERSE3REVERSE4REVERSENINITSSLOTINITSLOTLDSFLD0LDSFLD1LDSFLD2LDSFLD3LDSFLD4LDSFLD5LDSFLD6LDSFLDSTSFLD0STSFLD1STSFLD2STSFLD3STSFLD4STSFLD5STSFLD6STSFLDLDLOC0LDLOC1LDLOC2LDLOC3LDLOC4LDLOC5LDLOC6LDLOCSTLOC0STLOC1STLOC2STLOC3STLOC4STLOC5STLOC6STLOCLDARG0LDARG1LDARG2LDARG3LDARG4LDARG5LDARG6LDARGSTARG0STARG1STARG2STARG3STARG4STARG5STARG6STARGNEWBUFFERMEMCPYCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODPOWSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAY_TNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSPOPITEMISNULLISTYPECONVERT"
var _Opcode_map = map[Opcode]string{ var _Opcode_map = map[Opcode]string{
0: _Opcode_name[0:8], 0: _Opcode_name[0:8],
@ -350,43 +351,44 @@ var _Opcode_map = map[Opcode]string{
160: _Opcode_name[856:859], 160: _Opcode_name[856:859],
161: _Opcode_name[859:862], 161: _Opcode_name[859:862],
162: _Opcode_name[862:865], 162: _Opcode_name[862:865],
168: _Opcode_name[865:868], 163: _Opcode_name[865:868],
169: _Opcode_name[868:871], 168: _Opcode_name[868:871],
170: _Opcode_name[871:874], 169: _Opcode_name[871:874],
171: _Opcode_name[874:881], 170: _Opcode_name[874:877],
172: _Opcode_name[881:887], 171: _Opcode_name[877:884],
177: _Opcode_name[887:889], 172: _Opcode_name[884:890],
179: _Opcode_name[889:897], 177: _Opcode_name[890:892],
180: _Opcode_name[897:908], 179: _Opcode_name[892:900],
181: _Opcode_name[908:910], 180: _Opcode_name[900:911],
182: _Opcode_name[910:913], 181: _Opcode_name[911:913],
183: _Opcode_name[913:915], 182: _Opcode_name[913:916],
184: _Opcode_name[915:918], 183: _Opcode_name[916:918],
185: _Opcode_name[918:921], 184: _Opcode_name[918:921],
186: _Opcode_name[921:924], 185: _Opcode_name[921:924],
187: _Opcode_name[924:930], 186: _Opcode_name[924:927],
192: _Opcode_name[930:934], 187: _Opcode_name[927:933],
193: _Opcode_name[934:940], 192: _Opcode_name[933:937],
194: _Opcode_name[940:949], 193: _Opcode_name[937:943],
195: _Opcode_name[949:957], 194: _Opcode_name[943:952],
196: _Opcode_name[957:967], 195: _Opcode_name[952:960],
197: _Opcode_name[967:977], 196: _Opcode_name[960:970],
198: _Opcode_name[977:986], 197: _Opcode_name[970:980],
200: _Opcode_name[986:992], 198: _Opcode_name[980:989],
202: _Opcode_name[992:996], 200: _Opcode_name[989:995],
203: _Opcode_name[996:1002], 202: _Opcode_name[995:999],
204: _Opcode_name[1002:1006], 203: _Opcode_name[999:1005],
205: _Opcode_name[1006:1012], 204: _Opcode_name[1005:1009],
206: _Opcode_name[1012:1020], 205: _Opcode_name[1009:1015],
207: _Opcode_name[1020:1026], 206: _Opcode_name[1015:1023],
208: _Opcode_name[1026:1033], 207: _Opcode_name[1023:1029],
209: _Opcode_name[1033:1045], 208: _Opcode_name[1029:1036],
210: _Opcode_name[1045:1051], 209: _Opcode_name[1036:1048],
211: _Opcode_name[1051:1061], 210: _Opcode_name[1048:1054],
212: _Opcode_name[1061:1068], 211: _Opcode_name[1054:1064],
216: _Opcode_name[1068:1074], 212: _Opcode_name[1064:1071],
217: _Opcode_name[1074:1080], 216: _Opcode_name[1071:1077],
219: _Opcode_name[1080:1087], 217: _Opcode_name[1077:1083],
219: _Opcode_name[1083:1090],
} }
func (i Opcode) String() string { func (i Opcode) String() string {

View file

@ -910,6 +910,14 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
v.estack.PushVal(new(big.Int).Rem(a, b)) v.estack.PushVal(new(big.Int).Rem(a, b))
case opcode.POW:
exp := v.estack.Pop().BigInt()
a := v.estack.Pop().BigInt()
if ei := exp.Int64(); !exp.IsInt64() || ei > math.MaxInt32 || ei < 0 {
panic("invalid exponent")
}
v.estack.PushVal(new(big.Int).Exp(a, exp, nil))
case opcode.SHL, opcode.SHR: case opcode.SHL, opcode.SHR:
b := v.estack.Pop().BigInt().Int64() b := v.estack.Pop().BigInt().Int64()
if b == 0 { if b == 0 {

View file

@ -6,6 +6,7 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"math"
"math/big" "math/big"
"math/rand" "math/rand"
"testing" "testing"
@ -935,6 +936,16 @@ func TestSUBBigResult(t *testing.T) {
runWithArgs(t, prog, nil, -2, bi) runWithArgs(t, prog, nil, -2, bi)
} }
func TestPOW(t *testing.T) {
prog := makeProgram(opcode.POW)
t.Run("good, positive", getTestFuncForVM(prog, 9, 3, 2))
t.Run("good, negative, even", getTestFuncForVM(prog, 4, -2, 2))
t.Run("good, negative, odd", getTestFuncForVM(prog, -8, -2, 3))
t.Run("zero", getTestFuncForVM(prog, 1, 3, 0))
t.Run("negative exponent", getTestFuncForVM(prog, nil, 3, -1))
t.Run("too big exponent", getTestFuncForVM(prog, nil, 1, math.MaxInt32+1))
}
func TestSHR(t *testing.T) { func TestSHR(t *testing.T) {
prog := makeProgram(opcode.SHR) prog := makeProgram(opcode.SHR)
t.Run("Good", getTestFuncForVM(prog, 1, 4, 2)) t.Run("Good", getTestFuncForVM(prog, 1, 4, 2))