forked from TrueCloudLab/frostfs-contract
[#52] policy: Add admin
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
parent
20f86e96b2
commit
e56e8d02ee
3 changed files with 88 additions and 8 deletions
|
@ -1,2 +1,6 @@
|
|||
name: "APE"
|
||||
safemethods: ["listChains","getChain","listChainsByPrefix"]
|
||||
safemethods:
|
||||
- "getAdmin"
|
||||
- "listChains"
|
||||
- "getChain"
|
||||
- "listChainsByPrefix"
|
||||
|
|
|
@ -2,7 +2,9 @@ package policy
|
|||
|
||||
import (
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/common"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
||||
)
|
||||
|
||||
|
@ -16,8 +18,65 @@ const (
|
|||
IAM = 'i'
|
||||
)
|
||||
|
||||
const (
|
||||
ownerKeyPrefix = 'o'
|
||||
)
|
||||
|
||||
const (
|
||||
// ErrNotAutorized is returned when the none of the transaction signers
|
||||
// belongs to the list of autorized keys.
|
||||
ErrNotAutorized = "none of the signers is not autorized to change the contract"
|
||||
)
|
||||
|
||||
// _deploy function sets up initial list of inner ring public keys.
|
||||
func _deploy(data any, isUpdate bool) {
|
||||
if isUpdate {
|
||||
return
|
||||
}
|
||||
|
||||
args := data.(struct {
|
||||
Admin interop.Hash160
|
||||
})
|
||||
ctx := storage.GetContext()
|
||||
if args.Admin != nil {
|
||||
if len(args.Admin) != 20 {
|
||||
panic("invaliad admin hash length")
|
||||
}
|
||||
storage.Put(ctx, ownerKey(args.Admin), []byte{1})
|
||||
}
|
||||
}
|
||||
|
||||
func ownerKey(sender interop.Hash160) []byte {
|
||||
return append([]byte{ownerKeyPrefix}, sender...)
|
||||
}
|
||||
|
||||
func checkAuthorization(ctx storage.Context) {
|
||||
if runtime.CheckWitness(common.AlphabetAddress()) {
|
||||
return
|
||||
}
|
||||
|
||||
admin := getAdmin(ctx)
|
||||
if admin != nil && runtime.CheckWitness(admin) {
|
||||
return
|
||||
}
|
||||
|
||||
panic(ErrNotAutorized)
|
||||
}
|
||||
|
||||
func SetAdmin(addr interop.Hash160) {
|
||||
common.CheckAlphabetWitness()
|
||||
|
||||
ctx := storage.GetContext()
|
||||
storage.Put(ctx, []byte{ownerKeyPrefix}, addr)
|
||||
}
|
||||
|
||||
func GetAdmin() interop.Hash160 {
|
||||
ctx := storage.GetReadOnlyContext()
|
||||
return getAdmin(ctx)
|
||||
}
|
||||
|
||||
func getAdmin(ctx storage.Context) interop.Hash160 {
|
||||
return storage.Get(ctx, []byte{ownerKeyPrefix}).(interop.Hash160)
|
||||
}
|
||||
|
||||
func storageKey(prefix Kind, entityName, name string) []byte {
|
||||
|
@ -28,9 +87,9 @@ func storageKey(prefix Kind, entityName, name string) []byte {
|
|||
}
|
||||
|
||||
func AddChain(entity Kind, entityName, name string, chain []byte) {
|
||||
common.CheckAlphabetWitness() // TODO: Allow to work with chain directly for everyone?
|
||||
|
||||
ctx := storage.GetContext()
|
||||
checkAuthorization(ctx)
|
||||
|
||||
key := storageKey(entity, entityName, name)
|
||||
storage.Put(ctx, key, chain)
|
||||
}
|
||||
|
@ -47,17 +106,17 @@ func GetChain(entity Kind, entityName, name string) []byte {
|
|||
}
|
||||
|
||||
func RemoveChain(entity Kind, entityName string, name string) {
|
||||
common.CheckAlphabetWitness()
|
||||
|
||||
ctx := storage.GetContext()
|
||||
checkAuthorization(ctx)
|
||||
|
||||
key := storageKey(entity, entityName, name)
|
||||
storage.Delete(ctx, key)
|
||||
}
|
||||
|
||||
func RemoveChainsByPrefix(entity Kind, entityName string, name string) {
|
||||
common.CheckAlphabetWitness()
|
||||
|
||||
ctx := storage.GetContext()
|
||||
checkAuthorization(ctx)
|
||||
|
||||
key := storageKey(entity, entityName, name)
|
||||
it := storage.Find(ctx, key, storage.KeysOnly)
|
||||
for iterator.Next(it) {
|
||||
|
|
|
@ -18,7 +18,7 @@ const policyPath = "../policy"
|
|||
func deployPolicyContract(t *testing.T, e *neotest.Executor) util.Uint160 {
|
||||
cfgPath := path.Join(policyPath, "config.yml")
|
||||
c := neotest.CompileFile(t, e.CommitteeHash, policyPath, cfgPath)
|
||||
e.DeployContract(t, c, nil)
|
||||
e.DeployContract(t, c, []any{nil})
|
||||
return c.Hash
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,23 @@ func TestPolicy(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAutorization(t *testing.T) {
|
||||
e := newPolicyInvoker(t)
|
||||
|
||||
e.Invoke(t, stackitem.Null{}, "getAdmin")
|
||||
|
||||
s := e.NewAccount(t, 1_0000_0000)
|
||||
c := e.WithSigners(s)
|
||||
|
||||
args := []any{policy.Container, "cnr1", "ingress:myrule3", []byte("opaque")}
|
||||
c.InvokeFail(t, policy.ErrNotAutorized, "addChain", args...)
|
||||
|
||||
e.Invoke(t, stackitem.Null{}, "setAdmin", s.ScriptHash())
|
||||
e.Invoke(t, stackitem.NewBuffer(s.ScriptHash().BytesBE()), "getAdmin")
|
||||
|
||||
c.Invoke(t, stackitem.Null{}, "addChain", args...)
|
||||
}
|
||||
|
||||
func checkChains(t *testing.T, e *neotest.ContractInvoker, namespace, container, name string, expected [][]byte) {
|
||||
s, err := e.TestInvoke(t, "listChains", namespace, container, name)
|
||||
require.NoError(t, err)
|
||||
|
|
Loading…
Reference in a new issue