[#174] subnet: Add AddClientAdmin method

Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
Pavel Karpy 2021-11-23 12:54:32 +03:00 committed by LeL
parent b5db977e62
commit 0d45d83450
2 changed files with 72 additions and 21 deletions

View file

@ -17,12 +17,12 @@ const (
ErrInvalidOwner = "invalid owner" ErrInvalidOwner = "invalid owner"
// ErrInvalidAdmin is thrown when admin has invalid format. // ErrInvalidAdmin is thrown when admin has invalid format.
ErrInvalidAdmin = "invalid administrator" ErrInvalidAdmin = "invalid administrator"
// ErrInvalidNode is thrown when node has invalid format.
ErrInvalidNode = "invalid node key"
// ErrAlreadyExists is thrown when id already exists. // ErrAlreadyExists is thrown when id already exists.
ErrAlreadyExists = "subnet id already exists" ErrAlreadyExists = "subnet id already exists"
// ErrSubNotExist is thrown when id doesn't exist. // ErrSubNotExist is thrown when id doesn't exist.
ErrSubNotExist = "subnet id doesn't exist" ErrSubNotExist = "subnet id doesn't exist"
// ErrInvalidNode is thrown when node has invalid format.
ErrInvalidNode = "invalid node key"
// ErrNodeAdmNotExist is thrown when node admin is not found. // ErrNodeAdmNotExist is thrown when node admin is not found.
ErrNodeAdmNotExist = "node admin not found" ErrNodeAdmNotExist = "node admin not found"
// ErrNodeNotExist is thrown when node is not found. // ErrNodeNotExist is thrown when node is not found.
@ -176,7 +176,7 @@ func AddNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
panic("addNodeAdmin: node admin has already been added") panic("addNodeAdmin: node admin has already been added")
} }
storage.Put(ctx, append(stKey, adminKey...), []byte{1}) putKeyInList(ctx, adminKey, stKey)
} }
// RemoveNodeAdmin removes node administrator from the specified subnetwork. // RemoveNodeAdmin removes node administrator from the specified subnetwork.
@ -188,9 +188,9 @@ func RemoveNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
ctx := storage.GetContext() ctx := storage.GetContext()
stOwnerKey := append([]byte{ownerPrefix}, subnetID...) stKey := append([]byte{ownerPrefix}, subnetID...)
rawOwner := storage.Get(ctx, stOwnerKey) rawOwner := storage.Get(ctx, stKey)
if rawOwner == nil { if rawOwner == nil {
panic("removeNodeAdmin: " + ErrSubNotExist) panic("removeNodeAdmin: " + ErrSubNotExist)
} }
@ -200,14 +200,13 @@ func RemoveNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
panic("removeNodeAdmin: " + errCheckWitnessFailed) panic("removeNodeAdmin: " + errCheckWitnessFailed)
} }
stOwnerKey[0] = nodeAdminPrefix stKey[0] = nodeAdminPrefix
stNodeAdmKey := append(stOwnerKey, adminKey...)
if storage.Get(ctx, stNodeAdmKey) == nil { if !keyInList(ctx, adminKey, stKey) {
panic("removeNodeAdmin: " + ErrNodeAdmNotExist) panic("removeNodeAdmin: " + ErrNodeAdmNotExist)
} }
storage.Delete(ctx, stNodeAdmKey) deleteKeyFromList(ctx, adminKey, stKey)
} }
// AddNode adds node to the specified subnetwork. // AddNode adds node to the specified subnetwork.
@ -254,7 +253,7 @@ func AddNode(subnetID []byte, node interop.PublicKey) {
panic("addNode: node has already been added") panic("addNode: node has already been added")
} }
storage.Put(ctx, append(stKey, node...), []byte{1}) putKeyInList(ctx, node, stKey)
} }
// RemoveNode removes node from the specified subnetwork. // RemoveNode removes node from the specified subnetwork.
@ -327,21 +326,50 @@ func NodeAllowed(subnetID []byte, node interop.PublicKey) bool {
return storage.Get(ctx, append(stKey, node...)) != nil return storage.Get(ctx, append(stKey, node...)) != nil
} }
// AddClientAdmin adds new client administrator of the specified group in the specified subnetwork.
// Must be called by owner only.
func AddClientAdmin(subnetID []byte, groupID []byte, adminPublicKey interop.PublicKey) {
if len(adminPublicKey) != interop.PublicKeyCompressedLen {
panic("addClientAdmin: " + ErrInvalidAdmin)
}
ctx := storage.GetContext()
stKey := append([]byte{ownerPrefix}, subnetID...)
rawOwner := storage.Get(ctx, stKey)
if rawOwner == nil {
panic("addClientAdmin: " + ErrSubNotExist)
}
owner := rawOwner.([]byte)
if !runtime.CheckWitness(owner) {
panic("addClientAdmin: " + errCheckWitnessFailed)
}
stKey[0] = clientAdminPrefix
stKey = append(stKey, groupID...)
if keyInList(ctx, adminPublicKey, stKey) {
panic("addClientAdmin: client admin has already been added")
}
putKeyInList(ctx, adminPublicKey, stKey)
}
// Version returns version of the contract. // Version returns version of the contract.
func Version() int { func Version() int {
return common.Version return common.Version
} }
func keyInList(ctx storage.Context, searchedKey interop.PublicKey, prefix []byte) bool { func keyInList(ctx storage.Context, searchedKey interop.PublicKey, prefix []byte) bool {
prefixLen := len(prefix) return storage.Get(ctx, append(prefix, searchedKey...)) != nil
}
iter := storage.Find(ctx, prefix, storage.KeysOnly)
for iterator.Next(iter) { func putKeyInList(ctx storage.Context, keyToPut interop.PublicKey, prefix []byte) {
key := iterator.Value(iter).([]byte) storage.Put(ctx, append(prefix, keyToPut...), []byte{1})
if common.BytesEqual(key[prefixLen:], searchedKey) { }
return true
} func deleteKeyFromList(ctx storage.Context, keyToDelete interop.PublicKey, prefix []byte) {
} storage.Delete(ctx, append(prefix, keyToDelete...))
return false
} }

