From e8ba386e58cbd53964a6fef814166d15e8e9687e Mon Sep 17 00:00:00 2001 From: Evgeniy Stratonikov Date: Wed, 12 May 2021 15:02:40 +0300 Subject: [PATCH 1/4] compiler: remove offset comparison from debug test We shouldn't test for them anyway plus the error is more specific now. --- pkg/compiler/debug_test.go | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/pkg/compiler/debug_test.go b/pkg/compiler/debug_test.go index bb29280c5..1abbe0d07 100644 --- a/pkg/compiler/debug_test.go +++ b/pkg/compiler/debug_test.go @@ -158,14 +158,12 @@ func _deploy(data interface{}, isUpdate bool) {} t.Run("convert to Manifest", func(t *testing.T) { actual, err := d.ConvertToManifest(&Options{Name: "MyCTR", SafeMethods: []string{"methodInt", "methodString"}}) require.NoError(t, err) - // note: offsets are hard to predict, so we just take them from the output expected := &manifest.Manifest{ Name: "MyCTR", ABI: manifest.ABI{ Methods: []manifest.Method{ { - Name: "_deploy", - Offset: 0, + Name: "_deploy", Parameters: []manifest.Parameter{ manifest.NewParameter("data", smartcontract.AnyType), manifest.NewParameter("isUpdate", smartcontract.BoolType), @@ -173,16 +171,14 @@ func _deploy(data interface{}, isUpdate bool) {} ReturnType: smartcontract.VoidType, }, { - Name: "main", - Offset: 4, + Name: "main", Parameters: []manifest.Parameter{ manifest.NewParameter("op", smartcontract.StringType), }, ReturnType: smartcontract.BoolType, }, { - Name: "methodInt", - Offset: 70, + Name: "methodInt", Parameters: []manifest.Parameter{ { Name: "a", @@ -194,32 +190,27 @@ func _deploy(data interface{}, isUpdate bool) {} }, { Name: "methodString", - Offset: 101, Parameters: []manifest.Parameter{}, ReturnType: smartcontract.StringType, Safe: true, }, { Name: "methodByteArray", - Offset: 107, Parameters: []manifest.Parameter{}, ReturnType: smartcontract.ByteArrayType, }, { Name: "methodArray", - Offset: 112, Parameters: []manifest.Parameter{}, ReturnType: smartcontract.ArrayType, }, { Name: "methodStruct", - Offset: 117, Parameters: []manifest.Parameter{}, ReturnType: smartcontract.ArrayType, }, { - Name: "methodConcat", - Offset: 92, + Name: "methodConcat", Parameters: []manifest.Parameter{ { Name: "a", @@ -237,8 +228,7 @@ func _deploy(data interface{}, isUpdate bool) {} ReturnType: smartcontract.StringType, }, { - Name: "methodParams", - Offset: 129, + Name: "methodParams", Parameters: []manifest.Parameter{ manifest.NewParameter("addr", smartcontract.Hash160Type), manifest.NewParameter("h", smartcontract.Hash256Type), @@ -267,7 +257,15 @@ func _deploy(data interface{}, isUpdate bool) {} }, Extra: json.RawMessage("null"), } - require.ElementsMatch(t, expected.ABI.Methods, actual.ABI.Methods) + require.Equal(t, len(expected.ABI.Methods), len(actual.ABI.Methods)) + for _, exp := range expected.ABI.Methods { + md := actual.ABI.GetMethod(exp.Name, len(exp.Parameters)) + require.NotNil(t, md) + require.Equal(t, exp.Name, md.Name) + require.Equal(t, exp.Parameters, md.Parameters) + require.Equal(t, exp.ReturnType, md.ReturnType) + require.Equal(t, exp.Safe, md.Safe) + } require.Equal(t, expected.ABI.Events, actual.ABI.Events) require.Equal(t, expected.Groups, actual.Groups) require.Equal(t, expected.Permissions, actual.Permissions) From 7afca7f8e58476ed3d71639e3d653d32b07fc16f Mon Sep 17 00:00:00 2001 From: Evgeniy Stratonikov Date: Wed, 12 May 2021 14:54:40 +0300 Subject: [PATCH 2/4] compiler: add support for `static-variables` in debug info --- pkg/compiler/codegen.go | 2 ++ pkg/compiler/debug.go | 13 ++++++++----- pkg/compiler/debug_test.go | 11 +++++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 6bb8b2c62..41de79e05 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -44,6 +44,8 @@ type codegen struct { scope *funcScope globals map[string]int + // staticVariables contains global (static in NDX-DN11) variable names and types. + staticVariables []string // A mapping from label's names to their ids. labels map[labelWithType]uint16 diff --git a/pkg/compiler/debug.go b/pkg/compiler/debug.go index 042d47fd5..25ec62207 100644 --- a/pkg/compiler/debug.go +++ b/pkg/compiler/debug.go @@ -24,6 +24,8 @@ type DebugInfo struct { Events []EventDebugInfo `json:"events"` // EmittedEvents contains events occurring in code. EmittedEvents map[string][][]string `json:"-"` + // StaticVariables contains list of static variable names and types. + StaticVariables []string `json:"static-variables"` } // MethodDebugInfo represents smart-contract's method debug information. @@ -115,9 +117,10 @@ func (c *codegen) saveSequencePoint(n ast.Node) { func (c *codegen) emitDebugInfo(contract []byte) *DebugInfo { d := &DebugInfo{ - MainPkg: c.mainPkg.Pkg.Name(), - Events: []EventDebugInfo{}, - Documents: c.documents, + MainPkg: c.mainPkg.Pkg.Name(), + Events: []EventDebugInfo{}, + Documents: c.documents, + StaticVariables: c.staticVariables, } if c.initEndOffset > 0 { d.Methods = append(d.Methods, MethodDebugInfo{ @@ -179,11 +182,11 @@ func (c *codegen) emitDebugInfo(contract []byte) *DebugInfo { } func (c *codegen) registerDebugVariable(name string, expr ast.Expr) { + _, vt := c.scAndVMTypeFromExpr(expr) if c.scope == nil { - // do not save globals for now + c.staticVariables = append(c.staticVariables, name+","+vt.String()) return } - _, vt := c.scAndVMTypeFromExpr(expr) c.scope.variables = append(c.scope.variables, name+","+vt.String()) } diff --git a/pkg/compiler/debug_test.go b/pkg/compiler/debug_test.go index 1abbe0d07..8a876aaae 100644 --- a/pkg/compiler/debug_test.go +++ b/pkg/compiler/debug_test.go @@ -17,6 +17,7 @@ func TestCodeGen_DebugInfo(t *testing.T) { import "github.com/nspcc-dev/neo-go/pkg/interop" import "github.com/nspcc-dev/neo-go/pkg/interop/storage" import "github.com/nspcc-dev/neo-go/pkg/interop/native/ledger" +var staticVar int func Main(op string) bool { var s string _ = s @@ -79,6 +80,7 @@ func _deploy(data interface{}, isUpdate bool) {} "MethodOnPointerToStruct": "Void", "MethodParams": "Boolean", "_deploy": "Void", + manifest.MethodInit: "Void", } for i := range d.Methods { name := d.Methods[i].ID @@ -98,6 +100,10 @@ func _deploy(data interface{}, isUpdate bool) {} } }) + t.Run("static variables", func(t *testing.T) { + require.Equal(t, []string{"staticVar,Integer"}, d.StaticVariables) + }) + t.Run("param types", func(t *testing.T) { paramTypes := map[string][]DebugParam{ "_deploy": { @@ -162,6 +168,11 @@ func _deploy(data interface{}, isUpdate bool) {} Name: "MyCTR", ABI: manifest.ABI{ Methods: []manifest.Method{ + { + Name: manifest.MethodInit, + Parameters: []manifest.Parameter{}, + ReturnType: smartcontract.VoidType, + }, { Name: "_deploy", Parameters: []manifest.Parameter{ From b72f6be9e992d50663218e389a0e34fbcca64eb7 Mon Sep 17 00:00:00 2001 From: Evgeniy Stratonikov Date: Wed, 12 May 2021 15:08:22 +0300 Subject: [PATCH 3/4] compiler: emit debug variable info for `init()` --- pkg/compiler/codegen.go | 6 ++++++ pkg/compiler/debug.go | 1 + pkg/compiler/debug_test.go | 12 +++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 41de79e05..fb6a23d34 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -46,6 +46,8 @@ type codegen struct { globals map[string]int // staticVariables contains global (static in NDX-DN11) variable names and types. staticVariables []string + // initVariables contains variables local to `_initialize` method. + initVariables []string // A mapping from label's names to their ids. labels map[labelWithType]uint16 @@ -460,6 +462,10 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl, pkg *types. emit.Opcodes(c.prog.BinWriter, opcode.RET) } + if isInit { + c.initVariables = append(c.initVariables, f.variables...) + } + f.rng.End = uint16(c.prog.Len() - 1) if !isLambda { diff --git a/pkg/compiler/debug.go b/pkg/compiler/debug.go index 25ec62207..fb3beae80 100644 --- a/pkg/compiler/debug.go +++ b/pkg/compiler/debug.go @@ -138,6 +138,7 @@ func (c *codegen) emitDebugInfo(contract []byte) *DebugInfo { ReturnType: "Void", ReturnTypeSC: smartcontract.VoidType, SeqPoints: c.sequencePoints["init"], + Variables: c.initVariables, }) } if c.deployEndOffset >= 0 { diff --git a/pkg/compiler/debug_test.go b/pkg/compiler/debug_test.go index 8a876aaae..80cb885ed 100644 --- a/pkg/compiler/debug_test.go +++ b/pkg/compiler/debug_test.go @@ -18,6 +18,15 @@ func TestCodeGen_DebugInfo(t *testing.T) { import "github.com/nspcc-dev/neo-go/pkg/interop/storage" import "github.com/nspcc-dev/neo-go/pkg/interop/native/ledger" var staticVar int +func init() { + a := 1 + _ = a +} +func init() { + x := "" + _ = x + staticVar = 1 +} func Main(op string) bool { var s string _ = s @@ -90,7 +99,8 @@ func _deploy(data interface{}, isUpdate bool) {} t.Run("variables", func(t *testing.T) { vars := map[string][]string{ - "Main": {"s,ByteString", "res,Integer"}, + "Main": {"s,ByteString", "res,Integer"}, + manifest.MethodInit: {"a,Integer", "x,ByteString"}, } for i := range d.Methods { v, ok := vars[d.Methods[i].ID] From 7b638d548932eecc0a1af01eba7f57d679b365a8 Mon Sep 17 00:00:00 2001 From: Evgeniy Stratonikov Date: Wed, 12 May 2021 16:03:47 +0300 Subject: [PATCH 4/4] compiler: emit debug variable info for `_deploy()` --- pkg/compiler/codegen.go | 4 ++++ pkg/compiler/debug.go | 1 + pkg/compiler/debug_test.go | 7 ++++--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index fb6a23d34..92c56af0d 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -48,6 +48,8 @@ type codegen struct { staticVariables []string // initVariables contains variables local to `_initialize` method. initVariables []string + // deployVariables contains variables local to `_initialize` method. + deployVariables []string // A mapping from label's names to their ids. labels map[labelWithType]uint16 @@ -464,6 +466,8 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl, pkg *types. if isInit { c.initVariables = append(c.initVariables, f.variables...) + } else if isDeploy { + c.deployVariables = append(c.deployVariables, f.variables...) } f.rng.End = uint16(c.prog.Len() - 1) diff --git a/pkg/compiler/debug.go b/pkg/compiler/debug.go index fb3beae80..2ac735b5d 100644 --- a/pkg/compiler/debug.go +++ b/pkg/compiler/debug.go @@ -169,6 +169,7 @@ func (c *codegen) emitDebugInfo(contract []byte) *DebugInfo { ReturnType: "Void", ReturnTypeSC: smartcontract.VoidType, SeqPoints: c.sequencePoints[manifest.MethodDeploy], + Variables: c.deployVariables, }) } for name, scope := range c.funcs { diff --git a/pkg/compiler/debug_test.go b/pkg/compiler/debug_test.go index 80cb885ed..b5dfbd121 100644 --- a/pkg/compiler/debug_test.go +++ b/pkg/compiler/debug_test.go @@ -63,7 +63,7 @@ func MethodParams(addr interop.Hash160, h interop.Hash256, type MyStruct struct {} func (ms MyStruct) MethodOnStruct() { } func (ms *MyStruct) MethodOnPointerToStruct() { } -func _deploy(data interface{}, isUpdate bool) {} +func _deploy(data interface{}, isUpdate bool) { x := 1; _ = x } ` info, err := getBuildInfo("foo.go", src) @@ -99,8 +99,9 @@ func _deploy(data interface{}, isUpdate bool) {} t.Run("variables", func(t *testing.T) { vars := map[string][]string{ - "Main": {"s,ByteString", "res,Integer"}, - manifest.MethodInit: {"a,Integer", "x,ByteString"}, + "Main": {"s,ByteString", "res,Integer"}, + manifest.MethodInit: {"a,Integer", "x,ByteString"}, + manifest.MethodDeploy: {"x,Integer"}, } for i := range d.Methods { v, ok := vars[d.Methods[i].ID]