forked from TrueCloudLab/frostfs-contract
[#174] subnet: Add AddNode
method
Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
parent
cee4dd76dc
commit
18b5e56727
2 changed files with 83 additions and 7 deletions
|
@ -24,6 +24,8 @@ const (
|
||||||
ErrSubNotExist = "subnet id doesn't exist"
|
ErrSubNotExist = "subnet id doesn't exist"
|
||||||
// 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"
|
||||||
|
// ErrAccessDenied is thrown when operation is denied for caller.
|
||||||
|
ErrAccessDenied = "access denied"
|
||||||
|
|
||||||
errCheckWitnessFailed = "owner witness check failed"
|
errCheckWitnessFailed = "owner witness check failed"
|
||||||
|
|
||||||
|
@ -166,15 +168,10 @@ func AddNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
stKey[0] = nodeAdminPrefix
|
stKey[0] = nodeAdminPrefix
|
||||||
prefixLen := len(stKey)
|
|
||||||
|
|
||||||
iter := storage.Find(ctx, stKey, storage.KeysOnly)
|
if keyInList(ctx, adminKey, stKey) {
|
||||||
for iterator.Next(iter) {
|
|
||||||
key := iterator.Value(iter).([]byte)
|
|
||||||
if util.Equals(string(key[prefixLen:]), string(adminKey)) {
|
|
||||||
panic("addNodeAdmin: node admin has already been added")
|
panic("addNodeAdmin: node admin has already been added")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
storage.Put(ctx, append(stKey, adminKey...), []byte{1})
|
storage.Put(ctx, append(stKey, adminKey...), []byte{1})
|
||||||
}
|
}
|
||||||
|
@ -210,7 +207,68 @@ func RemoveNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
|
||||||
storage.Delete(ctx, stNodeAdmKey)
|
storage.Delete(ctx, stNodeAdmKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddNode adds node to the specified subnetwork.
|
||||||
|
// Must be called by subnet's owner or node administrator
|
||||||
|
// only.
|
||||||
|
func AddNode(subnetID []byte, node interop.PublicKey) {
|
||||||
|
if len(node) != interop.PublicKeyCompressedLen {
|
||||||
|
panic("addNode: " + ErrInvalidAdmin)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := storage.GetContext()
|
||||||
|
|
||||||
|
stKey := append([]byte{ownerPrefix}, subnetID...)
|
||||||
|
prefixLen := len(stKey)
|
||||||
|
|
||||||
|
rawOwner := storage.Get(ctx, stKey)
|
||||||
|
if rawOwner == nil {
|
||||||
|
panic("addNode: " + 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("addNode: " + ErrAccessDenied)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stKey[0] = nodePrefix
|
||||||
|
|
||||||
|
if keyInList(ctx, node, stKey) {
|
||||||
|
panic("addNode: node has already been added")
|
||||||
|
}
|
||||||
|
|
||||||
|
storage.Put(ctx, append(stKey, node...), []byte{1})
|
||||||
|
}
|
||||||
|
|
||||||
// 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 {
|
||||||
|
prefixLen := len(prefix)
|
||||||
|
|
||||||
|
iter := storage.Find(ctx, prefix, storage.KeysOnly)
|
||||||
|
for iterator.Next(iter) {
|
||||||
|
key := iterator.Value(iter).([]byte)
|
||||||
|
if util.Equals(string(key[prefixLen:]), string(searchedKey)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -124,6 +124,24 @@ func TestSubnet_RemoveNodeAdmin(t *testing.T) {
|
||||||
cOwner.InvokeFail(t, method+errSeparator+subnet.ErrNodeAdmNotExist, method, id, admPub)
|
cOwner.InvokeFail(t, method+errSeparator+subnet.ErrNodeAdmNotExist, method, id, admPub)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSubnet_AddNode(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)
|
||||||
|
|
||||||
|
const method = "addNode"
|
||||||
|
|
||||||
|
cOwn := e.WithSigners(owner)
|
||||||
|
cOwn.InvokeFail(t, method+errSeparator+subnet.ErrInvalidAdmin, method, id, nodePub[1:])
|
||||||
|
|
||||||
|
cOwn.Invoke(t, stackitem.Null{}, method, id, nodePub)
|
||||||
|
cOwn.InvokeFail(t, method+errSeparator+"node has already been added", method, id, nodePub)
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
Loading…
Reference in a new issue