func (pm *ManagerImpl) ProposePolicy(tx interface{}, key string, configPolicy *cb.ConfigPolicy) (proto.Message, error) {
	pm.pendingLock.RLock()
	pendingConfig, ok := pm.pendingConfig[tx]
	pm.pendingLock.RUnlock()
	if !ok {
		logger.Panicf("Serious Programming error: called Propose without Begin")
	}
	policy := configPolicy.Policy
	if policy == nil {
		return nil, fmt.Errorf("Policy cannot be nil")
	}
	var cPolicy Policy
	var deserialized proto.Message
	if policy.Type == int32(cb.Policy_IMPLICIT_META) {
		imp, err := newImplicitMetaPolicy(policy.Value)
		if err != nil {
			return nil, err
		}
		pendingConfig.imps = append(pendingConfig.imps, imp)
		cPolicy = imp
		deserialized = imp.conf
	} else {
		provider, ok := pm.providers[int32(policy.Type)]
		if !ok {
			return nil, fmt.Errorf("Unknown policy type: %v", policy.Type)
		}
		var err error
		cPolicy, deserialized, err = provider.NewPolicy(policy.Value)
		if err != nil {
			return nil, err
		}
	}
	pendingConfig.policies[key] = cPolicy
	logger.Debugf("Proposed new policy %s for %s", key, pm.basePath)
	return deserialized, nil
}
ProposePolicy takes key, path, and ConfigPolicy and registers it in the proposed PolicyManager, or errors
It also returns the deserialized policy value for tracking and inspection at the invocation side.
package policies
import (
	"fmt"
	"strings"
	"sync"
	cb "github.com/inklabsfoundation/inkchain/protos/common"
	"github.com/golang/protobuf/proto"
	"github.com/inklabsfoundation/inkchain/common/flogging"
	logging "github.com/op/go-logging"
)
const (
	PathSeparator = "/"
	ChannelPrefix = "Channel"
	ApplicationPrefix = "Application"
	OrdererPrefix = "Orderer"
	ChannelReaders = PathSeparator + ChannelPrefix + PathSeparator + "Readers"
	ChannelWriters = PathSeparator + ChannelPrefix + PathSeparator + "Writers"
	ChannelApplicationReaders = PathSeparator + ChannelPrefix + PathSeparator + ApplicationPrefix + PathSeparator + "Readers"
	ChannelApplicationWriters = PathSeparator + ChannelPrefix + PathSeparator + ApplicationPrefix + PathSeparator + "Writers"
	ChannelApplicationAdmins = PathSeparator + ChannelPrefix + PathSeparator + ApplicationPrefix + PathSeparator + "Admins"
	BlockValidation = PathSeparator + ChannelPrefix + PathSeparator + OrdererPrefix + PathSeparator + "BlockValidation"
)
var logger = flogging.MustGetLogger("policies")
type Policy interface {
	Evaluate(signatureSet []*cb.SignedData) error
}
type Manager interface {
	GetPolicy(id string) (Policy, bool)
	Manager(path []string) (Manager, bool)
	BasePath() string
	PolicyNames() []string
}
type Proposer interface {
	BeginPolicyProposals(tx interface{}, groups []string) ([]Proposer, error)
	ProposePolicy(tx interface{}, name string, policy *cb.ConfigPolicy) (proto.Message, error)
	RollbackProposals(tx interface{})
	CommitProposals(tx interface{})
	PreCommit(tx interface{}) error
}
type Provider interface {
	NewPolicy(data []byte) (Policy, proto.Message, error)
}
type ChannelPolicyManagerGetter interface {
	Manager(channelID string) (Manager, bool)
}
type policyConfig struct {
	policies map[string]Policy
	managers map[string]*ManagerImpl
	imps     []*implicitMetaPolicy
}
type ManagerImpl struct {
	parent        *ManagerImpl
	basePath      string
	fqPrefix      string
	providers     map[int32]Provider
	config        *policyConfig
	pendingConfig map[interface{}]*policyConfig
	pendingLock   sync.RWMutex
	SuppressSanityLogMessages bool
}
func NewManagerImpl(basePath string, providers map[int32]Provider) *ManagerImpl {
	_, ok := providers[int32(cb.Policy_IMPLICIT_META)]
	if ok {
		logger.Panicf("ImplicitMetaPolicy type must be provider by the policy manager")
	}
	return &ManagerImpl{
		basePath:  basePath,
		fqPrefix:  PathSeparator + basePath + PathSeparator,
		providers: providers,
		config: &policyConfig{
			policies: make(map[string]Policy),
			managers: make(map[string]*ManagerImpl),
		},
		pendingConfig: make(map[interface{}]*policyConfig),
	}
}
type rejectPolicy string
func (rp rejectPolicy) Evaluate(signedData []*cb.SignedData) error {
	return fmt.Errorf("No such policy type: %s", rp)
}
func (pm *ManagerImpl) BasePath() string {
	return pm.basePath
}
func (pm *ManagerImpl) PolicyNames() []string {
	policyNames := make([]string, len(pm.config.policies))
	i := 0
	for policyName := range pm.config.policies {
		policyNames[i] = policyName
		i++
	}
	return policyNames
}
func (pm *ManagerImpl) Manager(path []string) (Manager, bool) {
	if len(path) == 0 {
		return pm, true
	}
	m, ok := pm.config.managers[path[0]]
	if !ok {
		return nil, false
	}
	return m.Manager(path[1:])
}
func (pm *ManagerImpl) GetPolicy(id string) (Policy, bool) {
	if id == "" {
		logger.Errorf("Returning dummy reject all policy because no policy ID supplied")
		return rejectPolicy(id), false
	}
	var relpath string
	if strings.HasPrefix(id, PathSeparator) {
		if pm.parent != nil {
			return pm.parent.GetPolicy(id)
		}
		if !strings.HasPrefix(id, pm.fqPrefix) {
			if logger.IsEnabledFor(logging.DEBUG) {
				logger.Debugf("Requested policy from root manager with wrong basePath: %s, returning rejectAll", id)
			}
			return rejectPolicy(id), false
		}
		relpath = id[len(pm.fqPrefix):]
	} else {
		relpath = id
	}
	policy, ok := pm.config.policies[relpath]
	if !ok {
		if logger.IsEnabledFor(logging.DEBUG) {
			logger.Debugf("Returning dummy reject all policy because %s could not be found in /%s/%s", id, pm.basePath, relpath)
		}
		return rejectPolicy(relpath), false
	}
	if logger.IsEnabledFor(logging.DEBUG) {
		logger.Debugf("Returning policy %s for evaluation", relpath)
	}
	return policy, true
}
func (pm *ManagerImpl) BeginPolicyProposals(tx interface{}, groups []string) ([]Proposer, error) {
	pm.pendingLock.Lock()
	defer pm.pendingLock.Unlock()
	pendingConfig, ok := pm.pendingConfig[tx]
	if ok {
		logger.Panicf("Serious Programming error: cannot call begin multiply for the same proposal")
	}
	pendingConfig = &policyConfig{
		policies: make(map[string]Policy),
		managers: make(map[string]*ManagerImpl),
	}
	pm.pendingConfig[tx] = pendingConfig
	managers := make([]Proposer, len(groups))
	for i, group := range groups {
		newManager := NewManagerImpl(group, pm.providers)
		newManager.parent = pm
		pendingConfig.managers[group] = newManager
		managers[i] = newManager
	}
	return managers, nil
}
func (pm *ManagerImpl) RollbackProposals(tx interface{}) {
	pm.pendingLock.Lock()
	defer pm.pendingLock.Unlock()
	delete(pm.pendingConfig, tx)
}
func (pm *ManagerImpl) PreCommit(tx interface{}) error {
	return nil
}
func (pm *ManagerImpl) CommitProposals(tx interface{}) {
	pm.pendingLock.Lock()
	defer pm.pendingLock.Unlock()
	pendingConfig, ok := pm.pendingConfig[tx]
	if !ok {
		logger.Panicf("Programming error, cannot call begin in the middle of a proposal")
	}
	if pendingConfig == nil {
		logger.Panicf("Programming error, cannot call commit without an existing proposal")
	}
	for managerPath, m := range pendingConfig.managers {
		for _, policyName := range m.PolicyNames() {
			fqKey := managerPath + PathSeparator + policyName
			pendingConfig.policies[fqKey], _ = m.GetPolicy(policyName)
			logger.Debugf("In commit adding relative sub-policy %s to %s", fqKey, pm.basePath)
		}
	}
	for _, imp := range pendingConfig.imps {
		imp.initialize(pendingConfig)
	}
	pm.config = pendingConfig
	delete(pm.pendingConfig, tx)
	if pm.parent == nil && pm.basePath == ChannelPrefix && !pm.SuppressSanityLogMessages {
		for _, policyName := range []string{ChannelReaders, ChannelWriters} {
			_, ok := pm.GetPolicy(policyName)
			if !ok {
				logger.Warningf("Current configuration has no policy '%s', this will likely cause problems in production systems", policyName)
			} else {
				logger.Debugf("As expected, current configuration has policy '%s'", policyName)
			}
		}
		if _, ok := pm.config.managers[ApplicationPrefix]; ok {
			for _, policyName := range []string{
				ChannelApplicationReaders,
				ChannelApplicationWriters,
				ChannelApplicationAdmins} {
				_, ok := pm.GetPolicy(policyName)
				if !ok {
					logger.Warningf("Current configuration has no policy '%s', this will likely cause problems in production systems", policyName)
				} else {
					logger.Debugf("As expected, current configuration has policy '%s'", policyName)
				}
			}
		}
		if _, ok := pm.config.managers[OrdererPrefix]; ok {
			for _, policyName := range []string{BlockValidation} {
				_, ok := pm.GetPolicy(policyName)
				if !ok {
					logger.Warningf("Current configuration has no policy '%s', this will likely cause problems in production systems", policyName)
				} else {
					logger.Debugf("As expected, current configuration has policy '%s'", policyName)
				}
			}
		}
	}
}