-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
- Loading branch information
1 parent
8cb5a76
commit 124fda7
Showing
11 changed files
with
4,393 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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} | ||
} |
Oops, something went wrong.