github.com/anjalikarhana/fabric@v2.1.1+incompatible/orderer/common/server/onboarding.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package server
     8  
     9  import (
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/golang/protobuf/proto"
    14  	"github.com/hyperledger/fabric-protos-go/common"
    15  	"github.com/hyperledger/fabric/bccsp"
    16  	"github.com/hyperledger/fabric/common/channelconfig"
    17  	"github.com/hyperledger/fabric/common/flogging"
    18  	"github.com/hyperledger/fabric/common/ledger/blockledger"
    19  	"github.com/hyperledger/fabric/internal/pkg/comm"
    20  	"github.com/hyperledger/fabric/internal/pkg/identity"
    21  	"github.com/hyperledger/fabric/orderer/common/cluster"
    22  	"github.com/hyperledger/fabric/orderer/common/localconfig"
    23  	"github.com/hyperledger/fabric/orderer/consensus/etcdraft"
    24  	"github.com/hyperledger/fabric/protoutil"
    25  	"github.com/pkg/errors"
    26  )
    27  
    28  const (
    29  	defaultReplicationBackgroundRefreshInterval = time.Minute * 5
    30  	replicationBackgroundInitialRefreshInterval = time.Second * 10
    31  )
    32  
    33  type replicationInitiator struct {
    34  	registerChain     func(chain string)
    35  	verifierRetriever cluster.VerifierRetriever
    36  	channelLister     cluster.ChannelLister
    37  	logger            *flogging.FabricLogger
    38  	secOpts           comm.SecureOptions
    39  	conf              *localconfig.TopLevel
    40  	lf                cluster.LedgerFactory
    41  	signer            identity.SignerSerializer
    42  	cryptoProvider    bccsp.BCCSP
    43  }
    44  
    45  func (ri *replicationInitiator) replicateIfNeeded(bootstrapBlock *common.Block) {
    46  	if bootstrapBlock.Header.Number == 0 {
    47  		ri.logger.Debug("Booted with a genesis block, replication isn't an option")
    48  		return
    49  	}
    50  	ri.replicateNeededChannels(bootstrapBlock)
    51  }
    52  
    53  func (ri *replicationInitiator) createReplicator(bootstrapBlock *common.Block, filter func(string) bool) *cluster.Replicator {
    54  	consenterCert := &etcdraft.ConsenterCertificate{
    55  		ConsenterCertificate: ri.secOpts.Certificate,
    56  		CryptoProvider:       ri.cryptoProvider,
    57  	}
    58  
    59  	systemChannelName, err := protoutil.GetChainIDFromBlock(bootstrapBlock)
    60  	if err != nil {
    61  		ri.logger.Panicf("Failed extracting system channel name from bootstrap block: %v", err)
    62  	}
    63  	pullerConfig := cluster.PullerConfigFromTopLevelConfig(systemChannelName, ri.conf, ri.secOpts.Key, ri.secOpts.Certificate, ri.signer)
    64  	puller, err := cluster.BlockPullerFromConfigBlock(pullerConfig, bootstrapBlock, ri.verifierRetriever, ri.cryptoProvider)
    65  	if err != nil {
    66  		ri.logger.Panicf("Failed creating puller config from bootstrap block: %v", err)
    67  	}
    68  	puller.MaxPullBlockRetries = uint64(ri.conf.General.Cluster.ReplicationMaxRetries)
    69  	puller.RetryTimeout = ri.conf.General.Cluster.ReplicationRetryTimeout
    70  
    71  	replicator := &cluster.Replicator{
    72  		Filter:           filter,
    73  		LedgerFactory:    ri.lf,
    74  		SystemChannel:    systemChannelName,
    75  		BootBlock:        bootstrapBlock,
    76  		Logger:           ri.logger,
    77  		AmIPartOfChannel: consenterCert.IsConsenterOfChannel,
    78  		Puller:           puller,
    79  		ChannelLister: &cluster.ChainInspector{
    80  			Logger:          ri.logger,
    81  			Puller:          puller,
    82  			LastConfigBlock: bootstrapBlock,
    83  		},
    84  	}
    85  
    86  	// If a custom channel lister is requested, use it
    87  	if ri.channelLister != nil {
    88  		replicator.ChannelLister = ri.channelLister
    89  	}
    90  
    91  	return replicator
    92  }
    93  
    94  func (ri *replicationInitiator) replicateNeededChannels(bootstrapBlock *common.Block) {
    95  	replicator := ri.createReplicator(bootstrapBlock, cluster.AnyChannel)
    96  	defer replicator.Puller.Close()
    97  	replicationNeeded, err := replicator.IsReplicationNeeded()
    98  	if err != nil {
    99  		ri.logger.Panicf("Failed determining whether replication is needed: %v", err)
   100  	}
   101  
   102  	if !replicationNeeded {
   103  		ri.logger.Info("Replication isn't needed")
   104  		return
   105  	}
   106  
   107  	ri.logger.Info("Will now replicate chains")
   108  	replicator.ReplicateChains()
   109  }
   110  
   111  // ReplicateChains replicates the given chains with the assistance of the given last system channel config block,
   112  // and returns the names of the chains that were successfully replicated.
   113  func (ri *replicationInitiator) ReplicateChains(lastConfigBlock *common.Block, chains []string) []string {
   114  	ri.logger.Info("Will now replicate chains", chains)
   115  	wantedChannels := make(map[string]struct{})
   116  	for _, chain := range chains {
   117  		wantedChannels[chain] = struct{}{}
   118  	}
   119  	filter := func(channelName string) bool {
   120  		_, exists := wantedChannels[channelName]
   121  		return exists
   122  	}
   123  	replicator := ri.createReplicator(lastConfigBlock, filter)
   124  	replicator.DoNotPanicIfClusterNotReachable = true
   125  	defer replicator.Puller.Close()
   126  	return replicator.ReplicateChains()
   127  }
   128  
   129  type ledgerFactory struct {
   130  	blockledger.Factory
   131  	onBlockCommit cluster.BlockCommitFunc
   132  }
   133  
   134  func (lf *ledgerFactory) GetOrCreate(chainID string) (cluster.LedgerWriter, error) {
   135  	ledger, err := lf.Factory.GetOrCreate(chainID)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  	interceptedLedger := &cluster.LedgerInterceptor{
   140  		LedgerWriter:         ledger,
   141  		Channel:              chainID,
   142  		InterceptBlockCommit: lf.onBlockCommit,
   143  	}
   144  	return interceptedLedger, nil
   145  }
   146  
   147  //go:generate mockery -dir . -name ChainReplicator -case underscore -output mocks
   148  
   149  // ChainReplicator replicates chains
   150  type ChainReplicator interface {
   151  	// ReplicateChains replicates the given chains using the given last system channel config block.
   152  	// It returns the names of the chains that were successfully replicated.
   153  	ReplicateChains(lastConfigBlock *common.Block, chains []string) []string
   154  }
   155  
   156  // inactiveChainReplicator tracks disabled chains and replicates them upon demand
   157  type inactiveChainReplicator struct {
   158  	registerChain                     func(chain string)
   159  	logger                            *flogging.FabricLogger
   160  	retrieveLastSysChannelConfigBlock func() *common.Block
   161  	replicator                        ChainReplicator
   162  	scheduleChan                      <-chan time.Time
   163  	quitChan                          chan struct{}
   164  	lock                              sync.RWMutex
   165  	chains2CreationCallbacks          map[string]chainCreation
   166  }
   167  
   168  func (dc *inactiveChainReplicator) Channels() []cluster.ChannelGenesisBlock {
   169  	dc.lock.RLock()
   170  	defer dc.lock.RUnlock()
   171  
   172  	var res []cluster.ChannelGenesisBlock
   173  	for name, chain := range dc.chains2CreationCallbacks {
   174  		res = append(res, cluster.ChannelGenesisBlock{
   175  			ChannelName:  name,
   176  			GenesisBlock: chain.genesisBlock,
   177  		})
   178  	}
   179  	return res
   180  }
   181  
   182  func (dc *inactiveChainReplicator) Close() {}
   183  
   184  type chainCreation struct {
   185  	create       func()
   186  	genesisBlock *common.Block
   187  }
   188  
   189  // TrackChain tracks a chain with the given name, and calls the given callback
   190  // when this chain should be activated.
   191  func (dc *inactiveChainReplicator) TrackChain(chain string, genesisBlock *common.Block, createChainCallback func()) {
   192  	dc.lock.Lock()
   193  	defer dc.lock.Unlock()
   194  
   195  	dc.logger.Infof("Adding %s to the set of chains to track", chain)
   196  	dc.chains2CreationCallbacks[chain] = chainCreation{
   197  		genesisBlock: genesisBlock,
   198  		create:       createChainCallback,
   199  	}
   200  }
   201  
   202  func (dc *inactiveChainReplicator) run() {
   203  	for {
   204  		select {
   205  		case <-dc.scheduleChan:
   206  			dc.replicateDisabledChains()
   207  		case <-dc.quitChan:
   208  			return
   209  		}
   210  	}
   211  }
   212  
   213  func (dc *inactiveChainReplicator) replicateDisabledChains() {
   214  	chains := dc.listInactiveChains()
   215  	if len(chains) == 0 {
   216  		dc.logger.Debugf("No inactive chains to try to replicate")
   217  		return
   218  	}
   219  
   220  	// For each chain, ensure we registered it into the verifier registry, otherwise
   221  	// we won't be able to verify its blocks.
   222  	for _, chain := range chains {
   223  		dc.registerChain(chain)
   224  	}
   225  
   226  	dc.logger.Infof("Found %d inactive chains: %v", len(chains), chains)
   227  	lastSystemChannelConfigBlock := dc.retrieveLastSysChannelConfigBlock()
   228  	replicatedChains := dc.replicator.ReplicateChains(lastSystemChannelConfigBlock, chains)
   229  	dc.logger.Infof("Successfully replicated %d chains: %v", len(replicatedChains), replicatedChains)
   230  	dc.lock.Lock()
   231  	defer dc.lock.Unlock()
   232  	for _, chainName := range replicatedChains {
   233  		chain := dc.chains2CreationCallbacks[chainName]
   234  		delete(dc.chains2CreationCallbacks, chainName)
   235  		chain.create()
   236  	}
   237  }
   238  
   239  func (dc *inactiveChainReplicator) stop() {
   240  	close(dc.quitChan)
   241  }
   242  
   243  func (dc *inactiveChainReplicator) listInactiveChains() []string {
   244  	dc.lock.RLock()
   245  	defer dc.lock.RUnlock()
   246  	var chains []string
   247  	for chain := range dc.chains2CreationCallbacks {
   248  		chains = append(chains, chain)
   249  	}
   250  	return chains
   251  }
   252  
   253  //go:generate mockery -dir . -name Factory -case underscore  -output mocks/
   254  
   255  // Factory retrieves or creates new ledgers by chainID
   256  type Factory interface {
   257  	// GetOrCreate gets an existing ledger (if it exists)
   258  	// or creates it if it does not
   259  	GetOrCreate(chainID string) (blockledger.ReadWriter, error)
   260  
   261  	// ChannelIDs returns the channel IDs the Factory is aware of
   262  	ChannelIDs() []string
   263  
   264  	// Close releases all resources acquired by the factory
   265  	Close()
   266  }
   267  
   268  type blockGetter struct {
   269  	ledger blockledger.Reader
   270  }
   271  
   272  func (bg *blockGetter) Block(number uint64) *common.Block {
   273  	return blockledger.GetBlock(bg.ledger, number)
   274  }
   275  
   276  type verifierLoader struct {
   277  	ledgerFactory   blockledger.Factory
   278  	verifierFactory cluster.VerifierFactory
   279  	logger          *flogging.FabricLogger
   280  	onFailure       func(block *common.Block)
   281  }
   282  
   283  type verifiersByChannel map[string]cluster.BlockVerifier
   284  
   285  func (vl *verifierLoader) loadVerifiers() verifiersByChannel {
   286  	res := make(verifiersByChannel)
   287  
   288  	for _, channel := range vl.ledgerFactory.ChannelIDs() {
   289  		v := vl.loadVerifier(channel)
   290  		if v == nil {
   291  			continue
   292  		}
   293  		res[channel] = v
   294  	}
   295  
   296  	return res
   297  }
   298  
   299  func (vl *verifierLoader) loadVerifier(chain string) cluster.BlockVerifier {
   300  	ledger, err := vl.ledgerFactory.GetOrCreate(chain)
   301  	if err != nil {
   302  		vl.logger.Panicf("Failed obtaining ledger for channel %s", chain)
   303  	}
   304  
   305  	blockRetriever := &blockGetter{ledger: ledger}
   306  	height := ledger.Height()
   307  	if height == 0 {
   308  		vl.logger.Errorf("Channel %s has no blocks, skipping it", chain)
   309  		return nil
   310  	}
   311  	lastBlockIndex := height - 1
   312  	lastBlock := blockRetriever.Block(lastBlockIndex)
   313  	if lastBlock == nil {
   314  		vl.logger.Panicf("Failed retrieving block [%d] for channel %s", lastBlockIndex, chain)
   315  	}
   316  
   317  	lastConfigBlock, err := cluster.LastConfigBlock(lastBlock, blockRetriever)
   318  	if err != nil {
   319  		vl.logger.Panicf("Failed retrieving config block [%d] for channel %s", lastBlockIndex, chain)
   320  	}
   321  	conf, err := cluster.ConfigFromBlock(lastConfigBlock)
   322  	if err != nil {
   323  		vl.onFailure(lastConfigBlock)
   324  		vl.logger.Panicf("Failed extracting configuration for channel %s from block [%d]: %v",
   325  			chain, lastConfigBlock.Header.Number, err)
   326  	}
   327  
   328  	verifier, err := vl.verifierFactory.VerifierFromConfig(conf, chain)
   329  	if err != nil {
   330  		vl.onFailure(lastConfigBlock)
   331  		vl.logger.Panicf("Failed creating verifier for channel %s from block [%d]: %v", chain, lastBlockIndex, err)
   332  	}
   333  	vl.logger.Infof("Loaded verifier for channel %s from config block at index %d", chain, lastBlockIndex)
   334  	return verifier
   335  }
   336  
   337  // ValidateBootstrapBlock returns whether this block can be used as a bootstrap block.
   338  // A bootstrap block is a block of a system channel, and needs to have a ConsortiumsConfig.
   339  func ValidateBootstrapBlock(block *common.Block, bccsp bccsp.BCCSP) error {
   340  	if block == nil {
   341  		return errors.New("nil block")
   342  	}
   343  
   344  	if block.Data == nil || len(block.Data.Data) == 0 {
   345  		return errors.New("empty block data")
   346  	}
   347  
   348  	firstTransaction := &common.Envelope{}
   349  	if err := proto.Unmarshal(block.Data.Data[0], firstTransaction); err != nil {
   350  		return errors.Wrap(err, "failed extracting envelope from block")
   351  	}
   352  
   353  	bundle, err := channelconfig.NewBundleFromEnvelope(firstTransaction, bccsp)
   354  	if err != nil {
   355  		return err
   356  	}
   357  
   358  	_, exists := bundle.ConsortiumsConfig()
   359  	if !exists {
   360  		return errors.New("the block isn't a system channel block because it lacks ConsortiumsConfig")
   361  	}
   362  	return nil
   363  }