2020-01-27 07:59:57 +00:00
|
|
|
package compiler_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2020-06-08 11:16:41 +00:00
|
|
|
"math/big"
|
2020-01-27 07:59:57 +00:00
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
2020-06-18 09:00:51 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
2020-05-07 11:38:19 +00:00
|
|
|
"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"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
2020-06-10 12:51:28 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
2020-05-07 11:38:19 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
2020-06-08 11:16:41 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
2020-01-27 07:59:57 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2020-05-07 11:38:19 +00:00
|
|
|
"go.uber.org/zap/zaptest"
|
2020-01-27 07:59:57 +00:00
|
|
|
)
|
|
|
|
|
2020-01-27 08:53:47 +00:00
|
|
|
func TestFromAddress(t *testing.T) {
|
2020-06-16 10:47:29 +00:00
|
|
|
as1 := "NQRLhCpAru9BjGsMwk67vdMwmzKMRgsnnN"
|
2020-01-27 08:53:47 +00:00
|
|
|
addr1, err := address.StringToUint160(as1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-06-16 10:47:29 +00:00
|
|
|
as2 := "NPAsqZkx9WhNd4P72uhZxBhLinSuNkxfB8"
|
2020-01-27 08:53:47 +00:00
|
|
|
addr2, err := address.StringToUint160(as2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
t.Run("append 2 addresses", func(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package foo
|
2020-03-03 14:21:42 +00:00
|
|
|
import "github.com/nspcc-dev/neo-go/pkg/interop/util"
|
2020-01-27 08:53:47 +00:00
|
|
|
func Main() []byte {
|
|
|
|
addr1 := util.FromAddress("` + as1 + `")
|
|
|
|
addr2 := util.FromAddress("` + as2 + `")
|
|
|
|
sum := append(addr1, addr2...)
|
|
|
|
return sum
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
eval(t, src, append(addr1.BytesBE(), addr2.BytesBE()...))
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("append 2 addresses inline", func(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package foo
|
2020-03-03 14:21:42 +00:00
|
|
|
import "github.com/nspcc-dev/neo-go/pkg/interop/util"
|
2020-01-27 08:53:47 +00:00
|
|
|
func Main() []byte {
|
|
|
|
addr1 := util.FromAddress("` + as1 + `")
|
|
|
|
sum := append(addr1, util.FromAddress("` + as2 + `")...)
|
|
|
|
return sum
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
eval(t, src, append(addr1.BytesBE(), addr2.BytesBE()...))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-05-07 11:38:19 +00:00
|
|
|
func spawnVM(t *testing.T, ic *interop.Context, src string) *vm.VM {
|
2020-07-24 10:40:54 +00:00
|
|
|
b, di, err := compiler.CompileWithDebugInfo(strings.NewReader(src))
|
2020-05-07 11:38:19 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
v := core.SpawnVM(ic)
|
2020-07-24 10:40:54 +00:00
|
|
|
invokeMethod(t, testMainIdent, b, v, di)
|
2020-06-10 12:51:28 +00:00
|
|
|
v.LoadScriptWithFlags(b, smartcontract.All)
|
2020-05-07 11:38:19 +00:00
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
2020-01-27 07:59:57 +00:00
|
|
|
func TestAppCall(t *testing.T) {
|
|
|
|
srcInner := `
|
|
|
|
package foo
|
2020-07-24 10:40:54 +00:00
|
|
|
var a int = 3
|
2020-02-10 07:53:55 +00:00
|
|
|
func Main(a []byte, b []byte) []byte {
|
2020-07-23 15:13:02 +00:00
|
|
|
panic("Main was called")
|
|
|
|
}
|
|
|
|
func Append(a []byte, b []byte) []byte {
|
2020-02-10 07:53:55 +00:00
|
|
|
return append(a, b...)
|
2020-01-27 07:59:57 +00:00
|
|
|
}
|
2020-07-24 10:40:54 +00:00
|
|
|
func Add3(n int) int {
|
|
|
|
return a + n
|
|
|
|
}
|
2020-01-27 07:59:57 +00:00
|
|
|
`
|
|
|
|
|
2020-07-23 15:13:02 +00:00
|
|
|
inner, di, err := compiler.CompileWithDebugInfo(strings.NewReader(srcInner))
|
|
|
|
require.NoError(t, err)
|
2020-08-11 08:21:54 +00:00
|
|
|
m, err := di.ConvertToManifest(smartcontract.NoProperties, nil)
|
2020-01-27 07:59:57 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-07-23 15:13:02 +00:00
|
|
|
ih := hash.Hash160(inner)
|
2020-06-18 09:00:51 +00:00
|
|
|
ic := interop.NewContext(trigger.Application, nil, dao.NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet), nil, nil, nil, zaptest.NewLogger(t))
|
2020-07-23 15:13:02 +00:00
|
|
|
require.NoError(t, ic.DAO.PutContractState(&state.Contract{
|
|
|
|
Script: inner,
|
|
|
|
Manifest: *m,
|
|
|
|
}))
|
2020-01-27 07:59:57 +00:00
|
|
|
|
|
|
|
t.Run("valid script", func(t *testing.T) {
|
|
|
|
src := getAppCallScript(fmt.Sprintf("%#v", ih.BytesBE()))
|
2020-05-07 11:38:19 +00:00
|
|
|
v := spawnVM(t, ic, src)
|
2020-01-27 07:59:57 +00:00
|
|
|
require.NoError(t, v.Run())
|
|
|
|
|
2020-02-10 07:53:55 +00:00
|
|
|
assertResult(t, v, []byte{1, 2, 3, 4})
|
2020-01-27 07:59:57 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("missing script", func(t *testing.T) {
|
|
|
|
h := ih
|
|
|
|
h[0] = ^h[0]
|
|
|
|
|
|
|
|
src := getAppCallScript(fmt.Sprintf("%#v", h.BytesBE()))
|
2020-05-07 11:38:19 +00:00
|
|
|
v := spawnVM(t, ic, src)
|
2020-01-27 07:59:57 +00:00
|
|
|
require.Error(t, v.Run())
|
|
|
|
})
|
|
|
|
|
2020-01-27 12:30:36 +00:00
|
|
|
t.Run("convert from string constant", func(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package foo
|
2020-03-03 14:21:42 +00:00
|
|
|
import "github.com/nspcc-dev/neo-go/pkg/interop/engine"
|
2020-01-27 12:30:36 +00:00
|
|
|
const scriptHash = ` + fmt.Sprintf("%#v", string(ih.BytesBE())) + `
|
2020-02-10 07:53:55 +00:00
|
|
|
func Main() []byte {
|
|
|
|
x := []byte{1, 2}
|
|
|
|
y := []byte{3, 4}
|
2020-07-23 15:13:02 +00:00
|
|
|
result := engine.AppCall([]byte(scriptHash), "append", x, y)
|
2020-02-10 07:53:55 +00:00
|
|
|
return result.([]byte)
|
2020-01-27 12:30:36 +00:00
|
|
|
}
|
|
|
|
`
|
|
|
|
|
2020-05-07 11:38:19 +00:00
|
|
|
v := spawnVM(t, ic, src)
|
2020-01-27 12:30:36 +00:00
|
|
|
require.NoError(t, v.Run())
|
|
|
|
|
2020-02-10 07:53:55 +00:00
|
|
|
assertResult(t, v, []byte{1, 2, 3, 4})
|
2020-01-27 12:30:36 +00:00
|
|
|
})
|
2020-07-08 14:37:42 +00:00
|
|
|
|
|
|
|
t.Run("convert from var", func(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package foo
|
|
|
|
import "github.com/nspcc-dev/neo-go/pkg/interop/engine"
|
|
|
|
func Main() []byte {
|
|
|
|
x := []byte{1, 2}
|
|
|
|
y := []byte{3, 4}
|
|
|
|
var addr = []byte(` + fmt.Sprintf("%#v", string(ih.BytesBE())) + `)
|
2020-07-23 15:13:02 +00:00
|
|
|
result := engine.AppCall(addr, "append", x, y)
|
2020-07-08 14:37:42 +00:00
|
|
|
return result.([]byte)
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
v := spawnVM(t, ic, src)
|
|
|
|
require.NoError(t, v.Run())
|
|
|
|
|
|
|
|
assertResult(t, v, []byte{1, 2, 3, 4})
|
|
|
|
})
|
2020-07-24 10:40:54 +00:00
|
|
|
|
|
|
|
t.Run("InitializedGlobals", func(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
import "github.com/nspcc-dev/neo-go/pkg/interop/engine"
|
|
|
|
func Main() int {
|
|
|
|
var addr = []byte(` + fmt.Sprintf("%#v", string(ih.BytesBE())) + `)
|
|
|
|
result := engine.AppCall(addr, "add3", 39)
|
|
|
|
return result.(int)
|
|
|
|
}`
|
|
|
|
|
|
|
|
v := spawnVM(t, ic, src)
|
|
|
|
require.NoError(t, v.Run())
|
|
|
|
|
|
|
|
assertResult(t, v, big.NewInt(42))
|
|
|
|
})
|
2020-01-27 07:59:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func getAppCallScript(h string) string {
|
|
|
|
return `
|
|
|
|
package foo
|
2020-03-03 14:21:42 +00:00
|
|
|
import "github.com/nspcc-dev/neo-go/pkg/interop/engine"
|
2020-02-10 07:53:55 +00:00
|
|
|
func Main() []byte {
|
|
|
|
x := []byte{1, 2}
|
|
|
|
y := []byte{3, 4}
|
2020-07-23 15:13:02 +00:00
|
|
|
result := engine.AppCall(` + h + `, "append", x, y)
|
2020-02-10 07:53:55 +00:00
|
|
|
return result.([]byte)
|
2020-01-27 07:59:57 +00:00
|
|
|
}
|
|
|
|
`
|
|
|
|
}
|
2020-06-08 11:16:41 +00:00
|
|
|
|
|
|
|
func TestBuiltinDoesNotCompile(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
import "github.com/nspcc-dev/neo-go/pkg/interop/util"
|
|
|
|
func Main() bool {
|
|
|
|
a := 1
|
|
|
|
b := 2
|
|
|
|
return util.Equals(a, b)
|
|
|
|
}`
|
|
|
|
|
|
|
|
v := vmAndCompile(t, src)
|
|
|
|
ctx := v.Context()
|
|
|
|
retCount := 0
|
|
|
|
for op, _, err := ctx.Next(); err == nil; op, _, err = ctx.Next() {
|
|
|
|
if ctx.IP() > len(ctx.Program()) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if op == opcode.RET {
|
|
|
|
retCount++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.Equal(t, 1, retCount)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInteropPackage(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/block"
|
|
|
|
func Main() int {
|
|
|
|
b := block.Block{}
|
|
|
|
a := block.GetTransactionCount(b)
|
|
|
|
return a
|
|
|
|
}`
|
|
|
|
eval(t, src, big.NewInt(42))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBuiltinPackage(t *testing.T) {
|
|
|
|
src := `package foo
|
|
|
|
import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/util"
|
|
|
|
func Main() int {
|
|
|
|
if util.Equals(1, 2) { // always returns true
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
return 2
|
|
|
|
}`
|
|
|
|
eval(t, src, big.NewInt(1))
|
|
|
|
}
|
2020-07-07 18:49:21 +00:00
|
|
|
|
|
|
|
func TestLenForNil(t *testing.T) {
|
|
|
|
src := `
|
|
|
|
package foo
|
|
|
|
func Main() bool {
|
|
|
|
var a []int = nil
|
|
|
|
return len(a) == 0
|
|
|
|
}`
|
|
|
|
|
|
|
|
eval(t, src, true)
|
|
|
|
}
|