parent
0a52c32df3
commit
42a9d3d7b8
20 changed files with 54 additions and 10 deletions
|
@ -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/"
|
const dir = "./testdata/"
|
||||||
for _, name := range []string{"invalid1", "invalid2", "invalid3"} {
|
for _, name := range []string{"invalid1", "invalid2", "invalid3", "invalid4"} {
|
||||||
outF := path.Join(tmpDir, name+".nef")
|
outF := path.Join(tmpDir, name+".nef")
|
||||||
manifestF := path.Join(tmpDir, name+".manifest.json")
|
manifestF := path.Join(tmpDir, name+".manifest.json")
|
||||||
e.RunWithError(t, "neo-go", "contract", "compile",
|
e.RunWithError(t, "neo-go", "contract", "compile",
|
||||||
|
|
|
@ -427,6 +427,7 @@ func initSmartContract(ctx *cli.Context) error {
|
||||||
|
|
||||||
m := ProjectConfig{
|
m := ProjectConfig{
|
||||||
Name: contractName,
|
Name: contractName,
|
||||||
|
SourceURL: "http://example.com/",
|
||||||
SupportedStandards: []string{},
|
SupportedStandards: []string{},
|
||||||
SafeMethods: []string{},
|
SafeMethods: []string{},
|
||||||
Events: []manifest.Event{
|
Events: []manifest.Event{
|
||||||
|
@ -489,6 +490,7 @@ func contractCompile(ctx *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
o.Name = conf.Name
|
o.Name = conf.Name
|
||||||
|
o.SourceURL = conf.SourceURL
|
||||||
o.ContractEvents = conf.Events
|
o.ContractEvents = conf.Events
|
||||||
o.ContractSupportedStandards = conf.SupportedStandards
|
o.ContractSupportedStandards = conf.SupportedStandards
|
||||||
o.Permissions = make([]manifest.Permission, len(conf.Permissions))
|
o.Permissions = make([]manifest.Permission, len(conf.Permissions))
|
||||||
|
@ -733,6 +735,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
|
||||||
|
SourceURL string
|
||||||
SafeMethods []string
|
SafeMethods []string
|
||||||
SupportedStandards []string
|
SupportedStandards []string
|
||||||
Events []manifest.Event
|
Events []manifest.Event
|
||||||
|
|
|
@ -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
|
||||||
|
sourceurl: http://example.com/
|
||||||
safemethods: []
|
safemethods: []
|
||||||
supportedstandards: []
|
supportedstandards: []
|
||||||
events:
|
events:
|
||||||
|
|
5
cli/testdata/invalid4/invalid.go
vendored
Normal file
5
cli/testdata/invalid4/invalid.go
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package invalid4
|
||||||
|
|
||||||
|
func Verify() bool {
|
||||||
|
return true
|
||||||
|
}
|
2
cli/testdata/invalid4/invalid.yml
vendored
Normal file
2
cli/testdata/invalid4/invalid.yml
vendored
Normal 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
|
|
@ -1,4 +1,5 @@
|
||||||
name: "Engine example"
|
name: "Engine example"
|
||||||
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
supportedstandards: []
|
supportedstandards: []
|
||||||
events:
|
events:
|
||||||
- name: Tx
|
- name: Tx
|
||||||
|
@ -16,4 +17,4 @@ events:
|
||||||
- name: Entry
|
- name: Entry
|
||||||
parameters:
|
parameters:
|
||||||
- name: hash
|
- name: hash
|
||||||
type: Hash160
|
type: Hash160
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
name: "Event types example"
|
name: "Event types example"
|
||||||
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
supportedstandards: []
|
supportedstandards: []
|
||||||
events:
|
events:
|
||||||
- name: SomeBytes
|
- name: SomeBytes
|
||||||
|
@ -20,4 +21,4 @@ events:
|
||||||
- name: SomeArray
|
- name: SomeArray
|
||||||
parameters:
|
parameters:
|
||||||
- name: a
|
- name: a
|
||||||
type: Array
|
type: Array
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
name: "Iterator example"
|
name: "Iterator example"
|
||||||
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
supportedstandards: []
|
supportedstandards: []
|
||||||
events:
|
events:
|
||||||
- name: found storage key-value pair
|
- name: found storage key-value pair
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
name: "NameService"
|
name: "NameService"
|
||||||
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
supportedstandards: ["NEP-11"]
|
supportedstandards: ["NEP-11"]
|
||||||
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf",
|
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf",
|
||||||
"tokens", "properties", "roots", "getPrice", "isAvailable", "getRecord",
|
"tokens", "properties", "roots", "getPrice", "isAvailable", "getRecord",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
name: "HASHY NFT"
|
name: "HASHY NFT"
|
||||||
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
supportedstandards: ["NEP-11"]
|
supportedstandards: ["NEP-11"]
|
||||||
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "tokens", "properties"]
|
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "tokens", "properties"]
|
||||||
events:
|
events:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
name: "Oracle example"
|
name: "Oracle example"
|
||||||
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
supportedstandards: []
|
supportedstandards: []
|
||||||
events:
|
events:
|
||||||
permissions:
|
permissions:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
name: "Runtime example"
|
name: "Runtime example"
|
||||||
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
supportedstandards: []
|
supportedstandards: []
|
||||||
events:
|
events:
|
||||||
- name: Event
|
- name: Event
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
name: "Storage example"
|
name: "Storage example"
|
||||||
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
supportedstandards: []
|
supportedstandards: []
|
||||||
events: []
|
events: []
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
name: "Timer example"
|
name: "Timer example"
|
||||||
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
supportedstandards: []
|
supportedstandards: []
|
||||||
events: []
|
events: []
|
||||||
permissions:
|
permissions:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
name: "My awesome token"
|
name: "My awesome token"
|
||||||
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
supportedstandards: ["NEP-17"]
|
supportedstandards: ["NEP-17"]
|
||||||
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"]
|
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"]
|
||||||
events:
|
events:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
name: "Awesome NEO Token"
|
name: "Awesome NEO Token"
|
||||||
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
supportedstandards: ["NEP-17"]
|
supportedstandards: ["NEP-17"]
|
||||||
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"]
|
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"]
|
||||||
events:
|
events:
|
||||||
|
|
|
@ -52,6 +52,9 @@ type Options struct {
|
||||||
// Name is contract's name to be written to manifest.
|
// Name is contract's name to be written to manifest.
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
|
// SourceURL is contract's source URL to be written to manifest.
|
||||||
|
SourceURL string
|
||||||
|
|
||||||
// Runtime notifications.
|
// Runtime notifications.
|
||||||
ContractEvents []manifest.Event
|
ContractEvents []manifest.Event
|
||||||
|
|
||||||
|
@ -199,6 +202,13 @@ func CompileAndSave(src string, o *Options) ([]byte, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error while trying to create .nef file: %w", err)
|
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()
|
bytes, err := f.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error while serializing .nef file: %w", err)
|
return nil, fmt.Errorf("error while serializing .nef file: %w", err)
|
||||||
|
|
3
pkg/rpc/server/testdata/test_contract.yml
vendored
3
pkg/rpc/server/testdata/test_contract.yml
vendored
|
@ -1,4 +1,5 @@
|
||||||
name: "Rubl"
|
name: "Rubl"
|
||||||
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
supportedstandards: ["NEP-17"]
|
supportedstandards: ["NEP-17"]
|
||||||
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"]
|
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"]
|
||||||
events:
|
events:
|
||||||
|
@ -13,4 +14,4 @@ events:
|
||||||
permissions:
|
permissions:
|
||||||
- hash: ef4073a0f2b305a38ec4050e4d3d28bc40ea63f5
|
- hash: ef4073a0f2b305a38ec4050e4d3d28bc40ea63f5
|
||||||
methods: ["transfer"]
|
methods: ["transfer"]
|
||||||
- methods: ["onNEP17Payment"]
|
- methods: ["onNEP17Payment"]
|
||||||
|
|
|
@ -18,8 +18,9 @@ import (
|
||||||
// +------------+-----------+------------------------------------------------------------+
|
// +------------+-----------+------------------------------------------------------------+
|
||||||
// | Magic | 4 bytes | Magic header |
|
// | Magic | 4 bytes | Magic header |
|
||||||
// | Compiler | 64 bytes | Compiler used and it's version |
|
// | 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 |
|
// | Tokens | Var array | List of method tokens |
|
||||||
// | Reserved | 2-bytes | Reserved for extensions. Must be 0. |
|
// | Reserved | 2-bytes | Reserved for extensions. Must be 0. |
|
||||||
// | Script | Var bytes | Var bytes for the payload |
|
// | Script | Var bytes | Var bytes for the payload |
|
||||||
|
@ -32,6 +33,8 @@ const (
|
||||||
Magic uint32 = 0x3346454E
|
Magic uint32 = 0x3346454E
|
||||||
// MaxScriptLength is the maximum allowed contract script length.
|
// MaxScriptLength is the maximum allowed contract script length.
|
||||||
MaxScriptLength = 512 * 1024
|
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 is the length of `Compiler` File header field in bytes.
|
||||||
compilerFieldSize = 64
|
compilerFieldSize = 64
|
||||||
)
|
)
|
||||||
|
@ -39,6 +42,7 @@ const (
|
||||||
// File represents compiled contract file structure according to the NEF3 standard.
|
// File represents compiled contract file structure according to the NEF3 standard.
|
||||||
type File struct {
|
type File struct {
|
||||||
Header
|
Header
|
||||||
|
Source string `json:"source"`
|
||||||
Tokens []MethodToken `json:"tokens"`
|
Tokens []MethodToken `json:"tokens"`
|
||||||
Script []byte `json:"script"`
|
Script []byte `json:"script"`
|
||||||
Checksum uint32 `json:"checksum"`
|
Checksum uint32 `json:"checksum"`
|
||||||
|
@ -106,7 +110,12 @@ func (n *File) CalculateChecksum() uint32 {
|
||||||
// EncodeBinary implements io.Serializable interface.
|
// EncodeBinary implements io.Serializable interface.
|
||||||
func (n *File) EncodeBinary(w *io.BinWriter) {
|
func (n *File) EncodeBinary(w *io.BinWriter) {
|
||||||
n.Header.EncodeBinary(w)
|
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.WriteArray(n.Tokens)
|
||||||
w.WriteU16LE(0)
|
w.WriteU16LE(0)
|
||||||
w.WriteVarBytes(n.Script)
|
w.WriteVarBytes(n.Script)
|
||||||
|
@ -118,13 +127,14 @@ var errInvalidReserved = errors.New("reserved bytes must be 0")
|
||||||
// DecodeBinary implements io.Serializable interface.
|
// DecodeBinary implements io.Serializable interface.
|
||||||
func (n *File) DecodeBinary(r *io.BinReader) {
|
func (n *File) DecodeBinary(r *io.BinReader) {
|
||||||
n.Header.DecodeBinary(r)
|
n.Header.DecodeBinary(r)
|
||||||
reserved := r.ReadU16LE()
|
n.Source = r.ReadString(MaxSourceURLLength)
|
||||||
if r.Err == nil && reserved != 0 {
|
reservedB := r.ReadB()
|
||||||
|
if r.Err == nil && reservedB != 0 {
|
||||||
r.Err = errInvalidReserved
|
r.Err = errInvalidReserved
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.ReadArray(&n.Tokens)
|
r.ReadArray(&n.Tokens)
|
||||||
reserved = r.ReadU16LE()
|
reserved := r.ReadU16LE()
|
||||||
if r.Err == nil && reserved != 0 {
|
if r.Err == nil && reserved != 0 {
|
||||||
r.Err = errInvalidReserved
|
r.Err = errInvalidReserved
|
||||||
return
|
return
|
||||||
|
|
|
@ -149,6 +149,7 @@ func TestMarshalUnmarshalJSON(t *testing.T) {
|
||||||
require.JSONEq(t, `{
|
require.JSONEq(t, `{
|
||||||
"magic":`+strconv.FormatUint(uint64(Magic), 10)+`,
|
"magic":`+strconv.FormatUint(uint64(Magic), 10)+`,
|
||||||
"compiler": "test.compiler-test.ver",
|
"compiler": "test.compiler-test.ver",
|
||||||
|
"source": "",
|
||||||
"tokens": [
|
"tokens": [
|
||||||
{
|
{
|
||||||
"hash": "0x`+expected.Tokens[0].Hash.StringLE()+`",
|
"hash": "0x`+expected.Tokens[0].Hash.StringLE()+`",
|
||||||
|
|
Loading…
Reference in a new issue