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  }