github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/peer/config.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 // The 'viper' package for configuration handling is very flexible, but has 8 // been found to have extremely poor performance when configuration values are 9 // accessed repeatedly. The function CacheConfiguration() defined here caches 10 // all configuration values that are accessed frequently. These parameters 11 // are now presented as function calls that access local configuration 12 // variables. This seems to be the most robust way to represent these 13 // parameters in the face of the numerous ways that configuration files are 14 // loaded and used (e.g, normal usage vs. test cases). 15 16 // The CacheConfiguration() function is allowed to be called globally to 17 // ensure that the correct values are always cached; See for example how 18 // certain parameters are forced in 'ChaincodeDevMode' in main.go. 19 20 package peer 21 22 import ( 23 "crypto/tls" 24 "fmt" 25 "io/ioutil" 26 "net" 27 "path/filepath" 28 "runtime" 29 "time" 30 31 "github.com/hechain20/hechain/common/viperutil" 32 "github.com/hechain20/hechain/core/config" 33 "github.com/hechain20/hechain/internal/pkg/comm" 34 gatewayconfig "github.com/hechain20/hechain/internal/pkg/gateway/config" 35 "github.com/pkg/errors" 36 "github.com/spf13/viper" 37 ) 38 39 // ExternalBuilder represents the configuration structure of 40 // a chaincode external builder 41 type ExternalBuilder struct { 42 // TODO: Remove Environment in 3.0 43 // Deprecated: Environment is retained for backwards compatibility. 44 // New deployments should use the new PropagateEnvironment field 45 Environment []string `yaml:"environmentWhitelist"` 46 PropagateEnvironment []string `yaml:"propagateEnvironment"` 47 Name string `yaml:"name"` 48 Path string `yaml:"path"` 49 } 50 51 // Config is the struct that defines the Peer configurations. 52 type Config struct { 53 // LocalMSPID is the identifier of the local MSP. 54 LocalMSPID string 55 // ListenAddress is the local address the peer will listen on. It must be 56 // formatted as [host | ipaddr]:port. 57 ListenAddress string 58 // PeerID provides a name for this peer instance. It is used when naming 59 // docker resources to segregate fabric networks and peers. 60 PeerID string 61 // PeerAddress is the address other peers and clients should use to 62 // communicate with the peer. It must be formatted as [host | ipaddr]:port. 63 // When used by the CLI, it represents the target peer endpoint. 64 PeerAddress string 65 // NetworkID specifies a name to use for logical separation of networks. It 66 // is used when naming docker resources to segregate fabric networks and 67 // peers. 68 NetworkID string 69 // ChaincodeListenAddress is the endpoint on which this peer will listen for 70 // chaincode connections. If omitted, it defaults to the host portion of 71 // PeerAddress and port 7052. 72 ChaincodeListenAddress string 73 // ChaincodeAddress specifies the endpoint chaincode launched by the peer 74 // should use to connect to the peer. If omitted, it defaults to 75 // ChaincodeListenAddress and falls back to ListenAddress. 76 ChaincodeAddress string 77 // ValidatorPoolSize indicates the number of goroutines that will execute 78 // transaction validation in parallel. If omitted, it defaults to number of 79 // hardware threads on the machine. 80 ValidatorPoolSize int 81 82 // ----- Peer Delivery Client Keepalive ----- 83 // DeliveryClient Keepalive settings for communication with ordering nodes. 84 DeliverClientKeepaliveOptions comm.KeepaliveOptions 85 86 // ----- Profile ----- 87 // TODO: create separate sub-struct for Profile config. 88 89 // ProfileEnabled determines if the go pprof endpoint is enabled in the peer. 90 ProfileEnabled bool 91 // ProfileListenAddress is the address the pprof server should accept 92 // connections on. 93 ProfileListenAddress string 94 95 // ----- Discovery ----- 96 97 // The discovery service is used by clients to query information about peers, 98 // such as - which peers have joined a certain channel, what is the latest 99 // channel config, and most importantly - given a chaincode and a channel, what 100 // possible sets of peers satisfy the endorsement policy. 101 // TODO: create separate sub-struct for Discovery config. 102 103 // DiscoveryEnabled is used to enable the discovery service. 104 DiscoveryEnabled bool 105 // DiscoveryOrgMembersAllowed allows non-admins to perform non channel-scoped queries. 106 DiscoveryOrgMembersAllowed bool 107 // DiscoveryAuthCacheEnabled is used to enable the authentication cache. 108 DiscoveryAuthCacheEnabled bool 109 // DiscoveryAuthCacheMaxSize sets the maximum size of authentication cache. 110 DiscoveryAuthCacheMaxSize int 111 // DiscoveryAuthCachePurgeRetentionRatio set the proportion of entries remains in cache 112 // after overpopulation purge. 113 DiscoveryAuthCachePurgeRetentionRatio float64 114 115 // ----- Limits ----- 116 // Limits is used to configure some internal resource limits. 117 // TODO: create separate sub-struct for Limits config. 118 119 // LimitsConcurrencyEndorserService sets the limits for concurrent requests sent to 120 // endorser service that handles chaincode deployment, query and invocation, 121 // including both user chaincodes and system chaincodes. 122 LimitsConcurrencyEndorserService int 123 124 // LimitsConcurrencyDeliverService sets the limits for concurrent event listeners 125 // registered to deliver service for blocks and transaction events. 126 LimitsConcurrencyDeliverService int 127 128 // LimitsConcurrencyGatewayService sets the limits for concurrent requests to 129 // gateway service that handles the submission and evaluation of transactions. 130 LimitsConcurrencyGatewayService int 131 132 // ----- TLS ----- 133 // Require server-side TLS. 134 // TODO: create separate sub-struct for PeerTLS config. 135 136 // PeerTLSEnabled enables/disables Peer TLS. 137 PeerTLSEnabled bool 138 139 // ----- Authentication ----- 140 // Authentication contains configuration parameters related to authenticating 141 // client messages. 142 // TODO: create separate sub-struct for Authentication config. 143 144 // AuthenticationTimeWindow sets the acceptable time duration for current 145 // server time and client's time as specified in a client request message. 146 AuthenticationTimeWindow time.Duration 147 148 // Endpoint of the vm management system. For docker can be one of the following in general 149 // unix:///var/run/docker.sock 150 // http://localhost:2375 151 // https://localhost:2376 152 VMEndpoint string 153 154 // ----- vm.docker.tls ----- 155 // TODO: create separate sub-struct for VM.Docker.TLS config. 156 157 // VMDockerTLSEnabled enables/disables TLS for dockers. 158 VMDockerTLSEnabled bool 159 VMDockerAttachStdout bool 160 // VMNetworkMode sets the networking mode for the container. 161 VMNetworkMode string 162 163 // ChaincodePull enables/disables force pulling of the base docker image. 164 ChaincodePull bool 165 // ExternalBuilders represents the builders and launchers for 166 // chaincode. The external builder detection processing will iterate over the 167 // builders in the order specified below. 168 ExternalBuilders []ExternalBuilder 169 170 // ----- Operations config ----- 171 // TODO: create separate sub-struct for Operations config. 172 173 // OperationsListenAddress provides the host and port for the operations server 174 OperationsListenAddress string 175 // OperationsTLSEnabled enables/disables TLS for operations. 176 OperationsTLSEnabled bool 177 // OperationsTLSCertFile provides the path to PEM encoded server certificate for 178 // the operations server. 179 OperationsTLSCertFile string 180 // OperationsTLSKeyFile provides the path to PEM encoded server key for the 181 // operations server. 182 OperationsTLSKeyFile string 183 // OperationsTLSClientAuthRequired enables/disables the requirements for client 184 // certificate authentication at the TLS layer to access all resource. 185 OperationsTLSClientAuthRequired bool 186 // OperationsTLSClientRootCAs provides the path to PEM encoded ca certiricates to 187 // trust for client authentication. 188 OperationsTLSClientRootCAs []string 189 190 // ----- Metrics config ----- 191 // TODO: create separate sub-struct for Metrics config. 192 193 // MetricsProvider provides the categories of metrics providers, which is one of 194 // statsd, prometheus, or disabled. 195 MetricsProvider string 196 // StatsdNetwork indicate the network type used by statsd metrics. (tcp or udp). 197 StatsdNetwork string 198 // StatsdAaddress provides the address for statsd server. 199 StatsdAaddress string 200 // StatsdWriteInterval set the time interval at which locally cached counters and 201 // gauges are pushed. 202 StatsdWriteInterval time.Duration 203 // StatsdPrefix provides the prefix that prepended to all emitted statsd metrics. 204 StatsdPrefix string 205 206 // ----- Docker config ------ 207 208 // DockerCert is the path to the PEM encoded TLS client certificate required to access 209 // the docker daemon. 210 DockerCert string 211 // DockerKey is the path to the PEM encoded key required to access the docker daemon. 212 DockerKey string 213 // DockerCA is the path to the PEM encoded CA certificate for the docker daemon. 214 DockerCA string 215 216 // ----- Gateway config ----- 217 218 // The gateway service is used by client SDKs to 219 // interact with fabric networks 220 221 GatewayOptions gatewayconfig.Options 222 } 223 224 // GlobalConfig obtains a set of configuration from viper, build and returns 225 // the config struct. 226 func GlobalConfig() (*Config, error) { 227 c := &Config{} 228 if err := c.load(); err != nil { 229 return nil, err 230 } 231 return c, nil 232 } 233 234 func (c *Config) load() error { 235 peerAddress, err := getLocalAddress() 236 if err != nil { 237 return err 238 } 239 240 configDir := filepath.Dir(viper.ConfigFileUsed()) 241 242 c.PeerAddress = peerAddress 243 c.PeerID = viper.GetString("peer.id") 244 c.LocalMSPID = viper.GetString("peer.localMspId") 245 c.ListenAddress = viper.GetString("peer.listenAddress") 246 247 c.AuthenticationTimeWindow = viper.GetDuration("peer.authentication.timewindow") 248 if c.AuthenticationTimeWindow == 0 { 249 defaultTimeWindow := 15 * time.Minute 250 logger.Warningf("`peer.authentication.timewindow` not set; defaulting to %s", defaultTimeWindow) 251 c.AuthenticationTimeWindow = defaultTimeWindow 252 } 253 254 c.PeerTLSEnabled = viper.GetBool("peer.tls.enabled") 255 c.NetworkID = viper.GetString("peer.networkId") 256 c.LimitsConcurrencyEndorserService = viper.GetInt("peer.limits.concurrency.endorserService") 257 c.LimitsConcurrencyDeliverService = viper.GetInt("peer.limits.concurrency.deliverService") 258 c.LimitsConcurrencyGatewayService = viper.GetInt("peer.limits.concurrency.gatewayService") 259 c.DiscoveryEnabled = viper.GetBool("peer.discovery.enabled") 260 c.ProfileEnabled = viper.GetBool("peer.profile.enabled") 261 c.ProfileListenAddress = viper.GetString("peer.profile.listenAddress") 262 c.DiscoveryOrgMembersAllowed = viper.GetBool("peer.discovery.orgMembersAllowedAccess") 263 c.DiscoveryAuthCacheEnabled = viper.GetBool("peer.discovery.authCacheEnabled") 264 c.DiscoveryAuthCacheMaxSize = viper.GetInt("peer.discovery.authCacheMaxSize") 265 c.DiscoveryAuthCachePurgeRetentionRatio = viper.GetFloat64("peer.discovery.authCachePurgeRetentionRatio") 266 c.ChaincodeListenAddress = viper.GetString("peer.chaincodeListenAddress") 267 c.ChaincodeAddress = viper.GetString("peer.chaincodeAddress") 268 269 c.ValidatorPoolSize = viper.GetInt("peer.validatorPoolSize") 270 if c.ValidatorPoolSize <= 0 { 271 c.ValidatorPoolSize = runtime.NumCPU() 272 } 273 274 c.DeliverClientKeepaliveOptions = comm.DefaultKeepaliveOptions 275 if viper.IsSet("peer.keepalive.deliveryClient.interval") { 276 c.DeliverClientKeepaliveOptions.ClientInterval = viper.GetDuration("peer.keepalive.deliveryClient.interval") 277 } 278 if viper.IsSet("peer.keepalive.deliveryClient.timeout") { 279 c.DeliverClientKeepaliveOptions.ClientTimeout = viper.GetDuration("peer.keepalive.deliveryClient.timeout") 280 } 281 282 c.GatewayOptions = gatewayconfig.GetOptions(viper.GetViper()) 283 284 c.VMEndpoint = viper.GetString("vm.endpoint") 285 c.VMDockerTLSEnabled = viper.GetBool("vm.docker.tls.enabled") 286 c.VMDockerAttachStdout = viper.GetBool("vm.docker.attachStdout") 287 288 c.VMNetworkMode = viper.GetString("vm.docker.hostConfig.NetworkMode") 289 if c.VMNetworkMode == "" { 290 c.VMNetworkMode = "host" 291 } 292 293 c.ChaincodePull = viper.GetBool("chaincode.pull") 294 var externalBuilders []ExternalBuilder 295 296 err = viper.UnmarshalKey("chaincode.externalBuilders", &externalBuilders, viper.DecodeHook(viperutil.YamlStringToStructHook(externalBuilders))) 297 if err != nil { 298 return err 299 } 300 301 c.ExternalBuilders = externalBuilders 302 for builderIndex, builder := range c.ExternalBuilders { 303 if builder.Path == "" { 304 return fmt.Errorf("invalid external builder configuration, path attribute missing in one or more builders") 305 } 306 if builder.Name == "" { 307 return fmt.Errorf("external builder at path %s has no name attribute", builder.Path) 308 } 309 if builder.Environment != nil && builder.PropagateEnvironment == nil { 310 c.ExternalBuilders[builderIndex].PropagateEnvironment = builder.Environment 311 } 312 } 313 314 c.OperationsListenAddress = viper.GetString("operations.listenAddress") 315 c.OperationsTLSEnabled = viper.GetBool("operations.tls.enabled") 316 c.OperationsTLSCertFile = config.GetPath("operations.tls.cert.file") 317 c.OperationsTLSKeyFile = config.GetPath("operations.tls.key.file") 318 c.OperationsTLSClientAuthRequired = viper.GetBool("operations.tls.clientAuthRequired") 319 320 for _, rca := range viper.GetStringSlice("operations.tls.clientRootCAs.files") { 321 c.OperationsTLSClientRootCAs = append(c.OperationsTLSClientRootCAs, config.TranslatePath(configDir, rca)) 322 } 323 324 c.MetricsProvider = viper.GetString("metrics.provider") 325 c.StatsdNetwork = viper.GetString("metrics.statsd.network") 326 c.StatsdAaddress = viper.GetString("metrics.statsd.address") 327 c.StatsdWriteInterval = viper.GetDuration("metrics.statsd.writeInterval") 328 c.StatsdPrefix = viper.GetString("metrics.statsd.prefix") 329 330 c.DockerCert = config.GetPath("vm.docker.tls.cert.file") 331 c.DockerKey = config.GetPath("vm.docker.tls.key.file") 332 c.DockerCA = config.GetPath("vm.docker.tls.ca.file") 333 334 return nil 335 } 336 337 // getLocalAddress returns the address:port the local peer is operating on. Affected by env:peer.addressAutoDetect 338 func getLocalAddress() (string, error) { 339 peerAddress := viper.GetString("peer.address") 340 if peerAddress == "" { 341 return "", fmt.Errorf("peer.address isn't set") 342 } 343 host, port, err := net.SplitHostPort(peerAddress) 344 if err != nil { 345 return "", errors.Errorf("peer.address isn't in host:port format: %s", peerAddress) 346 } 347 348 localIP, err := getLocalIP() 349 if err != nil { 350 peerLogger.Errorf("local IP address not auto-detectable: %s", err) 351 return "", err 352 } 353 autoDetectedIPAndPort := net.JoinHostPort(localIP, port) 354 peerLogger.Info("Auto-detected peer address:", autoDetectedIPAndPort) 355 // If host is the IPv4 address "0.0.0.0" or the IPv6 address "::", 356 // then fallback to auto-detected address 357 if ip := net.ParseIP(host); ip != nil && ip.IsUnspecified() { 358 peerLogger.Info("Host is", host, ", falling back to auto-detected address:", autoDetectedIPAndPort) 359 return autoDetectedIPAndPort, nil 360 } 361 362 if viper.GetBool("peer.addressAutoDetect") { 363 peerLogger.Info("Auto-detect flag is set, returning", autoDetectedIPAndPort) 364 return autoDetectedIPAndPort, nil 365 } 366 peerLogger.Info("Returning", peerAddress) 367 return peerAddress, nil 368 } 369 370 // getLocalIP returns the a loopback local IP of the host. 371 func getLocalIP() (string, error) { 372 addrs, err := net.InterfaceAddrs() 373 if err != nil { 374 return "", err 375 } 376 for _, address := range addrs { 377 // check the address type and if it is not a loopback then display it 378 if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 379 if ipnet.IP.To4() != nil { 380 return ipnet.IP.String(), nil 381 } 382 } 383 } 384 return "", errors.Errorf("no non-loopback, IPv4 interface detected") 385 } 386 387 // GetServerConfig returns the gRPC server configuration for the peer 388 func GetServerConfig() (comm.ServerConfig, error) { 389 serverConfig := comm.ServerConfig{ 390 ConnectionTimeout: viper.GetDuration("peer.connectiontimeout"), 391 SecOpts: comm.SecureOptions{ 392 UseTLS: viper.GetBool("peer.tls.enabled"), 393 }, 394 } 395 if serverConfig.SecOpts.UseTLS { 396 // get the certs from the file system 397 serverKey, err := ioutil.ReadFile(config.GetPath("peer.tls.key.file")) 398 if err != nil { 399 return serverConfig, fmt.Errorf("error loading TLS key (%s)", err) 400 } 401 serverCert, err := ioutil.ReadFile(config.GetPath("peer.tls.cert.file")) 402 if err != nil { 403 return serverConfig, fmt.Errorf("error loading TLS certificate (%s)", err) 404 } 405 serverConfig.SecOpts.Certificate = serverCert 406 serverConfig.SecOpts.Key = serverKey 407 serverConfig.SecOpts.RequireClientCert = viper.GetBool("peer.tls.clientAuthRequired") 408 if serverConfig.SecOpts.RequireClientCert { 409 var clientRoots [][]byte 410 for _, file := range viper.GetStringSlice("peer.tls.clientRootCAs.files") { 411 clientRoot, err := ioutil.ReadFile( 412 config.TranslatePath(filepath.Dir(viper.ConfigFileUsed()), file)) 413 if err != nil { 414 return serverConfig, 415 fmt.Errorf("error loading client root CAs (%s)", err) 416 } 417 clientRoots = append(clientRoots, clientRoot) 418 } 419 serverConfig.SecOpts.ClientRootCAs = clientRoots 420 } 421 // check for root cert 422 if config.GetPath("peer.tls.rootcert.file") != "" { 423 rootCert, err := ioutil.ReadFile(config.GetPath("peer.tls.rootcert.file")) 424 if err != nil { 425 return serverConfig, fmt.Errorf("error loading TLS root certificate (%s)", err) 426 } 427 serverConfig.SecOpts.ServerRootCAs = [][]byte{rootCert} 428 } 429 } 430 // get the default keepalive options 431 serverConfig.KaOpts = comm.DefaultKeepaliveOptions 432 // check to see if interval is set for the env 433 if viper.IsSet("peer.keepalive.interval") { 434 serverConfig.KaOpts.ServerInterval = viper.GetDuration("peer.keepalive.interval") 435 } 436 // check to see if timeout is set for the env 437 if viper.IsSet("peer.keepalive.timeout") { 438 serverConfig.KaOpts.ServerTimeout = viper.GetDuration("peer.keepalive.timeout") 439 } 440 // check to see if minInterval is set for the env 441 if viper.IsSet("peer.keepalive.minInterval") { 442 serverConfig.KaOpts.ServerMinInterval = viper.GetDuration("peer.keepalive.minInterval") 443 } 444 445 serverConfig.MaxRecvMsgSize = comm.DefaultMaxRecvMsgSize 446 serverConfig.MaxSendMsgSize = comm.DefaultMaxSendMsgSize 447 448 if viper.IsSet("peer.maxRecvMsgSize") { 449 serverConfig.MaxRecvMsgSize = int(viper.GetInt32("peer.maxRecvMsgSize")) 450 } 451 if viper.IsSet("peer.maxSendMsgSize") { 452 serverConfig.MaxSendMsgSize = int(viper.GetInt32("peer.maxSendMsgSize")) 453 } 454 return serverConfig, nil 455 } 456 457 // GetClientCertificate returns the TLS certificate to use for gRPC client 458 // connections 459 func GetClientCertificate() (tls.Certificate, error) { 460 cert := tls.Certificate{} 461 462 keyPath := viper.GetString("peer.tls.clientKey.file") 463 certPath := viper.GetString("peer.tls.clientCert.file") 464 465 if keyPath != "" || certPath != "" { 466 // need both keyPath and certPath to be set 467 if keyPath == "" || certPath == "" { 468 return cert, errors.New("peer.tls.clientKey.file and " + 469 "peer.tls.clientCert.file must both be set or must both be empty") 470 } 471 keyPath = config.GetPath("peer.tls.clientKey.file") 472 certPath = config.GetPath("peer.tls.clientCert.file") 473 474 } else { 475 // use the TLS server keypair 476 keyPath = viper.GetString("peer.tls.key.file") 477 certPath = viper.GetString("peer.tls.cert.file") 478 479 if keyPath != "" || certPath != "" { 480 // need both keyPath and certPath to be set 481 if keyPath == "" || certPath == "" { 482 return cert, errors.New("peer.tls.key.file and " + 483 "peer.tls.cert.file must both be set or must both be empty") 484 } 485 keyPath = config.GetPath("peer.tls.key.file") 486 certPath = config.GetPath("peer.tls.cert.file") 487 } else { 488 return cert, errors.New("must set either " + 489 "[peer.tls.key.file and peer.tls.cert.file] or " + 490 "[peer.tls.clientKey.file and peer.tls.clientCert.file]" + 491 "when peer.tls.clientAuthEnabled is set to true") 492 } 493 } 494 // get the keypair from the file system 495 clientKey, err := ioutil.ReadFile(keyPath) 496 if err != nil { 497 return cert, errors.WithMessage(err, 498 "error loading client TLS key") 499 } 500 clientCert, err := ioutil.ReadFile(certPath) 501 if err != nil { 502 return cert, errors.WithMessage(err, 503 "error loading client TLS certificate") 504 } 505 cert, err = tls.X509KeyPair(clientCert, clientKey) 506 if err != nil { 507 return cert, errors.WithMessage(err, 508 "error parsing client TLS key pair") 509 } 510 return cert, nil 511 }