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  }