contract/enterprise/config.go
package enterprise
import (
"fmt"
"strings"
"github.com/aergoio/aergo/v2/state/statedb"
"github.com/aergoio/aergo/v2/types"
"github.com/aergoio/aergo/v2/types/dbkey"
)
const (
RPCPermissions = "RPCPERMISSIONS"
P2PWhite = "P2PWHITE"
P2PBlack = "P2PBLACK"
AccountWhite = "ACCOUNTWHITE"
)
// EnterpriseKeyDict is represent allowed key list and used when validate tx, int values are meaningless.
var enterpriseKeyDict = map[string]int{
RPCPermissions: 1,
P2PWhite: 2,
P2PBlack: 3,
AccountWhite: 4,
}
type Conf struct {
On bool
Values []string
}
func (c *Conf) AppendValue(r string) {
if c.Values == nil {
c.Values = []string{}
}
c.Values = append(c.Values, r)
}
func (c *Conf) RemoveValue(r string) {
for i, v := range c.Values {
if v == r {
c.Values = append(c.Values[:i], c.Values[i+1:]...)
break
}
}
}
func (c *Conf) Validate(key []byte, context *EnterpriseContext) error {
if !c.On {
return nil
}
strKey := strings.ToUpper(string(key))
switch strKey {
case RPCPermissions:
for _, v := range c.Values {
if strings.Contains(strings.ToUpper(strings.Split(v, ":")[1]), "W") {
return nil
}
}
return fmt.Errorf("the values of %s should have at least one write permission", strKey)
case AccountWhite:
for _, v := range context.Admins {
address := types.EncodeAddress(v)
if context.HasConfValue(address) {
return nil
}
}
return fmt.Errorf("the values of %s should have at least one admin address", strKey)
default:
return nil
}
}
func GetConf(ecs *statedb.ContractState, key string) (*types.EnterpriseConfig, error) {
ret := &types.EnterpriseConfig{Key: key}
if strings.ToUpper(key) == "PERMISSIONS" {
for k := range enterpriseKeyDict {
ret.Values = append(ret.Values, k)
}
} else {
conf, err := getConf(ecs, []byte(key))
if err != nil {
return nil, err
}
if conf != nil {
ret.On = conf.On
ret.Values = conf.Values
}
}
return ret, nil
}
func enableConf(scs *statedb.ContractState, key []byte, value bool) (*Conf, error) {
conf, err := getConf(scs, key)
if err != nil {
return nil, err
}
if conf != nil {
conf.On = value
} else {
conf = &Conf{On: value}
}
return conf, nil
}
func getConf(scs *statedb.ContractState, key []byte) (*Conf, error) {
data, err := scs.GetData(dbkey.EnterpriseConf(key))
if err != nil || data == nil {
return nil, err
}
return deserializeConf(data), err
}
func setConfValues(scs *statedb.ContractState, key []byte, values []string) (*Conf, error) {
conf, err := getConf(scs, key)
if err != nil {
return nil, err
}
if conf != nil {
conf.Values = values
} else {
conf = &Conf{Values: values}
}
return conf, nil
}
func setConf(scs *statedb.ContractState, key []byte, conf *Conf) error {
return scs.SetData(dbkey.EnterpriseConf(key), serializeConf(conf))
}
func serializeConf(c *Conf) []byte {
var ret []byte
if c.On {
ret = append(ret, 1)
} else {
ret = append(ret, 0)
}
for _, v := range c.Values {
ret = append(ret, '\\')
ret = append(ret, []byte(v)...)
}
return ret
}
func deserializeConf(data []byte) *Conf {
ret := &Conf{
On: false,
Values: strings.Split(string(data), "\\")[1:],
}
if data[0] == 1 {
ret.On = true
}
return ret
}