[#174] subnet: Add RemoveNodeAdmin method

Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
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" ErrInvalidAdmin = "invalid administrator"
// ErrAlreadyExists is thrown when id already exists. // ErrAlreadyExists is thrown when id already exists.
ErrAlreadyExists = "subnet id already exists" ErrAlreadyExists = "subnet id already exists"
// ErrNotExist is thrown when id doesn't exist. // ErrSubNotExist is thrown when id doesn't exist.
ErrNotExist = "subnet 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' ownerPrefix = 'o'
nodeAdminPrefix = 'a' nodeAdminPrefix = 'a'
@ -94,7 +98,7 @@ func Put(id []byte, ownerKey interop.PublicKey, info []byte) {
common.RemoveVotes(ctx, id) common.RemoveVotes(ctx, id)
} else { } else {
if !runtime.CheckWitness(ownerKey) { if !runtime.CheckWitness(ownerKey) {
panic("put: owner witness check failed") panic("put: " + errCheckWitnessFailed)
} }
multiaddr := common.AlphabetAddress() 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. // Get returns info about subnet with the specified id.
func Get(id []byte) []byte { func Get(id []byte) []byte {
ctx := storage.GetContext() ctx := storage.GetReadOnlyContext()
key := append([]byte{infoPrefix}, id...) key := append([]byte{infoPrefix}, id...)
raw := storage.Get(ctx, key) raw := storage.Get(ctx, key)
if raw == nil { if raw == nil {
panic("get: " + ErrNotExist) panic("get: " + ErrSubNotExist)
} }
return raw.([]byte) return raw.([]byte)
} }
@ -125,12 +129,12 @@ func Delete(id []byte) {
key := append([]byte{ownerPrefix}, id...) key := append([]byte{ownerPrefix}, id...)
raw := storage.Get(ctx, key) raw := storage.Get(ctx, key)
if raw == nil { if raw == nil {
panic("delete:" + ErrNotExist) panic("delete:" + ErrSubNotExist)
} }
owner := raw.([]byte) owner := raw.([]byte)
if !runtime.CheckWitness(owner) { if !runtime.CheckWitness(owner) {
panic("delete: owner witness check failed") panic("delete: " + errCheckWitnessFailed)
} }
storage.Delete(ctx, key) storage.Delete(ctx, key)
@ -153,12 +157,12 @@ func AddNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
rawOwner := storage.Get(ctx, stKey) rawOwner := storage.Get(ctx, stKey)
if rawOwner == nil { if rawOwner == nil {
panic("addNodeAdmin: " + ErrNotExist) panic("addNodeAdmin: " + ErrSubNotExist)
} }
owner := rawOwner.([]byte) owner := rawOwner.([]byte)
if !runtime.CheckWitness(owner) { if !runtime.CheckWitness(owner) {
panic("addNodeAdmin: owner witness check failed") panic("addNodeAdmin: " + errCheckWitnessFailed)
} }
stKey[0] = nodeAdminPrefix stKey[0] = nodeAdminPrefix
@ -175,6 +179,37 @@ func AddNodeAdmin(subnetID []byte, adminKey interop.PublicKey) {
storage.Put(ctx, append(stKey, adminKey...), []byte{1}) 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. // Version returns version of the contract.
func Version() int { func Version() int {
return common.Version return common.Version

View file

@ -14,7 +14,11 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
const subnetPath = "../subnet" const (
subnetPath = "../subnet"
errSeparator = ": "
)
func deploySubnetContract(t *testing.T, e *neotest.Executor) util.Uint160 { func deploySubnetContract(t *testing.T, e *neotest.Executor) util.Uint160 {
c := neotest.CompileFile(t, e.CommitteeHash, subnetPath, path.Join(subnetPath, "config.yml")) 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) { func TestSubnet_Delete(t *testing.T) {
e := newSubnetInvoker(t) e := newSubnetInvoker(t)
acc := e.NewAccount(t) id, owner := createSubnet(t, e)
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)
e.InvokeFail(t, "witness check failed", "delete", id) e.InvokeFail(t, "witness check failed", "delete", id)
cAcc := e.WithSigners(acc) cAcc := e.WithSigners(owner)
cAcc.InvokeFail(t, subnet.ErrNotExist, "delete", []byte{1, 1, 1, 1}) cAcc.InvokeFail(t, subnet.ErrSubNotExist, "delete", []byte{1, 1, 1, 1})
cAcc.Invoke(t, stackitem.Null{}, "delete", id) cAcc.Invoke(t, stackitem.Null{}, "delete", id)
cAcc.InvokeFail(t, subnet.ErrNotExist, "get", id) cAcc.InvokeFail(t, subnet.ErrSubNotExist, "get", id)
cAcc.InvokeFail(t, subnet.ErrNotExist, "delete", id) cAcc.InvokeFail(t, subnet.ErrSubNotExist, "delete", id)
} }
func TestSubnet_AddNodeAdmin(t *testing.T) { func TestSubnet_AddNodeAdmin(t *testing.T) {
e := newSubnetInvoker(t) e := newSubnetInvoker(t)
owner := e.NewAccount(t) id, owner := createSubnet(t, e)
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)
adm := e.NewAccount(t) adm := e.NewAccount(t)
admPub, ok := vm.ParseSignatureContract(adm.Script()) admPub, ok := vm.ParseSignatureContract(adm.Script())
require.True(t, ok) require.True(t, ok)
const ( const method = "addNodeAdmin"
method = "addNodeAdmin"
errSeparator = ": "
)
e.InvokeFail(t, method+errSeparator+subnet.ErrInvalidAdmin, method, id, admPub[1:]) 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 := e.WithSigners(adm)
cAdm.InvokeFail(t, method+errSeparator+"owner witness check failed", method, id, admPub) 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) 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
}