View file

@ -137,6 +137,7 @@ func TestSubnet_AddNode(t *testing.T) {
cOwn := e.WithSigners(owner) cOwn := e.WithSigners(owner)
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrInvalidNode, method, id, nodePub[1:]) cOwn.InvokeFail(t, method+errSeparator+subnet.ErrInvalidNode, method, id, nodePub[1:])
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrSubNotExist, method, []byte{0, 0, 0, 0}, nodePub)
cOwn.Invoke(t, stackitem.Null{}, method, id, nodePub) cOwn.Invoke(t, stackitem.Null{}, method, id, nodePub)
cOwn.InvokeFail(t, method+errSeparator+"node has already been added", method, id, nodePub) cOwn.InvokeFail(t, method+errSeparator+"node has already been added", method, id, nodePub)
@ -159,6 +160,7 @@ func TestSubnet_RemoveNode(t *testing.T) {
cOwn := e.WithSigners(owner) cOwn := e.WithSigners(owner)
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrInvalidNode, method, id, nodePub[1:]) cOwn.InvokeFail(t, method+errSeparator+subnet.ErrInvalidNode, method, id, nodePub[1:])
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrSubNotExist, method, []byte{0, 0, 0, 0}, nodePub)
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrNodeNotExist, method, id, nodePub) cOwn.InvokeFail(t, method+errSeparator+subnet.ErrNodeNotExist, method, id, nodePub)
cOwn.Invoke(t, stackitem.Null{}, "addNode", id, nodePub) cOwn.Invoke(t, stackitem.Null{}, "addNode", id, nodePub)
@ -183,12 +185,33 @@ func TestSubnet_NodeAllowed(t *testing.T) {
cOwn := e.WithSigners(owner) cOwn := e.WithSigners(owner)
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrInvalidNode, method, id, nodePub[1:]) cOwn.InvokeFail(t, method+errSeparator+subnet.ErrInvalidNode, method, id, nodePub[1:])
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrSubNotExist, method, []byte{0, 0, 0, 0}, nodePub)
cOwn.Invoke(t, stackitem.NewBool(false), method, id, nodePub) cOwn.Invoke(t, stackitem.NewBool(false), method, id, nodePub)
cOwn.Invoke(t, stackitem.Null{}, "addNode", id, nodePub) cOwn.Invoke(t, stackitem.Null{}, "addNode", id, nodePub)
cOwn.Invoke(t, stackitem.NewBool(true), method, id, nodePub) cOwn.Invoke(t, stackitem.NewBool(true), method, id, nodePub)
} }
func TestSubnet_AddClientAdmin(t *testing.T) {
e := newSubnetInvoker(t)
id, owner := createSubnet(t, e)
adm := e.NewAccount(t)
admPub, ok := vm.ParseSignatureContract(adm.Script())
require.True(t, ok)
const method = "addClientAdmin"
groupId := randomBytes(8)
cOwn := e.WithSigners(owner)
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrInvalidAdmin, method, id, groupId, admPub[1:])
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrSubNotExist, method, []byte{0, 0, 0, 0}, groupId, admPub)
cOwn.Invoke(t, stackitem.Null{}, method, id, groupId, admPub)
cOwn.InvokeFail(t, method+errSeparator+"client admin has already been added", method, id, groupId, admPub)
}
func createSubnet(t *testing.T, e *neotest.ContractInvoker) (id []byte, owner neotest.Signer) { func createSubnet(t *testing.T, e *neotest.ContractInvoker) (id []byte, owner neotest.Signer) {
var ( var (
ok bool ok bool