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 }