github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/core/peer/peer.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package peer 8 9 import ( 10 "errors" 11 "fmt" 12 "net" 13 "sync" 14 15 "github.com/hyperledger/fabric/common/config" 16 "github.com/hyperledger/fabric/common/configtx" 17 configtxapi "github.com/hyperledger/fabric/common/configtx/api" 18 configtxtest "github.com/hyperledger/fabric/common/configtx/test" 19 "github.com/hyperledger/fabric/common/flogging" 20 mockconfigtx "github.com/hyperledger/fabric/common/mocks/configtx" 21 mockpolicies "github.com/hyperledger/fabric/common/mocks/policies" 22 "github.com/hyperledger/fabric/common/policies" 23 "github.com/hyperledger/fabric/core/comm" 24 "github.com/hyperledger/fabric/core/committer" 25 "github.com/hyperledger/fabric/core/committer/txvalidator" 26 "github.com/hyperledger/fabric/core/ledger" 27 "github.com/hyperledger/fabric/core/ledger/ledgermgmt" 28 "github.com/hyperledger/fabric/gossip/api" 29 "github.com/hyperledger/fabric/gossip/service" 30 "github.com/hyperledger/fabric/msp" 31 mspmgmt "github.com/hyperledger/fabric/msp/mgmt" 32 "github.com/hyperledger/fabric/protos/common" 33 pb "github.com/hyperledger/fabric/protos/peer" 34 "github.com/hyperledger/fabric/protos/utils" 35 "github.com/spf13/viper" 36 "google.golang.org/grpc" 37 ) 38 39 var peerLogger = flogging.MustGetLogger("peer") 40 41 var peerServer comm.GRPCServer 42 43 // singleton instance to manage CAs for the peer across channel config changes 44 var rootCASupport = comm.GetCASupport() 45 46 type chainSupport struct { 47 configtxapi.Manager 48 config.Application 49 ledger ledger.PeerLedger 50 } 51 52 func (cs *chainSupport) Ledger() ledger.PeerLedger { 53 return cs.ledger 54 } 55 56 func (cs *chainSupport) GetMSPIDs(cid string) []string { 57 return GetMSPIDs(cid) 58 } 59 60 // chain is a local struct to manage objects in a chain 61 type chain struct { 62 cs *chainSupport 63 cb *common.Block 64 committer committer.Committer 65 } 66 67 // chains is a local map of chainID->chainObject 68 var chains = struct { 69 sync.RWMutex 70 list map[string]*chain 71 }{list: make(map[string]*chain)} 72 73 //MockInitialize resets chains for test env 74 func MockInitialize() { 75 ledgermgmt.InitializeTestEnv() 76 chains.list = nil 77 chains.list = make(map[string]*chain) 78 chainInitializer = func(string) { return } 79 } 80 81 var chainInitializer func(string) 82 83 var mockMSPIDGetter func(string) []string 84 85 func MockSetMSPIDGetter(mspIDGetter func(string) []string) { 86 mockMSPIDGetter = mspIDGetter 87 } 88 89 // Initialize sets up any chains that the peer has from the persistence. This 90 // function should be called at the start up when the ledger and gossip 91 // ready 92 func Initialize(init func(string)) { 93 chainInitializer = init 94 95 var cb *common.Block 96 var ledger ledger.PeerLedger 97 ledgermgmt.Initialize() 98 ledgerIds, err := ledgermgmt.GetLedgerIDs() 99 if err != nil { 100 panic(fmt.Errorf("Error in initializing ledgermgmt: %s", err)) 101 } 102 for _, cid := range ledgerIds { 103 peerLogger.Infof("Loading chain %s", cid) 104 if ledger, err = ledgermgmt.OpenLedger(cid); err != nil { 105 peerLogger.Warningf("Failed to load ledger %s(%s)", cid, err) 106 peerLogger.Debugf("Error while loading ledger %s with message %s. We continue to the next ledger rather than abort.", cid, err) 107 continue 108 } 109 if cb, err = getCurrConfigBlockFromLedger(ledger); err != nil { 110 peerLogger.Warningf("Failed to find config block on ledger %s(%s)", cid, err) 111 peerLogger.Debugf("Error while looking for config block on ledger %s with message %s. We continue to the next ledger rather than abort.", cid, err) 112 continue 113 } 114 // Create a chain if we get a valid ledger with config block 115 if err = createChain(cid, ledger, cb); err != nil { 116 peerLogger.Warningf("Failed to load chain %s(%s)", cid, err) 117 peerLogger.Debugf("Error reloading chain %s with message %s. We continue to the next chain rather than abort.", cid, err) 118 continue 119 } 120 121 InitChain(cid) 122 } 123 } 124 125 // Take care to initialize chain after peer joined, for example deploys system CCs 126 func InitChain(cid string) { 127 if chainInitializer != nil { 128 // Initialize chaincode, namely deploy system CC 129 peerLogger.Debugf("Init chain %s", cid) 130 chainInitializer(cid) 131 } 132 } 133 134 func getCurrConfigBlockFromLedger(ledger ledger.PeerLedger) (*common.Block, error) { 135 peerLogger.Debugf("Getting config block") 136 137 // get last block. Last block number is Height-1 138 blockchainInfo, err := ledger.GetBlockchainInfo() 139 if err != nil { 140 return nil, err 141 } 142 lastBlock, err := ledger.GetBlockByNumber(blockchainInfo.Height - 1) 143 if err != nil { 144 return nil, err 145 } 146 147 // get most recent config block location from last block metadata 148 configBlockIndex, err := utils.GetLastConfigIndexFromBlock(lastBlock) 149 if err != nil { 150 return nil, err 151 } 152 153 // get most recent config block 154 configBlock, err := ledger.GetBlockByNumber(configBlockIndex) 155 if err != nil { 156 return nil, err 157 } 158 159 peerLogger.Debugf("Got config block[%d]", configBlockIndex) 160 return configBlock, nil 161 } 162 163 // createChain creates a new chain object and insert it into the chains 164 func createChain(cid string, ledger ledger.PeerLedger, cb *common.Block) error { 165 166 envelopeConfig, err := utils.ExtractEnvelope(cb, 0) 167 if err != nil { 168 return err 169 } 170 171 configtxInitializer := configtx.NewInitializer() 172 173 gossipEventer := service.GetGossipService().NewConfigEventer() 174 175 gossipCallbackWrapper := func(cm configtxapi.Manager) { 176 ac, ok := configtxInitializer.ApplicationConfig() 177 if !ok { 178 // TODO, handle a missing ApplicationConfig more gracefully 179 ac = nil 180 } 181 gossipEventer.ProcessConfigUpdate(&chainSupport{ 182 Manager: cm, 183 Application: ac, 184 }) 185 service.GetGossipService().SuspectPeers(func(identity api.PeerIdentityType) bool { 186 // TODO: this is a place-holder that would somehow make the MSP layer suspect 187 // that a given certificate is revoked, or its intermediate CA is revoked. 188 // In the meantime, before we have such an ability, we return true in order 189 // to suspect ALL identities in order to validate all of them. 190 return true 191 }) 192 } 193 194 trustedRootsCallbackWrapper := func(cm configtxapi.Manager) { 195 updateTrustedRoots(cm) 196 } 197 198 configtxManager, err := configtx.NewManagerImpl( 199 envelopeConfig, 200 configtxInitializer, 201 []func(cm configtxapi.Manager){gossipCallbackWrapper, trustedRootsCallbackWrapper}, 202 ) 203 if err != nil { 204 return err 205 } 206 207 // TODO remove once all references to mspmgmt are gone from peer code 208 mspmgmt.XXXSetMSPManager(cid, configtxManager.MSPManager()) 209 210 ac, ok := configtxInitializer.ApplicationConfig() 211 if !ok { 212 ac = nil 213 } 214 cs := &chainSupport{ 215 Manager: configtxManager, 216 Application: ac, // TODO, refactor as this is accessible through Manager 217 ledger: ledger, 218 } 219 220 c := committer.NewLedgerCommitterReactive(ledger, txvalidator.NewTxValidator(cs), func(block *common.Block) error { 221 chainID, err := utils.GetChainIDFromBlock(block) 222 if err != nil { 223 return err 224 } 225 return SetCurrConfigBlock(block, chainID) 226 }) 227 228 ordererAddresses := configtxManager.ChannelConfig().OrdererAddresses() 229 if len(ordererAddresses) == 0 { 230 return errors.New("No ordering service endpoint provided in configuration block") 231 } 232 service.GetGossipService().InitializeChannel(cs.ChainID(), c, ordererAddresses) 233 234 chains.Lock() 235 defer chains.Unlock() 236 chains.list[cid] = &chain{ 237 cs: cs, 238 cb: cb, 239 committer: c, 240 } 241 return nil 242 } 243 244 // CreateChainFromBlock creates a new chain from config block 245 func CreateChainFromBlock(cb *common.Block) error { 246 cid, err := utils.GetChainIDFromBlock(cb) 247 if err != nil { 248 return err 249 } 250 251 var l ledger.PeerLedger 252 if l, err = ledgermgmt.CreateLedger(cb); err != nil { 253 return fmt.Errorf("Cannot create ledger from genesis block, due to %s", err) 254 } 255 256 return createChain(cid, l, cb) 257 } 258 259 // MockCreateChain used for creating a ledger for a chain for tests 260 // without havin to join 261 func MockCreateChain(cid string) error { 262 var ledger ledger.PeerLedger 263 var err error 264 265 if ledger = GetLedger(cid); ledger == nil { 266 gb, _ := configtxtest.MakeGenesisBlock(cid) 267 if ledger, err = ledgermgmt.CreateLedger(gb); err != nil { 268 return err 269 } 270 } 271 272 // Here we need to mock also the policy manager 273 // in order for the ACL to be checked 274 initializer := mockconfigtx.Initializer{ 275 Resources: mockconfigtx.Resources{ 276 PolicyManagerVal: &mockpolicies.Manager{ 277 Policy: &mockpolicies.Policy{}, 278 }, 279 }, 280 PolicyProposerVal: &mockconfigtx.PolicyProposer{ 281 Transactional: mockconfigtx.Transactional{}, 282 }, 283 ValueProposerVal: &mockconfigtx.ValueProposer{ 284 Transactional: mockconfigtx.Transactional{}, 285 }, 286 } 287 manager := &mockconfigtx.Manager{ 288 Initializer: initializer, 289 } 290 291 chains.Lock() 292 defer chains.Unlock() 293 294 chains.list[cid] = &chain{ 295 cs: &chainSupport{ 296 Manager: manager, 297 ledger: ledger}, 298 } 299 300 return nil 301 } 302 303 // GetLedger returns the ledger of the chain with chain ID. Note that this 304 // call returns nil if chain cid has not been created. 305 func GetLedger(cid string) ledger.PeerLedger { 306 chains.RLock() 307 defer chains.RUnlock() 308 if c, ok := chains.list[cid]; ok { 309 return c.cs.ledger 310 } 311 return nil 312 } 313 314 // GetPolicyManager returns the policy manager of the chain with chain ID. Note that this 315 // call returns nil if chain cid has not been created. 316 func GetPolicyManager(cid string) policies.Manager { 317 chains.RLock() 318 defer chains.RUnlock() 319 if c, ok := chains.list[cid]; ok { 320 return c.cs.PolicyManager() 321 } 322 return nil 323 } 324 325 // GetCurrConfigBlock returns the cached config block of the specified chain. 326 // Note that this call returns nil if chain cid has not been created. 327 func GetCurrConfigBlock(cid string) *common.Block { 328 chains.RLock() 329 defer chains.RUnlock() 330 if c, ok := chains.list[cid]; ok { 331 return c.cb 332 } 333 return nil 334 } 335 336 // updates the trusted roots for the peer based on updates to channels 337 func updateTrustedRoots(cm configtxapi.Manager) { 338 // this is triggered on per channel basis so first update the roots for the channel 339 peerLogger.Debugf("Updating trusted root authorities for channel %s", cm.ChainID()) 340 var secureConfig comm.SecureServerConfig 341 var err error 342 // only run is TLS is enabled 343 secureConfig, err = GetSecureConfig() 344 if err == nil && secureConfig.UseTLS { 345 buildTrustedRootsForChain(cm) 346 347 // now iterate over all roots for all app and orderer chains 348 trustedRoots := [][]byte{} 349 rootCASupport.RLock() 350 defer rootCASupport.RUnlock() 351 for _, roots := range rootCASupport.AppRootCAsByChain { 352 trustedRoots = append(trustedRoots, roots...) 353 } 354 // also need to append statically configured root certs 355 if len(secureConfig.ClientRootCAs) > 0 { 356 trustedRoots = append(trustedRoots, secureConfig.ClientRootCAs...) 357 } 358 if len(secureConfig.ServerRootCAs) > 0 { 359 trustedRoots = append(trustedRoots, secureConfig.ServerRootCAs...) 360 } 361 362 server := GetPeerServer() 363 // now update the client roots for the peerServer 364 if server != nil { 365 err := server.SetClientRootCAs(trustedRoots) 366 if err != nil { 367 msg := "Failed to update trusted roots for peer from latest config " + 368 "block. This peer may not be able to communicate " + 369 "with members of channel %s (%s)" 370 peerLogger.Warningf(msg, cm.ChainID(), err) 371 } 372 } 373 } 374 } 375 376 // populates the appRootCAs and orderRootCAs maps by getting the 377 // root and intermediate certs for all msps associated with the MSPManager 378 func buildTrustedRootsForChain(cm configtxapi.Manager) { 379 rootCASupport.Lock() 380 defer rootCASupport.Unlock() 381 382 appRootCAs := [][]byte{} 383 ordererRootCAs := [][]byte{} 384 appOrgMSPs := make(map[string]struct{}) 385 ordOrgMSPs := make(map[string]struct{}) 386 387 if ac, ok := cm.ApplicationConfig(); ok { 388 //loop through app orgs and build map of MSPIDs 389 for _, appOrg := range ac.Organizations() { 390 appOrgMSPs[appOrg.MSPID()] = struct{}{} 391 } 392 } 393 394 if ac, ok := cm.OrdererConfig(); ok { 395 //loop through orderer orgs and build map of MSPIDs 396 for _, ordOrg := range ac.Organizations() { 397 ordOrgMSPs[ordOrg.MSPID()] = struct{}{} 398 } 399 } 400 401 cid := cm.ChainID() 402 peerLogger.Debugf("updating root CAs for channel [%s]", cid) 403 msps, err := cm.MSPManager().GetMSPs() 404 if err != nil { 405 peerLogger.Errorf("Error getting root CAs for channel %s (%s)", cid, err) 406 } 407 if err == nil { 408 for k, v := range msps { 409 // check to see if this is a FABRIC MSP 410 if v.GetType() == msp.FABRIC { 411 for _, root := range v.GetTLSRootCerts() { 412 // check to see of this is an app org MSP 413 if _, ok := appOrgMSPs[k]; ok { 414 peerLogger.Debugf("adding app root CAs for MSP [%s]", k) 415 appRootCAs = append(appRootCAs, root) 416 } 417 // check to see of this is an orderer org MSP 418 if _, ok := ordOrgMSPs[k]; ok { 419 peerLogger.Debugf("adding orderer root CAs for MSP [%s]", k) 420 ordererRootCAs = append(ordererRootCAs, root) 421 } 422 } 423 for _, intermediate := range v.GetTLSIntermediateCerts() { 424 // check to see of this is an app org MSP 425 if _, ok := appOrgMSPs[k]; ok { 426 peerLogger.Debugf("adding app root CAs for MSP [%s]", k) 427 appRootCAs = append(appRootCAs, intermediate) 428 } 429 // check to see of this is an orderer org MSP 430 if _, ok := ordOrgMSPs[k]; ok { 431 peerLogger.Debugf("adding orderer root CAs for MSP [%s]", k) 432 ordererRootCAs = append(ordererRootCAs, intermediate) 433 } 434 } 435 } 436 } 437 rootCASupport.AppRootCAsByChain[cid] = appRootCAs 438 rootCASupport.OrdererRootCAsByChain[cid] = ordererRootCAs 439 } 440 } 441 442 // GetMSPIDs returns the ID of each application MSP defined on this chain 443 func GetMSPIDs(cid string) []string { 444 chains.RLock() 445 defer chains.RUnlock() 446 447 //if mock is set, use it to return MSPIDs 448 //used for tests without a proper join 449 if mockMSPIDGetter != nil { 450 return mockMSPIDGetter(cid) 451 } 452 if c, ok := chains.list[cid]; ok { 453 if c == nil || c.cs == nil { 454 return nil 455 } 456 ac, ok := c.cs.ApplicationConfig() 457 if !ok || ac.Organizations() == nil { 458 return nil 459 } 460 461 orgs := ac.Organizations() 462 toret := make([]string, len(orgs)) 463 i := 0 464 for _, org := range orgs { 465 toret[i] = org.MSPID() 466 i++ 467 } 468 469 return toret 470 } 471 return nil 472 } 473 474 // SetCurrConfigBlock sets the current config block of the specified chain 475 func SetCurrConfigBlock(block *common.Block, cid string) error { 476 chains.Lock() 477 defer chains.Unlock() 478 if c, ok := chains.list[cid]; ok { 479 c.cb = block 480 return nil 481 } 482 return fmt.Errorf("Chain %s doesn't exist on the peer", cid) 483 } 484 485 // NewPeerClientConnection Returns a new grpc.ClientConn to the configured local PEER. 486 func NewPeerClientConnection() (*grpc.ClientConn, error) { 487 return NewPeerClientConnectionWithAddress(viper.GetString("peer.address")) 488 } 489 490 // GetLocalIP returns the non loopback local IP of the host 491 func GetLocalIP() string { 492 addrs, err := net.InterfaceAddrs() 493 if err != nil { 494 return "" 495 } 496 for _, address := range addrs { 497 // check the address type and if it is not a loopback then display it 498 if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 499 if ipnet.IP.To4() != nil { 500 return ipnet.IP.String() 501 } 502 } 503 } 504 return "" 505 } 506 507 // NewPeerClientConnectionWithAddress Returns a new grpc.ClientConn to the configured local PEER. 508 func NewPeerClientConnectionWithAddress(peerAddress string) (*grpc.ClientConn, error) { 509 if comm.TLSEnabled() { 510 return comm.NewClientConnectionWithAddress(peerAddress, true, true, comm.InitTLSForPeer()) 511 } 512 return comm.NewClientConnectionWithAddress(peerAddress, true, false, nil) 513 } 514 515 // GetChannelsInfo returns an array with information about all channels for 516 // this peer 517 func GetChannelsInfo() []*pb.ChannelInfo { 518 // array to store metadata for all channels 519 var channelInfoArray []*pb.ChannelInfo 520 521 chains.RLock() 522 defer chains.RUnlock() 523 for key := range chains.list { 524 channelInfo := &pb.ChannelInfo{ChannelId: key} 525 526 // add this specific chaincode's metadata to the array of all chaincodes 527 channelInfoArray = append(channelInfoArray, channelInfo) 528 } 529 530 return channelInfoArray 531 } 532 533 // NewChannelPolicyManagerGetter returns a new instance of ChannelPolicyManagerGetter 534 func NewChannelPolicyManagerGetter() policies.ChannelPolicyManagerGetter { 535 return &channelPolicyManagerGetter{} 536 } 537 538 type channelPolicyManagerGetter struct{} 539 540 func (c *channelPolicyManagerGetter) Manager(channelID string) (policies.Manager, bool) { 541 policyManager := GetPolicyManager(channelID) 542 return policyManager, policyManager != nil 543 } 544 545 // CreatePeerServer creates an instance of comm.GRPCServer 546 // This server is used for peer communications 547 func CreatePeerServer(listenAddress string, 548 secureConfig comm.SecureServerConfig) (comm.GRPCServer, error) { 549 550 var err error 551 peerServer, err = comm.NewGRPCServer(listenAddress, secureConfig) 552 if err != nil { 553 peerLogger.Errorf("Failed to create peer server (%s)", err) 554 return nil, err 555 } 556 return peerServer, nil 557 } 558 559 // GetPeerServer returns the peer server instance 560 func GetPeerServer() comm.GRPCServer { 561 return peerServer 562 }