forked from TrueCloudLab/frostfs-contract
[#174] subnet: Add RemoveNodeAdmin
method
Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
parent
840e206963
commit
cee4dd76dc
2 changed files with 102 additions and 39 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue