mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-26 19:42:23 +00:00
Merge pull request #926 from nspcc-dev/feature/stack
Implement NEO3 VM stack opcodes
This commit is contained in:
commit
963a70d54a
10 changed files with 252 additions and 231 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
BIN
pkg/rpc/server/testdata/test_contract.avm
vendored
BIN
pkg/rpc/server/testdata/test_contract.avm
vendored
Binary file not shown.
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
112
pkg/vm/vm.go
112
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:
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue