github.com/aergoio/aergo@v1.3.1/contract/enterprise/config.go (about)

     1  package enterprise
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/aergoio/aergo/state"
     8  	"github.com/aergoio/aergo/types"
     9  )
    10  
    11  var confPrefix = []byte("conf\\")
    12  
    13  const (
    14  	RPCPermissions = "RPCPERMISSIONS"
    15  	P2PWhite       = "P2PWHITE"
    16  	P2PBlack       = "P2PBLACK"
    17  	AccountWhite   = "ACCOUNTWHITE"
    18  )
    19  
    20  //EnterpriseKeyDict is represent allowed key list and used when validate tx, int values are meaningless.
    21  var enterpriseKeyDict = map[string]int{
    22  	RPCPermissions: 1,
    23  	P2PWhite:       2,
    24  	P2PBlack:       3,
    25  	AccountWhite:   4,
    26  }
    27  
    28  type Conf struct {
    29  	On     bool
    30  	Values []string
    31  }
    32  
    33  func (c *Conf) AppendValue(r string) {
    34  	if c.Values == nil {
    35  		c.Values = []string{}
    36  	}
    37  	c.Values = append(c.Values, r)
    38  }
    39  func (c *Conf) RemoveValue(r string) {
    40  	for i, v := range c.Values {
    41  		if v == r {
    42  			c.Values = append(c.Values[:i], c.Values[i+1:]...)
    43  			break
    44  		}
    45  	}
    46  }
    47  
    48  func (c *Conf) Validate(key []byte, context *EnterpriseContext) error {
    49  	if !c.On {
    50  		return nil
    51  	}
    52  	strKey := string(key)
    53  	switch strKey {
    54  	case RPCPermissions:
    55  		for _, v := range c.Values {
    56  			if strings.Contains(strings.ToUpper(strings.Split(v, ":")[1]), "W") {
    57  				return nil
    58  			}
    59  		}
    60  		return fmt.Errorf("the values of %s should have at least one write permission", strKey)
    61  	case AccountWhite:
    62  		for _, v := range context.Admins {
    63  			address := types.EncodeAddress(v)
    64  			if context.HasConfValue(address) {
    65  				return nil
    66  			}
    67  		}
    68  		return fmt.Errorf("the values of %s should have at least one admin address", strKey)
    69  	default:
    70  		return nil
    71  	}
    72  	return nil
    73  }
    74  
    75  // AccountStateReader is an interface for getting a enterprise account state.
    76  type AccountStateReader interface {
    77  	GetEnterpriseAccountState() (*state.ContractState, error)
    78  }
    79  
    80  func GetConf(r AccountStateReader, key string) (*types.EnterpriseConfig, error) {
    81  	scs, err := r.GetEnterpriseAccountState()
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	ret := &types.EnterpriseConfig{Key: key}
    86  	if strings.ToUpper(key) == "PERMISSIONS" {
    87  		for k, _ := range enterpriseKeyDict {
    88  			ret.Values = append(ret.Values, k)
    89  		}
    90  	} else {
    91  		conf, err := getConf(scs, []byte(key))
    92  		if err != nil {
    93  			return nil, err
    94  		}
    95  		if conf != nil {
    96  			ret.On = conf.On
    97  			ret.Values = conf.Values
    98  		}
    99  	}
   100  	return ret, nil
   101  }
   102  
   103  func enableConf(scs *state.ContractState, key []byte, value bool) (*Conf, error) {
   104  	conf, err := getConf(scs, key)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	if conf != nil {
   109  		conf.On = value
   110  	} else {
   111  		conf = &Conf{On: value}
   112  	}
   113  	return conf, nil
   114  }
   115  
   116  func getConf(scs *state.ContractState, key []byte) (*Conf, error) {
   117  	data, err := scs.GetData(append(confPrefix, genKey(key)...))
   118  	if err != nil || data == nil {
   119  		return nil, err
   120  	}
   121  	return deserializeConf(data), err
   122  }
   123  
   124  func setConfValues(scs *state.ContractState, key []byte, values []string) (*Conf, error) {
   125  	conf, err := getConf(scs, key)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  	if conf != nil {
   130  		conf.Values = values
   131  	} else {
   132  		conf = &Conf{Values: values}
   133  	}
   134  	return conf, nil
   135  }
   136  
   137  func setConf(scs *state.ContractState, key []byte, conf *Conf) error {
   138  	return scs.SetData(append(confPrefix, genKey(key)...), serializeConf(conf))
   139  }
   140  
   141  func serializeConf(c *Conf) []byte {
   142  	var ret []byte
   143  	if c.On {
   144  		ret = append(ret, 1)
   145  	} else {
   146  		ret = append(ret, 0)
   147  	}
   148  	for _, v := range c.Values {
   149  		ret = append(ret, '\\')
   150  		ret = append(ret, []byte(v)...)
   151  	}
   152  	return ret
   153  }
   154  
   155  func deserializeConf(data []byte) *Conf {
   156  	ret := &Conf{
   157  		On:     false,
   158  		Values: strings.Split(string(data), "\\")[1:],
   159  	}
   160  	if data[0] == 1 {
   161  		ret.On = true
   162  	}
   163  	return ret
   164  }
   165  
   166  func genKey(key []byte) []byte {
   167  	return []byte(strings.ToUpper(string(key)))
   168  }