github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/common/configtx/template.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package configtx 18 19 import ( 20 "fmt" 21 22 "github.com/hyperledger/fabric/common/config" 23 configmsp "github.com/hyperledger/fabric/common/config/msp" 24 "github.com/hyperledger/fabric/common/policies" 25 "github.com/hyperledger/fabric/common/util" 26 "github.com/hyperledger/fabric/msp" 27 cb "github.com/hyperledger/fabric/protos/common" 28 "github.com/hyperledger/fabric/protos/utils" 29 30 "github.com/golang/protobuf/proto" 31 ) 32 33 const ( 34 // CreationPolicyKey defines the config key used in the channel 35 // config, under which the creation policy is defined. 36 CreationPolicyKey = "CreationPolicy" 37 msgVersion = int32(0) 38 epoch = 0 39 ) 40 41 // Template can be used to faciliate creation of config transactions 42 type Template interface { 43 // Envelope returns a ConfigUpdateEnvelope for the given chainID 44 Envelope(chainID string) (*cb.ConfigUpdateEnvelope, error) 45 } 46 47 type simpleTemplate struct { 48 configGroup *cb.ConfigGroup 49 } 50 51 // NewSimpleTemplate creates a Template using the supplied ConfigGroups 52 func NewSimpleTemplate(configGroups ...*cb.ConfigGroup) Template { 53 sts := make([]Template, len(configGroups)) 54 for i, group := range configGroups { 55 sts[i] = &simpleTemplate{ 56 configGroup: group, 57 } 58 } 59 return NewCompositeTemplate(sts...) 60 } 61 62 // Envelope returns a ConfigUpdateEnvelope for the given chainID 63 func (st *simpleTemplate) Envelope(chainID string) (*cb.ConfigUpdateEnvelope, error) { 64 config, err := proto.Marshal(&cb.ConfigUpdate{ 65 ChannelId: chainID, 66 WriteSet: st.configGroup, 67 }) 68 69 if err != nil { 70 return nil, err 71 } 72 73 return &cb.ConfigUpdateEnvelope{ 74 ConfigUpdate: config, 75 }, nil 76 } 77 78 type compositeTemplate struct { 79 templates []Template 80 } 81 82 // NewCompositeTemplate creates a Template using the source Templates 83 func NewCompositeTemplate(templates ...Template) Template { 84 return &compositeTemplate{templates: templates} 85 } 86 87 func copyGroup(source *cb.ConfigGroup, target *cb.ConfigGroup) error { 88 for key, value := range source.Values { 89 _, ok := target.Values[key] 90 if ok { 91 return fmt.Errorf("Duplicate key: %s", key) 92 } 93 target.Values[key] = value 94 } 95 96 for key, policy := range source.Policies { 97 _, ok := target.Policies[key] 98 if ok { 99 return fmt.Errorf("Duplicate policy: %s", key) 100 } 101 target.Policies[key] = policy 102 } 103 104 for key, group := range source.Groups { 105 _, ok := target.Groups[key] 106 if !ok { 107 target.Groups[key] = cb.NewConfigGroup() 108 } 109 110 err := copyGroup(group, target.Groups[key]) 111 if err != nil { 112 return fmt.Errorf("Error copying group %s: %s", key, err) 113 } 114 } 115 return nil 116 } 117 118 // Envelope returns a ConfigUpdateEnvelope for the given chainID 119 func (ct *compositeTemplate) Envelope(chainID string) (*cb.ConfigUpdateEnvelope, error) { 120 channel := cb.NewConfigGroup() 121 122 for i := range ct.templates { 123 configEnv, err := ct.templates[i].Envelope(chainID) 124 if err != nil { 125 return nil, err 126 } 127 config, err := UnmarshalConfigUpdate(configEnv.ConfigUpdate) 128 if err != nil { 129 return nil, err 130 } 131 err = copyGroup(config.WriteSet, channel) 132 if err != nil { 133 return nil, err 134 } 135 } 136 137 marshaledConfig, err := proto.Marshal(&cb.ConfigUpdate{ 138 ChannelId: chainID, 139 WriteSet: channel, 140 }) 141 if err != nil { 142 return nil, err 143 } 144 145 return &cb.ConfigUpdateEnvelope{ConfigUpdate: marshaledConfig}, nil 146 } 147 148 type modPolicySettingTemplate struct { 149 modPolicy string 150 template Template 151 } 152 153 // NewModPolicySettingTemplate wraps another template and sets the ModPolicy of 154 // every ConfigGroup/ConfigValue/ConfigPolicy to modPolicy 155 func NewModPolicySettingTemplate(modPolicy string, template Template) Template { 156 return &modPolicySettingTemplate{ 157 modPolicy: modPolicy, 158 template: template, 159 } 160 } 161 162 func setGroupModPolicies(modPolicy string, group *cb.ConfigGroup) { 163 group.ModPolicy = modPolicy 164 165 for _, value := range group.Values { 166 value.ModPolicy = modPolicy 167 } 168 169 for _, policy := range group.Policies { 170 policy.ModPolicy = modPolicy 171 } 172 173 for _, nextGroup := range group.Groups { 174 setGroupModPolicies(modPolicy, nextGroup) 175 } 176 } 177 178 func (mpst *modPolicySettingTemplate) Envelope(channelID string) (*cb.ConfigUpdateEnvelope, error) { 179 configUpdateEnv, err := mpst.template.Envelope(channelID) 180 if err != nil { 181 return nil, err 182 } 183 184 config, err := UnmarshalConfigUpdate(configUpdateEnv.ConfigUpdate) 185 if err != nil { 186 return nil, err 187 } 188 189 setGroupModPolicies(mpst.modPolicy, config.WriteSet) 190 configUpdateEnv.ConfigUpdate = utils.MarshalOrPanic(config) 191 return configUpdateEnv, nil 192 } 193 194 type channelCreationTemplate struct { 195 consortiumName string 196 orgs []string 197 } 198 199 // NewChainCreationTemplate takes a consortium name and a Template to produce a 200 // Template which outputs an appropriately constructed list of ConfigUpdateEnvelopes. 201 func NewChainCreationTemplate(consortiumName string, orgs []string) Template { 202 return &channelCreationTemplate{ 203 consortiumName: consortiumName, 204 orgs: orgs, 205 } 206 } 207 208 func (cct *channelCreationTemplate) Envelope(channelID string) (*cb.ConfigUpdateEnvelope, error) { 209 rSet := config.TemplateConsortium(cct.consortiumName) 210 wSet := config.TemplateConsortium(cct.consortiumName) 211 212 rSet.Groups[config.ApplicationGroupKey] = cb.NewConfigGroup() 213 wSet.Groups[config.ApplicationGroupKey] = cb.NewConfigGroup() 214 215 for _, org := range cct.orgs { 216 rSet.Groups[config.ApplicationGroupKey].Groups[org] = cb.NewConfigGroup() 217 wSet.Groups[config.ApplicationGroupKey].Groups[org] = cb.NewConfigGroup() 218 } 219 220 wSet.Groups[config.ApplicationGroupKey].ModPolicy = configmsp.AdminsPolicyKey 221 wSet.Groups[config.ApplicationGroupKey].Policies[configmsp.AdminsPolicyKey] = policies.ImplicitMetaPolicyWithSubPolicy(configmsp.AdminsPolicyKey, cb.ImplicitMetaPolicy_MAJORITY) 222 wSet.Groups[config.ApplicationGroupKey].Policies[configmsp.WritersPolicyKey] = policies.ImplicitMetaPolicyWithSubPolicy(configmsp.WritersPolicyKey, cb.ImplicitMetaPolicy_ANY) 223 wSet.Groups[config.ApplicationGroupKey].Policies[configmsp.ReadersPolicyKey] = policies.ImplicitMetaPolicyWithSubPolicy(configmsp.ReadersPolicyKey, cb.ImplicitMetaPolicy_ANY) 224 wSet.Groups[config.ApplicationGroupKey].Version = 1 225 226 return &cb.ConfigUpdateEnvelope{ 227 ConfigUpdate: utils.MarshalOrPanic(&cb.ConfigUpdate{ 228 ChannelId: channelID, 229 ReadSet: rSet, 230 WriteSet: wSet, 231 }), 232 }, nil 233 } 234 235 // MakeChainCreationTransaction is a handy utility function for creating new chain transactions using the underlying Template framework 236 func MakeChainCreationTransaction(channelID string, consortium string, signer msp.SigningIdentity, orgs ...string) (*cb.Envelope, error) { 237 sSigner, err := signer.Serialize() 238 if err != nil { 239 return nil, fmt.Errorf("Serialization of identity failed, err %s", err) 240 } 241 242 newChainTemplate := NewChainCreationTemplate(consortium, orgs) 243 newConfigUpdateEnv, err := newChainTemplate.Envelope(channelID) 244 if err != nil { 245 return nil, err 246 } 247 newConfigUpdateEnv.Signatures = []*cb.ConfigSignature{&cb.ConfigSignature{ 248 SignatureHeader: utils.MarshalOrPanic(utils.MakeSignatureHeader(sSigner, utils.CreateNonceOrPanic())), 249 }} 250 251 newConfigUpdateEnv.Signatures[0].Signature, err = signer.Sign(util.ConcatenateBytes(newConfigUpdateEnv.Signatures[0].SignatureHeader, newConfigUpdateEnv.ConfigUpdate)) 252 if err != nil { 253 return nil, err 254 } 255 256 payloadChannelHeader := utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, msgVersion, channelID, epoch) 257 payloadSignatureHeader := utils.MakeSignatureHeader(sSigner, utils.CreateNonceOrPanic()) 258 utils.SetTxID(payloadChannelHeader, payloadSignatureHeader) 259 payloadHeader := utils.MakePayloadHeader(payloadChannelHeader, payloadSignatureHeader) 260 payload := &cb.Payload{Header: payloadHeader, Data: utils.MarshalOrPanic(newConfigUpdateEnv)} 261 paylBytes := utils.MarshalOrPanic(payload) 262 263 // sign the payload 264 sig, err := signer.Sign(paylBytes) 265 if err != nil { 266 return nil, err 267 } 268 269 return &cb.Envelope{Payload: paylBytes, Signature: sig}, nil 270 }