[#174] subnet: Add `RemoveNodeAdmin` method

Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
enable-notary-in-public-chains
Pavel Karpy 2021-11-22 17:20:00 +03:00 committed by LeL
parent 840e206963
commit cee4dd76dc
2 changed files with 102 additions and 39 deletions

View File

@ -20,8 +20,12 @@ const (
ErrInvalidAdmin = "invalid administrator"
// ErrAlreadyExists is thrown when id already exists.
ErrAlreadyExists = "subnet id already exists"
// ErrNotExist is thrown when id doesn't exist.
ErrNotExist = "subnet id doesn't exist"
// ErrSubNotExist is thrown when id doesn't exist.
ErrSubNotExist = "subnet id doesn't exist"
// ErrNodeAdmNotExist is thrown when node admin is not found.
ErrNodeAdmNotExist = "node admin not found"
errCheckWitnessFailed = "owner witness check failed"
ownerPrefix = 'o'
nodeAdminPrefix = 'a'
@ -94,7 +98,7 @@ func Put(id []byte, ownerKey interop.PublicKey, info []byte) {
common.RemoveVotes(ctx, id)
} else {
if !runtime.CheckWitness(ownerKey) {
panic("put: owner witness check failed")
panic("put: " + errCheckWitnessFailed)
}
multiaddr := common.AlphabetAddress()
@ -110,11 +114,11 @@ func Put(id []byte, ownerKey interop.PublicKey, info []byte) {
// Get returns info about subnet with the specified id.
func Get(id []byte) []byte {
ctx := storage.GetContext()
ctx := storage.GetReadOnlyContext()
key := append([]byte{infoPrefix}, id...)
raw := storage.Get(ctx, key)
if raw == nil {
panic("get: " + ErrNotExist)
panic("get: " + ErrSubNotExist)
}
return raw.([]byte)
}
@ -125,12 +129,12 @@ func Delete(id []byte) {
key := append([]byte{ownerPrefix}, id...)
raw := storage.Get(ctx, key)
if raw == nil {
panic("delete:" + ErrNotExist)
panic("delete:" + ErrSubNotExist)
}
owner := raw.([]byte)
if !runtime.CheckWitness(owner) {
panic("delete: owner witness check failed")
panic("delete: " + errCheckWitnessFailed)
}
storage.Delete(ctx, key)
@ -153,12 +157,12 @@ func AddNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
rawOwner := storage.Get(ctx, stKey)
if rawOwner == nil {
panic("addNodeAdmin: " + ErrNotExist)
panic("addNodeAdmin: " + ErrSubNotExist)
}
owner := rawOwner.([]byte)
if !runtime.CheckWitness(owner) {
panic("addNodeAdmin: owner witness check failed")
panic("addNodeAdmin: " + errCheckWitnessFailed)
}
stKey[0] = nodeAdminPrefix
@ -175,6 +179,37 @@ func AddNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
storage.Put(ctx, append(stKey, adminKey...), []byte{1})
}
// RemoveNodeAdmin removes node administrator from the specified subnetwork.
// Must be called by subnet owner only.
func RemoveNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
if len(adminKey) != interop.PublicKeyCompressedLen {
panic("removeNodeAdmin: " + ErrInvalidAdmin)
}
ctx := storage.GetContext()
stOwnerKey := append([]byte{ownerPrefix}, subnetID...)
rawOwner := storage.Get(ctx, stOwnerKey)
if rawOwner == nil {
panic("removeNodeAdmin: " + ErrSubNotExist)
}
owner := rawOwner.([]byte)
if !runtime.CheckWitness(owner) {
panic("removeNodeAdmin: " + errCheckWitnessFailed)
}
stOwnerKey[0] = nodeAdminPrefix
stNodeAdmKey := append(stOwnerKey, adminKey...)
if storage.Get(ctx, stNodeAdmKey) == nil {
panic("removeNodeAdmin: " + ErrNodeAdmNotExist)
}
storage.Delete(ctx, stNodeAdmKey)
}
// Version returns version of the contract.
func Version() int {
return common.Version

View File

@ -14,7 +14,11 @@ import (
"github.com/stretchr/testify/require"
)
const subnetPath = "../subnet"
const (
subnetPath = "../subnet"
errSeparator = ": "
)
func deploySubnetContract(t *testing.T, e *neotest.Executor) util.Uint160 {
c := neotest.CompileFile(t, e.CommitteeHash, subnetPath, path.Join(subnetPath, "config.yml"))
@ -61,51 +65,30 @@ func TestSubnet_Put(t *testing.T) {
func TestSubnet_Delete(t *testing.T) {
e := newSubnetInvoker(t)
acc := e.NewAccount(t)
pub, ok := vm.ParseSignatureContract(acc.Script())
require.True(t, ok)
id := make([]byte, 4)
binary.LittleEndian.PutUint32(id, 123)
info := randomBytes(10)
cBoth := e.WithSigners(e.Committee, acc)
cBoth.Invoke(t, stackitem.Null{}, "put", id, pub, info)
id, owner := createSubnet(t, e)
e.InvokeFail(t, "witness check failed", "delete", id)
cAcc := e.WithSigners(acc)
cAcc.InvokeFail(t, subnet.ErrNotExist, "delete", []byte{1, 1, 1, 1})
cAcc := e.WithSigners(owner)
cAcc.InvokeFail(t, subnet.ErrSubNotExist, "delete", []byte{1, 1, 1, 1})
cAcc.Invoke(t, stackitem.Null{}, "delete", id)
cAcc.InvokeFail(t, subnet.ErrNotExist, "get", id)
cAcc.InvokeFail(t, subnet.ErrNotExist, "delete", id)
cAcc.InvokeFail(t, subnet.ErrSubNotExist, "get", id)
cAcc.InvokeFail(t, subnet.ErrSubNotExist, "delete", id)
}
func TestSubnet_AddNodeAdmin(t *testing.T) {
e := newSubnetInvoker(t)
owner := e.NewAccount(t)
pub, ok := vm.ParseSignatureContract(owner.Script())
require.True(t, ok)
id := make([]byte, 4)
binary.LittleEndian.PutUint32(id, 123)
info := randomBytes(10)
cBoth := e.WithSigners(e.Committee, owner)
cBoth.Invoke(t, stackitem.Null{}, "put", id, pub, info)
id, owner := createSubnet(t, e)
adm := e.NewAccount(t)
admPub, ok := vm.ParseSignatureContract(adm.Script())
require.True(t, ok)
const (
method = "addNodeAdmin"
errSeparator = ": "
)
const method = "addNodeAdmin"
e.InvokeFail(t, method+errSeparator+subnet.ErrInvalidAdmin, method, id, admPub[1:])
e.InvokeFail(t, method+errSeparator+subnet.ErrNotExist, method, []byte{0, 0, 0, 0}, admPub)
e.InvokeFail(t, method+errSeparator+subnet.ErrSubNotExist, method, []byte{0, 0, 0, 0}, admPub)
cAdm := e.WithSigners(adm)
cAdm.InvokeFail(t, method+errSeparator+"owner witness check failed", method, id, admPub)
@ -115,3 +98,48 @@ func TestSubnet_AddNodeAdmin(t *testing.T) {
cOwner.InvokeFail(t, method+errSeparator+"node admin has already been added", method, id, admPub)
}
func TestSubnet_RemoveNodeAdmin(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 = "removeNodeAdmin"
e.InvokeFail(t, method+errSeparator+subnet.ErrInvalidAdmin, method, id, admPub[1:])
e.InvokeFail(t, method+errSeparator+subnet.ErrSubNotExist, method, []byte{0, 0, 0, 0}, admPub)
cAdm := e.WithSigners(adm)
cAdm.InvokeFail(t, method+errSeparator+"owner witness check failed", method, id, admPub)
cOwner := e.WithSigners(owner)
cOwner.InvokeFail(t, method+errSeparator+subnet.ErrNodeAdmNotExist, method, id, admPub)
cOwner.Invoke(t, stackitem.Null{}, "addNodeAdmin", id, admPub)
cOwner.Invoke(t, stackitem.Null{}, method, id, admPub)
cOwner.InvokeFail(t, method+errSeparator+subnet.ErrNodeAdmNotExist, method, id, admPub)
}
func createSubnet(t *testing.T, e *neotest.ContractInvoker) (id []byte, owner neotest.Signer) {
var (
ok bool
pub []byte
)
owner = e.NewAccount(t)
pub, ok = vm.ParseSignatureContract(owner.Script())
require.True(t, ok)
id = make([]byte, 4)
binary.LittleEndian.PutUint32(id, 123)
info := randomBytes(10)
cBoth := e.WithSigners(e.Committee, owner)
cBoth.Invoke(t, stackitem.Null{}, "put", id, pub, info)
return
}