forked from TrueCloudLab/frostfs-contract
[#48] frostfsid: Support empty namespaces
Require ns to create subject. Since we don't allow move subject from one ns to another - drop add/remove subject to/from namespace Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
a0b73150c6
commit
3fb511ac15
5 changed files with 202 additions and 364 deletions
|
@ -105,8 +105,6 @@ const (
|
||||||
getNamespaceMethod = "getNamespace"
|
getNamespaceMethod = "getNamespace"
|
||||||
getNamespaceExtendedMethod = "getNamespaceExtended"
|
getNamespaceExtendedMethod = "getNamespaceExtended"
|
||||||
listNamespacesMethod = "listNamespaces"
|
listNamespacesMethod = "listNamespaces"
|
||||||
addSubjectToNamespaceMethod = "addSubjectToNamespace"
|
|
||||||
removeSubjectFromNamespaceMethod = "removeSubjectFromNamespace"
|
|
||||||
listNamespaceSubjectsMethod = "listNamespaceSubjects"
|
listNamespaceSubjectsMethod = "listNamespaceSubjects"
|
||||||
|
|
||||||
createGroupMethod = "createGroup"
|
createGroupMethod = "createGroup"
|
||||||
|
@ -199,16 +197,16 @@ func (c Client) GetAdmin() (util.Uint160, bool, error) {
|
||||||
return u, true, err
|
return u, true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateSubject creates new subject using public key.
|
// CreateSubject creates new subject using public key and namespace.
|
||||||
// Must be invoked by contract owner.
|
// Must be invoked by contract owner.
|
||||||
func (c Client) CreateSubject(key *keys.PublicKey) (tx util.Uint256, vub uint32, err error) {
|
func (c Client) CreateSubject(ns string, key *keys.PublicKey) (tx util.Uint256, vub uint32, err error) {
|
||||||
method, args := c.CreateSubjectCall(key)
|
method, args := c.CreateSubjectCall(ns, key)
|
||||||
return c.act.SendCall(c.contract, method, args...)
|
return c.act.SendCall(c.contract, method, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateSubjectCall provides args for CreateSubject to use in commonclient.Transaction.
|
// CreateSubjectCall provides args for CreateSubject to use in commonclient.Transaction.
|
||||||
func (c Client) CreateSubjectCall(key *keys.PublicKey) (method string, args []any) {
|
func (c Client) CreateSubjectCall(ns string, key *keys.PublicKey) (method string, args []any) {
|
||||||
return createSubjectMethod, []any{key.Bytes()}
|
return createSubjectMethod, []any{ns, key.Bytes()}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSubject gets subject by address.
|
// GetSubject gets subject by address.
|
||||||
|
@ -366,30 +364,6 @@ func (c Client) ListNamespaces() ([]*Namespace, error) {
|
||||||
return parseNamespaces(items)
|
return parseNamespaces(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSubjectToNamespace adds a subject to namespace.
|
|
||||||
// Must be invoked by contract owner.
|
|
||||||
func (c Client) AddSubjectToNamespace(addr util.Uint160, namespace string) (tx util.Uint256, vub uint32, err error) {
|
|
||||||
method, args := c.AddSubjectToNamespaceCall(addr, namespace)
|
|
||||||
return c.act.SendCall(c.contract, method, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddSubjectToNamespaceCall provides args for AddSubjectToNamespace to use in commonclient.Transaction.
|
|
||||||
func (c Client) AddSubjectToNamespaceCall(addr util.Uint160, namespace string) (method string, args []any) {
|
|
||||||
return addSubjectToNamespaceMethod, []any{addr, namespace}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveSubjectFromNamespace removes a subject from namespace.
|
|
||||||
// Must be invoked by contract owner.
|
|
||||||
func (c Client) RemoveSubjectFromNamespace(addr util.Uint160) (tx util.Uint256, vub uint32, err error) {
|
|
||||||
method, args := c.RemoveSubjectFromNamespaceCall(addr)
|
|
||||||
return c.act.SendCall(c.contract, method, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveSubjectFromNamespaceCall provides args for RemoveSubjectFromNamespace to use in commonclient.Transaction.
|
|
||||||
func (c Client) RemoveSubjectFromNamespaceCall(addr util.Uint160) (method string, args []any) {
|
|
||||||
return removeSubjectFromNamespaceMethod, []any{addr}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListNamespaceSubjects gets all subjects from namespace.
|
// ListNamespaceSubjects gets all subjects from namespace.
|
||||||
func (c Client) ListNamespaceSubjects(namespace string) ([]util.Uint160, error) {
|
func (c Client) ListNamespaceSubjects(namespace string) ([]util.Uint160, error) {
|
||||||
return unwrapArrayOfUint160(commonclient.ReadIteratorItems(c.act, iteratorBatchSize, c.contract, listNamespaceSubjectsMethod, namespace))
|
return unwrapArrayOfUint160(commonclient.ReadIteratorItems(c.act, iteratorBatchSize, c.contract, listNamespaceSubjectsMethod, namespace))
|
||||||
|
|
|
@ -85,6 +85,7 @@ func _deploy(data any, isUpdate bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
storage.Put(ctx, groupCounterKey, 0)
|
storage.Put(ctx, groupCounterKey, 0)
|
||||||
|
storage.Put(ctx, namespaceKey(""), std.Serialize(Namespace{}))
|
||||||
|
|
||||||
runtime.Log("frostfsid contract initialized")
|
runtime.Log("frostfsid contract initialized")
|
||||||
}
|
}
|
||||||
|
@ -128,7 +129,7 @@ func Version() int {
|
||||||
return common.Version
|
return common.Version
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateSubject(key interop.PublicKey) {
|
func CreateSubject(ns string, key interop.PublicKey) {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
checkContractOwner(ctx)
|
checkContractOwner(ctx)
|
||||||
|
|
||||||
|
@ -149,11 +150,22 @@ func CreateSubject(key interop.PublicKey) {
|
||||||
panic("key is occupied")
|
panic("key is occupied")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsKey := namespaceKey(ns)
|
||||||
|
data = storage.Get(ctx, nsKey).([]byte)
|
||||||
|
if data == nil {
|
||||||
|
panic("namespace not found")
|
||||||
|
}
|
||||||
|
|
||||||
subj := Subject{
|
subj := Subject{
|
||||||
PrimaryKey: key,
|
PrimaryKey: key,
|
||||||
|
Namespace: ns,
|
||||||
}
|
}
|
||||||
|
|
||||||
storage.Put(ctx, sKey, std.Serialize(subj))
|
storage.Put(ctx, sKey, std.Serialize(subj))
|
||||||
|
|
||||||
|
nsSubjKey := namespaceSubjectKey(ns, addr)
|
||||||
|
storage.Put(ctx, nsSubjKey, []byte{1})
|
||||||
|
|
||||||
runtime.Notify("CreateSubject", interop.Hash160(addr))
|
runtime.Notify("CreateSubject", interop.Hash160(addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,9 +327,7 @@ func DeleteSubject(addr interop.Hash160) {
|
||||||
}
|
}
|
||||||
storage.Delete(ctx, sKey)
|
storage.Delete(ctx, sKey)
|
||||||
|
|
||||||
if subj.Namespace != "" {
|
|
||||||
removeSubjectFromNamespace(ctx, subj.Namespace, addr)
|
removeSubjectFromNamespace(ctx, subj.Namespace, addr)
|
||||||
}
|
|
||||||
deleteNamespaceSubjectName(ctx, subj.Namespace, subj.Name)
|
deleteNamespaceSubjectName(ctx, subj.Namespace, subj.Name)
|
||||||
|
|
||||||
runtime.Notify("DeleteSubject", addr)
|
runtime.Notify("DeleteSubject", addr)
|
||||||
|
@ -339,26 +349,15 @@ func GetSubject(addr interop.Hash160) Subject {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSubjectExtended(addr interop.Hash160) SubjectExtended {
|
func GetSubjectExtended(addr interop.Hash160) SubjectExtended {
|
||||||
if len(addr) != interop.Hash160Len {
|
subj := GetSubject(addr)
|
||||||
panic("incorrect address length")
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := storage.GetReadOnlyContext()
|
ctx := storage.GetReadOnlyContext()
|
||||||
sKey := subjectKeyFromAddr(addr)
|
|
||||||
data := storage.Get(ctx, sKey).([]byte)
|
|
||||||
if data == nil {
|
|
||||||
panic("subject not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
subj := std.Deserialize(data).(Subject)
|
|
||||||
|
|
||||||
var groups []Group
|
var groups []Group
|
||||||
if subj.Namespace != "" {
|
|
||||||
nsHash := ripemd160Hash(subj.Namespace)
|
nsHash := ripemd160Hash(subj.Namespace)
|
||||||
it := storage.Find(ctx, groupPrefixFromHash(nsHash), storage.KeysOnly|storage.RemovePrefix)
|
it := storage.Find(ctx, groupPrefixFromHash(nsHash), storage.KeysOnly|storage.RemovePrefix)
|
||||||
for iterator.Next(it) {
|
for iterator.Next(it) {
|
||||||
groupHash := iterator.Value(it).([]byte)
|
groupHash := iterator.Value(it).([]byte)
|
||||||
data = storage.Get(ctx, groupSubjectKeyFromHashes(nsHash, groupHash, addr)).([]byte)
|
data := storage.Get(ctx, groupSubjectKeyFromHashes(nsHash, groupHash, addr)).([]byte)
|
||||||
if data != nil {
|
if data != nil {
|
||||||
data = storage.Get(ctx, groupKeyFromHashes(nsHash, groupHash)).([]byte)
|
data = storage.Get(ctx, groupKeyFromHashes(nsHash, groupHash)).([]byte)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
|
@ -367,7 +366,6 @@ func GetSubjectExtended(addr interop.Hash160) SubjectExtended {
|
||||||
groups = append(groups, std.Deserialize(data).(Group))
|
groups = append(groups, std.Deserialize(data).(Group))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
subjExt := SubjectExtended{
|
subjExt := SubjectExtended{
|
||||||
PrimaryKey: subj.PrimaryKey,
|
PrimaryKey: subj.PrimaryKey,
|
||||||
|
@ -410,8 +408,8 @@ func GetSubjectByKey(key interop.PublicKey) Subject {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSubjectKeyByName(ns, name string) interop.PublicKey {
|
func GetSubjectKeyByName(ns, name string) interop.PublicKey {
|
||||||
if ns == "" || name == "" {
|
if name == "" {
|
||||||
panic("invalid namespace or name")
|
panic("invalid or name")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := storage.GetReadOnlyContext()
|
ctx := storage.GetReadOnlyContext()
|
||||||
|
@ -434,10 +432,6 @@ func CreateNamespace(ns string) {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
checkContractOwner(ctx)
|
checkContractOwner(ctx)
|
||||||
|
|
||||||
if ns == "" {
|
|
||||||
panic("invalid namespace name")
|
|
||||||
}
|
|
||||||
|
|
||||||
nsKey := namespaceKey(ns)
|
nsKey := namespaceKey(ns)
|
||||||
data := storage.Get(ctx, nsKey).([]byte)
|
data := storage.Get(ctx, nsKey).([]byte)
|
||||||
if data != nil {
|
if data != nil {
|
||||||
|
@ -494,76 +488,6 @@ func ListNamespaces() iterator.Iterator {
|
||||||
return storage.Find(ctx, []byte{namespaceKeysPrefix}, storage.ValuesOnly|storage.DeserializeValues)
|
return storage.Find(ctx, []byte{namespaceKeysPrefix}, storage.ValuesOnly|storage.DeserializeValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddSubjectToNamespace(addr interop.Hash160, ns string) {
|
|
||||||
ctx := storage.GetContext()
|
|
||||||
checkContractOwner(ctx)
|
|
||||||
|
|
||||||
if ns == "" {
|
|
||||||
panic("invalid namespace name")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(addr) != interop.Hash160Len {
|
|
||||||
panic("invalid address length")
|
|
||||||
}
|
|
||||||
|
|
||||||
sKey := subjectKeyFromAddr(addr)
|
|
||||||
data := storage.Get(ctx, sKey).([]byte)
|
|
||||||
if data == nil {
|
|
||||||
panic("subject not found")
|
|
||||||
}
|
|
||||||
subject := std.Deserialize(data).(Subject)
|
|
||||||
|
|
||||||
if subject.Namespace == ns {
|
|
||||||
panic("subject already added")
|
|
||||||
}
|
|
||||||
if subject.Namespace != "" {
|
|
||||||
panic("subject cannot be moved to another namespace")
|
|
||||||
}
|
|
||||||
|
|
||||||
subject.Namespace = ns
|
|
||||||
storage.Put(ctx, sKey, std.Serialize(subject))
|
|
||||||
|
|
||||||
data = storage.Get(ctx, namespaceKey(ns)).([]byte)
|
|
||||||
if data == nil {
|
|
||||||
panic("namespace not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
nsSubjKey := namespaceSubjectKey(ns, addr)
|
|
||||||
storage.Put(ctx, nsSubjKey, []byte{1})
|
|
||||||
|
|
||||||
setNamespaceSubjectName(ctx, subject)
|
|
||||||
|
|
||||||
runtime.Notify("AddSubjectToNamespace", addr, ns)
|
|
||||||
}
|
|
||||||
|
|
||||||
func RemoveSubjectFromNamespace(addr interop.Hash160) {
|
|
||||||
ctx := storage.GetContext()
|
|
||||||
checkContractOwner(ctx)
|
|
||||||
|
|
||||||
if len(addr) != interop.Hash160Len {
|
|
||||||
panic("invalid address length")
|
|
||||||
}
|
|
||||||
|
|
||||||
sKey := subjectKeyFromAddr(addr)
|
|
||||||
data := storage.Get(ctx, sKey).([]byte)
|
|
||||||
if data == nil {
|
|
||||||
panic("subject not found")
|
|
||||||
}
|
|
||||||
subject := std.Deserialize(data).(Subject)
|
|
||||||
|
|
||||||
if subject.Namespace == "" {
|
|
||||||
panic("subject does not belong to any namespace")
|
|
||||||
}
|
|
||||||
|
|
||||||
removeSubjectFromNamespace(ctx, subject.Namespace, addr)
|
|
||||||
deleteNamespaceSubjectName(ctx, subject.Namespace, subject.Name)
|
|
||||||
|
|
||||||
subject.Namespace = ""
|
|
||||||
storage.Put(ctx, sKey, std.Serialize(subject))
|
|
||||||
|
|
||||||
runtime.Notify("RemoveSubjectFromNamespace", addr, subject.Namespace)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListNamespaceSubjects(ns string) iterator.Iterator {
|
func ListNamespaceSubjects(ns string) iterator.Iterator {
|
||||||
ctx := storage.GetReadOnlyContext()
|
ctx := storage.GetReadOnlyContext()
|
||||||
return storage.Find(ctx, namespaceSubjectPrefix(ns), storage.KeysOnly|storage.RemovePrefix)
|
return storage.Find(ctx, namespaceSubjectPrefix(ns), storage.KeysOnly|storage.RemovePrefix)
|
||||||
|
@ -573,9 +497,6 @@ func CreateGroup(ns, group string) int {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
checkContractOwner(ctx)
|
checkContractOwner(ctx)
|
||||||
|
|
||||||
if ns == "" {
|
|
||||||
panic("invalid namespace name")
|
|
||||||
}
|
|
||||||
if group == "" {
|
if group == "" {
|
||||||
panic("invalid group name")
|
panic("invalid group name")
|
||||||
}
|
}
|
||||||
|
@ -643,8 +564,8 @@ func GetGroupExtended(ns string, groupID int) GroupExtended {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGroupIDByName(ns, name string) int {
|
func GetGroupIDByName(ns, name string) int {
|
||||||
if ns == "" || name == "" {
|
if name == "" {
|
||||||
panic("invalid namespace or name")
|
panic("invalid name")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := storage.GetReadOnlyContext()
|
ctx := storage.GetReadOnlyContext()
|
||||||
|
@ -735,18 +656,16 @@ func AddSubjectToGroup(addr interop.Hash160, groupID int) {
|
||||||
}
|
}
|
||||||
subject := std.Deserialize(data).(Subject)
|
subject := std.Deserialize(data).(Subject)
|
||||||
|
|
||||||
if subject.Namespace == "" {
|
|
||||||
panic("subject does not belong to any namespace")
|
|
||||||
}
|
|
||||||
|
|
||||||
nSubjKey := namespaceSubjectKey(subject.Namespace, addr)
|
|
||||||
storage.Put(ctx, nSubjKey, []byte{1})
|
|
||||||
|
|
||||||
gKey := groupKey(subject.Namespace, groupID)
|
gKey := groupKey(subject.Namespace, groupID)
|
||||||
data = storage.Get(ctx, gKey).([]byte)
|
data = storage.Get(ctx, gKey).([]byte)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
panic("group not found")
|
panic("group not found")
|
||||||
}
|
}
|
||||||
|
group := std.Deserialize(data).(Group)
|
||||||
|
|
||||||
|
if group.Namespace != subject.Namespace {
|
||||||
|
panic("subject and group must be in the same namespace")
|
||||||
|
}
|
||||||
|
|
||||||
gsKey := groupSubjectKey(subject.Namespace, groupID, addr)
|
gsKey := groupSubjectKey(subject.Namespace, groupID, addr)
|
||||||
storage.Put(ctx, gsKey, []byte{1})
|
storage.Put(ctx, gsKey, []byte{1})
|
||||||
|
@ -769,15 +688,17 @@ func RemoveSubjectFromGroup(addr interop.Hash160, groupID int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
subject := std.Deserialize(data).(Subject)
|
subject := std.Deserialize(data).(Subject)
|
||||||
if subject.Namespace == "" {
|
|
||||||
panic("subject doesn't belong to any namespace")
|
|
||||||
}
|
|
||||||
|
|
||||||
gKey := groupKey(subject.Namespace, groupID)
|
gKey := groupKey(subject.Namespace, groupID)
|
||||||
data = storage.Get(ctx, gKey).([]byte)
|
data = storage.Get(ctx, gKey).([]byte)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
panic("group not found")
|
panic("group not found")
|
||||||
}
|
}
|
||||||
|
group := std.Deserialize(data).(Group)
|
||||||
|
|
||||||
|
if group.Namespace != subject.Namespace {
|
||||||
|
panic("subject and group must be in the same namespace")
|
||||||
|
}
|
||||||
|
|
||||||
gsKey := groupSubjectKey(subject.Namespace, groupID, addr)
|
gsKey := groupSubjectKey(subject.Namespace, groupID, addr)
|
||||||
storage.Delete(ctx, gsKey)
|
storage.Delete(ctx, gsKey)
|
||||||
|
|
|
@ -336,28 +336,6 @@ func (c *Contract) AddSubjectToGroupUnsigned(addr util.Uint160, groupID *big.Int
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "addSubjectToGroup", nil, addr, groupID)
|
return c.actor.MakeUnsignedCall(c.hash, "addSubjectToGroup", nil, addr, groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSubjectToNamespace creates a transaction invoking `addSubjectToNamespace` 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) AddSubjectToNamespace(addr util.Uint160, ns string) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "addSubjectToNamespace", addr, ns)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddSubjectToNamespaceTransaction creates a transaction invoking `addSubjectToNamespace` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) AddSubjectToNamespaceTransaction(addr util.Uint160, ns string) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "addSubjectToNamespace", addr, ns)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddSubjectToNamespaceUnsigned creates a transaction invoking `addSubjectToNamespace` 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) AddSubjectToNamespaceUnsigned(addr util.Uint160, ns string) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "addSubjectToNamespace", nil, addr, ns)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClearAdmin creates a transaction invoking `clearAdmin` method of the contract.
|
// ClearAdmin creates a transaction invoking `clearAdmin` method of the contract.
|
||||||
// This transaction is signed and immediately sent to the network.
|
// This transaction is signed and immediately sent to the network.
|
||||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||||
|
@ -427,23 +405,23 @@ func (c *Contract) CreateNamespaceUnsigned(ns string) (*transaction.Transaction,
|
||||||
// CreateSubject creates a transaction invoking `createSubject` method of the contract.
|
// CreateSubject creates a transaction invoking `createSubject` method of the contract.
|
||||||
// This transaction is signed and immediately sent to the network.
|
// This transaction is signed and immediately sent to the network.
|
||||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||||
func (c *Contract) CreateSubject(key *keys.PublicKey) (util.Uint256, uint32, error) {
|
func (c *Contract) CreateSubject(ns string, key *keys.PublicKey) (util.Uint256, uint32, error) {
|
||||||
return c.actor.SendCall(c.hash, "createSubject", key)
|
return c.actor.SendCall(c.hash, "createSubject", ns, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateSubjectTransaction creates a transaction invoking `createSubject` method of the contract.
|
// CreateSubjectTransaction creates a transaction invoking `createSubject` method of the contract.
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
// This transaction is signed, but not sent to the network, instead it's
|
||||||
// returned to the caller.
|
// returned to the caller.
|
||||||
func (c *Contract) CreateSubjectTransaction(key *keys.PublicKey) (*transaction.Transaction, error) {
|
func (c *Contract) CreateSubjectTransaction(ns string, key *keys.PublicKey) (*transaction.Transaction, error) {
|
||||||
return c.actor.MakeCall(c.hash, "createSubject", key)
|
return c.actor.MakeCall(c.hash, "createSubject", ns, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateSubjectUnsigned creates a transaction invoking `createSubject` method of the contract.
|
// CreateSubjectUnsigned creates a transaction invoking `createSubject` method of the contract.
|
||||||
// This transaction is not signed, it's simply returned to the caller.
|
// 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,
|
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||||
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||||
func (c *Contract) CreateSubjectUnsigned(key *keys.PublicKey) (*transaction.Transaction, error) {
|
func (c *Contract) CreateSubjectUnsigned(ns string, key *keys.PublicKey) (*transaction.Transaction, error) {
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "createSubject", nil, key)
|
return c.actor.MakeUnsignedCall(c.hash, "createSubject", nil, ns, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteGroup creates a transaction invoking `deleteGroup` method of the contract.
|
// DeleteGroup creates a transaction invoking `deleteGroup` method of the contract.
|
||||||
|
@ -556,28 +534,6 @@ func (c *Contract) RemoveSubjectFromGroupUnsigned(addr util.Uint160, groupID *bi
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "removeSubjectFromGroup", nil, addr, groupID)
|
return c.actor.MakeUnsignedCall(c.hash, "removeSubjectFromGroup", nil, addr, groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveSubjectFromNamespace creates a transaction invoking `removeSubjectFromNamespace` 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) RemoveSubjectFromNamespace(addr util.Uint160) (util.Uint256, uint32, error) {
|
|
||||||
return c.actor.SendCall(c.hash, "removeSubjectFromNamespace", addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveSubjectFromNamespaceTransaction creates a transaction invoking `removeSubjectFromNamespace` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) RemoveSubjectFromNamespaceTransaction(addr util.Uint160) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeCall(c.hash, "removeSubjectFromNamespace", addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveSubjectFromNamespaceUnsigned creates a transaction invoking `removeSubjectFromNamespace` 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) RemoveSubjectFromNamespaceUnsigned(addr util.Uint160) (*transaction.Transaction, error) {
|
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "removeSubjectFromNamespace", nil, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveSubjectKey creates a transaction invoking `removeSubjectKey` method of the contract.
|
// RemoveSubjectKey creates a transaction invoking `removeSubjectKey` method of the contract.
|
||||||
// This transaction is signed and immediately sent to the network.
|
// This transaction is signed and immediately sent to the network.
|
||||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||||
"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/rpcclient"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
|
@ -115,7 +116,7 @@ func TestFrostFSID_Client_SubjectManagement(t *testing.T) {
|
||||||
subjLogin := "subj-login"
|
subjLogin := "subj-login"
|
||||||
iamPathKV := "iam/path"
|
iamPathKV := "iam/path"
|
||||||
|
|
||||||
ffsid.a.await(ffsid.cli.CreateSubject(subjKey.PublicKey()))
|
ffsid.a.await(ffsid.cli.CreateSubject(defaultNamespace, subjKey.PublicKey()))
|
||||||
ffsid.a.await(ffsid.cli.SetSubjectName(subjAddr, subjLogin))
|
ffsid.a.await(ffsid.cli.SetSubjectName(subjAddr, subjLogin))
|
||||||
ffsid.a.await(ffsid.cli.SetSubjectKV(subjAddr, client.IAMPathKey, iamPathKV))
|
ffsid.a.await(ffsid.cli.SetSubjectKV(subjAddr, client.IAMPathKey, iamPathKV))
|
||||||
ffsid.a.await(ffsid.cli.AddSubjectKey(subjAddr, extraKey.PublicKey()))
|
ffsid.a.await(ffsid.cli.AddSubjectKey(subjAddr, extraKey.PublicKey()))
|
||||||
|
@ -157,25 +158,22 @@ func TestFrostFSID_Client_NamespaceManagement(t *testing.T) {
|
||||||
ffsid, cancel := initFrostfsIFClientTest(t)
|
ffsid, cancel := initFrostfsIFClientTest(t)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
subjKey, subjAddr := newKey(t)
|
|
||||||
ffsid.a.await(ffsid.cli.CreateSubject(subjKey.PublicKey()))
|
|
||||||
|
|
||||||
namespace := "namespace"
|
namespace := "namespace"
|
||||||
|
subjKey, subjAddr := newKey(t)
|
||||||
|
|
||||||
ffsid.a.await(ffsid.cli.CreateNamespace(namespace))
|
ffsid.a.await(ffsid.cli.CreateNamespace(namespace))
|
||||||
_, _, err := ffsid.cli.CreateNamespace(namespace)
|
_, _, err := ffsid.cli.CreateNamespace(namespace)
|
||||||
require.ErrorContains(t, err, "already exists")
|
require.ErrorContains(t, err, "already exists")
|
||||||
|
|
||||||
|
ffsid.a.await(ffsid.cli.CreateSubject(namespace, subjKey.PublicKey()))
|
||||||
|
|
||||||
ns, err := ffsid.cli.GetNamespace(namespace)
|
ns, err := ffsid.cli.GetNamespace(namespace)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, namespace, ns.Name)
|
require.Equal(t, namespace, ns.Name)
|
||||||
|
|
||||||
namespaces, err := ffsid.cli.ListNamespaces()
|
namespaces, err := ffsid.cli.ListNamespaces()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.ElementsMatch(t, []*client.Namespace{ns}, namespaces)
|
require.ElementsMatch(t, []*client.Namespace{{}, ns}, namespaces)
|
||||||
|
|
||||||
ffsid.a.await(ffsid.cli.AddSubjectToNamespace(subjAddr, namespace))
|
|
||||||
_, _, err = ffsid.cli.AddSubjectToNamespace(subjAddr, namespace)
|
|
||||||
require.ErrorContains(t, err, "already added")
|
|
||||||
|
|
||||||
subj, err := ffsid.cli.GetSubject(subjAddr)
|
subj, err := ffsid.cli.GetSubject(subjAddr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -185,26 +183,57 @@ func TestFrostFSID_Client_NamespaceManagement(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.ElementsMatch(t, []util.Uint160{subjAddr}, subjects)
|
require.ElementsMatch(t, []util.Uint160{subjAddr}, subjects)
|
||||||
|
|
||||||
ffsid.a.await(ffsid.cli.RemoveSubjectFromNamespace(subjAddr))
|
ffsid.a.await(ffsid.cli.DeleteSubject(subjAddr))
|
||||||
|
|
||||||
subj, err = ffsid.cli.GetSubject(subjAddr)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Empty(t, subj.Namespace)
|
|
||||||
|
|
||||||
subjects, err = ffsid.cli.ListNamespaceSubjects(namespace)
|
subjects, err = ffsid.cli.ListNamespaceSubjects(namespace)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Empty(t, subjects)
|
require.Empty(t, subjects)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFrostFSID_Client_DefaultNamespace(t *testing.T) {
|
||||||
|
ffsid, cancel := initFrostfsIFClientTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
group := "group"
|
||||||
|
subjKey, subjAddr := newKey(t)
|
||||||
|
|
||||||
|
ffsid.a.await(ffsid.cli.CreateSubject(defaultNamespace, subjKey.PublicKey()))
|
||||||
|
groupID, err := ffsid.cli.ParseGroupID(ffsid.cli.Wait(ffsid.cli.CreateGroup(defaultNamespace, group)))
|
||||||
|
require.NoError(t, err)
|
||||||
|
ffsid.a.await(ffsid.cli.AddSubjectToGroup(subjAddr, groupID))
|
||||||
|
|
||||||
|
namespaces, err := ffsid.cli.ListNamespaces()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, []*client.Namespace{{}}, namespaces)
|
||||||
|
|
||||||
|
groups, err := ffsid.cli.ListGroups(defaultNamespace)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, []*client.Group{{ID: groupID, Name: group, Namespace: defaultNamespace}}, groups)
|
||||||
|
|
||||||
|
subjects, err := ffsid.cli.ListNamespaceSubjects(defaultNamespace)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, []util.Uint160{subjAddr}, subjects)
|
||||||
|
|
||||||
|
subjects, err = ffsid.cli.ListGroupSubjects(defaultNamespace, groupID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, []util.Uint160{subjAddr}, subjects)
|
||||||
|
|
||||||
|
subject, err := ffsid.cli.GetSubjectExtended(subjAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, subjKey.PublicKey().Equal(subject.PrimaryKey))
|
||||||
|
require.Equal(t, defaultNamespace, subject.Namespace)
|
||||||
|
require.EqualValues(t, []*client.Group{{ID: groupID, Name: group, Namespace: defaultNamespace}}, subject.Groups)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFrostFSID_Client_GroupManagement(t *testing.T) {
|
func TestFrostFSID_Client_GroupManagement(t *testing.T) {
|
||||||
ffsid, cancel := initFrostfsIFClientTest(t)
|
ffsid, cancel := initFrostfsIFClientTest(t)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
subjKey, subjAddr := newKey(t)
|
|
||||||
ffsid.a.await(ffsid.cli.CreateSubject(subjKey.PublicKey()))
|
|
||||||
|
|
||||||
namespace := "namespace"
|
namespace := "namespace"
|
||||||
|
subjKey, subjAddr := newKey(t)
|
||||||
|
|
||||||
ffsid.a.await(ffsid.cli.CreateNamespace(namespace))
|
ffsid.a.await(ffsid.cli.CreateNamespace(namespace))
|
||||||
|
ffsid.a.await(ffsid.cli.CreateSubject(namespace, subjKey.PublicKey()))
|
||||||
|
|
||||||
groupName := "group"
|
groupName := "group"
|
||||||
groupID := int64(1)
|
groupID := int64(1)
|
||||||
|
@ -229,7 +258,6 @@ func TestFrostFSID_Client_GroupManagement(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Zero(t, groupExt.SubjectsCount)
|
require.Zero(t, groupExt.SubjectsCount)
|
||||||
|
|
||||||
ffsid.a.await(ffsid.cli.AddSubjectToNamespace(subjAddr, namespace))
|
|
||||||
ffsid.a.await(ffsid.cli.AddSubjectToGroup(subjAddr, groupID))
|
ffsid.a.await(ffsid.cli.AddSubjectToGroup(subjAddr, groupID))
|
||||||
|
|
||||||
subjExt, err := ffsid.cli.GetSubjectExtended(subjAddr)
|
subjExt, err := ffsid.cli.GetSubjectExtended(subjAddr)
|
||||||
|
@ -276,73 +304,17 @@ func TestFrostFSID_Client_Lists(t *testing.T) {
|
||||||
ffsid, cancel := initFrostfsIFClientTest(t)
|
ffsid, cancel := initFrostfsIFClientTest(t)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
namespaces := []string{"empty-ns0", "ns1", "ns2", "ns3"}
|
namespaces := append([]string{defaultNamespace}, createNamespaces(t, ffsid, 3)...)
|
||||||
|
|
||||||
tx := ffsid.cli.StartTx()
|
subjects := createSubjectsInNS(t, ffsid, namespaces[1], 3)
|
||||||
for _, namespace := range namespaces {
|
subjects = append(subjects, createSubjectsInNS(t, ffsid, namespaces[2], 2)...)
|
||||||
err := tx.WrapCall(ffsid.cli.CreateNamespaceCall(namespace))
|
subjects = append(subjects, createSubjectsInNS(t, ffsid, namespaces[3], 5)...)
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
ffsid.a.await(ffsid.cli.SendTx(tx))
|
|
||||||
|
|
||||||
subjects := make([]testSubject, 10)
|
groups := createGroupsInNS(t, ffsid, namespaces[0], 1)
|
||||||
tx = ffsid.cli.StartTx()
|
groups = append(groups, createGroupsInNS(t, ffsid, namespaces[1], 2)...)
|
||||||
for i := range subjects {
|
groups = append(groups, createGroupsInNS(t, ffsid, namespaces[2], 1)...)
|
||||||
subjects[i].key, subjects[i].addr = newKey(t)
|
groups = append(groups, createGroupsInNS(t, ffsid, namespaces[3], 2)...)
|
||||||
err := tx.WrapCall(ffsid.cli.CreateSubjectCall(subjects[i].key.PublicKey()))
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
ffsid.a.await(ffsid.cli.SendTx(tx))
|
|
||||||
|
|
||||||
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[: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)
|
|
||||||
}
|
|
||||||
ffsid.a.await(ffsid.cli.SendTx(tx))
|
|
||||||
|
|
||||||
addSubjectsToNamespaces(t, ffsid, namespaces, subjects)
|
|
||||||
addSubjectsToGroups(t, ffsid, groups, subjects)
|
addSubjectsToGroups(t, ffsid, groups, subjects)
|
||||||
|
|
||||||
nsList, err := ffsid.cli.ListNamespaces()
|
nsList, err := ffsid.cli.ListNamespaces()
|
||||||
|
@ -370,29 +342,55 @@ func TestFrostFSID_Client_Lists(t *testing.T) {
|
||||||
checkGroupSubjects(t, ffsid.cli, groups[5], subjects, 8, 10)
|
checkGroupSubjects(t, ffsid.cli, groups[5], subjects, 8, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addSubjectsToNamespaces(t *testing.T, ffsid *testFrostFSIDClientInvoker, namespaces []string, subjects []testSubject) {
|
func createSubjectsInNS(t *testing.T, ffsid *testFrostFSIDClientInvoker, ns string, count int) []testSubject {
|
||||||
cli := ffsid.cli
|
subjects := make([]testSubject, count)
|
||||||
|
|
||||||
tx := cli.StartTx()
|
tx := ffsid.cli.StartTx()
|
||||||
for _, subject := range subjects[:3] {
|
for i := range subjects {
|
||||||
err := tx.WrapCall(cli.AddSubjectToNamespaceCall(subject.addr, namespaces[1]))
|
subjects[i].key, subjects[i].addr = newKey(t)
|
||||||
|
err := tx.WrapCall(ffsid.cli.CreateSubjectCall(ns, subjects[i].key.PublicKey()))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
ffsid.a.await(cli.SendTx(tx))
|
ffsid.a.await(ffsid.cli.SendTx(tx))
|
||||||
|
|
||||||
tx = cli.StartTx()
|
return subjects
|
||||||
for _, subject := range subjects[3:5] {
|
}
|
||||||
err := tx.WrapCall(cli.AddSubjectToNamespaceCall(subject.addr, namespaces[2]))
|
|
||||||
|
func createGroupsInNS(t *testing.T, ffsid *testFrostFSIDClientInvoker, ns string, count int) []client.Group {
|
||||||
|
groups := make([]client.Group, count)
|
||||||
|
|
||||||
|
tx := ffsid.cli.StartTx()
|
||||||
|
for i := range groups {
|
||||||
|
groups[i].Namespace = ns
|
||||||
|
groups[i].Name = ns + "/group" + strconv.Itoa(i+1)
|
||||||
|
|
||||||
|
err := tx.WrapCall(ffsid.cli.CreateGroupCall(ns, groups[i].Name))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
ffsid.a.await(cli.SendTx(tx))
|
res := ffsid.a.await(ffsid.cli.SendTx(tx))
|
||||||
|
|
||||||
tx = cli.StartTx()
|
ids, err := unwrap.ArrayOfBigInts(makeValidRes(stackitem.NewArray(res.Stack)), nil)
|
||||||
for _, subject := range subjects[5:] {
|
require.NoError(t, err)
|
||||||
err := tx.WrapCall(cli.AddSubjectToNamespaceCall(subject.addr, namespaces[3]))
|
|
||||||
|
for i, id := range ids {
|
||||||
|
groups[i].ID = id.Int64()
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNamespaces(t *testing.T, ffsid *testFrostFSIDClientInvoker, count int) []string {
|
||||||
|
namespaces := make([]string, count)
|
||||||
|
|
||||||
|
tx := ffsid.cli.StartTx()
|
||||||
|
for i := range namespaces {
|
||||||
|
namespaces[i] = "ns" + strconv.Itoa(i+1)
|
||||||
|
err := tx.WrapCall(ffsid.cli.CreateNamespaceCall(namespaces[i]))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
ffsid.a.await(cli.SendTx(tx))
|
ffsid.a.await(ffsid.cli.SendTx(tx))
|
||||||
|
|
||||||
|
return namespaces
|
||||||
}
|
}
|
||||||
|
|
||||||
func addSubjectsToGroups(t *testing.T, ffsid *testFrostFSIDClientInvoker, groups []client.Group, subjects []testSubject) {
|
func addSubjectsToGroups(t *testing.T, ffsid *testFrostFSIDClientInvoker, groups []client.Group, subjects []testSubject) {
|
||||||
|
@ -457,14 +455,12 @@ func TestFrostFSID_Client_UseCaseWithS3GW(t *testing.T) {
|
||||||
tx := ffsid.cli.StartTx()
|
tx := ffsid.cli.StartTx()
|
||||||
err := tx.WrapCall(ffsid.cli.CreateNamespaceCall(namespace))
|
err := tx.WrapCall(ffsid.cli.CreateNamespaceCall(namespace))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = tx.WrapCall(ffsid.cli.CreateSubjectCall(dataUserKey.PublicKey()))
|
err = tx.WrapCall(ffsid.cli.CreateSubjectCall(namespace, dataUserKey.PublicKey()))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = tx.WrapCall(ffsid.cli.SetSubjectNameCall(dataUserAddr, login))
|
err = tx.WrapCall(ffsid.cli.SetSubjectNameCall(dataUserAddr, login))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = tx.WrapCall(ffsid.cli.AddSubjectKeyCall(dataUserAddr, extraDataUserKey.PublicKey()))
|
err = tx.WrapCall(ffsid.cli.AddSubjectKeyCall(dataUserAddr, extraDataUserKey.PublicKey()))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = tx.WrapCall(ffsid.cli.AddSubjectToNamespaceCall(dataUserAddr, namespace))
|
|
||||||
require.NoError(t, err)
|
|
||||||
ffsid.a.await(ffsid.cli.SendTx(tx))
|
ffsid.a.await(ffsid.cli.SendTx(tx))
|
||||||
|
|
||||||
// s3-gw
|
// s3-gw
|
||||||
|
@ -497,12 +493,10 @@ func TestFrostFSID_Client_UseCaseListNSSubjects(t *testing.T) {
|
||||||
for i := range subjects {
|
for i := range subjects {
|
||||||
tx = ffsid.cli.StartTx()
|
tx = ffsid.cli.StartTx()
|
||||||
subjects[i].key, subjects[i].addr = newKey(t)
|
subjects[i].key, subjects[i].addr = newKey(t)
|
||||||
err = tx.WrapCall(ffsid.cli.CreateSubjectCall(subjects[i].key.PublicKey()))
|
err = tx.WrapCall(ffsid.cli.CreateSubjectCall(namespace, subjects[i].key.PublicKey()))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = tx.WrapCall(ffsid.cli.SetSubjectNameCall(subjects[i].addr, "login"+strconv.Itoa(i)))
|
err = tx.WrapCall(ffsid.cli.SetSubjectNameCall(subjects[i].addr, "login"+strconv.Itoa(i)))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = tx.WrapCall(ffsid.cli.AddSubjectToNamespaceCall(subjects[i].addr, namespace))
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
if i > len(subjects)/2 {
|
if i > len(subjects)/2 {
|
||||||
err = tx.WrapCall(ffsid.cli.AddSubjectToGroupCall(subjects[i].addr, groupID))
|
err = tx.WrapCall(ffsid.cli.AddSubjectToGroupCall(subjects[i].addr, groupID))
|
||||||
|
|
|
@ -22,6 +22,8 @@ import (
|
||||||
|
|
||||||
const frostfsidPath = "../frostfsid"
|
const frostfsidPath = "../frostfsid"
|
||||||
|
|
||||||
|
const defaultNamespace = ""
|
||||||
|
|
||||||
const (
|
const (
|
||||||
setAdminMethod = "setAdmin"
|
setAdminMethod = "setAdmin"
|
||||||
getAdminMethod = "getAdmin"
|
getAdminMethod = "getAdmin"
|
||||||
|
@ -43,8 +45,6 @@ const (
|
||||||
getNamespaceMethod = "getNamespace"
|
getNamespaceMethod = "getNamespace"
|
||||||
getNamespaceExtendedMethod = "getNamespaceExtended"
|
getNamespaceExtendedMethod = "getNamespaceExtended"
|
||||||
listNamespacesMethod = "listNamespaces"
|
listNamespacesMethod = "listNamespaces"
|
||||||
addSubjectToNamespaceMethod = "addSubjectToNamespace"
|
|
||||||
removeSubjectFromNamespaceMethod = "removeSubjectFromNamespace"
|
|
||||||
listNamespaceSubjectsMethod = "listNamespaceSubjects"
|
listNamespaceSubjectsMethod = "listNamespaceSubjects"
|
||||||
|
|
||||||
createGroupMethod = "createGroup"
|
createGroupMethod = "createGroup"
|
||||||
|
@ -174,6 +174,26 @@ func checkOwner(t *testing.T, invoker *neotest.ContractInvoker, owner ...util.Ui
|
||||||
require.Equal(t, bs, owner[0].BytesBE())
|
require.Equal(t, bs, owner[0].BytesBE())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFrostFSID_DefaultNamespace(t *testing.T) {
|
||||||
|
f := newFrostFSIDInvoker(t)
|
||||||
|
|
||||||
|
subjKey, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
subjKeyAddr := subjKey.PublicKey().GetScriptHash()
|
||||||
|
|
||||||
|
invoker := f.OwnerInvoker()
|
||||||
|
|
||||||
|
groupID := int64(1)
|
||||||
|
groupName := "group"
|
||||||
|
|
||||||
|
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, subjKey.PublicKey().Bytes())
|
||||||
|
invoker.Invoke(t, stackitem.Make(groupID), createGroupMethod, defaultNamespace, groupName)
|
||||||
|
invoker.Invoke(t, stackitem.Null{}, addSubjectToGroupMethod, subjKeyAddr, groupID)
|
||||||
|
invoker.Invoke(t, stackitem.Null{}, removeSubjectFromGroupMethod, subjKeyAddr, groupID)
|
||||||
|
invoker.Invoke(t, stackitem.Null{}, deleteGroupMethod, defaultNamespace, groupID)
|
||||||
|
invoker.Invoke(t, stackitem.Null{}, deleteSubjectMethod, subjKeyAddr)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFrostFSID_SubjectManagement(t *testing.T) {
|
func TestFrostFSID_SubjectManagement(t *testing.T) {
|
||||||
f := newFrostFSIDInvoker(t)
|
f := newFrostFSIDInvoker(t)
|
||||||
|
|
||||||
|
@ -184,9 +204,9 @@ func TestFrostFSID_SubjectManagement(t *testing.T) {
|
||||||
anonInvoker := f.AnonInvoker(t)
|
anonInvoker := f.AnonInvoker(t)
|
||||||
invoker := f.OwnerInvoker()
|
invoker := f.OwnerInvoker()
|
||||||
|
|
||||||
anonInvoker.InvokeFail(t, notWitnessedError, createSubjectMethod, subjKey.PublicKey().Bytes())
|
anonInvoker.InvokeFail(t, notWitnessedError, createSubjectMethod, defaultNamespace, subjKey.PublicKey().Bytes())
|
||||||
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, subjKey.PublicKey().Bytes())
|
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, subjKey.PublicKey().Bytes())
|
||||||
invoker.InvokeFail(t, "already exists", createSubjectMethod, subjKey.PublicKey().Bytes())
|
invoker.InvokeFail(t, "already exists", createSubjectMethod, defaultNamespace, subjKey.PublicKey().Bytes())
|
||||||
|
|
||||||
s, err := anonInvoker.TestInvoke(t, getSubjectMethod, subjKeyAddr)
|
s, err := anonInvoker.TestInvoke(t, getSubjectMethod, subjKeyAddr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -263,7 +283,7 @@ func TestFrostFSID_SubjectManagement(t *testing.T) {
|
||||||
newSubjKey, err := keys.NewPrivateKey()
|
newSubjKey, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, newSubjKey.PublicKey().Bytes())
|
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, newSubjKey.PublicKey().Bytes())
|
||||||
|
|
||||||
s, err = anonInvoker.TestInvoke(t, listSubjectsMethod)
|
s, err = anonInvoker.TestInvoke(t, listSubjectsMethod)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -293,20 +313,22 @@ func TestFrostFSIS_SubjectNameRelatedInvariants(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
subjKeyAddr2 := subjKey2.PublicKey().GetScriptHash()
|
subjKeyAddr2 := subjKey2.PublicKey().GetScriptHash()
|
||||||
|
|
||||||
|
subjName3 := "subj3"
|
||||||
|
subjKey3, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
subjKeyAddr3 := subjKey3.PublicKey().GetScriptHash()
|
||||||
|
|
||||||
invoker := f.OwnerInvoker()
|
invoker := f.OwnerInvoker()
|
||||||
|
|
||||||
ns1, ns2 := "ns1", "ns2"
|
ns1, ns2 := "ns1", "ns2"
|
||||||
|
|
||||||
// Create two subject (one of them with name)
|
|
||||||
// Create two namespace.
|
|
||||||
// Add these subjects to ns1
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, subjKey1.PublicKey().Bytes())
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, setSubjectNameMethod, subjKeyAddr1, subjName1)
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, subjKey2.PublicKey().Bytes())
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, ns1)
|
invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, ns1)
|
||||||
invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, ns2)
|
invoker.Invoke(t, stackitem.Null{}, createNamespaceMethod, ns2)
|
||||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToNamespaceMethod, subjKeyAddr1, ns1)
|
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, ns1, subjKey1.PublicKey().Bytes())
|
||||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToNamespaceMethod, subjKeyAddr2, ns1)
|
invoker.Invoke(t, stackitem.Null{}, setSubjectNameMethod, subjKeyAddr1, subjName1)
|
||||||
|
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, ns1, subjKey2.PublicKey().Bytes())
|
||||||
|
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, ns2, subjKey3.PublicKey().Bytes())
|
||||||
|
invoker.Invoke(t, stackitem.Null{}, setSubjectNameMethod, subjKeyAddr3, subjName3)
|
||||||
|
|
||||||
// Check that we can find public key by name for subj1 (with name)
|
// Check that we can find public key by name for subj1 (with name)
|
||||||
// and cannot find key for subj2 (without name)
|
// and cannot find key for subj2 (without name)
|
||||||
|
@ -323,25 +345,17 @@ func TestFrostFSIS_SubjectNameRelatedInvariants(t *testing.T) {
|
||||||
// Check that we cannot set for second subject name that the first subject has already taken
|
// Check that we cannot set for second subject name that the first subject has already taken
|
||||||
invoker.InvokeFail(t, "not available", setSubjectNameMethod, subjKeyAddr2, subjName1)
|
invoker.InvokeFail(t, "not available", setSubjectNameMethod, subjKeyAddr2, subjName1)
|
||||||
|
|
||||||
// Check that we cannot move subject from one namespace to another
|
// Check that we cannot find public key by name for subject that was removed
|
||||||
invoker.InvokeFail(t, "cannot be moved", addSubjectToNamespaceMethod, subjKeyAddr2, ns2)
|
invoker.Invoke(t, stackitem.Null{}, deleteSubjectMethod, subjKeyAddr2)
|
||||||
|
|
||||||
// Check that we cannot find public key by name for subject that was removed from namespace
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, removeSubjectFromNamespaceMethod, subjKeyAddr2)
|
|
||||||
s, err = invoker.TestInvoke(t, getSubjectKeyByNameMethod, ns1, subjName2)
|
s, err = invoker.TestInvoke(t, getSubjectKeyByNameMethod, ns1, subjName2)
|
||||||
checkPublicKeyResult(t, s, err, nil)
|
checkPublicKeyResult(t, s, err, nil)
|
||||||
|
|
||||||
// Check that we can find public key by name for subject in new namespace
|
// Check that subj3 can have the same name as subj1 if they belong to different namespaces
|
||||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToNamespaceMethod, subjKeyAddr2, ns2)
|
|
||||||
s, err = invoker.TestInvoke(t, getSubjectKeyByNameMethod, ns2, subjName2)
|
|
||||||
checkPublicKeyResult(t, s, err, subjKey2)
|
|
||||||
|
|
||||||
// Check that subj2 can have the same name as subj1 if they belong to different namespaces
|
|
||||||
// Also check that after subject renaming its key cannot be found by old name
|
// Also check that after subject renaming its key cannot be found by old name
|
||||||
invoker.Invoke(t, stackitem.Null{}, setSubjectNameMethod, subjKeyAddr2, subjName1)
|
invoker.Invoke(t, stackitem.Null{}, setSubjectNameMethod, subjKeyAddr3, subjName1)
|
||||||
s, err = invoker.TestInvoke(t, getSubjectKeyByNameMethod, ns2, subjName1)
|
s, err = invoker.TestInvoke(t, getSubjectKeyByNameMethod, ns2, subjName1)
|
||||||
checkPublicKeyResult(t, s, err, subjKey2)
|
checkPublicKeyResult(t, s, err, subjKey3)
|
||||||
s, err = invoker.TestInvoke(t, getSubjectKeyByNameMethod, ns2, subjName2)
|
s, err = invoker.TestInvoke(t, getSubjectKeyByNameMethod, ns2, subjName3)
|
||||||
checkPublicKeyResult(t, s, err, nil)
|
checkPublicKeyResult(t, s, err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,16 +428,12 @@ func TestFrostFSID_NamespaceManagement(t *testing.T) {
|
||||||
t.Run("add user to namespace", func(t *testing.T) {
|
t.Run("add user to namespace", func(t *testing.T) {
|
||||||
subjKey, err := keys.NewPrivateKey()
|
subjKey, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, subjKey.PublicKey().Bytes())
|
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, ns.Name, subjKey.PublicKey().Bytes())
|
||||||
|
|
||||||
subjName := "name"
|
subjName := "name"
|
||||||
subjAddress := subjKey.PublicKey().GetScriptHash()
|
subjAddress := subjKey.PublicKey().GetScriptHash()
|
||||||
invoker.Invoke(t, stackitem.Null{}, setSubjectNameMethod, subjAddress, subjName)
|
invoker.Invoke(t, stackitem.Null{}, setSubjectNameMethod, subjAddress, subjName)
|
||||||
|
|
||||||
anonInvoker.InvokeFail(t, notWitnessedError, addSubjectToNamespaceMethod, subjAddress, namespace)
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToNamespaceMethod, subjAddress, namespace)
|
|
||||||
invoker.InvokeFail(t, "already added", addSubjectToNamespaceMethod, subjAddress, namespace)
|
|
||||||
|
|
||||||
s, err := anonInvoker.TestInvoke(t, getSubjectMethod, subjAddress)
|
s, err := anonInvoker.TestInvoke(t, getSubjectMethod, subjAddress)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
subj := parseSubject(t, s)
|
subj := parseSubject(t, s)
|
||||||
|
@ -456,7 +466,7 @@ func TestFrostFSID_NamespaceManagement(t *testing.T) {
|
||||||
|
|
||||||
namespaces := parseNamespaces(t, readIteratorAll(s))
|
namespaces := parseNamespaces(t, readIteratorAll(s))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.ElementsMatch(t, namespaces, []Namespace{{Name: namespace}, {Name: namespace2}})
|
require.ElementsMatch(t, namespaces, []Namespace{{Name: defaultNamespace}, {Name: namespace}, {Name: namespace2}})
|
||||||
|
|
||||||
t.Run("find namespaces with some subjects", func(t *testing.T) {
|
t.Run("find namespaces with some subjects", func(t *testing.T) {
|
||||||
for _, ns := range namespaces {
|
for _, ns := range namespaces {
|
||||||
|
@ -468,21 +478,6 @@ func TestFrostFSID_NamespaceManagement(t *testing.T) {
|
||||||
require.Equal(t, namespace, nsExt.Name)
|
require.Equal(t, namespace, nsExt.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("remove subject from namespace", func(t *testing.T) {
|
|
||||||
anonInvoker.InvokeFail(t, notWitnessedError, removeSubjectFromNamespaceMethod, subjAddress)
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, removeSubjectFromNamespaceMethod, subjAddress)
|
|
||||||
|
|
||||||
s, err := anonInvoker.TestInvoke(t, getSubjectMethod, subjAddress)
|
|
||||||
require.NoError(t, err)
|
|
||||||
subj := parseSubject(t, s)
|
|
||||||
require.Empty(t, subj.Namespace)
|
|
||||||
|
|
||||||
s, err = anonInvoker.TestInvoke(t, getNamespaceExtendedMethod, namespace)
|
|
||||||
require.NoError(t, err)
|
|
||||||
nsExt := parseNamespaceExtended(t, s.Pop().Item())
|
|
||||||
require.Zero(t, nsExt.SubjectsCount)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -516,10 +511,9 @@ func TestFrostFSID_GroupManagement(t *testing.T) {
|
||||||
t.Run("add subjects to group", func(t *testing.T) {
|
t.Run("add subjects to group", func(t *testing.T) {
|
||||||
subjKey, err := keys.NewPrivateKey()
|
subjKey, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, subjKey.PublicKey().Bytes())
|
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, nsName, subjKey.PublicKey().Bytes())
|
||||||
|
|
||||||
subjAddress := subjKey.PublicKey().GetScriptHash()
|
subjAddress := subjKey.PublicKey().GetScriptHash()
|
||||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToNamespaceMethod, subjAddress, nsName)
|
|
||||||
anonInvoker.InvokeFail(t, "not witnessed", addSubjectToGroupMethod, subjAddress, groupID)
|
anonInvoker.InvokeFail(t, "not witnessed", addSubjectToGroupMethod, subjAddress, groupID)
|
||||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToGroupMethod, subjAddress, groupID)
|
invoker.Invoke(t, stackitem.Null{}, addSubjectToGroupMethod, subjAddress, groupID)
|
||||||
|
|
||||||
|
@ -546,8 +540,7 @@ func TestFrostFSID_GroupManagement(t *testing.T) {
|
||||||
for i := 0; i < subjectsCount; i++ {
|
for i := 0; i < subjectsCount; i++ {
|
||||||
subjKey, err := keys.NewPrivateKey()
|
subjKey, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, subjKey.PublicKey().Bytes())
|
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, nsName, subjKey.PublicKey().Bytes())
|
||||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToNamespaceMethod, subjKey.PublicKey().GetScriptHash(), nsName)
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, addSubjectToGroupMethod, subjKey.PublicKey().GetScriptHash(), groupID)
|
invoker.Invoke(t, stackitem.Null{}, addSubjectToGroupMethod, subjKey.PublicKey().GetScriptHash(), groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue