vm,compiler: replace APPCALL with System.Contract.Call
Contract calls are performed via syscall System.Contract.Call in NEO3. This implements this in compiler and removes APPCALL from the VM.
This commit is contained in:
parent
ec900c7ff7
commit
73c82584a3
13 changed files with 108 additions and 241 deletions
|
@ -1080,16 +1080,12 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
|||
case "SHA256":
|
||||
emit.Syscall(c.prog.BinWriter, "Neo.Crypto.SHA256")
|
||||
case "AppCall":
|
||||
numArgs := len(expr.Args) - 1
|
||||
c.emitReverse(numArgs)
|
||||
|
||||
emit.Opcode(c.prog.BinWriter, opcode.APPCALL)
|
||||
c.emitReverse(len(expr.Args))
|
||||
buf := c.getByteArray(expr.Args[0])
|
||||
if len(buf) != 20 {
|
||||
c.prog.Err = errors.New("invalid script hash")
|
||||
}
|
||||
|
||||
c.prog.WriteBytes(buf)
|
||||
emit.Syscall(c.prog.BinWriter, "System.Contract.Call")
|
||||
case "Equals":
|
||||
emit.Opcode(c.prog.BinWriter, opcode.EQUAL)
|
||||
case "FromAddress":
|
||||
|
@ -1111,16 +1107,14 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
|||
// transformArgs returns a list of function arguments
|
||||
// which should be put on stack.
|
||||
// There are special cases for builtins:
|
||||
// 1. When using AppCall, script hash is a part of the instruction so
|
||||
// it should be emitted after APPCALL.
|
||||
// 2. With FromAddress, parameter conversion is happening at compile-time
|
||||
// 1. With FromAddress, parameter conversion is happening at compile-time
|
||||
// so there is no need to push parameters on stack and perform an actual call
|
||||
// 3. With panic, generated code depends on if argument was nil or a string so
|
||||
// 2. With panic, generated code depends on if argument was nil or a string so
|
||||
// it should be handled accordingly.
|
||||
func transformArgs(fun ast.Expr, args []ast.Expr) []ast.Expr {
|
||||
switch f := fun.(type) {
|
||||
case *ast.SelectorExpr:
|
||||
if f.Sel.Name == "AppCall" || f.Sel.Name == "FromAddress" {
|
||||
if f.Sel.Name == "FromAddress" {
|
||||
return args[1:]
|
||||
}
|
||||
case *ast.Ident:
|
||||
|
|
|
@ -6,10 +6,17 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap/zaptest"
|
||||
)
|
||||
|
||||
func TestFromAddress(t *testing.T) {
|
||||
|
@ -51,6 +58,14 @@ func TestFromAddress(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func spawnVM(t *testing.T, ic *interop.Context, src string) *vm.VM {
|
||||
b, err := compiler.Compile(strings.NewReader(src))
|
||||
require.NoError(t, err)
|
||||
v := core.SpawnVM(ic)
|
||||
v.Load(b)
|
||||
return v
|
||||
}
|
||||
|
||||
func TestAppCall(t *testing.T) {
|
||||
srcInner := `
|
||||
package foo
|
||||
|
@ -62,19 +77,13 @@ func TestAppCall(t *testing.T) {
|
|||
inner, err := compiler.Compile(strings.NewReader(srcInner))
|
||||
require.NoError(t, err)
|
||||
|
||||
ih := hash.Hash160(inner)
|
||||
getScript := func(u util.Uint160) ([]byte, bool) {
|
||||
if u.Equals(ih) {
|
||||
return inner, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
ic := interop.NewContext(trigger.Application, nil, dao.NewSimple(storage.NewMemoryStore()), nil, nil, nil, zaptest.NewLogger(t))
|
||||
require.NoError(t, ic.DAO.PutContractState(&state.Contract{Script: inner}))
|
||||
|
||||
ih := hash.Hash160(inner)
|
||||
t.Run("valid script", func(t *testing.T) {
|
||||
src := getAppCallScript(fmt.Sprintf("%#v", ih.BytesBE()))
|
||||
v := vmAndCompile(t, src)
|
||||
v.SetScriptGetter(getScript)
|
||||
|
||||
v := spawnVM(t, ic, src)
|
||||
require.NoError(t, v.Run())
|
||||
|
||||
assertResult(t, v, []byte{1, 2, 3, 4})
|
||||
|
@ -85,9 +94,7 @@ func TestAppCall(t *testing.T) {
|
|||
h[0] = ^h[0]
|
||||
|
||||
src := getAppCallScript(fmt.Sprintf("%#v", h.BytesBE()))
|
||||
v := vmAndCompile(t, src)
|
||||
v.SetScriptGetter(getScript)
|
||||
|
||||
v := spawnVM(t, ic, src)
|
||||
require.Error(t, v.Run())
|
||||
})
|
||||
|
||||
|
@ -111,9 +118,7 @@ func TestAppCall(t *testing.T) {
|
|||
}
|
||||
`
|
||||
|
||||
v := vmAndCompile(t, src)
|
||||
v.SetScriptGetter(getScript)
|
||||
|
||||
v := spawnVM(t, ic, src)
|
||||
require.NoError(t, v.Run())
|
||||
|
||||
assertResult(t, v, []byte{1, 2, 3, 4})
|
||||
|
|
|
@ -20,8 +20,6 @@ func getPrice(v *vm.VM, op opcode.Opcode, parameter []byte) util.Fixed8 {
|
|||
}
|
||||
|
||||
switch op {
|
||||
case opcode.APPCALL, opcode.TAILCALL:
|
||||
return toFixed8(10)
|
||||
case opcode.SYSCALL:
|
||||
interopID := vm.GetInteropID(parameter)
|
||||
return getSyscallPrice(v, interopID)
|
||||
|
|
|
@ -24,11 +24,11 @@ import (
|
|||
// up for current blockchain.
|
||||
func SpawnVM(ic *interop.Context) *vm.VM {
|
||||
vm := vm.New()
|
||||
bc := ic.Chain.(*Blockchain)
|
||||
vm.SetScriptGetter(ic.GetContract)
|
||||
vm.RegisterInteropGetter(getSystemInterop(ic))
|
||||
vm.RegisterInteropGetter(getNeoInterop(ic))
|
||||
vm.RegisterInteropGetter(bc.contracts.GetNativeInterop(ic))
|
||||
if ic.Chain != nil {
|
||||
vm.RegisterInteropGetter(ic.Chain.(*Blockchain).contracts.GetNativeInterop(ic))
|
||||
}
|
||||
return vm
|
||||
}
|
||||
|
||||
|
|
|
@ -19,43 +19,43 @@ func TestInvocationScriptCreationGood(t *testing.T) {
|
|||
ps Params
|
||||
script string
|
||||
}{{
|
||||
script: "676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "transfer"}},
|
||||
script: "0c087472616e73666572676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c087472616e736665720c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||
}, {
|
||||
ps: Params{{Type: NumberT, Value: 42}},
|
||||
script: "0c023432676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c0234320c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{}}},
|
||||
script: "10c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "10c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.ByteArrayType, Value: Param{Type: StringT, Value: "50befd26fdf6e4d957c11e078b24ebce6291456f"}}}}}},
|
||||
script: "0c1450befd26fdf6e4d957c11e078b24ebce6291456f11c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c1450befd26fdf6e4d957c11e078b24ebce6291456f11c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.SignatureType, Value: Param{Type: StringT, Value: "4edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f"}}}}}},
|
||||
script: "0c404edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f11c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c404edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f11c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.StringType, Value: Param{Type: StringT, Value: "50befd26fdf6e4d957c11e078b24ebce6291456f"}}}}}},
|
||||
script: "0c283530626566643236666466366534643935376331316530373862323465626365363239313435366611c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c283530626566643236666466366534643935376331316530373862323465626365363239313435366611c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.Hash160Type, Value: Param{Type: StringT, Value: "50befd26fdf6e4d957c11e078b24ebce6291456f"}}}}}},
|
||||
script: "0c146f459162ceeb248b071ec157d9e4f6fd26fdbe5011c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c146f459162ceeb248b071ec157d9e4f6fd26fdbe5011c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.Hash256Type, Value: Param{Type: StringT, Value: "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"}}}}}},
|
||||
script: "0c20e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6011c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c20e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6011c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.PublicKeyType, Value: Param{Type: StringT, Value: "03c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c1"}}}}}},
|
||||
script: "0c2103c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c111c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "0c2103c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c111c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.IntegerType, Value: Param{Type: NumberT, Value: 42}}}}}},
|
||||
script: "002a11c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "002a11c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.BoolType, Value: Param{Type: StringT, Value: "true"}}}}}},
|
||||
script: "1111c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "1111c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||
}, {
|
||||
ps: Params{{Type: StringT, Value: "a"}, {Type: ArrayT, Value: []Param{{Type: FuncParamT, Value: FuncParam{Type: smartcontract.BoolType, Value: Param{Type: StringT, Value: "false"}}}}}},
|
||||
script: "1011c00c0161676f459162ceeb248b071ec157d9e4f6fd26fdbe50",
|
||||
script: "1011c00c01610c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52",
|
||||
}}
|
||||
for _, ps := range paramScripts {
|
||||
script, err := CreateFunctionInvocationScript(contract, ps.ps)
|
||||
|
|
|
@ -54,12 +54,12 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
"getapplicationlog": {
|
||||
{
|
||||
name: "positive",
|
||||
params: `["caccb0e0465d87970190c90094e3fb54dbbcfa3e48683bd9a54b1fb834118d87"]`,
|
||||
params: `["c296c0929350d051b9b40cace54db5a3eac4b730a8851e958795d44918f23c08"]`,
|
||||
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("caccb0e0465d87970190c90094e3fb54dbbcfa3e48683bd9a54b1fb834118d87")
|
||||
expectedTxHash, err := util.Uint256DecodeStringLE("c296c0929350d051b9b40cace54db5a3eac4b730a8851e958795d44918f23c08")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expectedTxHash, res.TxHash)
|
||||
assert.Equal(t, 1, len(res.Executions))
|
||||
|
@ -647,7 +647,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
check: func(t *testing.T, e *executor, inv interface{}) {
|
||||
res, ok := inv.(*result.Invoke)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, "0c06717765727479676f459162ceeb248b071ec157d9e4f6fd26fdbe50", res.Script)
|
||||
assert.Equal(t, "0c067177657274790c146f459162ceeb248b071ec157d9e4f6fd26fdbe5041627d5b52", res.Script)
|
||||
assert.NotEqual(t, "", res.State)
|
||||
assert.NotEqual(t, 0, res.GasConsumed)
|
||||
},
|
||||
|
|
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
|
@ -113,8 +113,6 @@ func (c *Context) Next() (opcode.Opcode, []byte, error) {
|
|||
opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLTL, opcode.JMPLEL,
|
||||
opcode.CALLL, opcode.SYSCALL:
|
||||
numtoread = 4
|
||||
case opcode.APPCALL, opcode.TAILCALL:
|
||||
numtoread = 20
|
||||
default:
|
||||
if instr <= opcode.PUSHINT256 {
|
||||
numtoread = 1 << instr
|
||||
|
|
|
@ -144,11 +144,8 @@ func Jmp(w *io.BinWriter, op opcode.Opcode, label uint16) {
|
|||
// AppCall emits an appcall, if tailCall is true, tailCall opcode will be
|
||||
// emitted instead.
|
||||
func AppCall(w *io.BinWriter, scriptHash util.Uint160, tailCall bool) {
|
||||
op := opcode.APPCALL
|
||||
if tailCall {
|
||||
op = opcode.TAILCALL
|
||||
}
|
||||
Instruction(w, op, scriptHash.BytesBE())
|
||||
Bytes(w, scriptHash.BytesBE())
|
||||
Syscall(w, "System.Contract.Call")
|
||||
}
|
||||
|
||||
// AppCallWithOperationAndArgs emits an APPCALL with the given operation and arguments.
|
||||
|
|
|
@ -91,9 +91,6 @@ const (
|
|||
REVERSE4 Opcode = 0x54
|
||||
REVERSEN Opcode = 0x55
|
||||
|
||||
APPCALL Opcode = 0x67
|
||||
TAILCALL Opcode = 0x69
|
||||
|
||||
// Old stack opcodes
|
||||
DUPFROMALTSTACK Opcode = 0x6A
|
||||
TOALTSTACK Opcode = 0x6B
|
||||
|
|
|
@ -80,8 +80,6 @@ func _() {
|
|||
_ = x[REVERSE3-83]
|
||||
_ = x[REVERSE4-84]
|
||||
_ = x[REVERSEN-85]
|
||||
_ = x[APPCALL-103]
|
||||
_ = x[TAILCALL-105]
|
||||
_ = x[DUPFROMALTSTACK-106]
|
||||
_ = x[TOALTSTACK-107]
|
||||
_ = x[FROMALTSTACK-108]
|
||||
|
@ -143,7 +141,7 @@ func _() {
|
|||
_ = x[CONVERT-219]
|
||||
}
|
||||
|
||||
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENAPPCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT"
|
||||
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENDUPFROMALTSTACKTOALTSTACKFROMALTSTACKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT"
|
||||
|
||||
var _Opcode_map = map[Opcode]string{
|
||||
0: _Opcode_name[0:8],
|
||||
|
@ -215,67 +213,65 @@ var _Opcode_map = map[Opcode]string{
|
|||
83: _Opcode_name[380:388],
|
||||
84: _Opcode_name[388:396],
|
||||
85: _Opcode_name[396:404],
|
||||
103: _Opcode_name[404:411],
|
||||
105: _Opcode_name[411:419],
|
||||
106: _Opcode_name[419:434],
|
||||
107: _Opcode_name[434:444],
|
||||
108: _Opcode_name[444:456],
|
||||
126: _Opcode_name[456:459],
|
||||
127: _Opcode_name[459:465],
|
||||
128: _Opcode_name[465:469],
|
||||
129: _Opcode_name[469:474],
|
||||
144: _Opcode_name[474:480],
|
||||
145: _Opcode_name[480:483],
|
||||
146: _Opcode_name[483:485],
|
||||
147: _Opcode_name[485:488],
|
||||
151: _Opcode_name[488:493],
|
||||
152: _Opcode_name[493:501],
|
||||
153: _Opcode_name[501:505],
|
||||
154: _Opcode_name[505:508],
|
||||
155: _Opcode_name[508:514],
|
||||
156: _Opcode_name[514:517],
|
||||
157: _Opcode_name[517:520],
|
||||
158: _Opcode_name[520:523],
|
||||
159: _Opcode_name[523:526],
|
||||
160: _Opcode_name[526:529],
|
||||
161: _Opcode_name[529:532],
|
||||
162: _Opcode_name[532:535],
|
||||
168: _Opcode_name[535:538],
|
||||
169: _Opcode_name[538:541],
|
||||
170: _Opcode_name[541:544],
|
||||
171: _Opcode_name[544:551],
|
||||
172: _Opcode_name[551:557],
|
||||
177: _Opcode_name[557:559],
|
||||
179: _Opcode_name[559:567],
|
||||
180: _Opcode_name[567:578],
|
||||
181: _Opcode_name[578:580],
|
||||
182: _Opcode_name[580:583],
|
||||
183: _Opcode_name[583:585],
|
||||
184: _Opcode_name[585:588],
|
||||
185: _Opcode_name[588:591],
|
||||
186: _Opcode_name[591:594],
|
||||
187: _Opcode_name[594:600],
|
||||
192: _Opcode_name[600:604],
|
||||
193: _Opcode_name[604:610],
|
||||
194: _Opcode_name[610:619],
|
||||
195: _Opcode_name[619:627],
|
||||
196: _Opcode_name[627:636],
|
||||
197: _Opcode_name[636:646],
|
||||
198: _Opcode_name[646:655],
|
||||
200: _Opcode_name[655:661],
|
||||
202: _Opcode_name[661:665],
|
||||
203: _Opcode_name[665:671],
|
||||
204: _Opcode_name[671:675],
|
||||
205: _Opcode_name[675:681],
|
||||
206: _Opcode_name[681:689],
|
||||
207: _Opcode_name[689:695],
|
||||
208: _Opcode_name[695:702],
|
||||
209: _Opcode_name[702:714],
|
||||
210: _Opcode_name[714:720],
|
||||
211: _Opcode_name[720:730],
|
||||
216: _Opcode_name[730:736],
|
||||
217: _Opcode_name[736:742],
|
||||
219: _Opcode_name[742:749],
|
||||
106: _Opcode_name[404:419],
|
||||
107: _Opcode_name[419:429],
|
||||
108: _Opcode_name[429:441],
|
||||
126: _Opcode_name[441:444],
|
||||
127: _Opcode_name[444:450],
|
||||
128: _Opcode_name[450:454],
|
||||
129: _Opcode_name[454:459],
|
||||
144: _Opcode_name[459:465],
|
||||
145: _Opcode_name[465:468],
|
||||
146: _Opcode_name[468:470],
|
||||
147: _Opcode_name[470:473],
|
||||
151: _Opcode_name[473:478],
|
||||
152: _Opcode_name[478:486],
|
||||
153: _Opcode_name[486:490],
|
||||
154: _Opcode_name[490:493],
|
||||
155: _Opcode_name[493:499],
|
||||
156: _Opcode_name[499:502],
|
||||
157: _Opcode_name[502:505],
|
||||
158: _Opcode_name[505:508],
|
||||
159: _Opcode_name[508:511],
|
||||
160: _Opcode_name[511:514],
|
||||
161: _Opcode_name[514:517],
|
||||
162: _Opcode_name[517:520],
|
||||
168: _Opcode_name[520:523],
|
||||
169: _Opcode_name[523:526],
|
||||
170: _Opcode_name[526:529],
|
||||
171: _Opcode_name[529:536],
|
||||
172: _Opcode_name[536:542],
|
||||
177: _Opcode_name[542:544],
|
||||
179: _Opcode_name[544:552],
|
||||
180: _Opcode_name[552:563],
|
||||
181: _Opcode_name[563:565],
|
||||
182: _Opcode_name[565:568],
|
||||
183: _Opcode_name[568:570],
|
||||
184: _Opcode_name[570:573],
|
||||
185: _Opcode_name[573:576],
|
||||
186: _Opcode_name[576:579],
|
||||
187: _Opcode_name[579:585],
|
||||
192: _Opcode_name[585:589],
|
||||
193: _Opcode_name[589:595],
|
||||
194: _Opcode_name[595:604],
|
||||
195: _Opcode_name[604:612],
|
||||
196: _Opcode_name[612:621],
|
||||
197: _Opcode_name[621:631],
|
||||
198: _Opcode_name[631:640],
|
||||
200: _Opcode_name[640:646],
|
||||
202: _Opcode_name[646:650],
|
||||
203: _Opcode_name[650:656],
|
||||
204: _Opcode_name[656:660],
|
||||
205: _Opcode_name[660:666],
|
||||
206: _Opcode_name[666:674],
|
||||
207: _Opcode_name[674:680],
|
||||
208: _Opcode_name[680:687],
|
||||
209: _Opcode_name[687:699],
|
||||
210: _Opcode_name[699:705],
|
||||
211: _Opcode_name[705:715],
|
||||
216: _Opcode_name[715:721],
|
||||
217: _Opcode_name[721:727],
|
||||
219: _Opcode_name[727:734],
|
||||
}
|
||||
|
||||
func (i Opcode) String() string {
|
||||
|
|
55
pkg/vm/vm.go
55
pkg/vm/vm.go
|
@ -71,9 +71,6 @@ type VM struct {
|
|||
// callback to get interop price
|
||||
getPrice func(*VM, opcode.Opcode, []byte) util.Fixed8
|
||||
|
||||
// callback to get scripts.
|
||||
getScript func(util.Uint160) ([]byte, bool)
|
||||
|
||||
istack *Stack // invocation stack.
|
||||
estack *Stack // execution stack.
|
||||
astack *Stack // alt stack.
|
||||
|
@ -95,7 +92,6 @@ type VM struct {
|
|||
func New() *VM {
|
||||
vm := &VM{
|
||||
getInterop: make([]InteropGetterFunc, 0, 3), // 3 functions is typical for our default usage.
|
||||
getScript: nil,
|
||||
state: haltState,
|
||||
istack: NewStack("invocation"),
|
||||
|
||||
|
@ -204,8 +200,6 @@ func (v *VM) PrintOps() {
|
|||
desc = fmt.Sprintf("%d (%d/%x)", ctx.ip+int(offset), offset, parameter)
|
||||
case opcode.SYSCALL:
|
||||
desc = fmt.Sprintf("%q", parameter)
|
||||
case opcode.APPCALL, opcode.TAILCALL:
|
||||
desc = fmt.Sprintf("%x", parameter)
|
||||
default:
|
||||
if utf8.Valid(parameter) {
|
||||
desc = fmt.Sprintf("%x (%q)", parameter, parameter)
|
||||
|
@ -477,11 +471,6 @@ func (v *VM) SetCheckedHash(h []byte) {
|
|||
copy(v.checkhash, h)
|
||||
}
|
||||
|
||||
// SetScriptGetter sets the script getter for CALL instructions.
|
||||
func (v *VM) SetScriptGetter(gs func(util.Uint160) ([]byte, bool)) {
|
||||
v.getScript = gs
|
||||
}
|
||||
|
||||
// GetInteropID converts instruction parameter to an interop ID.
|
||||
func GetInteropID(parameter []byte) uint32 {
|
||||
return binary.LittleEndian.Uint32(parameter)
|
||||
|
@ -520,25 +509,6 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
}
|
||||
}
|
||||
|
||||
switch op {
|
||||
case opcode.APPCALL, opcode.TAILCALL:
|
||||
isZero := true
|
||||
for i := range parameter {
|
||||
if parameter[i] != 0 {
|
||||
isZero = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isZero {
|
||||
break
|
||||
}
|
||||
|
||||
parameter = v.estack.Pop().Bytes()
|
||||
if !ctx.hasDynamicInvoke {
|
||||
panic("contract is not allowed to make dynamic invocations")
|
||||
}
|
||||
}
|
||||
|
||||
if op <= opcode.PUSHINT256 {
|
||||
v.estack.PushVal(emit.BytesToInt(parameter))
|
||||
return
|
||||
|
@ -1175,31 +1145,6 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
panic(fmt.Sprintf("failed to invoke syscall: %s", err))
|
||||
}
|
||||
|
||||
case opcode.APPCALL, opcode.TAILCALL:
|
||||
if v.getScript == nil {
|
||||
panic("no getScript callback is set up")
|
||||
}
|
||||
|
||||
if op == opcode.APPCALL {
|
||||
v.checkInvocationStackSize()
|
||||
}
|
||||
|
||||
hash, err := util.Uint160DecodeBytesBE(parameter)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
script, hasDynamicInvoke := v.getScript(hash)
|
||||
if script == nil {
|
||||
panic("could not find script")
|
||||
}
|
||||
|
||||
if op == opcode.TAILCALL {
|
||||
_ = v.istack.Pop()
|
||||
}
|
||||
|
||||
v.loadScriptWithHash(script, hash, hasDynamicInvoke)
|
||||
|
||||
case opcode.RET:
|
||||
oldCtx := v.istack.Pop().Value().(*Context)
|
||||
rvcount := oldCtx.rvcount
|
||||
|
|
|
@ -1413,69 +1413,6 @@ func TestSIGN(t *testing.T) {
|
|||
t.Run("ByteArray", getTestFuncForVM(prog, 1, []byte{0, 1}))
|
||||
}
|
||||
|
||||
func TestAppCall(t *testing.T) {
|
||||
prog := []byte{byte(opcode.APPCALL)}
|
||||
hash := util.Uint160{1, 2}
|
||||
prog = append(prog, hash.BytesBE()...)
|
||||
prog = append(prog, byte(opcode.RET))
|
||||
|
||||
vm := load(prog)
|
||||
vm.SetScriptGetter(func(in util.Uint160) ([]byte, bool) {
|
||||
if in.Equals(hash) {
|
||||
return makeProgram(opcode.DEPTH), true
|
||||
}
|
||||
return nil, false
|
||||
})
|
||||
vm.estack.PushVal(2)
|
||||
|
||||
runVM(t, vm)
|
||||
elem := vm.estack.Pop() // depth should be 1
|
||||
assert.Equal(t, int64(1), elem.BigInt().Int64())
|
||||
}
|
||||
|
||||
func TestAppCallDynamicBad(t *testing.T) {
|
||||
prog := []byte{byte(opcode.APPCALL)}
|
||||
hash := util.Uint160{}
|
||||
prog = append(prog, hash.BytesBE()...)
|
||||
prog = append(prog, byte(opcode.RET))
|
||||
|
||||
vm := load(prog)
|
||||
vm.SetScriptGetter(func(in util.Uint160) ([]byte, bool) {
|
||||
if in.Equals(hash) {
|
||||
return makeProgram(opcode.DEPTH), true
|
||||
}
|
||||
return nil, false
|
||||
})
|
||||
vm.estack.PushVal(2)
|
||||
vm.estack.PushVal(hash.BytesBE())
|
||||
|
||||
checkVMFailed(t, vm)
|
||||
}
|
||||
|
||||
func TestAppCallDynamicGood(t *testing.T) {
|
||||
prog := []byte{byte(opcode.APPCALL)}
|
||||
zeroHash := util.Uint160{}
|
||||
hash := util.Uint160{1, 2, 3}
|
||||
prog = append(prog, zeroHash.BytesBE()...)
|
||||
prog = append(prog, byte(opcode.RET))
|
||||
|
||||
vm := load(prog)
|
||||
vm.SetScriptGetter(func(in util.Uint160) ([]byte, bool) {
|
||||
if in.Equals(hash) {
|
||||
return makeProgram(opcode.DEPTH), true
|
||||
}
|
||||
return nil, false
|
||||
})
|
||||
vm.estack.PushVal(42)
|
||||
vm.estack.PushVal(42)
|
||||
vm.estack.PushVal(hash.BytesBE())
|
||||
vm.Context().hasDynamicInvoke = true
|
||||
|
||||
runVM(t, vm)
|
||||
elem := vm.estack.Pop() // depth should be 2
|
||||
assert.Equal(t, int64(2), elem.BigInt().Int64())
|
||||
}
|
||||
|
||||
func TestSimpleCall(t *testing.T) {
|
||||
buf := io.NewBufBinWriter()
|
||||
w := buf.BinWriter
|
||||
|
|
Loading…
Reference in a new issue