github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/orderer/common/onboarding/onboarding.go (about)

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