From 097d35b9d50d6dc7c165a2680fd985d70ddb02f2 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Mon, 27 Jan 2020 11:53:47 +0300 Subject: [PATCH] compiler: fix a bug with FromAddress handling Conversion of string to address with FromAddress is performed at compile time so there is no need to push parameters on stack. --- pkg/compiler/analysis.go | 5 +++++ pkg/compiler/codegen.go | 10 ++++++--- pkg/compiler/interop_test.go | 40 ++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/pkg/compiler/analysis.go b/pkg/compiler/analysis.go index d29348b8d..c1b01e2ee 100644 --- a/pkg/compiler/analysis.go +++ b/pkg/compiler/analysis.go @@ -185,6 +185,11 @@ func isAppCall(expr ast.Expr) bool { return ok && t.Sel.Name == "AppCall" } +func isFromAddress(expr ast.Expr) bool { + t, ok := expr.(*ast.SelectorExpr) + return ok && t.Sel.Name == "FromAddress" +} + func isByteArray(lit *ast.CompositeLit, tInfo *types.Info) bool { if len(lit.Elts) == 0 { return false diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 95695e98b..1023bd142 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -491,9 +491,13 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { args := n.Args isAppCall := isAppCall(n.Fun) - // When using APPCALL, script hash is a part of the instruction so - // script hash should be emitted after APPCALL. - if isAppCall { + isFromAddress := isFromAddress(n.Fun) + // There are 2 special cases: + // 1. When using APPCALL, script hash is a part of the instruction so + // script hash should be emitted after APPCALL. + // 2. With FromAddress, parameter conversion is happening at compile-time + // so there is no need to push parameters on stack and perform an actual call + if isAppCall || isFromAddress { args = n.Args[1:] } diff --git a/pkg/compiler/interop_test.go b/pkg/compiler/interop_test.go index bd86c4e4f..f1e0e1748 100644 --- a/pkg/compiler/interop_test.go +++ b/pkg/compiler/interop_test.go @@ -8,10 +8,50 @@ import ( "github.com/CityOfZion/neo-go/pkg/compiler" "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/CityOfZion/neo-go/pkg/encoding/address" "github.com/CityOfZion/neo-go/pkg/util" "github.com/stretchr/testify/require" ) +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/CityOfZion/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/CityOfZion/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 TestAppCall(t *testing.T) { srcInner := ` package foo