nef: add Source field

Follow neo-project/neo#2605.
This commit is contained in:
Roman Khimov 2021-09-24 00:19:37 +03:00
parent 0a52c32df3
commit 42a9d3d7b8
20 changed files with 54 additions and 10 deletions

View file

@ -601,9 +601,9 @@ func TestCompileExamples(t *testing.T) {
})
}
t.Run("invalid events in manifest", func(t *testing.T) {
t.Run("invalid manifest", func(t *testing.T) {
const dir = "./testdata/"
for _, name := range []string{"invalid1", "invalid2", "invalid3"} {
for _, name := range []string{"invalid1", "invalid2", "invalid3", "invalid4"} {
outF := path.Join(tmpDir, name+".nef")
manifestF := path.Join(tmpDir, name+".manifest.json")
e.RunWithError(t, "neo-go", "contract", "compile",

View file

@ -427,6 +427,7 @@ func initSmartContract(ctx *cli.Context) error {
m := ProjectConfig{
Name: contractName,
SourceURL: "http://example.com/",
SupportedStandards: []string{},
SafeMethods: []string{},
Events: []manifest.Event{
@ -489,6 +490,7 @@ func contractCompile(ctx *cli.Context) error {
return err
}
o.Name = conf.Name
o.SourceURL = conf.SourceURL
o.ContractEvents = conf.Events
o.ContractSupportedStandards = conf.SupportedStandards
o.Permissions = make([]manifest.Permission, len(conf.Permissions))
@ -733,6 +735,7 @@ func testInvokeScript(ctx *cli.Context) error {
// ProjectConfig contains project metadata.
type ProjectConfig struct {
Name string
SourceURL string
SafeMethods []string
SupportedStandards []string
Events []manifest.Event

View file

@ -59,6 +59,7 @@ func RuntimeNotify(args []interface{}) {
require.NoError(t, err)
require.Equal(t,
`name: testContract
sourceurl: http://example.com/
safemethods: []
supportedstandards: []
events:

5
cli/testdata/invalid4/invalid.go vendored Normal file
View file

@ -0,0 +1,5 @@
package invalid4
func Verify() bool {
return true
}

2
cli/testdata/invalid4/invalid.yml vendored Normal file
View file

@ -0,0 +1,2 @@
name: Test bad source url
sourceurl: http://example.com/with/some/huge/path/that/cant/be/ever/normally/reached/but/we/need/to/test/for/it/anyway/because/there/is/some/path/in/the/code/that/does/this/check/and/it/should/be/triggered/to/ensure/proper/coverage/in/this/particular/component/of/our/perfect/compiler

View file

@ -1,4 +1,5 @@
name: "Engine example"
sourceurl: https://github.com/nspcc-dev/neo-go/
supportedstandards: []
events:
- name: Tx

View file

@ -1,4 +1,5 @@
name: "Event types example"
sourceurl: https://github.com/nspcc-dev/neo-go/
supportedstandards: []
events:
- name: SomeBytes

View file

@ -1,4 +1,5 @@
name: "Iterator example"
sourceurl: https://github.com/nspcc-dev/neo-go/
supportedstandards: []
events:
- name: found storage key-value pair

View file

@ -1,4 +1,5 @@
name: "NameService"
sourceurl: https://github.com/nspcc-dev/neo-go/
supportedstandards: ["NEP-11"]
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf",
"tokens", "properties", "roots", "getPrice", "isAvailable", "getRecord",

View file

@ -1,4 +1,5 @@
name: "HASHY NFT"
sourceurl: https://github.com/nspcc-dev/neo-go/
supportedstandards: ["NEP-11"]
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "tokens", "properties"]
events:

View file

@ -1,4 +1,5 @@
name: "Oracle example"
sourceurl: https://github.com/nspcc-dev/neo-go/
supportedstandards: []
events:
permissions:

View file

@ -1,4 +1,5 @@
name: "Runtime example"
sourceurl: https://github.com/nspcc-dev/neo-go/
supportedstandards: []
events:
- name: Event

View file

@ -1,3 +1,4 @@
name: "Storage example"
sourceurl: https://github.com/nspcc-dev/neo-go/
supportedstandards: []
events: []

View file

@ -1,4 +1,5 @@
name: "Timer example"
sourceurl: https://github.com/nspcc-dev/neo-go/
supportedstandards: []
events: []
permissions:

View file

@ -1,4 +1,5 @@
name: "My awesome token"
sourceurl: https://github.com/nspcc-dev/neo-go/
supportedstandards: ["NEP-17"]
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"]
events:

View file

@ -1,4 +1,5 @@
name: "Awesome NEO Token"
sourceurl: https://github.com/nspcc-dev/neo-go/
supportedstandards: ["NEP-17"]
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"]
events:

View file

@ -52,6 +52,9 @@ type Options struct {
// Name is contract's name to be written to manifest.
Name string
// SourceURL is contract's source URL to be written to manifest.
SourceURL string
// Runtime notifications.
ContractEvents []manifest.Event
@ -199,6 +202,13 @@ func CompileAndSave(src string, o *Options) ([]byte, error) {
if err != nil {
return nil, fmt.Errorf("error while trying to create .nef file: %w", err)
}
if o.SourceURL != "" {
if len(o.SourceURL) > nef.MaxSourceURLLength {
return nil, errors.New("too long source URL")
}
f.Source = o.SourceURL
f.Checksum = f.CalculateChecksum()
}
bytes, err := f.Bytes()
if err != nil {
return nil, fmt.Errorf("error while serializing .nef file: %w", err)

View file

@ -1,4 +1,5 @@
name: "Rubl"
sourceurl: https://github.com/nspcc-dev/neo-go/
supportedstandards: ["NEP-17"]
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"]
events:

View file

@ -18,8 +18,9 @@ import (
// +------------+-----------+------------------------------------------------------------+
// | Magic | 4 bytes | Magic header |
// | Compiler | 64 bytes | Compiler used and it's version |
// | Source | Var bytes | Source file URL. |
// +------------+-----------+------------------------------------------------------------+
// | Reserved | 2-bytes | Reserved for extensions. Must be 0. |
// | Reserved | 1 byte | Reserved for extensions. Must be 0. |
// | Tokens | Var array | List of method tokens |
// | Reserved | 2-bytes | Reserved for extensions. Must be 0. |
// | Script | Var bytes | Var bytes for the payload |
@ -32,6 +33,8 @@ const (
Magic uint32 = 0x3346454E
// MaxScriptLength is the maximum allowed contract script length.
MaxScriptLength = 512 * 1024
// MaxSourceURLLength is the maximum allowed source URL length.
MaxSourceURLLength = 256
// compilerFieldSize is the length of `Compiler` File header field in bytes.
compilerFieldSize = 64
)
@ -39,6 +42,7 @@ const (
// File represents compiled contract file structure according to the NEF3 standard.
type File struct {
Header
Source string `json:"source"`
Tokens []MethodToken `json:"tokens"`
Script []byte `json:"script"`
Checksum uint32 `json:"checksum"`
@ -106,7 +110,12 @@ func (n *File) CalculateChecksum() uint32 {
// EncodeBinary implements io.Serializable interface.
func (n *File) EncodeBinary(w *io.BinWriter) {
n.Header.EncodeBinary(w)
w.WriteU16LE(0)
if len(n.Source) > MaxSourceURLLength {
w.Err = errors.New("source url too long")
return
}
w.WriteString(n.Source)
w.WriteB(0)
w.WriteArray(n.Tokens)
w.WriteU16LE(0)
w.WriteVarBytes(n.Script)
@ -118,13 +127,14 @@ var errInvalidReserved = errors.New("reserved bytes must be 0")
// DecodeBinary implements io.Serializable interface.
func (n *File) DecodeBinary(r *io.BinReader) {
n.Header.DecodeBinary(r)
reserved := r.ReadU16LE()
if r.Err == nil && reserved != 0 {
n.Source = r.ReadString(MaxSourceURLLength)
reservedB := r.ReadB()
if r.Err == nil && reservedB != 0 {
r.Err = errInvalidReserved
return
}
r.ReadArray(&n.Tokens)
reserved = r.ReadU16LE()
reserved := r.ReadU16LE()
if r.Err == nil && reserved != 0 {
r.Err = errInvalidReserved
return

View file

@ -149,6 +149,7 @@ func TestMarshalUnmarshalJSON(t *testing.T) {
require.JSONEq(t, `{
"magic":`+strconv.FormatUint(uint64(Magic), 10)+`,
"compiler": "test.compiler-test.ver",
"source": "",
"tokens": [
{
"hash": "0x`+expected.Tokens[0].Hash.StringLE()+`",