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

compiler: refactor AppCall
This commit is contained in:
Roman Khimov 2020-02-10 12:17:29 +03:00 committed by GitHub
commit f148798291
4 changed files with 37 additions and 31 deletions

4
go.sum
View file

@ -97,8 +97,8 @@ github.com/nspcc-dev/dbft v0.0.0-20191209120240-0d6b7568d9ae h1:T5V1QANlNMKun0EP
github.com/nspcc-dev/dbft v0.0.0-20191209120240-0d6b7568d9ae/go.mod h1:3FjXOoHmA51EGfb5GS/HOv7VdmngNRTssSeQ729dvGY= github.com/nspcc-dev/dbft v0.0.0-20191209120240-0d6b7568d9ae/go.mod h1:3FjXOoHmA51EGfb5GS/HOv7VdmngNRTssSeQ729dvGY=
github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a h1:ajvxgEe9qY4vvoSmrADqdDx7hReodKTnT2IXN++qZG8= github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a h1:ajvxgEe9qY4vvoSmrADqdDx7hReodKTnT2IXN++qZG8=
github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a/go.mod h1:/YFK+XOxxg0Bfm6P92lY5eDSLYfp06XOdL8KAVgXjVk= github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a/go.mod h1:/YFK+XOxxg0Bfm6P92lY5eDSLYfp06XOdL8KAVgXjVk=
github.com/nspcc-dev/dbft v0.0.0-20200130105505-02c208d154bf h1:7QLeZnBQZ8eJeYksP7tnENG2ZEOZhHTJBC6LkFt4Ok8= github.com/nspcc-dev/dbft v0.0.0-20200203121303-549ecf2daaa1 h1:feHDSBix9oAVt5QzGABQczZo7dNWyeDKClLGwKvSJ/w=
github.com/nspcc-dev/dbft v0.0.0-20200130105505-02c208d154bf/go.mod h1:O0qtn62prQSqizzoagHmuuKoz8QMkU3SzBoKdEvm3aQ= github.com/nspcc-dev/dbft v0.0.0-20200203121303-549ecf2daaa1/go.mod h1:O0qtn62prQSqizzoagHmuuKoz8QMkU3SzBoKdEvm3aQ=
github.com/nspcc-dev/neofs-crypto v0.2.0 h1:ftN+59WqxSWz/RCgXYOfhmltOOqU+udsNQSvN6wkFck= github.com/nspcc-dev/neofs-crypto v0.2.0 h1:ftN+59WqxSWz/RCgXYOfhmltOOqU+udsNQSvN6wkFck=
github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA= github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA=
github.com/nspcc-dev/neofs-crypto v0.2.3 h1:aca3X2aly92ENRbFK+kH6Hd+J9EQ4Eu6XMVoITSIKtc= github.com/nspcc-dev/neofs-crypto v0.2.3 h1:aca3X2aly92ENRbFK+kH6Hd+J9EQ4Eu6XMVoITSIKtc=

View file

