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

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package cluster
     8  
     9  import (
    10  	"bytes"
    11  	"encoding/base64"
    12  	"encoding/hex"
    13  	"encoding/pem"
    14  	"time"
    15  
    16  	"github.com/hyperledger/fabric-protos-go/common"
    17  	"github.com/hyperledger/fabric/bccsp"
    18  	"github.com/hyperledger/fabric/common/flogging"
    19  	"github.com/hyperledger/fabric/internal/pkg/comm"
    20  	"github.com/hyperledger/fabric/internal/pkg/identity"
    21  	"github.com/hyperledger/fabric/orderer/common/localconfig"
    22  	"github.com/hyperledger/fabric/protoutil"
    23  	"github.com/pkg/errors"
    24  )
    25  
    26  const (
    27  	// RetryTimeout is the time the block puller retries.
    28  	RetryTimeout = time.Second * 10
    29  )
    30  
    31  // ChannelPredicate accepts channels according to their names.
    32  type ChannelPredicate func(channelName string) bool
    33  
    34  // AnyChannel accepts all channels.
    35  func AnyChannel(_ string) bool {
    36  	return true
    37  }
    38  
    39  // PullerConfigFromTopLevelConfig creates a PullerConfig from a TopLevel config,
    40  // and from a signer and TLS key cert pair.
    41  // The PullerConfig's channel is initialized to be the system channel.
    42  func PullerConfigFromTopLevelConfig(
    43  	systemChannel string,
    44  	conf *localconfig.TopLevel,
    45  	tlsKey,
    46  	tlsCert []byte,
    47  	signer identity.SignerSerializer,
    48  ) PullerConfig {
    49  	return PullerConfig{
    50  		Channel:             systemChannel,
    51  		MaxTotalBufferBytes: conf.General.Cluster.ReplicationBufferSize,
    52  		Timeout:             conf.General.Cluster.RPCTimeout,
    53  		TLSKey:              tlsKey,
    54  		TLSCert:             tlsCert,
    55  		Signer:              signer,
    56  	}
    57  }
    58  
    59  //go:generate mockery -dir . -name LedgerWriter -case underscore -output mocks/
    60  
    61  // LedgerWriter allows the caller to write blocks and inspect the height
    62  type LedgerWriter interface {
    63  	// Append a new block to the ledger
    64  	Append(block *common.Block) error
    65  
    66  	// Height returns the number of blocks on the ledger
    67  	Height() uint64
    68  }
    69  
    70  //go:generate mockery -dir . -name LedgerFactory -case underscore -output mocks/
    71  
    72  // LedgerFactory retrieves or creates new ledgers by chainID
    73  type LedgerFactory interface {
    74  	// GetOrCreate gets an existing ledger (if it exists)
    75  	// or creates it if it does not
    76  	GetOrCreate(chainID string) (LedgerWriter, error)
    77  }
    78  
    79  //go:generate mockery -dir . -name ChannelLister -case underscore -output mocks/
    80  
    81  // ChannelLister returns a list of channels
    82  type ChannelLister interface {
    83  	// Channels returns a list of channels
    84  	Channels() []ChannelGenesisBlock
    85  	// Close closes the ChannelLister
    86  	Close()
    87  }
    88  
    89  // Replicator replicates chains
    90  type Replicator struct {
    91  	DoNotPanicIfClusterNotReachable bool
    92  	Filter                          ChannelPredicate
    93  	SystemChannel                   string
    94  	ChannelLister                   ChannelLister
    95  	Logger                          *flogging.FabricLogger
    96  	Puller                          *BlockPuller
    97  	BootBlock                       *common.Block
    98  	AmIPartOfChannel                SelfMembershipPredicate
    99  	LedgerFactory                   LedgerFactory
   100  }
   101  
   102  // IsReplicationNeeded returns whether replication is needed,
   103  // or the cluster node can resume standard boot flow.
   104  func (r *Replicator) IsReplicationNeeded() (bool, error) {
   105  	systemChannelLedger, err := r.LedgerFactory.GetOrCreate(r.SystemChannel)
   106  	if err != nil {
   107  		return false, err
   108  	}
   109  
   110  	height := systemChannelLedger.Height()
   111  	var lastBlockSeq uint64
   112  	// If Height is 0 then lastBlockSeq would be 2^64 - 1,
   113  	// so make it 0 to take care of the overflow.
   114  	if height == 0 {
   115  		lastBlockSeq = 0
   116  	} else {
   117  		lastBlockSeq = height - 1
   118  	}
   119  
   120  	if r.BootBlock.Header.Number > lastBlockSeq {
   121  		return true, nil
   122  	}
   123  	return false, nil
   124  }
   125  
   126  // ReplicateChains pulls chains and commits them.
   127  // Returns the names of the chains replicated successfully.
   128  func (r *Replicator) ReplicateChains() []string {
   129  	var replicatedChains []string
   130  	channels := r.discoverChannels()
   131  	pullHints := r.channelsToPull(channels)
   132  	totalChannelCount := len(pullHints.channelsToPull) + len(pullHints.channelsNotToPull)
   133  	r.Logger.Info("Found myself in", len(pullHints.channelsToPull), "channels out of", totalChannelCount, ":", pullHints)
   134  
   135  	// Append the genesis blocks of the application channels we have into the ledger
   136  	for _, channels := range [][]ChannelGenesisBlock{pullHints.channelsToPull, pullHints.channelsNotToPull} {
   137  		for _, channel := range channels {
   138  			ledger, err := r.LedgerFactory.GetOrCreate(channel.ChannelName)
   139  			if err != nil {
   140  				r.Logger.Panicf("Failed to create a ledger for channel %s: %v", channel.ChannelName, err)
   141  			}
   142  
   143  			if channel.GenesisBlock == nil {
   144  				if ledger.Height() == 0 {
   145  					r.Logger.Panicf("Expecting channel %s to at least contain genesis block, but it doesn't", channel.ChannelName)
   146  				}
   147  
   148  				continue
   149  			}
   150  
   151  			r.appendBlock(channel.GenesisBlock, ledger, channel.ChannelName)
   152  		}
   153  	}
   154  
   155  	for _, channel := range pullHints.channelsToPull {
   156  		err := r.PullChannel(channel.ChannelName)
   157  		if err == nil {
   158  			replicatedChains = append(replicatedChains, channel.ChannelName)
   159  		} else {
   160  			r.Logger.Warningf("Failed pulling channel %s: %v", channel.ChannelName, err)
   161  		}
   162  	}
   163  
   164  	// Last, pull the system chain.
   165  	if err := r.PullChannel(r.SystemChannel); err != nil && err != ErrSkipped {
   166  		r.Logger.Panicf("Failed pulling system channel: %v", err)
   167  	}
   168  	return replicatedChains
   169  }
   170  
   171  func (r *Replicator) discoverChannels() []ChannelGenesisBlock {
   172  	r.Logger.Debug("Entering")
   173  	defer r.Logger.Debug("Exiting")
   174  	channels := GenesisBlocks(r.ChannelLister.Channels())
   175  	r.Logger.Info("Discovered", len(channels), "channels:", channels.Names())
   176  	r.ChannelLister.Close()
   177  	return channels
   178  }
   179  
   180  // PullChannel pulls the given channel from some orderer,
   181  // and commits it to the ledger.
   182  func (r *Replicator) PullChannel(channel string) error {
   183  	if !r.Filter(channel) {
   184  		r.Logger.Infof("Channel %s shouldn't be pulled. Skipping it", channel)
   185  		return ErrSkipped
   186  	}
   187  	r.Logger.Info("Pulling channel", channel)
   188  	puller := r.Puller.Clone()
   189  	defer puller.Close()
   190  	puller.Channel = channel
   191  
   192  	ledger, err := r.LedgerFactory.GetOrCreate(channel)
   193  	if err != nil {
   194  		r.Logger.Panicf("Failed to create a ledger for channel %s: %v", channel, err)
   195  	}
   196  
   197  	endpoint, latestHeight, _ := latestHeightAndEndpoint(puller)
   198  	if endpoint == "" {
   199  		return errors.Errorf("failed obtaining the latest block for channel %s", channel)
   200  	}
   201  	r.Logger.Info("Latest block height for channel", channel, "is", latestHeight)
   202  	// Ensure that if we pull the system channel, the latestHeight is bigger or equal to the
   203  	// bootstrap block of the system channel.
   204  	// Otherwise, we'd be left with a block gap.
   205  	if channel == r.SystemChannel && latestHeight-1 < r.BootBlock.Header.Number {
   206  		return errors.Errorf("latest height found among system channel(%s) orderers is %d, but the boot block's "+
   207  			"sequence is %d", r.SystemChannel, latestHeight, r.BootBlock.Header.Number)
   208  	}
   209  	return r.pullChannelBlocks(channel, puller, latestHeight, ledger)
   210  }
   211  
   212  func (r *Replicator) pullChannelBlocks(channel string, puller *BlockPuller, latestHeight uint64, ledger LedgerWriter) error {
   213  	nextBlockToPull := ledger.Height()
   214  	if nextBlockToPull == latestHeight {
   215  		r.Logger.Infof("Latest height found (%d) is equal to our height, skipping pulling channel %s", latestHeight, channel)
   216  		return nil
   217  	}
   218  	// Pull the next block and remember its hash.
   219  	nextBlock := puller.PullBlock(nextBlockToPull)
   220  	if nextBlock == nil {
   221  		return ErrRetryCountExhausted
   222  	}
   223  	r.appendBlock(nextBlock, ledger, channel)
   224  	actualPrevHash := protoutil.BlockHeaderHash(nextBlock.Header)
   225  
   226  	for seq := uint64(nextBlockToPull + 1); seq < latestHeight; seq++ {
   227  		block := puller.PullBlock(seq)
   228  		if block == nil {
   229  			return ErrRetryCountExhausted
   230  		}
   231  		reportedPrevHash := block.Header.PreviousHash
   232  		if !bytes.Equal(reportedPrevHash, actualPrevHash) {
   233  			return errors.Errorf("block header mismatch on sequence %d, expected %x, got %x",
   234  				block.Header.Number, actualPrevHash, reportedPrevHash)
   235  		}
   236  		actualPrevHash = protoutil.BlockHeaderHash(block.Header)
   237  		if channel == r.SystemChannel && block.Header.Number == r.BootBlock.Header.Number {
   238  			r.compareBootBlockWithSystemChannelLastConfigBlock(block)
   239  			r.appendBlock(block, ledger, channel)
   240  			// No need to pull further blocks from the system channel
   241  			return nil
   242  		}
   243  		r.appendBlock(block, ledger, channel)
   244  	}
   245  	return nil
   246  }
   247  
   248  func (r *Replicator) appendBlock(block *common.Block, ledger LedgerWriter, channel string) {
   249  	height := ledger.Height()
   250  	if height > block.Header.Number {
   251  		r.Logger.Infof("Skipping commit of block [%d] for channel %s because height is at %d", block.Header.Number, channel, height)
   252  		return
   253  	}
   254  	if err := ledger.Append(block); err != nil {
   255  		r.Logger.Panicf("Failed to write block [%d]: %v", block.Header.Number, err)
   256  	}
   257  	r.Logger.Infof("Committed block [%d] for channel %s", block.Header.Number, channel)
   258  }
   259  
   260  func (r *Replicator) compareBootBlockWithSystemChannelLastConfigBlock(block *common.Block) {
   261  	// Overwrite the received block's data hash
   262  	block.Header.DataHash = protoutil.BlockDataHash(block.Data)
   263  
   264  	bootBlockHash := protoutil.BlockHeaderHash(r.BootBlock.Header)
   265  	retrievedBlockHash := protoutil.BlockHeaderHash(block.Header)
   266  	if bytes.Equal(bootBlockHash, retrievedBlockHash) {
   267  		return
   268  	}
   269  	r.Logger.Panicf("Block header mismatch on last system channel block, expected %s, got %s",
   270  		hex.EncodeToString(bootBlockHash), hex.EncodeToString(retrievedBlockHash))
   271  }
   272  
   273  type channelPullHints struct {
   274  	channelsToPull    []ChannelGenesisBlock
   275  	channelsNotToPull []ChannelGenesisBlock
   276  }
   277  
   278  func (r *Replicator) channelsToPull(channels GenesisBlocks) channelPullHints {
   279  	r.Logger.Info("Evaluating channels to pull:", channels.Names())
   280  
   281  	// Backup the verifier of the puller
   282  	verifier := r.Puller.VerifyBlockSequence
   283  	// Restore it at the end of the function
   284  	defer func() {
   285  		r.Puller.VerifyBlockSequence = verifier
   286  	}()
   287  	// Set it to be a no-op verifier, because we can't verify latest blocks of channels.
   288  	r.Puller.VerifyBlockSequence = func(blocks []*common.Block, channel string) error {
   289  		return nil
   290  	}
   291  
   292  	var channelsNotToPull []ChannelGenesisBlock
   293  	var channelsToPull []ChannelGenesisBlock
   294  	for _, channel := range channels {
   295  		r.Logger.Info("Probing whether I should pull channel", channel.ChannelName)
   296  		puller := r.Puller.Clone()
   297  		puller.Channel = channel.ChannelName
   298  		// Disable puller buffering when we check whether we are in the channel,
   299  		// as we only need to know about a single block.
   300  		bufferSize := puller.MaxTotalBufferBytes
   301  		puller.MaxTotalBufferBytes = 1
   302  		err := Participant(puller, r.AmIPartOfChannel)
   303  		puller.Close()
   304  		// Restore the previous buffer size
   305  		puller.MaxTotalBufferBytes = bufferSize
   306  		if err == ErrNotInChannel || err == ErrForbidden {
   307  			r.Logger.Infof("I do not belong to channel %s or am forbidden pulling it (%v), skipping chain retrieval", channel.ChannelName, err)
   308  			channelsNotToPull = append(channelsNotToPull, channel)
   309  			continue
   310  		}
   311  		if err == ErrServiceUnavailable {
   312  			r.Logger.Infof("All orderers in the system channel are either down,"+
   313  				"or do not service channel %s (%v), skipping chain retrieval", channel.ChannelName, err)
   314  			channelsNotToPull = append(channelsNotToPull, channel)
   315  			continue
   316  		}
   317  		if err == ErrRetryCountExhausted {
   318  			r.Logger.Warningf("Could not obtain blocks needed for classifying whether I am in the channel,"+
   319  				"skipping the retrieval of the chan %s", channel.ChannelName)
   320  			channelsNotToPull = append(channelsNotToPull, channel)
   321  			continue
   322  		}
   323  		if err != nil {
   324  			if !r.DoNotPanicIfClusterNotReachable {
   325  				r.Logger.Panicf("Failed classifying whether I belong to channel %s: %v, skipping chain retrieval", channel.ChannelName, err)
   326  			}
   327  			continue
   328  		}
   329  		r.Logger.Infof("I need to pull channel %s", channel.ChannelName)
   330  		channelsToPull = append(channelsToPull, channel)
   331  	}
   332  	return channelPullHints{
   333  		channelsToPull:    channelsToPull,
   334  		channelsNotToPull: channelsNotToPull,
   335  	}
   336  }
   337  
   338  // PullerConfig configures a BlockPuller.
   339  type PullerConfig struct {
   340  	TLSKey              []byte
   341  	TLSCert             []byte
   342  	Timeout             time.Duration
   343  	Signer              identity.SignerSerializer
   344  	Channel             string
   345  	MaxTotalBufferBytes int
   346  }
   347  
   348  //go:generate mockery -dir . -name VerifierRetriever -case underscore -output mocks/
   349  
   350  // VerifierRetriever retrieves BlockVerifiers for channels.
   351  type VerifierRetriever interface {
   352  	// RetrieveVerifier retrieves a BlockVerifier for the given channel.
   353  	RetrieveVerifier(channel string) BlockVerifier
   354  }
   355  
   356  // BlockPullerFromConfigBlock returns a BlockPuller that doesn't verify signatures on blocks.
   357  func BlockPullerFromConfigBlock(conf PullerConfig, block *common.Block, verifierRetriever VerifierRetriever, bccsp bccsp.BCCSP) (*BlockPuller, error) {
   358  	if block == nil {
   359  		return nil, errors.New("nil block")
   360  	}
   361  
   362  	endpoints, err := EndpointconfigFromConfigBlock(block, bccsp)
   363  	if err != nil {
   364  		return nil, err
   365  	}
   366  
   367  	clientConf := comm.ClientConfig{
   368  		Timeout: conf.Timeout,
   369  		SecOpts: comm.SecureOptions{
   370  			Certificate:       conf.TLSCert,
   371  			Key:               conf.TLSKey,
   372  			RequireClientCert: true,
   373  			UseTLS:            true,
   374  		},
   375  	}
   376  
   377  	dialer := &StandardDialer{
   378  		Config: clientConf.Clone(),
   379  	}
   380  
   381  	tlsCertAsDER, _ := pem.Decode(conf.TLSCert)
   382  	if tlsCertAsDER == nil {
   383  		return nil, errors.Errorf("unable to decode TLS certificate PEM: %s", base64.StdEncoding.EncodeToString(conf.TLSCert))
   384  	}
   385  
   386  	return &BlockPuller{
   387  		Logger:  flogging.MustGetLogger("orderer.common.cluster.replication").With("channel", conf.Channel),
   388  		Dialer:  dialer,
   389  		TLSCert: tlsCertAsDER.Bytes,
   390  		VerifyBlockSequence: func(blocks []*common.Block, channel string) error {
   391  			verifier := verifierRetriever.RetrieveVerifier(channel)
   392  			if verifier == nil {
   393  				return errors.Errorf("couldn't acquire verifier for channel %s", channel)
   394  			}
   395  			return VerifyBlocks(blocks, verifier)
   396  		},
   397  		MaxTotalBufferBytes: conf.MaxTotalBufferBytes,
   398  		Endpoints:           endpoints,
   399  		RetryTimeout:        RetryTimeout,
   400  		FetchTimeout:        conf.Timeout,
   401  		Channel:             conf.Channel,
   402  		Signer:              conf.Signer,
   403  	}, nil
   404  }
   405  
   406  // NoopBlockVerifier doesn't verify block signatures
   407  type NoopBlockVerifier struct{}
   408  
   409  // VerifyBlockSignature accepts all signatures over blocks.
   410  func (*NoopBlockVerifier) VerifyBlockSignature(sd []*protoutil.SignedData, config *common.ConfigEnvelope) error {
   411  	return nil
   412  }
   413  
   414  //go:generate mockery -dir . -name ChainPuller -case underscore -output mocks/
   415  
   416  // ChainPuller pulls blocks from a chain
   417  type ChainPuller interface {
   418  	// PullBlock pulls the given block from some orderer node
   419  	PullBlock(seq uint64) *common.Block
   420  
   421  	// HeightsByEndpoints returns the block heights by endpoints of orderers
   422  	HeightsByEndpoints() (map[string]uint64, error)
   423  
   424  	// Close closes the ChainPuller
   425  	Close()
   426  }
   427  
   428  // ChainInspector walks over a chain
   429  type ChainInspector struct {
   430  	Logger          *flogging.FabricLogger
   431  	Puller          ChainPuller
   432  	LastConfigBlock *common.Block
   433  }
   434  
   435  // ErrSkipped denotes that replicating a chain was skipped
   436  var ErrSkipped = errors.New("skipped")
   437  
   438  // ErrForbidden denotes that an ordering node refuses sending blocks due to access control.
   439  var ErrForbidden = errors.New("forbidden pulling the channel")
   440  
   441  // ErrServiceUnavailable denotes that an ordering node is not servicing at the moment.
   442  var ErrServiceUnavailable = errors.New("service unavailable")
   443  
   444  // ErrNotInChannel denotes that an ordering node is not in the channel
   445  var ErrNotInChannel = errors.New("not in the channel")
   446  
   447  var ErrRetryCountExhausted = errors.New("retry attempts exhausted")
   448  
   449  // SelfMembershipPredicate determines whether the caller is found in the given config block
   450  type SelfMembershipPredicate func(configBlock *common.Block) error
   451  
   452  // Participant returns whether the caller participates in the chain.
   453  // It receives a ChainPuller that should already be calibrated for the chain,
   454  // and a SelfMembershipPredicate that is used to detect whether the caller should service the chain.
   455  // It returns nil if the caller participates in the chain.
   456  // It may return:
   457  // ErrNotInChannel in case the caller doesn't participate in the chain.
   458  // ErrForbidden in case the caller is forbidden from pulling the block.
   459  // ErrServiceUnavailable in case all orderers reachable cannot complete the request.
   460  // ErrRetryCountExhausted in case no orderer is reachable.
   461  func Participant(puller ChainPuller, analyzeLastConfBlock SelfMembershipPredicate) error {
   462  	lastConfigBlock, err := PullLastConfigBlock(puller)
   463  	if err != nil {
   464  		return err
   465  	}
   466  	return analyzeLastConfBlock(lastConfigBlock)
   467  }
   468  
   469  // PullLastConfigBlock pulls the last configuration block, or returns an error on failure.
   470  func PullLastConfigBlock(puller ChainPuller) (*common.Block, error) {
   471  	endpoint, latestHeight, err := latestHeightAndEndpoint(puller)
   472  	if err != nil {
   473  		return nil, err
   474  	}
   475  	if endpoint == "" {
   476  		return nil, ErrRetryCountExhausted
   477  	}
   478  	lastBlock := puller.PullBlock(latestHeight - 1)
   479  	if lastBlock == nil {
   480  		return nil, ErrRetryCountExhausted
   481  	}
   482  	lastConfNumber, err := protoutil.GetLastConfigIndexFromBlock(lastBlock)
   483  	if err != nil {
   484  		return nil, err
   485  	}
   486  	// The last config block is smaller than the latest height,
   487  	// and a block iterator on the server side is a sequenced one.
   488  	// So we need to reset the puller if we wish to pull an earlier block.
   489  	puller.Close()
   490  	lastConfigBlock := puller.PullBlock(lastConfNumber)
   491  	if lastConfigBlock == nil {
   492  		return nil, ErrRetryCountExhausted
   493  	}
   494  	return lastConfigBlock, nil
   495  }
   496  
   497  func latestHeightAndEndpoint(puller ChainPuller) (string, uint64, error) {
   498  	var maxHeight uint64
   499  	var mostUpToDateEndpoint string
   500  	heightsByEndpoints, err := puller.HeightsByEndpoints()
   501  	if err != nil {
   502  		return "", 0, err
   503  	}
   504  	for endpoint, height := range heightsByEndpoints {
   505  		if height >= maxHeight {
   506  			maxHeight = height
   507  			mostUpToDateEndpoint = endpoint
   508  		}
   509  	}
   510  	return mostUpToDateEndpoint, maxHeight, nil
   511  }
   512  
   513  // Close closes the ChainInspector
   514  func (ci *ChainInspector) Close() {
   515  	ci.Puller.Close()
   516  }
   517  
   518  // ChannelGenesisBlock wraps a Block and its channel name
   519  type ChannelGenesisBlock struct {
   520  	ChannelName  string
   521  	GenesisBlock *common.Block
   522  }
   523  
   524  // GenesisBlocks aggregates several ChannelGenesisBlocks
   525  type GenesisBlocks []ChannelGenesisBlock
   526  
   527  // Names returns the channel names all ChannelGenesisBlocks
   528  func (gbs GenesisBlocks) Names() []string {
   529  	var res []string
   530  	for _, gb := range gbs {
   531  		res = append(res, gb.ChannelName)
   532  	}
   533  	return res
   534  }
   535  
   536  // Channels returns the list of ChannelGenesisBlocks
   537  // for all channels. Each such ChannelGenesisBlock contains
   538  // the genesis block of the channel.
   539  func (ci *ChainInspector) Channels() []ChannelGenesisBlock {
   540  	channels := make(map[string]ChannelGenesisBlock)
   541  	lastConfigBlockNum := ci.LastConfigBlock.Header.Number
   542  	var block *common.Block
   543  	var prevHash []byte
   544  	for seq := uint64(0); seq < lastConfigBlockNum; seq++ {
   545  		block = ci.Puller.PullBlock(seq)
   546  		if block == nil {
   547  			ci.Logger.Panicf("Failed pulling block [%d] from the system channel", seq)
   548  		}
   549  		ci.validateHashPointer(block, prevHash)
   550  		// Set the previous hash for the next iteration
   551  		prevHash = protoutil.BlockHeaderHash(block.Header)
   552  
   553  		channel, gb, err := ExtractGenesisBlock(ci.Logger, block)
   554  		if err != nil {
   555  			// If we failed to inspect a block, something is wrong in the system chain
   556  			// we're trying to pull, so abort.
   557  			ci.Logger.Panicf("Failed extracting channel genesis block from config block: %v", err)
   558  		}
   559  
   560  		if channel == "" {
   561  			ci.Logger.Info("Block", seq, "doesn't contain a new channel")
   562  			continue
   563  		}
   564  
   565  		ci.Logger.Info("Block", seq, "contains channel", channel)
   566  		channels[channel] = ChannelGenesisBlock{
   567  			ChannelName:  channel,
   568  			GenesisBlock: gb,
   569  		}
   570  	}
   571  	// At this point, block holds reference to the last block pulled.
   572  	// We ensure that the hash of the last block pulled, is the previous hash
   573  	// of the LastConfigBlock we were initialized with.
   574  	// We don't need to verify the entire chain of all blocks we pulled,
   575  	// because the block puller calls VerifyBlockHash on all blocks it pulls.
   576  	last2Blocks := []*common.Block{block, ci.LastConfigBlock}
   577  	if err := VerifyBlockHash(1, last2Blocks); err != nil {
   578  		ci.Logger.Panic("System channel pulled doesn't match the boot last config block:", err)
   579  	}
   580  
   581  	return flattenChannelMap(channels)
   582  }
   583  
   584  func (ci *ChainInspector) validateHashPointer(block *common.Block, prevHash []byte) {
   585  	if prevHash == nil {
   586  		return
   587  	}
   588  	if bytes.Equal(block.Header.PreviousHash, prevHash) {
   589  		return
   590  	}
   591  	ci.Logger.Panicf("Claimed previous hash of block [%d] is %x but actual previous hash is %x",
   592  		block.Header.Number, block.Header.PreviousHash, prevHash)
   593  }
   594  
   595  func flattenChannelMap(m map[string]ChannelGenesisBlock) []ChannelGenesisBlock {
   596  	var res []ChannelGenesisBlock
   597  	for _, csb := range m {
   598  		res = append(res, csb)
   599  	}
   600  	return res
   601  }
   602  
   603  // ExtractGenesisBlock determines if a config block creates new channel, in which
   604  // case it returns channel name, genesis block and nil error.
   605  func ExtractGenesisBlock(logger *flogging.FabricLogger, block *common.Block) (string, *common.Block, error) {
   606  	if block == nil {
   607  		return "", nil, errors.New("nil block")
   608  	}
   609  	env, err := protoutil.ExtractEnvelope(block, 0)
   610  	if err != nil {
   611  		return "", nil, err
   612  	}
   613  	payload, err := protoutil.UnmarshalPayload(env.Payload)
   614  	if err != nil {
   615  		return "", nil, err
   616  	}
   617  	if payload.Header == nil {
   618  		return "", nil, errors.New("nil header in payload")
   619  	}
   620  	chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   621  	if err != nil {
   622  		return "", nil, err
   623  	}
   624  	// The transaction is not orderer transaction
   625  	if common.HeaderType(chdr.Type) != common.HeaderType_ORDERER_TRANSACTION {
   626  		return "", nil, nil
   627  	}
   628  	systemChannelName := chdr.ChannelId
   629  	innerEnvelope, err := protoutil.UnmarshalEnvelope(payload.Data)
   630  	if err != nil {
   631  		return "", nil, err
   632  	}
   633  	innerPayload, err := protoutil.UnmarshalPayload(innerEnvelope.Payload)
   634  	if err != nil {
   635  		return "", nil, err
   636  	}
   637  	if innerPayload.Header == nil {
   638  		return "", nil, errors.New("inner payload's header is nil")
   639  	}
   640  	chdr, err = protoutil.UnmarshalChannelHeader(innerPayload.Header.ChannelHeader)
   641  	if err != nil {
   642  		return "", nil, err
   643  	}
   644  	// The inner payload's header should be a config transaction
   645  	if common.HeaderType(chdr.Type) != common.HeaderType_CONFIG {
   646  		logger.Warnf("Expecting %s envelope in block, got %s", common.HeaderType_CONFIG, common.HeaderType(chdr.Type))
   647  		return "", nil, nil
   648  	}
   649  	// In any case, exclude all system channel transactions
   650  	if chdr.ChannelId == systemChannelName {
   651  		logger.Warnf("Expecting config envelope in %s block to target a different "+
   652  			"channel other than system channel '%s'", common.HeaderType_ORDERER_TRANSACTION, systemChannelName)
   653  		return "", nil, nil
   654  	}
   655  
   656  	metadata := &common.BlockMetadata{
   657  		Metadata: make([][]byte, 4),
   658  	}
   659  	metadata.Metadata[common.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&common.OrdererBlockMetadata{
   660  		LastConfig: &common.LastConfig{Index: 0},
   661  		// This is a genesis block, peer never verify this signature because we can't bootstrap
   662  		// trust from an earlier block, hence there are no signatures here.
   663  	})
   664  	metadata.Metadata[common.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&common.Metadata{
   665  		Value: protoutil.MarshalOrPanic(&common.LastConfig{Index: 0}),
   666  		// This is a genesis block, peer never verify this signature because we can't bootstrap
   667  		// trust from an earlier block, hence there are no signatures here.
   668  	})
   669  
   670  	blockdata := &common.BlockData{Data: [][]byte{payload.Data}}
   671  	b := &common.Block{
   672  		Header:   &common.BlockHeader{DataHash: protoutil.BlockDataHash(blockdata)},
   673  		Data:     blockdata,
   674  		Metadata: metadata,
   675  	}
   676  	return chdr.ChannelId, b, nil
   677  }