github.com/true-sqn/fabric@v2.1.1+incompatible/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/committer" 25 "github.com/hyperledger/fabric/core/committer/txvalidator" 26 "github.com/hyperledger/fabric/core/committer/txvalidator/plugin" 27 validatorv14 "github.com/hyperledger/fabric/core/committer/txvalidator/v14" 28 validatorv20 "github.com/hyperledger/fabric/core/committer/txvalidator/v20" 29 "github.com/hyperledger/fabric/core/committer/txvalidator/v20/plugindispatcher" 30 vir "github.com/hyperledger/fabric/core/committer/txvalidator/v20/valinforetriever" 31 "github.com/hyperledger/fabric/core/common/privdata" 32 validation "github.com/hyperledger/fabric/core/handlers/validation/api/state" 33 "github.com/hyperledger/fabric/core/ledger" 34 "github.com/hyperledger/fabric/core/ledger/ledgermgmt" 35 "github.com/hyperledger/fabric/core/transientstore" 36 "github.com/hyperledger/fabric/gossip/api" 37 gossipprivdata "github.com/hyperledger/fabric/gossip/privdata" 38 gossipservice "github.com/hyperledger/fabric/gossip/service" 39 "github.com/hyperledger/fabric/internal/pkg/comm" 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, 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 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider, 242 legacyLifecycleValidation plugindispatcher.LifecycleResources, 243 newLifecycleValidation plugindispatcher.CollectionAndLifecycleResources, 244 ) error { 245 chanConf, err := retrievePersistedChannelConfig(l) 246 if err != nil { 247 return err 248 } 249 250 bundle, err := channelconfig.NewBundle(cid, chanConf, p.CryptoProvider) 251 if err != nil { 252 return err 253 } 254 255 capabilitiesSupportedOrPanic(bundle) 256 257 channelconfig.LogSanityChecks(bundle) 258 259 gossipEventer := p.GossipService.NewConfigEventer() 260 261 gossipCallbackWrapper := func(bundle *channelconfig.Bundle) { 262 ac, ok := bundle.ApplicationConfig() 263 if !ok { 264 // TODO, handle a missing ApplicationConfig more gracefully 265 ac = nil 266 } 267 gossipEventer.ProcessConfigUpdate(&gossipSupport{ 268 Validator: bundle.ConfigtxValidator(), 269 Application: ac, 270 Channel: bundle.ChannelConfig(), 271 }) 272 p.GossipService.SuspectPeers(func(identity api.PeerIdentityType) bool { 273 // TODO: this is a place-holder that would somehow make the MSP layer suspect 274 // that a given certificate is revoked, or its intermediate CA is revoked. 275 // In the meantime, before we have such an ability, we return true in order 276 // to suspect ALL identities in order to validate all of them. 277 return true 278 }) 279 } 280 281 trustedRootsCallbackWrapper := func(bundle *channelconfig.Bundle) { 282 p.updateTrustedRoots(bundle) 283 } 284 285 mspCallback := func(bundle *channelconfig.Bundle) { 286 // TODO remove once all references to mspmgmt are gone from peer code 287 mspmgmt.XXXSetMSPManager(cid, bundle.MSPManager()) 288 } 289 290 osLogger := flogging.MustGetLogger("peer.orderers") 291 namedOSLogger := osLogger.With("channel", cid) 292 ordererSource := orderers.NewConnectionSource(namedOSLogger, p.OrdererEndpointOverrides) 293 294 ordererSourceCallback := func(bundle *channelconfig.Bundle) { 295 globalAddresses := bundle.ChannelConfig().OrdererAddresses() 296 orgAddresses := map[string]orderers.OrdererOrg{} 297 if ordererConfig, ok := bundle.OrdererConfig(); ok { 298 for orgName, org := range ordererConfig.Organizations() { 299 certs := [][]byte{} 300 for _, root := range org.MSP().GetTLSRootCerts() { 301 certs = append(certs, root) 302 } 303 304 for _, intermediate := range org.MSP().GetTLSIntermediateCerts() { 305 certs = append(certs, intermediate) 306 } 307 308 orgAddresses[orgName] = orderers.OrdererOrg{ 309 Addresses: org.Endpoints(), 310 RootCerts: certs, 311 } 312 } 313 } 314 ordererSource.Update(globalAddresses, orgAddresses) 315 } 316 317 channel := &Channel{ 318 ledger: l, 319 resources: bundle, 320 cryptoProvider: p.CryptoProvider, 321 } 322 323 channel.bundleSource = channelconfig.NewBundleSource( 324 bundle, 325 ordererSourceCallback, 326 gossipCallbackWrapper, 327 trustedRootsCallbackWrapper, 328 mspCallback, 329 channel.bundleUpdate, 330 ) 331 332 committer := committer.NewLedgerCommitter(l) 333 validator := &txvalidator.ValidationRouter{ 334 CapabilityProvider: channel, 335 V14Validator: validatorv14.NewTxValidator( 336 cid, 337 p.validationWorkersSemaphore, 338 channel, 339 p.pluginMapper, 340 p.CryptoProvider, 341 ), 342 V20Validator: validatorv20.NewTxValidator( 343 cid, 344 p.validationWorkersSemaphore, 345 channel, 346 channel.Ledger(), 347 &vir.ValidationInfoRetrieveShim{ 348 New: newLifecycleValidation, 349 Legacy: legacyLifecycleValidation, 350 }, 351 &CollectionInfoShim{ 352 CollectionAndLifecycleResources: newLifecycleValidation, 353 ChannelID: bundle.ConfigtxValidator().ChannelID(), 354 }, 355 p.pluginMapper, 356 policies.PolicyManagerGetterFunc(p.GetPolicyManager), 357 p.CryptoProvider, 358 ), 359 } 360 361 // TODO: does someone need to call Close() on the transientStoreFactory at shutdown of the peer? 362 store, err := p.openStore(bundle.ConfigtxValidator().ChannelID()) 363 if err != nil { 364 return errors.Wrapf(err, "[channel %s] failed opening transient store", bundle.ConfigtxValidator().ChannelID()) 365 } 366 channel.store = store 367 368 simpleCollectionStore := privdata.NewSimpleCollectionStore(l, deployedCCInfoProvider) 369 p.GossipService.InitializeChannel(bundle.ConfigtxValidator().ChannelID(), ordererSource, store, gossipservice.Support{ 370 Validator: validator, 371 Committer: committer, 372 CollectionStore: simpleCollectionStore, 373 IdDeserializeFactory: gossipprivdata.IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer { 374 return mspmgmt.GetManagerForChain(chainID) 375 }), 376 CapabilityProvider: channel, 377 }) 378 379 p.mutex.Lock() 380 defer p.mutex.Unlock() 381 if p.channels == nil { 382 p.channels = map[string]*Channel{} 383 } 384 p.channels[cid] = channel 385 386 return nil 387 } 388 389 func (p *Peer) Channel(cid string) *Channel { 390 p.mutex.RLock() 391 defer p.mutex.RUnlock() 392 if c, ok := p.channels[cid]; ok { 393 return c 394 } 395 return nil 396 } 397 398 func (p *Peer) StoreForChannel(cid string) *transientstore.Store { 399 if c := p.Channel(cid); c != nil { 400 return c.Store() 401 } 402 return nil 403 } 404 405 // GetChannelsInfo returns an array with information about all channels for 406 // this peer. 407 func (p *Peer) GetChannelsInfo() []*pb.ChannelInfo { 408 p.mutex.RLock() 409 defer p.mutex.RUnlock() 410 411 var channelInfos []*pb.ChannelInfo 412 for key := range p.channels { 413 ci := &pb.ChannelInfo{ChannelId: key} 414 channelInfos = append(channelInfos, ci) 415 } 416 return channelInfos 417 } 418 419 // GetChannelConfig returns the channel configuration of the channel with channel ID. Note that this 420 // call returns nil if channel cid has not been created. 421 func (p *Peer) GetChannelConfig(cid string) channelconfig.Resources { 422 if c := p.Channel(cid); c != nil { 423 return c.Resources() 424 } 425 return nil 426 } 427 428 // GetStableChannelConfig returns the stable channel configuration of the channel with channel ID. 429 // Note that this call returns nil if channel cid has not been created. 430 func (p *Peer) GetStableChannelConfig(cid string) channelconfig.Resources { 431 if c := p.Channel(cid); c != nil { 432 return c.Resources() 433 } 434 return nil 435 } 436 437 // GetLedger returns the ledger of the channel with channel ID. Note that this 438 // call returns nil if channel cid has not been created. 439 func (p *Peer) GetLedger(cid string) ledger.PeerLedger { 440 if c := p.Channel(cid); c != nil { 441 return c.Ledger() 442 } 443 return nil 444 } 445 446 // GetMSPIDs returns the ID of each application MSP defined on this channel 447 func (p *Peer) GetMSPIDs(cid string) []string { 448 if c := p.Channel(cid); c != nil { 449 return c.GetMSPIDs() 450 } 451 return nil 452 } 453 454 // GetPolicyManager returns the policy manager of the channel with channel ID. Note that this 455 // call returns nil if channel cid has not been created. 456 func (p *Peer) GetPolicyManager(cid string) policies.Manager { 457 if c := p.Channel(cid); c != nil { 458 return c.Resources().PolicyManager() 459 } 460 return nil 461 } 462 463 // initChannel takes care to initialize channel after peer joined, for example deploys system CCs 464 func (p *Peer) initChannel(cid string) { 465 if p.channelInitializer != nil { 466 // Initialize chaincode, namely deploy system CC 467 peerLogger.Debugf("Initializing channel %s", cid) 468 p.channelInitializer(cid) 469 } 470 } 471 472 func (p *Peer) GetApplicationConfig(cid string) (channelconfig.Application, bool) { 473 cc := p.GetChannelConfig(cid) 474 if cc == nil { 475 return nil, false 476 } 477 478 return cc.ApplicationConfig() 479 } 480 481 // Initialize sets up any channels that the peer has from the persistence. This 482 // function should be called at the start up when the ledger and gossip 483 // ready 484 func (p *Peer) Initialize( 485 init func(string), 486 server *comm.GRPCServer, 487 pm plugin.Mapper, 488 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider, 489 legacyLifecycleValidation plugindispatcher.LifecycleResources, 490 newLifecycleValidation plugindispatcher.CollectionAndLifecycleResources, 491 nWorkers int, 492 ) { 493 // TODO: exported dep fields or constructor 494 p.server = server 495 p.validationWorkersSemaphore = semaphore.New(nWorkers) 496 p.pluginMapper = pm 497 p.channelInitializer = init 498 499 ledgerIds, err := p.LedgerMgr.GetLedgerIDs() 500 if err != nil { 501 panic(fmt.Errorf("error in initializing ledgermgmt: %s", err)) 502 } 503 504 for _, cid := range ledgerIds { 505 peerLogger.Infof("Loading chain %s", cid) 506 ledger, err := p.LedgerMgr.OpenLedger(cid) 507 if err != nil { 508 peerLogger.Errorf("Failed to load ledger %s(%+v)", cid, err) 509 peerLogger.Debugf("Error while loading ledger %s with message %s. We continue to the next ledger rather than abort.", cid, err) 510 continue 511 } 512 // Create a chain if we get a valid ledger with config block 513 err = p.createChannel(cid, ledger, deployedCCInfoProvider, legacyLifecycleValidation, newLifecycleValidation) 514 if err != nil { 515 peerLogger.Errorf("Failed to load chain %s(%s)", cid, err) 516 peerLogger.Debugf("Error reloading chain %s with message %s. We continue to the next chain rather than abort.", cid, err) 517 continue 518 } 519 520 p.initChannel(cid) 521 } 522 }