go_study/fabric-main/orderer/common/multichannel/chainsupport.go

184 lines
6.0 KiB
Go

/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package multichannel
import (
cb "github.com/hyperledger/fabric-protos-go/common"
"github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric/common/ledger/blockledger"
"github.com/hyperledger/fabric/internal/pkg/identity"
"github.com/hyperledger/fabric/orderer/common/blockcutter"
"github.com/hyperledger/fabric/orderer/common/msgprocessor"
"github.com/hyperledger/fabric/orderer/common/types"
"github.com/hyperledger/fabric/orderer/consensus"
"github.com/hyperledger/fabric/protoutil"
"github.com/pkg/errors"
)
// ChainSupport holds the resources for a particular channel.
type ChainSupport struct {
*ledgerResources
msgprocessor.Processor
*BlockWriter
consensus.Chain
cutter blockcutter.Receiver
identity.SignerSerializer
BCCSP bccsp.BCCSP
// NOTE: It makes sense to add this to the ChainSupport since the design of Registrar does not assume
// that there is a single consensus type at this orderer node and therefore the resolution of
// the consensus type too happens only at the ChainSupport level.
consensus.MetadataValidator
// The registrar is not aware of the exact type that the Chain is, e.g. etcdraft, inactive, or follower.
// Therefore, we let each chain report its cluster relation and status through this interface. Non cluster
// type chains (solo) are assigned a static reporter.
consensus.StatusReporter
}
func newChainSupport(
registrar *Registrar,
ledgerResources *ledgerResources,
consenters map[string]consensus.Consenter,
signer identity.SignerSerializer,
blockcutterMetrics *blockcutter.Metrics,
bccsp bccsp.BCCSP,
) (*ChainSupport, error) {
// Read in the last block and metadata for the channel
lastBlock := blockledger.GetBlock(ledgerResources, ledgerResources.Height()-1)
metadata, err := protoutil.GetConsenterMetadataFromBlock(lastBlock)
// Assuming a block created with cb.NewBlock(), this should not
// error even if the orderer metadata is an empty byte slice
if err != nil {
return nil, errors.WithMessagef(err, "error extracting orderer metadata for channel: %s", ledgerResources.ConfigtxValidator().ChannelID())
}
// Construct limited support needed as a parameter for additional support
cs := &ChainSupport{
ledgerResources: ledgerResources,
SignerSerializer: signer,
cutter: blockcutter.NewReceiverImpl(
ledgerResources.ConfigtxValidator().ChannelID(),
ledgerResources,
blockcutterMetrics,
),
BCCSP: bccsp,
}
// Set up the msgprocessor
cs.Processor = msgprocessor.NewStandardChannel(cs, msgprocessor.CreateStandardChannelFilters(cs, registrar.config), bccsp)
// Set up the block writer
cs.BlockWriter = newBlockWriter(lastBlock, cs)
// Set up the consenter
consenterType := ledgerResources.SharedConfig().ConsensusType()
consenter, ok := consenters[consenterType]
if !ok {
return nil, errors.Errorf("error retrieving consenter of type: %s", consenterType)
}
cs.Chain, err = consenter.HandleChain(cs, metadata)
if err != nil {
return nil, errors.WithMessagef(err, "error creating consenter for channel: %s", cs.ChannelID())
}
cs.MetadataValidator, ok = cs.Chain.(consensus.MetadataValidator)
if !ok {
cs.MetadataValidator = consensus.NoOpMetadataValidator{}
}
cs.StatusReporter, ok = cs.Chain.(consensus.StatusReporter)
if !ok { // Non-cluster types: solo
cs.StatusReporter = consensus.StaticStatusReporter{ConsensusRelation: types.ConsensusRelationOther, Status: types.StatusActive}
}
clusterRelation, status := cs.StatusReporter.StatusReport()
registrar.ReportConsensusRelationAndStatusMetrics(cs.ChannelID(), clusterRelation, status)
logger.Debugf("[channel: %s] Done creating channel support resources", cs.ChannelID())
return cs, nil
}
func (cs *ChainSupport) Reader() blockledger.Reader {
return cs
}
// Signer returns the SignerSerializer for this channel.
func (cs *ChainSupport) Signer() identity.SignerSerializer {
return cs
}
func (cs *ChainSupport) start() {
cs.Chain.Start()
}
// BlockCutter returns the blockcutter.Receiver instance for this channel.
func (cs *ChainSupport) BlockCutter() blockcutter.Receiver {
return cs.cutter
}
// Validate passes through to the underlying configtx.Validator
func (cs *ChainSupport) Validate(configEnv *cb.ConfigEnvelope) error {
return cs.ConfigtxValidator().Validate(configEnv)
}
// ProposeConfigUpdate validates a config update using the underlying configtx.Validator
// and the consensus.MetadataValidator.
func (cs *ChainSupport) ProposeConfigUpdate(configtx *cb.Envelope) (*cb.ConfigEnvelope, error) {
env, err := cs.ConfigtxValidator().ProposeConfigUpdate(configtx)
if err != nil {
return nil, err
}
bundle, err := cs.CreateBundle(cs.ChannelID(), env.Config)
if err != nil {
return nil, err
}
if err = checkResources(bundle); err != nil {
return nil, errors.WithMessage(err, "config update is not compatible")
}
if err = cs.ValidateNew(bundle); err != nil {
return nil, err
}
oldOrdererConfig, ok := cs.OrdererConfig()
if !ok {
logger.Panic("old config is missing orderer group")
}
// we can remove this check since this is being validated in checkResources earlier
newOrdererConfig, ok := bundle.OrdererConfig()
if !ok {
return nil, errors.New("new config is missing orderer group")
}
if err = cs.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, false); err != nil {
return nil, errors.WithMessage(err, "consensus metadata update for channel config update is invalid")
}
return env, nil
}
// ConfigProto passes through to the underlying configtx.Validator
func (cs *ChainSupport) ConfigProto() *cb.Config {
return cs.ConfigtxValidator().ConfigProto()
}
// Sequence passes through to the underlying configtx.Validator
func (cs *ChainSupport) Sequence() uint64 {
return cs.ConfigtxValidator().Sequence()
}
// Append appends a new block to the ledger in its raw form,
// unlike WriteBlock that also mutates its metadata.
func (cs *ChainSupport) Append(block *cb.Block) error {
return cs.ledgerResources.ReadWriter.Append(block)
}