github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/orderer/multichain/systemchain.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 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 multichain
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  
    23  	"github.com/hyperledger/fabric/common/config"
    24  	"github.com/hyperledger/fabric/common/configtx"
    25  	configtxapi "github.com/hyperledger/fabric/common/configtx/api"
    26  	"github.com/hyperledger/fabric/orderer/common/filter"
    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  // Define some internal interfaces for easier mocking
    34  type chainCreator interface {
    35  	NewChannelConfig(envConfigUpdate *cb.Envelope) (configtxapi.Manager, error)
    36  	newChain(configTx *cb.Envelope)
    37  	channelsCount() int
    38  }
    39  
    40  type limitedSupport interface {
    41  	SharedConfig() config.Orderer
    42  }
    43  
    44  type systemChainCommitter struct {
    45  	filter   *systemChainFilter
    46  	configTx *cb.Envelope
    47  }
    48  
    49  func (scc *systemChainCommitter) Isolated() bool {
    50  	return true
    51  }
    52  
    53  func (scc *systemChainCommitter) Commit() {
    54  	scc.filter.cc.newChain(scc.configTx)
    55  }
    56  
    57  type systemChainFilter struct {
    58  	cc      chainCreator
    59  	support limitedSupport
    60  }
    61  
    62  func newSystemChainFilter(ls limitedSupport, cc chainCreator) filter.Rule {
    63  	return &systemChainFilter{
    64  		support: ls,
    65  		cc:      cc,
    66  	}
    67  }
    68  
    69  func (scf *systemChainFilter) Apply(env *cb.Envelope) (filter.Action, filter.Committer) {
    70  	msgData := &cb.Payload{}
    71  
    72  	err := proto.Unmarshal(env.Payload, msgData)
    73  	if err != nil {
    74  		return filter.Forward, nil
    75  	}
    76  
    77  	if msgData.Header == nil {
    78  		return filter.Forward, nil
    79  	}
    80  
    81  	chdr, err := utils.UnmarshalChannelHeader(msgData.Header.ChannelHeader)
    82  	if err != nil {
    83  		return filter.Forward, nil
    84  	}
    85  
    86  	if chdr.Type != int32(cb.HeaderType_ORDERER_TRANSACTION) {
    87  		return filter.Forward, nil
    88  	}
    89  
    90  	maxChannels := scf.support.SharedConfig().MaxChannelsCount()
    91  	if maxChannels > 0 {
    92  		// We check for strictly greater than to accommodate the system channel
    93  		if uint64(scf.cc.channelsCount()) > maxChannels {
    94  			logger.Warningf("Rejecting channel creation because the orderer has reached the maximum number of channels, %d", maxChannels)
    95  			return filter.Reject, nil
    96  		}
    97  	}
    98  
    99  	configTx := &cb.Envelope{}
   100  	err = proto.Unmarshal(msgData.Data, configTx)
   101  	if err != nil {
   102  		return filter.Reject, nil
   103  	}
   104  
   105  	err = scf.authorizeAndInspect(configTx)
   106  	if err != nil {
   107  		logger.Debugf("Rejecting channel creation because: %s", err)
   108  		return filter.Reject, nil
   109  	}
   110  
   111  	return filter.Accept, &systemChainCommitter{
   112  		filter:   scf,
   113  		configTx: configTx,
   114  	}
   115  }
   116  
   117  func (scf *systemChainFilter) authorize(configEnvelope *cb.ConfigEnvelope) (configtxapi.Manager, error) {
   118  	if configEnvelope.LastUpdate == nil {
   119  		return nil, fmt.Errorf("Must include a config update")
   120  	}
   121  
   122  	configManager, err := scf.cc.NewChannelConfig(configEnvelope.LastUpdate)
   123  	if err != nil {
   124  		return nil, fmt.Errorf("Error constructing new channel config from update: %s", err)
   125  	}
   126  
   127  	newChannelConfigEnv, err := configManager.ProposeConfigUpdate(configEnvelope.LastUpdate)
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  
   132  	err = configManager.Apply(newChannelConfigEnv)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	return configManager, nil
   138  }
   139  
   140  func (scf *systemChainFilter) inspect(proposedManager, configManager configtxapi.Manager) error {
   141  	proposedEnv := proposedManager.ConfigEnvelope()
   142  	actualEnv := configManager.ConfigEnvelope()
   143  	if !reflect.DeepEqual(proposedEnv.Config, actualEnv.Config) {
   144  		return fmt.Errorf("The config proposed by the channel creation request did not match the config received with the channel creation request")
   145  	}
   146  	return nil
   147  }
   148  
   149  func (scf *systemChainFilter) authorizeAndInspect(configTx *cb.Envelope) error {
   150  	payload := &cb.Payload{}
   151  	err := proto.Unmarshal(configTx.Payload, payload)
   152  	if err != nil {
   153  		return fmt.Errorf("Rejecting chain proposal: Error unmarshaling envelope payload: %s", err)
   154  	}
   155  
   156  	if payload.Header == nil {
   157  		return fmt.Errorf("Rejecting chain proposal: Not a config transaction")
   158  	}
   159  
   160  	chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   161  	if err != nil {
   162  		return fmt.Errorf("Rejecting chain proposal: Error unmarshaling channel header: %s", err)
   163  	}
   164  
   165  	if chdr.Type != int32(cb.HeaderType_CONFIG) {
   166  		return fmt.Errorf("Rejecting chain proposal: Not a config transaction")
   167  	}
   168  
   169  	configEnvelope := &cb.ConfigEnvelope{}
   170  	err = proto.Unmarshal(payload.Data, configEnvelope)
   171  	if err != nil {
   172  		return fmt.Errorf("Rejecting chain proposal: Error unmarshalling config envelope from payload: %s", err)
   173  	}
   174  
   175  	// Make sure that the config was signed by the appropriate authorized entities
   176  	proposedManager, err := scf.authorize(configEnvelope)
   177  	if err != nil {
   178  		return err
   179  	}
   180  
   181  	initializer := configtx.NewInitializer()
   182  	configManager, err := configtx.NewManagerImpl(configTx, initializer, nil)
   183  	if err != nil {
   184  		return fmt.Errorf("Failed to create config manager and handlers: %s", err)
   185  	}
   186  
   187  	// Make sure that the config does not modify any of the orderer
   188  	return scf.inspect(proposedManager, configManager)
   189  }