forked from TrueCloudLab/frostfs-contract
[#48] frostfsid: Support Group updating
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
501b0c5e3c
commit
e2e406932f
6 changed files with 965 additions and 199 deletions
|
@ -57,21 +57,26 @@ type (
|
|||
}
|
||||
|
||||
Group struct {
|
||||
ID int64
|
||||
Name string
|
||||
Namespace string
|
||||
KV map[string]string
|
||||
}
|
||||
|
||||
GroupExtended struct {
|
||||
ID int64
|
||||
Name string
|
||||
Namespace string
|
||||
KV map[string]string
|
||||
SubjectsCount int64
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
SubjectIAMPathKey = "iam-path"
|
||||
SubjectCreatedTimeKey = "ctime"
|
||||
SubjectModifiedTimeKey = "mtime"
|
||||
IAMPathKey = "iam-path"
|
||||
IAMARNKey = "iam-arn"
|
||||
IAMCreatedTimeKey = "ctime"
|
||||
IAMModifiedTimeKey = "mtime"
|
||||
)
|
||||
|
||||
const iteratorBatchSize = 100
|
||||
|
@ -107,6 +112,10 @@ const (
|
|||
createGroupMethod = "createGroup"
|
||||
getGroupMethod = "getGroup"
|
||||
getGroupExtendedMethod = "getGroupExtended"
|
||||
getGroupIDByNameMethod = "getGroupIDByName"
|
||||
setGroupNameMethod = "setGroupName"
|
||||
setGroupKVMethod = "setGroupKV"
|
||||
deleteGroupKVMethod = "deleteGroupKV"
|
||||
listGroupsMethod = "listGroups"
|
||||
addSubjectToGroupMethod = "addSubjectToGroup"
|
||||
removeSubjectFromGroupMethod = "removeSubjectFromGroup"
|
||||
|
@ -240,13 +249,13 @@ func (c Client) RemoveSubjectKeyCall(addr util.Uint160, key *keys.PublicKey) (me
|
|||
|
||||
// SetSubjectKV updates subject kv map.
|
||||
// Must be invoked by contract owner.
|
||||
// You can use some predefined key constants: SubjectLoginKey, SubjectIAMPathKey, SubjectCreatedTimeKey, SubjectModifiedTimeKey.
|
||||
// You can use some predefined key constants: IAMPathKey, IAMARNKey, IAMCreatedTimeKey, IAMModifiedTimeKey.
|
||||
func (c Client) SetSubjectKV(addr util.Uint160, key, val string) (tx util.Uint256, vub uint32, err error) {
|
||||
method, args := c.SetSubjectKVCall(addr, key, val)
|
||||
return c.act.SendCall(c.contract, method, args...)
|
||||
}
|
||||
|
||||
// SetSubjectKVCall provides args for SetSubjectLogin to use in commonclient.Transaction.
|
||||
// SetSubjectKVCall provides args for SetSubjectKV to use in commonclient.Transaction.
|
||||
func (c Client) SetSubjectKVCall(addr util.Uint160, key, val string) (method string, args []any) {
|
||||
return setSubjectKVMethod, []any{addr, key, val}
|
||||
}
|
||||
|
@ -258,7 +267,7 @@ func (c Client) SetSubjectName(addr util.Uint160, name string) (tx util.Uint256,
|
|||
return c.act.SendCall(c.contract, method, args...)
|
||||
}
|
||||
|
||||
// SetSubjectNameCall provides args for SetSubjectLogin to use in commonclient.Transaction.
|
||||
// SetSubjectNameCall provides args for SetSubjectName to use in commonclient.Transaction.
|
||||
func (c Client) SetSubjectNameCall(addr util.Uint160, name string) (method string, args []any) {
|
||||
return setSubjectNameMethod, []any{addr, name}
|
||||
}
|
||||
|
@ -270,7 +279,7 @@ func (c Client) DeleteSubjectKV(addr util.Uint160, key string) (tx util.Uint256,
|
|||
return c.act.SendCall(c.contract, method, args...)
|
||||
}
|
||||
|
||||
// DeleteSubjectKVCall provides args for SetSubjectLogin to use in commonclient.Transaction.
|
||||
// DeleteSubjectKVCall provides args for DeleteSubjectKV to use in commonclient.Transaction.
|
||||
func (c Client) DeleteSubjectKVCall(addr util.Uint160, key string) (method string, args []any) {
|
||||
return deleteSubjectKVMethod, []any{addr, key}
|
||||
}
|
||||
|
@ -386,8 +395,8 @@ func (c Client) CreateGroupCall(namespace, group string) (method string, args []
|
|||
}
|
||||
|
||||
// GetGroup gets group.
|
||||
func (c Client) GetGroup(namespace, group string) (*Group, error) {
|
||||
items, err := unwrap.Array(c.act.Call(c.contract, getGroupMethod, namespace, group))
|
||||
func (c Client) GetGroup(namespace string, groupID int64) (*Group, error) {
|
||||
items, err := unwrap.Array(c.act.Call(c.contract, getGroupMethod, namespace, groupID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -396,8 +405,8 @@ func (c Client) GetGroup(namespace, group string) (*Group, error) {
|
|||
}
|
||||
|
||||
// GetGroupExtended gets extended group.
|
||||
func (c Client) GetGroupExtended(namespace, group string) (*GroupExtended, error) {
|
||||
items, err := unwrap.Array(c.act.Call(c.contract, getGroupExtendedMethod, namespace, group))
|
||||
func (c Client) GetGroupExtended(namespace string, groupID int64) (*GroupExtended, error) {
|
||||
items, err := unwrap.Array(c.act.Call(c.contract, getGroupExtendedMethod, namespace, groupID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -405,6 +414,48 @@ func (c Client) GetGroupExtended(namespace, group string) (*GroupExtended, error
|
|||
return parseGroupExtended(items)
|
||||
}
|
||||
|
||||
// SetGroupName updates subject name.
|
||||
// Must be invoked by contract owner.
|
||||
func (c Client) SetGroupName(namespace string, groupID int64, name string) (tx util.Uint256, vub uint32, err error) {
|
||||
method, args := c.SetGroupNameCall(namespace, groupID, name)
|
||||
return c.act.SendCall(c.contract, method, args...)
|
||||
}
|
||||
|
||||
// SetGroupNameCall provides args for SetGroupName to use in commonclient.Transaction.
|
||||
func (c Client) SetGroupNameCall(namespace string, groupID int64, name string) (method string, args []any) {
|
||||
return setGroupNameMethod, []any{namespace, groupID, name}
|
||||
}
|
||||
|
||||
// SetGroupKV updates group kv map.
|
||||
// Must be invoked by contract owner.
|
||||
// You can use some predefined key constants: IAMPathKey, IAMARNKey, IAMCreatedTimeKey, IAMModifiedTimeKey.
|
||||
func (c Client) SetGroupKV(namespace string, groupID int64, key, val string) (tx util.Uint256, vub uint32, err error) {
|
||||
method, args := c.SetGroupKVCall(namespace, groupID, key, val)
|
||||
return c.act.SendCall(c.contract, method, args...)
|
||||
}
|
||||
|
||||
// SetGroupKVCall provides args for SetGroupKV to use in commonclient.Transaction.
|
||||
func (c Client) SetGroupKVCall(namespace string, groupID int64, key, val string) (method string, args []any) {
|
||||
return setGroupKVMethod, []any{namespace, groupID, key, val}
|
||||
}
|
||||
|
||||
// DeleteGroupKV removes group kv map.
|
||||
// Must be invoked by contract owner.
|
||||
func (c Client) DeleteGroupKV(namespace string, groupID int64, key string) (tx util.Uint256, vub uint32, err error) {
|
||||
method, args := c.DeleteGroupKVCall(namespace, groupID, key)
|
||||
return c.act.SendCall(c.contract, method, args...)
|
||||
}
|
||||
|
||||
// DeleteGroupKVCall provides args for DeleteGroupKV to use in commonclient.Transaction.
|
||||
func (c Client) DeleteGroupKVCall(namespace string, groupID int64, key string) (method string, args []any) {
|
||||
return deleteGroupKVMethod, []any{namespace, groupID, key}
|
||||
}
|
||||
|
||||
// GetGroupIDByName gets group id its name (namespace scope).
|
||||
func (c Client) GetGroupIDByName(namespace, groupName string) (int64, error) {
|
||||
return unwrap.Int64(c.act.Call(c.contract, getGroupIDByNameMethod, namespace, groupName))
|
||||
}
|
||||
|
||||
// ListGroups gets all groups in specific namespace.
|
||||
func (c Client) ListGroups(namespace string) ([]*Group, error) {
|
||||
items, err := commonclient.ReadIteratorItems(c.act, iteratorBatchSize, c.contract, listGroupsMethod, namespace)
|
||||
|
@ -417,43 +468,43 @@ func (c Client) ListGroups(namespace string) ([]*Group, error) {
|
|||
|
||||
// AddSubjectToGroup adds a new subject to group.
|
||||
// Must be invoked by contract owner.
|
||||
func (c Client) AddSubjectToGroup(addr util.Uint160, group string) (tx util.Uint256, vub uint32, err error) {
|
||||
method, args := c.AddSubjectToGroupCall(addr, group)
|
||||
func (c Client) AddSubjectToGroup(addr util.Uint160, groupID int64) (tx util.Uint256, vub uint32, err error) {
|
||||
method, args := c.AddSubjectToGroupCall(addr, groupID)
|
||||
return c.act.SendCall(c.contract, method, args...)
|
||||
}
|
||||
|
||||
// AddSubjectToGroupCall provides args for AddSubjectToGroup to use in commonclient.Transaction.
|
||||
func (c Client) AddSubjectToGroupCall(addr util.Uint160, group string) (method string, args []any) {
|
||||
return addSubjectToGroupMethod, []any{addr, group}
|
||||
func (c Client) AddSubjectToGroupCall(addr util.Uint160, groupID int64) (method string, args []any) {
|
||||
return addSubjectToGroupMethod, []any{addr, groupID}
|
||||
}
|
||||
|
||||
// RemoveSubjectFromGroup removes subject from group.
|
||||
// Must be invoked by contract owner.
|
||||
func (c Client) RemoveSubjectFromGroup(addr util.Uint160, namespace, group string) (tx util.Uint256, vub uint32, err error) {
|
||||
method, args := c.RemoveSubjectFromGroupCall(addr, namespace, group)
|
||||
func (c Client) RemoveSubjectFromGroup(addr util.Uint160, groupID int64) (tx util.Uint256, vub uint32, err error) {
|
||||
method, args := c.RemoveSubjectFromGroupCall(addr, groupID)
|
||||
return c.act.SendCall(c.contract, method, args...)
|
||||
}
|
||||
|
||||
// RemoveSubjectFromGroupCall provides args for RemoveSubjectFromGroup to use in commonclient.Transaction.
|
||||
func (c Client) RemoveSubjectFromGroupCall(addr util.Uint160, namespace, group string) (method string, args []any) {
|
||||
return removeSubjectFromGroupMethod, []any{addr, namespace, group}
|
||||
func (c Client) RemoveSubjectFromGroupCall(addr util.Uint160, groupID int64) (method string, args []any) {
|
||||
return removeSubjectFromGroupMethod, []any{addr, groupID}
|
||||
}
|
||||
|
||||
// ListGroupSubjects gets all subjects in specific group.
|
||||
func (c Client) ListGroupSubjects(namespace, group string) ([]util.Uint160, error) {
|
||||
return unwrapArrayOfUint160(commonclient.ReadIteratorItems(c.act, iteratorBatchSize, c.contract, listGroupSubjectsMethod, namespace, group))
|
||||
func (c Client) ListGroupSubjects(namespace string, groupID int64) ([]util.Uint160, error) {
|
||||
return unwrapArrayOfUint160(commonclient.ReadIteratorItems(c.act, iteratorBatchSize, c.contract, listGroupSubjectsMethod, namespace, groupID))
|
||||
}
|
||||
|
||||
// DeleteGroup deletes group.
|
||||
// Must be invoked by contract owner.
|
||||
func (c Client) DeleteGroup(namespace, group string) (tx util.Uint256, vub uint32, err error) {
|
||||
method, args := c.DeleteGroupCall(namespace, group)
|
||||
func (c Client) DeleteGroup(namespace string, groupID int64) (tx util.Uint256, vub uint32, err error) {
|
||||
method, args := c.DeleteGroupCall(namespace, groupID)
|
||||
return c.act.SendCall(c.contract, method, args...)
|
||||
}
|
||||
|
||||
// DeleteGroupCall provides args for DeleteGroup to use in commonclient.Transaction.
|
||||
func (c Client) DeleteGroupCall(namespace, group string) (method string, args []any) {
|
||||
return deleteGroupMethod, []any{namespace, group}
|
||||
func (c Client) DeleteGroupCall(namespace string, groupID int64) (method string, args []any) {
|
||||
return deleteGroupMethod, []any{namespace, groupID}
|
||||
}
|
||||
|
||||
// ListNonEmptyNamespaces gets namespaces that contain at least one subject.
|
||||
|
@ -484,6 +535,15 @@ func (c Client) Wait(tx util.Uint256, vub uint32, err error) (*state.AppExecResu
|
|||
return c.act.Wait(tx, vub, err)
|
||||
}
|
||||
|
||||
// ParseGroupID fetch groupID from stack after creating group method invocation.
|
||||
func (c Client) ParseGroupID(res *state.AppExecResult, err error) (int64, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return unwrap.Int64(makeResFromAppExec(res))
|
||||
}
|
||||
|
||||
// ListNonEmptyGroups gets groups that contain at least one subject.
|
||||
func (c Client) ListNonEmptyGroups(namespace string) ([]string, error) {
|
||||
groups, err := c.ListGroups(namespace)
|
||||
|
@ -494,7 +554,7 @@ func (c Client) ListNonEmptyGroups(namespace string) ([]string, error) {
|
|||
var res []string
|
||||
|
||||
for _, group := range groups {
|
||||
groupExt, err := c.GetGroupExtended(namespace, group.Name)
|
||||
groupExt, err := c.GetGroupExtended(namespace, group.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -522,6 +582,13 @@ func makeValidRes(item stackitem.Item) (*result.Invoke, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func makeResFromAppExec(res *state.AppExecResult) (*result.Invoke, error) {
|
||||
return &result.Invoke{
|
||||
Stack: res.Stack,
|
||||
State: res.VMState.String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseSubject(structArr []stackitem.Item) (*Subject, error) {
|
||||
if len(structArr) < 5 {
|
||||
return nil, errors.New("invalid response subject struct")
|
||||
|
@ -710,49 +777,73 @@ func parseNamespaces(items []stackitem.Item) ([]*Namespace, error) {
|
|||
}
|
||||
|
||||
func parseGroup(structArr []stackitem.Item) (*Group, error) {
|
||||
if len(structArr) < 2 {
|
||||
if len(structArr) < 4 {
|
||||
return nil, errors.New("invalid response group struct")
|
||||
}
|
||||
|
||||
name, err := structArr[0].TryBytes()
|
||||
groupID, err := structArr[0].TryInteger()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
namespace, err := structArr[1].TryBytes()
|
||||
name, err := structArr[1].TryBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
namespace, err := structArr[2].TryBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kvs, err := parseMap(structArr[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Group{
|
||||
ID: groupID.Int64(),
|
||||
Name: string(name),
|
||||
Namespace: string(namespace),
|
||||
KV: kvs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseGroupExtended(structArr []stackitem.Item) (*GroupExtended, error) {
|
||||
if len(structArr) < 3 {
|
||||
if len(structArr) < 5 {
|
||||
return nil, errors.New("invalid response group extended struct")
|
||||
}
|
||||
|
||||
name, err := structArr[0].TryBytes()
|
||||
groupID, err := structArr[0].TryInteger()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
namespace, err := structArr[1].TryBytes()
|
||||
name, err := structArr[1].TryBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
subjectCount, err := structArr[2].TryInteger()
|
||||
namespace, err := structArr[2].TryBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kvs, err := parseMap(structArr[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
subjectCount, err := structArr[4].TryInteger()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &GroupExtended{
|
||||
ID: groupID.Int64(),
|
||||
Name: string(name),
|
||||
Namespace: string(namespace),
|
||||
KV: kvs,
|
||||
SubjectsCount: subjectCount.Int64(),
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -65,25 +65,51 @@ events:
|
|||
type: String
|
||||
- name: group
|
||||
type: String
|
||||
- name: SetGroupName
|
||||
parameters:
|
||||
- name: namespace
|
||||
type: String
|
||||
- name: groupID
|
||||
type: Integer
|
||||
- name: name
|
||||
type: String
|
||||
- name: SetGroupKV
|
||||
parameters:
|
||||
- name: namespace
|
||||
type: String
|
||||
- name: groupID
|
||||
type: Integer
|
||||
- name: key
|
||||
type: String
|
||||
- name: value
|
||||
type: String
|
||||
- name: DeleteGroupKV
|
||||
parameters:
|
||||
- name: namespace
|
||||
type: String
|
||||
- name: groupID
|
||||
type: Integer
|
||||
- name: key
|
||||
type: String
|
||||
- name: AddSubjectToGroup
|
||||
parameters:
|
||||
- name: subjectAddress
|
||||
type: Hash160
|
||||
- name: namespace
|
||||
type: String
|
||||
- name: group
|
||||
type: String
|
||||
- name: groupID
|
||||
type: Integer
|
||||
- name: RemoveSubjectFromGroup
|
||||
parameters:
|
||||
- name: subjectAddress
|
||||
type: Hash160
|
||||
- name: namespace
|
||||
type: String
|
||||
- name: group
|
||||
type: String
|
||||
- name: groupID
|
||||
type: Integer
|
||||
- name: DeleteGroup
|
||||
parameters:
|
||||
- name: namespace
|
||||
type: String
|
||||
- name: group
|
||||
type: String
|
||||
- name: groupID
|
||||
type: Integer
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-contract/common"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/convert"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/crypto"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
|
||||
|
@ -41,13 +42,17 @@ type (
|
|||
}
|
||||
|
||||
Group struct {
|
||||
ID int
|
||||
Name string
|
||||
Namespace string
|
||||
KV map[string]string
|
||||
}
|
||||
|
||||
GroupExtended struct {
|
||||
ID int
|
||||
Name string
|
||||
Namespace string
|
||||
KV map[string]string
|
||||
SubjectsCount int
|
||||
}
|
||||
)
|
||||
|
@ -61,6 +66,8 @@ const (
|
|||
namespaceSubjectsNamesPrefix = 'l'
|
||||
groupKeysPrefix = 'g'
|
||||
groupSubjectsKeysPrefix = 'G'
|
||||
groupCounterKey = 'c'
|
||||
namespaceGroupsNamesPrefix = 'm'
|
||||
)
|
||||
|
||||
func _deploy(data any, isUpdate bool) {
|
||||
|
@ -77,6 +84,8 @@ func _deploy(data any, isUpdate bool) {
|
|||
storage.Put(ctx, ownerKey(owner), []byte{1})
|
||||
}
|
||||
|
||||
storage.Put(ctx, groupCounterKey, 0)
|
||||
|
||||
runtime.Log("frostfsid contract initialized")
|
||||
}
|
||||
|
||||
|
@ -560,7 +569,7 @@ func ListNamespaceSubjects(ns string) iterator.Iterator {
|
|||
return storage.Find(ctx, namespaceSubjectPrefix(ns), storage.KeysOnly|storage.RemovePrefix)
|
||||
}
|
||||
|
||||
func CreateGroup(ns, group string) {
|
||||
func CreateGroup(ns, group string) int {
|
||||
ctx := storage.GetContext()
|
||||
checkContractOwner(ctx)
|
||||
|
||||
|
@ -577,23 +586,29 @@ func CreateGroup(ns, group string) {
|
|||
panic("namespace not found")
|
||||
}
|
||||
|
||||
groupCountID := storage.Get(ctx, groupCounterKey).(int)
|
||||
groupCountID++
|
||||
storage.Put(ctx, groupCounterKey, groupCountID)
|
||||
|
||||
gr := Group{
|
||||
ID: groupCountID,
|
||||
Name: group,
|
||||
Namespace: ns,
|
||||
}
|
||||
gKey := groupKey(ns, group)
|
||||
data = storage.Get(ctx, gKey).([]byte)
|
||||
if data != nil {
|
||||
panic("group already exists")
|
||||
}
|
||||
|
||||
setNamespaceGroupName(ctx, gr)
|
||||
|
||||
gKey := groupKey(ns, groupCountID)
|
||||
storage.Put(ctx, gKey, std.Serialize(gr))
|
||||
|
||||
runtime.Notify("CreateGroup", ns, group)
|
||||
|
||||
return groupCountID
|
||||
}
|
||||
|
||||
func GetGroup(ns, group string) Group {
|
||||
func GetGroup(ns string, groupID int) Group {
|
||||
ctx := storage.GetReadOnlyContext()
|
||||
gKey := groupKey(ns, group)
|
||||
gKey := groupKey(ns, groupID)
|
||||
data := storage.Get(ctx, gKey).([]byte)
|
||||
if data == nil {
|
||||
panic("group not found")
|
||||
|
@ -602,9 +617,9 @@ func GetGroup(ns, group string) Group {
|
|||
return std.Deserialize(data).(Group)
|
||||
}
|
||||
|
||||
func GetGroupExtended(ns, group string) GroupExtended {
|
||||
func GetGroupExtended(ns string, groupID int) GroupExtended {
|
||||
ctx := storage.GetReadOnlyContext()
|
||||
gKey := groupKey(ns, group)
|
||||
gKey := groupKey(ns, groupID)
|
||||
data := storage.Get(ctx, gKey).([]byte)
|
||||
if data == nil {
|
||||
panic("group not found")
|
||||
|
@ -613,11 +628,13 @@ func GetGroupExtended(ns, group string) GroupExtended {
|
|||
gr := std.Deserialize(data).(Group)
|
||||
|
||||
grExtended := GroupExtended{
|
||||
ID: gr.ID,
|
||||
Name: gr.Name,
|
||||
Namespace: gr.Namespace,
|
||||
KV: gr.KV,
|
||||
}
|
||||
|
||||
it := storage.Find(ctx, groupSubjectPrefix(ns, group), storage.KeysOnly)
|
||||
it := storage.Find(ctx, groupSubjectPrefix(ns, groupID), storage.KeysOnly)
|
||||
for iterator.Next(it) {
|
||||
grExtended.SubjectsCount += 1
|
||||
}
|
||||
|
@ -625,12 +642,85 @@ func GetGroupExtended(ns, group string) GroupExtended {
|
|||
return grExtended
|
||||
}
|
||||
|
||||
func GetGroupIDByName(ns, name string) int {
|
||||
if ns == "" || name == "" {
|
||||
panic("invalid namespace or name")
|
||||
}
|
||||
|
||||
ctx := storage.GetReadOnlyContext()
|
||||
|
||||
nsGroupNameKey := namespaceGroupNameKey(ns, name)
|
||||
groupIDRaw := storage.Get(ctx, nsGroupNameKey).([]byte)
|
||||
if groupIDRaw == nil {
|
||||
panic("group not found")
|
||||
}
|
||||
|
||||
return std.Deserialize(groupIDRaw).(int)
|
||||
}
|
||||
|
||||
func SetGroupName(ns string, groupID int, name string) {
|
||||
ctx := storage.GetContext()
|
||||
checkContractOwner(ctx)
|
||||
|
||||
gKey := groupKey(ns, groupID)
|
||||
data := storage.Get(ctx, gKey).([]byte)
|
||||
if data == nil {
|
||||
panic("group not found")
|
||||
}
|
||||
|
||||
gr := std.Deserialize(data).(Group)
|
||||
oldName := gr.Name
|
||||
gr.Name = name
|
||||
storage.Put(ctx, gKey, std.Serialize(gr))
|
||||
|
||||
updateNamespaceGroupName(ctx, gr, oldName)
|
||||
|
||||
runtime.Notify("SetGroupName", ns, groupID, name)
|
||||
}
|
||||
|
||||
func SetGroupKV(ns string, groupID int, key, val string) {
|
||||
ctx := storage.GetContext()
|
||||
checkContractOwner(ctx)
|
||||
|
||||
gKey := groupKey(ns, groupID)
|
||||
data := storage.Get(ctx, gKey).([]byte)
|
||||
if data == nil {
|
||||
panic("group not found")
|
||||
}
|
||||
|
||||
gr := std.Deserialize(data).(Group)
|
||||
if gr.KV == nil {
|
||||
gr.KV = map[string]string{}
|
||||
}
|
||||
gr.KV[key] = val
|
||||
|
||||
storage.Put(ctx, gKey, std.Serialize(gr))
|
||||
runtime.Notify("SetGroupKV", ns, groupID, key, val)
|
||||
}
|
||||
|
||||
func DeleteGroupKV(ns string, groupID int, key string) {
|
||||
ctx := storage.GetContext()
|
||||
checkContractOwner(ctx)
|
||||
|
||||
gKey := groupKey(ns, groupID)
|
||||
data := storage.Get(ctx, gKey).([]byte)
|
||||
if data == nil {
|
||||
panic("group not found")
|
||||
}
|
||||
|
||||
gr := std.Deserialize(data).(Group)
|
||||
delete(gr.KV, key)
|
||||
|
||||
storage.Put(ctx, gKey, std.Serialize(gr))
|
||||
runtime.Notify("DeleteGroupKV", ns, groupID, key)
|
||||
}
|
||||
|
||||
func ListGroups(ns string) iterator.Iterator {
|
||||
ctx := storage.GetReadOnlyContext()
|
||||
return storage.Find(ctx, groupPrefix(ns), storage.ValuesOnly|storage.DeserializeValues)
|
||||
}
|
||||
|
||||
func AddSubjectToGroup(addr interop.Hash160, group string) {
|
||||
func AddSubjectToGroup(addr interop.Hash160, groupID int) {
|
||||
ctx := storage.GetContext()
|
||||
checkContractOwner(ctx)
|
||||
|
||||
|
@ -652,19 +742,19 @@ func AddSubjectToGroup(addr interop.Hash160, group string) {
|
|||
nSubjKey := namespaceSubjectKey(subject.Namespace, addr)
|
||||
storage.Put(ctx, nSubjKey, []byte{1})
|
||||
|
||||
gKey := groupKey(subject.Namespace, group)
|
||||
gKey := groupKey(subject.Namespace, groupID)
|
||||
data = storage.Get(ctx, gKey).([]byte)
|
||||
if data == nil {
|
||||
panic("group not found")
|
||||
}
|
||||
|
||||
gsKey := groupSubjectKey(subject.Namespace, group, addr)
|
||||
gsKey := groupSubjectKey(subject.Namespace, groupID, addr)
|
||||
storage.Put(ctx, gsKey, []byte{1})
|
||||
|
||||
runtime.Notify("AddSubjectToGroup", addr, subject.Namespace, group)
|
||||
runtime.Notify("AddSubjectToGroup", addr, subject.Namespace, groupID)
|
||||
}
|
||||
|
||||
func RemoveSubjectFromGroup(addr interop.Hash160, ns, group string) {
|
||||
func RemoveSubjectFromGroup(addr interop.Hash160, groupID int) {
|
||||
ctx := storage.GetContext()
|
||||
checkContractOwner(ctx)
|
||||
|
||||
|
@ -678,41 +768,50 @@ func RemoveSubjectFromGroup(addr interop.Hash160, ns, group string) {
|
|||
panic("subject not found")
|
||||
}
|
||||
|
||||
gKey := groupKey(ns, group)
|
||||
subject := std.Deserialize(data).(Subject)
|
||||
if subject.Namespace == "" {
|
||||
panic("subject doesn't belong to any namespace")
|
||||
}
|
||||
|
||||
gKey := groupKey(subject.Namespace, groupID)
|
||||
data = storage.Get(ctx, gKey).([]byte)
|
||||
if data == nil {
|
||||
panic("group not found")
|
||||
}
|
||||
|
||||
gsKey := groupSubjectKey(ns, group, addr)
|
||||
gsKey := groupSubjectKey(subject.Namespace, groupID, addr)
|
||||
storage.Delete(ctx, gsKey)
|
||||
|
||||
runtime.Notify("RemoveSubjectFromGroup", addr, ns, group)
|
||||
runtime.Notify("RemoveSubjectFromGroup", addr, subject.Namespace, groupID)
|
||||
}
|
||||
|
||||
func ListGroupSubjects(ns, group string) iterator.Iterator {
|
||||
func ListGroupSubjects(ns string, groupID int) iterator.Iterator {
|
||||
ctx := storage.GetReadOnlyContext()
|
||||
return storage.Find(ctx, groupSubjectPrefix(ns, group), storage.KeysOnly|storage.RemovePrefix)
|
||||
return storage.Find(ctx, groupSubjectPrefix(ns, groupID), storage.KeysOnly|storage.RemovePrefix)
|
||||
}
|
||||
|
||||
func DeleteGroup(ns, group string) {
|
||||
func DeleteGroup(ns string, groupID int) {
|
||||
ctx := storage.GetContext()
|
||||
checkContractOwner(ctx)
|
||||
|
||||
gKey := groupKey(ns, group)
|
||||
gKey := groupKey(ns, groupID)
|
||||
data := storage.Get(ctx, gKey).([]byte)
|
||||
if data == nil {
|
||||
panic("group not found")
|
||||
}
|
||||
gr := std.Deserialize(data).(Group)
|
||||
|
||||
storage.Delete(ctx, gKey)
|
||||
|
||||
it := storage.Find(ctx, groupSubjectPrefix(ns, group), storage.KeysOnly)
|
||||
it := storage.Find(ctx, groupSubjectPrefix(ns, groupID), storage.KeysOnly)
|
||||
for iterator.Next(it) {
|
||||
gsKey := iterator.Value(it).([]byte)
|
||||
storage.Delete(ctx, gsKey)
|
||||
}
|
||||
|
||||
runtime.Notify("DeleteGroup", ns, group)
|
||||
deleteNamespaceGroupName(ctx, ns, gr.Name)
|
||||
|
||||
runtime.Notify("DeleteGroup", ns, groupID)
|
||||
}
|
||||
|
||||
func checkContractOwner(ctx storage.Context) {
|
||||
|
@ -770,6 +869,42 @@ func updateNamespaceSubjectName(ctx storage.Context, subj Subject, oldName strin
|
|||
setNamespaceSubjectName(ctx, subj)
|
||||
}
|
||||
|
||||
func updateNamespaceGroupName(ctx storage.Context, gr Group, oldName string) {
|
||||
if gr.Name == oldName {
|
||||
return
|
||||
}
|
||||
|
||||
deleteNamespaceGroupName(ctx, gr.Namespace, oldName)
|
||||
setNamespaceGroupName(ctx, gr)
|
||||
}
|
||||
|
||||
func deleteNamespaceGroupName(ctx storage.Context, ns, grName string) {
|
||||
if grName == "" {
|
||||
return
|
||||
}
|
||||
|
||||
nsGroupNameKey := namespaceGroupNameKey(ns, grName)
|
||||
storage.Delete(ctx, nsGroupNameKey)
|
||||
}
|
||||
|
||||
func setNamespaceGroupName(ctx storage.Context, gr Group) {
|
||||
if gr.Name == "" {
|
||||
return
|
||||
}
|
||||
|
||||
nsGroupNameKey := namespaceGroupNameKey(gr.Namespace, gr.Name)
|
||||
groupIDRaw := storage.Get(ctx, nsGroupNameKey).([]byte)
|
||||
if groupIDRaw == nil {
|
||||
storage.Put(ctx, nsGroupNameKey, std.Serialize(gr.ID))
|
||||
return
|
||||
}
|
||||
|
||||
groupID := std.Deserialize(groupIDRaw).(int)
|
||||
if groupID != gr.ID {
|
||||
panic("group name is not available in the current namespace")
|
||||
}
|
||||
}
|
||||
|
||||
func ownerKey(owner interop.Hash160) []byte {
|
||||
return append([]byte{ownerKeysPrefix}, owner...)
|
||||
}
|
||||
|
@ -799,14 +934,14 @@ func namespaceKeyFromHash(ns []byte) []byte {
|
|||
return append([]byte{namespaceKeysPrefix}, ns...)
|
||||
}
|
||||
|
||||
func groupKey(ns, group string) []byte {
|
||||
func groupKey(ns string, groupID int) []byte {
|
||||
prefix := groupPrefix(ns)
|
||||
return append(prefix, ripemd160Hash(group)...)
|
||||
return append(prefix, idToBytes(groupID)...)
|
||||
}
|
||||
|
||||
func groupKeyFromHashes(nsHash, groupHash []byte) []byte {
|
||||
func groupKeyFromHashes(nsHash []byte, groupIDBytes []byte) []byte {
|
||||
prefix := groupPrefixFromHash(nsHash)
|
||||
return append(prefix, groupHash...)
|
||||
return append(prefix, groupIDBytes...)
|
||||
}
|
||||
|
||||
func groupPrefix(ns string) []byte {
|
||||
|
@ -837,8 +972,14 @@ func namespaceSubjectNameKey(ns, subjName string) []byte {
|
|||
return append([]byte{namespaceSubjectsNamesPrefix}, append(nsHash, nameHash...)...)
|
||||
}
|
||||
|
||||
func groupSubjectKey(ns, group string, addr interop.Hash160) []byte {
|
||||
prefix := groupSubjectPrefix(ns, group)
|
||||
func namespaceGroupNameKey(ns, groupName string) []byte {
|
||||
nsHash := ripemd160Hash(ns)
|
||||
nameHash := ripemd160Hash(groupName)
|
||||
return append([]byte{namespaceGroupsNamesPrefix}, append(nsHash, nameHash...)...)
|
||||
}
|
||||
|
||||
func groupSubjectKey(ns string, groupID int, addr interop.Hash160) []byte {
|
||||
prefix := groupSubjectPrefix(ns, groupID)
|
||||
return append(prefix, addr...)
|
||||
}
|
||||
|
||||
|
@ -847,12 +988,22 @@ func groupSubjectKeyFromHashes(nsHash, groupHash []byte, addr interop.Hash160) [
|
|||
return append(prefix, addr...)
|
||||
}
|
||||
|
||||
func groupSubjectPrefix(ns, group string) []byte {
|
||||
func groupSubjectPrefix(ns string, groupID int) []byte {
|
||||
nsHash := ripemd160Hash(ns)
|
||||
gHash := ripemd160Hash(group)
|
||||
return groupSubjectPrefixFromHashes(nsHash, gHash)
|
||||
return groupSubjectPrefixFromHashes(nsHash, idToBytes(groupID))
|
||||
}
|
||||
|
||||
func groupSubjectPrefixFromHashes(nsHash, groupHash []byte) []byte {
|
||||
return append([]byte{groupSubjectsKeysPrefix}, append(nsHash, groupHash...)...)
|
||||
func groupSubjectPrefixFromHashes(nsHash, groupIDBytes []byte) []byte {
|
||||
return append([]byte{groupSubjectsKeysPrefix}, append(nsHash, groupIDBytes...)...)
|
||||
}
|
||||
|
||||
// idToBytes converts i64 value to BE bytes. Panics if value is bigger than i64.
|
||||
func idToBytes(itemID int) []byte {
|
||||
b := convert.ToBytes(itemID)
|
||||
ln := len(b)
|
||||
if ln > 8 {
|
||||
panic("item ID exceeds 8 byte limit")
|
||||
}
|
||||
zeros := make([]byte, 8-ln)
|
||||
return append(b, zeros...)
|
||||
}
|
||||
|
|
|
@ -81,24 +81,46 @@ type CreateGroupEvent struct {
|
|||
Group string
|
||||
}
|
||||
|
||||
// SetGroupNameEvent represents "SetGroupName" event emitted by the contract.
|
||||
type SetGroupNameEvent struct {
|
||||
Namespace string
|
||||
GroupID *big.Int
|
||||
Name string
|
||||
}
|
||||
|
||||
// SetGroupKVEvent represents "SetGroupKV" event emitted by the contract.
|
||||
type SetGroupKVEvent struct {
|
||||
Namespace string
|
||||
GroupID *big.Int
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// DeleteGroupKVEvent represents "DeleteGroupKV" event emitted by the contract.
|
||||
type DeleteGroupKVEvent struct {
|
||||
Namespace string
|
||||
GroupID *big.Int
|
||||
Key string
|
||||
}
|
||||
|
||||
// AddSubjectToGroupEvent represents "AddSubjectToGroup" event emitted by the contract.
|
||||
type AddSubjectToGroupEvent struct {
|
||||
SubjectAddress util.Uint160
|
||||
Namespace string
|
||||
Group string
|
||||
GroupID *big.Int
|
||||
}
|
||||
|
||||
// RemoveSubjectFromGroupEvent represents "RemoveSubjectFromGroup" event emitted by the contract.
|
||||
type RemoveSubjectFromGroupEvent struct {
|
||||
SubjectAddress util.Uint160
|
||||
Namespace string
|
||||
Group string
|
||||
GroupID *big.Int
|
||||
}
|
||||
|
||||
// DeleteGroupEvent represents "DeleteGroup" event emitted by the contract.
|
||||
type DeleteGroupEvent struct {
|
||||
Namespace string
|
||||
Group string
|
||||
GroupID *big.Int
|
||||
}
|
||||
|
||||
// Invoker is used by ContractReader to call various safe methods.
|
||||
|
@ -193,23 +215,23 @@ func (c *Contract) AddSubjectKeyUnsigned(addr util.Uint160, key *keys.PublicKey)
|
|||
// AddSubjectToGroup creates a transaction invoking `addSubjectToGroup` method of the contract.
|
||||
// This transaction is signed and immediately sent to the network.
|
||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||
func (c *Contract) AddSubjectToGroup(addr util.Uint160, group string) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "addSubjectToGroup", addr, group)
|
||||
func (c *Contract) AddSubjectToGroup(addr util.Uint160, groupID *big.Int) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "addSubjectToGroup", addr, groupID)
|
||||
}
|
||||
|
||||
// AddSubjectToGroupTransaction creates a transaction invoking `addSubjectToGroup` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) AddSubjectToGroupTransaction(addr util.Uint160, group string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "addSubjectToGroup", addr, group)
|
||||
func (c *Contract) AddSubjectToGroupTransaction(addr util.Uint160, groupID *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "addSubjectToGroup", addr, groupID)
|
||||
}
|
||||
|
||||
// AddSubjectToGroupUnsigned creates a transaction invoking `addSubjectToGroup` method of the contract.
|
||||
// This transaction is not signed, it's simply returned to the caller.
|
||||
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||
func (c *Contract) AddSubjectToGroupUnsigned(addr util.Uint160, group string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "addSubjectToGroup", nil, addr, group)
|
||||
func (c *Contract) AddSubjectToGroupUnsigned(addr util.Uint160, groupID *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "addSubjectToGroup", nil, addr, groupID)
|
||||
}
|
||||
|
||||
// AddSubjectToNamespace creates a transaction invoking `addSubjectToNamespace` method of the contract.
|
||||
|
@ -303,23 +325,45 @@ func (c *Contract) CreateSubjectUnsigned(key *keys.PublicKey) (*transaction.Tran
|
|||
// DeleteGroup creates a transaction invoking `deleteGroup` method of the contract.
|
||||
// This transaction is signed and immediately sent to the network.
|
||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||
func (c *Contract) DeleteGroup(ns string, group string) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "deleteGroup", ns, group)
|
||||
func (c *Contract) DeleteGroup(ns string, groupID *big.Int) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "deleteGroup", ns, groupID)
|
||||
}
|
||||
|
||||
// DeleteGroupTransaction creates a transaction invoking `deleteGroup` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) DeleteGroupTransaction(ns string, group string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "deleteGroup", ns, group)
|
||||
func (c *Contract) DeleteGroupTransaction(ns string, groupID *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "deleteGroup", ns, groupID)
|
||||
}
|
||||
|
||||
// DeleteGroupUnsigned creates a transaction invoking `deleteGroup` method of the contract.
|
||||
// This transaction is not signed, it's simply returned to the caller.
|
||||
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||
func (c *Contract) DeleteGroupUnsigned(ns string, group string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "deleteGroup", nil, ns, group)
|
||||
func (c *Contract) DeleteGroupUnsigned(ns string, groupID *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "deleteGroup", nil, ns, groupID)
|
||||
}
|
||||
|
||||
// DeleteGroupKV creates a transaction invoking `deleteGroupKV` method of the contract.
|
||||
// This transaction is signed and immediately sent to the network.
|
||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||
func (c *Contract) DeleteGroupKV(ns string, groupID *big.Int, key string) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "deleteGroupKV", ns, groupID, key)
|
||||
}
|
||||
|
||||
// DeleteGroupKVTransaction creates a transaction invoking `deleteGroupKV` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) DeleteGroupKVTransaction(ns string, groupID *big.Int, key string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "deleteGroupKV", ns, groupID, key)
|
||||
}
|
||||
|
||||
// DeleteGroupKVUnsigned creates a transaction invoking `deleteGroupKV` method of the contract.
|
||||
// This transaction is not signed, it's simply returned to the caller.
|
||||
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||
func (c *Contract) DeleteGroupKVUnsigned(ns string, groupID *big.Int, key string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "deleteGroupKV", nil, ns, groupID, key)
|
||||
}
|
||||
|
||||
// DeleteOwner creates a transaction invoking `deleteOwner` method of the contract.
|
||||
|
@ -391,45 +435,67 @@ func (c *Contract) DeleteSubjectKVUnsigned(addr util.Uint160, key string) (*tran
|
|||
// GetGroup creates a transaction invoking `getGroup` method of the contract.
|
||||
// This transaction is signed and immediately sent to the network.
|
||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||
func (c *Contract) GetGroup(ns string, group string) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "getGroup", ns, group)
|
||||
func (c *Contract) GetGroup(ns string, groupID *big.Int) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "getGroup", ns, groupID)
|
||||
}
|
||||
|
||||
// GetGroupTransaction creates a transaction invoking `getGroup` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) GetGroupTransaction(ns string, group string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "getGroup", ns, group)
|
||||
func (c *Contract) GetGroupTransaction(ns string, groupID *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "getGroup", ns, groupID)
|
||||
}
|
||||
|
||||
// GetGroupUnsigned creates a transaction invoking `getGroup` method of the contract.
|
||||
// This transaction is not signed, it's simply returned to the caller.
|
||||
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||
func (c *Contract) GetGroupUnsigned(ns string, group string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "getGroup", nil, ns, group)
|
||||
func (c *Contract) GetGroupUnsigned(ns string, groupID *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "getGroup", nil, ns, groupID)
|
||||
}
|
||||
|
||||
// GetGroupExtended creates a transaction invoking `getGroupExtended` method of the contract.
|
||||
// This transaction is signed and immediately sent to the network.
|
||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||
func (c *Contract) GetGroupExtended(ns string, group string) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "getGroupExtended", ns, group)
|
||||
func (c *Contract) GetGroupExtended(ns string, groupID *big.Int) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "getGroupExtended", ns, groupID)
|
||||
}
|
||||
|
||||
// GetGroupExtendedTransaction creates a transaction invoking `getGroupExtended` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) GetGroupExtendedTransaction(ns string, group string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "getGroupExtended", ns, group)
|
||||
func (c *Contract) GetGroupExtendedTransaction(ns string, groupID *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "getGroupExtended", ns, groupID)
|
||||
}
|
||||
|
||||
// GetGroupExtendedUnsigned creates a transaction invoking `getGroupExtended` method of the contract.
|
||||
// This transaction is not signed, it's simply returned to the caller.
|
||||
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||
func (c *Contract) GetGroupExtendedUnsigned(ns string, group string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "getGroupExtended", nil, ns, group)
|
||||
func (c *Contract) GetGroupExtendedUnsigned(ns string, groupID *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "getGroupExtended", nil, ns, groupID)
|
||||
}
|
||||
|
||||
// GetGroupIDByName creates a transaction invoking `getGroupIDByName` method of the contract.
|
||||
// This transaction is signed and immediately sent to the network.
|
||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||
func (c *Contract) GetGroupIDByName(ns string, name string) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "getGroupIDByName", ns, name)
|
||||
}
|
||||
|
||||
// GetGroupIDByNameTransaction creates a transaction invoking `getGroupIDByName` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) GetGroupIDByNameTransaction(ns string, name string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "getGroupIDByName", ns, name)
|
||||
}
|
||||
|
||||
// GetGroupIDByNameUnsigned creates a transaction invoking `getGroupIDByName` method of the contract.
|
||||
// This transaction is not signed, it's simply returned to the caller.
|
||||
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||
func (c *Contract) GetGroupIDByNameUnsigned(ns string, name string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "getGroupIDByName", nil, ns, name)
|
||||
}
|
||||
|
||||
// GetNamespace creates a transaction invoking `getNamespace` method of the contract.
|
||||
|
@ -567,23 +633,23 @@ func (c *Contract) GetSubjectKeyByNameUnsigned(ns string, name string) (*transac
|
|||
// ListGroupSubjects creates a transaction invoking `listGroupSubjects` method of the contract.
|
||||
// This transaction is signed and immediately sent to the network.
|
||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||
func (c *Contract) ListGroupSubjects(ns string, group string) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "listGroupSubjects", ns, group)
|
||||
func (c *Contract) ListGroupSubjects(ns string, groupID *big.Int) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "listGroupSubjects", ns, groupID)
|
||||
}
|
||||
|
||||
// ListGroupSubjectsTransaction creates a transaction invoking `listGroupSubjects` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) ListGroupSubjectsTransaction(ns string, group string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "listGroupSubjects", ns, group)
|
||||
func (c *Contract) ListGroupSubjectsTransaction(ns string, groupID *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "listGroupSubjects", ns, groupID)
|
||||
}
|
||||
|
||||
// ListGroupSubjectsUnsigned creates a transaction invoking `listGroupSubjects` method of the contract.
|
||||
// This transaction is not signed, it's simply returned to the caller.
|
||||
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||
func (c *Contract) ListGroupSubjectsUnsigned(ns string, group string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "listGroupSubjects", nil, ns, group)
|
||||
func (c *Contract) ListGroupSubjectsUnsigned(ns string, groupID *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "listGroupSubjects", nil, ns, groupID)
|
||||
}
|
||||
|
||||
// ListGroups creates a transaction invoking `listGroups` method of the contract.
|
||||
|
@ -699,23 +765,23 @@ func (c *Contract) ListSubjectsUnsigned() (*transaction.Transaction, error) {
|
|||
// RemoveSubjectFromGroup creates a transaction invoking `removeSubjectFromGroup` method of the contract.
|
||||
// This transaction is signed and immediately sent to the network.
|
||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||
func (c *Contract) RemoveSubjectFromGroup(addr util.Uint160, ns string, group string) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "removeSubjectFromGroup", addr, ns, group)
|
||||
func (c *Contract) RemoveSubjectFromGroup(addr util.Uint160, groupID *big.Int) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "removeSubjectFromGroup", addr, groupID)
|
||||
}
|
||||
|
||||
// RemoveSubjectFromGroupTransaction creates a transaction invoking `removeSubjectFromGroup` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) RemoveSubjectFromGroupTransaction(addr util.Uint160, ns string, group string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "removeSubjectFromGroup", addr, ns, group)
|
||||
func (c *Contract) RemoveSubjectFromGroupTransaction(addr util.Uint160, groupID *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "removeSubjectFromGroup", addr, groupID)
|
||||
}
|
||||
|
||||
// RemoveSubjectFromGroupUnsigned creates a transaction invoking `removeSubjectFromGroup` method of the contract.
|
||||
// This transaction is not signed, it's simply returned to the caller.
|
||||
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||
func (c *Contract) RemoveSubjectFromGroupUnsigned(addr util.Uint160, ns string, group string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "removeSubjectFromGroup", nil, addr, ns, group)
|
||||
func (c *Contract) RemoveSubjectFromGroupUnsigned(addr util.Uint160, groupID *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "removeSubjectFromGroup", nil, addr, groupID)
|
||||
}
|
||||
|
||||
// RemoveSubjectFromNamespace creates a transaction invoking `removeSubjectFromNamespace` method of the contract.
|
||||
|
@ -762,6 +828,50 @@ func (c *Contract) RemoveSubjectKeyUnsigned(addr util.Uint160, key *keys.PublicK
|
|||
return c.actor.MakeUnsignedCall(c.hash, "removeSubjectKey", nil, addr, key)
|
||||
}
|
||||
|
||||
// SetGroupKV creates a transaction invoking `setGroupKV` method of the contract.
|
||||
// This transaction is signed and immediately sent to the network.
|
||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||
func (c *Contract) SetGroupKV(ns string, groupID *big.Int, key string, val string) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "setGroupKV", ns, groupID, key, val)
|
||||
}
|
||||
|
||||
// SetGroupKVTransaction creates a transaction invoking `setGroupKV` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) SetGroupKVTransaction(ns string, groupID *big.Int, key string, val string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "setGroupKV", ns, groupID, key, val)
|
||||
}
|
||||
|
||||
// SetGroupKVUnsigned creates a transaction invoking `setGroupKV` method of the contract.
|
||||
// This transaction is not signed, it's simply returned to the caller.
|
||||
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||
func (c *Contract) SetGroupKVUnsigned(ns string, groupID *big.Int, key string, val string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "setGroupKV", nil, ns, groupID, key, val)
|
||||
}
|
||||
|
||||
// SetGroupName creates a transaction invoking `setGroupName` method of the contract.
|
||||
// This transaction is signed and immediately sent to the network.
|
||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||
func (c *Contract) SetGroupName(ns string, groupID *big.Int, name string) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "setGroupName", ns, groupID, name)
|
||||
}
|
||||
|
||||
// SetGroupNameTransaction creates a transaction invoking `setGroupName` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) SetGroupNameTransaction(ns string, groupID *big.Int, name string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "setGroupName", ns, groupID, name)
|
||||
}
|
||||
|
||||
// SetGroupNameUnsigned creates a transaction invoking `setGroupName` method of the contract.
|
||||
// This transaction is not signed, it's simply returned to the caller.
|
||||
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||
func (c *Contract) SetGroupNameUnsigned(ns string, groupID *big.Int, name string) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "setGroupName", nil, ns, groupID, name)
|
||||
}
|
||||
|
||||
// SetSubjectKV creates a transaction invoking `setSubjectKV` method of the contract.
|
||||
// This transaction is signed and immediately sent to the network.
|
||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||
|
@ -1645,6 +1755,267 @@ func (e *CreateGroupEvent) FromStackItem(item *stackitem.Array) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SetGroupNameEventsFromApplicationLog retrieves a set of all emitted events
|
||||
// with "SetGroupName" name from the provided [result.ApplicationLog].
|
||||
func SetGroupNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*SetGroupNameEvent, error) {
|
||||
if log == nil {
|
||||
return nil, errors.New("nil application log")
|
||||
}
|
||||
|
||||
var res []*SetGroupNameEvent
|
||||
for i, ex := range log.Executions {
|
||||
for j, e := range ex.Events {
|
||||
if e.Name != "SetGroupName" {
|
||||
continue
|
||||
}
|
||||
event := new(SetGroupNameEvent)
|
||||
err := event.FromStackItem(e.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to deserialize SetGroupNameEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
||||
}
|
||||
res = append(res, event)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// FromStackItem converts provided [stackitem.Array] to SetGroupNameEvent or
|
||||
// returns an error if it's not possible to do to so.
|
||||
func (e *SetGroupNameEvent) FromStackItem(item *stackitem.Array) error {
|
||||
if item == nil {
|
||||
return errors.New("nil item")
|
||||
}
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return errors.New("not an array")
|
||||
}
|
||||
if len(arr) != 3 {
|
||||
return errors.New("wrong number of structure elements")
|
||||
}
|
||||
|
||||
var (
|
||||
index = -1
|
||||
err error
|
||||
)
|
||||
index++
|
||||
e.Namespace, err = func(item stackitem.Item) (string, error) {
|
||||
b, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !utf8.Valid(b) {
|
||||
return "", errors.New("not a UTF-8 string")
|
||||
}
|
||||
return string(b), nil
|
||||
}(arr[index])
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Namespace: %w", err)
|
||||
}
|
||||
|
||||
index++
|
||||
e.GroupID, err = arr[index].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("field GroupID: %w", err)
|
||||
}
|
||||
|
||||
index++
|
||||
e.Name, err = func(item stackitem.Item) (string, error) {
|
||||
b, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !utf8.Valid(b) {
|
||||
return "", errors.New("not a UTF-8 string")
|
||||
}
|
||||
return string(b), nil
|
||||
}(arr[index])
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Name: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetGroupKVEventsFromApplicationLog retrieves a set of all emitted events
|
||||
// with "SetGroupKV" name from the provided [result.ApplicationLog].
|
||||
func SetGroupKVEventsFromApplicationLog(log *result.ApplicationLog) ([]*SetGroupKVEvent, error) {
|
||||
if log == nil {
|
||||
return nil, errors.New("nil application log")
|
||||
}
|
||||
|
||||
var res []*SetGroupKVEvent
|
||||
for i, ex := range log.Executions {
|
||||
for j, e := range ex.Events {
|
||||
if e.Name != "SetGroupKV" {
|
||||
continue
|
||||
}
|
||||
event := new(SetGroupKVEvent)
|
||||
err := event.FromStackItem(e.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to deserialize SetGroupKVEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
||||
}
|
||||
res = append(res, event)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// FromStackItem converts provided [stackitem.Array] to SetGroupKVEvent or
|
||||
// returns an error if it's not possible to do to so.
|
||||
func (e *SetGroupKVEvent) FromStackItem(item *stackitem.Array) error {
|
||||
if item == nil {
|
||||
return errors.New("nil item")
|
||||
}
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return errors.New("not an array")
|
||||
}
|
||||
if len(arr) != 4 {
|
||||
return errors.New("wrong number of structure elements")
|
||||
}
|
||||
|
||||
var (
|
||||
index = -1
|
||||
err error
|
||||
)
|
||||
index++
|
||||
e.Namespace, err = func(item stackitem.Item) (string, error) {
|
||||
b, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !utf8.Valid(b) {
|
||||
return "", errors.New("not a UTF-8 string")
|
||||
}
|
||||
return string(b), nil
|
||||
}(arr[index])
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Namespace: %w", err)
|
||||
}
|
||||
|
||||
index++
|
||||
e.GroupID, err = arr[index].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("field GroupID: %w", err)
|
||||
}
|
||||
|
||||
index++
|
||||
e.Key, err = func(item stackitem.Item) (string, error) {
|
||||
b, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !utf8.Valid(b) {
|
||||
return "", errors.New("not a UTF-8 string")
|
||||
}
|
||||
return string(b), nil
|
||||
}(arr[index])
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Key: %w", err)
|
||||
}
|
||||
|
||||
index++
|
||||
e.Value, err = func(item stackitem.Item) (string, error) {
|
||||
b, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !utf8.Valid(b) {
|
||||
return "", errors.New("not a UTF-8 string")
|
||||
}
|
||||
return string(b), nil
|
||||
}(arr[index])
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Value: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteGroupKVEventsFromApplicationLog retrieves a set of all emitted events
|
||||
// with "DeleteGroupKV" name from the provided [result.ApplicationLog].
|
||||
func DeleteGroupKVEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteGroupKVEvent, error) {
|
||||
if log == nil {
|
||||
return nil, errors.New("nil application log")
|
||||
}
|
||||
|
||||
var res []*DeleteGroupKVEvent
|
||||
for i, ex := range log.Executions {
|
||||
for j, e := range ex.Events {
|
||||
if e.Name != "DeleteGroupKV" {
|
||||
continue
|
||||
}
|
||||
event := new(DeleteGroupKVEvent)
|
||||
err := event.FromStackItem(e.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to deserialize DeleteGroupKVEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
||||
}
|
||||
res = append(res, event)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// FromStackItem converts provided [stackitem.Array] to DeleteGroupKVEvent or
|
||||
// returns an error if it's not possible to do to so.
|
||||
func (e *DeleteGroupKVEvent) FromStackItem(item *stackitem.Array) error {
|
||||
if item == nil {
|
||||
return errors.New("nil item")
|
||||
}
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return errors.New("not an array")
|
||||
}
|
||||
if len(arr) != 3 {
|
||||
return errors.New("wrong number of structure elements")
|
||||
}
|
||||
|
||||
var (
|
||||
index = -1
|
||||
err error
|
||||
)
|
||||
index++
|
||||
e.Namespace, err = func(item stackitem.Item) (string, error) {
|
||||
b, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !utf8.Valid(b) {
|
||||
return "", errors.New("not a UTF-8 string")
|
||||
}
|
||||
return string(b), nil
|
||||
}(arr[index])
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Namespace: %w", err)
|
||||
}
|
||||
|
||||
index++
|
||||
e.GroupID, err = arr[index].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("field GroupID: %w", err)
|
||||
}
|
||||
|
||||
index++
|
||||
e.Key, err = func(item stackitem.Item) (string, error) {
|
||||
b, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !utf8.Valid(b) {
|
||||
return "", errors.New("not a UTF-8 string")
|
||||
}
|
||||
return string(b), nil
|
||||
}(arr[index])
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Key: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddSubjectToGroupEventsFromApplicationLog retrieves a set of all emitted events
|
||||
// with "AddSubjectToGroup" name from the provided [result.ApplicationLog].
|
||||
func AddSubjectToGroupEventsFromApplicationLog(log *result.ApplicationLog) ([]*AddSubjectToGroupEvent, error) {
|
||||
|
@ -1720,18 +2091,9 @@ func (e *AddSubjectToGroupEvent) FromStackItem(item *stackitem.Array) error {
|
|||
}
|
||||
|
||||
index++
|
||||
e.Group, err = func(item stackitem.Item) (string, error) {
|
||||
b, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !utf8.Valid(b) {
|
||||
return "", errors.New("not a UTF-8 string")
|
||||
}
|
||||
return string(b), nil
|
||||
}(arr[index])
|
||||
e.GroupID, err = arr[index].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Group: %w", err)
|
||||
return fmt.Errorf("field GroupID: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -1812,18 +2174,9 @@ func (e *RemoveSubjectFromGroupEvent) FromStackItem(item *stackitem.Array) error
|
|||
}
|
||||
|
||||
index++
|
||||
e.Group, err = func(item stackitem.Item) (string, error) {
|
||||
b, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !utf8.Valid(b) {
|
||||
return "", errors.New("not a UTF-8 string")
|
||||
}
|
||||
return string(b), nil
|
||||
}(arr[index])
|
||||
e.GroupID, err = arr[index].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Group: %w", err)
|
||||
return fmt.Errorf("field GroupID: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -1888,18 +2241,9 @@ func (e *DeleteGroupEvent) FromStackItem(item *stackitem.Array) error {
|
|||
}
|
||||
|
||||
index++
|
||||
e.Group, err = func(item stackitem.Item) (string, error) {
|
||||
b, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !utf8.Valid(b) {
|
||||
return "", errors.New("not a UTF-8 string")
|
||||
}
|
||||
return string(b), nil
|
||||
}(arr[index])
|
||||
e.GroupID, err = arr[index].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Group: %w", err)
|
||||
return fmt.Errorf("field GroupID: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -114,17 +114,17 @@ func TestFrostFSID_Client_SubjectManagement(t *testing.T) {
|
|||
|
||||
ffsid.a.await(ffsid.cli.CreateSubject(subjKey.PublicKey()))
|
||||
ffsid.a.await(ffsid.cli.SetSubjectName(subjAddr, subjLogin))
|
||||
ffsid.a.await(ffsid.cli.SetSubjectKV(subjAddr, client.SubjectIAMPathKey, iamPathKV))
|
||||
ffsid.a.await(ffsid.cli.SetSubjectKV(subjAddr, client.IAMPathKey, iamPathKV))
|
||||
ffsid.a.await(ffsid.cli.AddSubjectKey(subjAddr, extraKey.PublicKey()))
|
||||
|
||||
subj, err := ffsid.cli.GetSubject(subjAddr)
|
||||
require.NoError(t, err)
|
||||
require.True(t, subjKey.PublicKey().Equal(subj.PrimaryKey))
|
||||
require.Equal(t, subj.Name, subjLogin)
|
||||
require.Equal(t, map[string]string{client.SubjectIAMPathKey: iamPathKV}, subj.KV)
|
||||
require.Equal(t, map[string]string{client.IAMPathKey: iamPathKV}, subj.KV)
|
||||
require.ElementsMatch(t, []*keys.PublicKey{extraKey.PublicKey()}, subj.AdditionalKeys)
|
||||
|
||||
ffsid.a.await(ffsid.cli.DeleteSubjectKV(subjAddr, client.SubjectIAMPathKey))
|
||||
ffsid.a.await(ffsid.cli.DeleteSubjectKV(subjAddr, client.IAMPathKey))
|
||||
subj, err = ffsid.cli.GetSubject(subjAddr)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, subj.KV)
|
||||
|
@ -204,43 +204,59 @@ func TestFrostFSID_Client_GroupManagement(t *testing.T) {
|
|||
ffsid.a.await(ffsid.cli.CreateNamespace(namespace))
|
||||
|
||||
groupName := "group"
|
||||
ffsid.a.await(ffsid.cli.CreateGroup(namespace, groupName))
|
||||
_, _, err := ffsid.cli.CreateGroup(namespace, groupName)
|
||||
require.ErrorContains(t, err, "already exists")
|
||||
groupID := int64(1)
|
||||
actGroupID, err := ffsid.cli.ParseGroupID(ffsid.cli.Wait(ffsid.cli.CreateGroup(namespace, groupName)))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, groupID, actGroupID)
|
||||
|
||||
group, err := ffsid.cli.GetGroup(namespace, groupName)
|
||||
_, _, err = ffsid.cli.CreateGroup(namespace, groupName)
|
||||
require.ErrorContains(t, err, "is not available")
|
||||
|
||||
iamARN := "arn"
|
||||
ffsid.a.await(ffsid.cli.SetGroupKV(namespace, groupID, client.IAMARNKey, iamARN))
|
||||
|
||||
group, err := ffsid.cli.GetGroup(namespace, groupID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, groupName, group.Name)
|
||||
require.Equal(t, map[string]string{client.IAMARNKey: iamARN}, group.KV)
|
||||
|
||||
groupExt, err := ffsid.cli.GetGroupExtended(namespace, groupName)
|
||||
ffsid.a.await(ffsid.cli.DeleteGroupKV(namespace, groupID, client.IAMARNKey))
|
||||
|
||||
groupExt, err := ffsid.cli.GetGroupExtended(namespace, groupID)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, groupExt.SubjectsCount)
|
||||
|
||||
ffsid.a.await(ffsid.cli.AddSubjectToNamespace(subjAddr, namespace))
|
||||
ffsid.a.await(ffsid.cli.AddSubjectToGroup(subjAddr, groupName))
|
||||
ffsid.a.await(ffsid.cli.AddSubjectToGroup(subjAddr, groupID))
|
||||
|
||||
subjExt, err := ffsid.cli.GetSubjectExtended(subjAddr)
|
||||
require.NoError(t, err)
|
||||
require.ElementsMatch(t, []*client.Group{{Name: groupName, Namespace: namespace}}, subjExt.Groups)
|
||||
require.ElementsMatch(t, []*client.Group{{ID: groupID, Name: groupName, Namespace: namespace, KV: map[string]string{}}}, subjExt.Groups)
|
||||
|
||||
groupExt, err = ffsid.cli.GetGroupExtended(namespace, groupName)
|
||||
groupExt, err = ffsid.cli.GetGroupExtended(namespace, groupID)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, groupExt.SubjectsCount)
|
||||
|
||||
subjects, err := ffsid.cli.ListGroupSubjects(namespace, groupName)
|
||||
subjects, err := ffsid.cli.ListGroupSubjects(namespace, groupID)
|
||||
require.NoError(t, err)
|
||||
require.ElementsMatch(t, []util.Uint160{subjAddr}, subjects)
|
||||
|
||||
ffsid.a.await(ffsid.cli.RemoveSubjectFromGroup(subjAddr, groupID))
|
||||
|
||||
subjects, err = ffsid.cli.ListGroupSubjects(namespace, groupID)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, subjects)
|
||||
|
||||
subjects, err = ffsid.cli.ListNamespaceSubjects(namespace)
|
||||
require.NoError(t, err)
|
||||
require.ElementsMatch(t, []util.Uint160{subjAddr}, subjects)
|
||||
|
||||
groups, err := ffsid.cli.ListGroups(namespace)
|
||||
require.NoError(t, err)
|
||||
require.ElementsMatch(t, []*client.Group{{Name: groupName, Namespace: namespace}}, groups)
|
||||
require.ElementsMatch(t, []*client.Group{{ID: groupID, Name: groupName, Namespace: namespace, KV: map[string]string{}}}, groups)
|
||||
|
||||
ffsid.a.await(ffsid.cli.DeleteGroup(namespace, groupName))
|
||||
_, err = ffsid.cli.GetGroup(namespace, groupName)
|
||||
ffsid.a.await(ffsid.cli.DeleteGroup(namespace, groupID))
|
||||
_, err = ffsid.cli.GetGroup(namespace, groupID)
|
||||
require.ErrorContains(t, err, "not found")
|
||||
|
||||
groups, err = ffsid.cli.ListGroups(namespace)
|
||||
|
@ -277,33 +293,47 @@ func TestFrostFSID_Client_Lists(t *testing.T) {
|
|||
|
||||
groups := []client.Group{
|
||||
{
|
||||
ID: 1,
|
||||
Name: "empty-group0",
|
||||
Namespace: namespaces[0],
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
Name: "empty-group1",
|
||||
Namespace: namespaces[1],
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
Name: "group2",
|
||||
Namespace: namespaces[1],
|
||||
},
|
||||
{
|
||||
ID: 4,
|
||||
Name: "group3",
|
||||
Namespace: namespaces[2],
|
||||
},
|
||||
{
|
||||
ID: 5,
|
||||
Name: "group4",
|
||||
Namespace: namespaces[3],
|
||||
},
|
||||
{
|
||||
ID: 6,
|
||||
Name: "group5",
|
||||
Namespace: namespaces[3],
|
||||
},
|
||||
}
|
||||
|
||||
tx = ffsid.cli.StartTx()
|
||||
for _, group := range groups {
|
||||
for _, group := range groups[:3] {
|
||||
err := tx.WrapCall(ffsid.cli.CreateGroupCall(group.Namespace, group.Name))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
ffsid.a.await(ffsid.cli.SendTx(tx))
|
||||
|
||||
// we split into two tx because of gas limit exceeded error
|
||||
tx = ffsid.cli.StartTx()
|
||||
for _, group := range groups[3:] {
|
||||
err := tx.WrapCall(ffsid.cli.CreateGroupCall(group.Namespace, group.Name))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
@ -366,12 +396,12 @@ func addSubjectsToGroups(t *testing.T, ffsid *testFrostFSIDClientInvoker, groups
|
|||
cli := ffsid.cli
|
||||
tx := cli.StartTx()
|
||||
|
||||
err := tx.WrapCall(cli.AddSubjectToGroupCall(subjects[2].addr, groups[2].Name))
|
||||
err := tx.WrapCall(cli.AddSubjectToGroupCall(subjects[2].addr, groups[2].ID))
|
||||
require.NoError(t, err)
|
||||
|
||||
err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[3].addr, groups[3].Name))
|
||||
err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[3].addr, groups[3].ID))
|
||||
require.NoError(t, err)
|
||||
err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[4].addr, groups[3].Name))
|
||||
err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[4].addr, groups[3].ID))
|
||||
require.NoError(t, err)
|
||||
|
||||
ffsid.a.await(cli.SendTx(tx))
|
||||
|
@ -379,13 +409,13 @@ func addSubjectsToGroups(t *testing.T, ffsid *testFrostFSIDClientInvoker, groups
|
|||
// we have to start new tx because of insufficient gas / gas limit exceeded error
|
||||
tx = cli.StartTx()
|
||||
|
||||
err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[6].addr, groups[4].Name))
|
||||
err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[6].addr, groups[4].ID))
|
||||
require.NoError(t, err)
|
||||
err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[7].addr, groups[4].Name))
|
||||
err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[7].addr, groups[4].ID))
|
||||
require.NoError(t, err)
|
||||
err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[8].addr, groups[5].Name))
|
||||
err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[8].addr, groups[5].ID))
|
||||
require.NoError(t, err)
|
||||
err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[9].addr, groups[5].Name))
|
||||
err = tx.WrapCall(cli.AddSubjectToGroupCall(subjects[9].addr, groups[5].ID))
|
||||
require.NoError(t, err)
|
||||
|
||||
ffsid.a.await(cli.SendTx(tx))
|
||||
|
@ -398,7 +428,7 @@ func checkNamespaceSubjects(t *testing.T, cli *client.Client, ns string, subject
|
|||
}
|
||||
|
||||
func checkGroupSubjects(t *testing.T, cli *client.Client, group client.Group, subjects []testSubject, start, end int) {
|
||||
groupSubjects, err := cli.ListGroupSubjects(group.Namespace, group.Name)
|
||||
groupSubjects, err := cli.ListGroupSubjects(group.Namespace, group.ID)
|
||||
require.NoError(t, err)
|
||||
require.ElementsMatch(t, subjSlice(subjects, start, end), groupSubjects)
|
||||
}
|
||||
|
@ -448,6 +478,7 @@ func TestFrostFSID_Client_UseCaseListNSSubjects(t *testing.T) {
|
|||
|
||||
namespace := "namespace"
|
||||
group := "group"
|
||||
groupID := int64(1)
|
||||
|
||||
tx := ffsid.cli.StartTx()
|
||||
err := tx.WrapCall(ffsid.cli.CreateNamespaceCall(namespace))
|
||||
|
@ -471,7 +502,7 @@ func TestFrostFSID_Client_UseCaseListNSSubjects(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
if i > len(subjects)/2 {
|
||||
err = tx.WrapCall(ffsid.cli.AddSubjectToGroupCall(subjects[i].addr, group))
|
||||
err = tx.WrapCall(ffsid.cli.AddSubjectToGroupCall(subjects[i].addr, groupID))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
ffsid.a.await(ffsid.cli.SendTx(tx))
|
||||
|
|
|
@ -50,6 +50,10 @@ const (
|
|||
createGroupMethod = "createGroup"
|
||||
getGroupMethod = "getGroup"
|
||||
getGroupExtendedMethod = "getGroupExtended"
|
||||
getGroupIDByNameMethod = "getGroupIDByName"
|
||||
setGroupNameMethod = "setGroupName"
|
||||
setGroupKVMethod = "setGroupKV"
|
||||
deleteGroupKVMethod = "deleteGroupKV"
|
||||
listGroupsMethod = "listGroups"
|
||||
addSubjectToGroupMethod = "addSubjectToGroup"
|
||||
removeSubjectFromGroupMethod = "removeSubjectFromGroup"
|
||||
|
@ -220,16 +224,16 @@ func TestFrostFSID_SubjectManagement(t *testing.T) {
|
|||
t.Run("set subject KVs", func(t *testing.T) {
|
||||
iamPath := "iam/path"
|
||||
|
||||
anonInvoker.InvokeFail(t, notWitnessedError, setSubjectKVMethod, subjKeyAddr, client.SubjectIAMPathKey, iamPath)
|
||||
invoker.Invoke(t, stackitem.Null{}, setSubjectKVMethod, subjKeyAddr, client.SubjectIAMPathKey, iamPath)
|
||||
anonInvoker.InvokeFail(t, notWitnessedError, setSubjectKVMethod, subjKeyAddr, client.IAMPathKey, iamPath)
|
||||
invoker.Invoke(t, stackitem.Null{}, setSubjectKVMethod, subjKeyAddr, client.IAMPathKey, iamPath)
|
||||
|
||||
s, err = anonInvoker.TestInvoke(t, getSubjectMethod, subjKeyAddr)
|
||||
require.NoError(t, err)
|
||||
subj = parseSubject(t, s)
|
||||
require.Equal(t, iamPath, subj.KV[client.SubjectIAMPathKey])
|
||||
require.Equal(t, iamPath, subj.KV[client.IAMPathKey])
|
||||
|
||||
anonInvoker.InvokeFail(t, notWitnessedError, deleteSubjectKVMethod, subjKeyAddr, client.SubjectIAMPathKey)
|
||||
invoker.Invoke(t, stackitem.Null{}, deleteSubjectKVMethod, subjKeyAddr, client.SubjectIAMPathKey)
|
||||
anonInvoker.InvokeFail(t, notWitnessedError, deleteSubjectKVMethod, subjKeyAddr, client.IAMPathKey)
|
||||
invoker.Invoke(t, stackitem.Null{}, deleteSubjectKVMethod, subjKeyAddr, client.IAMPathKey)
|
||||
|
||||
s, err = anonInvoker.TestInvoke(t, getSubjectMethod, subjKeyAddr)
|
||||
require.NoError(t, err)
|
||||
|
@ -324,6 +328,55 @@ func TestFrostFSIS_SubjectNameRelatedInvariants(t *testing.T) {
|
|||
checkPublicKeyResult(t, s, err, nil)
|
||||
}
|
||||
|
||||
func TestFrostFSIS_GroupNameRelatedInvariants(t *testing.T) {
|
||||
f := newFrostFSIDInvoker(t)
|
||||
|
||||
groupName1, groupName2 := "group1", "group2"
|
||||
groupID1, groupID2 := int64(1), int64(2)
|
||||
|
||||
invoker := f.OwnerInvoker()
|
||||
|
||||
ns1, ns2 := "ns1", "ns2"
|
||||
|
||||
// Create two group
|
||||
// Create two namespace.
|
||||
// Add these groups to ns1
|
||||
invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, ns1)
|
||||
invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, ns2)
|
||||
invoker.Invoke(t, stackitem.Make(groupID1), createGroupMethod, ns1, groupName1)
|
||||
invoker.Invoke(t, stackitem.Make(groupID2), createGroupMethod, ns1, groupName2)
|
||||
|
||||
// Check that we can find group id by name for group1 in ns1 and not in ns2
|
||||
s, err := invoker.TestInvoke(t, getGroupIDByNameMethod, ns1, groupName1)
|
||||
checkGroupIDResult(t, s, err, groupID1)
|
||||
s, err = invoker.TestInvoke(t, getGroupIDByNameMethod, ns2, groupName1)
|
||||
checkGroupIDResult(t, s, err, -1)
|
||||
|
||||
// Check that we cannot set for second group name that the first subject has already taken
|
||||
invoker.InvokeFail(t, "not available", setGroupNameMethod, ns1, groupID1, groupName2)
|
||||
|
||||
// Check that we cannot create group with the same name in namespace, but can in another
|
||||
invoker.InvokeFail(t, "not available", createGroupMethod, ns1, groupName2)
|
||||
invoker.Invoke(t, stackitem.Make(3), createGroupMethod, ns2, groupName2)
|
||||
|
||||
|
||||
// Check that we cannot find group id by name for group that was removed
|
||||
invoker.Invoke(t, stackitem.Null{}, deleteGroupMethod, ns1, groupID2)
|
||||
s, err = invoker.TestInvoke(t, getGroupIDByNameMethod, ns1, groupName2)
|
||||
checkGroupIDResult(t, s, err, -1)
|
||||
|
||||
// Check that we can create group with the name that was freed after deleting
|
||||
invoker.Invoke(t, stackitem.Make(4), createGroupMethod, ns1, groupName2)
|
||||
|
||||
// Check that after group renaming its id cannot be found by old name
|
||||
newGroupName:= "new"
|
||||
invoker.Invoke(t, stackitem.Null{}, setGroupNameMethod, ns1, groupID1, newGroupName)
|
||||
s, err = invoker.TestInvoke(t, getGroupIDByNameMethod, ns1, groupName1)
|
||||
checkGroupIDResult(t, s, err, -1)
|
||||
s, err = invoker.TestInvoke(t, getGroupIDByNameMethod, ns1, newGroupName)
|
||||
checkGroupIDResult(t, s, err, groupID1)
|
||||
}
|
||||
|
||||
func TestFrostFSID_NamespaceManagement(t *testing.T) {
|
||||
f := newFrostFSIDInvoker(t)
|
||||
|
||||
|
@ -428,19 +481,21 @@ func TestFrostFSID_GroupManagement(t *testing.T) {
|
|||
nsName := "namespace"
|
||||
invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, nsName)
|
||||
|
||||
groupID := int64(1)
|
||||
groupName := "group"
|
||||
anonInvoker.InvokeFail(t, notWitnessedError, createGroupMethod, nsName, groupName)
|
||||
invoker.Invoke(t, stackitem.Null{}, createGroupMethod, nsName, groupName)
|
||||
invoker.Invoke(t, stackitem.Make(groupID), createGroupMethod, nsName, groupName)
|
||||
|
||||
s, err := anonInvoker.TestInvoke(t, getGroupMethod, nsName, groupName)
|
||||
s, err := anonInvoker.TestInvoke(t, getGroupMethod, nsName, groupID)
|
||||
require.NoError(t, err)
|
||||
group := parseGroup(t, s.Pop().Item())
|
||||
require.Equal(t, groupID, group.ID)
|
||||
require.Equal(t, groupName, group.Name)
|
||||
|
||||
s, err = anonInvoker.TestInvoke(t, listGroupsMethod, nsName)
|
||||
require.NoError(t, err)
|
||||
groups := parseGroups(t, readIteratorAll(s))
|
||||
require.ElementsMatch(t, groups, []Group{{Name: groupName, Namespace: nsName}})
|
||||
require.ElementsMatch(t, groups, []Group{{ID: groupID, Name: groupName, Namespace: nsName}})
|
||||
|
||||
t.Run("add subjects to group", func(t *testing.T) {
|
||||
subjKey, err := keys.NewPrivateKey()
|
||||
|
@ -449,21 +504,21 @@ func TestFrostFSID_GroupManagement(t *testing.T) {
|
|||
|
||||
subjAddress := subjKey.PublicKey().GetScriptHash()
|
||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToNamespaceMethod, subjAddress, nsName)
|
||||
anonInvoker.InvokeFail(t, "not witnessed", addSubjectToGroupMethod, subjAddress, groupName)
|
||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToGroupMethod, subjAddress, groupName)
|
||||
anonInvoker.InvokeFail(t, "not witnessed", addSubjectToGroupMethod, subjAddress, groupID)
|
||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToGroupMethod, subjAddress, groupID)
|
||||
|
||||
t.Run("list group subjects", func(t *testing.T) {
|
||||
s, err = anonInvoker.TestInvoke(t, listGroupSubjectsMethod, nsName, groupName)
|
||||
s, err = anonInvoker.TestInvoke(t, listGroupSubjectsMethod, nsName, groupID)
|
||||
require.NoError(t, err)
|
||||
|
||||
addresses, err := unwrap.ArrayOfUint160(makeValidRes(stackitem.NewArray(readIteratorAll(s))), nil)
|
||||
require.NoError(t, err)
|
||||
require.ElementsMatch(t, addresses, []util.Uint160{subjAddress})
|
||||
|
||||
anonInvoker.InvokeFail(t, "not witnessed", removeSubjectFromGroupMethod, subjAddress, nsName, groupName)
|
||||
invoker.Invoke(t, stackitem.Null{}, removeSubjectFromGroupMethod, subjAddress, nsName, groupName)
|
||||
anonInvoker.InvokeFail(t, "not witnessed", removeSubjectFromGroupMethod, subjAddress, groupID)
|
||||
invoker.Invoke(t, stackitem.Null{}, removeSubjectFromGroupMethod, subjAddress, groupID)
|
||||
|
||||
s, err = anonInvoker.TestInvoke(t, listGroupSubjectsMethod, nsName, groupName)
|
||||
s, err = anonInvoker.TestInvoke(t, listGroupSubjectsMethod, nsName, groupID)
|
||||
require.NoError(t, err)
|
||||
|
||||
addresses, err = unwrap.ArrayOfUint160(makeValidRes(stackitem.NewArray(readIteratorAll(s))), nil)
|
||||
|
@ -477,23 +532,61 @@ func TestFrostFSID_GroupManagement(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, subjKey.PublicKey().Bytes())
|
||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToNamespaceMethod, subjKey.PublicKey().GetScriptHash(), nsName)
|
||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToGroupMethod, subjKey.PublicKey().GetScriptHash(), groupName)
|
||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToGroupMethod, subjKey.PublicKey().GetScriptHash(), groupID)
|
||||
}
|
||||
|
||||
s, err = anonInvoker.TestInvoke(t, getGroupExtendedMethod, nsName, groupName)
|
||||
s, err = anonInvoker.TestInvoke(t, getGroupExtendedMethod, nsName, groupID)
|
||||
require.NoError(t, err)
|
||||
groupExt := parseGroupExtended(t, s.Pop().Item())
|
||||
require.Equal(t, groupID, groupExt.ID)
|
||||
require.Equal(t, groupName, groupExt.Name)
|
||||
require.Empty(t, groupExt.KV)
|
||||
require.EqualValues(t, subjectsCount, groupExt.SubjectsCount)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("delete group", func(t *testing.T) {
|
||||
anonInvoker.InvokeFail(t, notWitnessedError, deleteGroupMethod, nsName, groupName)
|
||||
invoker.Invoke(t, stackitem.Null{}, deleteGroupMethod, nsName, groupName)
|
||||
t.Run("set group name", func(t *testing.T) {
|
||||
newGroupName := "new-name"
|
||||
|
||||
anonInvoker.InvokeFail(t, "group not found", getGroupMethod, nsName, groupName)
|
||||
anonInvoker.InvokeFail(t, notWitnessedError, setGroupNameMethod, nsName, groupID, newGroupName)
|
||||
invoker.Invoke(t, stackitem.Null{}, setGroupNameMethod, nsName, groupID, newGroupName)
|
||||
|
||||
s, err = anonInvoker.TestInvoke(t, getGroupIDByNameMethod, nsName, newGroupName)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, groupID, s.Pop().BigInt().Int64())
|
||||
|
||||
s, err = anonInvoker.TestInvoke(t, getGroupMethod, nsName, groupID)
|
||||
require.NoError(t, err)
|
||||
group = parseGroup(t, s.Pop().Item())
|
||||
require.Equal(t, newGroupName, group.Name)
|
||||
})
|
||||
|
||||
t.Run("set group KVs", func(t *testing.T) {
|
||||
iamARN := "arn"
|
||||
|
||||
anonInvoker.InvokeFail(t, notWitnessedError, setGroupKVMethod, nsName, groupID, client.IAMARNKey, iamARN)
|
||||
invoker.Invoke(t, stackitem.Null{}, setGroupKVMethod, nsName, groupID, client.IAMARNKey, iamARN)
|
||||
|
||||
s, err = anonInvoker.TestInvoke(t, getGroupMethod, nsName, groupID)
|
||||
require.NoError(t, err)
|
||||
group = parseGroup(t, s.Pop().Item())
|
||||
require.Equal(t, iamARN, group.KV[client.IAMARNKey])
|
||||
|
||||
anonInvoker.InvokeFail(t, notWitnessedError, deleteGroupKVMethod, nsName, groupID, client.IAMARNKey)
|
||||
invoker.Invoke(t, stackitem.Null{}, deleteGroupKVMethod, nsName, groupID, client.IAMARNKey)
|
||||
|
||||
s, err = anonInvoker.TestInvoke(t, getGroupMethod, nsName, groupID)
|
||||
require.NoError(t, err)
|
||||
group = parseGroup(t, s.Pop().Item())
|
||||
require.Empty(t, group.KV)
|
||||
})
|
||||
|
||||
t.Run("delete group", func(t *testing.T) {
|
||||
anonInvoker.InvokeFail(t, notWitnessedError, deleteGroupMethod, nsName, groupID)
|
||||
invoker.Invoke(t, stackitem.Null{}, deleteGroupMethod, nsName, groupID)
|
||||
|
||||
anonInvoker.InvokeFail(t, "group not found", getGroupMethod, nsName, groupID)
|
||||
|
||||
s, err = anonInvoker.TestInvoke(t, listGroupsMethod, nsName)
|
||||
require.NoError(t, err)
|
||||
|
@ -514,6 +607,18 @@ func checkPublicKeyResult(t *testing.T, s *vm.Stack, err error, key *keys.Privat
|
|||
require.Equal(t, key.PublicKey(), foundKey)
|
||||
}
|
||||
|
||||
func checkGroupIDResult(t *testing.T, s *vm.Stack, err error, groupID int64) {
|
||||
if groupID == -1 {
|
||||
require.ErrorContains(t, err, "not found")
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
foundGroupID, err := unwrap.Int64(makeValidRes(s.Pop().Item()), nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, groupID, foundGroupID)
|
||||
}
|
||||
|
||||
func readIteratorAll(s *vm.Stack) []stackitem.Item {
|
||||
iter := s.Pop().Value().(*storage.Iterator)
|
||||
|
||||
|
@ -649,13 +754,17 @@ func parseNamespaces(t *testing.T, items []stackitem.Item) []Namespace {
|
|||
}
|
||||
|
||||
type Group struct {
|
||||
ID int64
|
||||
Name string
|
||||
Namespace string
|
||||
KV map[string]string
|
||||
}
|
||||
|
||||
type GroupExtended struct {
|
||||
ID int64
|
||||
Name string
|
||||
Namespace string
|
||||
KV map[string]string
|
||||
SubjectsCount int64
|
||||
}
|
||||
|
||||
|
@ -663,16 +772,23 @@ func parseGroup(t *testing.T, item stackitem.Item) Group {
|
|||
var group Group
|
||||
|
||||
subjStruct := item.Value().([]stackitem.Item)
|
||||
require.Len(t, subjStruct, 2)
|
||||
require.Len(t, subjStruct, 4)
|
||||
|
||||
nameBytes, err := subjStruct[0].TryBytes()
|
||||
groupID, err := subjStruct[0].TryInteger()
|
||||
require.NoError(t, err)
|
||||
group.ID = groupID.Int64()
|
||||
|
||||
nameBytes, err := subjStruct[1].TryBytes()
|
||||
require.NoError(t, err)
|
||||
group.Name = string(nameBytes)
|
||||
|
||||
namespaceBytes, err := subjStruct[1].TryBytes()
|
||||
namespaceBytes, err := subjStruct[2].TryBytes()
|
||||
require.NoError(t, err)
|
||||
group.Namespace = string(namespaceBytes)
|
||||
|
||||
group.KV, err = parseMap(subjStruct[3])
|
||||
require.NoError(t, err)
|
||||
|
||||
return group
|
||||
}
|
||||
|
||||
|
@ -680,17 +796,24 @@ func parseGroupExtended(t *testing.T, item stackitem.Item) GroupExtended {
|
|||
var gr GroupExtended
|
||||
|
||||
subjStruct := item.Value().([]stackitem.Item)
|
||||
require.Len(t, subjStruct, 3)
|
||||
require.Len(t, subjStruct, 5)
|
||||
|
||||
nameBytes, err := subjStruct[0].TryBytes()
|
||||
groupID, err := subjStruct[0].TryInteger()
|
||||
require.NoError(t, err)
|
||||
gr.ID = groupID.Int64()
|
||||
|
||||
nameBytes, err := subjStruct[1].TryBytes()
|
||||
require.NoError(t, err)
|
||||
gr.Name = string(nameBytes)
|
||||
|
||||
namespaceBytes, err := subjStruct[1].TryBytes()
|
||||
namespaceBytes, err := subjStruct[2].TryBytes()
|
||||
require.NoError(t, err)
|
||||
gr.Namespace = string(namespaceBytes)
|
||||
|
||||
subjectsCountInt, err := subjStruct[2].TryInteger()
|
||||
gr.KV, err = parseMap(subjStruct[3])
|
||||
require.NoError(t, err)
|
||||
|
||||
subjectsCountInt, err := subjStruct[4].TryInteger()
|
||||
require.NoError(t, err)
|
||||
gr.SubjectsCount = subjectsCountInt.Int64()
|
||||
|
||||
|
|
Loading…
Reference in a new issue