github.com/ewagmig/fabric@v2.1.1+incompatible/common/channelconfig/orderer.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package channelconfig
     8  
     9  import (
    10  	"fmt"
    11  	"regexp"
    12  	"strconv"
    13  	"strings"
    14  	"time"
    15  
    16  	cb "github.com/hyperledger/fabric-protos-go/common"
    17  	ab "github.com/hyperledger/fabric-protos-go/orderer"
    18  	"github.com/hyperledger/fabric/common/capabilities"
    19  	"github.com/pkg/errors"
    20  )
    21  
    22  const (
    23  	// OrdererGroupKey is the group name for the orderer config.
    24  	OrdererGroupKey = "Orderer"
    25  )
    26  
    27  const (
    28  	// ConsensusTypeKey is the cb.ConfigItem type key name for the ConsensusType message.
    29  	ConsensusTypeKey = "ConsensusType"
    30  
    31  	// BatchSizeKey is the cb.ConfigItem type key name for the BatchSize message.
    32  	BatchSizeKey = "BatchSize"
    33  
    34  	// BatchTimeoutKey is the cb.ConfigItem type key name for the BatchTimeout message.
    35  	BatchTimeoutKey = "BatchTimeout"
    36  
    37  	// ChannelRestrictionsKey is the key name for the ChannelRestrictions message.
    38  	ChannelRestrictionsKey = "ChannelRestrictions"
    39  
    40  	// KafkaBrokersKey is the cb.ConfigItem type key name for the KafkaBrokers message.
    41  	KafkaBrokersKey = "KafkaBrokers"
    42  
    43  	// EndpointsKey is the cb.COnfigValue key name for the Endpoints message in the OrdererOrgGroup.
    44  	EndpointsKey = "Endpoints"
    45  )
    46  
    47  // OrdererProtos is used as the source of the OrdererConfig.
    48  type OrdererProtos struct {
    49  	ConsensusType       *ab.ConsensusType
    50  	BatchSize           *ab.BatchSize
    51  	BatchTimeout        *ab.BatchTimeout
    52  	KafkaBrokers        *ab.KafkaBrokers
    53  	ChannelRestrictions *ab.ChannelRestrictions
    54  	Capabilities        *cb.Capabilities
    55  }
    56  
    57  // OrdererConfig holds the orderer configuration information.
    58  type OrdererConfig struct {
    59  	protos *OrdererProtos
    60  	orgs   map[string]OrdererOrg
    61  
    62  	batchTimeout time.Duration
    63  }
    64  
    65  // OrdererOrgProtos are deserialized from the Orderer org config values
    66  type OrdererOrgProtos struct {
    67  	Endpoints *cb.OrdererAddresses
    68  }
    69  
    70  // OrdererOrgConfig defines the configuration for an orderer org
    71  type OrdererOrgConfig struct {
    72  	*OrganizationConfig
    73  	protos *OrdererOrgProtos
    74  	name   string
    75  }
    76  
    77  // Endpoints returns the set of addresses this ordering org exposes as orderers
    78  func (oc *OrdererOrgConfig) Endpoints() []string {
    79  	return oc.protos.Endpoints.Addresses
    80  }
    81  
    82  // NewOrdererOrgConfig returns an orderer org config built from the given ConfigGroup.
    83  func NewOrdererOrgConfig(orgName string, orgGroup *cb.ConfigGroup, mspConfigHandler *MSPConfigHandler, channelCapabilities ChannelCapabilities) (*OrdererOrgConfig, error) {
    84  	if len(orgGroup.Groups) > 0 {
    85  		return nil, fmt.Errorf("OrdererOrg config does not allow sub-groups")
    86  	}
    87  
    88  	if !channelCapabilities.OrgSpecificOrdererEndpoints() {
    89  		if _, ok := orgGroup.Values[EndpointsKey]; ok {
    90  			return nil, errors.Errorf("Orderer Org %s cannot contain endpoints value until V1_4_2+ capabilities have been enabled", orgName)
    91  		}
    92  	}
    93  
    94  	protos := &OrdererOrgProtos{}
    95  	orgProtos := &OrganizationProtos{}
    96  
    97  	if err := DeserializeProtoValuesFromGroup(orgGroup, protos, orgProtos); err != nil {
    98  		return nil, errors.Wrap(err, "failed to deserialize values")
    99  	}
   100  
   101  	ooc := &OrdererOrgConfig{
   102  		name:   orgName,
   103  		protos: protos,
   104  		OrganizationConfig: &OrganizationConfig{
   105  			name:             orgName,
   106  			protos:           orgProtos,
   107  			mspConfigHandler: mspConfigHandler,
   108  		},
   109  	}
   110  
   111  	if err := ooc.Validate(); err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	return ooc, nil
   116  }
   117  
   118  func (ooc *OrdererOrgConfig) Validate() error {
   119  	return ooc.OrganizationConfig.Validate()
   120  }
   121  
   122  // NewOrdererConfig creates a new instance of the orderer config.
   123  func NewOrdererConfig(ordererGroup *cb.ConfigGroup, mspConfig *MSPConfigHandler, channelCapabilities ChannelCapabilities) (*OrdererConfig, error) {
   124  	oc := &OrdererConfig{
   125  		protos: &OrdererProtos{},
   126  		orgs:   make(map[string]OrdererOrg),
   127  	}
   128  
   129  	if err := DeserializeProtoValuesFromGroup(ordererGroup, oc.protos); err != nil {
   130  		return nil, errors.Wrap(err, "failed to deserialize values")
   131  	}
   132  
   133  	if err := oc.Validate(); err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	for orgName, orgGroup := range ordererGroup.Groups {
   138  		var err error
   139  		if oc.orgs[orgName], err = NewOrdererOrgConfig(orgName, orgGroup, mspConfig, channelCapabilities); err != nil {
   140  			return nil, err
   141  		}
   142  	}
   143  	return oc, nil
   144  }
   145  
   146  // ConsensusType returns the configured consensus type.
   147  func (oc *OrdererConfig) ConsensusType() string {
   148  	return oc.protos.ConsensusType.Type
   149  }
   150  
   151  // ConsensusMetadata returns the metadata associated with the consensus type.
   152  func (oc *OrdererConfig) ConsensusMetadata() []byte {
   153  	return oc.protos.ConsensusType.Metadata
   154  }
   155  
   156  // ConsensusState return the consensus type state.
   157  func (oc *OrdererConfig) ConsensusState() ab.ConsensusType_State {
   158  	return oc.protos.ConsensusType.State
   159  }
   160  
   161  // BatchSize returns the maximum number of messages to include in a block.
   162  func (oc *OrdererConfig) BatchSize() *ab.BatchSize {
   163  	return oc.protos.BatchSize
   164  }
   165  
   166  // BatchTimeout returns the amount of time to wait before creating a batch.
   167  func (oc *OrdererConfig) BatchTimeout() time.Duration {
   168  	return oc.batchTimeout
   169  }
   170  
   171  // KafkaBrokers returns the addresses (IP:port notation) of a set of "bootstrap"
   172  // Kafka brokers, i.e. this is not necessarily the entire set of Kafka brokers
   173  // used for ordering.
   174  func (oc *OrdererConfig) KafkaBrokers() []string {
   175  	return oc.protos.KafkaBrokers.Brokers
   176  }
   177  
   178  // MaxChannelsCount returns the maximum count of channels this orderer supports.
   179  func (oc *OrdererConfig) MaxChannelsCount() uint64 {
   180  	return oc.protos.ChannelRestrictions.MaxCount
   181  }
   182  
   183  // Organizations returns a map of the orgs in the channel.
   184  func (oc *OrdererConfig) Organizations() map[string]OrdererOrg {
   185  	return oc.orgs
   186  }
   187  
   188  // Capabilities returns the capabilities the ordering network has for this channel.
   189  func (oc *OrdererConfig) Capabilities() OrdererCapabilities {
   190  	return capabilities.NewOrdererProvider(oc.protos.Capabilities.Capabilities)
   191  }
   192  
   193  func (oc *OrdererConfig) Validate() error {
   194  	for _, validator := range []func() error{
   195  		oc.validateBatchSize,
   196  		oc.validateBatchTimeout,
   197  		oc.validateKafkaBrokers,
   198  	} {
   199  		if err := validator(); err != nil {
   200  			return err
   201  		}
   202  	}
   203  
   204  	return nil
   205  }
   206  
   207  func (oc *OrdererConfig) validateBatchSize() error {
   208  	if oc.protos.BatchSize.MaxMessageCount == 0 {
   209  		return fmt.Errorf("Attempted to set the batch size max message count to an invalid value: 0")
   210  	}
   211  	if oc.protos.BatchSize.AbsoluteMaxBytes == 0 {
   212  		return fmt.Errorf("Attempted to set the batch size absolute max bytes to an invalid value: 0")
   213  	}
   214  	if oc.protos.BatchSize.PreferredMaxBytes == 0 {
   215  		return fmt.Errorf("Attempted to set the batch size preferred max bytes to an invalid value: 0")
   216  	}
   217  	if oc.protos.BatchSize.PreferredMaxBytes > oc.protos.BatchSize.AbsoluteMaxBytes {
   218  		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)
   219  	}
   220  	return nil
   221  }
   222  
   223  func (oc *OrdererConfig) validateBatchTimeout() error {
   224  	var err error
   225  	oc.batchTimeout, err = time.ParseDuration(oc.protos.BatchTimeout.Timeout)
   226  	if err != nil {
   227  		return fmt.Errorf("Attempted to set the batch timeout to a invalid value: %s", err)
   228  	}
   229  	if oc.batchTimeout <= 0 {
   230  		return fmt.Errorf("Attempted to set the batch timeout to a non-positive value: %s", oc.batchTimeout)
   231  	}
   232  	return nil
   233  }
   234  
   235  func (oc *OrdererConfig) validateKafkaBrokers() error {
   236  	for _, broker := range oc.protos.KafkaBrokers.Brokers {
   237  		if !brokerEntrySeemsValid(broker) {
   238  			return fmt.Errorf("Invalid broker entry: %s", broker)
   239  		}
   240  	}
   241  	return nil
   242  }
   243  
   244  // This does just a barebones sanity check.
   245  func brokerEntrySeemsValid(broker string) bool {
   246  	if !strings.Contains(broker, ":") {
   247  		return false
   248  	}
   249  
   250  	parts := strings.Split(broker, ":")
   251  	if len(parts) > 2 {
   252  		return false
   253  	}
   254  
   255  	host := parts[0]
   256  	port := parts[1]
   257  
   258  	if _, err := strconv.ParseUint(port, 10, 16); err != nil {
   259  		return false
   260  	}
   261  
   262  	// Valid hostnames may contain only the ASCII letters 'a' through 'z' (in a
   263  	// case-insensitive manner), the digits '0' through '9', and the hyphen. IP
   264  	// v4 addresses are  represented in dot-decimal notation, which consists of
   265  	// four decimal numbers, each ranging from 0 to 255, separated by dots,
   266  	// e.g., 172.16.254.1
   267  	// The following regular expression:
   268  	// 1. allows just a-z (case-insensitive), 0-9, and the dot and hyphen characters
   269  	// 2. does not allow leading trailing dots or hyphens
   270  	re, _ := regexp.Compile("^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9])$")
   271  	matched := re.FindString(host)
   272  	return len(matched) == len(host)
   273  }