forked from TrueCloudLab/frostfs-contract
[#174] subnet: Add RemoveNode
method
Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
parent
18b5e56727
commit
4b47bfadcd
3 changed files with 85 additions and 0 deletions
|
@ -15,3 +15,9 @@ events:
|
|||
parameters:
|
||||
- name: id
|
||||
type: ByteArray
|
||||
- name: NodeRemove
|
||||
parameters:
|
||||
- name: subnetID
|
||||
type: ByteArray
|
||||
- name: node
|
||||
type: PublicKey
|
||||
|
|
|
@ -24,6 +24,8 @@ const (
|
|||
ErrSubNotExist = "subnet id doesn't exist"
|
||||
// ErrNodeAdmNotExist is thrown when node admin is not found.
|
||||
ErrNodeAdmNotExist = "node admin not found"
|
||||
// ErrNodeNotExist is thrown when node is not found.
|
||||
ErrNodeNotExist = "node not found"
|
||||
// ErrAccessDenied is thrown when operation is denied for caller.
|
||||
ErrAccessDenied = "access denied"
|
||||
|
||||
|
@ -254,6 +256,55 @@ func AddNode(subnetID []byte, node interop.PublicKey) {
|
|||
storage.Put(ctx, append(stKey, node...), []byte{1})
|
||||
}
|
||||
|
||||
// RemoveNode removes node from the specified subnetwork.
|
||||
// Must be called by subnet's owner or node administrator
|
||||
// only.
|
||||
func RemoveNode(subnetID []byte, node interop.PublicKey) {
|
||||
if len(node) != interop.PublicKeyCompressedLen {
|
||||
panic("removeNode: " + ErrInvalidAdmin)
|
||||
}
|
||||
|
||||
ctx := storage.GetContext()
|
||||
|
||||
stKey := append([]byte{ownerPrefix}, subnetID...)
|
||||
prefixLen := len(stKey)
|
||||
|
||||
rawOwner := storage.Get(ctx, stKey)
|
||||
if rawOwner == nil {
|
||||
panic("removeNode: " + ErrSubNotExist)
|
||||
}
|
||||
|
||||
owner := rawOwner.([]byte)
|
||||
if !runtime.CheckWitness(owner) {
|
||||
var hasAccess bool
|
||||
|
||||
stKey[0] = nodeAdminPrefix
|
||||
|
||||
iter := storage.Find(ctx, stKey, storage.KeysOnly)
|
||||
for iterator.Next(iter) {
|
||||
key := iterator.Value(iter).([]byte)
|
||||
if runtime.CheckWitness(key[prefixLen:]) {
|
||||
hasAccess = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !hasAccess {
|
||||
panic("removeNode: " + ErrAccessDenied)
|
||||
}
|
||||
}
|
||||
|
||||
stKey[0] = nodePrefix
|
||||
|
||||
if !keyInList(ctx, node, stKey) {
|
||||
panic("removeNode: " + ErrNodeNotExist)
|
||||
}
|
||||
|
||||
storage.Delete(ctx, append(stKey, node...))
|
||||
|
||||
runtime.Notify("NodeRemove", subnetID, node)
|
||||
}
|
||||
|
||||
// Version returns version of the contract.
|
||||
func Version() int {
|
||||
return common.Version
|
||||
|
|
|
@ -142,6 +142,34 @@ func TestSubnet_AddNode(t *testing.T) {
|
|||
cOwn.InvokeFail(t, method+errSeparator+"node has already been added", method, id, nodePub)
|
||||
}
|
||||
|
||||
func TestSubnet_RemoveNode(t *testing.T) {
|
||||
e := newSubnetInvoker(t)
|
||||
|
||||
id, owner := createSubnet(t, e)
|
||||
|
||||
node := e.NewAccount(t)
|
||||
nodePub, ok := vm.ParseSignatureContract(node.Script())
|
||||
require.True(t, ok)
|
||||
|
||||
adm := e.NewAccount(t)
|
||||
admPub, ok := vm.ParseSignatureContract(adm.Script())
|
||||
require.True(t, ok)
|
||||
|
||||
const method = "removeNode"
|
||||
|
||||
cOwn := e.WithSigners(owner)
|
||||
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrInvalidAdmin, method, id, nodePub[1:])
|
||||
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrNodeNotExist, method, id, nodePub)
|
||||
|
||||
cOwn.Invoke(t, stackitem.Null{}, "addNode", id, nodePub)
|
||||
cOwn.Invoke(t, stackitem.Null{}, method, id, nodePub)
|
||||
|
||||
cAdm := cOwn.WithSigners(adm)
|
||||
|
||||
cOwn.Invoke(t, stackitem.Null{}, "addNodeAdmin", id, admPub)
|
||||
cAdm.InvokeFail(t, method+errSeparator+subnet.ErrNodeNotExist, method, id, nodePub)
|
||||
}
|
||||
|
||||
func createSubnet(t *testing.T, e *neotest.ContractInvoker) (id []byte, owner neotest.Signer) {
|
||||
var (
|
||||
ok bool
|
||||
|
|
Loading…
Reference in a new issue