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

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package multichannel
     8  
     9  import (
    10  	cb "github.com/hyperledger/fabric-protos-go/common"
    11  	"github.com/hyperledger/fabric/bccsp"
    12  	"github.com/hyperledger/fabric/common/channelconfig"
    13  	"github.com/hyperledger/fabric/common/ledger/blockledger"
    14  	"github.com/hyperledger/fabric/common/policies"
    15  	"github.com/hyperledger/fabric/internal/pkg/identity"
    16  	"github.com/hyperledger/fabric/orderer/common/blockcutter"
    17  	"github.com/hyperledger/fabric/orderer/common/msgprocessor"
    18  	"github.com/hyperledger/fabric/orderer/consensus"
    19  	"github.com/hyperledger/fabric/protoutil"
    20  	"github.com/pkg/errors"
    21  )
    22  
    23  // ChainSupport holds the resources for a particular channel.
    24  type ChainSupport struct {
    25  	*ledgerResources
    26  	msgprocessor.Processor
    27  	*BlockWriter
    28  	consensus.Chain
    29  	cutter blockcutter.Receiver
    30  	identity.SignerSerializer
    31  	BCCSP bccsp.BCCSP
    32  
    33  	// NOTE: It makes sense to add this to the ChainSupport since the design of Registrar does not assume
    34  	// that there is a single consensus type at this orderer node and therefore the resolution of
    35  	// the consensus type too happens only at the ChainSupport level.
    36  	consensus.MetadataValidator
    37  }
    38  
    39  func newChainSupport(
    40  	registrar *Registrar,
    41  	ledgerResources *ledgerResources,
    42  	consenters map[string]consensus.Consenter,
    43  	signer identity.SignerSerializer,
    44  	blockcutterMetrics *blockcutter.Metrics,
    45  	bccsp bccsp.BCCSP,
    46  ) *ChainSupport {
    47  	// Read in the last block and metadata for the channel
    48  	lastBlock := blockledger.GetBlock(ledgerResources, ledgerResources.Height()-1)
    49  	metadata, err := protoutil.GetConsenterMetadataFromBlock(lastBlock)
    50  	// Assuming a block created with cb.NewBlock(), this should not
    51  	// error even if the orderer metadata is an empty byte slice
    52  	if err != nil {
    53  		logger.Fatalf("[channel: %s] Error extracting orderer metadata: %s", ledgerResources.ConfigtxValidator().ChannelID(), err)
    54  	}
    55  
    56  	// Construct limited support needed as a parameter for additional support
    57  	cs := &ChainSupport{
    58  		ledgerResources:  ledgerResources,
    59  		SignerSerializer: signer,
    60  		cutter: blockcutter.NewReceiverImpl(
    61  			ledgerResources.ConfigtxValidator().ChannelID(),
    62  			ledgerResources,
    63  			blockcutterMetrics,
    64  		),
    65  		BCCSP: bccsp,
    66  	}
    67  
    68  	// Set up the msgprocessor
    69  	cs.Processor = msgprocessor.NewStandardChannel(cs, msgprocessor.CreateStandardChannelFilters(cs, registrar.config), bccsp)
    70  
    71  	// Set up the block writer
    72  	cs.BlockWriter = newBlockWriter(lastBlock, registrar, cs)
    73  
    74  	// Set up the consenter
    75  	consenterType := ledgerResources.SharedConfig().ConsensusType()
    76  	consenter, ok := consenters[consenterType]
    77  	if !ok {
    78  		logger.Panicf("Error retrieving consenter of type: %s", consenterType)
    79  	}
    80  
    81  	cs.Chain, err = consenter.HandleChain(cs, metadata)
    82  	if err != nil {
    83  		logger.Panicf("[channel: %s] Error creating consenter: %s", cs.ChannelID(), err)
    84  	}
    85  
    86  	cs.MetadataValidator, ok = cs.Chain.(consensus.MetadataValidator)
    87  	if !ok {
    88  		cs.MetadataValidator = consensus.NoOpMetadataValidator{}
    89  	}
    90  
    91  	logger.Debugf("[channel: %s] Done creating channel support resources", cs.ChannelID())
    92  
    93  	return cs
    94  }
    95  
    96  // Block returns a block with the following number,
    97  // or nil if such a block doesn't exist.
    98  func (cs *ChainSupport) Block(number uint64) *cb.Block {
    99  	if cs.Height() <= number {
   100  		return nil
   101  	}
   102  	return blockledger.GetBlock(cs.Reader(), number)
   103  }
   104  
   105  func (cs *ChainSupport) Reader() blockledger.Reader {
   106  	return cs
   107  }
   108  
   109  // Signer returns the SignerSerializer for this channel.
   110  func (cs *ChainSupport) Signer() identity.SignerSerializer {
   111  	return cs
   112  }
   113  
   114  func (cs *ChainSupport) start() {
   115  	cs.Chain.Start()
   116  }
   117  
   118  // BlockCutter returns the blockcutter.Receiver instance for this channel.
   119  func (cs *ChainSupport) BlockCutter() blockcutter.Receiver {
   120  	return cs.cutter
   121  }
   122  
   123  // Validate passes through to the underlying configtx.Validator
   124  func (cs *ChainSupport) Validate(configEnv *cb.ConfigEnvelope) error {
   125  	return cs.ConfigtxValidator().Validate(configEnv)
   126  }
   127  
   128  // ProposeConfigUpdate validates a config update using the underlying configtx.Validator
   129  // and the consensus.MetadataValidator.
   130  func (cs *ChainSupport) ProposeConfigUpdate(configtx *cb.Envelope) (*cb.ConfigEnvelope, error) {
   131  	env, err := cs.ConfigtxValidator().ProposeConfigUpdate(configtx)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  
   136  	bundle, err := cs.CreateBundle(cs.ChannelID(), env.Config)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  
   141  	if err = checkResources(bundle); err != nil {
   142  		return nil, errors.Wrap(err, "config update is not compatible")
   143  	}
   144  
   145  	if err = cs.ValidateNew(bundle); err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	oldOrdererConfig, ok := cs.OrdererConfig()
   150  	if !ok {
   151  		logger.Panic("old config is missing orderer group")
   152  	}
   153  	oldMetadata := oldOrdererConfig.ConsensusMetadata()
   154  
   155  	// we can remove this check since this is being validated in checkResources earlier
   156  	newOrdererConfig, ok := bundle.OrdererConfig()
   157  	if !ok {
   158  		return nil, errors.New("new config is missing orderer group")
   159  	}
   160  	newMetadata := newOrdererConfig.ConsensusMetadata()
   161  
   162  	if err = cs.ValidateConsensusMetadata(oldMetadata, newMetadata, false); err != nil {
   163  		return nil, errors.Wrap(err, "consensus metadata update for channel config update is invalid")
   164  	}
   165  	return env, nil
   166  }
   167  
   168  // ChannelID passes through to the underlying configtx.Validator
   169  func (cs *ChainSupport) ChannelID() string {
   170  	return cs.ConfigtxValidator().ChannelID()
   171  }
   172  
   173  // ConfigProto passes through to the underlying configtx.Validator
   174  func (cs *ChainSupport) ConfigProto() *cb.Config {
   175  	return cs.ConfigtxValidator().ConfigProto()
   176  }
   177  
   178  // Sequence passes through to the underlying configtx.Validator
   179  func (cs *ChainSupport) Sequence() uint64 {
   180  	return cs.ConfigtxValidator().Sequence()
   181  }
   182  
   183  // Append appends a new block to the ledger in its raw form,
   184  // unlike WriteBlock that also mutates its metadata.
   185  func (cs *ChainSupport) Append(block *cb.Block) error {
   186  	return cs.ledgerResources.ReadWriter.Append(block)
   187  }
   188  
   189  // VerifyBlockSignature verifies a signature of a block.
   190  // It has an optional argument of a configuration envelope
   191  // which would make the block verification to use validation rules
   192  // based on the given configuration in the ConfigEnvelope.
   193  // If the config envelope passed is nil, then the validation rules used
   194  // are the ones that were applied at commit of previous blocks.
   195  func (cs *ChainSupport) VerifyBlockSignature(sd []*protoutil.SignedData, envelope *cb.ConfigEnvelope) error {
   196  	policyMgr := cs.PolicyManager()
   197  	// If the envelope passed isn't nil, we should use a different policy manager.
   198  	if envelope != nil {
   199  		bundle, err := channelconfig.NewBundle(cs.ChannelID(), envelope.Config, cs.BCCSP)
   200  		if err != nil {
   201  			return err
   202  		}
   203  		policyMgr = bundle.PolicyManager()
   204  	}
   205  	policy, exists := policyMgr.GetPolicy(policies.BlockValidation)
   206  	if !exists {
   207  		return errors.Errorf("policy %s wasn't found", policies.BlockValidation)
   208  	}
   209  	err := policy.EvaluateSignedData(sd)
   210  	if err != nil {
   211  		return errors.Wrap(err, "block verification failed")
   212  	}
   213  	return nil
   214  }