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 }