73c82584a3
Contract calls are performed via syscall System.Contract.Call in NEO3. This implements this in compiler and removes APPCALL from the VM.
139 lines
3.5 KiB
Go
139 lines
3.5 KiB
Go
package compiler_test
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"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/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) {
|
|
as1 := "Aej1fe4mUgou48Zzup5j8sPrE3973cJ5oz"
|
|
addr1, err := address.StringToUint160(as1)
|
|
require.NoError(t, err)
|
|
|
|
as2 := "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y"
|
|
addr2, err := address.StringToUint160(as2)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("append 2 addresses", func(t *testing.T) {
|
|
src := `
|
|
package foo
|
|
import "github.com/nspcc-dev/neo-go/pkg/interop/util"
|
|
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
|
|
import "github.com/nspcc-dev/neo-go/pkg/interop/util"
|
|
func Main() []byte {
|
|
addr1 := util.FromAddress("` + as1 + `")
|
|
sum := append(addr1, util.FromAddress("` + as2 + `")...)
|
|
return sum
|
|
}
|
|
`
|
|
|
|
eval(t, src, append(addr1.BytesBE(), addr2.BytesBE()...))
|
|
})
|
|
}
|
|
|
|
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
|
|
func Main(a []byte, b []byte) []byte {
|
|
return append(a, b...)
|
|
}
|
|
`
|
|
|
|
inner, err := compiler.Compile(strings.NewReader(srcInner))
|
|
require.NoError(t, err)
|
|
|
|
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 := spawnVM(t, ic, src)
|
|
require.NoError(t, v.Run())
|
|
|
|
assertResult(t, v, []byte{1, 2, 3, 4})
|
|
})
|
|
|
|
t.Run("missing script", func(t *testing.T) {
|
|
h := ih
|
|
h[0] = ^h[0]
|
|
|
|
src := getAppCallScript(fmt.Sprintf("%#v", h.BytesBE()))
|
|
v := spawnVM(t, ic, src)
|
|
require.Error(t, v.Run())
|
|
})
|
|
|
|
t.Run("invalid script address", func(t *testing.T) {
|
|
src := getAppCallScript("[]byte{1, 2, 3}")
|
|
|
|
_, err := compiler.Compile(strings.NewReader(src))
|
|
require.Error(t, err)
|
|
})
|
|
|
|
t.Run("convert from string constant", func(t *testing.T) {
|
|
src := `
|
|
package foo
|
|
import "github.com/nspcc-dev/neo-go/pkg/interop/engine"
|
|
const scriptHash = ` + fmt.Sprintf("%#v", string(ih.BytesBE())) + `
|
|
func Main() []byte {
|
|
x := []byte{1, 2}
|
|
y := []byte{3, 4}
|
|
result := engine.AppCall([]byte(scriptHash), x, y)
|
|
return result.([]byte)
|
|
}
|
|
`
|
|
|
|
v := spawnVM(t, ic, src)
|
|
require.NoError(t, v.Run())
|
|
|
|
assertResult(t, v, []byte{1, 2, 3, 4})
|
|
})
|
|
}
|
|
|
|
func getAppCallScript(h string) string {
|
|
return `
|
|
package foo
|
|
import "github.com/nspcc-dev/neo-go/pkg/interop/engine"
|
|
func Main() []byte {
|
|
x := []byte{1, 2}
|
|
y := []byte{3, 4}
|
|
result := engine.AppCall(` + h + `, x, y)
|
|
return result.([]byte)
|
|
}
|
|
`
|
|
}
|