diff --git a/go.sum b/go.sum index 68831bf15..9747c253e 100644 --- a/go.sum +++ b/go.sum @@ -129,16 +129,8 @@ github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a h1:ajvxgEe9qY4vvoSm github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a/go.mod h1:/YFK+XOxxg0Bfm6P92lY5eDSLYfp06XOdL8KAVgXjVk= github.com/nspcc-dev/dbft v0.0.0-20200219114139-199d286ed6c1 h1:yEx9WznS+rjE0jl0dLujCxuZSIb+UTjF+005TJu/nNI= github.com/nspcc-dev/dbft v0.0.0-20200219114139-199d286ed6c1/go.mod h1:O0qtn62prQSqizzoagHmuuKoz8QMkU3SzBoKdEvm3aQ= -github.com/nspcc-dev/dbft v0.0.0-20200303183127-36d3da79c682 h1:63OWUolW4GcjJR7cThq8hLnMLTwL+sjO3Qf4fo4sx8w= -github.com/nspcc-dev/dbft v0.0.0-20200303183127-36d3da79c682/go.mod h1:1FYQXSbb6/9HQIkoF8XO7W/S8N7AZRkBsgwbcXRvk0E= github.com/nspcc-dev/dbft v0.0.0-20200427132226-05feeca847dd h1:4XKbXahJWlhjVx2cETQz9edHQfe3BQ2JjNdvSKFBelY= github.com/nspcc-dev/dbft v0.0.0-20200427132226-05feeca847dd/go.mod h1:1FYQXSbb6/9HQIkoF8XO7W/S8N7AZRkBsgwbcXRvk0E= -github.com/nspcc-dev/dbft v0.0.0-20200427132226-15a7927772a4 h1:3cFSp4v2u9+S7K1GdLUOP1680EiGEHSBvSI6G2n8XzY= -github.com/nspcc-dev/dbft v0.0.0-20200427132226-15a7927772a4/go.mod h1:1FYQXSbb6/9HQIkoF8XO7W/S8N7AZRkBsgwbcXRvk0E= -github.com/nspcc-dev/dbft v0.0.0-20200427132226-342f23599814 h1:iNqBioi0RU2VX9UiGl/GfQKBbZrDWq5KSxQG+dgTaqo= -github.com/nspcc-dev/dbft v0.0.0-20200427132226-342f23599814/go.mod h1:1FYQXSbb6/9HQIkoF8XO7W/S8N7AZRkBsgwbcXRvk0E= -github.com/nspcc-dev/dbft v0.0.0-20200427132226-660464796c11 h1:sledsmRo0wzgWNCZir5/CeM0PjhHVP8khnGtOfBCFWk= -github.com/nspcc-dev/dbft v0.0.0-20200427132226-660464796c11/go.mod h1:1FYQXSbb6/9HQIkoF8XO7W/S8N7AZRkBsgwbcXRvk0E= github.com/nspcc-dev/neo-go v0.73.1-pre.0.20200303142215-f5a1b928ce09/go.mod h1:pPYwPZ2ks+uMnlRLUyXOpLieaDQSEaf4NM3zHVbRjmg= github.com/nspcc-dev/neofs-crypto v0.2.0 h1:ftN+59WqxSWz/RCgXYOfhmltOOqU+udsNQSvN6wkFck= github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA= diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 3ddcb1ecc..d91cdf759 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -616,8 +616,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { case n.Op == token.NEQ: // VM has separate opcodes for number and string equality if isStringType(c.typeInfo.Types[n.X].Type) { - emit.Opcode(c.prog.BinWriter, opcode.EQUAL) - emit.Opcode(c.prog.BinWriter, opcode.NOT) + emit.Opcode(c.prog.BinWriter, opcode.NOTEQUAL) } else { emit.Opcode(c.prog.BinWriter, opcode.NUMNOTEQUAL) } diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index 77b669db6..2d10b8e5e 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -47,18 +47,18 @@ type rpcTestCase struct { check func(t *testing.T, e *executor, result interface{}) } -const testContractHash = "7858559a8405f4e4e1834fcff274ddf4f1b8f407" +const testContractHash = "642e2f47cc6883f0c196cf0dd3dcbb2333300173" var rpcTestCases = map[string][]rpcTestCase{ "getapplicationlog": { { name: "positive", - params: `["fe1a3678b16eca35209acf85397708eb0f1668e4045ad4cd5d2453d3bc0a0a6d"]`, + params: `["953b6e5ba85dd068c2eba5afd2ffdf8ff832b3a791976e2fd896baf5737b2616"]`, 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("fe1a3678b16eca35209acf85397708eb0f1668e4045ad4cd5d2453d3bc0a0a6d") + expectedTxHash, err := util.Uint256DecodeStringLE("953b6e5ba85dd068c2eba5afd2ffdf8ff832b3a791976e2fd896baf5737b2616") require.NoError(t, err) assert.Equal(t, expectedTxHash, res.TxHash) assert.Equal(t, 1, len(res.Executions)) diff --git a/pkg/rpc/server/testdata/test_contract.avm b/pkg/rpc/server/testdata/test_contract.avm index 725dc9a81..a82e371d5 100755 Binary files a/pkg/rpc/server/testdata/test_contract.avm and b/pkg/rpc/server/testdata/test_contract.avm differ diff --git a/pkg/rpc/server/testdata/testblocks.acc b/pkg/rpc/server/testdata/testblocks.acc index 1885c851b..d069cd910 100644 Binary files a/pkg/rpc/server/testdata/testblocks.acc and b/pkg/rpc/server/testdata/testblocks.acc differ diff --git a/pkg/vm/opcode/opcode.go b/pkg/vm/opcode/opcode.go index 39fd7b1f5..071317cdf 100644 --- a/pkg/vm/opcode/opcode.go +++ b/pkg/vm/opcode/opcode.go @@ -98,38 +98,39 @@ const ( RIGHT Opcode = 0x81 // Bitwise logic - INVERT Opcode = 0x83 - AND Opcode = 0x84 - OR Opcode = 0x85 - XOR Opcode = 0x86 - EQUAL Opcode = 0x87 + INVERT Opcode = 0x90 + AND Opcode = 0x91 + OR Opcode = 0x92 + XOR Opcode = 0x93 + EQUAL Opcode = 0x97 + NOTEQUAL Opcode = 0x98 // Arithmetic - INC Opcode = 0x8B - DEC Opcode = 0x8C - SIGN Opcode = 0x8D - NEGATE Opcode = 0x8F - ABS Opcode = 0x90 - NOT Opcode = 0x91 - NZ Opcode = 0x92 - ADD Opcode = 0x93 - SUB Opcode = 0x94 - MUL Opcode = 0x95 - DIV Opcode = 0x96 - MOD Opcode = 0x97 - SHL Opcode = 0x98 - SHR Opcode = 0x99 - BOOLAND Opcode = 0x9A - BOOLOR Opcode = 0x9B - NUMEQUAL Opcode = 0x9C - NUMNOTEQUAL Opcode = 0x9E - LT Opcode = 0x9F - GT Opcode = 0xA0 - LTE Opcode = 0xA1 - GTE Opcode = 0xA2 - MIN Opcode = 0xA3 - MAX Opcode = 0xA4 - WITHIN Opcode = 0xA5 + SIGN Opcode = 0x99 + ABS Opcode = 0x9A + NEGATE Opcode = 0x9B + INC Opcode = 0x9C + DEC Opcode = 0x9D + ADD Opcode = 0x9E + SUB Opcode = 0x9F + MUL Opcode = 0xA0 + DIV Opcode = 0xA1 + MOD Opcode = 0xA2 + SHL Opcode = 0xA8 + SHR Opcode = 0xA9 + NOT Opcode = 0xAA + BOOLAND Opcode = 0xAB + BOOLOR Opcode = 0xAC + NZ Opcode = 0xB1 + NUMEQUAL Opcode = 0xB3 + NUMNOTEQUAL Opcode = 0xB4 + LT Opcode = 0xB5 + LTE Opcode = 0xB6 + GT Opcode = 0xB7 + GTE Opcode = 0xB8 + MIN Opcode = 0xB9 + MAX Opcode = 0xBA + WITHIN Opcode = 0xBB // Advanced data structures (arrays, structures, maps) PACK Opcode = 0xC0 diff --git a/pkg/vm/opcode/opcode_string.go b/pkg/vm/opcode/opcode_string.go index 8a8a66f9c..39d7cbbfe 100644 --- a/pkg/vm/opcode/opcode_string.go +++ b/pkg/vm/opcode/opcode_string.go @@ -84,36 +84,36 @@ func _() { _ = x[SUBSTR-127] _ = x[LEFT-128] _ = x[RIGHT-129] - _ = x[INVERT-131] - _ = x[AND-132] - _ = x[OR-133] - _ = x[XOR-134] - _ = x[EQUAL-135] - _ = x[INC-139] - _ = x[DEC-140] - _ = x[SIGN-141] - _ = x[NEGATE-143] - _ = x[ABS-144] - _ = x[NOT-145] - _ = x[NZ-146] - _ = x[ADD-147] - _ = x[SUB-148] - _ = x[MUL-149] - _ = x[DIV-150] - _ = x[MOD-151] - _ = x[SHL-152] - _ = x[SHR-153] - _ = x[BOOLAND-154] - _ = x[BOOLOR-155] - _ = x[NUMEQUAL-156] - _ = x[NUMNOTEQUAL-158] - _ = x[LT-159] - _ = x[GT-160] - _ = x[LTE-161] - _ = x[GTE-162] - _ = x[MIN-163] - _ = x[MAX-164] - _ = x[WITHIN-165] + _ = x[INVERT-144] + _ = x[AND-145] + _ = x[OR-146] + _ = x[XOR-147] + _ = x[EQUAL-151] + _ = x[SIGN-153] + _ = x[ABS-154] + _ = x[NEGATE-155] + _ = x[INC-156] + _ = x[DEC-157] + _ = x[ADD-158] + _ = x[SUB-159] + _ = x[MUL-160] + _ = x[DIV-161] + _ = x[MOD-162] + _ = x[SHL-168] + _ = x[SHR-169] + _ = x[NOT-170] + _ = x[BOOLAND-171] + _ = x[BOOLOR-172] + _ = x[NZ-177] + _ = x[NUMEQUAL-179] + _ = x[NUMNOTEQUAL-180] + _ = x[LT-181] + _ = x[LTE-182] + _ = x[GT-183] + _ = x[GTE-184] + _ = x[MIN-185] + _ = x[MAX-186] + _ = x[WITHIN-187] _ = x[PACK-192] _ = x[UNPACK-193] _ = x[NEWARRAY0-194] @@ -139,7 +139,7 @@ func _() { _ = x[THROWIFNOT-241] } -const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLOLDPUSH1RETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERTTHROWTHROWIFNOT" +const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLOLDPUSH1RETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERTTHROWTHROWIFNOT" var _Opcode_map = map[Opcode]string{ 0: _Opcode_name[0:8], @@ -216,36 +216,36 @@ var _Opcode_map = map[Opcode]string{ 127: _Opcode_name[427:433], 128: _Opcode_name[433:437], 129: _Opcode_name[437:442], - 131: _Opcode_name[442:448], - 132: _Opcode_name[448:451], - 133: _Opcode_name[451:453], - 134: _Opcode_name[453:456], - 135: _Opcode_name[456:461], - 139: _Opcode_name[461:464], - 140: _Opcode_name[464:467], - 141: _Opcode_name[467:471], - 143: _Opcode_name[471:477], - 144: _Opcode_name[477:480], - 145: _Opcode_name[480:483], - 146: _Opcode_name[483:485], - 147: _Opcode_name[485:488], - 148: _Opcode_name[488:491], - 149: _Opcode_name[491:494], - 150: _Opcode_name[494:497], - 151: _Opcode_name[497:500], - 152: _Opcode_name[500:503], - 153: _Opcode_name[503:506], - 154: _Opcode_name[506:513], - 155: _Opcode_name[513:519], - 156: _Opcode_name[519:527], - 158: _Opcode_name[527:538], - 159: _Opcode_name[538:540], - 160: _Opcode_name[540:542], - 161: _Opcode_name[542:545], - 162: _Opcode_name[545:548], - 163: _Opcode_name[548:551], - 164: _Opcode_name[551:554], - 165: _Opcode_name[554:560], + 144: _Opcode_name[442:448], + 145: _Opcode_name[448:451], + 146: _Opcode_name[451:453], + 147: _Opcode_name[453:456], + 151: _Opcode_name[456:461], + 153: _Opcode_name[461:465], + 154: _Opcode_name[465:468], + 155: _Opcode_name[468:474], + 156: _Opcode_name[474:477], + 157: _Opcode_name[477:480], + 158: _Opcode_name[480:483], + 159: _Opcode_name[483:486], + 160: _Opcode_name[486:489], + 161: _Opcode_name[489:492], + 162: _Opcode_name[492:495], + 168: _Opcode_name[495:498], + 169: _Opcode_name[498:501], + 170: _Opcode_name[501:504], + 171: _Opcode_name[504:511], + 172: _Opcode_name[511:517], + 177: _Opcode_name[517:519], + 179: _Opcode_name[519:527], + 180: _Opcode_name[527:538], + 181: _Opcode_name[538:540], + 182: _Opcode_name[540:543], + 183: _Opcode_name[543:545], + 184: _Opcode_name[545:548], + 185: _Opcode_name[548:551], + 186: _Opcode_name[551:554], + 187: _Opcode_name[554:560], 192: _Opcode_name[560:564], 193: _Opcode_name[564:570], 194: _Opcode_name[570:579], diff --git a/pkg/vm/stack_item.go b/pkg/vm/stack_item.go index bca4e2745..bba8b8fc3 100644 --- a/pkg/vm/stack_item.go +++ b/pkg/vm/stack_item.go @@ -85,9 +85,7 @@ func makeStackItem(v interface{}) StackItem { value: val, } case *big.Int: - return &BigIntegerItem{ - value: val, - } + return NewBigIntegerItem(val) case StackItem: return val case []int: @@ -311,6 +309,9 @@ type BigIntegerItem struct { // NewBigIntegerItem returns an new BigIntegerItem object. func NewBigIntegerItem(value *big.Int) *BigIntegerItem { + if value.BitLen() > MaxBigIntegerSizeBits { + panic("integer is too big") + } return &BigIntegerItem{ value: value, } @@ -519,7 +520,11 @@ func (i *ByteArrayItem) TryBytes() ([]byte, error) { // TryInteger implements StackItem interface. func (i *ByteArrayItem) TryInteger() (*big.Int, error) { - return emit.BytesToInt(i.value), nil + bi := emit.BytesToInt(i.value) + if bi.BitLen() > MaxBigIntegerSizeBits { + return nil, errors.New("integer is too big") + } + return bi, nil } // Equals implements StackItem interface. diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index 4793a3dfd..b11bfb876 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -726,17 +726,6 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro } v.estack.Pop() - case opcode.EQUAL: - b := v.estack.Pop() - if b == nil { - panic("no top-level element found") - } - a := v.estack.Pop() - if a == nil { - panic("no second-to-the-top element found") - } - v.estack.PushVal(a.value.Equals(b.value)) - // Bit operations. case opcode.INVERT: // inplace @@ -759,50 +748,70 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro a := v.estack.Pop().BigInt() v.estack.PushVal(new(big.Int).Xor(b, a)) + case opcode.EQUAL, opcode.NOTEQUAL: + b := v.estack.Pop() + if b == nil { + panic("no top-level element found") + } + a := v.estack.Pop() + if a == nil { + panic("no second-to-the-top element found") + } + v.estack.PushVal(a.value.Equals(b.value) == (op == opcode.EQUAL)) + // Numeric operations. + case opcode.SIGN: + x := v.estack.Pop().BigInt() + v.estack.PushVal(x.Sign()) + + case opcode.ABS: + x := v.estack.Pop().BigInt() + v.estack.PushVal(x.Abs(x)) + + case opcode.NEGATE: + x := v.estack.Pop().BigInt() + v.estack.PushVal(x.Neg(x)) + + case opcode.INC: + x := v.estack.Pop().BigInt() + a := new(big.Int).Add(x, big.NewInt(1)) + v.estack.PushVal(a) + + case opcode.DEC: + x := v.estack.Pop().BigInt() + a := new(big.Int).Sub(x, big.NewInt(1)) + v.estack.PushVal(a) + case opcode.ADD: a := v.estack.Pop().BigInt() - v.checkBigIntSize(a) b := v.estack.Pop().BigInt() - v.checkBigIntSize(b) c := new(big.Int).Add(a, b) - v.checkBigIntSize(c) v.estack.PushVal(c) case opcode.SUB: b := v.estack.Pop().BigInt() - v.checkBigIntSize(b) a := v.estack.Pop().BigInt() - v.checkBigIntSize(a) c := new(big.Int).Sub(a, b) - v.checkBigIntSize(c) + v.estack.PushVal(c) + + case opcode.MUL: + a := v.estack.Pop().BigInt() + b := v.estack.Pop().BigInt() + + c := new(big.Int).Mul(a, b) v.estack.PushVal(c) case opcode.DIV: b := v.estack.Pop().BigInt() - v.checkBigIntSize(b) a := v.estack.Pop().BigInt() - v.checkBigIntSize(a) v.estack.PushVal(new(big.Int).Quo(a, b)) - case opcode.MUL: - a := v.estack.Pop().BigInt() - v.checkBigIntSize(a) - b := v.estack.Pop().BigInt() - v.checkBigIntSize(b) - - c := new(big.Int).Mul(a, b) - v.checkBigIntSize(c) - v.estack.PushVal(c) - case opcode.MOD: b := v.estack.Pop().BigInt() - v.checkBigIntSize(b) a := v.estack.Pop().BigInt() - v.checkBigIntSize(a) v.estack.PushVal(new(big.Int).Rem(a, b)) @@ -814,7 +823,6 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro panic(fmt.Sprintf("operand must be between %d and %d", 0, maxSHLArg)) } a := v.estack.Pop().BigInt() - v.checkBigIntSize(a) var item big.Int if op == opcode.SHL { @@ -823,9 +831,12 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro item.Rsh(a, uint(b)) } - v.checkBigIntSize(&item) v.estack.PushVal(&item) + case opcode.NOT: + x := v.estack.Pop().Bool() + v.estack.PushVal(!x) + case opcode.BOOLAND: b := v.estack.Pop().Bool() a := v.estack.Pop().Bool() @@ -836,6 +847,10 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro a := v.estack.Pop().Bool() v.estack.PushVal(a || b) + case opcode.NZ: + x := v.estack.Pop().BigInt() + v.estack.PushVal(x.Sign() != 0) + case opcode.NUMEQUAL: b := v.estack.Pop().BigInt() a := v.estack.Pop().BigInt() @@ -851,16 +866,16 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro a := v.estack.Pop().BigInt() v.estack.PushVal(a.Cmp(b) == -1) - case opcode.GT: - b := v.estack.Pop().BigInt() - a := v.estack.Pop().BigInt() - v.estack.PushVal(a.Cmp(b) == 1) - case opcode.LTE: b := v.estack.Pop().BigInt() a := v.estack.Pop().BigInt() v.estack.PushVal(a.Cmp(b) <= 0) + case opcode.GT: + b := v.estack.Pop().BigInt() + a := v.estack.Pop().BigInt() + v.estack.PushVal(a.Cmp(b) == 1) + case opcode.GTE: b := v.estack.Pop().BigInt() a := v.estack.Pop().BigInt() @@ -890,38 +905,6 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro x := v.estack.Pop().BigInt() v.estack.PushVal(a.Cmp(x) <= 0 && x.Cmp(b) == -1) - case opcode.INC: - x := v.estack.Pop().BigInt() - a := new(big.Int).Add(x, big.NewInt(1)) - v.checkBigIntSize(a) - v.estack.PushVal(a) - - case opcode.DEC: - x := v.estack.Pop().BigInt() - a := new(big.Int).Sub(x, big.NewInt(1)) - v.checkBigIntSize(a) - v.estack.PushVal(a) - - case opcode.SIGN: - x := v.estack.Pop().BigInt() - v.estack.PushVal(x.Sign()) - - case opcode.NEGATE: - x := v.estack.Pop().BigInt() - v.estack.PushVal(x.Neg(x)) - - case opcode.ABS: - x := v.estack.Pop().BigInt() - v.estack.PushVal(x.Abs(x)) - - case opcode.NOT: - x := v.estack.Pop().Bool() - v.estack.PushVal(!x) - - case opcode.NZ: - x := v.estack.Pop().BigInt() - v.estack.PushVal(x.Cmp(big.NewInt(0)) != 0) - // Object operations case opcode.NEWARRAY0: v.estack.PushVal(&ArrayItem{[]StackItem{}}) @@ -1527,12 +1510,6 @@ func (v *VM) checkInvocationStackSize() { } } -func (v *VM) checkBigIntSize(a *big.Int) { - if a.BitLen() > MaxBigIntegerSizeBits { - panic("big integer is too big") - } -} - // bytesToPublicKey is a helper deserializing keys using cache and panicing on // error. func (v *VM) bytesToPublicKey(b []byte) *keys.PublicKey { diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index 2774ad9d8..d498386d6 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -174,20 +174,13 @@ func TestStackLimitPUSH1Bad(t *testing.T) { checkVMFailed(t, v) } -func testPUSHINT(t *testing.T, op opcode.Opcode, parameter []byte, expected *big.Int) { - prog := append([]byte{byte(op)}, parameter...) - v := load(prog) - runVM(t, v) - require.Equal(t, 1, v.estack.Len()) - require.EqualValues(t, expected, v.estack.Pop().BigInt()) -} - func TestPUSHINT(t *testing.T) { for i := byte(0); i < 5; i++ { op := opcode.PUSHINT8 + opcode.Opcode(i) t.Run(op.String(), func(t *testing.T) { buf := random.Bytes((8 << i) / 8) - testPUSHINT(t, op, buf, emit.BytesToInt(buf)) + prog := append([]byte{byte(op)}, buf...) + runWithArgs(t, prog, emit.BytesToInt(buf)) }) } } @@ -202,28 +195,14 @@ func TestPUSHNULL(t *testing.T) { } func TestISNULL(t *testing.T) { - t.Run("Integer", func(t *testing.T) { - prog := makeProgram(opcode.PUSH1, opcode.ISNULL) - v := load(prog) - runVM(t, v) - require.False(t, v.estack.Pop().Bool()) - }) - - t.Run("Null", func(t *testing.T) { - prog := makeProgram(opcode.PUSHNULL, opcode.ISNULL) - v := load(prog) - runVM(t, v) - require.True(t, v.estack.Pop().Bool()) - }) + prog := makeProgram(opcode.ISNULL) + t.Run("Integer", getTestFuncForVM(prog, false, 1)) + t.Run("Null", getTestFuncForVM(prog, true, NullItem{})) } 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()) + runWithArgs(t, prog, result, item) } func TestISTYPE(t *testing.T) { @@ -257,18 +236,10 @@ func TestISTYPE(t *testing.T) { }) } -func testCONVERT(isErr bool, to StackItemType, item, res StackItem) func(t *testing.T) { +func testCONVERT(to StackItemType, item, res StackItem) func(t *testing.T) { return func(t *testing.T) { prog := []byte{byte(opcode.CONVERT), byte(to)} - v := load(prog) - v.estack.PushVal(item) - if isErr { - checkVMFailed(t, v) - return - } - runVM(t, v) - require.Equal(t, 1, v.estack.Len()) - require.Equal(t, res, v.estack.Pop().value) + runWithArgs(t, prog, res, item) } } @@ -287,7 +258,7 @@ func TestCONVERT(t *testing.T) { t.Run("->Bool", func(t *testing.T) { testBool := func(a, b StackItem) func(t *testing.T) { - return testCONVERT(false, BooleanT, a, b) + return testCONVERT(BooleanT, a, b) } trueCases := []StackItem{ @@ -313,7 +284,7 @@ func TestCONVERT(t *testing.T) { items := []StackItem{NewArrayItem(nil), NewStructItem(nil), NewMapItem(), NewInteropItem(struct{}{})} for _, typ := range types { for j := range items { - t.Run(getName(items[j], typ), testCONVERT(true, typ, items[j], nil)) + t.Run(getName(items[j], typ), testCONVERT(typ, items[j], nil)) } } }) @@ -342,7 +313,7 @@ func TestCONVERT(t *testing.T) { for typ := range trueCases { for _, tc := range trueCases[typ] { - t.Run(getName(tc.item, typ), testCONVERT(false, typ, tc.item, tc.res)) + t.Run(getName(tc.item, typ), testCONVERT(typ, tc.item, tc.res)) } } }) @@ -350,20 +321,20 @@ func TestCONVERT(t *testing.T) { t.Run("Struct<->Array", func(t *testing.T) { arrayItem := NewArrayItem(arr) structItem := NewStructItem(arr) - t.Run("Array->Array", testCONVERT(false, ArrayT, arrayItem, arrayItem)) - t.Run("Array->Struct", testCONVERT(false, StructT, arrayItem, structItem)) - t.Run("Struct->Array", testCONVERT(false, ArrayT, structItem, arrayItem)) - t.Run("Struct->Struct", testCONVERT(false, StructT, structItem, structItem)) + t.Run("Array->Array", testCONVERT(ArrayT, arrayItem, arrayItem)) + t.Run("Array->Struct", testCONVERT(StructT, arrayItem, structItem)) + t.Run("Struct->Array", testCONVERT(ArrayT, structItem, arrayItem)) + t.Run("Struct->Struct", testCONVERT(StructT, structItem, structItem)) }) - t.Run("Map->Map", testCONVERT(false, MapT, m, m)) + t.Run("Map->Map", testCONVERT(MapT, m, m)) t.Run("Null->", func(t *testing.T) { types := []StackItemType{ BooleanT, ByteArrayT, IntegerT, ArrayT, StructT, MapT, InteropT, } for i := range types { - t.Run(types[i].String(), testCONVERT(false, types[i], NullItem{}, NullItem{})) + t.Run(types[i].String(), testCONVERT(types[i], NullItem{}, NullItem{})) } }) @@ -374,7 +345,7 @@ func TestCONVERT(t *testing.T) { } for i := range items { - t.Run(items[i].String(), testCONVERT(true, AnyT, items[i], nil)) + t.Run(items[i].String(), testCONVERT(AnyT, items[i], nil)) } }) } @@ -472,68 +443,24 @@ func TestPushm1to16(t *testing.T) { } } -func TestPushData1BadNoN(t *testing.T) { - prog := []byte{byte(opcode.PUSHDATA1)} - vm := load(prog) - checkVMFailed(t, vm) +func TestPUSHDATA1(t *testing.T) { + t.Run("Good", getTestFuncForVM([]byte{byte(opcode.PUSHDATA1), 3, 1, 2, 3}, []byte{1, 2, 3})) + t.Run("NoN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA1)}, nil)) + t.Run("BadN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA1), 1}, nil)) } -func TestPushData1BadN(t *testing.T) { - prog := []byte{byte(opcode.PUSHDATA1), 1} - vm := load(prog) - checkVMFailed(t, vm) +func TestPUSHDATA2(t *testing.T) { + t.Run("Good", getTestFuncForVM([]byte{byte(opcode.PUSHDATA2), 3, 0, 1, 2, 3}, []byte{1, 2, 3})) + t.Run("NoN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA2)}, nil)) + t.Run("ShortN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA2), 0}, nil)) + t.Run("BadN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA2), 1, 0}, nil)) } -func TestPushData1Good(t *testing.T) { - prog := makeProgram(opcode.PUSHDATA1, 3, 1, 2, 3) - vm := load(prog) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, []byte{1, 2, 3}, vm.estack.Pop().Bytes()) -} - -func TestPushData2BadNoN(t *testing.T) { - prog := []byte{byte(opcode.PUSHDATA2)} - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestPushData2ShortN(t *testing.T) { - prog := []byte{byte(opcode.PUSHDATA2), 0} - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestPushData2BadN(t *testing.T) { - prog := []byte{byte(opcode.PUSHDATA2), 1, 0} - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestPushData2Good(t *testing.T) { - prog := makeProgram(opcode.PUSHDATA2, 3, 0, 1, 2, 3) - vm := load(prog) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, []byte{1, 2, 3}, vm.estack.Pop().Bytes()) -} - -func TestPushData4BadNoN(t *testing.T) { - prog := []byte{byte(opcode.PUSHDATA4)} - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestPushData4BadN(t *testing.T) { - prog := []byte{byte(opcode.PUSHDATA4), 1, 0, 0, 0} - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestPushData4ShortN(t *testing.T) { - prog := []byte{byte(opcode.PUSHDATA4), 0, 0, 0} - vm := load(prog) - checkVMFailed(t, vm) +func TestPUSHDATA4(t *testing.T) { + t.Run("Good", getTestFuncForVM([]byte{byte(opcode.PUSHDATA4), 3, 0, 0, 0, 1, 2, 3}, []byte{1, 2, 3})) + t.Run("NoN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA4)}, nil)) + t.Run("BadN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA4), 1, 0, 0, 0}, nil)) + t.Run("ShortN", getTestFuncForVM([]byte{byte(opcode.PUSHDATA4), 0, 0, 0}, nil)) } func TestPushData4BigN(t *testing.T) { @@ -542,16 +469,7 @@ func TestPushData4BigN(t *testing.T) { binary.LittleEndian.PutUint32(prog[1:], MaxItemSize+1) vm := load(prog) - vm.Run() - assert.Equal(t, true, vm.HasFailed()) -} - -func TestPushData4Good(t *testing.T) { - prog := makeProgram(opcode.PUSHDATA4, 3, 0, 0, 0, 1, 2, 3) - vm := load(prog) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, []byte{1, 2, 3}, vm.estack.Pop().Bytes()) + checkVMFailed(t, vm) } func getEnumeratorProg(n int, isIter bool) (prog []byte) { @@ -822,15 +740,13 @@ func TestSerializeStruct(t *testing.T) { func TestDeserializeUnknown(t *testing.T) { prog := append(getSyscallProg("Neo.Runtime.Deserialize"), byte(opcode.RET)) - vm := load(prog) data, err := SerializeItem(NewBigIntegerItem(big.NewInt(123))) require.NoError(t, err) data[0] = 0xFF - vm.estack.PushVal(data) - checkVMFailed(t, vm) + runWithArgs(t, prog, nil, data) } func TestSerializeMap(t *testing.T) { @@ -989,58 +905,15 @@ func TestJMPs(t *testing.T) { } } -func TestNOTNoArgument(t *testing.T) { +func TestNOT(t *testing.T) { prog := makeProgram(opcode.NOT) - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestNOTBool(t *testing.T) { - prog := makeProgram(opcode.NOT) - vm := load(prog) - vm.estack.PushVal(false) - runVM(t, vm) - assert.Equal(t, &BoolItem{true}, vm.estack.Pop().value) -} - -func TestNOTNonZeroInt(t *testing.T) { - prog := makeProgram(opcode.NOT) - vm := load(prog) - vm.estack.PushVal(3) - runVM(t, vm) - assert.Equal(t, &BoolItem{false}, vm.estack.Pop().value) -} - -func TestNOTArray(t *testing.T) { - prog := makeProgram(opcode.NOT) - vm := load(prog) - vm.estack.PushVal([]StackItem{}) - runVM(t, vm) - assert.Equal(t, &BoolItem{false}, vm.estack.Pop().value) -} - -func TestNOTStruct(t *testing.T) { - prog := makeProgram(opcode.NOT) - vm := load(prog) - vm.estack.Push(NewElement(&StructItem{[]StackItem{}})) - runVM(t, vm) - assert.Equal(t, &BoolItem{false}, vm.estack.Pop().value) -} - -func TestNOTByteArray0(t *testing.T) { - prog := makeProgram(opcode.NOT) - vm := load(prog) - vm.estack.PushVal([]byte{0, 0}) - runVM(t, vm) - assert.Equal(t, &BoolItem{true}, vm.estack.Pop().value) -} - -func TestNOTByteArray1(t *testing.T) { - prog := makeProgram(opcode.NOT) - vm := load(prog) - vm.estack.PushVal([]byte{0, 1}) - runVM(t, vm) - assert.Equal(t, &BoolItem{false}, vm.estack.Pop().value) + t.Run("Bool", getTestFuncForVM(prog, true, false)) + t.Run("NonZeroInt", getTestFuncForVM(prog, false, 3)) + t.Run("Array", getTestFuncForVM(prog, false, []StackItem{})) + t.Run("Struct", getTestFuncForVM(prog, false, NewStructItem([]StackItem{}))) + t.Run("ByteArray0", getTestFuncForVM(prog, true, []byte{0, 0})) + t.Run("ByteArray1", getTestFuncForVM(prog, false, []byte{0, 1})) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) } // getBigInt returns 2^a+b @@ -1050,74 +923,35 @@ func getBigInt(a, b int64) *big.Int { return p } -func TestAdd(t *testing.T) { - prog := makeProgram(opcode.ADD) - vm := load(prog) - vm.estack.PushVal(4) - vm.estack.PushVal(2) - runVM(t, vm) - assert.Equal(t, int64(6), vm.estack.Pop().BigInt().Int64()) +func TestArith(t *testing.T) { + // results for 5 and 2 + testCases := map[opcode.Opcode]int{ + opcode.ADD: 7, + opcode.MUL: 10, + opcode.DIV: 2, + opcode.MOD: 1, + opcode.SUB: 3, + } + + for op, res := range testCases { + t.Run(op.String(), getTestFuncForVM(makeProgram(op), res, 5, 2)) + } } func TestADDBigResult(t *testing.T) { prog := makeProgram(opcode.ADD) - vm := load(prog) - vm.estack.PushVal(getBigInt(MaxBigIntegerSizeBits, -1)) - vm.estack.PushVal(1) - checkVMFailed(t, vm) -} - -func testBigArgument(t *testing.T, inst opcode.Opcode) { - prog := makeProgram(inst) - x := getBigInt(MaxBigIntegerSizeBits, 0) - t.Run(inst.String()+" big 1-st argument", func(t *testing.T) { - vm := load(prog) - vm.estack.PushVal(x) - vm.estack.PushVal(0) - checkVMFailed(t, vm) - }) - t.Run(inst.String()+" big 2-nd argument", func(t *testing.T) { - vm := load(prog) - vm.estack.PushVal(0) - vm.estack.PushVal(x) - checkVMFailed(t, vm) - }) -} - -func TestArithBigArgument(t *testing.T) { - testBigArgument(t, opcode.ADD) - testBigArgument(t, opcode.SUB) - testBigArgument(t, opcode.MUL) - testBigArgument(t, opcode.DIV) - testBigArgument(t, opcode.MOD) -} - -func TestMul(t *testing.T) { - prog := makeProgram(opcode.MUL) - vm := load(prog) - vm.estack.PushVal(4) - vm.estack.PushVal(2) - runVM(t, vm) - assert.Equal(t, int64(8), vm.estack.Pop().BigInt().Int64()) + runWithArgs(t, prog, nil, getBigInt(MaxBigIntegerSizeBits, -1), 1) } func TestMULBigResult(t *testing.T) { prog := makeProgram(opcode.MUL) - vm := load(prog) - vm.estack.PushVal(getBigInt(MaxBigIntegerSizeBits/2+1, 0)) - vm.estack.PushVal(getBigInt(MaxBigIntegerSizeBits/2+1, 0)) - checkVMFailed(t, vm) + bi := getBigInt(MaxBigIntegerSizeBits/2+1, 0) + runWithArgs(t, prog, nil, bi, bi) } func TestArithNegativeArguments(t *testing.T) { runCase := func(op opcode.Opcode, p, q, result int64) func(t *testing.T) { - return func(t *testing.T) { - vm := load(makeProgram(op)) - vm.estack.PushVal(p) - vm.estack.PushVal(q) - runVM(t, vm) - assert.Equal(t, result, vm.estack.Pop().BigInt().Int64()) - } + return getTestFuncForVM(makeProgram(op), result, p, q) } t.Run("DIV", func(t *testing.T) { @@ -1145,138 +979,44 @@ func TestArithNegativeArguments(t *testing.T) { }) } -func TestSub(t *testing.T) { - prog := makeProgram(opcode.SUB) - vm := load(prog) - vm.estack.PushVal(4) - vm.estack.PushVal(2) - runVM(t, vm) - assert.Equal(t, int64(2), vm.estack.Pop().BigInt().Int64()) -} - func TestSUBBigResult(t *testing.T) { prog := makeProgram(opcode.SUB) - vm := load(prog) - vm.estack.PushVal(getBigInt(MaxBigIntegerSizeBits, -1)) - vm.estack.PushVal(-1) - checkVMFailed(t, vm) + runWithArgs(t, prog, nil, getBigInt(MaxBigIntegerSizeBits, -1), -1) } -func TestSHRGood(t *testing.T) { +func TestSHR(t *testing.T) { prog := makeProgram(opcode.SHR) - vm := load(prog) - vm.estack.PushVal(4) - vm.estack.PushVal(2) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(1), vm.estack.Pop().value) + t.Run("Good", getTestFuncForVM(prog, 1, 4, 2)) + t.Run("Zero", getTestFuncForVM(prog, []byte{0, 1}, []byte{0, 1}, 0)) + t.Run("Negative", getTestFuncForVM(prog, nil, 5, -1)) } -func TestSHRZero(t *testing.T) { - prog := makeProgram(opcode.SHR) - vm := load(prog) - vm.estack.PushVal([]byte{0, 1}) - vm.estack.PushVal(0) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem([]byte{0, 1}), vm.estack.Pop().value) -} - -func TestSHRNegative(t *testing.T) { - prog := makeProgram(opcode.SHR) - vm := load(prog) - vm.estack.PushVal(5) - vm.estack.PushVal(-1) - checkVMFailed(t, vm) -} - -func TestSHRBigArgument(t *testing.T) { - prog := makeProgram(opcode.SHR) - vm := load(prog) - vm.estack.PushVal(getBigInt(MaxBigIntegerSizeBits, 0)) - vm.estack.PushVal(1) - checkVMFailed(t, vm) -} - -func TestSHLGood(t *testing.T) { +func TestSHL(t *testing.T) { prog := makeProgram(opcode.SHL) - vm := load(prog) - vm.estack.PushVal(4) - vm.estack.PushVal(2) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(16), vm.estack.Pop().value) -} - -func TestSHLZero(t *testing.T) { - prog := makeProgram(opcode.SHL) - vm := load(prog) - vm.estack.PushVal([]byte{0, 1}) - vm.estack.PushVal(0) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem([]byte{0, 1}), vm.estack.Pop().value) -} - -func TestSHLBigValue(t *testing.T) { - prog := makeProgram(opcode.SHL) - vm := load(prog) - vm.estack.PushVal(5) - vm.estack.PushVal(maxSHLArg + 1) - checkVMFailed(t, vm) -} - -func TestSHLBigResult(t *testing.T) { - prog := makeProgram(opcode.SHL) - vm := load(prog) - vm.estack.PushVal(getBigInt(MaxBigIntegerSizeBits/2, 0)) - vm.estack.PushVal(MaxBigIntegerSizeBits / 2) - checkVMFailed(t, vm) -} - -func TestSHLBigArgument(t *testing.T) { - prog := makeProgram(opcode.SHR) - vm := load(prog) - vm.estack.PushVal(getBigInt(MaxBigIntegerSizeBits, 0)) - vm.estack.PushVal(1) - checkVMFailed(t, vm) + t.Run("Good", getTestFuncForVM(prog, 16, 4, 2)) + t.Run("Zero", getTestFuncForVM(prog, []byte{0, 1}, []byte{0, 1}, 0)) + t.Run("BigShift", getTestFuncForVM(prog, nil, 5, maxSHLArg+1)) + t.Run("BigResult", getTestFuncForVM(prog, nil, getBigInt(MaxBigIntegerSizeBits/2, 0), MaxBigIntegerSizeBits/2)) } func TestLT(t *testing.T) { prog := makeProgram(opcode.LT) - vm := load(prog) - vm.estack.PushVal(4) - vm.estack.PushVal(3) - runVM(t, vm) - assert.Equal(t, false, vm.estack.Pop().Bool()) + runWithArgs(t, prog, false, 4, 3) } func TestLTE(t *testing.T) { prog := makeProgram(opcode.LTE) - vm := load(prog) - vm.estack.PushVal(2) - vm.estack.PushVal(3) - runVM(t, vm) - assert.Equal(t, true, vm.estack.Pop().Bool()) + runWithArgs(t, prog, true, 2, 3) } func TestGT(t *testing.T) { prog := makeProgram(opcode.GT) - vm := load(prog) - vm.estack.PushVal(9) - vm.estack.PushVal(3) - runVM(t, vm) - assert.Equal(t, true, vm.estack.Pop().Bool()) - + runWithArgs(t, prog, true, 9, 3) } func TestGTE(t *testing.T) { prog := makeProgram(opcode.GTE) - vm := load(prog) - vm.estack.PushVal(3) - vm.estack.PushVal(3) - runVM(t, vm) - assert.Equal(t, true, vm.estack.Pop().Bool()) + runWithArgs(t, prog, true, 3, 3) } func TestDepth(t *testing.T) { @@ -1289,101 +1029,63 @@ func TestDepth(t *testing.T) { assert.Equal(t, int64(3), vm.estack.Pop().BigInt().Int64()) } -func TestEQUALNoArguments(t *testing.T) { - prog := makeProgram(opcode.EQUAL) - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestEQUALBad1Argument(t *testing.T) { - prog := makeProgram(opcode.EQUAL) - vm := load(prog) - vm.estack.PushVal(1) - checkVMFailed(t, vm) -} - -func TestEQUALGoodInteger(t *testing.T) { - prog := makeProgram(opcode.EQUAL) - vm := load(prog) - vm.estack.PushVal(5) - vm.estack.PushVal(5) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &BoolItem{true}, vm.estack.Pop().value) -} - -func TestEQUALIntegerByteArray(t *testing.T) { - prog := makeProgram(opcode.EQUAL) - vm := load(prog) - vm.estack.PushVal([]byte{16}) - vm.estack.PushVal(16) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &BoolItem{true}, vm.estack.Pop().value) -} - -func TestEQUALArrayTrue(t *testing.T) { +func TestEQUALTrue(t *testing.T) { prog := makeProgram(opcode.DUP, opcode.EQUAL) - vm := load(prog) - vm.estack.PushVal([]StackItem{}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &BoolItem{true}, vm.estack.Pop().value) + t.Run("Array", getTestFuncForVM(prog, true, []StackItem{})) + t.Run("Map", getTestFuncForVM(prog, true, NewMapItem())) } -func TestEQUALArrayFalse(t *testing.T) { +func TestEQUAL(t *testing.T) { prog := makeProgram(opcode.EQUAL) - vm := load(prog) - vm.estack.PushVal([]StackItem{}) - vm.estack.PushVal([]StackItem{}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &BoolItem{false}, vm.estack.Pop().value) + t.Run("NoArgs", getTestFuncForVM(prog, nil)) + t.Run("OneArgument", getTestFuncForVM(prog, nil, 1)) + t.Run("Integer", getTestFuncForVM(prog, true, 5, 5)) + t.Run("IntegerByteArray", getTestFuncForVM(prog, true, []byte{16}, 16)) + t.Run("Map", getTestFuncForVM(prog, false, NewMapItem(), NewMapItem())) + t.Run("Array", getTestFuncForVM(prog, false, []StackItem{}, []StackItem{})) } -func TestEQUALMapTrue(t *testing.T) { - prog := makeProgram(opcode.DUP, opcode.EQUAL) - vm := load(prog) - vm.estack.Push(&Element{value: NewMapItem()}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &BoolItem{true}, vm.estack.Pop().value) +func runWithArgs(t *testing.T, prog []byte, result interface{}, args ...interface{}) { + getTestFuncForVM(prog, result, args...)(t) } -func TestEQUALMapFalse(t *testing.T) { - prog := makeProgram(opcode.EQUAL) - vm := load(prog) - vm.estack.Push(&Element{value: NewMapItem()}) - vm.estack.Push(&Element{value: NewMapItem()}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &BoolItem{false}, vm.estack.Pop().value) +func getTestFuncForVM(prog []byte, result interface{}, args ...interface{}) func(t *testing.T) { + return func(t *testing.T) { + v := load(prog) + for i := range args { + v.estack.PushVal(args[i]) + } + if result == nil { + checkVMFailed(t, v) + return + } + runVM(t, v) + require.Equal(t, 1, v.estack.Len()) + require.Equal(t, makeStackItem(result), v.estack.Pop().value) + } } -func TestNumEqual(t *testing.T) { +func TestNOTEQUALByteArray(t *testing.T) { + prog := makeProgram(opcode.NOTEQUAL) + t.Run("True", getTestFuncForVM(prog, true, []byte{1, 2}, []byte{0, 1, 2})) + t.Run("False", getTestFuncForVM(prog, false, []byte{1, 2}, []byte{1, 2})) +} + +func TestNUMEQUAL(t *testing.T) { prog := makeProgram(opcode.NUMEQUAL) - vm := load(prog) - vm.estack.PushVal(1) - vm.estack.PushVal(2) - runVM(t, vm) - assert.Equal(t, false, vm.estack.Pop().Bool()) + t.Run("True", getTestFuncForVM(prog, true, 2, 2)) + t.Run("False", getTestFuncForVM(prog, false, 1, 2)) } -func TestNumNotEqual(t *testing.T) { +func TestNUMNOTEQUAL(t *testing.T) { prog := makeProgram(opcode.NUMNOTEQUAL) - vm := load(prog) - vm.estack.PushVal(2) - vm.estack.PushVal(2) - runVM(t, vm) - assert.Equal(t, false, vm.estack.Pop().Bool()) + t.Run("True", getTestFuncForVM(prog, true, 1, 2)) + t.Run("False", getTestFuncForVM(prog, false, 2, 2)) } func TestINC(t *testing.T) { prog := makeProgram(opcode.INC) - vm := load(prog) - vm.estack.PushVal(1) - runVM(t, vm) - assert.Equal(t, big.NewInt(2), vm.estack.Pop().BigInt()) + runWithArgs(t, prog, 2, 1) } func TestINCBigResult(t *testing.T) { @@ -1417,37 +1119,23 @@ func TestDECBigResult(t *testing.T) { 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) + runWithArgs(t, prog, []StackItem{}) } 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) + runWithArgs(t, prog, NewStructItem([]StackItem{})) } -func TestNEWARRAYInteger(t *testing.T) { +func TestNEWARRAYArray(t *testing.T) { prog := makeProgram(opcode.NEWARRAY) - vm := load(prog) - vm.estack.PushVal(1) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &ArrayItem{[]StackItem{makeStackItem(false)}}, vm.estack.Pop().value) -} + t.Run("ByteArray", getTestFuncForVM(prog, NewArrayItem([]StackItem{}), []byte{})) + t.Run("BadSize", getTestFuncForVM(prog, nil, MaxArraySize+1)) + t.Run("Integer", getTestFuncForVM(prog, []StackItem{NewBoolItem(false)}, 1)) -func TestNEWARRAYStruct(t *testing.T) { - prog := makeProgram(opcode.NEWARRAY) - vm := load(prog) arr := []StackItem{makeStackItem(42)} - vm.estack.Push(&Element{value: &StructItem{arr}}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &ArrayItem{arr}, vm.estack.Pop().value) + t.Run("Array", getTestFuncForVM(prog, arr, arr)) + t.Run("Struct", getTestFuncForVM(prog, arr, NewStructItem(arr))) } func testNEWARRAYIssue437(t *testing.T, i1, i2 opcode.Opcode, appended bool) { @@ -1483,38 +1171,6 @@ func TestNEWARRAYIssue437(t *testing.T) { t.Run("Struct+Array", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWSTRUCT, opcode.NEWARRAY, false) }) } -func TestNEWARRAYArray(t *testing.T) { - prog := makeProgram(opcode.NEWARRAY) - vm := load(prog) - arr := []StackItem{makeStackItem(42)} - vm.estack.Push(&Element{value: &ArrayItem{arr}}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &ArrayItem{arr}, vm.estack.Pop().value) -} - -func TestNEWARRAYByteArray(t *testing.T) { - prog := makeProgram(opcode.NEWARRAY) - vm := load(prog) - vm.estack.PushVal([]byte{}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - 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), @@ -1524,111 +1180,41 @@ func TestNEWARRAYT(t *testing.T) { 0xFF: nil, } for typ, item := range testCases { - t.Run(typ.String(), func(t *testing.T) { testNEWARRAYT(t, typ, item) }) + prog := makeProgram(opcode.NEWARRAYT, opcode.Opcode(typ), opcode.PUSH0, opcode.PICKITEM) + t.Run(typ.String(), getTestFuncForVM(prog, item, 1)) } } -func TestNEWARRAYBadSize(t *testing.T) { - prog := makeProgram(opcode.NEWARRAY) - vm := load(prog) - vm.estack.PushVal(MaxArraySize + 1) - checkVMFailed(t, vm) -} - -func TestNEWSTRUCTInteger(t *testing.T) { +func TestNEWSTRUCT(t *testing.T) { prog := makeProgram(opcode.NEWSTRUCT) - vm := load(prog) - vm.estack.PushVal(1) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &StructItem{[]StackItem{makeStackItem(false)}}, vm.estack.Pop().value) -} + t.Run("ByteArray", getTestFuncForVM(prog, NewStructItem([]StackItem{}), []byte{})) + t.Run("BadSize", getTestFuncForVM(prog, nil, MaxArraySize+1)) + t.Run("Integer", getTestFuncForVM(prog, NewStructItem([]StackItem{NewBoolItem(false)}), 1)) -func TestNEWSTRUCTArray(t *testing.T) { - prog := makeProgram(opcode.NEWSTRUCT) - vm := load(prog) arr := []StackItem{makeStackItem(42)} - vm.estack.Push(&Element{value: &ArrayItem{arr}}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &StructItem{arr}, vm.estack.Pop().value) + t.Run("Array", getTestFuncForVM(prog, NewStructItem(arr), NewArrayItem(arr))) + t.Run("Struct", getTestFuncForVM(prog, NewStructItem(arr), NewStructItem(arr))) } -func TestNEWSTRUCTStruct(t *testing.T) { - prog := makeProgram(opcode.NEWSTRUCT) - vm := load(prog) - arr := []StackItem{makeStackItem(42)} - vm.estack.Push(&Element{value: &StructItem{arr}}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &StructItem{arr}, vm.estack.Pop().value) -} - -func TestNEWSTRUCTByteArray(t *testing.T) { - prog := makeProgram(opcode.NEWSTRUCT) - vm := load(prog) - vm.estack.PushVal([]byte{}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &StructItem{[]StackItem{}}, vm.estack.Pop().value) -} - -func TestNEWSTRUCTBadSize(t *testing.T) { - prog := makeProgram(opcode.NEWSTRUCT) - vm := load(prog) - vm.estack.PushVal(MaxArraySize + 1) - checkVMFailed(t, vm) -} - -func TestAPPENDArray(t *testing.T) { +func TestAPPEND(t *testing.T) { prog := makeProgram(opcode.DUP, opcode.PUSH5, opcode.APPEND) - vm := load(prog) - vm.estack.Push(&Element{value: &ArrayItem{}}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &ArrayItem{[]StackItem{makeStackItem(5)}}, vm.estack.Pop().value) -} - -func TestAPPENDStruct(t *testing.T) { - prog := makeProgram(opcode.DUP, opcode.PUSH5, opcode.APPEND) - vm := load(prog) - vm.estack.Push(&Element{value: &StructItem{}}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &StructItem{[]StackItem{makeStackItem(5)}}, vm.estack.Pop().value) + arr := []StackItem{makeStackItem(5)} + t.Run("Array", getTestFuncForVM(prog, NewArrayItem(arr), NewArrayItem(nil))) + t.Run("Struct", getTestFuncForVM(prog, NewStructItem(arr), NewStructItem(nil))) } func TestAPPENDCloneStruct(t *testing.T) { prog := makeProgram(opcode.DUP, opcode.PUSH0, opcode.NEWSTRUCT, opcode.TOALTSTACK, opcode.DUPFROMALTSTACK, opcode.APPEND, opcode.FROMALTSTACK, opcode.PUSH1, opcode.APPEND) - vm := load(prog) - vm.estack.Push(&Element{value: &ArrayItem{}}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &ArrayItem{[]StackItem{ - &StructItem{[]StackItem{}}, - }}, vm.estack.Pop().value) + arr := []StackItem{&StructItem{[]StackItem{}}} + runWithArgs(t, prog, NewArrayItem(arr), NewArrayItem(nil)) } -func TestAPPENDBadNoArguments(t *testing.T) { +func TestAPPENDBad(t *testing.T) { prog := makeProgram(opcode.APPEND) - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestAPPENDBad1Argument(t *testing.T) { - prog := makeProgram(opcode.APPEND) - vm := load(prog) - vm.estack.PushVal(1) - checkVMFailed(t, vm) -} - -func TestAPPENDWrongType(t *testing.T) { - prog := makeProgram(opcode.APPEND) - vm := load(prog) - vm.estack.PushVal([]byte{}) - vm.estack.PushVal(1) - checkVMFailed(t, vm) + t.Run("no arguments", getTestFuncForVM(prog, nil)) + t.Run("one argument", getTestFuncForVM(prog, nil, 1)) + t.Run("wrong type", getTestFuncForVM(prog, nil, []byte{}, 1)) } func TestAPPENDGoodSizeLimit(t *testing.T) { @@ -1642,37 +1228,14 @@ func TestAPPENDGoodSizeLimit(t *testing.T) { func TestAPPENDBadSizeLimit(t *testing.T) { prog := makeProgram(opcode.NEWARRAY, opcode.DUP, opcode.PUSH0, opcode.APPEND) - vm := load(prog) - vm.estack.PushVal(MaxArraySize) - checkVMFailed(t, vm) + runWithArgs(t, prog, nil, MaxArraySize) } -func TestPICKITEMBadIndex(t *testing.T) { +func TestPICKITEM(t *testing.T) { prog := makeProgram(opcode.PICKITEM) - vm := load(prog) - vm.estack.PushVal([]StackItem{}) - vm.estack.PushVal(0) - checkVMFailed(t, vm) -} - -func TestPICKITEMArray(t *testing.T) { - prog := makeProgram(opcode.PICKITEM) - vm := load(prog) - vm.estack.PushVal([]StackItem{makeStackItem(1), makeStackItem(2)}) - vm.estack.PushVal(1) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(2), vm.estack.Pop().value) -} - -func TestPICKITEMByteArray(t *testing.T) { - prog := makeProgram(opcode.PICKITEM) - vm := load(prog) - vm.estack.PushVal([]byte{1, 2}) - vm.estack.PushVal(1) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(2), vm.estack.Pop().value) + t.Run("bad index", getTestFuncForVM(prog, nil, []StackItem{}, 0)) + t.Run("Array", getTestFuncForVM(prog, 2, []StackItem{makeStackItem(1), makeStackItem(2)}, 1)) + t.Run("ByteArray", getTestFuncForVM(prog, 2, []byte{1, 2}, 1)) } func TestPICKITEMDupArray(t *testing.T) { @@ -1703,48 +1266,26 @@ func TestPICKITEMDupMap(t *testing.T) { func TestPICKITEMMap(t *testing.T) { prog := makeProgram(opcode.PICKITEM) - vm := load(prog) - m := NewMapItem() m.Add(makeStackItem(5), makeStackItem(3)) - vm.estack.Push(&Element{value: m}) - vm.estack.PushVal(makeStackItem(5)) - - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(3), vm.estack.Pop().value) + runWithArgs(t, prog, 3, m, 5) } func TestSETITEMMap(t *testing.T) { prog := makeProgram(opcode.SETITEM, opcode.PICKITEM) - vm := load(prog) - m := NewMapItem() m.Add(makeStackItem(5), makeStackItem(3)) - vm.estack.Push(&Element{value: m}) - vm.estack.PushVal(5) - vm.estack.Push(&Element{value: m}) - vm.estack.PushVal(5) - vm.estack.PushVal([]byte{0, 1}) - - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem([]byte{0, 1}), vm.estack.Pop().value) + runWithArgs(t, prog, []byte{0, 1}, m, 5, m, 5, []byte{0, 1}) } func TestSETITEMBigMapBad(t *testing.T) { prog := makeProgram(opcode.SETITEM) - vm := load(prog) - m := NewMapItem() for i := 0; i < MaxArraySize; i++ { m.Add(makeStackItem(i), makeStackItem(i)) } - vm.estack.Push(&Element{value: m}) - vm.estack.PushVal(MaxArraySize) - vm.estack.PushVal(0) - checkVMFailed(t, vm) + runWithArgs(t, prog, nil, m, MaxArraySize, 0) } func TestSETITEMBigMapGood(t *testing.T) { @@ -1762,54 +1303,18 @@ func TestSETITEMBigMapGood(t *testing.T) { runVM(t, vm) } -func TestSIZENoArgument(t *testing.T) { +func TestSIZE(t *testing.T) { prog := makeProgram(opcode.SIZE) - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestSIZEByteArray(t *testing.T) { - prog := makeProgram(opcode.SIZE) - vm := load(prog) - vm.estack.PushVal([]byte{0, 1}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(2), vm.estack.Pop().value) -} - -func TestSIZEBool(t *testing.T) { - prog := makeProgram(opcode.SIZE) - vm := load(prog) - vm.estack.PushVal(false) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(1), vm.estack.Pop().value) -} - -func TestSIZEArray(t *testing.T) { - prog := makeProgram(opcode.SIZE) - vm := load(prog) - vm.estack.PushVal([]StackItem{ - makeStackItem(1), - makeStackItem([]byte{}), + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("ByteArray", getTestFuncForVM(prog, 2, []byte{0, 1})) + t.Run("Bool", getTestFuncForVM(prog, 1, false)) + t.Run("Array", getTestFuncForVM(prog, 2, []StackItem{makeStackItem(1), makeStackItem([]byte{})})) + t.Run("Map", func(t *testing.T) { + m := NewMapItem() + m.Add(makeStackItem(5), makeStackItem(6)) + m.Add(makeStackItem([]byte{0, 1}), makeStackItem(6)) + runWithArgs(t, prog, 2, m) }) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(2), vm.estack.Pop().value) -} - -func TestSIZEMap(t *testing.T) { - prog := makeProgram(opcode.SIZE) - vm := load(prog) - - m := NewMapItem() - m.Add(makeStackItem(5), makeStackItem(6)) - m.Add(makeStackItem([]byte{0, 1}), makeStackItem(6)) - vm.estack.Push(&Element{value: m}) - - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(2), vm.estack.Pop().value) } func TestKEYSMap(t *testing.T) { @@ -1830,17 +1335,10 @@ func TestKEYSMap(t *testing.T) { assert.Contains(t, top.value, makeStackItem([]byte{0, 1})) } -func TestKEYSNoArgument(t *testing.T) { +func TestKEYS(t *testing.T) { prog := makeProgram(opcode.KEYS) - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestKEYSWrongType(t *testing.T) { - prog := makeProgram(opcode.KEYS) - vm := load(prog) - vm.estack.PushVal([]StackItem{}) - checkVMFailed(t, vm) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("WrongType", getTestFuncForVM(prog, nil, []StackItem{})) } func TestVALUESMap(t *testing.T) { @@ -1861,169 +1359,48 @@ func TestVALUESMap(t *testing.T) { assert.Contains(t, top.value, makeStackItem([]StackItem{})) } -func TestVALUESArray(t *testing.T) { +func TestVALUES(t *testing.T) { prog := makeProgram(opcode.VALUES) - vm := load(prog) - vm.estack.PushVal([]StackItem{makeStackItem(4)}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &ArrayItem{[]StackItem{makeStackItem(4)}}, vm.estack.Pop().value) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("WrongType", getTestFuncForVM(prog, nil, 5)) + t.Run("Array", getTestFuncForVM(prog, []int{4}, []int{4})) } -func TestVALUESNoArgument(t *testing.T) { - prog := makeProgram(opcode.VALUES) - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestVALUESWrongType(t *testing.T) { - prog := makeProgram(opcode.VALUES) - vm := load(prog) - vm.estack.PushVal(5) - checkVMFailed(t, vm) -} - -func TestHASKEYArrayTrue(t *testing.T) { - prog := makeProgram(opcode.PUSH5, opcode.NEWARRAY, opcode.PUSH4, opcode.HASKEY) - vm := load(prog) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(true), vm.estack.Pop().value) -} - -func TestHASKEYArrayFalse(t *testing.T) { - prog := makeProgram(opcode.PUSH5, opcode.NEWARRAY, opcode.PUSH5, opcode.HASKEY) - vm := load(prog) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(false), vm.estack.Pop().value) -} - -func TestHASKEYStructTrue(t *testing.T) { - prog := makeProgram(opcode.PUSH5, opcode.NEWSTRUCT, opcode.PUSH4, opcode.HASKEY) - vm := load(prog) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(true), vm.estack.Pop().value) -} - -func TestHASKEYStructFalse(t *testing.T) { - prog := makeProgram(opcode.PUSH5, opcode.NEWSTRUCT, opcode.PUSH5, opcode.HASKEY) - vm := load(prog) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(false), vm.estack.Pop().value) -} - -func TestHASKEYMapTrue(t *testing.T) { +func TestHASKEY(t *testing.T) { + prog := makeProgram(opcode.HASKEY) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("OneArgument", getTestFuncForVM(prog, nil, 1)) + t.Run("WrongKeyType", getTestFuncForVM(prog, nil, []StackItem{}, []StackItem{})) + t.Run("WrongCollectionType", getTestFuncForVM(prog, nil, 1, 2)) + + arr := makeArrayOfType(5, BooleanT) + t.Run("Array", func(t *testing.T) { + t.Run("True", getTestFuncForVM(prog, true, NewArrayItem(arr), 4)) + t.Run("False", getTestFuncForVM(prog, false, NewArrayItem(arr), 5)) + }) + t.Run("Struct", func(t *testing.T) { + t.Run("True", getTestFuncForVM(prog, true, NewStructItem(arr), 4)) + t.Run("False", getTestFuncForVM(prog, false, NewStructItem(arr), 5)) + }) +} + +func TestHASKEYMap(t *testing.T) { prog := makeProgram(opcode.HASKEY) - vm := load(prog) m := NewMapItem() m.Add(makeStackItem(5), makeStackItem(6)) - vm.estack.Push(&Element{value: m}) - vm.estack.PushVal(5) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(true), vm.estack.Pop().value) + t.Run("True", getTestFuncForVM(prog, true, m, 5)) + t.Run("False", getTestFuncForVM(prog, false, m, 6)) } -func TestHASKEYMapFalse(t *testing.T) { - prog := makeProgram(opcode.HASKEY) - vm := load(prog) - m := NewMapItem() - m.Add(makeStackItem(5), makeStackItem(6)) - vm.estack.Push(&Element{value: m}) - vm.estack.PushVal(6) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(false), vm.estack.Pop().value) -} - -func TestHASKEYNoArguments(t *testing.T) { - prog := makeProgram(opcode.HASKEY) - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestHASKEY1Argument(t *testing.T) { - prog := makeProgram(opcode.HASKEY) - vm := load(prog) - vm.estack.PushVal(1) - checkVMFailed(t, vm) -} - -func TestHASKEYWrongKeyType(t *testing.T) { - prog := makeProgram(opcode.HASKEY) - vm := load(prog) - vm.estack.PushVal([]StackItem{}) - vm.estack.PushVal([]StackItem{}) - checkVMFailed(t, vm) -} - -func TestHASKEYWrongCollectionType(t *testing.T) { - prog := makeProgram(opcode.HASKEY) - vm := load(prog) - vm.estack.PushVal(1) - vm.estack.PushVal(2) - checkVMFailed(t, vm) -} - -func TestSIGNNoArgument(t *testing.T) { +func TestSIGN(t *testing.T) { prog := makeProgram(opcode.SIGN) - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestSIGNWrongType(t *testing.T) { - prog := makeProgram(opcode.SIGN) - vm := load(prog) - vm.estack.PushVal([]StackItem{}) - checkVMFailed(t, vm) -} - -func TestSIGNBool(t *testing.T) { - prog := makeProgram(opcode.SIGN) - vm := load(prog) - vm.estack.PushVal(false) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &BigIntegerItem{big.NewInt(0)}, vm.estack.Pop().value) -} - -func TestSIGNPositiveInt(t *testing.T) { - prog := makeProgram(opcode.SIGN) - vm := load(prog) - vm.estack.PushVal(1) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &BigIntegerItem{big.NewInt(1)}, vm.estack.Pop().value) -} - -func TestSIGNNegativeInt(t *testing.T) { - prog := makeProgram(opcode.SIGN) - vm := load(prog) - vm.estack.PushVal(-1) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &BigIntegerItem{big.NewInt(-1)}, vm.estack.Pop().value) -} - -func TestSIGNZero(t *testing.T) { - prog := makeProgram(opcode.SIGN) - vm := load(prog) - vm.estack.PushVal(0) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &BigIntegerItem{big.NewInt(0)}, vm.estack.Pop().value) -} - -func TestSIGNByteArray(t *testing.T) { - prog := makeProgram(opcode.SIGN) - vm := load(prog) - vm.estack.PushVal([]byte{0, 1}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &BigIntegerItem{big.NewInt(1)}, vm.estack.Pop().value) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("WrongType", getTestFuncForVM(prog, nil, []StackItem{})) + t.Run("Bool", getTestFuncForVM(prog, 0, false)) + t.Run("PositiveInt", getTestFuncForVM(prog, 1, 2)) + t.Run("NegativeInt", getTestFuncForVM(prog, -1, -1)) + t.Run("Zero", getTestFuncForVM(prog, 0, 0)) + t.Run("ByteArray", getTestFuncForVM(prog, 1, []byte{0, 1})) } func TestAppCall(t *testing.T) { @@ -2105,34 +1482,16 @@ func TestSimpleCall(t *testing.T) { assert.Equal(t, result, int(vm.estack.Pop().BigInt().Int64())) } -func TestNZtrue(t *testing.T) { +func TestNZ(t *testing.T) { prog := makeProgram(opcode.NZ) - vm := load(prog) - vm.estack.PushVal(1) - runVM(t, vm) - assert.Equal(t, true, vm.estack.Pop().Bool()) + t.Run("True", getTestFuncForVM(prog, true, 1)) + t.Run("False", getTestFuncForVM(prog, false, 0)) } -func TestNZfalse(t *testing.T) { - prog := makeProgram(opcode.NZ) - vm := load(prog) - vm.estack.PushVal(0) - runVM(t, vm) - assert.Equal(t, false, vm.estack.Pop().Bool()) -} - -func TestPICKbadNoitem(t *testing.T) { +func TestPICK(t *testing.T) { prog := makeProgram(opcode.PICK) - vm := load(prog) - vm.estack.PushVal(1) - checkVMFailed(t, vm) -} - -func TestPICKbadNegative(t *testing.T) { - prog := makeProgram(opcode.PICK) - vm := load(prog) - vm.estack.PushVal(-1) - checkVMFailed(t, vm) + t.Run("NoItem", getTestFuncForVM(prog, nil, 1)) + t.Run("Negative", getTestFuncForVM(prog, nil, -1)) } func TestPICKgood(t *testing.T) { @@ -2167,10 +1526,7 @@ func TestPICKDup(t *testing.T) { func TestROTBad(t *testing.T) { prog := makeProgram(opcode.ROT) - vm := load(prog) - vm.estack.PushVal(1) - vm.estack.PushVal(2) - checkVMFailed(t, vm) + runWithArgs(t, prog, nil, 1, 2) } func TestROTGood(t *testing.T) { @@ -2188,20 +1544,12 @@ func TestROTGood(t *testing.T) { func TestROLLBad1(t *testing.T) { prog := makeProgram(opcode.ROLL) - vm := load(prog) - vm.estack.PushVal(1) - vm.estack.PushVal(-1) - checkVMFailed(t, vm) + runWithArgs(t, prog, nil, 1, -1) } func TestROLLBad2(t *testing.T) { prog := makeProgram(opcode.ROLL) - vm := load(prog) - vm.estack.PushVal(1) - vm.estack.PushVal(2) - vm.estack.PushVal(3) - vm.estack.PushVal(3) - checkVMFailed(t, vm) + runWithArgs(t, prog, nil, 1, 2, 3, 3) } func TestROLLGood(t *testing.T) { @@ -2220,34 +1568,12 @@ func TestROLLGood(t *testing.T) { assert.Equal(t, makeStackItem(1), vm.estack.Pop().value) } -func TestXTUCKbadNoitem(t *testing.T) { +func TestXTUCK(t *testing.T) { prog := makeProgram(opcode.XTUCK) - vm := load(prog) - vm.estack.PushVal(1) - checkVMFailed(t, vm) -} - -func TestXTUCKbadNoN(t *testing.T) { - prog := makeProgram(opcode.XTUCK) - vm := load(prog) - vm.estack.PushVal(1) - vm.estack.PushVal(2) - checkVMFailed(t, vm) -} - -func TestXTUCKbadNegative(t *testing.T) { - prog := makeProgram(opcode.XTUCK) - vm := load(prog) - vm.estack.PushVal(-1) - checkVMFailed(t, vm) -} - -func TestXTUCKbadZero(t *testing.T) { - prog := makeProgram(opcode.XTUCK) - vm := load(prog) - vm.estack.PushVal(1) - vm.estack.PushVal(0) - checkVMFailed(t, vm) + t.Run("NoItem", getTestFuncForVM(prog, nil, 1)) + t.Run("NoN", getTestFuncForVM(prog, nil, 1, 2)) + t.Run("Negative", getTestFuncForVM(prog, nil, -1)) + t.Run("Zero", getTestFuncForVM(prog, nil, 1, 0)) } func TestXTUCKgood(t *testing.T) { @@ -2269,15 +1595,8 @@ func TestXTUCKgood(t *testing.T) { func TestTUCKbadNoitems(t *testing.T) { prog := makeProgram(opcode.TUCK) - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestTUCKbadNoitem(t *testing.T) { - prog := makeProgram(opcode.TUCK) - vm := load(prog) - vm.estack.PushVal(1) - checkVMFailed(t, vm) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("NoItem", getTestFuncForVM(prog, nil, 1)) } func TestTUCKgood(t *testing.T) { @@ -2304,19 +1623,10 @@ func TestTUCKgood2(t *testing.T) { assert.Equal(t, int64(11), vm.estack.Peek(3).BigInt().Int64()) } -func TestOVERbadNoitem(t *testing.T) { +func TestOVER(t *testing.T) { prog := makeProgram(opcode.OVER) - vm := load(prog) - vm.estack.PushVal(1) - checkVMFailed(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(1), vm.estack.Pop().value) -} - -func TestOVERbadNoitems(t *testing.T) { - prog := makeProgram(opcode.OVER) - vm := load(prog) - checkVMFailed(t, vm) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("NoItem", getTestFuncForVM(prog, nil, 1)) } func TestOVERgood(t *testing.T) { @@ -2349,25 +1659,17 @@ func TestOVERDup(t *testing.T) { func TestNIPBadNoItem(t *testing.T) { prog := makeProgram(opcode.NIP) - vm := load(prog) - vm.estack.PushVal(1) - checkVMFailed(t, vm) + runWithArgs(t, prog, nil, 1) } func TestNIPGood(t *testing.T) { prog := makeProgram(opcode.NIP) - vm := load(prog) - vm.estack.PushVal(1) - vm.estack.PushVal(2) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, makeStackItem(2), vm.estack.Pop().value) + runWithArgs(t, prog, 2, 1, 2) } func TestDROPBadNoItem(t *testing.T) { prog := makeProgram(opcode.DROP) - vm := load(prog) - checkVMFailed(t, vm) + runWithArgs(t, prog, nil) } func TestDROPGood(t *testing.T) { @@ -2378,26 +1680,11 @@ func TestDROPGood(t *testing.T) { assert.Equal(t, 0, vm.estack.Len()) } -func TestXDROPbadNoitem(t *testing.T) { +func TestXDROP(t *testing.T) { prog := makeProgram(opcode.XDROP) - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestXDROPbadNoN(t *testing.T) { - prog := makeProgram(opcode.XDROP) - vm := load(prog) - vm.estack.PushVal(1) - vm.estack.PushVal(2) - checkVMFailed(t, vm) -} - -func TestXDROPbadNegative(t *testing.T) { - prog := makeProgram(opcode.XDROP) - vm := load(prog) - vm.estack.PushVal(1) - vm.estack.PushVal(-1) - checkVMFailed(t, vm) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("NoN", getTestFuncForVM(prog, nil, 1, 2)) + t.Run("Negative", getTestFuncForVM(prog, nil, 1, -1)) } func TestXDROPgood(t *testing.T) { @@ -2415,16 +1702,12 @@ func TestXDROPgood(t *testing.T) { func TestINVERTbadNoitem(t *testing.T) { prog := makeProgram(opcode.INVERT) - vm := load(prog) - checkVMFailed(t, vm) + runWithArgs(t, prog, nil) } func TestINVERTgood1(t *testing.T) { prog := makeProgram(opcode.INVERT) - vm := load(prog) - vm.estack.PushVal(0) - runVM(t, vm) - assert.Equal(t, int64(-1), vm.estack.Peek(0).BigInt().Int64()) + runWithArgs(t, prog, -1, 0) } func TestINVERTgood2(t *testing.T) { @@ -2457,107 +1740,29 @@ func TestINVERTWithConversion2(t *testing.T) { assert.Equal(t, int64(-1), vm.estack.Peek(0).BigInt().Int64()) } -func TestCATBadNoArgs(t *testing.T) { +func TestCAT(t *testing.T) { prog := makeProgram(opcode.CAT) - vm := load(prog) - checkVMFailed(t, vm) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("OneArgument", getTestFuncForVM(prog, nil, []byte("abc"))) + t.Run("BigItem", func(t *testing.T) { + arg := make([]byte, MaxItemSize/2+1) + runWithArgs(t, prog, nil, arg, arg) + }) + t.Run("Good", getTestFuncForVM(prog, []byte("abcdef"), []byte("abc"), []byte("def"))) + t.Run("Int0ByteArray", getTestFuncForVM(prog, []byte{}, 0, []byte{})) + t.Run("ByteArrayInt1", getTestFuncForVM(prog, []byte{1}, []byte{}, 1)) } -func TestCATBadOneArg(t *testing.T) { - prog := makeProgram(opcode.CAT) - vm := load(prog) - vm.estack.PushVal([]byte("abc")) - checkVMFailed(t, vm) -} - -func TestCATBadBigItem(t *testing.T) { - prog := makeProgram(opcode.CAT) - vm := load(prog) - vm.estack.PushVal(make([]byte, MaxItemSize/2+1)) - vm.estack.PushVal(make([]byte, MaxItemSize/2+1)) - vm.Run() - assert.Equal(t, true, vm.HasFailed()) -} - -func TestCATGood(t *testing.T) { - prog := makeProgram(opcode.CAT) - vm := load(prog) - vm.estack.PushVal([]byte("abc")) - vm.estack.PushVal([]byte("def")) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, []byte("abcdef"), vm.estack.Peek(0).Bytes()) -} - -func TestCATInt0ByteArray(t *testing.T) { - prog := makeProgram(opcode.CAT) - vm := load(prog) - vm.estack.PushVal(0) - vm.estack.PushVal([]byte{}) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &ByteArrayItem{[]byte{}}, vm.estack.Pop().value) -} - -func TestCATByteArrayInt1(t *testing.T) { - prog := makeProgram(opcode.CAT) - vm := load(prog) - vm.estack.PushVal([]byte{}) - vm.estack.PushVal(1) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, &ByteArrayItem{[]byte{1}}, vm.estack.Pop().value) -} - -func TestSUBSTRBadNoArgs(t *testing.T) { +func TestSUBSTR(t *testing.T) { prog := makeProgram(opcode.SUBSTR) - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestSUBSTRBadOneArg(t *testing.T) { - prog := makeProgram(opcode.SUBSTR) - vm := load(prog) - vm.estack.PushVal(1) - checkVMFailed(t, vm) -} - -func TestSUBSTRBadTwoArgs(t *testing.T) { - prog := makeProgram(opcode.SUBSTR) - vm := load(prog) - vm.estack.PushVal(0) - vm.estack.PushVal(2) - checkVMFailed(t, vm) -} - -func TestSUBSTRGood(t *testing.T) { - prog := makeProgram(opcode.SUBSTR) - vm := load(prog) - vm.estack.PushVal([]byte("abcdef")) - vm.estack.PushVal(1) - vm.estack.PushVal(2) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, []byte("bc"), vm.estack.Peek(0).Bytes()) -} - -func TestSUBSTRBadOffset(t *testing.T) { - prog := makeProgram(opcode.SUBSTR) - vm := load(prog) - vm.estack.PushVal([]byte("abcdef")) - vm.estack.PushVal(7) - vm.estack.PushVal(1) - - checkVMFailed(t, vm) -} - -func TestSUBSTRBigLen(t *testing.T) { - prog := makeProgram(opcode.SUBSTR) - vm := load(prog) - vm.estack.PushVal([]byte("abcdef")) - vm.estack.PushVal(1) - vm.estack.PushVal(6) - checkVMFailed(t, vm) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("OneArgument", getTestFuncForVM(prog, nil, 1)) + t.Run("TwoArguments", getTestFuncForVM(prog, nil, 0, 2)) + t.Run("Good", getTestFuncForVM(prog, []byte("bc"), []byte("abcdef"), 1, 2)) + t.Run("BadOffset", getTestFuncForVM(prog, nil, []byte("abcdef"), 7, 1)) + t.Run("BigLen", getTestFuncForVM(prog, nil, []byte("abcdef"), 1, 6)) + t.Run("NegativeOffset", getTestFuncForVM(prog, nil, []byte("abcdef"), -1, 3)) + t.Run("NegativeLen", getTestFuncForVM(prog, nil, []byte("abcdef"), 3, -1)) } func TestSUBSTRBad387(t *testing.T) { @@ -2571,109 +1776,28 @@ func TestSUBSTRBad387(t *testing.T) { checkVMFailed(t, vm) } -func TestSUBSTRBadNegativeOffset(t *testing.T) { - prog := makeProgram(opcode.SUBSTR) - vm := load(prog) - vm.estack.PushVal([]byte("abcdef")) - vm.estack.PushVal(-1) - vm.estack.PushVal(3) - checkVMFailed(t, vm) -} - -func TestSUBSTRBadNegativeLen(t *testing.T) { - prog := makeProgram(opcode.SUBSTR) - vm := load(prog) - vm.estack.PushVal([]byte("abcdef")) - vm.estack.PushVal(3) - vm.estack.PushVal(-1) - checkVMFailed(t, vm) -} - -func TestLEFTBadNoArgs(t *testing.T) { +func TestLEFT(t *testing.T) { prog := makeProgram(opcode.LEFT) - vm := load(prog) - checkVMFailed(t, vm) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("NoString", getTestFuncForVM(prog, nil, 2)) + t.Run("NegativeLen", getTestFuncForVM(prog, nil, "abcdef", -1)) + t.Run("Good", getTestFuncForVM(prog, "ab", "abcdef", 2)) + t.Run("GoodBigLen", getTestFuncForVM(prog, "abcdef", "abcdef", 8)) } -func TestLEFTBadNoString(t *testing.T) { - prog := makeProgram(opcode.LEFT) - vm := load(prog) - vm.estack.PushVal(2) - checkVMFailed(t, vm) -} - -func TestLEFTBadNegativeLen(t *testing.T) { - prog := makeProgram(opcode.LEFT) - vm := load(prog) - vm.estack.PushVal([]byte("abcdef")) - vm.estack.PushVal(-1) - checkVMFailed(t, vm) -} - -func TestLEFTGood(t *testing.T) { - prog := makeProgram(opcode.LEFT) - vm := load(prog) - vm.estack.PushVal([]byte("abcdef")) - vm.estack.PushVal(2) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, []byte("ab"), vm.estack.Peek(0).Bytes()) -} - -func TestLEFTGoodLen(t *testing.T) { - prog := makeProgram(opcode.LEFT) - vm := load(prog) - vm.estack.PushVal([]byte("abcdef")) - vm.estack.PushVal(8) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, []byte("abcdef"), vm.estack.Peek(0).Bytes()) -} - -func TestRIGHTBadNoArgs(t *testing.T) { +func TestRIGHT(t *testing.T) { prog := makeProgram(opcode.RIGHT) - vm := load(prog) - checkVMFailed(t, vm) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("NoString", getTestFuncForVM(prog, nil, 2)) + t.Run("NegativeLen", getTestFuncForVM(prog, nil, "abcdef", -1)) + t.Run("Good", getTestFuncForVM(prog, "ef", "abcdef", 2)) + t.Run("BadLen", getTestFuncForVM(prog, nil, "abcdef", 8)) } -func TestRIGHTBadNoString(t *testing.T) { - prog := makeProgram(opcode.RIGHT) - vm := load(prog) - vm.estack.PushVal(2) - checkVMFailed(t, vm) -} - -func TestRIGHTBadNegativeLen(t *testing.T) { - prog := makeProgram(opcode.RIGHT) - vm := load(prog) - vm.estack.PushVal([]byte("abcdef")) - vm.estack.PushVal(-1) - checkVMFailed(t, vm) -} - -func TestRIGHTGood(t *testing.T) { - prog := makeProgram(opcode.RIGHT) - vm := load(prog) - vm.estack.PushVal([]byte("abcdef")) - vm.estack.PushVal(2) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, []byte("ef"), vm.estack.Peek(0).Bytes()) -} - -func TestRIGHTBadLen(t *testing.T) { - prog := makeProgram(opcode.RIGHT) - vm := load(prog) - vm.estack.PushVal([]byte("abcdef")) - vm.estack.PushVal(8) - checkVMFailed(t, vm) -} - -func TestPACKBadLen(t *testing.T) { +func TestPACK(t *testing.T) { prog := makeProgram(opcode.PACK) - vm := load(prog) - vm.estack.PushVal(1) - checkVMFailed(t, vm) + t.Run("BadLen", getTestFuncForVM(prog, nil, 1)) + t.Run("Good0Len", getTestFuncForVM(prog, []StackItem{}, 0)) } func TestPACKBigLen(t *testing.T) { @@ -2686,15 +1810,6 @@ func TestPACKBigLen(t *testing.T) { checkVMFailed(t, vm) } -func TestPACKGoodZeroLen(t *testing.T) { - prog := makeProgram(opcode.PACK) - vm := load(prog) - vm.estack.PushVal(0) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, []StackItem{}, vm.estack.Peek(0).Array()) -} - func TestPACKGood(t *testing.T) { prog := makeProgram(opcode.PACK) elements := []int{55, 34, 42} @@ -2718,9 +1833,7 @@ func TestPACKGood(t *testing.T) { func TestUNPACKBadNotArray(t *testing.T) { prog := makeProgram(opcode.UNPACK) - vm := load(prog) - vm.estack.PushVal(1) - checkVMFailed(t, vm) + runWithArgs(t, prog, nil, 1) } func TestUNPACKGood(t *testing.T) { @@ -2843,34 +1956,12 @@ func TestREVERSEITEMSGood(t *testing.T) { } } -func TestREMOVEBadNoArgs(t *testing.T) { +func TestREMOVE(t *testing.T) { prog := makeProgram(opcode.REMOVE) - vm := load(prog) - checkVMFailed(t, vm) -} - -func TestREMOVEBadOneArg(t *testing.T) { - prog := makeProgram(opcode.REMOVE) - vm := load(prog) - vm.estack.PushVal(1) - checkVMFailed(t, vm) -} - -func TestREMOVEBadNotArray(t *testing.T) { - prog := makeProgram(opcode.REMOVE) - vm := load(prog) - vm.estack.PushVal(1) - vm.estack.PushVal(1) - checkVMFailed(t, vm) -} - -func TestREMOVEBadIndex(t *testing.T) { - prog := makeProgram(opcode.REMOVE) - elements := []int{22, 34, 42, 55, 81} - vm := load(prog) - vm.estack.PushVal(elements) - vm.estack.PushVal(10) - checkVMFailed(t, vm) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("OneArgument", getTestFuncForVM(prog, nil, 1)) + t.Run("NotArray", getTestFuncForVM(prog, nil, 1, 1)) + t.Run("BadIndex", getTestFuncForVM(prog, nil, []int{22, 34, 42, 55, 81}, 10)) } func TestREMOVEGood(t *testing.T) { @@ -2933,9 +2024,7 @@ func TestCLEARITEMS(t *testing.T) { t.Run("Integer", func(t *testing.T) { prog := makeProgram(opcode.CLEARITEMS) - v := load(prog) - v.estack.PushVal(1) - checkVMFailed(t, v) + runWithArgs(t, prog, nil, 1) }) } @@ -2950,17 +2039,10 @@ func TestSWAPGood(t *testing.T) { assert.Equal(t, int64(4), vm.estack.Pop().BigInt().Int64()) } -func TestSWAPBad1(t *testing.T) { +func TestSWAP(t *testing.T) { prog := makeProgram(opcode.SWAP) - vm := load(prog) - vm.estack.PushVal(4) - checkVMFailed(t, vm) -} - -func TestSWAPBad2(t *testing.T) { - prog := makeProgram(opcode.SWAP) - vm := load(prog) - checkVMFailed(t, vm) + t.Run("EmptyStack", getTestFuncForVM(prog, nil)) + t.Run("SmallStack", getTestFuncForVM(prog, nil, 4)) } func TestXSWAPGood(t *testing.T) { @@ -2983,22 +2065,12 @@ func TestXSWAPGood(t *testing.T) { func TestXSWAPBad1(t *testing.T) { prog := makeProgram(opcode.XSWAP) - vm := load(prog) - vm.estack.PushVal(1) - vm.estack.PushVal(2) - vm.estack.PushVal(-1) - checkVMFailed(t, vm) + runWithArgs(t, prog, nil, 1, 2, -1) } func TestXSWAPBad2(t *testing.T) { prog := makeProgram(opcode.XSWAP) - vm := load(prog) - vm.estack.PushVal(1) - vm.estack.PushVal(2) - vm.estack.PushVal(3) - vm.estack.PushVal(4) - vm.estack.PushVal(4) - checkVMFailed(t, vm) + runWithArgs(t, prog, nil, 1, 2, 3, 4, 4) } func TestDupInt(t *testing.T) {