func (cc *ChannelConfig) Validate(tx interface{}, groups map[string]ValueProposer) error {
	for _, validator := range []func() error{
		cc.validateHashingAlgorithm,
		cc.validateBlockDataHashingStructure,
		cc.validateOrdererAddresses,
	} {
		if err := validator(); err != nil {
			return err
		}
	}
	var ok bool
	for key, value := range groups {
		switch key {
		case ApplicationGroupKey:
			cc.appConfig, ok = value.(*ApplicationGroup)
			if !ok {
				return fmt.Errorf("Application group was not Application config")
			}
		case OrdererGroupKey:
			cc.ordererConfig, ok = value.(*OrdererGroup)
			if !ok {
				return fmt.Errorf("Orderer group was not Orderer config")
			}
		case ConsortiumsGroupKey:
			cc.consortiumsConfig, ok = value.(*ConsortiumsGroup)
			if !ok {
				return fmt.Errorf("Consortiums group was no Consortium config")
			}
		default:
			return fmt.Errorf("Disallowed channel group: %s", key)
		}
	}
	return nil
}
Validate inspects the generated configuration protos, ensures that the values are correct, and
sets the ChannelConfig fields that may be referenced after Commit
package config
import (
	"fmt"
	"math"
	"github.com/inklabsfoundation/inkchain/bccsp"
	"github.com/inklabsfoundation/inkchain/common/config/msp"
	"github.com/inklabsfoundation/inkchain/common/util"
	cb "github.com/inklabsfoundation/inkchain/protos/common"
)
const (
	ConsortiumKey = "Consortium"
	HashingAlgorithmKey = "HashingAlgorithm"
	BlockDataHashingStructureKey = "BlockDataHashingStructure"
	OrdererAddressesKey = "OrdererAddresses"
	ChannelGroupKey = "Channel"
)
type ChannelValues interface {
	HashingAlgorithm() func(input []byte) []byte
	BlockDataHashingStructureWidth() uint32
	OrdererAddresses() []string
}
type ChannelProtos struct {
	HashingAlgorithm          *cb.HashingAlgorithm
	BlockDataHashingStructure *cb.BlockDataHashingStructure
	OrdererAddresses          *cb.OrdererAddresses
	Consortium                *cb.Consortium
}
type channelConfigSetter struct {
	target **ChannelConfig
	*ChannelConfig
}
func (ccs *channelConfigSetter) Commit() {
	*(ccs.target) = ccs.ChannelConfig
}
type ChannelGroup struct {
	*ChannelConfig
	*Proposer
	mspConfigHandler *msp.MSPConfigHandler
}
func NewChannelGroup(mspConfigHandler *msp.MSPConfigHandler) *ChannelGroup {
	cg := &ChannelGroup{
		ChannelConfig:    NewChannelConfig(),
		mspConfigHandler: mspConfigHandler,
	}
	cg.Proposer = NewProposer(cg)
	return cg
}
func (cg *ChannelGroup) Allocate() Values {
	return &channelConfigSetter{
		ChannelConfig: NewChannelConfig(),
		target:        &cg.ChannelConfig,
	}
}
func (cg *ChannelGroup) OrdererConfig() *OrdererGroup {
	return cg.ChannelConfig.ordererConfig
}
func (cg *ChannelGroup) ApplicationConfig() *ApplicationGroup {
	return cg.ChannelConfig.appConfig
}
func (cg *ChannelGroup) ConsortiumsConfig() *ConsortiumsGroup {
	return cg.ChannelConfig.consortiumsConfig
}
func (cg *ChannelGroup) NewGroup(group string) (ValueProposer, error) {
	switch group {
	case ApplicationGroupKey:
		return NewApplicationGroup(cg.mspConfigHandler), nil
	case OrdererGroupKey:
		return NewOrdererGroup(cg.mspConfigHandler), nil
	case ConsortiumsGroupKey:
		return NewConsortiumsGroup(cg.mspConfigHandler), nil
	default:
		return nil, fmt.Errorf("Disallowed channel group: %s", group)
	}
}
type ChannelConfig struct {
	*standardValues
	protos *ChannelProtos
	hashingAlgorithm func(input []byte) []byte
	appConfig         *ApplicationGroup
	ordererConfig     *OrdererGroup
	consortiumsConfig *ConsortiumsGroup
}
func NewChannelConfig() *ChannelConfig {
	cc := &ChannelConfig{
		protos: &ChannelProtos{},
	}
	var err error
	cc.standardValues, err = NewStandardValues(cc.protos)
	if err != nil {
		logger.Panicf("Programming error: %s", err)
	}
	return cc
}
func (cc *ChannelConfig) HashingAlgorithm() func(input []byte) []byte {
	return cc.hashingAlgorithm
}
func (cc *ChannelConfig) BlockDataHashingStructureWidth() uint32 {
	return cc.protos.BlockDataHashingStructure.Width
}
func (cc *ChannelConfig) OrdererAddresses() []string {
	return cc.protos.OrdererAddresses.Addresses
}
func (cc *ChannelConfig) ConsortiumName() string {
	return cc.protos.Consortium.Name
}