github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/initializer/orderer/configtx/profile.go (about) 1 /* 2 * Copyright contributors to the Hyperledger Fabric Operator project 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package configtx 20 21 import ( 22 "strings" 23 24 "github.com/gogo/protobuf/proto" 25 "github.com/hyperledger/fabric/common/cauthdsl" 26 "github.com/hyperledger/fabric/common/channelconfig" 27 "github.com/hyperledger/fabric/common/policies" 28 29 cb "github.com/hyperledger/fabric-protos-go/common" 30 "github.com/hyperledger/fabric-protos-go/msp" 31 "github.com/hyperledger/fabric-protos-go/orderer/etcdraft" 32 utils "github.com/hyperledger/fabric/protoutil" 33 "github.com/pkg/errors" 34 ) 35 36 const ( 37 ordererAdminsPolicyName = "/Channel/Orderer/Admins" 38 ) 39 40 func (p *Profile) AddOrdererAddress(address string) { 41 p.Orderer.Addresses = append(p.Orderer.Addresses, address) 42 } 43 44 func (p *Profile) SetOrdererType(ordererType string) { 45 p.Orderer.OrdererType = ordererType 46 } 47 48 func (p *Profile) SetCapabilitiesForOrderer(capabilities map[string]bool) { 49 p.Orderer.Capabilities = capabilities 50 } 51 52 func (p *Profile) AddRaftConsentingNode(consenter *etcdraft.Consenter) error { 53 if strings.ToLower(p.Orderer.OrdererType) != "etcdraft" { 54 return errors.New("can only add raft consenting node if orderer type is 'etcdraft'") 55 } 56 p.Orderer.EtcdRaft.Consenters = append(p.Orderer.EtcdRaft.Consenters, consenter) 57 return nil 58 } 59 60 func (p *Profile) AddConsortium(name string, consortium *Consortium) error { 61 for _, org := range consortium.Organizations { 62 err := ValidateOrg(org) 63 if err != nil { 64 return err 65 } 66 } 67 p.Consortiums[name] = consortium 68 return nil 69 } 70 71 func (p *Profile) AddOrgToConsortium(name string, org *Organization) error { 72 err := ValidateOrg(org) 73 if err != nil { 74 return err 75 } 76 p.Consortiums[name].Organizations = append(p.Consortiums[name].Organizations, org) 77 return nil 78 } 79 80 func (p *Profile) AddOrgToOrderer(org *Organization) error { 81 err := ValidateOrg(org) 82 if err != nil { 83 return err 84 } 85 p.Orderer.Organizations = append(p.Orderer.Organizations, org) 86 return nil 87 } 88 89 func (p *Profile) SetMaxChannel(max uint64) { 90 p.Orderer.MaxChannels = max 91 } 92 93 func (p *Profile) SetChannelPolicy(policies map[string]*Policy) { 94 p.Policies = policies 95 } 96 97 func (p *Profile) GenerateBlock(channelID string, mspConfigs map[string]*msp.MSPConfig) ([]byte, error) { 98 if p.Orderer == nil { 99 return nil, errors.Errorf("refusing to generate block which is missing orderer section") 100 } 101 102 if p.Consortiums == nil { 103 return nil, errors.New("Genesis block does not contain a consortiums group definition. This block cannot be used for orderer bootstrap.") 104 } 105 106 cg, err := p.NewChannelConfigGroup(mspConfigs) 107 if err != nil { 108 return nil, err 109 } 110 111 genesisBlock := p.Block(channelID, cg) 112 gBlockBytes, err := utils.Marshal(genesisBlock) 113 if err != nil { 114 return nil, errors.Wrap(err, "error marshalling genesis block") 115 } 116 117 return gBlockBytes, nil 118 119 } 120 121 func (p *Profile) Block(channelID string, channelGroup *cb.ConfigGroup) *cb.Block { 122 payloadChannelHeader := utils.MakeChannelHeader(cb.HeaderType_CONFIG, int32(1), channelID, 0) 123 payloadSignatureHeader := utils.MakeSignatureHeader(nil, utils.CreateNonceOrPanic()) 124 utils.SetTxID(payloadChannelHeader, payloadSignatureHeader) 125 payloadHeader := utils.MakePayloadHeader(payloadChannelHeader, payloadSignatureHeader) 126 payload := &cb.Payload{Header: payloadHeader, Data: utils.MarshalOrPanic(&cb.ConfigEnvelope{Config: &cb.Config{ChannelGroup: channelGroup}})} 127 envelope := &cb.Envelope{Payload: utils.MarshalOrPanic(payload), Signature: nil} 128 129 block := utils.NewBlock(0, nil) 130 block.Data = &cb.BlockData{Data: [][]byte{utils.MarshalOrPanic(envelope)}} 131 block.Header.DataHash = utils.BlockDataHash(block.Data) 132 block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = utils.MarshalOrPanic(&cb.Metadata{ 133 Value: utils.MarshalOrPanic(&cb.LastConfig{Index: 0}), 134 }) 135 return block 136 } 137 138 func (p *Profile) NewChannelConfigGroup(mspConfigs map[string]*msp.MSPConfig) (*cb.ConfigGroup, error) { 139 channelGroup := utils.NewConfigGroup() 140 if len(p.Policies) == 0 { 141 addImplicitMetaPolicyDefaults(channelGroup) 142 } 143 144 err := addPolicies(channelGroup, p.Policies, channelconfig.AdminsPolicyKey) 145 if err != nil { 146 return nil, errors.Wrapf(err, "error adding policies to channel group") 147 } 148 149 addValue(channelGroup, channelconfig.HashingAlgorithmValue(), channelconfig.AdminsPolicyKey) 150 addValue(channelGroup, channelconfig.BlockDataHashingStructureValue(), channelconfig.AdminsPolicyKey) 151 if p.Orderer != nil && len(p.Orderer.Addresses) > 0 { 152 addValue(channelGroup, channelconfig.OrdererAddressesValue(p.Orderer.Addresses), ordererAdminsPolicyName) 153 } 154 155 if p.Consortium != "" { 156 addValue(channelGroup, channelconfig.ConsortiumValue(p.Consortium), channelconfig.AdminsPolicyKey) 157 } 158 159 if len(p.Capabilities) > 0 { 160 addValue(channelGroup, channelconfig.CapabilitiesValue(p.Capabilities), channelconfig.AdminsPolicyKey) 161 } 162 163 if p.Orderer != nil { 164 channelGroup.Groups[channelconfig.OrdererGroupKey], err = p.NewOrdererGroup(p.Orderer, mspConfigs) 165 if err != nil { 166 return nil, errors.Wrap(err, "could not create orderer group") 167 } 168 } 169 170 if p.Application != nil { 171 channelGroup.Groups[channelconfig.ApplicationGroupKey], err = NewApplicationGroup(p.Application) 172 if err != nil { 173 return nil, errors.Wrap(err, "could not create application group") 174 } 175 } 176 177 if p.Consortiums != nil { 178 channelGroup.Groups[channelconfig.ConsortiumsGroupKey], err = NewConsortiumsGroup(p.Consortiums) 179 if err != nil { 180 return nil, errors.Wrap(err, "could not create consortiums group") 181 } 182 } 183 184 channelGroup.ModPolicy = channelconfig.AdminsPolicyKey 185 return channelGroup, nil 186 } 187 188 func (p *Profile) NewOrdererGroup(conf *Orderer, mspConfigs map[string]*msp.MSPConfig) (*cb.ConfigGroup, error) { 189 ordererGroup := utils.NewConfigGroup() 190 if len(conf.Policies) == 0 { 191 addImplicitMetaPolicyDefaults(ordererGroup) 192 } else { 193 if err := addPolicies(ordererGroup, conf.Policies, channelconfig.AdminsPolicyKey); err != nil { 194 return nil, errors.Wrapf(err, "error adding policies to orderer group") 195 } 196 } 197 ordererGroup.Policies[BlockValidationPolicyKey] = &cb.ConfigPolicy{ 198 Policy: policies.ImplicitMetaAnyPolicy(channelconfig.WritersPolicyKey).Value(), 199 ModPolicy: channelconfig.AdminsPolicyKey, 200 } 201 addValue(ordererGroup, channelconfig.BatchSizeValue( 202 conf.BatchSize.MaxMessageCount, 203 conf.BatchSize.AbsoluteMaxBytes, 204 conf.BatchSize.PreferredMaxBytes, 205 ), channelconfig.AdminsPolicyKey) 206 addValue(ordererGroup, channelconfig.BatchTimeoutValue(conf.BatchTimeout.String()), channelconfig.AdminsPolicyKey) 207 addValue(ordererGroup, channelconfig.ChannelRestrictionsValue(conf.MaxChannels), channelconfig.AdminsPolicyKey) 208 209 if len(conf.Capabilities) > 0 { 210 addValue(ordererGroup, channelconfig.CapabilitiesValue(conf.Capabilities), channelconfig.AdminsPolicyKey) 211 } 212 213 var consensusMetadata []byte 214 switch conf.OrdererType { 215 case ConsensusTypeSolo: 216 // nothing to be done here 217 case ConsensusTypeKafka: 218 // nothing to be done here 219 case ConsensusTypeEtcdRaft: 220 cm, err := proto.Marshal(p.Orderer.EtcdRaft) 221 if err != nil { 222 return nil, err 223 } 224 consensusMetadata = cm 225 default: 226 return nil, errors.Errorf("unknown orderer type: %s", conf.OrdererType) 227 } 228 229 addValue(ordererGroup, channelconfig.ConsensusTypeValue(conf.OrdererType, consensusMetadata), channelconfig.AdminsPolicyKey) 230 231 for _, org := range conf.Organizations { 232 var err error 233 ordererGroup.Groups[org.Name], err = NewOrdererOrgGroup(org, mspConfigs[org.Name]) 234 if err != nil { 235 return nil, errors.Wrap(err, "failed to create orderer org") 236 } 237 } 238 239 ordererGroup.ModPolicy = channelconfig.AdminsPolicyKey 240 return ordererGroup, nil 241 } 242 243 func ValidateOrg(org *Organization) error { 244 if org.MSPType == "" { 245 return errors.Errorf("failed to provide msp type for org '%s'", org.Name) 246 } 247 248 if org.AdminPrincipal == "" { 249 return errors.Errorf("failed to provide admin principal") 250 } 251 252 return nil 253 } 254 255 // NewOrdererOrgGroup returns an orderer org component of the channel configuration. It defines the crypto material for the 256 // organization (its MSP). It sets the mod_policy of all elements to "Admins". 257 func NewOrdererOrgGroup(conf *Organization, mspConfig *msp.MSPConfig) (*cb.ConfigGroup, error) { 258 ordererOrgGroup := utils.NewConfigGroup() 259 if len(conf.Policies) == 0 { 260 addSignaturePolicyDefaults(ordererOrgGroup, conf.ID, conf.AdminPrincipal != AdminRoleAdminPrincipal) 261 } else { 262 if err := addPolicies(ordererOrgGroup, conf.Policies, channelconfig.AdminsPolicyKey); err != nil { 263 return nil, errors.Wrapf(err, "error adding policies to orderer org group '%s'", conf.Name) 264 } 265 } 266 267 addValue(ordererOrgGroup, channelconfig.MSPValue(mspConfig), channelconfig.AdminsPolicyKey) 268 269 ordererOrgGroup.ModPolicy = channelconfig.AdminsPolicyKey 270 271 if len(conf.OrdererEndpoints) > 0 { 272 addValue(ordererOrgGroup, channelconfig.EndpointsValue(conf.OrdererEndpoints), channelconfig.AdminsPolicyKey) 273 } 274 275 return ordererOrgGroup, nil 276 } 277 278 func addValue(cg *cb.ConfigGroup, value channelconfig.ConfigValue, modPolicy string) { 279 cg.Values[value.Key()] = &cb.ConfigValue{ 280 Value: utils.MarshalOrPanic(value.Value()), 281 ModPolicy: modPolicy, 282 } 283 } 284 285 func addPolicy(cg *cb.ConfigGroup, policy policies.ConfigPolicy, modPolicy string) { 286 cg.Policies[policy.Key()] = &cb.ConfigPolicy{ 287 Policy: policy.Value(), 288 ModPolicy: modPolicy, 289 } 290 } 291 292 func addPolicies(cg *cb.ConfigGroup, policyMap map[string]*Policy, modPolicy string) error { 293 for policyName, policy := range policyMap { 294 switch policy.Type { 295 case ImplicitMetaPolicyType: 296 imp, err := policies.ImplicitMetaFromString(policy.Rule) 297 if err != nil { 298 return errors.Wrapf(err, "invalid implicit meta policy rule '%s'", policy.Rule) 299 } 300 cg.Policies[policyName] = &cb.ConfigPolicy{ 301 ModPolicy: modPolicy, 302 Policy: &cb.Policy{ 303 Type: int32(cb.Policy_IMPLICIT_META), 304 Value: utils.MarshalOrPanic(imp), 305 }, 306 } 307 case SignaturePolicyType: 308 sp, err := cauthdsl.FromString(policy.Rule) 309 if err != nil { 310 return errors.Wrapf(err, "invalid signature policy rule '%s'", policy.Rule) 311 } 312 cg.Policies[policyName] = &cb.ConfigPolicy{ 313 ModPolicy: modPolicy, 314 Policy: &cb.Policy{ 315 Type: int32(cb.Policy_SIGNATURE), 316 Value: utils.MarshalOrPanic(sp), 317 }, 318 } 319 default: 320 return errors.Errorf("unknown policy type: %s", policy.Type) 321 } 322 } 323 return nil 324 } 325 326 func addImplicitMetaPolicyDefaults(cg *cb.ConfigGroup) { 327 addPolicy(cg, policies.ImplicitMetaMajorityPolicy(channelconfig.AdminsPolicyKey), channelconfig.AdminsPolicyKey) 328 addPolicy(cg, policies.ImplicitMetaAnyPolicy(channelconfig.ReadersPolicyKey), channelconfig.AdminsPolicyKey) 329 addPolicy(cg, policies.ImplicitMetaAnyPolicy(channelconfig.WritersPolicyKey), channelconfig.AdminsPolicyKey) 330 } 331 332 func addSignaturePolicyDefaults(cg *cb.ConfigGroup, mspID string, devMode bool) { 333 if devMode { 334 addPolicy(cg, policies.SignaturePolicy(channelconfig.AdminsPolicyKey, cauthdsl.SignedByMspMember(mspID)), channelconfig.AdminsPolicyKey) 335 } else { 336 addPolicy(cg, policies.SignaturePolicy(channelconfig.AdminsPolicyKey, cauthdsl.SignedByMspAdmin(mspID)), channelconfig.AdminsPolicyKey) 337 } 338 addPolicy(cg, policies.SignaturePolicy(channelconfig.ReadersPolicyKey, cauthdsl.SignedByMspMember(mspID)), channelconfig.AdminsPolicyKey) 339 addPolicy(cg, policies.SignaturePolicy(channelconfig.WritersPolicyKey, cauthdsl.SignedByMspMember(mspID)), channelconfig.AdminsPolicyKey) 340 }