github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/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  	orgs         map[string]Org
    93  
    94  	batchTimeout time.Duration
    95  }
    96  
    97  // NewOrdererConfig creates a new instance of the orderer config
    98  func NewOrdererConfig(og *OrdererGroup) *OrdererConfig {
    99  	oc := &OrdererConfig{
   100  		protos:       &OrdererProtos{},
   101  		ordererGroup: og,
   102  	}
   103  
   104  	var err error
   105  	oc.standardValues, err = NewStandardValues(oc.protos)
   106  	if err != nil {
   107  		logger.Panicf("Programming error: %s", err)
   108  	}
   109  	return oc
   110  }
   111  
   112  // Commit writes the orderer config back to the orderer config group
   113  func (oc *OrdererConfig) Commit() {
   114  	oc.ordererGroup.OrdererConfig = oc
   115  }
   116  
   117  // ConsensusType returns the configured consensus type
   118  func (oc *OrdererConfig) ConsensusType() string {
   119  	return oc.protos.ConsensusType.Type
   120  }
   121  
   122  // BatchSize returns the maximum number of messages to include in a block
   123  func (oc *OrdererConfig) BatchSize() *ab.BatchSize {
   124  	return oc.protos.BatchSize
   125  }
   126  
   127  // BatchTimeout returns the amount of time to wait before creating a batch
   128  func (oc *OrdererConfig) BatchTimeout() time.Duration {
   129  	return oc.batchTimeout
   130  }
   131  
   132  // KafkaBrokers returns the addresses (IP:port notation) of a set of "bootstrap"
   133  // Kafka brokers, i.e. this is not necessarily the entire set of Kafka brokers
   134  // used for ordering
   135  func (oc *OrdererConfig) KafkaBrokers() []string {
   136  	return oc.protos.KafkaBrokers.Brokers
   137  }
   138  
   139  // MaxChannelsCount returns the maximum count of channels this orderer supports
   140  func (oc *OrdererConfig) MaxChannelsCount() uint64 {
   141  	return oc.protos.ChannelRestrictions.MaxCount
   142  }
   143  
   144  // Organizations returns a map of the orgs in the channel
   145  func (oc *OrdererConfig) Organizations() map[string]Org {
   146  	return oc.orgs
   147  }
   148  
   149  func (oc *OrdererConfig) Validate(tx interface{}, groups map[string]ValueProposer) error {
   150  	for _, validator := range []func() error{
   151  		oc.validateConsensusType,
   152  		oc.validateBatchSize,
   153  		oc.validateBatchTimeout,
   154  		oc.validateKafkaBrokers,
   155  	} {
   156  		if err := validator(); err != nil {
   157  			return err
   158  		}
   159  	}
   160  
   161  	var ok bool
   162  	oc.orgs = make(map[string]Org)
   163  	for key, value := range groups {
   164  		oc.orgs[key], ok = value.(*OrganizationGroup)
   165  		if !ok {
   166  			return fmt.Errorf("Organization sub-group %s was not an OrgGroup, actually %T", key, value)
   167  		}
   168  	}
   169  
   170  	return nil
   171  }
   172  
   173  func (oc *OrdererConfig) validateConsensusType() error {
   174  	if oc.ordererGroup.OrdererConfig != nil && oc.ordererGroup.ConsensusType() != oc.protos.ConsensusType.Type {
   175  		// The first config we accept the consensus type regardless
   176  		return fmt.Errorf("Attempted to change the consensus type from %s to %s after init", oc.ordererGroup.ConsensusType(), oc.protos.ConsensusType.Type)
   177  	}
   178  	return nil
   179  }
   180  
   181  func (oc *OrdererConfig) validateBatchSize() error {
   182  	if oc.protos.BatchSize.MaxMessageCount == 0 {
   183  		return fmt.Errorf("Attempted to set the batch size max message count to an invalid value: 0")
   184  	}
   185  	if oc.protos.BatchSize.AbsoluteMaxBytes == 0 {
   186  		return fmt.Errorf("Attempted to set the batch size absolute max bytes to an invalid value: 0")
   187  	}
   188  	if oc.protos.BatchSize.PreferredMaxBytes == 0 {
   189  		return fmt.Errorf("Attempted to set the batch size preferred max bytes to an invalid value: 0")
   190  	}
   191  	if oc.protos.BatchSize.PreferredMaxBytes > oc.protos.BatchSize.AbsoluteMaxBytes {
   192  		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)
   193  	}
   194  	return nil
   195  }
   196  
   197  func (oc *OrdererConfig) validateBatchTimeout() error {
   198  	var err error
   199  	oc.batchTimeout, err = time.ParseDuration(oc.protos.BatchTimeout.Timeout)
   200  	if err != nil {
   201  		return fmt.Errorf("Attempted to set the batch timeout to a invalid value: %s", err)
   202  	}
   203  	if oc.batchTimeout <= 0 {
   204  		return fmt.Errorf("Attempted to set the batch timeout to a non-positive value: %s", oc.batchTimeout)
   205  	}
   206  	return nil
   207  }
   208  
   209  func (oc *OrdererConfig) validateKafkaBrokers() error {
   210  	for _, broker := range oc.protos.KafkaBrokers.Brokers {
   211  		if !brokerEntrySeemsValid(broker) {
   212  			return fmt.Errorf("Invalid broker entry: %s", broker)
   213  		}
   214  	}
   215  	return nil
   216  }
   217  
   218  // This does just a barebones sanity check.
   219  func brokerEntrySeemsValid(broker string) bool {
   220  	if !strings.Contains(broker, ":") {
   221  		return false
   222  	}
   223  
   224  	parts := strings.Split(broker, ":")
   225  	if len(parts) > 2 {
   226  		return false
   227  	}
   228  
   229  	host := parts[0]
   230  	port := parts[1]
   231  
   232  	if _, err := strconv.ParseUint(port, 10, 16); err != nil {
   233  		return false
   234  	}
   235  
   236  	// Valid hostnames may contain only the ASCII letters 'a' through 'z' (in a
   237  	// case-insensitive manner), the digits '0' through '9', and the hyphen. IP
   238  	// v4 addresses are  represented in dot-decimal notation, which consists of
   239  	// four decimal numbers, each ranging from 0 to 255, separated by dots,
   240  	// e.g., 172.16.254.1
   241  	// The following regular expression:
   242  	// 1. allows just a-z (case-insensitive), 0-9, and the dot and hyphen characters
   243  	// 2. does not allow leading trailing dots or hyphens
   244  	re, _ := regexp.Compile("^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9])$")
   245  	matched := re.FindString(host)
   246  	return len(matched) == len(host)
   247  }