[#174] subnet: Add `RemoveNode` method

Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
enable-notary-in-public-chains
Pavel Karpy 2021-11-22 21:35:07 +03:00 committed by LeL
parent 18b5e56727
commit 4b47bfadcd
3 changed files with 85 additions and 0 deletions

View File

@ -15,3 +15,9 @@ events:
parameters:
- name: id
type: ByteArray
- name: NodeRemove
parameters:
- name: subnetID
type: ByteArray
- name: node
type: PublicKey

View File

@ -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

View File

@ -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