github.com/ewagmig/fabric@v2.1.1+incompatible/common/channelconfig/bundle.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package channelconfig 8 9 import ( 10 cb "github.com/hyperledger/fabric-protos-go/common" 11 "github.com/hyperledger/fabric/bccsp" 12 "github.com/hyperledger/fabric/common/cauthdsl" 13 "github.com/hyperledger/fabric/common/configtx" 14 "github.com/hyperledger/fabric/common/flogging" 15 "github.com/hyperledger/fabric/common/policies" 16 "github.com/hyperledger/fabric/msp" 17 "github.com/hyperledger/fabric/protoutil" 18 "github.com/pkg/errors" 19 ) 20 21 var logger = flogging.MustGetLogger("common.channelconfig") 22 23 // RootGroupKey is the key for namespacing the channel config, especially for 24 // policy evaluation. 25 const RootGroupKey = "Channel" 26 27 // Bundle is a collection of resources which will always have a consistent 28 // view of the channel configuration. In particular, for a given bundle reference, 29 // the config sequence, the policy manager etc. will always return exactly the 30 // same value. The Bundle structure is immutable and will always be replaced in its 31 // entirety, with new backing memory. 32 type Bundle struct { 33 policyManager policies.Manager 34 channelConfig *ChannelConfig 35 configtxManager configtx.Validator 36 } 37 38 // PolicyManager returns the policy manager constructed for this config. 39 func (b *Bundle) PolicyManager() policies.Manager { 40 return b.policyManager 41 } 42 43 // MSPManager returns the MSP manager constructed for this config. 44 func (b *Bundle) MSPManager() msp.MSPManager { 45 return b.channelConfig.MSPManager() 46 } 47 48 // ChannelConfig returns the config.Channel for the chain. 49 func (b *Bundle) ChannelConfig() Channel { 50 return b.channelConfig 51 } 52 53 // OrdererConfig returns the config.Orderer for the channel 54 // and whether the Orderer config exists. 55 func (b *Bundle) OrdererConfig() (Orderer, bool) { 56 result := b.channelConfig.OrdererConfig() 57 return result, result != nil 58 } 59 60 // ConsortiumsConfig returns the config.Consortiums for the channel 61 // and whether the consortiums config exists. 62 func (b *Bundle) ConsortiumsConfig() (Consortiums, bool) { 63 result := b.channelConfig.ConsortiumsConfig() 64 return result, result != nil 65 } 66 67 // ApplicationConfig returns the configtxapplication.SharedConfig for the channel 68 // and whether the Application config exists. 69 func (b *Bundle) ApplicationConfig() (Application, bool) { 70 result := b.channelConfig.ApplicationConfig() 71 return result, result != nil 72 } 73 74 // ConfigtxValidator returns the configtx.Validator for the channel. 75 func (b *Bundle) ConfigtxValidator() configtx.Validator { 76 return b.configtxManager 77 } 78 79 // ValidateNew checks if a new bundle's contained configuration is valid to be derived from the current bundle. 80 // This allows checks of the nature "Make sure that the consensus type did not change". 81 func (b *Bundle) ValidateNew(nb Resources) error { 82 if oc, ok := b.OrdererConfig(); ok { 83 noc, ok := nb.OrdererConfig() 84 if !ok { 85 return errors.New("current config has orderer section, but new config does not") 86 } 87 88 // Prevent consensus-type migration when channel capabilities ConsensusTypeMigration is disabled 89 if !b.channelConfig.Capabilities().ConsensusTypeMigration() { 90 if oc.ConsensusType() != noc.ConsensusType() { 91 return errors.Errorf("attempted to change consensus type from %s to %s", 92 oc.ConsensusType(), noc.ConsensusType()) 93 } 94 } 95 96 for orgName, org := range oc.Organizations() { 97 norg, ok := noc.Organizations()[orgName] 98 if !ok { 99 continue 100 } 101 mspID := org.MSPID() 102 if mspID != norg.MSPID() { 103 return errors.Errorf("orderer org %s attempted to change MSP ID from %s to %s", orgName, mspID, norg.MSPID()) 104 } 105 } 106 } 107 108 if ac, ok := b.ApplicationConfig(); ok { 109 nac, ok := nb.ApplicationConfig() 110 if !ok { 111 return errors.New("current config has application section, but new config does not") 112 } 113 114 for orgName, org := range ac.Organizations() { 115 norg, ok := nac.Organizations()[orgName] 116 if !ok { 117 continue 118 } 119 mspID := org.MSPID() 120 if mspID != norg.MSPID() { 121 return errors.Errorf("application org %s attempted to change MSP ID from %s to %s", orgName, mspID, norg.MSPID()) 122 } 123 } 124 } 125 126 if cc, ok := b.ConsortiumsConfig(); ok { 127 ncc, ok := nb.ConsortiumsConfig() 128 if !ok { 129 return errors.Errorf("current config has consortiums section, but new config does not") 130 } 131 132 for consortiumName, consortium := range cc.Consortiums() { 133 nconsortium, ok := ncc.Consortiums()[consortiumName] 134 if !ok { 135 continue 136 } 137 138 for orgName, org := range consortium.Organizations() { 139 norg, ok := nconsortium.Organizations()[orgName] 140 if !ok { 141 continue 142 } 143 mspID := org.MSPID() 144 if mspID != norg.MSPID() { 145 return errors.Errorf("consortium %s org %s attempted to change MSP ID from %s to %s", consortiumName, orgName, mspID, norg.MSPID()) 146 } 147 } 148 } 149 } else if _, okNew := nb.ConsortiumsConfig(); okNew { 150 return errors.Errorf("current config has no consortiums section, but new config does") 151 } 152 153 return nil 154 } 155 156 // NewBundleFromEnvelope wraps the NewBundle function, extracting the needed 157 // information from a full configtx 158 func NewBundleFromEnvelope(env *cb.Envelope, bccsp bccsp.BCCSP) (*Bundle, error) { 159 payload, err := protoutil.UnmarshalPayload(env.Payload) 160 if err != nil { 161 return nil, errors.Wrap(err, "failed to unmarshal payload from envelope") 162 } 163 164 configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data) 165 if err != nil { 166 return nil, errors.Wrap(err, "failed to unmarshal config envelope from payload") 167 } 168 169 if payload.Header == nil { 170 return nil, errors.Errorf("envelope header cannot be nil") 171 } 172 173 chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader) 174 if err != nil { 175 return nil, errors.Wrap(err, "failed to unmarshal channel header") 176 } 177 178 return NewBundle(chdr.ChannelId, configEnvelope.Config, bccsp) 179 } 180 181 // NewBundle creates a new immutable bundle of configuration 182 func NewBundle(channelID string, config *cb.Config, bccsp bccsp.BCCSP) (*Bundle, error) { 183 if err := preValidate(config); err != nil { 184 return nil, err 185 } 186 187 channelConfig, err := NewChannelConfig(config.ChannelGroup, bccsp) 188 if err != nil { 189 return nil, errors.Wrap(err, "initializing channelconfig failed") 190 } 191 192 policyProviderMap := make(map[int32]policies.Provider) 193 for pType := range cb.Policy_PolicyType_name { 194 rtype := cb.Policy_PolicyType(pType) 195 switch rtype { 196 case cb.Policy_UNKNOWN: 197 // Do not register a handler 198 case cb.Policy_SIGNATURE: 199 policyProviderMap[pType] = cauthdsl.NewPolicyProvider(channelConfig.MSPManager()) 200 case cb.Policy_MSP: 201 // Add hook for MSP Handler here 202 } 203 } 204 205 policyManager, err := policies.NewManagerImpl(RootGroupKey, policyProviderMap, config.ChannelGroup) 206 if err != nil { 207 return nil, errors.Wrap(err, "initializing policymanager failed") 208 } 209 210 configtxManager, err := configtx.NewValidatorImpl(channelID, config, RootGroupKey, policyManager) 211 if err != nil { 212 return nil, errors.Wrap(err, "initializing configtx manager failed") 213 } 214 215 return &Bundle{ 216 policyManager: policyManager, 217 channelConfig: channelConfig, 218 configtxManager: configtxManager, 219 }, nil 220 } 221 222 func preValidate(config *cb.Config) error { 223 if config == nil { 224 return errors.New("channelconfig Config cannot be nil") 225 } 226 227 if config.ChannelGroup == nil { 228 return errors.New("config must contain a channel group") 229 } 230 231 if og, ok := config.ChannelGroup.Groups[OrdererGroupKey]; ok { 232 if _, ok := og.Values[CapabilitiesKey]; !ok { 233 if _, ok := config.ChannelGroup.Values[CapabilitiesKey]; ok { 234 return errors.New("cannot enable channel capabilities without orderer support first") 235 } 236 237 if ag, ok := config.ChannelGroup.Groups[ApplicationGroupKey]; ok { 238 if _, ok := ag.Values[CapabilitiesKey]; ok { 239 return errors.New("cannot enable application capabilities without orderer support first") 240 } 241 } 242 } 243 } 244 245 return nil 246 }