Merge pull request #932 from nspcc-dev/feature/abort

vm: implement ASSERT/ABORT opcodes
This commit is contained in:
Roman Khimov 2020-05-06 16:32:18 +03:00 committed by GitHub
commit 9afcd71be3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 104 additions and 106 deletions

View file

@ -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)

View file

@ -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

View file

@ -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))

Binary file not shown.

Binary file not shown.

View file

@ -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
) )

View file

@ -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 {

View file

@ -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())

View file

@ -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: