cli, compiler: switch from .avm to .nef
We don't generate clear .avm instructions anymore. Instead, use .nef files with additional metadata.
This commit is contained in:
parent
6b8957243a
commit
c7746da023
6 changed files with 67 additions and 33 deletions
|
@ -16,12 +16,12 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/cli/options"
|
||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpc/request"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
|
@ -73,14 +73,14 @@ func NewCommands() []cli.Command {
|
|||
testInvokeScriptFlags := []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "in, i",
|
||||
Usage: "Input location of the avm file that needs to be invoked",
|
||||
Usage: "Input location of the .nef file that needs to be invoked",
|
||||
},
|
||||
}
|
||||
testInvokeScriptFlags = append(testInvokeScriptFlags, options.RPC...)
|
||||
deployFlags := []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "in, i",
|
||||
Usage: "Input file for the smart contract (*.avm)",
|
||||
Usage: "Input file for the smart contract (*.nef)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "config, c",
|
||||
|
@ -103,7 +103,7 @@ func NewCommands() []cli.Command {
|
|||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "compile",
|
||||
Usage: "compile a smart contract to a .avm file",
|
||||
Usage: "compile a smart contract to a .nef file",
|
||||
Action: contractCompile,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
|
@ -134,7 +134,7 @@ func NewCommands() []cli.Command {
|
|||
},
|
||||
{
|
||||
Name: "deploy",
|
||||
Usage: "deploy a smart contract (.avm with description)",
|
||||
Usage: "deploy a smart contract (.nef with description)",
|
||||
Description: `Deploys given contract into the chain. The gas parameter is for additional
|
||||
gas to be added as a network fee to prioritize the transaction. It may also
|
||||
be required to add that to satisfy chain's policy regarding transaction size
|
||||
|
@ -254,9 +254,9 @@ func NewCommands() []cli.Command {
|
|||
},
|
||||
{
|
||||
Name: "testinvokescript",
|
||||
Usage: "Invoke compiled AVM code on the blockchain (test mode, not creating a transaction for it)",
|
||||
UsageText: "neo-go contract testinvokescript -r endpoint -i input.avm [cosigners...]",
|
||||
Description: `Executes given compiled AVM instructions with the given set of
|
||||
Usage: "Invoke compiled AVM code in NEF format on the blockchain (test mode, not creating a transaction for it)",
|
||||
UsageText: "neo-go contract testinvokescript -r endpoint -i input.nef [cosigners...]",
|
||||
Description: `Executes given compiled AVM instructions in NEF format with the given set of
|
||||
cosigners. See testinvokefunction documentation for the details about parameters.
|
||||
`,
|
||||
Action: testInvokeScript,
|
||||
|
@ -288,7 +288,7 @@ func NewCommands() []cli.Command {
|
|||
},
|
||||
cli.StringFlag{
|
||||
Name: "in, i",
|
||||
Usage: "input file of the program",
|
||||
Usage: "input file of the program (either .go or .nef)",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -492,6 +492,10 @@ func testInvokeScript(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
nefFile, err := nef.FileFromBytes(b)
|
||||
if err != nil {
|
||||
return cli.NewExitError(errors.Wrapf(err, "failed to restore .nef file"), 1)
|
||||
}
|
||||
|
||||
args := ctx.Args()
|
||||
var cosigners []transaction.Cosigner
|
||||
|
@ -513,7 +517,7 @@ func testInvokeScript(ctx *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
scriptHex := hex.EncodeToString(b)
|
||||
scriptHex := hex.EncodeToString(nefFile.Script)
|
||||
resp, err := c.InvokeScript(scriptHex, cosigners)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
|
@ -551,11 +555,10 @@ func (p *ProjectConfig) GetFeatures() smartcontract.PropertyState {
|
|||
}
|
||||
|
||||
// ToManifest converts project config to the manifest.
|
||||
func (p *ProjectConfig) ToManifest(script []byte) *manifest.Manifest {
|
||||
h := hash.Hash160(script)
|
||||
m := manifest.NewManifest(h)
|
||||
func (p *ProjectConfig) ToManifest(file nef.File) *manifest.Manifest {
|
||||
m := manifest.NewManifest(file.Header.ScriptHash)
|
||||
m.Features = p.GetFeatures()
|
||||
m.ABI.Hash = h
|
||||
m.ABI.Hash = file.Header.ScriptHash
|
||||
m.ABI.EntryPoint = p.EntryPoint
|
||||
m.ABI.Methods = p.Methods
|
||||
m.ABI.Events = p.Events
|
||||
|
@ -577,6 +580,12 @@ func inspect(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
return cli.NewExitError(errors.Wrap(err, "failed to compile"), 1)
|
||||
}
|
||||
} else {
|
||||
nefFile, err := nef.FileFromBytes(b)
|
||||
if err != nil {
|
||||
return cli.NewExitError(errors.Wrapf(err, "failed to restore .nef file"), 1)
|
||||
}
|
||||
b = nefFile.Script
|
||||
}
|
||||
v := vm.New()
|
||||
v.LoadScript(b)
|
||||
|
@ -638,10 +647,14 @@ func contractDeploy(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
avm, err := ioutil.ReadFile(in)
|
||||
f, err := ioutil.ReadFile(in)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
nefFile, err := nef.FileFromBytes(f)
|
||||
if err != nil {
|
||||
return cli.NewExitError(errors.Wrapf(err, "failed to restore .nef file"), 1)
|
||||
}
|
||||
conf, err := parseContractConfig(confFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -655,8 +668,8 @@ func contractDeploy(ctx *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
m := conf.ToManifest(avm)
|
||||
txScript, sysfee, err := request.CreateDeploymentScript(avm, m)
|
||||
m := conf.ToManifest(nefFile)
|
||||
txScript, sysfee, err := request.CreateDeploymentScript(nefFile.Script, m)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to create deployment script: %v", err), 1)
|
||||
}
|
||||
|
@ -665,7 +678,7 @@ func contractDeploy(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %v", err), 1)
|
||||
}
|
||||
fmt.Printf("Sent deployment transaction %s for contract %s\n", txHash.StringLE(), hash.Hash160(avm).StringLE())
|
||||
fmt.Printf("Sent deployment transaction %s for contract %s\n", txHash.StringLE(), nefFile.Header.ScriptHash.StringLE())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -104,11 +104,11 @@ In case you don't want to provide details use `--skip-details, -skip`.
|
|||
./bin/neo-go contract compile -i mycontract.go
|
||||
```
|
||||
|
||||
By default the output filename will be the name of your `.go` file with the `.avm` extension, the file will be located
|
||||
By default the output filename will be the name of your `.go` file with the `.nef` extension, the file will be located
|
||||
in the same directory where you called the command from. If you want another location for your compiled contract:
|
||||
|
||||
```
|
||||
./bin/neo-go contract compile -i mycontract.go --out /Users/foo/bar/contract.avm
|
||||
./bin/neo-go contract compile -i mycontract.go --out /Users/foo/bar/contract.nef
|
||||
```
|
||||
|
||||
### Deploy
|
||||
|
@ -118,7 +118,7 @@ in the same directory where you called the command from. If you want another loc
|
|||
//Implemented in test mode. It means that it won't affect the blockchain
|
||||
|
||||
```
|
||||
./bin/neo-go contract testinvoke -i mycontract.avm
|
||||
./bin/neo-go contract testinvoke -i mycontract.nef
|
||||
```
|
||||
|
||||
### Debug
|
||||
|
|
|
@ -37,17 +37,17 @@ functionality as Neo .net Framework library.
|
|||
./bin/neo-go contract compile -i mycontract.go
|
||||
```
|
||||
|
||||
By default the filename will be the name of your .go file with the .avm extension, the file will be located in the same directory where your Go contract is. If you want another location for your compiled contract:
|
||||
By default the filename will be the name of your .go file with the .nef extension, the file will be located in the same directory where your Go contract is. If you want another location for your compiled contract:
|
||||
|
||||
```
|
||||
./bin/neo-go contract compile -i mycontract.go --out /Users/foo/bar/contract.avm
|
||||
./bin/neo-go contract compile -i mycontract.go --out /Users/foo/bar/contract.nef
|
||||
```
|
||||
|
||||
### Debugging
|
||||
You can dump the opcodes generated by the compiler with the following command:
|
||||
|
||||
```
|
||||
./bin/neo-go contract inspect -i mycontract.go
|
||||
./bin/neo-go contract inspect -i mycontract.go -c
|
||||
```
|
||||
|
||||
This will result in something like this:
|
||||
|
@ -116,7 +116,7 @@ Toolkit](https://github.com/neo-project/neo-blockchain-toolkit/). To do that
|
|||
you need to generate debug information using `--debug` option, like this:
|
||||
|
||||
```
|
||||
$ ./bin/neo-go contract compile -i contract.go -o contract.avm --debug contract.debug.json
|
||||
$ ./bin/neo-go contract compile -i contract.go -o contract.nef --debug contract.debug.json
|
||||
```
|
||||
|
||||
This file can then be used by debugger and set up to work just like for any
|
||||
|
@ -144,7 +144,7 @@ project:
|
|||
It's passed to the `deploy` command via `-c` option:
|
||||
|
||||
```
|
||||
$ ./bin/neo-go contract deploy -i contract.avm -c contract.yml -r http://localhost:20331 -w wallet.json -g 0.001
|
||||
$ ./bin/neo-go contract deploy -i contract.nef -c contract.yml -r http://localhost:20331 -w wallet.json -g 0.001
|
||||
```
|
||||
|
||||
Deployment works via an RPC server, an address of which is passed via `-r`
|
||||
|
@ -163,7 +163,7 @@ deployment with neo-go. It's done in the same step with compilation via
|
|||
support the command line will look like this:
|
||||
|
||||
```
|
||||
$ ./bin/neo-go contract compile -i contract.go --config contract.yml -o contract.avm --debug contract.debug.json --abi contract.abi.json
|
||||
$ ./bin/neo-go contract compile -i contract.go --config contract.yml -o contract.nef --debug contract.debug.json --abi contract.abi.json
|
||||
```
|
||||
|
||||
This file can then be used by toolkit to deploy contract the same way
|
||||
|
|
|
@ -12,14 +12,15 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||
"golang.org/x/tools/go/loader"
|
||||
)
|
||||
|
||||
const fileExt = "avm"
|
||||
const fileExt = "nef"
|
||||
|
||||
// Options contains all the parameters that affect the behaviour of the compiler.
|
||||
type Options struct {
|
||||
// The extension of the output file default set to .avm
|
||||
// The extension of the output file default set to .nef
|
||||
Ext string
|
||||
|
||||
// The name of the output file.
|
||||
|
@ -78,7 +79,7 @@ func CompileWithDebugInfo(r io.Reader) ([]byte, *DebugInfo, error) {
|
|||
return CodeGen(ctx)
|
||||
}
|
||||
|
||||
// CompileAndSave will compile and save the file to disk.
|
||||
// CompileAndSave will compile and save the file to disk in the NEF format.
|
||||
func CompileAndSave(src string, o *Options) ([]byte, error) {
|
||||
if !strings.HasSuffix(src, ".go") {
|
||||
return nil, fmt.Errorf("%s is not a Go file", src)
|
||||
|
@ -98,8 +99,16 @@ func CompileAndSave(src string, o *Options) ([]byte, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("error while trying to compile smart contract file: %v", err)
|
||||
}
|
||||
f, err := nef.NewFile(b)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while trying to create .nef file: %v", err)
|
||||
}
|
||||
bytes, err := f.Bytes()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while serializing .nef file: %v", err)
|
||||
}
|
||||
out := fmt.Sprintf("%s.%s", o.Outfile, o.Ext)
|
||||
err = ioutil.WriteFile(out, b, os.ModePerm)
|
||||
err = ioutil.WriteFile(out, bytes, os.ModePerm)
|
||||
if o.DebugInfo == "" {
|
||||
return b, err
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -20,6 +21,8 @@ type compilerTestCase struct {
|
|||
}
|
||||
|
||||
func TestCompiler(t *testing.T) {
|
||||
// CompileAndSave use config.Version for proper .nef generation.
|
||||
config.Version = "0.90.0-test"
|
||||
testCases := []compilerTestCase{
|
||||
{
|
||||
name: "TestCompile",
|
||||
|
@ -44,7 +47,7 @@ func TestCompiler(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
err = os.MkdirAll(exampleSavePath, os.ModePerm)
|
||||
require.NoError(t, err)
|
||||
outfile := exampleSavePath + "/test.avm"
|
||||
outfile := exampleSavePath + "/test.nef"
|
||||
_, err = compiler.CompileAndSave(exampleCompilePath+"/"+infos[0].Name(), &compiler.Options{Outfile: outfile})
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
|
|
|
@ -145,7 +145,16 @@ func methodStruct() struct{} { return struct{}{} }
|
|||
},
|
||||
Events: []Event{},
|
||||
}
|
||||
assert.Equal(t, expected, actual)
|
||||
require.True(t, expected.ABI.Hash.Equals(actual.ABI.Hash))
|
||||
require.ElementsMatch(t, expected.ABI.Methods, actual.ABI.Methods)
|
||||
require.Equal(t, expected.ABI.EntryPoint, actual.ABI.EntryPoint)
|
||||
require.Equal(t, expected.ABI.Events, actual.ABI.Events)
|
||||
require.Equal(t, expected.Groups, actual.Groups)
|
||||
require.Equal(t, expected.Features, actual.Features)
|
||||
require.Equal(t, expected.Permissions, actual.Permissions)
|
||||
require.Equal(t, expected.Trusts, actual.Trusts)
|
||||
require.Equal(t, expected.SafeMethods, actual.SafeMethods)
|
||||
require.Equal(t, expected.Extra, actual.Extra)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue