github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/orderer/common/cluster/replication.go (about)

     1  /*
     2  Copyright hechain. 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/hechain20/hechain/bccsp"
    17  	"github.com/hechain20/hechain/common/flogging"
    18  	"github.com/hechain20/hechain/internal/pkg/comm"
    19  	"github.com/hechain20/hechain/internal/pkg/identity"
    20  	"github.com/hechain20/hechain/orderer/common/localconfig"
    21  	"github.com/hechain20/hechain/protoutil"
    22  	"github.com/hyperledger/fabric-protos-go/common"
    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  	puller.Logger = flogging.MustGetLogger("orderer.common.cluster.replication").With("channel", channel)
   192  
   193  	ledger, err := r.LedgerFactory.GetOrCreate(channel)
   194  	if err != nil {
   195  		r.Logger.Panicf("Failed to create a ledger for channel %s: %v", channel, err)
   196  	}
   197  
   198  	endpoint, latestHeight, _ := LatestHeightAndEndpoint(puller)
   199  	if endpoint == "" {
   200  		return errors.Errorf("failed obtaining the latest block for channel %s", channel)
   201  	}
   202  	r.Logger.Info("Latest block height for channel", channel, "is", latestHeight)
   203  	// Ensure that if we pull the system channel, the latestHeight is bigger or equal to the
   204  	// bootstrap block of the system channel.
   205  	// Otherwise, we'd be left with a block gap.
   206  	if channel == r.SystemChannel && latestHeight-1 < r.BootBlock.Header.Number {
   207  		return errors.Errorf("latest height found among system channel(%s) orderers is %d, but the boot block's "+
   208  			"sequence is %d", r.SystemChannel, latestHeight, r.BootBlock.Header.Number)
   209  	}
   210  	return r.pullChannelBlocks(channel, puller, latestHeight, ledger)
   211  }
   212  
   213  func (r *Replicator) pullChannelBlocks(channel string, puller *BlockPuller, latestHeight uint64, ledger LedgerWriter) error {
   214  	nextBlockToPull := ledger.Height()
   215  	if nextBlockToPull == latestHeight {
   216  		r.Logger.Infof("Latest height found (%d) is equal to our height, skipping pulling channel %s", latestHeight, channel)
   217  		return nil
   218  	}
   219  	// Pull the next block and remember its hash.
   220  	nextBlock := puller.PullBlock(nextBlockToPull)
   221  	if nextBlock == nil {
   222  		return ErrRetryCountExhausted
   223  	}
   224  	r.appendBlock(nextBlock, ledger, channel)
   225  	actualPrevHash := protoutil.BlockHeaderHash(nextBlock.Header)
   226  
   227  	for seq := uint64(nextBlockToPull + 1); seq < latestHeight; seq++ {
   228  		block := puller.PullBlock(seq)
   229  		if block == nil {
   230  			return ErrRetryCountExhausted
   231  		}
   232  		reportedPrevHash := block.Header.PreviousHash
   233  		if !bytes.Equal(reportedPrevHash, actualPrevHash) {
   234  			return errors.Errorf("block header mismatch on sequence %d, expected %x, got %x",
   235  				block.Header.Number, actualPrevHash, reportedPrevHash)
   236  		}
   237  		actualPrevHash = protoutil.BlockHeaderHash(block.Header)
   238  		if channel == r.SystemChannel && block.Header.Number == r.BootBlock.Header.Number {
   239  			r.compareBootBlockWithSystemChannelLastConfigBlock(block)
   240  			r.appendBlock(block, ledger, channel)
   241  			// No need to pull further blocks from the system channel
   242  			return nil
   243  		}
   244  		r.appendBlock(block, ledger, channel)
   245  	}
   246  	return nil
   247  }
   248  
   249  func (r *Replicator) appendBlock(block *common.Block, ledger LedgerWriter, channel string) {
   250  	height := ledger.Height()
   251  	if height > block.Header.Number {
   252  		r.Logger.Infof("Skipping commit of block [%d] for channel %s because height is at %d", block.Header.Number, channel, height)
   253  		return
   254  	}
   255  	if err := ledger.Append(block); err != nil {
   256  		r.Logger.Panicf("Failed to write block [%d]: %v", block.Header.Number, err)
   257  	}
   258  	r.Logger.Infof("Committed block [%d] for channel %s", block.Header.Number, channel)
   259  }
   260  
   261  func (r *Replicator) compareBootBlockWithSystemChannelLastConfigBlock(block *common.Block) {
   262  	// Overwrite the received block's data hash
   263  	block.Header.DataHash = protoutil.BlockDataHash(block.Data)
   264  
   265  	bootBlockHash := protoutil.BlockHeaderHash(r.BootBlock.Header)
   266  	retrievedBlockHash := protoutil.BlockHeaderHash(block.Header)
   267  	if bytes.Equal(bootBlockHash, retrievedBlockHash) {
   268  		return
   269  	}
   270  	r.Logger.Panicf("Block header mismatch on last system channel block, expected %s, got %s",
   271  		hex.EncodeToString(bootBlockHash), hex.EncodeToString(retrievedBlockHash))
   272  }
   273  
   274  type channelPullHints struct {
   275  	channelsToPull    []ChannelGenesisBlock
   276  	channelsNotToPull []ChannelGenesisBlock
   277  }
   278  
   279  func (r *Replicator) channelsToPull(channels GenesisBlocks) channelPullHints {
   280  	r.Logger.Info("Evaluating channels to pull:", channels.Names())
   281  
   282  	// Backup the verifier of the puller
   283  	verifier := r.Puller.VerifyBlockSequence
   284  	// Restore it at the end of the function
   285  	defer func() {
   286  		r.Puller.VerifyBlockSequence = verifier
   287  	}()
   288  	// Set it to be a no-op verifier, because we can't verify latest blocks of channels.
   289  	r.Puller.VerifyBlockSequence = func(blocks []*common.Block, channel string) error {
   290  		return nil
   291  	}
   292  
   293  	var channelsNotToPull []ChannelGenesisBlock
   294  	var channelsToPull []ChannelGenesisBlock
   295  	for _, channel := range channels {
   296  		r.Logger.Info("Probing whether I should pull channel", channel.ChannelName)
   297  		puller := r.Puller.Clone()
   298  		puller.Logger = flogging.MustGetLogger("orderer.common.cluster.replication").With("channel", channel.ChannelName)
   299  		puller.Channel = channel.ChannelName
   300  		// Disable puller buffering when we check whether we are in the channel,
   301  		// as we only need to know about a single block.
   302  		bufferSize := puller.MaxTotalBufferBytes
   303  		puller.MaxTotalBufferBytes = 1
   304  		err := Participant(puller, r.AmIPartOfChannel)
   305  		puller.Close()
   306  		// Restore the previous buffer size
   307  		puller.MaxTotalBufferBytes = bufferSize
   308  		if err == ErrNotInChannel || err == ErrForbidden {
   309  			r.Logger.Infof("I do not belong to channel %s or am forbidden pulling it (%v), skipping chain retrieval", channel.ChannelName, err)
   310  			channelsNotToPull = append(channelsNotToPull, channel)
   311  			continue
   312  		}
   313  		if err == ErrServiceUnavailable {
   314  			r.Logger.Infof("All orderers in the system channel are either down,"+
   315  				"or do not service channel %s (%v), skipping chain retrieval", channel.ChannelName, err)
   316  			channelsNotToPull = append(channelsNotToPull, channel)
   317  			continue
   318  		}
   319  		if err == ErrRetryCountExhausted {
   320  			r.Logger.Warningf("Could not obtain blocks needed for classifying whether I am in the channel,"+
   321  				"skipping the retrieval of the chan %s", channel.ChannelName)
   322  			channelsNotToPull = append(channelsNotToPull, channel)
   323  			continue
   324  		}
   325  		if err != nil {
   326  			if !r.DoNotPanicIfClusterNotReachable {
   327  				r.Logger.Panicf("Failed classifying whether I belong to channel %s: %v, skipping chain retrieval", channel.ChannelName, err)
   328  			}
   329  			continue
   330  		}
   331  		r.Logger.Infof("I need to pull channel %s", channel.ChannelName)
   332  		channelsToPull = append(channelsToPull, channel)
   333  	}
   334  	return channelPullHints{
   335  		channelsToPull:    channelsToPull,
   336  		channelsNotToPull: channelsNotToPull,
   337  	}
   338  }
   339  
   340  // PullerConfig configures a BlockPuller.
   341  type PullerConfig struct {
   342  	TLSKey              []byte
   343  	TLSCert             []byte
   344  	Timeout             time.Duration
   345  	Signer              identity.SignerSerializer
   346  	Channel             string
   347  	MaxTotalBufferBytes int
   348  }
   349  
   350  //go:generate mockery -dir . -name VerifierRetriever -case underscore -output mocks/
   351  
   352  // VerifierRetriever retrieves BlockVerifiers for channels.
   353  type VerifierRetriever interface {
   354  	// RetrieveVerifier retrieves a BlockVerifier for the given channel.
   355  	RetrieveVerifier(channel string) BlockVerifier
   356  }
   357  
   358  // BlockPullerFromConfigBlock returns a BlockPuller that doesn't verify signatures on blocks.
   359  func BlockPullerFromConfigBlock(conf PullerConfig, block *common.Block, verifierRetriever VerifierRetriever, bccsp bccsp.BCCSP) (*BlockPuller, error) {
   360  	if block == nil {
   361  		return nil, errors.New("nil block")
   362  	}
   363  
   364  	endpoints, err := EndpointconfigFromConfigBlock(block, bccsp)
   365  	if err != nil {
   366  		return nil, err
   367  	}
   368  
   369  	clientConf := comm.ClientConfig{
   370  		DialTimeout: conf.Timeout,
   371  		SecOpts: comm.SecureOptions{
   372  			Certificate:       conf.TLSCert,
   373  			Key:               conf.TLSKey,
   374  			RequireClientCert: true,
   375  			UseTLS:            true,
   376  		},
   377  	}
   378  
   379  	dialer := &StandardDialer{
   380  		Config: clientConf,
   381  	}
   382  
   383  	tlsCertAsDER, _ := pem.Decode(conf.TLSCert)
   384  	if tlsCertAsDER == nil {
   385  		return nil, errors.Errorf("unable to decode TLS certificate PEM: %s", base64.StdEncoding.EncodeToString(conf.TLSCert))
   386  	}
   387  
   388  	return &BlockPuller{
   389  		Logger:  flogging.MustGetLogger("orderer.common.cluster.replication").With("channel", conf.Channel),
   390  		Dialer:  dialer,
   391  		TLSCert: tlsCertAsDER.Bytes,
   392  		VerifyBlockSequence: func(blocks []*common.Block, channel string) error {
   393  			verifier := verifierRetriever.RetrieveVerifier(channel)
   394  			if verifier == nil {
   395  				return errors.Errorf("couldn't acquire verifier for channel %s", channel)
   396  			}
   397  			return VerifyBlocks(blocks, verifier)
   398  		},
   399  		MaxTotalBufferBytes: conf.MaxTotalBufferBytes,
   400  		Endpoints:           endpoints,
   401  		RetryTimeout:        RetryTimeout,
   402  		FetchTimeout:        conf.Timeout,
   403  		Channel:             conf.Channel,
   404  		Signer:              conf.Signer,
   405  		StopChannel:         make(chan struct{}),
   406  	}, nil
   407  }
   408  
   409  // NoopBlockVerifier doesn't verify block signatures
   410  type NoopBlockVerifier struct{}
   411  
   412  // VerifyBlockSignature accepts all signatures over blocks.
   413  func (*NoopBlockVerifier) VerifyBlockSignature(sd []*protoutil.SignedData, config *common.ConfigEnvelope) error {
   414  	return nil
   415  }
   416  
   417  //go:generate mockery -dir . -name ChainPuller -case underscore -output mocks/
   418  
   419  // ChainPuller pulls blocks from a chain
   420  type ChainPuller interface {
   421  	// PullBlock pulls the given block from some orderer node
   422  	PullBlock(seq uint64) *common.Block
   423  
   424  	// HeightsByEndpoints returns the block heights by endpoints of orderers
   425  	HeightsByEndpoints() (map[string]uint64, error)
   426  
   427  	// Close closes the ChainPuller
   428  	Close()
   429  }
   430  
   431  // ChainInspector walks over a chain
   432  type ChainInspector struct {
   433  	Logger          *flogging.FabricLogger
   434  	Puller          ChainPuller
   435  	LastConfigBlock *common.Block
   436  }
   437  
   438  // ErrSkipped denotes that replicating a chain was skipped
   439  var ErrSkipped = errors.New("skipped")
   440  
   441  // ErrForbidden denotes that an ordering node refuses sending blocks due to access control.
   442  var ErrForbidden = errors.New("forbidden pulling the channel")
   443  
   444  // ErrServiceUnavailable denotes that an ordering node is not servicing at the moment.
   445  var ErrServiceUnavailable = errors.New("service unavailable")
   446  
   447  // ErrNotInChannel denotes that an ordering node is not in the channel
   448  var ErrNotInChannel = errors.New("not in the channel")
   449  
   450  var ErrRetryCountExhausted = errors.New("retry attempts exhausted")
   451  
   452  // SelfMembershipPredicate determines whether the caller is found in the given config block
   453  type SelfMembershipPredicate func(configBlock *common.Block) error
   454  
   455  // Participant returns whether the caller participates in the chain.
   456  // It receives a ChainPuller that should already be calibrated for the chain,
   457  // and a SelfMembershipPredicate that is used to detect whether the caller should service the chain.
   458  // It returns nil if the caller participates in the chain.
   459  // It may return:
   460  // ErrNotInChannel in case the caller doesn't participate in the chain.
   461  // ErrForbidden in case the caller is forbidden from pulling the block.
   462  // ErrServiceUnavailable in case all orderers reachable cannot complete the request.
   463  // ErrRetryCountExhausted in case no orderer is reachable.
   464  func Participant(puller ChainPuller, analyzeLastConfBlock SelfMembershipPredicate) error {
   465  	lastConfigBlock, err := PullLastConfigBlock(puller)
   466  	if err != nil {
   467  		return err
   468  	}
   469  	return analyzeLastConfBlock(lastConfigBlock)
   470  }
   471  
   472  // PullLastConfigBlock pulls the last configuration block, or returns an error on failure.
   473  func PullLastConfigBlock(puller ChainPuller) (*common.Block, error) {
   474  	endpoint, latestHeight, err := LatestHeightAndEndpoint(puller)
   475  	if err != nil {
   476  		return nil, err
   477  	}
   478  	if endpoint == "" {
   479  		return nil, ErrRetryCountExhausted
   480  	}
   481  	lastBlock := puller.PullBlock(latestHeight - 1)
   482  	if lastBlock == nil {
   483  		return nil, ErrRetryCountExhausted
   484  	}
   485  	lastConfNumber, err := protoutil.GetLastConfigIndexFromBlock(lastBlock)
   486  	if err != nil {
   487  		return nil, err
   488  	}
   489  	// The last config block is smaller than the latest height,
   490  	// and a block iterator on the server side is a sequenced one.
   491  	// So we need to reset the puller if we wish to pull an earlier block.
   492  	puller.Close()
   493  	lastConfigBlock := puller.PullBlock(lastConfNumber)
   494  	if lastConfigBlock == nil {
   495  		return nil, ErrRetryCountExhausted
   496  	}
   497  	return lastConfigBlock, nil
   498  }
   499  
   500  func LatestHeightAndEndpoint(puller ChainPuller) (string, uint64, error) {
   501  	var maxHeight uint64
   502  	var mostUpToDateEndpoint string
   503  	heightsByEndpoints, err := puller.HeightsByEndpoints()
   504  	if err != nil {
   505  		return "", 0, err
   506  	}
   507  	for endpoint, height := range heightsByEndpoints {
   508  		if height >= maxHeight {
   509  			maxHeight = height
   510  			mostUpToDateEndpoint = endpoint
   511  		}
   512  	}
   513  	return mostUpToDateEndpoint, maxHeight, nil
   514  }
   515  
   516  // Close closes the ChainInspector
   517  func (ci *ChainInspector) Close() {
   518  	ci.Puller.Close()
   519  }
   520  
   521  // ChannelGenesisBlock wraps a Block and its channel name
   522  type ChannelGenesisBlock struct {
   523  	ChannelName  string
   524  	GenesisBlock *common.Block
   525  }
   526  
   527  // GenesisBlocks aggregates several ChannelGenesisBlocks
   528  type GenesisBlocks []ChannelGenesisBlock
   529  
   530  // Names returns the channel names all ChannelGenesisBlocks
   531  func (gbs GenesisBlocks) Names() []string {
   532  	var res []string
   533  	for _, gb := range gbs {
   534  		res = append(res, gb.ChannelName)
   535  	}
   536  	return res
   537  }
   538  
   539  // Channels returns the list of ChannelGenesisBlocks
   540  // for all channels. Each such ChannelGenesisBlock contains
   541  // the genesis block of the channel.
   542  func (ci *ChainInspector) Channels() []ChannelGenesisBlock {
   543  	channels := make(map[string]ChannelGenesisBlock)
   544  	lastConfigBlockNum := ci.LastConfigBlock.Header.Number
   545  	var block *common.Block
   546  	var prevHash []byte
   547  	for seq := uint64(0); seq < lastConfigBlockNum; seq++ {
   548  		block = ci.Puller.PullBlock(seq)
   549  		if block == nil {
   550  			ci.Logger.Panicf("Failed pulling block [%d] from the system channel", seq)
   551  		}
   552  		ci.validateHashPointer(block, prevHash)
   553  		// Set the previous hash for the next iteration
   554  		prevHash = protoutil.BlockHeaderHash(block.Header) //lint:ignore SA5011 logs and panics above
   555  
   556  		channel, gb, err := ExtractGenesisBlock(ci.Logger, block)
   557  		if err != nil {
   558  			// If we failed to inspect a block, something is wrong in the system chain
   559  			// we're trying to pull, so abort.
   560  			ci.Logger.Panicf("Failed extracting channel genesis block from config block: %v", err)
   561  		}
   562  
   563  		if channel == "" {
   564  			ci.Logger.Info("Block", seq, "doesn't contain a new channel")
   565  			continue
   566  		}
   567  
   568  		ci.Logger.Info("Block", seq, "contains channel", channel)
   569  		channels[channel] = ChannelGenesisBlock{
   570  			ChannelName:  channel,
   571  			GenesisBlock: gb,
   572  		}
   573  	}
   574  	// At this point, block holds reference to the last block pulled.
   575  	// We ensure that the hash of the last block pulled, is the previous hash
   576  	// of the LastConfigBlock we were initialized with.
   577  	// We don't need to verify the entire chain of all blocks we pulled,
   578  	// because the block puller calls VerifyBlockHash on all blocks it pulls.
   579  	last2Blocks := []*common.Block{block, ci.LastConfigBlock}
   580  	if err := VerifyBlockHash(1, last2Blocks); err != nil {
   581  		ci.Logger.Panic("System channel pulled doesn't match the boot last config block:", err)
   582  	}
   583  
   584  	return flattenChannelMap(channels)
   585  }
   586  
   587  func (ci *ChainInspector) validateHashPointer(block *common.Block, prevHash []byte) {
   588  	if prevHash == nil {
   589  		return
   590  	}
   591  	if bytes.Equal(block.Header.PreviousHash, prevHash) {
   592  		return
   593  	}
   594  	ci.Logger.Panicf("Claimed previous hash of block [%d] is %x but actual previous hash is %x",
   595  		block.Header.Number, block.Header.PreviousHash, prevHash)
   596  }
   597  
   598  func flattenChannelMap(m map[string]ChannelGenesisBlock) []ChannelGenesisBlock {
   599  	var res []ChannelGenesisBlock
   600  	for _, csb := range m {
   601  		res = append(res, csb)
   602  	}
   603  	return res
   604  }
   605  
   606  // ExtractGenesisBlock determines if a config block creates new channel, in which
   607  // case it returns channel name, genesis block and nil error.
   608  func ExtractGenesisBlock(logger *flogging.FabricLogger, block *common.Block) (string, *common.Block, error) {
   609  	if block == nil {
   610  		return "", nil, errors.New("nil block")
   611  	}
   612  	env, err := protoutil.ExtractEnvelope(block, 0)
   613  	if err != nil {
   614  		return "", nil, err
   615  	}
   616  	payload, err := protoutil.UnmarshalPayload(env.Payload)
   617  	if err != nil {
   618  		return "", nil, err
   619  	}
   620  	if payload.Header == nil {
   621  		return "", nil, errors.New("nil header in payload")
   622  	}
   623  	chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   624  	if err != nil {
   625  		return "", nil, err
   626  	}
   627  	// The transaction is not orderer transaction
   628  	if common.HeaderType(chdr.Type) != common.HeaderType_ORDERER_TRANSACTION {
   629  		return "", nil, nil
   630  	}
   631  	systemChannelName := chdr.ChannelId
   632  	innerEnvelope, err := protoutil.UnmarshalEnvelope(payload.Data)
   633  	if err != nil {
   634  		return "", nil, err
   635  	}
   636  	innerPayload, err := protoutil.UnmarshalPayload(innerEnvelope.Payload)
   637  	if err != nil {
   638  		return "", nil, err
   639  	}
   640  	if innerPayload.Header == nil {
   641  		return "", nil, errors.New("inner payload's header is nil")
   642  	}
   643  	chdr, err = protoutil.UnmarshalChannelHeader(innerPayload.Header.ChannelHeader)
   644  	if err != nil {
   645  		return "", nil, err
   646  	}
   647  	// The inner payload's header should be a config transaction
   648  	if common.HeaderType(chdr.Type) != common.HeaderType_CONFIG {
   649  		logger.Warnf("Expecting %s envelope in block, got %s", common.HeaderType_CONFIG, common.HeaderType(chdr.Type))
   650  		return "", nil, nil
   651  	}
   652  	// In any case, exclude all system channel transactions
   653  	if chdr.ChannelId == systemChannelName {
   654  		logger.Warnf("Expecting config envelope in %s block to target a different "+
   655  			"channel other than system channel '%s'", common.HeaderType_ORDERER_TRANSACTION, systemChannelName)
   656  		return "", nil, nil
   657  	}
   658  
   659  	metadata := &common.BlockMetadata{
   660  		Metadata: make([][]byte, 4),
   661  	}
   662  	metadata.Metadata[common.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&common.OrdererBlockMetadata{
   663  		LastConfig: &common.LastConfig{Index: 0},
   664  		// This is a genesis block, peer never verify this signature because we can't bootstrap
   665  		// trust from an earlier block, hence there are no signatures here.
   666  	})
   667  	metadata.Metadata[common.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&common.Metadata{
   668  		Value: protoutil.MarshalOrPanic(&common.LastConfig{Index: 0}),
   669  		// This is a genesis block, peer never verify this signature because we can't bootstrap
   670  		// trust from an earlier block, hence there are no signatures here.
   671  	})
   672  
   673  	blockdata := &common.BlockData{Data: [][]byte{payload.Data}}
   674  	b := &common.Block{
   675  		Header:   &common.BlockHeader{DataHash: protoutil.BlockDataHash(blockdata)},
   676  		Data:     blockdata,
   677  		Metadata: metadata,
   678  	}
   679  	return chdr.ChannelId, b, nil
   680  }