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  }