forked from TrueCloudLab/neoneo-go
Merge pull request #932 from nspcc-dev/feature/abort
vm: implement ASSERT/ABORT opcodes
This commit is contained in:
commit
9afcd71be3
9 changed files with 104 additions and 106 deletions
|
@ -14,7 +14,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/internal/testchain"
|
"github.com/nspcc-dev/neo-go/pkg/internal/testchain"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
|
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
|
@ -141,13 +140,6 @@ func newDumbBlock() *block.Block {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getInvocationScript(data []byte, priv *keys.PrivateKey) []byte {
|
|
||||||
signature := priv.Sign(data)
|
|
||||||
buf := io.NewBufBinWriter()
|
|
||||||
emit.Bytes(buf.BinWriter, signature)
|
|
||||||
return buf.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function generates "../rpc/testdata/testblocks.acc" file which contains data
|
// This function generates "../rpc/testdata/testblocks.acc" file which contains data
|
||||||
// for RPC unit tests. It also is a nice integration test.
|
// for RPC unit tests. It also is a nice integration test.
|
||||||
// To generate new "../rpc/testdata/testblocks.acc", follow the steps:
|
// To generate new "../rpc/testdata/testblocks.acc", follow the steps:
|
||||||
|
@ -424,7 +416,7 @@ func TestCreateBasicChain(t *testing.T) {
|
||||||
func newNEP5Transfer(sc, from, to util.Uint160, amount int64) *transaction.Transaction {
|
func newNEP5Transfer(sc, from, to util.Uint160, amount int64) *transaction.Transaction {
|
||||||
w := io.NewBufBinWriter()
|
w := io.NewBufBinWriter()
|
||||||
emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", from, to, amount)
|
emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", from, to, amount)
|
||||||
emit.Opcode(w.BinWriter, opcode.THROWIFNOT)
|
emit.Opcode(w.BinWriter, opcode.ASSERT)
|
||||||
|
|
||||||
script := w.Bytes()
|
script := w.Bytes()
|
||||||
return transaction.NewInvocationTX(script, 0)
|
return transaction.NewInvocationTX(script, 0)
|
||||||
|
|
|
@ -105,7 +105,7 @@ func (c *Client) TransferNEP5(acc *wallet.Account, to util.Uint160, token *walle
|
||||||
// 2 round trips instead of one.
|
// 2 round trips instead of one.
|
||||||
w := io.NewBufBinWriter()
|
w := io.NewBufBinWriter()
|
||||||
emit.AppCallWithOperationAndArgs(w.BinWriter, token.Hash, "transfer", from, to, amount)
|
emit.AppCallWithOperationAndArgs(w.BinWriter, token.Hash, "transfer", from, to, amount)
|
||||||
emit.Opcode(w.BinWriter, opcode.THROWIFNOT)
|
emit.Opcode(w.BinWriter, opcode.ASSERT)
|
||||||
|
|
||||||
tx := transaction.NewInvocationTX(w.Bytes(), gas)
|
tx := transaction.NewInvocationTX(w.Bytes(), gas)
|
||||||
tx.Sender = from
|
tx.Sender = from
|
||||||
|
|
|
@ -48,18 +48,18 @@ type rpcTestCase struct {
|
||||||
check func(t *testing.T, e *executor, result interface{})
|
check func(t *testing.T, e *executor, result interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
const testContractHash = "76751a2fdde4dc6c7489799a28bb539bc09d1f54"
|
const testContractHash = "2077e1382aab3983aa342e68f7bbc94e69f204b9"
|
||||||
|
|
||||||
var rpcTestCases = map[string][]rpcTestCase{
|
var rpcTestCases = map[string][]rpcTestCase{
|
||||||
"getapplicationlog": {
|
"getapplicationlog": {
|
||||||
{
|
{
|
||||||
name: "positive",
|
name: "positive",
|
||||||
params: `["113437bd8dfc44e3a6dfe77b750fcff246cbe933ca9667311f45d794cf0410cc"]`,
|
params: `["16c26d67f06770a5b0cda4b1c5ccc28d12c0197c7239a7fe30c2eb523b58f54d"]`,
|
||||||
result: func(e *executor) interface{} { return &result.ApplicationLog{} },
|
result: func(e *executor) interface{} { return &result.ApplicationLog{} },
|
||||||
check: func(t *testing.T, e *executor, acc interface{}) {
|
check: func(t *testing.T, e *executor, acc interface{}) {
|
||||||
res, ok := acc.(*result.ApplicationLog)
|
res, ok := acc.(*result.ApplicationLog)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
expectedTxHash, err := util.Uint256DecodeStringLE("113437bd8dfc44e3a6dfe77b750fcff246cbe933ca9667311f45d794cf0410cc")
|
expectedTxHash, err := util.Uint256DecodeStringLE("16c26d67f06770a5b0cda4b1c5ccc28d12c0197c7239a7fe30c2eb523b58f54d")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, expectedTxHash, res.TxHash)
|
assert.Equal(t, expectedTxHash, res.TxHash)
|
||||||
assert.Equal(t, 1, len(res.Executions))
|
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.
|
@ -65,6 +65,11 @@ const (
|
||||||
CALL Opcode = 0x34
|
CALL Opcode = 0x34
|
||||||
CALLL Opcode = 0x35
|
CALLL Opcode = 0x35
|
||||||
|
|
||||||
|
// Exceptions
|
||||||
|
ABORT Opcode = 0x37
|
||||||
|
ASSERT Opcode = 0x38
|
||||||
|
THROW Opcode = 0x3A
|
||||||
|
|
||||||
// Stack
|
// Stack
|
||||||
DEPTH Opcode = 0x43
|
DEPTH Opcode = 0x43
|
||||||
DROP Opcode = 0x45
|
DROP Opcode = 0x45
|
||||||
|
@ -158,8 +163,4 @@ const (
|
||||||
ISNULL Opcode = 0xD8
|
ISNULL Opcode = 0xD8
|
||||||
ISTYPE Opcode = 0xD9
|
ISTYPE Opcode = 0xD9
|
||||||
CONVERT Opcode = 0xDB
|
CONVERT Opcode = 0xDB
|
||||||
|
|
||||||
// Exceptions
|
|
||||||
THROW Opcode = 0xF0
|
|
||||||
THROWIFNOT Opcode = 0xF1
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -59,6 +59,9 @@ func _() {
|
||||||
_ = x[JMPLEL-51]
|
_ = x[JMPLEL-51]
|
||||||
_ = x[CALL-52]
|
_ = x[CALL-52]
|
||||||
_ = x[CALLL-53]
|
_ = x[CALLL-53]
|
||||||
|
_ = x[ABORT-55]
|
||||||
|
_ = x[ASSERT-56]
|
||||||
|
_ = x[THROW-58]
|
||||||
_ = x[DEPTH-67]
|
_ = x[DEPTH-67]
|
||||||
_ = x[DROP-69]
|
_ = x[DROP-69]
|
||||||
_ = x[NIP-70]
|
_ = x[NIP-70]
|
||||||
|
@ -138,11 +141,9 @@ func _() {
|
||||||
_ = x[ISNULL-216]
|
_ = x[ISNULL-216]
|
||||||
_ = x[ISTYPE-217]
|
_ = x[ISTYPE-217]
|
||||||
_ = x[CONVERT-219]
|
_ = x[CONVERT-219]
|
||||||
_ = x[THROW-240]
|
|
||||||
_ = x[THROWIFNOT-241]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENRETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERTTHROWTHROWIFNOT"
|
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLABORTASSERTTHROWDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENRETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT"
|
||||||
|
|
||||||
var _Opcode_map = map[Opcode]string{
|
var _Opcode_map = map[Opcode]string{
|
||||||
0: _Opcode_name[0:8],
|
0: _Opcode_name[0:8],
|
||||||
|
@ -194,86 +195,87 @@ var _Opcode_map = map[Opcode]string{
|
||||||
51: _Opcode_name[286:292],
|
51: _Opcode_name[286:292],
|
||||||
52: _Opcode_name[292:296],
|
52: _Opcode_name[292:296],
|
||||||
53: _Opcode_name[296:301],
|
53: _Opcode_name[296:301],
|
||||||
67: _Opcode_name[301:306],
|
55: _Opcode_name[301:306],
|
||||||
69: _Opcode_name[306:310],
|
56: _Opcode_name[306:312],
|
||||||
70: _Opcode_name[310:313],
|
58: _Opcode_name[312:317],
|
||||||
72: _Opcode_name[313:318],
|
67: _Opcode_name[317:322],
|
||||||
73: _Opcode_name[318:323],
|
69: _Opcode_name[322:326],
|
||||||
74: _Opcode_name[323:326],
|
70: _Opcode_name[326:329],
|
||||||
75: _Opcode_name[326:330],
|
72: _Opcode_name[329:334],
|
||||||
77: _Opcode_name[330:334],
|
73: _Opcode_name[334:339],
|
||||||
78: _Opcode_name[334:338],
|
74: _Opcode_name[339:342],
|
||||||
80: _Opcode_name[338:342],
|
75: _Opcode_name[342:346],
|
||||||
81: _Opcode_name[342:350],
|
77: _Opcode_name[346:350],
|
||||||
82: _Opcode_name[350:354],
|
78: _Opcode_name[350:354],
|
||||||
83: _Opcode_name[354:362],
|
80: _Opcode_name[354:358],
|
||||||
84: _Opcode_name[362:370],
|
81: _Opcode_name[358:366],
|
||||||
85: _Opcode_name[370:378],
|
82: _Opcode_name[366:370],
|
||||||
102: _Opcode_name[378:381],
|
83: _Opcode_name[370:378],
|
||||||
103: _Opcode_name[381:388],
|
84: _Opcode_name[378:386],
|
||||||
104: _Opcode_name[388:395],
|
85: _Opcode_name[386:394],
|
||||||
105: _Opcode_name[395:403],
|
102: _Opcode_name[394:397],
|
||||||
106: _Opcode_name[403:418],
|
103: _Opcode_name[397:404],
|
||||||
107: _Opcode_name[418:428],
|
104: _Opcode_name[404:411],
|
||||||
108: _Opcode_name[428:440],
|
105: _Opcode_name[411:419],
|
||||||
126: _Opcode_name[440:443],
|
106: _Opcode_name[419:434],
|
||||||
127: _Opcode_name[443:449],
|
107: _Opcode_name[434:444],
|
||||||
128: _Opcode_name[449:453],
|
108: _Opcode_name[444:456],
|
||||||
129: _Opcode_name[453:458],
|
126: _Opcode_name[456:459],
|
||||||
144: _Opcode_name[458:464],
|
127: _Opcode_name[459:465],
|
||||||
145: _Opcode_name[464:467],
|
128: _Opcode_name[465:469],
|
||||||
146: _Opcode_name[467:469],
|
129: _Opcode_name[469:474],
|
||||||
147: _Opcode_name[469:472],
|
144: _Opcode_name[474:480],
|
||||||
151: _Opcode_name[472:477],
|
145: _Opcode_name[480:483],
|
||||||
152: _Opcode_name[477:485],
|
146: _Opcode_name[483:485],
|
||||||
153: _Opcode_name[485:489],
|
147: _Opcode_name[485:488],
|
||||||
154: _Opcode_name[489:492],
|
151: _Opcode_name[488:493],
|
||||||
155: _Opcode_name[492:498],
|
152: _Opcode_name[493:501],
|
||||||
156: _Opcode_name[498:501],
|
153: _Opcode_name[501:505],
|
||||||
157: _Opcode_name[501:504],
|
154: _Opcode_name[505:508],
|
||||||
158: _Opcode_name[504:507],
|
155: _Opcode_name[508:514],
|
||||||
159: _Opcode_name[507:510],
|
156: _Opcode_name[514:517],
|
||||||
160: _Opcode_name[510:513],
|
157: _Opcode_name[517:520],
|
||||||
161: _Opcode_name[513:516],
|
158: _Opcode_name[520:523],
|
||||||
162: _Opcode_name[516:519],
|
159: _Opcode_name[523:526],
|
||||||
168: _Opcode_name[519:522],
|
160: _Opcode_name[526:529],
|
||||||
169: _Opcode_name[522:525],
|
161: _Opcode_name[529:532],
|
||||||
170: _Opcode_name[525:528],
|
162: _Opcode_name[532:535],
|
||||||
171: _Opcode_name[528:535],
|
168: _Opcode_name[535:538],
|
||||||
172: _Opcode_name[535:541],
|
169: _Opcode_name[538:541],
|
||||||
177: _Opcode_name[541:543],
|
170: _Opcode_name[541:544],
|
||||||
179: _Opcode_name[543:551],
|
171: _Opcode_name[544:551],
|
||||||
180: _Opcode_name[551:562],
|
172: _Opcode_name[551:557],
|
||||||
181: _Opcode_name[562:564],
|
177: _Opcode_name[557:559],
|
||||||
182: _Opcode_name[564:567],
|
179: _Opcode_name[559:567],
|
||||||
183: _Opcode_name[567:569],
|
180: _Opcode_name[567:578],
|
||||||
184: _Opcode_name[569:572],
|
181: _Opcode_name[578:580],
|
||||||
185: _Opcode_name[572:575],
|
182: _Opcode_name[580:583],
|
||||||
186: _Opcode_name[575:578],
|
183: _Opcode_name[583:585],
|
||||||
187: _Opcode_name[578:584],
|
184: _Opcode_name[585:588],
|
||||||
192: _Opcode_name[584:588],
|
185: _Opcode_name[588:591],
|
||||||
193: _Opcode_name[588:594],
|
186: _Opcode_name[591:594],
|
||||||
194: _Opcode_name[594:603],
|
187: _Opcode_name[594:600],
|
||||||
195: _Opcode_name[603:611],
|
192: _Opcode_name[600:604],
|
||||||
196: _Opcode_name[611:620],
|
193: _Opcode_name[604:610],
|
||||||
197: _Opcode_name[620:630],
|
194: _Opcode_name[610:619],
|
||||||
198: _Opcode_name[630:639],
|
195: _Opcode_name[619:627],
|
||||||
200: _Opcode_name[639:645],
|
196: _Opcode_name[627:636],
|
||||||
202: _Opcode_name[645:649],
|
197: _Opcode_name[636:646],
|
||||||
203: _Opcode_name[649:655],
|
198: _Opcode_name[646:655],
|
||||||
204: _Opcode_name[655:659],
|
200: _Opcode_name[655:661],
|
||||||
205: _Opcode_name[659:665],
|
202: _Opcode_name[661:665],
|
||||||
206: _Opcode_name[665:673],
|
203: _Opcode_name[665:671],
|
||||||
207: _Opcode_name[673:679],
|
204: _Opcode_name[671:675],
|
||||||
208: _Opcode_name[679:686],
|
205: _Opcode_name[675:681],
|
||||||
209: _Opcode_name[686:698],
|
206: _Opcode_name[681:689],
|
||||||
210: _Opcode_name[698:704],
|
207: _Opcode_name[689:695],
|
||||||
211: _Opcode_name[704:714],
|
208: _Opcode_name[695:702],
|
||||||
216: _Opcode_name[714:720],
|
209: _Opcode_name[702:714],
|
||||||
217: _Opcode_name[720:726],
|
210: _Opcode_name[714:720],
|
||||||
219: _Opcode_name[726:733],
|
211: _Opcode_name[720:730],
|
||||||
240: _Opcode_name[733:738],
|
216: _Opcode_name[730:736],
|
||||||
241: _Opcode_name[738:748],
|
217: _Opcode_name[736:742],
|
||||||
|
219: _Opcode_name[742:749],
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i Opcode) String() string {
|
func (i Opcode) String() string {
|
||||||
|
|
|
@ -9,10 +9,10 @@ import (
|
||||||
// Nothing more to test here, really.
|
// Nothing more to test here, really.
|
||||||
func TestStringer(t *testing.T) {
|
func TestStringer(t *testing.T) {
|
||||||
tests := map[Opcode]string{
|
tests := map[Opcode]string{
|
||||||
ADD: "ADD",
|
ADD: "ADD",
|
||||||
SUB: "SUB",
|
SUB: "SUB",
|
||||||
THROWIFNOT: "THROWIFNOT",
|
ASSERT: "ASSERT",
|
||||||
0xff: "Opcode(255)",
|
0xff: "Opcode(255)",
|
||||||
}
|
}
|
||||||
for o, s := range tests {
|
for o, s := range tests {
|
||||||
assert.Equal(t, s, o.String())
|
assert.Equal(t, s, o.String())
|
||||||
|
|
|
@ -1298,9 +1298,12 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
case opcode.THROW:
|
case opcode.THROW:
|
||||||
panic("THROW")
|
panic("THROW")
|
||||||
|
|
||||||
case opcode.THROWIFNOT:
|
case opcode.ABORT:
|
||||||
|
panic("ABORT")
|
||||||
|
|
||||||
|
case opcode.ASSERT:
|
||||||
if !v.estack.Pop().Bool() {
|
if !v.estack.Pop().Bool() {
|
||||||
panic("THROWIFNOT")
|
panic("ASSERT failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in a new issue