github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/peer/peer.go (about) 1 /* 2 Copyright hechain. 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/hechain20/hechain/bccsp" 14 "github.com/hechain20/hechain/common/channelconfig" 15 "github.com/hechain20/hechain/common/deliver" 16 "github.com/hechain20/hechain/common/flogging" 17 commonledger "github.com/hechain20/hechain/common/ledger" 18 "github.com/hechain20/hechain/common/policies" 19 "github.com/hechain20/hechain/common/semaphore" 20 "github.com/hechain20/hechain/core/committer" 21 "github.com/hechain20/hechain/core/committer/txvalidator" 22 "github.com/hechain20/hechain/core/committer/txvalidator/plugin" 23 validatorv14 "github.com/hechain20/hechain/core/committer/txvalidator/v14" 24 validatorv20 "github.com/hechain20/hechain/core/committer/txvalidator/v20" 25 "github.com/hechain20/hechain/core/committer/txvalidator/v20/plugindispatcher" 26 vir "github.com/hechain20/hechain/core/committer/txvalidator/v20/valinforetriever" 27 "github.com/hechain20/hechain/core/common/privdata" 28 validation "github.com/hechain20/hechain/core/handlers/validation/api/state" 29 "github.com/hechain20/hechain/core/ledger" 30 "github.com/hechain20/hechain/core/ledger/ledgermgmt" 31 "github.com/hechain20/hechain/core/transientstore" 32 "github.com/hechain20/hechain/gossip/api" 33 gossipservice "github.com/hechain20/hechain/gossip/service" 34 "github.com/hechain20/hechain/internal/pkg/comm" 35 "github.com/hechain20/hechain/internal/pkg/peer/orderers" 36 "github.com/hechain20/hechain/msp" 37 mspmgmt "github.com/hechain20/hechain/msp/mgmt" 38 "github.com/hechain20/hechain/protoutil" 39 "github.com/hyperledger/fabric-protos-go/common" 40 pb "github.com/hyperledger/fabric-protos-go/peer" 41 "github.com/pkg/errors" 42 ) 43 44 var peerLogger = flogging.MustGetLogger("peer") 45 46 type CollectionInfoShim struct { 47 plugindispatcher.CollectionAndLifecycleResources 48 ChannelID string 49 } 50 51 func (cis *CollectionInfoShim) CollectionValidationInfo(chaincodeName, collectionName string, validationState validation.State) ([]byte, error, error) { 52 return cis.CollectionAndLifecycleResources.CollectionValidationInfo(cis.ChannelID, chaincodeName, collectionName, validationState) 53 } 54 55 func ConfigBlockFromLedger(ledger ledger.PeerLedger) (*common.Block, error) { 56 peerLogger.Debugf("Getting config block") 57 58 // get last block. Last block number is Height-1 59 blockchainInfo, err := ledger.GetBlockchainInfo() 60 if err != nil { 61 return nil, err 62 } 63 lastBlock, err := ledger.GetBlockByNumber(blockchainInfo.Height - 1) 64 if err != nil { 65 return nil, err 66 } 67 68 // get most recent config block location from last block metadata 69 configBlockIndex, err := protoutil.GetLastConfigIndexFromBlock(lastBlock) 70 if err != nil { 71 return nil, err 72 } 73 74 // get most recent config block 75 configBlock, err := ledger.GetBlockByNumber(configBlockIndex) 76 if err != nil { 77 return nil, err 78 } 79 80 peerLogger.Debugf("Got config block[%d]", configBlockIndex) 81 return configBlock, nil 82 } 83 84 // updates the trusted roots for the peer based on updates to channels 85 func (p *Peer) updateTrustedRoots(cm channelconfig.Resources) { 86 if !p.ServerConfig.SecOpts.UseTLS { 87 return 88 } 89 90 // this is triggered on per channel basis so first update the roots for the channel 91 peerLogger.Debugf("Updating trusted root authorities for channel %s", cm.ConfigtxValidator().ChannelID()) 92 93 p.CredentialSupport.BuildTrustedRootsForChain(cm) 94 95 // now iterate over all roots for all app and orderer channels 96 var trustedRoots [][]byte 97 for _, roots := range p.CredentialSupport.AppRootCAsByChain() { 98 trustedRoots = append(trustedRoots, roots...) 99 } 100 trustedRoots = append(trustedRoots, p.ServerConfig.SecOpts.ClientRootCAs...) 101 trustedRoots = append(trustedRoots, p.ServerConfig.SecOpts.ServerRootCAs...) 102 103 // now update the client roots for the peerServer 104 err := p.server.SetClientRootCAs(trustedRoots) 105 if err != nil { 106 msg := "Failed to update trusted roots from latest config block. " + 107 "This peer may not be able to communicate with members of channel %s (%s)" 108 peerLogger.Warningf(msg, cm.ConfigtxValidator().ChannelID(), err) 109 } 110 } 111 112 // 113 // Deliver service support structs for the peer 114 // 115 116 // DeliverChainManager provides access to a channel for performing deliver 117 type DeliverChainManager struct { 118 Peer *Peer 119 } 120 121 func (d DeliverChainManager) GetChain(chainID string) deliver.Chain { 122 if channel := d.Peer.Channel(chainID); channel != nil { 123 return channel 124 } 125 return nil 126 } 127 128 // fileLedgerBlockStore implements the interface expected by 129 // common/ledger/blockledger/file to interact with a file ledger for deliver 130 type fileLedgerBlockStore struct { 131 ledger.PeerLedger 132 } 133 134 func (flbs fileLedgerBlockStore) AddBlock(*common.Block) error { 135 return nil 136 } 137 138 func (flbs fileLedgerBlockStore) RetrieveBlocks(startBlockNumber uint64) (commonledger.ResultsIterator, error) { 139 return flbs.GetBlocksIterator(startBlockNumber) 140 } 141 142 func (flbs fileLedgerBlockStore) Shutdown() {} 143 144 // A Peer holds references to subsystems and channels associated with a Fabric peer. 145 type Peer struct { 146 ServerConfig comm.ServerConfig 147 CredentialSupport *comm.CredentialSupport 148 StoreProvider transientstore.StoreProvider 149 GossipService *gossipservice.GossipService 150 LedgerMgr *ledgermgmt.LedgerMgr 151 OrdererEndpointOverrides map[string]*orderers.Endpoint 152 CryptoProvider bccsp.BCCSP 153 154 // validationWorkersSemaphore is used to limit the number of concurrent validation 155 // go routines. 156 validationWorkersSemaphore semaphore.Semaphore 157 158 server *comm.GRPCServer 159 pluginMapper plugin.Mapper 160 channelInitializer func(cid string) 161 162 // channels is a map of channelID to channel 163 mutex sync.RWMutex 164 channels map[string]*Channel 165 166 configCallbacks []channelconfig.BundleActor 167 } 168 169 // AddConfigCallbacks adds one or more BundleActor functions to list of callbacks that 170 // get invoked when a channel configuration update event is received via gossip. 171 func (p *Peer) AddConfigCallbacks(callbacks ...channelconfig.BundleActor) { 172 p.configCallbacks = append(p.configCallbacks, callbacks...) 173 } 174 175 func (p *Peer) openStore(cid string) (*transientstore.Store, error) { 176 store, err := p.StoreProvider.OpenStore(cid) 177 if err != nil { 178 return nil, err 179 } 180 181 return store, nil 182 } 183 184 func (p *Peer) CreateChannel( 185 cid string, 186 cb *common.Block, 187 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider, 188 legacyLifecycleValidation plugindispatcher.LifecycleResources, 189 newLifecycleValidation plugindispatcher.CollectionAndLifecycleResources, 190 ) error { 191 l, err := p.LedgerMgr.CreateLedger(cid, cb) 192 if err != nil { 193 return errors.WithMessage(err, "cannot create ledger from genesis block") 194 } 195 196 if err := p.createChannel(cid, l, deployedCCInfoProvider, legacyLifecycleValidation, newLifecycleValidation); err != nil { 197 return err 198 } 199 200 p.initChannel(cid) 201 return nil 202 } 203 204 // CreateChannelFromSnapshot creates a channel from the specified snapshot. 205 func (p *Peer) CreateChannelFromSnapshot( 206 snapshotDir string, 207 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider, 208 legacyLifecycleValidation plugindispatcher.LifecycleResources, 209 newLifecycleValidation plugindispatcher.CollectionAndLifecycleResources, 210 ) error { 211 channelCallback := func(l ledger.PeerLedger, cid string) { 212 if err := p.createChannel(cid, l, deployedCCInfoProvider, legacyLifecycleValidation, newLifecycleValidation); err != nil { 213 logger.Errorf("error creating channel for %s", cid) 214 return 215 } 216 p.initChannel(cid) 217 } 218 219 err := p.LedgerMgr.CreateLedgerFromSnapshot(snapshotDir, channelCallback) 220 if err != nil { 221 return errors.WithMessagef(err, "cannot create ledger from snapshot %s", snapshotDir) 222 } 223 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 ac = nil 265 } 266 gossipEventer.ProcessConfigUpdate(gossipservice.ConfigUpdate{ 267 ChannelID: bundle.ConfigtxValidator().ChannelID(), 268 Organizations: ac.Organizations(), 269 OrdererAddresses: bundle.ChannelConfig().OrdererAddresses(), 270 Sequence: bundle.ConfigtxValidator().Sequence(), 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 var certs [][]byte 300 certs = append(certs, org.MSP().GetTLSRootCerts()...) 301 certs = append(certs, org.MSP().GetTLSIntermediateCerts()...) 302 303 orgAddresses[orgName] = orderers.OrdererOrg{ 304 Addresses: org.Endpoints(), 305 RootCerts: certs, 306 } 307 } 308 } 309 ordererSource.Update(globalAddresses, orgAddresses) 310 } 311 312 channel := &Channel{ 313 ledger: l, 314 resources: bundle, 315 cryptoProvider: p.CryptoProvider, 316 } 317 318 callbacks := []channelconfig.BundleActor{ 319 ordererSourceCallback, 320 gossipCallbackWrapper, 321 trustedRootsCallbackWrapper, 322 mspCallback, 323 channel.bundleUpdate, 324 } 325 callbacks = append(callbacks, p.configCallbacks...) 326 327 channel.bundleSource = channelconfig.NewBundleSource( 328 bundle, 329 callbacks..., 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 var idDeserializerFactory privdata.IdentityDeserializerFactoryFunc = func(channelID string) msp.IdentityDeserializer { 369 return p.Channel(channelID).MSPManager() 370 } 371 simpleCollectionStore := privdata.NewSimpleCollectionStore(l, deployedCCInfoProvider, idDeserializerFactory) 372 p.GossipService.InitializeChannel(bundle.ConfigtxValidator().ChannelID(), ordererSource, store, gossipservice.Support{ 373 Validator: validator, 374 Committer: committer, 375 CollectionStore: simpleCollectionStore, 376 IdDeserializeFactory: idDeserializerFactory, 377 CapabilityProvider: channel, 378 }) 379 380 p.mutex.Lock() 381 defer p.mutex.Unlock() 382 if p.channels == nil { 383 p.channels = map[string]*Channel{} 384 } 385 p.channels[cid] = channel 386 387 return nil 388 } 389 390 func (p *Peer) Channel(cid string) *Channel { 391 p.mutex.RLock() 392 defer p.mutex.RUnlock() 393 if c, ok := p.channels[cid]; ok { 394 return c 395 } 396 return nil 397 } 398 399 func (p *Peer) StoreForChannel(cid string) *transientstore.Store { 400 if c := p.Channel(cid); c != nil { 401 return c.Store() 402 } 403 return nil 404 } 405 406 // GetChannelsInfo returns an array with information about all channels for 407 // this peer. 408 func (p *Peer) GetChannelsInfo() []*pb.ChannelInfo { 409 p.mutex.RLock() 410 defer p.mutex.RUnlock() 411 412 var channelInfos []*pb.ChannelInfo 413 for key := range p.channels { 414 ci := &pb.ChannelInfo{ChannelId: key} 415 channelInfos = append(channelInfos, ci) 416 } 417 return channelInfos 418 } 419 420 // GetChannelConfig returns the channel configuration of the channel with channel ID. Note that this 421 // call returns nil if channel cid has not been created. 422 func (p *Peer) GetChannelConfig(cid string) channelconfig.Resources { 423 if c := p.Channel(cid); c != nil { 424 return c.Resources() 425 } 426 return nil 427 } 428 429 // GetStableChannelConfig returns the stable channel configuration of the channel with channel ID. 430 // Note that this call returns nil if channel cid has not been created. 431 func (p *Peer) GetStableChannelConfig(cid string) channelconfig.Resources { 432 if c := p.Channel(cid); c != nil { 433 return c.Resources() 434 } 435 return nil 436 } 437 438 // GetLedger returns the ledger of the channel with channel ID. Note that this 439 // call returns nil if channel cid has not been created. 440 func (p *Peer) GetLedger(cid string) ledger.PeerLedger { 441 if c := p.Channel(cid); c != nil { 442 return c.Ledger() 443 } 444 return nil 445 } 446 447 // GetMSPIDs returns the ID of each application MSP defined on this channel 448 func (p *Peer) GetMSPIDs(cid string) []string { 449 if c := p.Channel(cid); c != nil { 450 return c.GetMSPIDs() 451 } 452 return nil 453 } 454 455 // GetPolicyManager returns the policy manager of the channel with channel ID. Note that this 456 // call returns nil if channel cid has not been created. 457 func (p *Peer) GetPolicyManager(cid string) policies.Manager { 458 if c := p.Channel(cid); c != nil { 459 return c.Resources().PolicyManager() 460 } 461 return nil 462 } 463 464 // JoinBySnaphotStatus queries ledger mgr to get the status of joinbysnapshot 465 func (p *Peer) JoinBySnaphotStatus() *pb.JoinBySnapshotStatus { 466 return p.LedgerMgr.JoinBySnapshotStatus() 467 } 468 469 // initChannel takes care to initialize channel after peer joined, for example deploys system CCs 470 func (p *Peer) initChannel(cid string) { 471 if p.channelInitializer != nil { 472 // Initialize chaincode, namely deploy system CC 473 peerLogger.Debugf("Initializing channel %s", cid) 474 p.channelInitializer(cid) 475 } 476 } 477 478 func (p *Peer) GetApplicationConfig(cid string) (channelconfig.Application, bool) { 479 cc := p.GetChannelConfig(cid) 480 if cc == nil { 481 return nil, false 482 } 483 484 return cc.ApplicationConfig() 485 } 486 487 // Initialize sets up any channels that the peer has from the persistence. This 488 // function should be called at the start up when the ledger and gossip 489 // ready 490 func (p *Peer) Initialize( 491 init func(string), 492 server *comm.GRPCServer, 493 pm plugin.Mapper, 494 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider, 495 legacyLifecycleValidation plugindispatcher.LifecycleResources, 496 newLifecycleValidation plugindispatcher.CollectionAndLifecycleResources, 497 nWorkers int, 498 ) { 499 // TODO: exported dep fields or constructor 500 p.server = server 501 p.validationWorkersSemaphore = semaphore.New(nWorkers) 502 p.pluginMapper = pm 503 p.channelInitializer = init 504 505 ledgerIds, err := p.LedgerMgr.GetLedgerIDs() 506 if err != nil { 507 panic(fmt.Errorf("error in initializing ledgermgmt: %s", err)) 508 } 509 510 for _, cid := range ledgerIds { 511 peerLogger.Infof("Loading chain %s", cid) 512 ledger, err := p.LedgerMgr.OpenLedger(cid) 513 if err != nil { 514 peerLogger.Errorf("Failed to load ledger %s(%+v)", cid, err) 515 peerLogger.Debugf("Error while loading ledger %s with message %s. We continue to the next ledger rather than abort.", cid, err) 516 continue 517 } 518 // Create a chain if we get a valid ledger with config block 519 err = p.createChannel(cid, ledger, deployedCCInfoProvider, legacyLifecycleValidation, newLifecycleValidation) 520 if err != nil { 521 peerLogger.Errorf("Failed to load chain %s(%s)", cid, err) 522 peerLogger.Debugf("Error reloading chain %s with message %s. We continue to the next chain rather than abort.", cid, err) 523 continue 524 } 525 526 p.initChannel(cid) 527 } 528 } 529 530 func (flbs fileLedgerBlockStore) RetrieveBlockByNumber(blockNum uint64) (*common.Block, error) { 531 return flbs.GetBlockByNumber(blockNum) 532 }