github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/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/inklabsfoundation/inkchain/common/config/msp" 27 ab "github.com/inklabsfoundation/inkchain/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 }