From 9fd8577dd974b1d4b8c1106cee179fdba095292c Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 10 Dec 2020 17:42:12 +0300 Subject: [PATCH 1/5] compiler: use `Options` in `ConvertToManifest()` --- internal/testchain/transaction.go | 2 +- pkg/compiler/compiler.go | 2 +- pkg/compiler/debug.go | 16 ++++++++-------- pkg/compiler/debug_test.go | 2 +- pkg/compiler/interop_test.go | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/internal/testchain/transaction.go b/internal/testchain/transaction.go index c024ad85c..10e71529e 100644 --- a/internal/testchain/transaction.go +++ b/internal/testchain/transaction.go @@ -62,7 +62,7 @@ func NewDeployTx(name string, sender util.Uint160, r gio.Reader) (*transaction.T return nil, util.Uint160{}, err } - m, err := di.ConvertToManifest(name, nil) + m, err := di.ConvertToManifest(&compiler.Options{Name: name}) if err != nil { return nil, util.Uint160{}, err } diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index 41fe8d0c8..0d4b5b970 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -219,7 +219,7 @@ func CompileAndSave(src string, o *Options) ([]byte, error) { } if o.ManifestFile != "" { - m, err := di.ConvertToManifest(o.Name, o.ContractEvents, o.ContractSupportedStandards...) + m, err := di.ConvertToManifest(o) if err != nil { return b, fmt.Errorf("failed to convert debug info to manifest: %w", err) } diff --git a/pkg/compiler/debug.go b/pkg/compiler/debug.go index d82fc688e..4fc221504 100644 --- a/pkg/compiler/debug.go +++ b/pkg/compiler/debug.go @@ -425,7 +425,7 @@ func parsePairJSON(data []byte, sep string) (string, string, error) { // ConvertToManifest converts contract to the manifest.Manifest struct for debugger. // Note: manifest is taken from the external source, however it can be generated ad-hoc. See #1038. -func (di *DebugInfo) ConvertToManifest(name string, events []manifest.Event, supportedStandards ...string) (*manifest.Manifest, error) { +func (di *DebugInfo) ConvertToManifest(o *Options) (*manifest.Manifest, error) { if di.MainPkg == "" { return nil, errors.New("no Main method was found") } @@ -440,16 +440,16 @@ func (di *DebugInfo) ConvertToManifest(name string, events []manifest.Event, sup } } - result := manifest.NewManifest(name) - if supportedStandards != nil { - result.SupportedStandards = supportedStandards - } - if events == nil { - events = make([]manifest.Event, 0) + result := manifest.NewManifest(o.Name) + if o.ContractSupportedStandards != nil { + result.SupportedStandards = o.ContractSupportedStandards } result.ABI = manifest.ABI{ Methods: methods, - Events: events, + Events: o.ContractEvents, + } + if result.ABI.Events == nil { + result.ABI.Events = make([]manifest.Event, 0) } result.Permissions = []manifest.Permission{ { diff --git a/pkg/compiler/debug_test.go b/pkg/compiler/debug_test.go index 3be6ec420..3915c6b63 100644 --- a/pkg/compiler/debug_test.go +++ b/pkg/compiler/debug_test.go @@ -150,7 +150,7 @@ func _deploy(isUpdate bool) {} } t.Run("convert to Manifest", func(t *testing.T) { - actual, err := d.ConvertToManifest("MyCTR", nil) + actual, err := d.ConvertToManifest(&Options{Name: "MyCTR"}) require.NoError(t, err) // note: offsets are hard to predict, so we just take them from the output expected := &manifest.Manifest{ diff --git a/pkg/compiler/interop_test.go b/pkg/compiler/interop_test.go index 6aa603aaa..eb81b717b 100644 --- a/pkg/compiler/interop_test.go +++ b/pkg/compiler/interop_test.go @@ -128,7 +128,7 @@ func TestAppCall(t *testing.T) { }` barCtr, di, err := compiler.CompileWithDebugInfo("bar.go", strings.NewReader(srcDeep)) require.NoError(t, err) - mBar, err := di.ConvertToManifest("Bar", nil) + mBar, err := di.ConvertToManifest(&compiler.Options{Name: "Bar"}) require.NoError(t, err) barH := hash.Hash160(barCtr) @@ -160,7 +160,7 @@ func TestAppCall(t *testing.T) { inner, di, err := compiler.CompileWithDebugInfo("foo.go", strings.NewReader(srcInner)) require.NoError(t, err) - m, err := di.ConvertToManifest("Foo", nil) + m, err := di.ConvertToManifest(&compiler.Options{Name: "Foo"}) require.NoError(t, err) ih := hash.Hash160(inner) From d7194e4da588dbe82570e09faa392d03c2360a63 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 10 Dec 2020 17:45:23 +0300 Subject: [PATCH 2/5] compiler: do not check for main package in `ConvertToManifest` --- pkg/compiler/debug.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/compiler/debug.go b/pkg/compiler/debug.go index 4fc221504..978241130 100644 --- a/pkg/compiler/debug.go +++ b/pkg/compiler/debug.go @@ -426,9 +426,6 @@ func parsePairJSON(data []byte, sep string) (string, string, error) { // ConvertToManifest converts contract to the manifest.Manifest struct for debugger. // Note: manifest is taken from the external source, however it can be generated ad-hoc. See #1038. func (di *DebugInfo) ConvertToManifest(o *Options) (*manifest.Manifest, error) { - if di.MainPkg == "" { - return nil, errors.New("no Main method was found") - } methods := make([]manifest.Method, 0) for _, method := range di.Methods { if method.IsExported && method.IsFunction && method.Name.Namespace == di.MainPkg { From 2341ae0c5314706c7a2489e674071dd7507a9b2f Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 10 Dec 2020 17:55:52 +0300 Subject: [PATCH 3/5] compiler: specify safe methods in config --- cli/smartcontract/smart_contract.go | 3 +++ cli/smartcontract/smart_contract_test.go | 1 + pkg/compiler/compiler.go | 3 +++ pkg/compiler/debug.go | 6 ++++++ pkg/compiler/debug_test.go | 4 +++- 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 270a4014b..dc9205953 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -363,6 +363,7 @@ func initSmartContract(ctx *cli.Context) error { m := ProjectConfig{ Name: contractName, SupportedStandards: []string{}, + SafeMethods: []string{}, Events: []manifest.Event{ { Name: "Hello world!", @@ -423,6 +424,7 @@ func contractCompile(ctx *cli.Context) error { o.Name = conf.Name o.ContractEvents = conf.Events o.ContractSupportedStandards = conf.SupportedStandards + o.SafeMethods = conf.SafeMethods } result, err := compiler.CompileAndSave(src, o) @@ -646,6 +648,7 @@ func testInvokeScript(ctx *cli.Context) error { // ProjectConfig contains project metadata. type ProjectConfig struct { Name string + SafeMethods []string SupportedStandards []string Events []manifest.Event } diff --git a/cli/smartcontract/smart_contract_test.go b/cli/smartcontract/smart_contract_test.go index 8264cb858..eba92c021 100644 --- a/cli/smartcontract/smart_contract_test.go +++ b/cli/smartcontract/smart_contract_test.go @@ -59,6 +59,7 @@ func RuntimeNotify(args []interface{}) { require.NoError(t, err) require.Equal(t, `name: testContract +safemethods: [] supportedstandards: [] events: - name: Hello world! diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index 0d4b5b970..02987acb7 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -51,6 +51,9 @@ type Options struct { // The list of standards supported by the contract. ContractSupportedStandards []string + + // SafeMethods contains list of methods which will be marked as safe in manifest. + SafeMethods []string } type buildInfo struct { diff --git a/pkg/compiler/debug.go b/pkg/compiler/debug.go index 978241130..11e08db58 100644 --- a/pkg/compiler/debug.go +++ b/pkg/compiler/debug.go @@ -433,6 +433,12 @@ func (di *DebugInfo) ConvertToManifest(o *Options) (*manifest.Manifest, error) { if err != nil { return nil, err } + for i := range o.SafeMethods { + if mMethod.Name == o.SafeMethods[i] { + mMethod.Safe = true + break + } + } methods = append(methods, mMethod) } } diff --git a/pkg/compiler/debug_test.go b/pkg/compiler/debug_test.go index 3915c6b63..fcced5851 100644 --- a/pkg/compiler/debug_test.go +++ b/pkg/compiler/debug_test.go @@ -150,7 +150,7 @@ func _deploy(isUpdate bool) {} } t.Run("convert to Manifest", func(t *testing.T) { - actual, err := d.ConvertToManifest(&Options{Name: "MyCTR"}) + 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{ @@ -183,12 +183,14 @@ func _deploy(isUpdate bool) {} }, }, ReturnType: smartcontract.IntegerType, + Safe: true, }, { Name: "methodString", Offset: 101, Parameters: []manifest.Parameter{}, ReturnType: smartcontract.StringType, + Safe: true, }, { Name: "methodByteArray", From ec1ff42872c4a44345386cb0565160de13f3b555 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 10 Dec 2020 18:04:49 +0300 Subject: [PATCH 4/5] manifest: add `Safe` flag for NEP-17 methods --- examples/token-sale/token_sale.yml | 1 + examples/token/token.yml | 1 + pkg/smartcontract/manifest/standard/nep17.go | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/examples/token-sale/token_sale.yml b/examples/token-sale/token_sale.yml index bda6ba182..20ea78365 100644 --- a/examples/token-sale/token_sale.yml +++ b/examples/token-sale/token_sale.yml @@ -1,5 +1,6 @@ name: "My awesome token" supportedstandards: ["NEP-17"] +safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"] events: - name: Transfer parameters: diff --git a/examples/token/token.yml b/examples/token/token.yml index 32fd428b5..071976019 100644 --- a/examples/token/token.yml +++ b/examples/token/token.yml @@ -1,5 +1,6 @@ name: "Awesome NEO Token" supportedstandards: ["NEP-17"] +safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"] events: - name: Transfer parameters: diff --git a/pkg/smartcontract/manifest/standard/nep17.go b/pkg/smartcontract/manifest/standard/nep17.go index ff76c4199..098ce6cfc 100644 --- a/pkg/smartcontract/manifest/standard/nep17.go +++ b/pkg/smartcontract/manifest/standard/nep17.go @@ -14,18 +14,22 @@ var nep17 = &manifest.Manifest{ {Type: smartcontract.Hash160Type}, }, ReturnType: smartcontract.IntegerType, + Safe: true, }, { Name: "decimals", ReturnType: smartcontract.IntegerType, + Safe: true, }, { Name: "symbol", ReturnType: smartcontract.StringType, + Safe: true, }, { Name: "totalSupply", ReturnType: smartcontract.IntegerType, + Safe: true, }, { Name: "transfer", From 4dc587767474527e54be6bccc32782e1365796be Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 10 Dec 2020 18:56:05 +0300 Subject: [PATCH 5/5] compiler: remove unused code and simplify error handling After cbf26f3 some errors can't occur. --- pkg/compiler/debug.go | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/pkg/compiler/debug.go b/pkg/compiler/debug.go index 11e08db58..49812c1b8 100644 --- a/pkg/compiler/debug.go +++ b/pkg/compiler/debug.go @@ -334,49 +334,27 @@ func (d *DebugParam) UnmarshalJSON(data []byte) error { } // ToManifestParameter converts DebugParam to manifest.Parameter -func (d *DebugParam) ToManifestParameter() (manifest.Parameter, error) { +func (d *DebugParam) ToManifestParameter() manifest.Parameter { return manifest.Parameter{ Name: d.Name, Type: d.TypeSC, - }, nil + } } // ToManifestMethod converts MethodDebugInfo to manifest.Method -func (m *MethodDebugInfo) ToManifestMethod() (manifest.Method, error) { +func (m *MethodDebugInfo) ToManifestMethod() manifest.Method { var ( result manifest.Method - err error ) parameters := make([]manifest.Parameter, len(m.Parameters)) for i, p := range m.Parameters { - parameters[i], err = p.ToManifestParameter() - if err != nil { - return result, err - } + parameters[i] = p.ToManifestParameter() } result.Name = m.Name.Name result.Offset = int(m.Range.Start) result.Parameters = parameters result.ReturnType = m.ReturnTypeSC - return result, nil -} - -// ToManifestEvent converts EventDebugInfo to manifest.Event -func (e *EventDebugInfo) ToManifestEvent() (manifest.Event, error) { - var ( - result manifest.Event - err error - ) - parameters := make([]manifest.Parameter, len(e.Parameters)) - for i, p := range e.Parameters { - parameters[i], err = p.ToManifestParameter() - if err != nil { - return result, err - } - } - result.Name = e.Name - result.Parameters = parameters - return result, nil + return result } // MarshalJSON implements json.Marshaler interface. @@ -429,10 +407,7 @@ func (di *DebugInfo) ConvertToManifest(o *Options) (*manifest.Manifest, error) { methods := make([]manifest.Method, 0) for _, method := range di.Methods { if method.IsExported && method.IsFunction && method.Name.Namespace == di.MainPkg { - mMethod, err := method.ToManifestMethod() - if err != nil { - return nil, err - } + mMethod := method.ToManifestMethod() for i := range o.SafeMethods { if mMethod.Name == o.SafeMethods[i] { mMethod.Safe = true