Merge pull request #938 from nspcc-dev/fix/appcall

vm: remove APPCALL, TAILCALL
This commit is contained in:
Roman Khimov 2020-05-08 13:11:02 +03:00 committed by GitHub
commit b83ee77698
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 297 additions and 376 deletions

View file

@ -1081,16 +1081,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":
@ -1112,16 +1108,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:

View file

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