Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cli: add --no-nef-check option to contract compile command
Browse files Browse the repository at this point in the history
This option allows to skip the generated NEF file size check on contract
compilation. The resulting .nef file can't be deployed to the chain and is
invalid according to the updated verification rules, but it still may be
useful either for previous node versions or for development/debugging
purposes.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
AnnaShaleva committed Nov 20, 2023
1 parent dd3da28 commit 6ff0aa8
Showing 4 changed files with 51 additions and 2 deletions.
31 changes: 31 additions & 0 deletions cli/smartcontract/contract_test.go
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strconv"
@@ -304,6 +305,36 @@ func TestContractInitAndCompile(t *testing.T) {
})
}

func TestContractCompile_NEFSizeCheck(t *testing.T) {
tmpDir := t.TempDir()
e := testcli.NewExecutor(t, false)

src := `package nefconstraints
var data = "%s"
func Main() string {
return data
}`
data := make([]byte, stackitem.MaxSize-10)
for i := range data {
data[i] = byte('a')
}

in := filepath.Join(tmpDir, "main.go")
cfg := filepath.Join(tmpDir, "main.yml")
require.NoError(t, os.WriteFile(cfg, []byte("name: main"), os.ModePerm))
require.NoError(t, os.WriteFile(in, []byte(fmt.Sprintf(src, data)), os.ModePerm))

t.Run("perform size check", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "compile", "--in", in)
require.NoFileExists(t, filepath.Join(tmpDir, "main.nef"))
})
t.Run("skip size check", func(t *testing.T) {
e.Run(t, "neo-go", "contract", "compile", "--in", in, "--no-nef-check")
require.FileExists(t, filepath.Join(tmpDir, "main.nef"))
})
}

// Checks that error is returned if GAS available for test-invoke exceeds
// GAS needed to be consumed.
func TestDeployBigContract(t *testing.T) {
7 changes: 6 additions & 1 deletion cli/smartcontract/smart_contract.go
Original file line number Diff line number Diff line change
@@ -126,7 +126,7 @@ func NewCommands() []cli.Command {
{
Name: "compile",
Usage: "compile a smart contract to a .nef file",
UsageText: "neo-go contract compile -i path [-o nef] [-v] [-d] [-m manifest] [-c yaml] [--bindings file] [--no-standards] [--no-events] [--no-permissions] [--guess-eventtypes]",
UsageText: "neo-go contract compile -i path [-o nef] [-v] [-d] [-m manifest] [-c yaml] [--bindings file] [--no-standards] [--no-events] [--no-permissions] [--no-nef-check] [--guess-eventtypes]",
Description: `Compiles given smart contract to a .nef file and emits other associated
information (manifest, bindings configuration, debug information files) if
asked to. If none of --out, --manifest, --config, --bindings flags are specified,
@@ -172,6 +172,10 @@ func NewCommands() []cli.Command {
Name: "no-permissions",
Usage: "do not check if invoked contracts are allowed in manifest",
},
cli.BoolFlag{
Name: "no-nef-check",
Usage: "do not check if the resulting .nef size exceeds allowed limits; the resulting .nef file can't be deployed if exceeds stackitem.MaxSize limits",
},
cli.BoolFlag{
Name: "guess-eventtypes",
Usage: "guess event types for smart-contract bindings configuration from the code usages",
@@ -454,6 +458,7 @@ func contractCompile(ctx *cli.Context) error {
NoStandardCheck: ctx.Bool("no-standards"),
NoEventsCheck: ctx.Bool("no-events"),
NoPermissionsCheck: ctx.Bool("no-permissions"),
NoNEFSizeCheck: ctx.Bool("no-nef-check"),

GuessEventTypes: ctx.Bool("guess-eventtypes"),
}
9 changes: 9 additions & 0 deletions docs/compiler.md
Original file line number Diff line number Diff line change
@@ -352,6 +352,15 @@ Using either constant or literal for contract hash and method will allow the com
to perform more extensive analysis.
This check can be disabled with `--no-permissions` flag.

##### NEF file validation check

By default, compiler performs size restriction check over generated NEF file and
fails compilation if the resulting NEF file doesn't fit into `stackitem.MaxSize`
limit. However, it's still possible to disable this check and properly generate
large NEF files with `--no-nef-check` compiling option. Large NEF files can't
be deployed onto chain, but still may be used for development or debugging
purposes.

##### Overloads
NeoVM allows a contract to have multiple methods with the same name
but different parameters number. Go lacks this feature, but this can be circumvented
6 changes: 5 additions & 1 deletion pkg/compiler/compiler.go
Original file line number Diff line number Diff line change
@@ -53,6 +53,10 @@ type Options struct {
// This setting has effect only if manifest is emitted.
NoPermissionsCheck bool

// NoNEFSizeCheck allows to skip serialized NEF size check against max allowed
// stackitem size.
NoNEFSizeCheck bool

// GuessEventTypes specifies if types of runtime notifications need to be guessed
// from the usage context. These types are used for RPC binding generation only and
// can be defined for events with name known at the compilation time and without
@@ -276,7 +280,7 @@ func CompileAndSave(src string, o *Options) ([]byte, error) {
}()
f.Checksum = f.CalculateChecksum()
}
bytes, err := f.Bytes(true)
bytes, err := f.Bytes(!o.NoNEFSizeCheck)
if err != nil {
return nil, fmt.Errorf("error while serializing .nef file: %w", err)
}

0 comments on commit 6ff0aa8

Please sign in to comment.