github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/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 "fmt" 11 "sync" 12 13 "github.com/hyperledger/fabric-protos-go/common" 14 pb "github.com/hyperledger/fabric-protos-go/peer" 15 "github.com/hyperledger/fabric/bccsp" 16 "github.com/hyperledger/fabric/common/channelconfig" 17 cc "github.com/hyperledger/fabric/common/config" 18 "github.com/hyperledger/fabric/common/configtx" 19 "github.com/hyperledger/fabric/common/deliver" 20 "github.com/hyperledger/fabric/common/flogging" 21 commonledger "github.com/hyperledger/fabric/common/ledger" 22 "github.com/hyperledger/fabric/common/policies" 23 "github.com/hyperledger/fabric/common/semaphore" 24 "github.com/hyperledger/fabric/core/comm" 25 "github.com/hyperledger/fabric/core/committer" 26 "github.com/hyperledger/fabric/core/committer/txvalidator" 27 "github.com/hyperledger/fabric/core/committer/txvalidator/plugin" 28 validatorv14 "github.com/hyperledger/fabric/core/committer/txvalidator/v14" 29 validatorv20 "github.com/hyperledger/fabric/core/committer/txvalidator/v20" 30 "github.com/hyperledger/fabric/core/committer/txvalidator/v20/plugindispatcher" 31 vir "github.com/hyperledger/fabric/core/committer/txvalidator/v20/valinforetriever" 32 "github.com/hyperledger/fabric/core/common/privdata" 33 validation "github.com/hyperledger/fabric/core/handlers/validation/api/state" 34 "github.com/hyperledger/fabric/core/ledger" 35 "github.com/hyperledger/fabric/core/ledger/ledgermgmt" 36 "github.com/hyperledger/fabric/core/transientstore" 37 "github.com/hyperledger/fabric/gossip/api" 38 gossipprivdata "github.com/hyperledger/fabric/gossip/privdata" 39 gossipservice "github.com/hyperledger/fabric/gossip/service" 40 "github.com/hyperledger/fabric/internal/pkg/peer/orderers" 41 "github.com/hyperledger/fabric/msp" 42 mspmgmt "github.com/hyperledger/fabric/msp/mgmt" 43 "github.com/hyperledger/fabric/protoutil" 44 "github.com/pkg/errors" 45 ) 46 47 var peerLogger = flogging.MustGetLogger("peer") 48 49 type CollectionInfoShim struct { 50 plugindispatcher.CollectionAndLifecycleResources 51 ChannelID string 52 } 53 54 func (cis *CollectionInfoShim) CollectionValidationInfo(chaincodeName, collectionName string, validationState validation.State) ([]byte, error, error) { 55 return cis.CollectionAndLifecycleResources.CollectionValidationInfo(cis.ChannelID, chaincodeName, collectionName, validationState) 56 } 57 58 type gossipSupport struct { 59 channelconfig.Application 60 configtx.Validator 61 channelconfig.Channel 62 } 63 64 func ConfigBlockFromLedger(ledger ledger.PeerLedger) (*common.Block, error) { 65 peerLogger.Debugf("Getting config block") 66 67 // get last block. Last block number is Height-1 68 blockchainInfo, err := ledger.GetBlockchainInfo() 69 if err != nil { 70 return nil, err 71 } 72 lastBlock, err := ledger.GetBlockByNumber(blockchainInfo.Height - 1) 73 if err != nil { 74 return nil, err 75 } 76 77 // get most recent config block location from last block metadata 78 configBlockIndex, err := protoutil.GetLastConfigIndexFromBlock(lastBlock) 79 if err != nil { 80 return nil, err 81 } 82 83 // get most recent config block 84 configBlock, err := ledger.GetBlockByNumber(configBlockIndex) 85 if err != nil { 86 return nil, err 87 } 88 89 peerLogger.Debugf("Got config block[%d]", configBlockIndex) 90 return configBlock, nil 91 } 92 93 // updates the trusted roots for the peer based on updates to channels 94 func (p *Peer) updateTrustedRoots(cm channelconfig.Resources) { 95 if !p.ServerConfig.SecOpts.UseTLS { 96 return 97 } 98 99 // this is triggered on per channel basis so first update the roots for the channel 100 peerLogger.Debugf("Updating trusted root authorities for channel %s", cm.ConfigtxValidator().ChannelID()) 101 102 p.CredentialSupport.BuildTrustedRootsForChain(cm) 103 104 // now iterate over all roots for all app and orderer channels 105 var trustedRoots [][]byte 106 for _, roots := range p.CredentialSupport.AppRootCAsByChain() { 107 trustedRoots = append(trustedRoots, roots...) 108 } 109 trustedRoots = append(trustedRoots, p.ServerConfig.SecOpts.ClientRootCAs...) 110 trustedRoots = append(trustedRoots, p.ServerConfig.SecOpts.ServerRootCAs...) 111 112 // now update the client roots for the peerServer 113 err := p.server.SetClientRootCAs(trustedRoots) 114 if err != nil { 115 msg := "Failed to update trusted roots from latest config block. " + 116 "This peer may not be able to communicate with members of channel %s (%s)" 117 peerLogger.Warningf(msg, cm.ConfigtxValidator().ChannelID(), err) 118 } 119 } 120 121 // 122 // Deliver service support structs for the peer 123 // 124 125 // DeliverChainManager provides access to a channel for performing deliver 126 type DeliverChainManager struct { 127 Peer *Peer 128 } 129 130 func (d DeliverChainManager) GetChain(chainID string) deliver.Chain { 131 if channel := d.Peer.Channel(chainID); channel != nil { 132 return channel 133 } 134 return nil 135 } 136 137 // fileLedgerBlockStore implements the interface expected by 138 // common/ledger/blockledger/file to interact with a file ledger for deliver 139 type fileLedgerBlockStore struct { 140 ledger.PeerLedger 141 } 142 143 func (flbs fileLedgerBlockStore) AddBlock(*common.Block) error { 144 return nil 145 } 146 147 func (flbs fileLedgerBlockStore) RetrieveBlocks(startBlockNumber uint64) (commonledger.ResultsIterator, error) { 148 return flbs.GetBlocksIterator(startBlockNumber) 149 } 150 151 // NewConfigSupport returns 152 func NewConfigSupport(peer *Peer) cc.Manager { 153 return &configSupport{ 154 peer: peer, 155 } 156 } 157 158 type configSupport struct { 159 peer *Peer 160 } 161 162 // GetChannelConfig returns an instance of a object that represents 163 // current channel configuration tree of the specified channel. The 164 // ConfigProto method of the returned object can be used to get the 165 // proto representing the channel configuration. 166 func (c *configSupport) GetChannelConfig(cid string) cc.Config { 167 channel := c.peer.Channel(cid) 168 if channel == nil { 169 peerLogger.Errorf("[channel %s] channel not associated with this peer", cid) 170 return nil 171 } 172 return channel.Resources().ConfigtxValidator() 173 } 174 175 // A Peer holds references to subsystems and channels associated with a Fabric peer. 176 type Peer struct { 177 ServerConfig comm.ServerConfig 178 CredentialSupport *comm.CredentialSupport 179 StoreProvider transientstore.StoreProvider 180 GossipService *gossipservice.GossipService 181 LedgerMgr *ledgermgmt.LedgerMgr 182 OrdererEndpointOverrides map[string]*orderers.Endpoint 183 CryptoProvider bccsp.BCCSP 184 185 // validationWorkersSemaphore is used to limit the number of concurrent validation 186 // go routines. 187 validationWorkersSemaphore semaphore.Semaphore 188 189 server *comm.GRPCServer 190 pluginMapper plugin.Mapper 191 channelInitializer func(cid string) 192 193 // channels is a map of channelID to channel 194 mutex sync.RWMutex 195 channels map[string]*Channel 196 } 197 198 func (p *Peer) openStore(cid string) (*transientstore.Store, error) { 199 store, err := p.StoreProvider.OpenStore(cid) 200 if err != nil { 201 return nil, err 202 } 203 204 return store, nil 205 } 206 207 func (p *Peer) CreateChannel( 208 cid string, 209 cb *common.Block, 210 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider, 211 legacyLifecycleValidation plugindispatcher.LifecycleResources, 212 newLifecycleValidation plugindispatcher.CollectionAndLifecycleResources, 213 ) error { 214 l, err := p.LedgerMgr.CreateLedger(cid, cb) 215 if err != nil { 216 return errors.WithMessage(err, "cannot create ledger from genesis block") 217 } 218 219 if err := p.createChannel(cid, l, cb, p.pluginMapper, deployedCCInfoProvider, legacyLifecycleValidation, newLifecycleValidation); err != nil { 220 return err 221 } 222 223 p.initChannel(cid) 224 return nil 225 } 226 227 // retrievePersistedChannelConfig retrieves the persisted channel config from statedb 228 func retrievePersistedChannelConfig(ledger ledger.PeerLedger) (*common.Config, error) { 229 qe, err := ledger.NewQueryExecutor() 230 if err != nil { 231 return nil, err 232 } 233 defer qe.Done() 234 return retrieveChannelConfig(qe) 235 } 236 237 // createChannel creates a new channel object and insert it into the channels slice. 238 func (p *Peer) createChannel( 239 cid string, 240 l ledger.PeerLedger, 241 cb *common.Block, 242 pluginMapper plugin.Mapper, 243 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider, 244 legacyLifecycleValidation plugindispatcher.LifecycleResources, 245 newLifecycleValidation plugindispatcher.CollectionAndLifecycleResources, 246 ) error { 247 chanConf, err := retrievePersistedChannelConfig(l) 248 if err != nil { 249 return err 250 } 251 252 bundle, err := channelconfig.NewBundle(cid, chanConf, p.CryptoProvider) 253 if err != nil { 254 return err 255 } 256 257 capabilitiesSupportedOrPanic(bundle) 258 259 channelconfig.LogSanityChecks(bundle) 260 261 gossipEventer := p.GossipService.NewConfigEventer() 262 263 gossipCallbackWrapper := func(bundle *channelconfig.Bundle) { 264 ac, ok := bundle.ApplicationConfig() 265 if !ok { 266 // TODO, handle a missing ApplicationConfig more gracefully 267 ac = nil 268 } 269 gossipEventer.ProcessConfigUpdate(&gossipSupport{ 270 Validator: bundle.ConfigtxValidator(), 271 Application: ac, 272 Channel: bundle.ChannelConfig(), 273 }) 274 p.GossipService.SuspectPeers(func(identity api.PeerIdentityType) bool { 275 // TODO: this is a place-holder that would somehow make the MSP layer suspect 276 // that a given certificate is revoked, or its intermediate CA is revoked. 277 // In the meantime, before we have such an ability, we return true in order 278 // to suspect ALL identities in order to validate all of them. 279 return true 280 }) 281 } 282 283 trustedRootsCallbackWrapper := func(bundle *channelconfig.Bundle) { 284 p.updateTrustedRoots(bundle) 285 } 286 287 mspCallback := func(bundle *channelconfig.Bundle) { 288 // TODO remove once all references to mspmgmt are gone from peer code 289 mspmgmt.XXXSetMSPManager(cid, bundle.MSPManager()) 290 } 291 292 osLogger := flogging.MustGetLogger("peer.orderers") 293 namedOSLogger := osLogger.With("channel", cid) 294 ordererSource := orderers.NewConnectionSource(namedOSLogger, p.OrdererEndpointOverrides) 295 296 ordererSourceCallback := func(bundle *channelconfig.Bundle) { 297 globalAddresses := bundle.ChannelConfig().OrdererAddresses() 298 orgAddresses := map[string]orderers.OrdererOrg{} 299 if ordererConfig, ok := bundle.OrdererConfig(); ok { 300 for orgName, org := range ordererConfig.Organizations() { 301 certs := [][]byte{} 302 for _, root := range org.MSP().GetTLSRootCerts() { 303 certs = append(certs, root) 304 } 305 306 for _, intermediate := range org.MSP().GetTLSIntermediateCerts() { 307 certs = append(certs, intermediate) 308 } 309 310 orgAddresses[orgName] = orderers.OrdererOrg{ 311 Addresses: org.Endpoints(), 312 RootCerts: certs, 313 } 314 } 315 } 316 ordererSource.Update(globalAddresses, orgAddresses) 317 } 318 319 channel := &Channel{ 320 ledger: l, 321 resources: bundle, 322 cryptoProvider: p.CryptoProvider, 323 } 324 325 channel.bundleSource = channelconfig.NewBundleSource( 326 bundle, 327 ordererSourceCallback, 328 gossipCallbackWrapper, 329 trustedRootsCallbackWrapper, 330 mspCallback, 331 channel.bundleUpdate, 332 ) 333 334 committer := committer.NewLedgerCommitter(l) 335 validator := &txvalidator.ValidationRouter{ 336 CapabilityProvider: channel, 337 V14Validator: validatorv14.NewTxValidator( 338 cid, 339 p.validationWorkersSemaphore, 340 channel, 341 p.pluginMapper, 342 p.CryptoProvider, 343 ), 344 V20Validator: validatorv20.NewTxValidator( 345 cid, 346 p.validationWorkersSemaphore, 347 channel, 348 channel.Ledger(), 349 &vir.ValidationInfoRetrieveShim{ 350 New: newLifecycleValidation, 351 Legacy: legacyLifecycleValidation, 352 }, 353 &CollectionInfoShim{ 354 CollectionAndLifecycleResources: newLifecycleValidation, 355 ChannelID: bundle.ConfigtxValidator().ChannelID(), 356 }, 357 p.pluginMapper, 358 policies.PolicyManagerGetterFunc(p.GetPolicyManager), 359 p.CryptoProvider, 360 ), 361 } 362 363 // TODO: does someone need to call Close() on the transientStoreFactory at shutdown of the peer? 364 store, err := p.openStore(bundle.ConfigtxValidator().ChannelID()) 365 if err != nil { 366 return errors.Wrapf(err, "[channel %s] failed opening transient store", bundle.ConfigtxValidator().ChannelID()) 367 } 368 channel.store = store 369 370 simpleCollectionStore := privdata.NewSimpleCollectionStore(l, deployedCCInfoProvider) 371 p.GossipService.InitializeChannel(bundle.ConfigtxValidator().ChannelID(), ordererSource, store, gossipservice.Support{ 372 Validator: validator, 373 Committer: committer, 374 CollectionStore: simpleCollectionStore, 375 IdDeserializeFactory: gossipprivdata.IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer { 376 return mspmgmt.GetManagerForChain(chainID) 377 }), 378 CapabilityProvider: channel, 379 }) 380 381 p.mutex.Lock() 382 defer p.mutex.Unlock() 383 if p.channels == nil { 384 p.channels = map[string]*Channel{} 385 } 386 p.channels[cid] = channel 387 388 return nil 389 } 390 391 func (p *Peer) Channel(cid string) *Channel { 392 p.mutex.RLock() 393 defer p.mutex.RUnlock() 394 if c, ok := p.channels[cid]; ok { 395 return c 396 } 397 return nil 398 } 399 400 func (p *Peer) StoreForChannel(cid string) *transientstore.Store { 401 if c := p.Channel(cid); c != nil { 402 return c.Store() 403 } 404 return nil 405 } 406 407 // GetChannelsInfo returns an array with information about all channels for 408 // this peer. 409 func (p *Peer) GetChannelsInfo() []*pb.ChannelInfo { 410 p.mutex.RLock() 411 defer p.mutex.RUnlock() 412 413 var channelInfos []*pb.ChannelInfo 414 for key := range p.channels { 415 ci := &pb.ChannelInfo{ChannelId: key} 416 channelInfos = append(channelInfos, ci) 417 } 418 return channelInfos 419 } 420 421 // GetChannelConfig returns the channel configuration of the channel with channel ID. Note that this 422 // call returns nil if channel cid has not been created. 423 func (p *Peer) GetChannelConfig(cid string) channelconfig.Resources { 424 if c := p.Channel(cid); c != nil { 425 return c.Resources() 426 } 427 return nil 428 } 429 430 // GetStableChannelConfig returns the stable channel configuration of the channel with channel ID. 431 // Note that this call returns nil if channel cid has not been created. 432 func (p *Peer) GetStableChannelConfig(cid string) channelconfig.Resources { 433 if c := p.Channel(cid); c != nil { 434 return c.Resources() 435 } 436 return nil 437 } 438 439 // GetLedger returns the ledger of the channel with channel ID. Note that this 440 // call returns nil if channel cid has not been created. 441 func (p *Peer) GetLedger(cid string) ledger.PeerLedger { 442 if c := p.Channel(cid); c != nil { 443 return c.Ledger() 444 } 445 return nil 446 } 447 448 // GetMSPIDs returns the ID of each application MSP defined on this channel 449 func (p *Peer) GetMSPIDs(cid string) []string { 450 if c := p.Channel(cid); c != nil { 451 return c.GetMSPIDs() 452 } 453 return nil 454 } 455 456 // GetPolicyManager returns the policy manager of the channel with channel ID. Note that this 457 // call returns nil if channel cid has not been created. 458 func (p *Peer) GetPolicyManager(cid string) policies.Manager { 459 if c := p.Channel(cid); c != nil { 460 return c.Resources().PolicyManager() 461 } 462 return nil 463 } 464 465 // initChannel takes care to initialize channel after peer joined, for example deploys system CCs 466 func (p *Peer) initChannel(cid string) { 467 if p.channelInitializer != nil { 468 // Initialize chaincode, namely deploy system CC 469 peerLogger.Debugf("Initializing channel %s", cid) 470 p.channelInitializer(cid) 471 } 472 } 473 474 func (p *Peer) GetApplicationConfig(cid string) (channelconfig.Application, bool) { 475 cc := p.GetChannelConfig(cid) 476 if cc == nil { 477 return nil, false 478 } 479 480 return cc.ApplicationConfig() 481 } 482 483 // Initialize sets up any channels that the peer has from the persistence. This 484 // function should be called at the start up when the ledger and gossip 485 // ready 486 func (p *Peer) Initialize( 487 init func(string), 488 server *comm.GRPCServer, 489 pm plugin.Mapper, 490 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider, 491 legacyLifecycleValidation plugindispatcher.LifecycleResources, 492 newLifecycleValidation plugindispatcher.CollectionAndLifecycleResources, 493 nWorkers int, 494 ) { 495 // TODO: exported dep fields or constructor 496 p.server = server 497 p.validationWorkersSemaphore = semaphore.New(nWorkers) 498 p.pluginMapper = pm 499 p.channelInitializer = init 500 501 ledgerIds, err := p.LedgerMgr.GetLedgerIDs() 502 if err != nil { 503 panic(fmt.Errorf("error in initializing ledgermgmt: %s", err)) 504 } 505 506 for _, cid := range ledgerIds { 507 peerLogger.Infof("Loading chain %s", cid) 508 ledger, err := p.LedgerMgr.OpenLedger(cid) 509 if err != nil { 510 peerLogger.Errorf("Failed to load ledger %s(%+v)", cid, err) 511 peerLogger.Debugf("Error while loading ledger %s with message %s. We continue to the next ledger rather than abort.", cid, err) 512 continue 513 } 514 cb, err := ConfigBlockFromLedger(ledger) 515 if err != nil { 516 peerLogger.Errorf("Failed to find config block on ledger %s(%s)", cid, err) 517 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) 518 continue 519 } 520 // Create a chain if we get a valid ledger with config block 521 err = p.createChannel(cid, ledger, cb, pm, deployedCCInfoProvider, legacyLifecycleValidation, newLifecycleValidation) 522 if err != nil { 523 peerLogger.Errorf("Failed to load chain %s(%s)", cid, err) 524 peerLogger.Debugf("Error reloading chain %s with message %s. We continue to the next chain rather than abort.", cid, err) 525 continue 526 } 527 528 p.initChannel(cid) 529 } 530 }