Merge pull request #1607 from nspcc-dev/compiler/safe

Set `Safe` flag in emitted manifest
This commit is contained in:
Roman Khimov 2020-12-11 14:03:55 +03:00 committed by GitHub
commit 1d529dc5b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 39 additions and 46 deletions

View file

@ -363,6 +363,7 @@ func initSmartContract(ctx *cli.Context) error {
m := ProjectConfig{ m := ProjectConfig{
Name: contractName, Name: contractName,
SupportedStandards: []string{}, SupportedStandards: []string{},
SafeMethods: []string{},
Events: []manifest.Event{ Events: []manifest.Event{
{ {
Name: "Hello world!", Name: "Hello world!",
@ -423,6 +424,7 @@ func contractCompile(ctx *cli.Context) error {
o.Name = conf.Name o.Name = conf.Name
o.ContractEvents = conf.Events o.ContractEvents = conf.Events
o.ContractSupportedStandards = conf.SupportedStandards o.ContractSupportedStandards = conf.SupportedStandards
o.SafeMethods = conf.SafeMethods
} }
result, err := compiler.CompileAndSave(src, o) result, err := compiler.CompileAndSave(src, o)
@ -646,6 +648,7 @@ func testInvokeScript(ctx *cli.Context) error {
// ProjectConfig contains project metadata. // ProjectConfig contains project metadata.
type ProjectConfig struct { type ProjectConfig struct {
Name string Name string
SafeMethods []string
SupportedStandards []string SupportedStandards []string
Events []manifest.Event Events []manifest.Event
} }

View file

@ -59,6 +59,7 @@ func RuntimeNotify(args []interface{}) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, require.Equal(t,
`name: testContract `name: testContract
safemethods: []
supportedstandards: [] supportedstandards: []
events: events:
- name: Hello world! - name: Hello world!

View file

@ -1,5 +1,6 @@
name: "My awesome token" name: "My awesome token"
supportedstandards: ["NEP-17"] supportedstandards: ["NEP-17"]
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"]
events: events:
- name: Transfer - name: Transfer
parameters: parameters:

View file

@ -1,5 +1,6 @@
name: "Awesome NEO Token" name: "Awesome NEO Token"
supportedstandards: ["NEP-17"] supportedstandards: ["NEP-17"]
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"]
events: events:
- name: Transfer - name: Transfer
parameters: parameters:

View file

@ -62,7 +62,7 @@ func NewDeployTx(name string, sender util.Uint160, r gio.Reader) (*transaction.T
return nil, util.Uint160{}, err return nil, util.Uint160{}, err
} }
m, err := di.ConvertToManifest(name, nil) m, err := di.ConvertToManifest(&compiler.Options{Name: name})
if err != nil { if err != nil {
return nil, util.Uint160{}, err return nil, util.Uint160{}, err
} }

View file

@ -51,6 +51,9 @@ type Options struct {
// The list of standards supported by the contract. // The list of standards supported by the contract.
ContractSupportedStandards []string ContractSupportedStandards []string
// SafeMethods contains list of methods which will be marked as safe in manifest.
SafeMethods []string
} }
type buildInfo struct { type buildInfo struct {
@ -219,7 +222,7 @@ func CompileAndSave(src string, o *Options) ([]byte, error) {
} }
if o.ManifestFile != "" { if o.ManifestFile != "" {
m, err := di.ConvertToManifest(o.Name, o.ContractEvents, o.ContractSupportedStandards...) m, err := di.ConvertToManifest(o)
if err != nil { if err != nil {
return b, fmt.Errorf("failed to convert debug info to manifest: %w", err) return b, fmt.Errorf("failed to convert debug info to manifest: %w", err)
} }

View file

@ -334,49 +334,27 @@ func (d *DebugParam) UnmarshalJSON(data []byte) error {
} }
// ToManifestParameter converts DebugParam to manifest.Parameter // ToManifestParameter converts DebugParam to manifest.Parameter
func (d *DebugParam) ToManifestParameter() (manifest.Parameter, error) { func (d *DebugParam) ToManifestParameter() manifest.Parameter {
return manifest.Parameter{ return manifest.Parameter{
Name: d.Name, Name: d.Name,
Type: d.TypeSC, Type: d.TypeSC,
}, nil }
} }
// ToManifestMethod converts MethodDebugInfo to manifest.Method // ToManifestMethod converts MethodDebugInfo to manifest.Method
func (m *MethodDebugInfo) ToManifestMethod() (manifest.Method, error) { func (m *MethodDebugInfo) ToManifestMethod() manifest.Method {
var ( var (
result manifest.Method result manifest.Method
err error
) )
parameters := make([]manifest.Parameter, len(m.Parameters)) parameters := make([]manifest.Parameter, len(m.Parameters))
for i, p := range m.Parameters { for i, p := range m.Parameters {
parameters[i], err = p.ToManifestParameter() parameters[i] = p.ToManifestParameter()
if err != nil {
return result, err
}
} }
result.Name = m.Name.Name result.Name = m.Name.Name
result.Offset = int(m.Range.Start) result.Offset = int(m.Range.Start)
result.Parameters = parameters result.Parameters = parameters
result.ReturnType = m.ReturnTypeSC result.ReturnType = m.ReturnTypeSC
return result, nil return result
}
// 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
} }
// MarshalJSON implements json.Marshaler interface. // MarshalJSON implements json.Marshaler interface.
@ -425,31 +403,31 @@ func parsePairJSON(data []byte, sep string) (string, string, error) {
// ConvertToManifest converts contract to the manifest.Manifest struct for debugger. // 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. // 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")
}
methods := make([]manifest.Method, 0) methods := make([]manifest.Method, 0)
for _, method := range di.Methods { for _, method := range di.Methods {
if method.IsExported && method.IsFunction && method.Name.Namespace == di.MainPkg { if method.IsExported && method.IsFunction && method.Name.Namespace == di.MainPkg {
mMethod, err := method.ToManifestMethod() mMethod := method.ToManifestMethod()
if err != nil { for i := range o.SafeMethods {
return nil, err if mMethod.Name == o.SafeMethods[i] {
mMethod.Safe = true
break
}
} }
methods = append(methods, mMethod) methods = append(methods, mMethod)
} }
} }
result := manifest.NewManifest(name) result := manifest.NewManifest(o.Name)
if supportedStandards != nil { if o.ContractSupportedStandards != nil {
result.SupportedStandards = supportedStandards result.SupportedStandards = o.ContractSupportedStandards
}
if events == nil {
events = make([]manifest.Event, 0)
} }
result.ABI = manifest.ABI{ result.ABI = manifest.ABI{
Methods: methods, Methods: methods,
Events: events, Events: o.ContractEvents,
}
if result.ABI.Events == nil {
result.ABI.Events = make([]manifest.Event, 0)
} }
result.Permissions = []manifest.Permission{ result.Permissions = []manifest.Permission{
{ {

View file

@ -150,7 +150,7 @@ func _deploy(isUpdate bool) {}
} }
t.Run("convert to Manifest", func(t *testing.T) { t.Run("convert to Manifest", func(t *testing.T) {
actual, err := d.ConvertToManifest("MyCTR", nil) actual, err := d.ConvertToManifest(&Options{Name: "MyCTR", SafeMethods: []string{"methodInt", "methodString"}})
require.NoError(t, err) require.NoError(t, err)
// note: offsets are hard to predict, so we just take them from the output // note: offsets are hard to predict, so we just take them from the output
expected := &manifest.Manifest{ expected := &manifest.Manifest{
@ -183,12 +183,14 @@ func _deploy(isUpdate bool) {}
}, },
}, },
ReturnType: smartcontract.IntegerType, ReturnType: smartcontract.IntegerType,
Safe: true,
}, },
{ {
Name: "methodString", Name: "methodString",
Offset: 101, Offset: 101,
Parameters: []manifest.Parameter{}, Parameters: []manifest.Parameter{},
ReturnType: smartcontract.StringType, ReturnType: smartcontract.StringType,
Safe: true,
}, },
{ {
Name: "methodByteArray", Name: "methodByteArray",

View file

@ -128,7 +128,7 @@ func TestAppCall(t *testing.T) {
}` }`
barCtr, di, err := compiler.CompileWithDebugInfo("bar.go", strings.NewReader(srcDeep)) barCtr, di, err := compiler.CompileWithDebugInfo("bar.go", strings.NewReader(srcDeep))
require.NoError(t, err) require.NoError(t, err)
mBar, err := di.ConvertToManifest("Bar", nil) mBar, err := di.ConvertToManifest(&compiler.Options{Name: "Bar"})
require.NoError(t, err) require.NoError(t, err)
barH := hash.Hash160(barCtr) barH := hash.Hash160(barCtr)
@ -160,7 +160,7 @@ func TestAppCall(t *testing.T) {
inner, di, err := compiler.CompileWithDebugInfo("foo.go", strings.NewReader(srcInner)) inner, di, err := compiler.CompileWithDebugInfo("foo.go", strings.NewReader(srcInner))
require.NoError(t, err) require.NoError(t, err)
m, err := di.ConvertToManifest("Foo", nil) m, err := di.ConvertToManifest(&compiler.Options{Name: "Foo"})
require.NoError(t, err) require.NoError(t, err)
ih := hash.Hash160(inner) ih := hash.Hash160(inner)

View file

@ -14,18 +14,22 @@ var nep17 = &manifest.Manifest{
{Type: smartcontract.Hash160Type}, {Type: smartcontract.Hash160Type},
}, },
ReturnType: smartcontract.IntegerType, ReturnType: smartcontract.IntegerType,
Safe: true,
}, },
{ {
Name: "decimals", Name: "decimals",
ReturnType: smartcontract.IntegerType, ReturnType: smartcontract.IntegerType,
Safe: true,
}, },
{ {
Name: "symbol", Name: "symbol",
ReturnType: smartcontract.StringType, ReturnType: smartcontract.StringType,
Safe: true,
}, },
{ {
Name: "totalSupply", Name: "totalSupply",
ReturnType: smartcontract.IntegerType, ReturnType: smartcontract.IntegerType,
Safe: true,
}, },
{ {
Name: "transfer", Name: "transfer",