diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index d91cdf759..696e96914 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -940,13 +940,12 @@ func (c *codegen) emitReverse(num int) { case 2: emit.Opcode(c.prog.BinWriter, opcode.SWAP) case 3: - emit.Int(c.prog.BinWriter, 2) - emit.Opcode(c.prog.BinWriter, opcode.XSWAP) + emit.Opcode(c.prog.BinWriter, opcode.REVERSE3) + case 4: + emit.Opcode(c.prog.BinWriter, opcode.REVERSE4) default: - for i := 1; i < num; i++ { - emit.Int(c.prog.BinWriter, int64(i)) - emit.Opcode(c.prog.BinWriter, opcode.ROLL) - } + emit.Int(c.prog.BinWriter, int64(num)) + emit.Opcode(c.prog.BinWriter, opcode.REVERSEN) } } diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index a41961d1f..aba846861 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -48,18 +48,18 @@ type rpcTestCase struct { check func(t *testing.T, e *executor, result interface{}) } -const testContractHash = "642e2f47cc6883f0c196cf0dd3dcbb2333300173" +const testContractHash = "76751a2fdde4dc6c7489799a28bb539bc09d1f54" var rpcTestCases = map[string][]rpcTestCase{ "getapplicationlog": { { name: "positive", - params: `["9872fd330d63d64beba7122fcc9678e7f380d2163acff6a7d4f67a3c01cd67d1"]`, + params: `["113437bd8dfc44e3a6dfe77b750fcff246cbe933ca9667311f45d794cf0410cc"]`, 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("9872fd330d63d64beba7122fcc9678e7f380d2163acff6a7d4f67a3c01cd67d1") + expectedTxHash, err := util.Uint256DecodeStringLE("113437bd8dfc44e3a6dfe77b750fcff246cbe933ca9667311f45d794cf0410cc") 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 a82e371d5..092a7f0a2 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 91f52796f..5cd45c5e2 100644 Binary files a/pkg/rpc/server/testdata/testblocks.acc and b/pkg/rpc/server/testdata/testblocks.acc differ diff --git a/pkg/vm/context.go b/pkg/vm/context.go index 3a799b13c..b20dbb088 100644 --- a/pkg/vm/context.go +++ b/pkg/vm/context.go @@ -74,6 +74,12 @@ func (c *Context) Next() (opcode.Opcode, []byte, error) { var numtoread int switch instr { + case opcode.OLDPUSH1: + // OLDPUSH1 is used during transition to NEO3 in verification scripts. + // FIXME remove #927 + if len(c.prog) == 1 { + return opcode.PUSH1, nil, nil + } case opcode.PUSHDATA1: if c.nextip >= len(c.prog) { err = errNoInstParam diff --git a/pkg/vm/opcode/opcode.go b/pkg/vm/opcode/opcode.go index 071317cdf..bbe71772f 100644 --- a/pkg/vm/opcode/opcode.go +++ b/pkg/vm/opcode/opcode.go @@ -65,31 +65,33 @@ const ( CALL Opcode = 0x34 CALLL Opcode = 0x35 - // Legacy - OLDPUSH1 Opcode = 0x51 + // Stack + DEPTH Opcode = 0x43 + DROP Opcode = 0x45 + NIP Opcode = 0x46 + XDROP Opcode = 0x48 + CLEAR Opcode = 0x49 + DUP Opcode = 0x4A + OVER Opcode = 0x4B + PICK Opcode = 0x4D + TUCK Opcode = 0x4E + SWAP Opcode = 0x50 + OLDPUSH1 Opcode = 0x51 // FIXME remove #927 + ROT Opcode = 0x51 + ROLL Opcode = 0x52 + REVERSE3 Opcode = 0x53 + REVERSE4 Opcode = 0x54 + REVERSEN Opcode = 0x55 RET Opcode = 0x66 APPCALL Opcode = 0x67 SYSCALL Opcode = 0x68 TAILCALL Opcode = 0x69 - // Stack + // Old stack opcodes DUPFROMALTSTACK Opcode = 0x6A TOALTSTACK Opcode = 0x6B FROMALTSTACK Opcode = 0x6C - XDROP Opcode = 0x6D - XSWAP Opcode = 0x72 - XTUCK Opcode = 0x73 - DEPTH Opcode = 0x74 - DROP Opcode = 0x75 - DUP Opcode = 0x76 - NIP Opcode = 0x77 - OVER Opcode = 0x78 - PICK Opcode = 0x79 - ROLL Opcode = 0x7A - ROT Opcode = 0x7B - SWAP Opcode = 0x7C - TUCK Opcode = 0x7D // Splice CAT Opcode = 0x7E diff --git a/pkg/vm/opcode/opcode_string.go b/pkg/vm/opcode/opcode_string.go index 39d7cbbfe..9a8e2b655 100644 --- a/pkg/vm/opcode/opcode_string.go +++ b/pkg/vm/opcode/opcode_string.go @@ -59,7 +59,22 @@ func _() { _ = x[JMPLEL-51] _ = x[CALL-52] _ = x[CALLL-53] + _ = x[DEPTH-67] + _ = x[DROP-69] + _ = x[NIP-70] + _ = x[XDROP-72] + _ = x[CLEAR-73] + _ = x[DUP-74] + _ = x[OVER-75] + _ = x[PICK-77] + _ = x[TUCK-78] + _ = x[SWAP-80] _ = x[OLDPUSH1-81] + _ = x[ROT-81] + _ = x[ROLL-82] + _ = x[REVERSE3-83] + _ = x[REVERSE4-84] + _ = x[REVERSEN-85] _ = x[RET-102] _ = x[APPCALL-103] _ = x[SYSCALL-104] @@ -67,19 +82,6 @@ func _() { _ = x[DUPFROMALTSTACK-106] _ = x[TOALTSTACK-107] _ = x[FROMALTSTACK-108] - _ = x[XDROP-109] - _ = x[XSWAP-114] - _ = x[XTUCK-115] - _ = x[DEPTH-116] - _ = x[DROP-117] - _ = x[DUP-118] - _ = x[NIP-119] - _ = x[OVER-120] - _ = x[PICK-121] - _ = x[ROLL-122] - _ = x[ROT-123] - _ = x[SWAP-124] - _ = x[TUCK-125] _ = x[CAT-126] _ = x[SUBSTR-127] _ = x[LEFT-128] @@ -89,6 +91,7 @@ func _() { _ = x[OR-146] _ = x[XOR-147] _ = x[EQUAL-151] + _ = x[NOTEQUAL-152] _ = x[SIGN-153] _ = x[ABS-154] _ = x[NEGATE-155] @@ -139,7 +142,7 @@ func _() { _ = x[THROWIFNOT-241] } -const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLOLDPUSH1RETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERTTHROWTHROWIFNOT" +const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENRETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERTTHROWTHROWIFNOT" var _Opcode_map = map[Opcode]string{ 0: _Opcode_name[0:8], @@ -191,84 +194,86 @@ var _Opcode_map = map[Opcode]string{ 51: _Opcode_name[286:292], 52: _Opcode_name[292:296], 53: _Opcode_name[296:301], - 81: _Opcode_name[301:309], - 102: _Opcode_name[309:312], - 103: _Opcode_name[312:319], - 104: _Opcode_name[319:326], - 105: _Opcode_name[326:334], - 106: _Opcode_name[334:349], - 107: _Opcode_name[349:359], - 108: _Opcode_name[359:371], - 109: _Opcode_name[371:376], - 114: _Opcode_name[376:381], - 115: _Opcode_name[381:386], - 116: _Opcode_name[386:391], - 117: _Opcode_name[391:395], - 118: _Opcode_name[395:398], - 119: _Opcode_name[398:401], - 120: _Opcode_name[401:405], - 121: _Opcode_name[405:409], - 122: _Opcode_name[409:413], - 123: _Opcode_name[413:416], - 124: _Opcode_name[416:420], - 125: _Opcode_name[420:424], - 126: _Opcode_name[424:427], - 127: _Opcode_name[427:433], - 128: _Opcode_name[433:437], - 129: _Opcode_name[437:442], - 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], - 195: _Opcode_name[579:587], - 196: _Opcode_name[587:596], - 197: _Opcode_name[596:606], - 198: _Opcode_name[606:615], - 200: _Opcode_name[615:621], - 202: _Opcode_name[621:625], - 203: _Opcode_name[625:631], - 204: _Opcode_name[631:635], - 205: _Opcode_name[635:641], - 206: _Opcode_name[641:649], - 207: _Opcode_name[649:655], - 208: _Opcode_name[655:662], - 209: _Opcode_name[662:674], - 210: _Opcode_name[674:680], - 211: _Opcode_name[680:690], - 216: _Opcode_name[690:696], - 217: _Opcode_name[696:702], - 219: _Opcode_name[702:709], - 240: _Opcode_name[709:714], - 241: _Opcode_name[714:724], + 67: _Opcode_name[301:306], + 69: _Opcode_name[306:310], + 70: _Opcode_name[310:313], + 72: _Opcode_name[313:318], + 73: _Opcode_name[318:323], + 74: _Opcode_name[323:326], + 75: _Opcode_name[326:330], + 77: _Opcode_name[330:334], + 78: _Opcode_name[334:338], + 80: _Opcode_name[338:342], + 81: _Opcode_name[342:350], + 82: _Opcode_name[350:354], + 83: _Opcode_name[354:362], + 84: _Opcode_name[362:370], + 85: _Opcode_name[370:378], + 102: _Opcode_name[378:381], + 103: _Opcode_name[381:388], + 104: _Opcode_name[388:395], + 105: _Opcode_name[395:403], + 106: _Opcode_name[403:418], + 107: _Opcode_name[418:428], + 108: _Opcode_name[428:440], + 126: _Opcode_name[440:443], + 127: _Opcode_name[443:449], + 128: _Opcode_name[449:453], + 129: _Opcode_name[453:458], + 144: _Opcode_name[458:464], + 145: _Opcode_name[464:467], + 146: _Opcode_name[467:469], + 147: _Opcode_name[469:472], + 151: _Opcode_name[472:477], + 152: _Opcode_name[477:485], + 153: _Opcode_name[485:489], + 154: _Opcode_name[489:492], + 155: _Opcode_name[492:498], + 156: _Opcode_name[498:501], + 157: _Opcode_name[501:504], + 158: _Opcode_name[504:507], + 159: _Opcode_name[507:510], + 160: _Opcode_name[510:513], + 161: _Opcode_name[513:516], + 162: _Opcode_name[516:519], + 168: _Opcode_name[519:522], + 169: _Opcode_name[522:525], + 170: _Opcode_name[525:528], + 171: _Opcode_name[528:535], + 172: _Opcode_name[535:541], + 177: _Opcode_name[541:543], + 179: _Opcode_name[543:551], + 180: _Opcode_name[551:562], + 181: _Opcode_name[562:564], + 182: _Opcode_name[564:567], + 183: _Opcode_name[567:569], + 184: _Opcode_name[569:572], + 185: _Opcode_name[572:575], + 186: _Opcode_name[575:578], + 187: _Opcode_name[578:584], + 192: _Opcode_name[584:588], + 193: _Opcode_name[588:594], + 194: _Opcode_name[594:603], + 195: _Opcode_name[603:611], + 196: _Opcode_name[611:620], + 197: _Opcode_name[620:630], + 198: _Opcode_name[630:639], + 200: _Opcode_name[639:645], + 202: _Opcode_name[645:649], + 203: _Opcode_name[649:655], + 204: _Opcode_name[655:659], + 205: _Opcode_name[659:665], + 206: _Opcode_name[665:673], + 207: _Opcode_name[673:679], + 208: _Opcode_name[679:686], + 209: _Opcode_name[686:698], + 210: _Opcode_name[698:704], + 211: _Opcode_name[704:714], + 216: _Opcode_name[714:720], + 217: _Opcode_name[720:726], + 219: _Opcode_name[726:733], + 240: _Opcode_name[733:738], + 241: _Opcode_name[738:748], } func (i Opcode) String() string { diff --git a/pkg/vm/stack.go b/pkg/vm/stack.go index fd779e941..e65bcada2 100644 --- a/pkg/vm/stack.go +++ b/pkg/vm/stack.go @@ -353,9 +353,31 @@ func (s *Stack) Swap(n1, n2 int) error { if n1 == n2 { return nil } + s.swap(n1, n2) + return nil +} + +func (s *Stack) swap(n1, n2 int) { a := s.Peek(n1) b := s.Peek(n2) a.value, b.value = b.value, a.value +} + +// ReverseTop reverses top n items of the stack. +func (s *Stack) ReverseTop(n int) error { + if n < 0 { + return errors.New("negative index") + } else if n > s.len { + return errors.New("too big index") + } else if n <= 1 { + return nil + } + + for i, j := 0, n-1; i < j; { + s.swap(i, j) + i++ + j-- + } return nil } diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index 573d28159..c3f79f35e 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -553,10 +553,6 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro val := int(op) - int(opcode.PUSH1) + 1 v.estack.PushVal(val) - case opcode.OLDPUSH1: - // FIXME remove this after Issue transactions will be removed - v.estack.PushVal(1) - case opcode.PUSH0: v.estack.PushVal([]byte{}) @@ -593,25 +589,6 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro case opcode.DUPFROMALTSTACK: v.estack.Push(v.astack.Dup(0)) - case opcode.DUP: - v.estack.Push(v.estack.Dup(0)) - - case opcode.SWAP: - err := v.estack.Swap(1, 0) - if err != nil { - panic(err.Error()) - } - - case opcode.TUCK: - a := v.estack.Dup(0) - if a == nil { - panic("no top-level element found") - } - if v.estack.Len() < 2 { - panic("can't TUCK with a one-element stack") - } - v.estack.InsertAt(a, 2) - case opcode.CAT: b := v.estack.Pop().Bytes() a := v.estack.Pop().Bytes() @@ -656,6 +633,21 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro s := v.estack.Pop().Bytes() v.estack.PushVal(s[len(s)-l:]) + case opcode.DEPTH: + v.estack.PushVal(v.estack.Len()) + + case opcode.DROP: + if v.estack.Len() < 1 { + panic("stack is too small") + } + v.estack.Pop() + + case opcode.NIP: + elem := v.estack.RemoveAt(1) + if elem == nil { + panic("no second element found") + } + case opcode.XDROP: n := int(v.estack.Pop().BigInt().Int64()) if n < 0 { @@ -666,41 +658,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro panic("bad index") } - case opcode.XSWAP: - n := int(v.estack.Pop().BigInt().Int64()) - err := v.estack.Swap(n, 0) - if err != nil { - panic(err.Error()) - } + case opcode.CLEAR: + v.estack.Clear() - case opcode.XTUCK: - n := int(v.estack.Pop().BigInt().Int64()) - if n <= 0 { - panic("XTUCK: invalid length") - } - a := v.estack.Dup(0) - if a == nil { - panic("no top-level element found") - } - if n > v.estack.Len() { - panic("can't push to the position specified") - } - v.estack.InsertAt(a, n) - - case opcode.ROT: - err := v.estack.Roll(2) - if err != nil { - panic(err.Error()) - } - - case opcode.DEPTH: - v.estack.PushVal(v.estack.Len()) - - case opcode.NIP: - elem := v.estack.RemoveAt(1) - if elem == nil { - panic("no second element found") - } + case opcode.DUP: + v.estack.Push(v.estack.Dup(0)) case opcode.OVER: a := v.estack.Dup(1) @@ -720,6 +682,28 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro } v.estack.Push(a) + case opcode.TUCK: + a := v.estack.Dup(0) + if a == nil { + panic("no top-level element found") + } + if v.estack.Len() < 2 { + panic("can't TUCK with a one-element stack") + } + v.estack.InsertAt(a, 2) + + case opcode.SWAP: + err := v.estack.Swap(1, 0) + if err != nil { + panic(err.Error()) + } + + case opcode.ROT: + err := v.estack.Roll(2) + if err != nil { + panic(err.Error()) + } + case opcode.ROLL: n := int(v.estack.Pop().BigInt().Int64()) err := v.estack.Roll(n) @@ -727,11 +711,17 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro panic(err.Error()) } - case opcode.DROP: - if v.estack.Len() < 1 { - panic("stack is too small") + case opcode.REVERSE3, opcode.REVERSE4, opcode.REVERSEN: + n := 3 + switch op { + case opcode.REVERSE4: + n = 4 + case opcode.REVERSEN: + n = int(v.estack.Pop().BigInt().Int64()) + } + if err := v.estack.ReverseTop(n); err != nil { + panic(err.Error()) } - v.estack.Pop() // Bit operations. case opcode.INVERT: diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index d498386d6..f67a760f3 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -1049,22 +1049,32 @@ func runWithArgs(t *testing.T, prog []byte, result interface{}, args ...interfac getTestFuncForVM(prog, result, args...)(t) } -func getTestFuncForVM(prog []byte, result interface{}, args ...interface{}) func(t *testing.T) { +func getCustomTestFuncForVM(prog []byte, check func(t *testing.T, v *VM), 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 { + if check == nil { checkVMFailed(t, v) return } runVM(t, v) - require.Equal(t, 1, v.estack.Len()) - require.Equal(t, makeStackItem(result), v.estack.Pop().value) + check(t, v) } } +func getTestFuncForVM(prog []byte, result interface{}, args ...interface{}) func(t *testing.T) { + var f func(t *testing.T, v *VM) + if result != nil { + f = func(t *testing.T, v *VM) { + require.Equal(t, 1, v.estack.Len()) + require.Equal(t, makeStackItem(result), v.estack.Pop().value) + } + } + return getCustomTestFuncForVM(prog, f, args...) +} + func TestNOTEQUALByteArray(t *testing.T) { prog := makeProgram(opcode.NOTEQUAL) t.Run("True", getTestFuncForVM(prog, true, []byte{1, 2}, []byte{0, 1, 2})) @@ -1568,29 +1578,35 @@ func TestROLLGood(t *testing.T) { assert.Equal(t, makeStackItem(1), vm.estack.Pop().value) } -func TestXTUCK(t *testing.T) { - prog := makeProgram(opcode.XTUCK) - 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 getCheckEStackFunc(items ...interface{}) func(t *testing.T, v *VM) { + return func(t *testing.T, v *VM) { + require.Equal(t, len(items), v.estack.Len()) + for i := 0; i < len(items); i++ { + assert.Equal(t, makeStackItem(items[i]), v.estack.Peek(i).Item()) + } + } } -func TestXTUCKgood(t *testing.T) { - prog := makeProgram(opcode.XTUCK) - topelement := 5 - xtuckdepth := 3 - vm := load(prog) - vm.estack.PushVal(0) - vm.estack.PushVal(1) - vm.estack.PushVal(2) - vm.estack.PushVal(3) - vm.estack.PushVal(4) - vm.estack.PushVal(topelement) - vm.estack.PushVal(xtuckdepth) - runVM(t, vm) - assert.Equal(t, int64(topelement), vm.estack.Peek(0).BigInt().Int64()) - assert.Equal(t, int64(topelement), vm.estack.Peek(xtuckdepth).BigInt().Int64()) +func TestREVERSE3(t *testing.T) { + prog := makeProgram(opcode.REVERSE3) + t.Run("SmallStack", getTestFuncForVM(prog, nil, 1, 2)) + t.Run("Good", getCustomTestFuncForVM(prog, getCheckEStackFunc(1, 2, 3), 1, 2, 3)) +} + +func TestREVERSE4(t *testing.T) { + prog := makeProgram(opcode.REVERSE4) + t.Run("SmallStack", getTestFuncForVM(prog, nil, 1, 2, 3)) + t.Run("Good", getCustomTestFuncForVM(prog, getCheckEStackFunc(1, 2, 3, 4), 1, 2, 3, 4)) +} + +func TestREVERSEN(t *testing.T) { + prog := makeProgram(opcode.REVERSEN) + t.Run("NoArgument", getTestFuncForVM(prog, nil)) + t.Run("SmallStack", getTestFuncForVM(prog, nil, 1, 2, 3)) + t.Run("NegativeArgument", getTestFuncForVM(prog, nil, 1, 2, -1)) + t.Run("Zero", getCustomTestFuncForVM(prog, getCheckEStackFunc(3, 2, 1), 1, 2, 3, 0)) + t.Run("OneItem", getCustomTestFuncForVM(prog, getCheckEStackFunc(42), 42, 1)) + t.Run("Good", getCustomTestFuncForVM(prog, getCheckEStackFunc(1, 2, 3, 4, 5), 1, 2, 3, 4, 5, 5)) } func TestTUCKbadNoitems(t *testing.T) { @@ -1700,6 +1716,15 @@ func TestXDROPgood(t *testing.T) { assert.Equal(t, int64(1), vm.estack.Peek(1).BigInt().Int64()) } +func TestCLEAR(t *testing.T) { + prog := makeProgram(opcode.CLEAR) + v := load(prog) + v.estack.PushVal(123) + require.Equal(t, 1, v.estack.Len()) + require.NoError(t, v.Run()) + require.Equal(t, 0, v.estack.Len()) +} + func TestINVERTbadNoitem(t *testing.T) { prog := makeProgram(opcode.INVERT) runWithArgs(t, prog, nil) @@ -2045,34 +2070,6 @@ func TestSWAP(t *testing.T) { t.Run("SmallStack", getTestFuncForVM(prog, nil, 4)) } -func TestXSWAPGood(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(5) - vm.estack.PushVal(3) - runVM(t, vm) - assert.Equal(t, 5, vm.estack.Len()) - assert.Equal(t, int64(2), vm.estack.Pop().BigInt().Int64()) - assert.Equal(t, int64(4), vm.estack.Pop().BigInt().Int64()) - assert.Equal(t, int64(3), vm.estack.Pop().BigInt().Int64()) - assert.Equal(t, int64(5), vm.estack.Pop().BigInt().Int64()) - assert.Equal(t, int64(1), vm.estack.Pop().BigInt().Int64()) -} - -func TestXSWAPBad1(t *testing.T) { - prog := makeProgram(opcode.XSWAP) - runWithArgs(t, prog, nil, 1, 2, -1) -} - -func TestXSWAPBad2(t *testing.T) { - prog := makeProgram(opcode.XSWAP) - runWithArgs(t, prog, nil, 1, 2, 3, 4, 4) -} - func TestDupInt(t *testing.T) { prog := makeProgram(opcode.DUP, opcode.ABS) vm := load(prog)