github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/common/config/orderer.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 config
    18  
    19  import (
    20  	"fmt"
    21  	"regexp"
    22  	"strconv"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/hyperledger/fabric/common/config/msp"
    27  	ab "github.com/hyperledger/fabric/protos/orderer"
    28  )
    29  
    30  const (
    31  	// OrdererGroupKey is the group name for the orderer config
    32  	OrdererGroupKey = "Orderer"
    33  )
    34  
    35  const (
    36  	// ConsensusTypeKey is the cb.ConfigItem type key name for the ConsensusType message
    37  	ConsensusTypeKey = "ConsensusType"
    38  
    39  	// BatchSizeKey is the cb.ConfigItem type key name for the BatchSize message
    40  	BatchSizeKey = "BatchSize"
    41  
    42  	// BatchTimeoutKey is the cb.ConfigItem type key name for the BatchTimeout message
    43  	BatchTimeoutKey = "BatchTimeout"
    44  
    45  	// ChannelRestrictions is the key name for the ChannelRestrictions message
    46  	ChannelRestrictionsKey = "ChannelRestrictions"
    47  
    48  	// KafkaBrokersKey is the cb.ConfigItem type key name for the KafkaBrokers message
    49  	KafkaBrokersKey = "KafkaBrokers"
    50  )
    51  
    52  // OrdererProtos is used as the source of the OrdererConfig
    53  type OrdererProtos struct {
    54  	ConsensusType       *ab.ConsensusType
    55  	BatchSize           *ab.BatchSize
    56  	BatchTimeout        *ab.BatchTimeout
    57  	KafkaBrokers        *ab.KafkaBrokers
    58  	ChannelRestrictions *ab.ChannelRestrictions
    59  }
    60  
    61  // Config is stores the orderer component configuration
    62  type OrdererGroup struct {
    63  	*Proposer
    64  	*OrdererConfig
    65  
    66  	mspConfig *msp.MSPConfigHandler
    67  }
    68  
    69  // NewConfig creates a new *OrdererConfig
    70  func NewOrdererGroup(mspConfig *msp.MSPConfigHandler) *OrdererGroup {
    71  	og := &OrdererGroup{
    72  		mspConfig: mspConfig,
    73  	}
    74  	og.Proposer = NewProposer(og)
    75  	return og
    76  }
    77  
    78  // NewGroup returns an Org instance
    79  func (og *OrdererGroup) NewGroup(name string) (ValueProposer, error) {
    80  	return NewOrganizationGroup(name, og.mspConfig), nil
    81  }
    82  
    83  func (og *OrdererGroup) Allocate() Values {
    84  	return NewOrdererConfig(og)
    85  }
    86  
    87  // OrdererConfig holds the orderer configuration information
    88  type OrdererConfig struct {
    89  	*standardValues
    90  	protos       *OrdererProtos
    91  	ordererGroup *OrdererGroup
    92  
    93  	batchTimeout time.Duration
    94  }
    95  
    96  // NewOrdererConfig creates a new instance of the orderer config
    97  func NewOrdererConfig(og *OrdererGroup) *OrdererConfig {
    98  	oc := &OrdererConfig{
    99  		protos:       &OrdererProtos{},
   100  		ordererGroup: og,
   101  	}
   102  
   103  	var err error
   104  	oc.standardValues, err = NewStandardValues(oc.protos)
   105  	if err != nil {
   106  		logger.Panicf("Programming error: %s", err)
   107  	}
   108  	return oc
   109  }
   110  
   111  // Commit writes the orderer config back to the orderer config group
   112  func (oc *OrdererConfig) Commit() {
   113  	oc.ordererGroup.OrdererConfig = oc
   114  }
   115  
   116  // ConsensusType returns the configured consensus type
   117  func (oc *OrdererConfig) ConsensusType() string {
   118  	return oc.protos.ConsensusType.Type
   119  }
   120  
   121  // BatchSize returns the maximum number of messages to include in a block
   122  func (oc *OrdererConfig) BatchSize() *ab.BatchSize {
   123  	return oc.protos.BatchSize
   124  }
   125  
   126  // BatchTimeout returns the amount of time to wait before creating a batch
   127  func (oc *OrdererConfig) BatchTimeout() time.Duration {
   128  	return oc.batchTimeout
   129  }
   130  
   131  // KafkaBrokers returns the addresses (IP:port notation) of a set of "bootstrap"
   132  // Kafka brokers, i.e. this is not necessarily the entire set of Kafka brokers
   133  // used for ordering
   134  func (oc *OrdererConfig) KafkaBrokers() []string {
   135  	return oc.protos.KafkaBrokers.Brokers
   136  }
   137  
   138  // MaxChannelsCount returns the maximum count of channels this orderer supports
   139  func (oc *OrdererConfig) MaxChannelsCount() uint64 {
   140  	return oc.protos.ChannelRestrictions.MaxCount
   141  }
   142  
   143  func (oc *OrdererConfig) Validate(tx interface{}, groups map[string]ValueProposer) error {
   144  	for _, validator := range []func() error{
   145  		oc.validateConsensusType,
   146  		oc.validateBatchSize,
   147  		oc.validateBatchTimeout,
   148  		oc.validateKafkaBrokers,
   149  	} {
   150  		if err := validator(); err != nil {
   151  			return err
   152  		}
   153  	}
   154  
   155  	return nil
   156  }
   157  
   158  func (oc *OrdererConfig) validateConsensusType() error {
   159  	if oc.ordererGroup.OrdererConfig != nil && oc.ordererGroup.ConsensusType() != oc.protos.ConsensusType.Type {
   160  		// The first config we accept the consensus type regardless
   161  		return fmt.Errorf("Attempted to change the consensus type from %s to %s after init", oc.ordererGroup.ConsensusType(), oc.protos.ConsensusType.Type)
   162  	}
   163  	return nil
   164  }
   165  
   166  func (oc *OrdererConfig) validateBatchSize() error {
   167  	if oc.protos.BatchSize.MaxMessageCount == 0 {
   168  		return fmt.Errorf("Attempted to set the batch size max message count to an invalid value: 0")
   169  	}
   170  	if oc.protos.BatchSize.AbsoluteMaxBytes == 0 {
   171  		return fmt.Errorf("Attempted to set the batch size absolute max bytes to an invalid value: 0")
   172  	}
   173  	if oc.protos.BatchSize.PreferredMaxBytes == 0 {
   174  		return fmt.Errorf("Attempted to set the batch size preferred max bytes to an invalid value: 0")
   175  	}
   176  	if oc.protos.BatchSize.PreferredMaxBytes > oc.protos.BatchSize.AbsoluteMaxBytes {
   177  		return fmt.Errorf("Attempted to set the batch size preferred max bytes (%v) greater than the absolute max bytes (%v).", oc.protos.BatchSize.PreferredMaxBytes, oc.protos.BatchSize.AbsoluteMaxBytes)
   178  	}
   179  	return nil
   180  }
   181  
   182  func (oc *OrdererConfig) validateBatchTimeout() error {
   183  	var err error
   184  	oc.batchTimeout, err = time.ParseDuration(oc.protos.BatchTimeout.Timeout)
   185  	if err != nil {
   186  		return fmt.Errorf("Attempted to set the batch timeout to a invalid value: %s", err)
   187  	}
   188  	if oc.batchTimeout <= 0 {
   189  		return fmt.Errorf("Attempted to set the batch timeout to a non-positive value: %s", oc.batchTimeout)
   190  	}
   191  	return nil
   192  }
   193  
   194  func (oc *OrdererConfig) validateKafkaBrokers() error {
   195  	for _, broker := range oc.protos.KafkaBrokers.Brokers {
   196  		if !brokerEntrySeemsValid(broker) {
   197  			return fmt.Errorf("Invalid broker entry: %s", broker)
   198  		}
   199  	}
   200  	return nil
   201  }
   202  
   203  // This does just a barebones sanity check.
   204  func brokerEntrySeemsValid(broker string) bool {
   205  	if !strings.Contains(broker, ":") {
   206  		return false
   207  	}
   208  
   209  	parts := strings.Split(broker, ":")
   210  	if len(parts) > 2 {
   211  		return false
   212  	}
   213  
   214  	host := parts[0]
   215  	port := parts[1]
   216  
   217  	if _, err := strconv.ParseUint(port, 10, 16); err != nil {
   218  		return false
   219  	}
   220  
   221  	// Valid hostnames may contain only the ASCII letters 'a' through 'z' (in a
   222  	// case-insensitive manner), the digits '0' through '9', and the hyphen. IP
   223  	// v4 addresses are  represented in dot-decimal notation, which consists of
   224  	// four decimal numbers, each ranging from 0 to 255, separated by dots,
   225  	// e.g., 172.16.254.1
   226  	// The following regular expression:
   227  	// 1. allows just a-z (case-insensitive), 0-9, and the dot and hyphen characters
   228  	// 2. does not allow leading trailing dots or hyphens
   229  	re, _ := regexp.Compile("^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9])$")
   230  	matched := re.FindString(host)
   231  	return len(matched) == len(host)
   232  }