Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cli: allow to specify CustomContracts/Groups signer #1973

Merged
merged 1 commit into from
May 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions cli/cmdargs/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/nspcc-dev/neo-go/cli/flags"
"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/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/rpc/client"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
Expand Down Expand Up @@ -53,11 +54,52 @@ func parseCosigner(c string) (transaction.Signer, error) {
if err != nil {
return res, err
}
if len(data) > 1 {
res.Scopes, err = transaction.ScopesFromString(data[1])

if len(data) == 1 {
return res, nil
}

res.Scopes = 0
scopes := strings.Split(data[1], ",")
for _, s := range scopes {
sub := strings.Split(s, ":")
scope, err := transaction.ScopesFromString(sub[0])
if err != nil {
return transaction.Signer{}, err
}
if scope == transaction.Global && res.Scopes&^transaction.Global != 0 ||
scope != transaction.Global && res.Scopes&transaction.Global != 0 {
return transaction.Signer{}, errors.New("Global scope can not be combined with other scopes")
}

res.Scopes |= scope

switch scope {
case transaction.CustomContracts:
if len(sub) == 1 {
return transaction.Signer{}, errors.New("CustomContracts scope must refer to at least one contract")
}
for _, s := range sub[1:] {
addr, err := flags.ParseAddress(s)
if err != nil {
return transaction.Signer{}, err
}

res.AllowedContracts = append(res.AllowedContracts, addr)
}
case transaction.CustomGroups:
if len(sub) == 1 {
return transaction.Signer{}, errors.New("CustomGroups scope must refer to at least one group")
}
for _, s := range sub[1:] {
pub, err := keys.NewPublicKeyFromString(s)
if err != nil {
return transaction.Signer{}, err
}

res.AllowedGroups = append(res.AllowedGroups, pub)
}
}
}
return res, nil
}
Expand Down
28 changes: 23 additions & 5 deletions cli/cmdargs/parser_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
package cmdargs

import (
"encoding/hex"
"strings"
"testing"

"github.com/nspcc-dev/neo-go/internal/random"
"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/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/stretchr/testify/require"
)

func TestParseCosigner(t *testing.T) {
acc := util.Uint160{1, 3, 5, 7}
c1, c2 := random.Uint160(), random.Uint160()
priv, err := keys.NewPrivateKey()
require.NoError(t, err)

testCases := map[string]transaction.Signer{
acc.StringLE(): {
Account: acc,
Expand All @@ -33,25 +40,36 @@ func TestParseCosigner(t *testing.T) {
Account: acc,
Scopes: transaction.None,
},
acc.StringLE() + ":CalledByEntry,CustomContracts": {
Account: acc,
Scopes: transaction.CalledByEntry | transaction.CustomContracts,
acc.StringLE() + ":CalledByEntry,CustomContracts:" + c1.StringLE() + ":0x" + c2.StringLE(): {
Account: acc,
Scopes: transaction.CalledByEntry | transaction.CustomContracts,
AllowedContracts: []util.Uint160{c1, c2},
},
acc.StringLE() + ":CustomGroups:" + hex.EncodeToString(priv.PublicKey().Bytes()): {
Account: acc,
Scopes: transaction.CustomGroups,
AllowedGroups: keys.PublicKeys{priv.PublicKey()},
},
}
for s, expected := range testCases {
actual, err := parseCosigner(s)
require.NoError(t, err)
require.Equal(t, expected, actual)
require.Equal(t, expected, actual, s)
}
errorCases := []string{
acc.StringLE() + "0",
acc.StringLE() + ":Unknown",
acc.StringLE() + ":Global,CustomContracts",
acc.StringLE() + ":Global,None",
acc.StringLE() + ":CustomContracts:" + acc.StringLE() + ",Global",
acc.StringLE() + ":CustomContracts",
acc.StringLE() + ":CustomContracts:xxx",
acc.StringLE() + ":CustomGroups",
acc.StringLE() + ":CustomGroups:xxx",
}
for _, s := range errorCases {
_, err := parseCosigner(s)
require.Error(t, err)
require.Error(t, err, s)
}
}

Expand Down
13 changes: 11 additions & 2 deletions cli/smartcontract/smart_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,13 @@ func NewCommands() []cli.Command {
entering deeper internal invokes. This can be default
safe choice for native NEO/GAS.
- 'CustomContracts' - define valid custom contract hashes for witness check.
- 'CustomGroups' - define custom pubkey for group members.
Hashes are be provided as hex-encoded LE value string.
At lest one hash must be provided. Multiple hashes
are separated by ':'.
- 'CustomGroups' - define custom public keys for group members. Public keys are
provided as short-form (1-byte prefix + 32 bytes) hex-encoded
values. At least one key must be provided. Multiple keys
are separated by ':'.

If no scopes were specified, 'CalledByEntry' used as default. If no signers were
specified, no array is passed. Note that scopes are properly handled by
Expand All @@ -287,7 +293,10 @@ func NewCommands() []cli.Command {
* 'NNQk4QXsxvsrr3GSozoWBUxEmfag7B6hz5'
* 'NVquyZHoPirw6zAEPvY1ZezxM493zMWQqs:Global'
* '0x0000000009070e030d0f0e020d0c06050e030c02'
* '0000000009070e030d0f0e020d0c06050e030c02:CalledByEntry,CustomGroups'
* '0000000009070e030d0f0e020d0c06050e030c02:CalledByEntry,` +
`CustomGroups:0206d7495ceb34c197093b5fc1cccf1996ada05e69ef67e765462a7f5d88ee14d0'
* '0000000009070e030d0f0e020d0c06050e030c02:CalledByEntry,` +
`CustomContracts:1011120009070e030d0f0e020d0c06050e030c02:0x1211100009070e030d0f0e020d0c06050e030c02'
`,
Action: testInvokeFunction,
Flags: options.RPC,
Expand Down