github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/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/inklabsfoundation/inkchain/common/config" 16 "github.com/inklabsfoundation/inkchain/common/configtx" 17 configtxapi "github.com/inklabsfoundation/inkchain/common/configtx/api" 18 configtxtest "github.com/inklabsfoundation/inkchain/common/configtx/test" 19 "github.com/inklabsfoundation/inkchain/common/flogging" 20 mockconfigtx "github.com/inklabsfoundation/inkchain/common/mocks/configtx" 21 mockpolicies "github.com/inklabsfoundation/inkchain/common/mocks/policies" 22 "github.com/inklabsfoundation/inkchain/common/policies" 23 "github.com/inklabsfoundation/inkchain/core/comm" 24 "github.com/inklabsfoundation/inkchain/core/committer" 25 "github.com/inklabsfoundation/inkchain/core/committer/txvalidator" 26 "github.com/inklabsfoundation/inkchain/core/ledger" 27 "github.com/inklabsfoundation/inkchain/core/ledger/ledgermgmt" 28 "github.com/inklabsfoundation/inkchain/gossip/api" 29 "github.com/inklabsfoundation/inkchain/gossip/service" 30 "github.com/inklabsfoundation/inkchain/msp" 31 mspmgmt "github.com/inklabsfoundation/inkchain/msp/mgmt" 32 "github.com/inklabsfoundation/inkchain/protos/common" 33 pb "github.com/inklabsfoundation/inkchain/protos/peer" 34 "github.com/inklabsfoundation/inkchain/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 ac, ok := cm.ApplicationConfig() 386 if ok { 387 //loop through app orgs and build map of MSPIDs 388 for _, appOrg := range ac.Organizations() { 389 appOrgMSPs[appOrg.MSPID()] = struct{}{} 390 } 391 } 392 393 cid := cm.ChainID() 394 peerLogger.Debugf("updating root CAs for channel [%s]", cid) 395 msps, err := cm.MSPManager().GetMSPs() 396 if err != nil { 397 peerLogger.Errorf("Error getting root CAs for channel %s (%s)", cid, err) 398 } 399 if err == nil { 400 for k, v := range msps { 401 // check to see if this is a INKCHAIN MSP 402 if v.GetType() == msp.INKCHAIN { 403 for _, root := range v.GetTLSRootCerts() { 404 // check to see of this is an app org MSP 405 if _, ok := appOrgMSPs[k]; ok { 406 peerLogger.Debugf("adding app root CAs for MSP [%s]", k) 407 appRootCAs = append(appRootCAs, root) 408 } else { 409 peerLogger.Debugf("adding orderer root CAs for MSP [%s]", k) 410 ordererRootCAs = append(ordererRootCAs, root) 411 } 412 } 413 for _, intermediate := range v.GetTLSIntermediateCerts() { 414 // check to see of this is an app org MSP 415 if _, ok := appOrgMSPs[k]; ok { 416 peerLogger.Debugf("adding app root CAs for MSP [%s]", k) 417 appRootCAs = append(appRootCAs, intermediate) 418 } else { 419 peerLogger.Debugf("adding orderer root CAs for MSP [%s]", k) 420 ordererRootCAs = append(ordererRootCAs, intermediate) 421 } 422 } 423 } 424 } 425 rootCASupport.AppRootCAsByChain[cid] = appRootCAs 426 rootCASupport.OrdererRootCAsByChain[cid] = ordererRootCAs 427 } 428 } 429 430 // GetMSPIDs returns the ID of each application MSP defined on this chain 431 func GetMSPIDs(cid string) []string { 432 chains.RLock() 433 defer chains.RUnlock() 434 435 //if mock is set, use it to return MSPIDs 436 //used for tests without a proper join 437 if mockMSPIDGetter != nil { 438 return mockMSPIDGetter(cid) 439 } 440 if c, ok := chains.list[cid]; ok { 441 if c == nil || c.cs == nil { 442 return nil 443 } 444 ac, ok := c.cs.ApplicationConfig() 445 if !ok || ac.Organizations() == nil { 446 return nil 447 } 448 449 orgs := ac.Organizations() 450 toret := make([]string, len(orgs)) 451 i := 0 452 for _, org := range orgs { 453 toret[i] = org.MSPID() 454 i++ 455 } 456 457 return toret 458 } 459 return nil 460 } 461 462 // SetCurrConfigBlock sets the current config block of the specified chain 463 func SetCurrConfigBlock(block *common.Block, cid string) error { 464 chains.Lock() 465 defer chains.Unlock() 466 if c, ok := chains.list[cid]; ok { 467 c.cb = block 468 return nil 469 } 470 return fmt.Errorf("Chain %s doesn't exist on the peer", cid) 471 } 472 473 // NewPeerClientConnection Returns a new grpc.ClientConn to the configured local PEER. 474 func NewPeerClientConnection() (*grpc.ClientConn, error) { 475 return NewPeerClientConnectionWithAddress(viper.GetString("peer.address")) 476 } 477 478 // GetLocalIP returns the non loopback local IP of the host 479 func GetLocalIP() string { 480 addrs, err := net.InterfaceAddrs() 481 if err != nil { 482 return "" 483 } 484 for _, address := range addrs { 485 // check the address type and if it is not a loopback then display it 486 if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 487 if ipnet.IP.To4() != nil { 488 return ipnet.IP.String() 489 } 490 } 491 } 492 return "" 493 } 494 495 // NewPeerClientConnectionWithAddress Returns a new grpc.ClientConn to the configured local PEER. 496 func NewPeerClientConnectionWithAddress(peerAddress string) (*grpc.ClientConn, error) { 497 if comm.TLSEnabled() { 498 return comm.NewClientConnectionWithAddress(peerAddress, true, true, comm.InitTLSForPeer()) 499 } 500 return comm.NewClientConnectionWithAddress(peerAddress, true, false, nil) 501 } 502 503 // GetChannelsInfo returns an array with information about all channels for 504 // this peer 505 func GetChannelsInfo() []*pb.ChannelInfo { 506 // array to store metadata for all channels 507 var channelInfoArray []*pb.ChannelInfo 508 509 chains.RLock() 510 defer chains.RUnlock() 511 for key := range chains.list { 512 channelInfo := &pb.ChannelInfo{ChannelId: key} 513 514 // add this specific chaincode's metadata to the array of all chaincodes 515 channelInfoArray = append(channelInfoArray, channelInfo) 516 } 517 518 return channelInfoArray 519 } 520 521 // NewChannelPolicyManagerGetter returns a new instance of ChannelPolicyManagerGetter 522 func NewChannelPolicyManagerGetter() policies.ChannelPolicyManagerGetter { 523 return &channelPolicyManagerGetter{} 524 } 525 526 type channelPolicyManagerGetter struct{} 527 528 func (c *channelPolicyManagerGetter) Manager(channelID string) (policies.Manager, bool) { 529 policyManager := GetPolicyManager(channelID) 530 return policyManager, policyManager != nil 531 } 532 533 // CreatePeerServer creates an instance of comm.GRPCServer 534 // This server is used for peer communications 535 func CreatePeerServer(listenAddress string, 536 secureConfig comm.SecureServerConfig) (comm.GRPCServer, error) { 537 538 var err error 539 peerServer, err = comm.NewGRPCServer(listenAddress, secureConfig) 540 if err != nil { 541 peerLogger.Errorf("Failed to create peer server (%s)", err) 542 return nil, err 543 } 544 return peerServer, nil 545 } 546 547 // GetPeerServer returns the peer server instance 548 func GetPeerServer() comm.GRPCServer { 549 return peerServer 550 }