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  }