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