Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
  • Loading branch information
cthulhu-rider committed May 15, 2023
1 parent 8cb5a76 commit 947a3e9
Show file tree
Hide file tree
Showing 4 changed files with 2,599 additions and 0 deletions.
122 changes: 122 additions & 0 deletions contracts/contracts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package contracts

import (
"embed"
"encoding/json"
"errors"
"fmt"
"io/fs"
"strconv"
"strings"

"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
)

type Contract struct {
NEF nef.File
Manifest manifest.Manifest
}

type Contracts struct {
NNS Contract
Alphabet Contract
Others []Contract
}

//go:embed *-contract.nef *-contract.manifest.json
var _fs embed.FS

func Get() (Contracts, error) {
return get(_fs)
}

const fileSuffixNEF = "-contract.nef"

func get(_fs fs.FS) (Contracts, error) {
var res Contracts

const nnsPrefix = "nns"
err := readContractFromFilesWithPrefix(&res.NNS, _fs, nnsPrefix)
if err != nil {
return res, fmt.Errorf("read NNS contract: %w", err)
}

const alphabetPrefix = "alphabet"
err = readContractFromFilesWithPrefix(&res.Alphabet, _fs, alphabetPrefix)
if err != nil {
return res, fmt.Errorf("read Alphabet contract: %w", err)
}

nefFiles, err := fs.Glob(_fs, "*"+fileSuffixNEF)
if err != nil {
return res, fmt.Errorf("match files with suffix %s", fileSuffixNEF)
}

mOrdered := make(map[int]Contract, len(nefFiles))

for i := range nefFiles {
prefix := strings.TrimSuffix(nefFiles[i], fileSuffixNEF)
if prefix == nnsPrefix || prefix == alphabetPrefix {
continue
}

index, err := strconv.Atoi(prefix)
if err != nil {
return res, fmt.Errorf("invalid prefix of file '%s', expected index number", nefFiles[i])
}

var c Contract

err = readContractFromFilesWithPrefix(&c, _fs, prefix)
if err != nil {
return res, fmt.Errorf("read contract #%d: %w", index, err)
}

mOrdered[index] = c
}

if len(mOrdered) == 0 {
return res, errors.New("missing indexed contracts")
}

res.Others = make([]Contract, len(mOrdered))
var ok bool

for i := range res.Others {
res.Others[i], ok = mOrdered[i]
if !ok {
return res, fmt.Errorf("missing index number %d", i)
}
}

return res, nil
}

func readContractFromFilesWithPrefix(c *Contract, _fs fs.FS, filePrefix string) error {
fNEF, err := _fs.Open(filePrefix + fileSuffixNEF)
if err != nil {
return fmt.Errorf("open file containing contract NEF: %w", err)
}
defer fNEF.Close()

fManifest, err := _fs.Open(filePrefix + "-contract.manifest.json")
if err != nil {
return fmt.Errorf("open file containing contract NEF: %w", err)
}
defer fManifest.Close()

bReader := io.NewBinReaderFromIO(fNEF)
c.NEF.DecodeBinary(bReader)
if bReader.Err != nil {
return fmt.Errorf("decode contract NEF from binary: %w", bReader.Err)
}

err = json.NewDecoder(fManifest).Decode(&c.Manifest)
if err != nil {
return fmt.Errorf("decode contract manifest from JSON")
}

return nil
}
124 changes: 124 additions & 0 deletions contracts/contracts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package contracts

import (
"encoding/json"
"fmt"
"io/fs"
"testing"
"testing/fstest"

"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/stretchr/testify/require"
)

func TestGetDir(t *testing.T) {
cs, err := Get()
require.NoError(t, err)

// names are taken from neofs-contract repository
require.Equal(t, "NameService", cs.NNS.Manifest.Name)
require.Equal(t, "NeoFS Alphabet", cs.Alphabet.Manifest.Name)
require.Len(t, cs.Others, 2)
require.Equal(t, "NeoFS Audit", cs.Others[0].Manifest.Name)
require.Equal(t, "NeoFS Balance", cs.Others[1].Manifest.Name)
}

func TestGet(t *testing.T) {
_fs := fstest.MapFS{}

// missing or invalid NNS
_, err := get(_fs)
require.ErrorIs(t, err, fs.ErrNotExist)

setInvalidContractFiles(t, _fs, "nns")
_, err = get(_fs)
require.Error(t, err)

// add NNS
nnsContract := setValidContractFiles(t, _fs, "nns")

// missing or invalid Alphabet
_, err = get(_fs)
require.ErrorIs(t, err, fs.ErrNotExist)

setInvalidContractFiles(t, _fs, "alphabet")
_, err = get(_fs)
require.Error(t, err)

alphabetContract := setValidContractFiles(t, _fs, "alphabet")

// missing or invalid indexed contracts
_, err = get(_fs)
require.Error(t, err)

_fs["any-contract.nef"] = &fstest.MapFile{Data: []byte("any script")}

_, err = get(_fs)
require.Error(t, err)

delete(_fs, "any-contract.nef")

// add indexed contracts
setInvalidContractFiles(t, _fs, "0")
_, err = get(_fs)
require.Error(t, err)

firstContract := setValidContractFiles(t, _fs, "0")

_, err = get(_fs)
require.NoError(t, err)

// add hole
thirdContract := setValidContractFiles(t, _fs, "2")
_, err = get(_fs)
require.Error(t, err)

// fill hole
secondContract := setValidContractFiles(t, _fs, "1")
c, err := get(_fs)
require.NoError(t, err)

// check correctness
require.Equal(t, c.NNS, nnsContract)
require.Equal(t, c.Alphabet, alphabetContract)
require.Len(t, c.Others, 3)
require.Equal(t, c.Others[0], firstContract)
require.Equal(t, c.Others[1], secondContract)
require.Equal(t, c.Others[2], thirdContract)
}

func setValidContractFiles(tb testing.TB, _fs fstest.MapFS, prefix string) Contract {
_setContractFiles(tb, _fs, prefix, true)

var c Contract

err := readContractFromFilesWithPrefix(&c, _fs, prefix)
require.NoError(tb, err)

return c
}

func setInvalidContractFiles(tb testing.TB, _fs fstest.MapFS, prefix string) {
_setContractFiles(tb, _fs, prefix, false)
}

func _setContractFiles(tb testing.TB, _fs fstest.MapFS, prefix string, valid bool) {
var bNEF, jManifest []byte
if valid {
_nef, err := nef.NewFile([]byte(fmt.Sprintf("any %s script", prefix)))
require.NoError(tb, err)

bNEF, err = _nef.Bytes()
require.NoError(tb, err)

jManifest, err = json.Marshal(manifest.NewManifest(prefix + " contract"))
require.NoError(tb, err)
} else {
bNEF = []byte("invalid NEF")
jManifest = []byte("invalid manifest")
}

_fs[prefix+"-contract.nef"] = &fstest.MapFile{Data: bNEF}
_fs[prefix+"-contract.manifest.json"] = &fstest.MapFile{Data: jManifest}
}
Loading

0 comments on commit 947a3e9

Please sign in to comment.