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" ) // Kind represents the object the chain is attached to. // Currently only namespace and container are supported. type Kind byte const ( Namespace = 'n' Container = 'c' IAM = 'i' ) const ( ownerKeyPrefix = 'o' ) const ( // ErrNotAuthorized is returned when the none of the transaction signers // belongs to the list of autorized keys. ErrNotAuthorized = "none of the signers is authorized 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, []byte{ownerKeyPrefix}, args.Admin) } } func checkAuthorization(ctx storage.Context) { admin := getAdmin(ctx) if admin != nil && runtime.CheckWitness(admin) { return } if runtime.CheckWitness(common.AlphabetAddress()) { return } panic(ErrNotAuthorized) } // Version returns the version of the contract. func Version() int { return common.Version } 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 string, name []byte) []byte { ln := len(entityName) key := append([]byte{byte(prefix)}, byte(ln&0xFF), byte(ln>>8)) key = append(key, entityName...) return append(key, name...) } func AddChain(entity Kind, entityName string, name []byte, chain []byte) { ctx := storage.GetContext() checkAuthorization(ctx) key := storageKey(entity, entityName, name) storage.Put(ctx, key, chain) } func GetChain(entity Kind, entityName string, name []byte) []byte { ctx := storage.GetReadOnlyContext() key := storageKey(entity, entityName, name) data := storage.Get(ctx, key).([]byte) if data == nil { panic("not found") } return data } func RemoveChain(entity Kind, entityName string, name []byte) { ctx := storage.GetContext() checkAuthorization(ctx) key := storageKey(entity, entityName, name) storage.Delete(ctx, key) } func RemoveChainsByPrefix(entity Kind, entityName string, name []byte) { ctx := storage.GetContext() checkAuthorization(ctx) key := storageKey(entity, entityName, name) it := storage.Find(ctx, key, storage.KeysOnly) for iterator.Next(it) { storage.Delete(ctx, iterator.Value(it).([]byte)) } } // ListChains lists all chains for the namespace by prefix. // container may be empty. func ListChains(namespace, container string, name []byte) [][]byte { result := ListChainsByPrefix(Namespace, namespace, name) if container != "" { result = append(result, ListChainsByPrefix(Container, container, name)...) } return result } // ListChainsByPrefix list all chains for the provided kind and entity by prefix. func ListChainsByPrefix(entity Kind, entityName string, prefix []byte) [][]byte { ctx := storage.GetReadOnlyContext() result := [][]byte{} keyPrefix := storageKey(entity, entityName, prefix) it := storage.Find(ctx, keyPrefix, storage.ValuesOnly) for iterator.Next(it) { result = append(result, iterator.Value(it).([]byte)) } return result }