@ -540,17 +540,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
} }
// Do not swap for builtin functions. // Do not swap for builtin functions.
if !isBuiltin { if !isBuiltin {
if numArgs == 2 { c.emitReverse(numArgs)
emit.Opcode(c.prog.BinWriter, opcode.SWAP)
} else if numArgs == 3 {
emit.Int(c.prog.BinWriter, 2)
emit.Opcode(c.prog.BinWriter, opcode.XSWAP)
} else {
for i := 1; i < numArgs; i++ {
emit.Int(c.prog.BinWriter, int64(i))
emit.Opcode(c.prog.BinWriter, opcode.ROLL)
}
}
} }
// Check builtin first to avoid nil pointer on funcScope! // Check builtin first to avoid nil pointer on funcScope!
@ -680,6 +670,22 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
return c return c
} }
// emitReverse reverses top num items of the stack.
func (c *codegen) emitReverse(num int) {
switch num {
case 2:
emit.Opcode(c.prog.BinWriter, opcode.SWAP)
case 3:
emit.Int(c.prog.BinWriter, 2)
emit.Opcode(c.prog.BinWriter, opcode.XSWAP)
default:
for i := 1; i < num; i++ {
emit.Int(c.prog.BinWriter, int64(i))
emit.Opcode(c.prog.BinWriter, opcode.ROLL)
}
}
}
func (c *codegen) getEqualityOpcode(expr ast.Expr) opcode.Opcode { func (c *codegen) getEqualityOpcode(expr ast.Expr) opcode.Opcode {
t, ok := c.typeInfo.Types[expr].Type.Underlying().(*types.Basic) t, ok := c.typeInfo.Types[expr].Type.Underlying().(*types.Basic)
if ok && t.Info()&types.IsNumeric != 0 { if ok && t.Info()&types.IsNumeric != 0 {
@ -780,6 +786,9 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
case "VerifySignature": case "VerifySignature":
emit.Opcode(c.prog.BinWriter, opcode.VERIFY) emit.Opcode(c.prog.BinWriter, opcode.VERIFY)
case "AppCall": case "AppCall":
numArgs := len(expr.Args) - 1
c.emitReverse(numArgs)
emit.Opcode(c.prog.BinWriter, opcode.APPCALL) emit.Opcode(c.prog.BinWriter, opcode.APPCALL)
buf := c.getByteArray(expr.Args[0]) buf := c.getByteArray(expr.Args[0])
if len(buf) != 20 { if len(buf) != 20 {

View file

@ -2,7 +2,6 @@ package compiler_test
import ( import (
"fmt" "fmt"
"math/big"
"strings" "strings"
"testing" "testing"
@ -55,10 +54,8 @@ func TestFromAddress(t *testing.T) {
func TestAppCall(t *testing.T) { func TestAppCall(t *testing.T) {
srcInner := ` srcInner := `
package foo package foo
func Main(args []interface{}) int { func Main(a []byte, b []byte) []byte {
a := args[0].(int) return append(a, b...)
b := args[1].(int)
return a + b
} }
` `
@ -80,7 +77,7 @@ func TestAppCall(t *testing.T) {
require.NoError(t, v.Run()) require.NoError(t, v.Run())
assertResult(t, v, big.NewInt(42)) assertResult(t, v, []byte{1, 2, 3, 4})
}) })
t.Run("missing script", func(t *testing.T) { t.Run("missing script", func(t *testing.T) {
@ -106,11 +103,11 @@ func TestAppCall(t *testing.T) {
package foo package foo
import "github.com/CityOfZion/neo-go/pkg/interop/engine" import "github.com/CityOfZion/neo-go/pkg/interop/engine"
const scriptHash = ` + fmt.Sprintf("%#v", string(ih.BytesBE())) + ` const scriptHash = ` + fmt.Sprintf("%#v", string(ih.BytesBE())) + `
func Main() int { func Main() []byte {
x := 13 x := []byte{1, 2}
y := 29 y := []byte{3, 4}
result := engine.AppCall([]byte(scriptHash), []interface{}{x, y}) result := engine.AppCall([]byte(scriptHash), x, y)
return result.(int) return result.([]byte)
} }
` `
@ -119,7 +116,7 @@ func TestAppCall(t *testing.T) {
require.NoError(t, v.Run()) require.NoError(t, v.Run())
assertResult(t, v, big.NewInt(42)) assertResult(t, v, []byte{1, 2, 3, 4})
}) })
} }
@ -127,11 +124,11 @@ func getAppCallScript(h string) string {
return ` return `
package foo package foo
import "github.com/CityOfZion/neo-go/pkg/interop/engine" import "github.com/CityOfZion/neo-go/pkg/interop/engine"
func Main() int { func Main() []byte {
x := 13 x := []byte{1, 2}
y := 29 y := []byte{3, 4}
result := engine.AppCall(` + h + `, []interface{}{x, y}) result := engine.AppCall(` + h + `, x, y)
return result.(int) return result.([]byte)
} }
` `
} }

View file

@ -29,6 +29,6 @@ func GetEntryScriptHash() []byte {
} }
// AppCall executes script with specified hash using provided arguments. // AppCall executes script with specified hash using provided arguments.
func AppCall(scriptHash []byte, args []interface{}) interface{} { func AppCall(scriptHash []byte, args ...interface{}) interface{} {
return nil return nil
} }