github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/orderer/common/multichannel/chainsupport.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package multichannel 8 9 import ( 10 "github.com/hechain20/hechain/bccsp" 11 "github.com/hechain20/hechain/common/ledger/blockledger" 12 "github.com/hechain20/hechain/internal/pkg/identity" 13 "github.com/hechain20/hechain/orderer/common/blockcutter" 14 "github.com/hechain20/hechain/orderer/common/localconfig" 15 "github.com/hechain20/hechain/orderer/common/msgprocessor" 16 "github.com/hechain20/hechain/orderer/common/types" 17 "github.com/hechain20/hechain/orderer/consensus" 18 "github.com/hechain20/hechain/orderer/consensus/inactive" 19 "github.com/hechain20/hechain/protoutil" 20 cb "github.com/hyperledger/fabric-protos-go/common" 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.WithMessagef(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.WithMessagef(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{ConsensusRelation: types.ConsensusRelationOther, Status: types.StatusActive} 100 } 101 102 clusterRelation, status := cs.StatusReporter.StatusReport() 103 registrar.ReportConsensusRelationAndStatusMetrics(cs.ChannelID(), clusterRelation, status) 104 105 logger.Debugf("[channel: %s] Done creating channel support resources", cs.ChannelID()) 106 107 return cs, nil 108 } 109 110 func (cs *ChainSupport) Reader() blockledger.Reader { 111 return cs 112 } 113 114 // Signer returns the SignerSerializer for this channel. 115 func (cs *ChainSupport) Signer() identity.SignerSerializer { 116 return cs 117 } 118 119 func (cs *ChainSupport) start() { 120 cs.Chain.Start() 121 } 122 123 // BlockCutter returns the blockcutter.Receiver instance for this channel. 124 func (cs *ChainSupport) BlockCutter() blockcutter.Receiver { 125 return cs.cutter 126 } 127 128 // Validate passes through to the underlying configtx.Validator 129 func (cs *ChainSupport) Validate(configEnv *cb.ConfigEnvelope) error { 130 return cs.ConfigtxValidator().Validate(configEnv) 131 } 132 133 // ProposeConfigUpdate validates a config update using the underlying configtx.Validator 134 // and the consensus.MetadataValidator. 135 func (cs *ChainSupport) ProposeConfigUpdate(configtx *cb.Envelope) (*cb.ConfigEnvelope, error) { 136 env, err := cs.ConfigtxValidator().ProposeConfigUpdate(configtx) 137 if err != nil { 138 return nil, err 139 } 140 141 bundle, err := cs.CreateBundle(cs.ChannelID(), env.Config) 142 if err != nil { 143 return nil, err 144 } 145 146 if err = checkResources(bundle); err != nil { 147 return nil, errors.WithMessage(err, "config update is not compatible") 148 } 149 150 if err = cs.ValidateNew(bundle); err != nil { 151 return nil, err 152 } 153 154 oldOrdererConfig, ok := cs.OrdererConfig() 155 if !ok { 156 logger.Panic("old config is missing orderer group") 157 } 158 159 // we can remove this check since this is being validated in checkResources earlier 160 newOrdererConfig, ok := bundle.OrdererConfig() 161 if !ok { 162 return nil, errors.New("new config is missing orderer group") 163 } 164 165 if err = cs.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, false); err != nil { 166 return nil, errors.WithMessage(err, "consensus metadata update for channel config update is invalid") 167 } 168 return env, nil 169 } 170 171 // ConfigProto passes through to the underlying configtx.Validator 172 func (cs *ChainSupport) ConfigProto() *cb.Config { 173 return cs.ConfigtxValidator().ConfigProto() 174 } 175 176 // Sequence passes through to the underlying configtx.Validator 177 func (cs *ChainSupport) Sequence() uint64 { 178 return cs.ConfigtxValidator().Sequence() 179 } 180 181 // Append appends a new block to the ledger in its raw form, 182 // unlike WriteBlock that also mutates its metadata. 183 func (cs *ChainSupport) Append(block *cb.Block) error { 184 return cs.ledgerResources.ReadWriter.Append(block) 185 } 186 187 func newOnBoardingChainSupport( 188 ledgerResources *ledgerResources, 189 config localconfig.TopLevel, 190 bccsp bccsp.BCCSP, 191 ) (*ChainSupport, error) { 192 cs := &ChainSupport{ledgerResources: ledgerResources} 193 cs.Processor = msgprocessor.NewStandardChannel(cs, msgprocessor.CreateStandardChannelFilters(cs, config), bccsp) 194 cs.Chain = &inactive.Chain{Err: errors.New("system channel creation pending: server requires restart")} 195 cs.StatusReporter = consensus.StaticStatusReporter{ConsensusRelation: types.ConsensusRelationConsenter, Status: types.StatusInactive} 196 197 logger.Debugf("[channel: %s] Done creating onboarding channel support resources", cs.ChannelID()) 198 199 return cs, nil 200 }