github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/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/osdi23p228/fabric/bccsp"
    12  	"github.com/osdi23p228/fabric/common/channelconfig"
    13  	"github.com/osdi23p228/fabric/common/ledger/blockledger"
    14  	"github.com/osdi23p228/fabric/common/policies"
    15  	"github.com/osdi23p228/fabric/internal/pkg/identity"
    16  	"github.com/osdi23p228/fabric/orderer/common/blockcutter"
    17  	"github.com/osdi23p228/fabric/orderer/common/msgprocessor"
    18  	"github.com/osdi23p228/fabric/orderer/common/types"
    19  	"github.com/osdi23p228/fabric/orderer/consensus"
    20  	"github.com/osdi23p228/fabric/protoutil"
    21  	"github.com/pkg/errors"
    22  )
    23  
    24  // ChainSupport holds the resources for a particular channel.
    25  type ChainSupport struct {
    26  	*ledgerResources
    27  	msgprocessor.Processor
    28  	*BlockWriter
    29  	consensus.Chain
    30  	cutter blockcutter.Receiver
    31  	identity.SignerSerializer
    32  	BCCSP bccsp.BCCSP
    33  
    34  	// NOTE: It makes sense to add this to the ChainSupport since the design of Registrar does not assume
    35  	// that there is a single consensus type at this orderer node and therefore the resolution of
    36  	// the consensus type too happens only at the ChainSupport level.
    37  	consensus.MetadataValidator
    38  
    39  	// The registrar is not aware of the exact type that the Chain is, e.g. etcdraft, inactive, or follower.
    40  	// Therefore, we let each chain report its cluster relation and status through this interface. Non cluster
    41  	// type chains (solo, kafka) are assigned a static reporter.
    42  	consensus.StatusReporter
    43  }
    44  
    45  func newChainSupport(
    46  	registrar *Registrar,
    47  	ledgerResources *ledgerResources,
    48  	consenters map[string]consensus.Consenter,
    49  	signer identity.SignerSerializer,
    50  	blockcutterMetrics *blockcutter.Metrics,
    51  	bccsp bccsp.BCCSP,
    52  ) (*ChainSupport, error) {
    53  	// Read in the last block and metadata for the channel
    54  	lastBlock := blockledger.GetBlock(ledgerResources, ledgerResources.Height()-1)
    55  	metadata, err := protoutil.GetConsenterMetadataFromBlock(lastBlock)
    56  	// Assuming a block created with cb.NewBlock(), this should not
    57  	// error even if the orderer metadata is an empty byte slice
    58  	if err != nil {
    59  		return nil, errors.Wrapf(err, "error extracting orderer metadata for channel: %s", ledgerResources.ConfigtxValidator().ChannelID())
    60  	}
    61  
    62  	// Construct limited support needed as a parameter for additional support
    63  	cs := &ChainSupport{
    64  		ledgerResources:  ledgerResources,
    65  		SignerSerializer: signer,
    66  		cutter: blockcutter.NewReceiverImpl(
    67  			ledgerResources.ConfigtxValidator().ChannelID(),
    68  			ledgerResources,
    69  			blockcutterMetrics,
    70  		),
    71  		BCCSP: bccsp,
    72  	}
    73  
    74  	// Set up the msgprocessor
    75  	cs.Processor = msgprocessor.NewStandardChannel(cs, msgprocessor.CreateStandardChannelFilters(cs, registrar.config), bccsp)
    76  
    77  	// Set up the block writer
    78  	cs.BlockWriter = newBlockWriter(lastBlock, registrar, cs)
    79  
    80  	// Set up the consenter
    81  	consenterType := ledgerResources.SharedConfig().ConsensusType()
    82  	consenter, ok := consenters[consenterType]
    83  	if !ok {
    84  		return nil, errors.Errorf("error retrieving consenter of type: %s", consenterType)
    85  	}
    86  
    87  	cs.Chain, err = consenter.HandleChain(cs, metadata)
    88  	if err != nil {
    89  		return nil, errors.Wrapf(err, "error creating consenter for channel: %s", cs.ChannelID())
    90  	}
    91  
    92  	cs.MetadataValidator, ok = cs.Chain.(consensus.MetadataValidator)
    93  	if !ok {
    94  		cs.MetadataValidator = consensus.NoOpMetadataValidator{}
    95  	}
    96  
    97  	cs.StatusReporter, ok = cs.Chain.(consensus.StatusReporter)
    98  	if !ok { // Non-cluster types: solo, kafka
    99  		cs.StatusReporter = consensus.StaticStatusReporter{ClusterRelation: types.ClusterRelationNone, Status: types.StatusActive}
   100  	}
   101  
   102  	logger.Debugf("[channel: %s] Done creating channel support resources", cs.ChannelID())
   103  
   104  	return cs, nil
   105  }
   106  
   107  func newChainSupportForJoin(
   108  	joinBlock *cb.Block,
   109  	registrar *Registrar,
   110  	ledgerResources *ledgerResources,
   111  	consenters map[string]consensus.Consenter,
   112  	signer identity.SignerSerializer,
   113  	blockcutterMetrics *blockcutter.Metrics,
   114  	bccsp bccsp.BCCSP,
   115  ) (*ChainSupport, error) {
   116  
   117  	if joinBlock.Header.Number == 0 {
   118  		err := ledgerResources.Append(joinBlock)
   119  		if err != nil {
   120  			return nil, errors.Wrap(err, "error appending join block to the ledger")
   121  		}
   122  		return newChainSupport(registrar, ledgerResources, consenters, signer, blockcutterMetrics, bccsp)
   123  	}
   124  
   125  	// Construct limited support needed as a parameter for additional support
   126  	cs := &ChainSupport{
   127  		ledgerResources:  ledgerResources,
   128  		SignerSerializer: signer,
   129  		cutter: blockcutter.NewReceiverImpl(
   130  			ledgerResources.ConfigtxValidator().ChannelID(),
   131  			ledgerResources,
   132  			blockcutterMetrics,
   133  		),
   134  		BCCSP: bccsp,
   135  	}
   136  
   137  	// Set up the msgprocessor
   138  	cs.Processor = msgprocessor.NewStandardChannel(cs, msgprocessor.CreateStandardChannelFilters(cs, registrar.config), bccsp)
   139  	// No BlockWriter, this will be created when the chain gets converted from follower.Chain to etcdraft.Chain
   140  	cs.BlockWriter = nil //TODO change embedding of BlockWriter struct to interface, and put here a NoOp implementation or one that panics if used
   141  
   142  	// Get the consenter
   143  	consenterType := ledgerResources.SharedConfig().ConsensusType()
   144  	consenter, ok := consenters[consenterType]
   145  	if !ok {
   146  		return nil, errors.Errorf("error retrieving consenter of type: %s", consenterType)
   147  	}
   148  
   149  	var err error
   150  	cs.Chain, err = consenter.JoinChain(cs, joinBlock)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  
   155  	cs.MetadataValidator, ok = cs.Chain.(consensus.MetadataValidator)
   156  	if !ok {
   157  		cs.MetadataValidator = consensus.NoOpMetadataValidator{}
   158  	}
   159  
   160  	cs.StatusReporter, ok = cs.Chain.(consensus.StatusReporter)
   161  	if !ok { // Non-cluster types: solo, kafka
   162  		cs.StatusReporter = consensus.StaticStatusReporter{ClusterRelation: types.ClusterRelationNone, Status: types.StatusActive}
   163  	}
   164  
   165  	logger.Debugf("[channel: %s] Done creating channel support resources for join", cs.ChannelID())
   166  
   167  	return cs, nil
   168  }
   169  
   170  // Block returns a block with the following number,
   171  // or nil if such a block doesn't exist.
   172  func (cs *ChainSupport) Block(number uint64) *cb.Block {
   173  	if cs.Height() <= number {
   174  		return nil
   175  	}
   176  	return blockledger.GetBlock(cs.Reader(), number)
   177  }
   178  
   179  func (cs *ChainSupport) Reader() blockledger.Reader {
   180  	return cs
   181  }
   182  
   183  // Signer returns the SignerSerializer for this channel.
   184  func (cs *ChainSupport) Signer() identity.SignerSerializer {
   185  	return cs
   186  }
   187  
   188  func (cs *ChainSupport) start() {
   189  	cs.Chain.Start()
   190  }
   191  
   192  // BlockCutter returns the blockcutter.Receiver instance for this channel.
   193  func (cs *ChainSupport) BlockCutter() blockcutter.Receiver {
   194  	return cs.cutter
   195  }
   196  
   197  // Validate passes through to the underlying configtx.Validator
   198  func (cs *ChainSupport) Validate(configEnv *cb.ConfigEnvelope) error {
   199  	return cs.ConfigtxValidator().Validate(configEnv)
   200  }
   201  
   202  // ProposeConfigUpdate validates a config update using the underlying configtx.Validator
   203  // and the consensus.MetadataValidator.
   204  func (cs *ChainSupport) ProposeConfigUpdate(configtx *cb.Envelope) (*cb.ConfigEnvelope, error) {
   205  	env, err := cs.ConfigtxValidator().ProposeConfigUpdate(configtx)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  
   210  	bundle, err := cs.CreateBundle(cs.ChannelID(), env.Config)
   211  	if err != nil {
   212  		return nil, err
   213  	}
   214  
   215  	if err = checkResources(bundle); err != nil {
   216  		return nil, errors.Wrap(err, "config update is not compatible")
   217  	}
   218  
   219  	if err = cs.ValidateNew(bundle); err != nil {
   220  		return nil, err
   221  	}
   222  
   223  	oldOrdererConfig, ok := cs.OrdererConfig()
   224  	if !ok {
   225  		logger.Panic("old config is missing orderer group")
   226  	}
   227  
   228  	// we can remove this check since this is being validated in checkResources earlier
   229  	newOrdererConfig, ok := bundle.OrdererConfig()
   230  	if !ok {
   231  		return nil, errors.New("new config is missing orderer group")
   232  	}
   233  
   234  	if err = cs.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, false); err != nil {
   235  		return nil, errors.Wrap(err, "consensus metadata update for channel config update is invalid")
   236  	}
   237  	return env, nil
   238  }
   239  
   240  // ChannelID passes through to the underlying configtx.Validator
   241  func (cs *ChainSupport) ChannelID() string {
   242  	return cs.ConfigtxValidator().ChannelID()
   243  }
   244  
   245  // ConfigProto passes through to the underlying configtx.Validator
   246  func (cs *ChainSupport) ConfigProto() *cb.Config {
   247  	return cs.ConfigtxValidator().ConfigProto()
   248  }
   249  
   250  // Sequence passes through to the underlying configtx.Validator
   251  func (cs *ChainSupport) Sequence() uint64 {
   252  	return cs.ConfigtxValidator().Sequence()
   253  }
   254  
   255  // Append appends a new block to the ledger in its raw form,
   256  // unlike WriteBlock that also mutates its metadata.
   257  func (cs *ChainSupport) Append(block *cb.Block) error {
   258  	return cs.ledgerResources.ReadWriter.Append(block)
   259  }
   260  
   261  // VerifyBlockSignature verifies a signature of a block.
   262  // It has an optional argument of a configuration envelope
   263  // which would make the block verification to use validation rules
   264  // based on the given configuration in the ConfigEnvelope.
   265  // If the config envelope passed is nil, then the validation rules used
   266  // are the ones that were applied at commit of previous blocks.
   267  func (cs *ChainSupport) VerifyBlockSignature(sd []*protoutil.SignedData, envelope *cb.ConfigEnvelope) error {
   268  	policyMgr := cs.PolicyManager()
   269  	// If the envelope passed isn't nil, we should use a different policy manager.
   270  	if envelope != nil {
   271  		bundle, err := channelconfig.NewBundle(cs.ChannelID(), envelope.Config, cs.BCCSP)
   272  		if err != nil {
   273  			return err
   274  		}
   275  		policyMgr = bundle.PolicyManager()
   276  	}
   277  	policy, exists := policyMgr.GetPolicy(policies.BlockValidation)
   278  	if !exists {
   279  		return errors.Errorf("policy %s wasn't found", policies.BlockValidation)
   280  	}
   281  	err := policy.EvaluateSignedData(sd)
   282  	if err != nil {
   283  		return errors.Wrap(err, "block verification failed")
   284  	}
   285  	return nil
   286  }