Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
246 lines (208 sloc) 7.64 KB
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package channelconfig
import (
cb "github.com/hyperledger/fabric-protos-go/common"
"github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric/common/cauthdsl"
"github.com/hyperledger/fabric/common/configtx"
"github.com/hyperledger/fabric/common/flogging"
"github.com/hyperledger/fabric/common/policies"
"github.com/hyperledger/fabric/msp"
"github.com/hyperledger/fabric/protoutil"
"github.com/pkg/errors"
)
var logger = flogging.MustGetLogger("common.channelconfig")
// RootGroupKey is the key for namespacing the channel config, especially for
// policy evaluation.
const RootGroupKey = "Channel"
// Bundle is a collection of resources which will always have a consistent
// view of the channel configuration. In particular, for a given bundle reference,
// the config sequence, the policy manager etc. will always return exactly the
// same value. The Bundle structure is immutable and will always be replaced in its
// entirety, with new backing memory.
type Bundle struct {
policyManager policies.Manager
channelConfig *ChannelConfig
configtxManager configtx.Validator
}
// PolicyManager returns the policy manager constructed for this config.
func (b *Bundle) PolicyManager() policies.Manager {
return b.policyManager
}
// MSPManager returns the MSP manager constructed for this config.
func (b *Bundle) MSPManager() msp.MSPManager {
return b.channelConfig.MSPManager()
}
// ChannelConfig returns the config.Channel for the chain.
func (b *Bundle) ChannelConfig() Channel {
return b.channelConfig
}
// OrdererConfig returns the config.Orderer for the channel
// and whether the Orderer config exists.
func (b *Bundle) OrdererConfig() (Orderer, bool) {
result := b.channelConfig.OrdererConfig()
return result, result != nil
}
// ConsortiumsConfig returns the config.Consortiums for the channel
// and whether the consortiums config exists.
func (b *Bundle) ConsortiumsConfig() (Consortiums, bool) {
result := b.channelConfig.ConsortiumsConfig()
return result, result != nil
}
// ApplicationConfig returns the configtxapplication.SharedConfig for the channel
// and whether the Application config exists.
func (b *Bundle) ApplicationConfig() (Application, bool) {
result := b.channelConfig.ApplicationConfig()
return result, result != nil
}
// ConfigtxValidator returns the configtx.Validator for the channel.
func (b *Bundle) ConfigtxValidator() configtx.Validator {
return b.configtxManager
}
// ValidateNew checks if a new bundle's contained configuration is valid to be derived from the current bundle.
// This allows checks of the nature "Make sure that the consensus type did not change".
func (b *Bundle) ValidateNew(nb Resources) error {
if oc, ok := b.OrdererConfig(); ok {
noc, ok := nb.OrdererConfig()
if !ok {
return errors.New("current config has orderer section, but new config does not")
}
// Prevent consensus-type migration when channel capabilities ConsensusTypeMigration is disabled
if !b.channelConfig.Capabilities().ConsensusTypeMigration() {
if oc.ConsensusType() != noc.ConsensusType() {
return errors.Errorf("attempted to change consensus type from %s to %s",
oc.ConsensusType(), noc.ConsensusType())
}
}
for orgName, org := range oc.Organizations() {
norg, ok := noc.Organizations()[orgName]
if !ok {
continue
}
mspID := org.MSPID()
if mspID != norg.MSPID() {
return errors.Errorf("orderer org %s attempted to change MSP ID from %s to %s", orgName, mspID, norg.MSPID())
}
}
}
if ac, ok := b.ApplicationConfig(); ok {
nac, ok := nb.ApplicationConfig()
if !ok {
return errors.New("current config has application section, but new config does not")
}
for orgName, org := range ac.Organizations() {
norg, ok := nac.Organizations()[orgName]
if !ok {
continue
}
mspID := org.MSPID()
if mspID != norg.MSPID() {
return errors.Errorf("application org %s attempted to change MSP ID from %s to %s", orgName, mspID, norg.MSPID())
}
}
}
if cc, ok := b.ConsortiumsConfig(); ok {
ncc, ok := nb.ConsortiumsConfig()
if !ok {
return errors.Errorf("current config has consortiums section, but new config does not")
}
for consortiumName, consortium := range cc.Consortiums() {
nconsortium, ok := ncc.Consortiums()[consortiumName]
if !ok {
continue
}
for orgName, org := range consortium.Organizations() {
norg, ok := nconsortium.Organizations()[orgName]
if !ok {
continue
}
mspID := org.MSPID()
if mspID != norg.MSPID() {
return errors.Errorf("consortium %s org %s attempted to change MSP ID from %s to %s", consortiumName, orgName, mspID, norg.MSPID())
}
}
}
} else if _, okNew := nb.ConsortiumsConfig(); okNew {
return errors.Errorf("current config has no consortiums section, but new config does")
}
return nil
}
// NewBundleFromEnvelope wraps the NewBundle function, extracting the needed
// information from a full configtx
func NewBundleFromEnvelope(env *cb.Envelope, bccsp bccsp.BCCSP) (*Bundle, error) {
payload, err := protoutil.UnmarshalPayload(env.Payload)
if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal payload from envelope")
}
configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal config envelope from payload")
}
if payload.Header == nil {
return nil, errors.Errorf("envelope header cannot be nil")
}
chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal channel header")
}
return NewBundle(chdr.ChannelId, configEnvelope.Config, bccsp)
}
// NewBundle creates a new immutable bundle of configuration
func NewBundle(channelID string, config *cb.Config, bccsp bccsp.BCCSP) (*Bundle, error) {
if err := preValidate(config); err != nil {
return nil, err
}
channelConfig, err := NewChannelConfig(config.ChannelGroup, bccsp)
if err != nil {
return nil, errors.Wrap(err, "initializing channelconfig failed")
}
policyProviderMap := make(map[int32]policies.Provider)
for pType := range cb.Policy_PolicyType_name {
rtype := cb.Policy_PolicyType(pType)
switch rtype {
case cb.Policy_UNKNOWN:
// Do not register a handler
case cb.Policy_SIGNATURE:
policyProviderMap[pType] = cauthdsl.NewPolicyProvider(channelConfig.MSPManager())
case cb.Policy_MSP:
// Add hook for MSP Handler here
}
}
policyManager, err := policies.NewManagerImpl(RootGroupKey, policyProviderMap, config.ChannelGroup)
if err != nil {
return nil, errors.Wrap(err, "initializing policymanager failed")
}
configtxManager, err := configtx.NewValidatorImpl(channelID, config, RootGroupKey, policyManager)
if err != nil {
return nil, errors.Wrap(err, "initializing configtx manager failed")
}
return &Bundle{
policyManager: policyManager,
channelConfig: channelConfig,
configtxManager: configtxManager,
}, nil
}
func preValidate(config *cb.Config) error {
if config == nil {
return errors.New("channelconfig Config cannot be nil")
}
if config.ChannelGroup == nil {
return errors.New("config must contain a channel group")
}
if og, ok := config.ChannelGroup.Groups[OrdererGroupKey]; ok {
if _, ok := og.Values[CapabilitiesKey]; !ok {
if _, ok := config.ChannelGroup.Values[CapabilitiesKey]; ok {
return errors.New("cannot enable channel capabilities without orderer support first")
}
if ag, ok := config.ChannelGroup.Groups[ApplicationGroupKey]; ok {
if _, ok := ag.Values[CapabilitiesKey]; ok {
return errors.New("cannot enable application capabilities without orderer support first")
}
}
}
}
return nil
}
You can’t perform that action at this time.