Merge pull request #2213 from nspcc-dev/deploy-scope
cli/smartcontract: allow to deploy contracts with scope
This commit is contained in:
commit
40dfca3eda
3 changed files with 102 additions and 38 deletions
|
@ -164,6 +164,16 @@ func ParseParams(args []string, calledFromMain bool) (int, []smartcontract.Param
|
||||||
default:
|
default:
|
||||||
param, err := smartcontract.NewParameterFromString(s)
|
param, err := smartcontract.NewParameterFromString(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// '--' argument is skipped by urfave/cli library, which leads
|
||||||
|
// to [--, addr:scope] being transformed to [addr:scope] and
|
||||||
|
// interpreted as a parameter if other positional arguments are not present.
|
||||||
|
// Here we fallback to parsing cosigners in this specific case to
|
||||||
|
// create a better user experience ('-- addr:scope' vs '-- -- addr:scope').
|
||||||
|
if k == 0 {
|
||||||
|
if _, err := parseCosigner(s); err == nil {
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0, nil, fmt.Errorf("failed to parse argument #%d: %w", k+1, err)
|
return 0, nil, fmt.Errorf("failed to parse argument #%d: %w", k+1, err)
|
||||||
}
|
}
|
||||||
res = append(res, *param)
|
res = append(res, *param)
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
|
@ -157,6 +158,83 @@ func TestDeployBigContract(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContractDeployWithData(t *testing.T) {
|
func TestContractDeployWithData(t *testing.T) {
|
||||||
|
eCompile := newExecutor(t, false)
|
||||||
|
|
||||||
|
// For proper nef generation.
|
||||||
|
config.Version = "0.90.0-test"
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
|
nefName := path.Join(tmpDir, "deploy.nef")
|
||||||
|
manifestName := path.Join(tmpDir, "deploy.manifest.json")
|
||||||
|
eCompile.Run(t, "neo-go", "contract", "compile",
|
||||||
|
"--in", "testdata/deploy/main.go", // compile single file
|
||||||
|
"--config", "testdata/deploy/neo-go.yml",
|
||||||
|
"--out", nefName, "--manifest", manifestName)
|
||||||
|
|
||||||
|
deployContract := func(t *testing.T, haveData bool, scope string) {
|
||||||
|
e := newExecutor(t, true)
|
||||||
|
cmd := []string{
|
||||||
|
"neo-go", "contract", "deploy",
|
||||||
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
|
"--in", nefName, "--manifest", manifestName,
|
||||||
|
"--force",
|
||||||
|
}
|
||||||
|
|
||||||
|
if haveData {
|
||||||
|
cmd = append(cmd, "[", "key1", "12", "key2", "take_me_to_church", "]")
|
||||||
|
}
|
||||||
|
if scope != "" {
|
||||||
|
cmd = append(cmd, "--", validatorAddr+":"+scope)
|
||||||
|
} else {
|
||||||
|
scope = "CalledByEntry"
|
||||||
|
}
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, cmd...)
|
||||||
|
|
||||||
|
tx, _ := e.checkTxPersisted(t, "Sent invocation transaction ")
|
||||||
|
require.Equal(t, scope, tx.Signers[0].Scopes.String())
|
||||||
|
if !haveData {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
line, err := e.Out.ReadString('\n')
|
||||||
|
require.NoError(t, err)
|
||||||
|
line = strings.TrimSpace(strings.TrimPrefix(line, "Contract: "))
|
||||||
|
h, err := util.Uint160DecodeStringLE(line)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
h.StringLE(),
|
||||||
|
"getValueWithKey", "key1",
|
||||||
|
)
|
||||||
|
|
||||||
|
res := new(result.Invoke)
|
||||||
|
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||||
|
require.Equal(t, vm.HaltState.String(), res.State, res.FaultException)
|
||||||
|
require.Len(t, res.Stack, 1)
|
||||||
|
require.Equal(t, []byte{12}, res.Stack[0].Value())
|
||||||
|
|
||||||
|
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
h.StringLE(),
|
||||||
|
"getValueWithKey", "key2",
|
||||||
|
)
|
||||||
|
|
||||||
|
res = new(result.Invoke)
|
||||||
|
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||||
|
require.Equal(t, vm.HaltState.String(), res.State, res.FaultException)
|
||||||
|
require.Len(t, res.Stack, 1)
|
||||||
|
require.Equal(t, []byte("take_me_to_church"), res.Stack[0].Value())
|
||||||
|
}
|
||||||
|
|
||||||
|
deployContract(t, true, "")
|
||||||
|
deployContract(t, false, "Global")
|
||||||
|
deployContract(t, true, "Global")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeployWithSigners(t *testing.T) {
|
||||||
e := newExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
|
|
||||||
// For proper nef generation.
|
// For proper nef generation.
|
||||||
|
@ -166,7 +244,7 @@ func TestContractDeployWithData(t *testing.T) {
|
||||||
nefName := path.Join(tmpDir, "deploy.nef")
|
nefName := path.Join(tmpDir, "deploy.nef")
|
||||||
manifestName := path.Join(tmpDir, "deploy.manifest.json")
|
manifestName := path.Join(tmpDir, "deploy.manifest.json")
|
||||||
e.Run(t, "neo-go", "contract", "compile",
|
e.Run(t, "neo-go", "contract", "compile",
|
||||||
"--in", "testdata/deploy/main.go", // compile single file
|
"--in", "testdata/deploy/main.go",
|
||||||
"--config", "testdata/deploy/neo-go.yml",
|
"--config", "testdata/deploy/neo-go.yml",
|
||||||
"--out", nefName, "--manifest", manifestName)
|
"--out", nefName, "--manifest", manifestName)
|
||||||
|
|
||||||
|
@ -176,38 +254,9 @@ func TestContractDeployWithData(t *testing.T) {
|
||||||
"--wallet", validatorWallet, "--address", validatorAddr,
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
"--in", nefName, "--manifest", manifestName,
|
"--in", nefName, "--manifest", manifestName,
|
||||||
"--force",
|
"--force",
|
||||||
"[", "key1", "12", "key2", "take_me_to_church", "]")
|
"--", validatorAddr+":Global")
|
||||||
|
tx, _ := e.checkTxPersisted(t, "Sent invocation transaction ")
|
||||||
e.checkTxPersisted(t, "Sent invocation transaction ")
|
require.Equal(t, transaction.Global, tx.Signers[0].Scopes)
|
||||||
line, err := e.Out.ReadString('\n')
|
|
||||||
require.NoError(t, err)
|
|
||||||
line = strings.TrimSpace(strings.TrimPrefix(line, "Contract: "))
|
|
||||||
h, err := util.Uint160DecodeStringLE(line)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
|
||||||
h.StringLE(),
|
|
||||||
"getValueWithKey", "key1",
|
|
||||||
)
|
|
||||||
|
|
||||||
res := new(result.Invoke)
|
|
||||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
|
||||||
require.Equal(t, vm.HaltState.String(), res.State, res.FaultException)
|
|
||||||
require.Len(t, res.Stack, 1)
|
|
||||||
require.Equal(t, []byte{12}, res.Stack[0].Value())
|
|
||||||
|
|
||||||
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
|
||||||
h.StringLE(),
|
|
||||||
"getValueWithKey", "key2",
|
|
||||||
)
|
|
||||||
|
|
||||||
res = new(result.Invoke)
|
|
||||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
|
||||||
require.Equal(t, vm.HaltState.String(), res.State, res.FaultException)
|
|
||||||
require.Len(t, res.Stack, 1)
|
|
||||||
require.Equal(t, []byte("take_me_to_church"), res.Stack[0].Value())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContractManifestGroups(t *testing.T) {
|
func TestContractManifestGroups(t *testing.T) {
|
||||||
|
|
|
@ -843,7 +843,7 @@ func contractDeploy(ctx *cli.Context) error {
|
||||||
Value: manifestBytes,
|
Value: manifestBytes,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, data, err := cmdargs.ParseParams(ctx.Args(), true)
|
signOffset, data, err := cmdargs.ParseParams(ctx.Args(), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("unable to parse 'data' parameter: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("unable to parse 'data' parameter: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
@ -872,10 +872,15 @@ func contractDeploy(ctx *cli.Context) error {
|
||||||
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
cosigners := []transaction.Signer{{
|
cosigners, sgnErr := cmdargs.GetSignersFromContext(ctx, signOffset)
|
||||||
Account: acc.Contract.ScriptHash(),
|
if sgnErr != nil {
|
||||||
Scopes: transaction.CalledByEntry,
|
return err
|
||||||
}}
|
} else if len(cosigners) == 0 {
|
||||||
|
cosigners = []transaction.Signer{{
|
||||||
|
Account: acc.Contract.ScriptHash(),
|
||||||
|
Scopes: transaction.CalledByEntry,
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
sender, extErr := invokeWithArgs(ctx, acc, w, mgmtHash, "deploy", appCallParams, cosigners)
|
sender, extErr := invokeWithArgs(ctx, acc, w, mgmtHash, "deploy", appCallParams, cosigners)
|
||||||
if extErr != nil {
|
if extErr != nil {
|
||||||
|
|
Loading…
Reference in a new issue