github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/orderer/common/multichannel/registrar.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 // Package multichannel tracks the channel resources for the orderer. It initially 8 // loads the set of existing channels, and provides an interface for users of these 9 // channels to retrieve them, or create new ones. 10 package multichannel 11 12 import ( 13 "fmt" 14 "sync" 15 16 cb "github.com/hyperledger/fabric-protos-go/common" 17 ab "github.com/hyperledger/fabric-protos-go/orderer" 18 "github.com/osdi23p228/fabric/bccsp" 19 "github.com/osdi23p228/fabric/common/channelconfig" 20 "github.com/osdi23p228/fabric/common/configtx" 21 "github.com/osdi23p228/fabric/common/flogging" 22 "github.com/osdi23p228/fabric/common/ledger/blockledger" 23 "github.com/osdi23p228/fabric/common/metrics" 24 "github.com/osdi23p228/fabric/internal/pkg/identity" 25 "github.com/osdi23p228/fabric/orderer/common/blockcutter" 26 "github.com/osdi23p228/fabric/orderer/common/localconfig" 27 "github.com/osdi23p228/fabric/orderer/common/msgprocessor" 28 "github.com/osdi23p228/fabric/orderer/common/types" 29 "github.com/osdi23p228/fabric/orderer/consensus" 30 "github.com/osdi23p228/fabric/protoutil" 31 "github.com/pkg/errors" 32 ) 33 34 const ( 35 msgVersion = int32(0) 36 epoch = 0 37 ) 38 39 var logger = flogging.MustGetLogger("orderer.commmon.multichannel") 40 41 // checkResources makes sure that the channel config is compatible with this binary and logs sanity checks 42 func checkResources(res channelconfig.Resources) error { 43 channelconfig.LogSanityChecks(res) 44 oc, ok := res.OrdererConfig() 45 if !ok { 46 return errors.New("config does not contain orderer config") 47 } 48 if err := oc.Capabilities().Supported(); err != nil { 49 return errors.Wrapf(err, "config requires unsupported orderer capabilities: %s", err) 50 } 51 if err := res.ChannelConfig().Capabilities().Supported(); err != nil { 52 return errors.Wrapf(err, "config requires unsupported channel capabilities: %s", err) 53 } 54 return nil 55 } 56 57 // checkResourcesOrPanic invokes checkResources and panics if an error is returned 58 func checkResourcesOrPanic(res channelconfig.Resources) { 59 if err := checkResources(res); err != nil { 60 logger.Panicf("[channel %s] %s", res.ConfigtxValidator().ChannelID(), err) 61 } 62 } 63 64 type mutableResources interface { 65 channelconfig.Resources 66 Update(*channelconfig.Bundle) 67 } 68 69 type configResources struct { 70 mutableResources 71 bccsp bccsp.BCCSP 72 } 73 74 func (cr *configResources) CreateBundle(channelID string, config *cb.Config) (*channelconfig.Bundle, error) { 75 return channelconfig.NewBundle(channelID, config, cr.bccsp) 76 } 77 78 func (cr *configResources) Update(bndl *channelconfig.Bundle) { 79 checkResourcesOrPanic(bndl) 80 cr.mutableResources.Update(bndl) 81 } 82 83 func (cr *configResources) SharedConfig() channelconfig.Orderer { 84 oc, ok := cr.OrdererConfig() 85 if !ok { 86 logger.Panicf("[channel %s] has no orderer configuration", cr.ConfigtxValidator().ChannelID()) 87 } 88 return oc 89 } 90 91 type ledgerResources struct { 92 *configResources 93 blockledger.ReadWriter 94 } 95 96 // Registrar serves as a point of access and control for the individual channel resources. 97 type Registrar struct { 98 config localconfig.TopLevel 99 lock sync.RWMutex 100 chains map[string]*ChainSupport 101 102 consenters map[string]consensus.Consenter 103 ledgerFactory blockledger.Factory 104 signer identity.SignerSerializer 105 blockcutterMetrics *blockcutter.Metrics 106 systemChannelID string 107 systemChannel *ChainSupport 108 templator msgprocessor.ChannelConfigTemplator 109 callbacks []channelconfig.BundleActor 110 bccsp bccsp.BCCSP 111 } 112 113 // ConfigBlock retrieves the last configuration block from the given ledger. 114 // Panics on failure. 115 func ConfigBlock(reader blockledger.Reader) *cb.Block { 116 lastBlock := blockledger.GetBlock(reader, reader.Height()-1) 117 index, err := protoutil.GetLastConfigIndexFromBlock(lastBlock) 118 if err != nil { 119 logger.Panicf("Chain did not have appropriately encoded last config in its latest block: %s", err) 120 } 121 configBlock := blockledger.GetBlock(reader, index) 122 if configBlock == nil { 123 logger.Panicf("Config block does not exist") 124 } 125 126 return configBlock 127 } 128 129 func configTx(reader blockledger.Reader) *cb.Envelope { 130 return protoutil.ExtractEnvelopeOrPanic(ConfigBlock(reader), 0) 131 } 132 133 // NewRegistrar produces an instance of a *Registrar. 134 func NewRegistrar( 135 config localconfig.TopLevel, 136 ledgerFactory blockledger.Factory, 137 signer identity.SignerSerializer, 138 metricsProvider metrics.Provider, 139 bccsp bccsp.BCCSP, 140 callbacks ...channelconfig.BundleActor, 141 ) *Registrar { 142 r := &Registrar{ 143 config: config, 144 chains: make(map[string]*ChainSupport), 145 ledgerFactory: ledgerFactory, 146 signer: signer, 147 blockcutterMetrics: blockcutter.NewMetrics(metricsProvider), 148 callbacks: callbacks, 149 bccsp: bccsp, 150 } 151 152 return r 153 } 154 155 func (r *Registrar) Initialize(consenters map[string]consensus.Consenter) { 156 r.consenters = consenters 157 existingChannels := r.ledgerFactory.ChannelIDs() 158 159 for _, channelID := range existingChannels { 160 rl, err := r.ledgerFactory.GetOrCreate(channelID) 161 if err != nil { 162 logger.Panicf("Ledger factory reported channelID %s but could not retrieve it: %s", channelID, err) 163 } 164 configTx := configTx(rl) 165 if configTx == nil { 166 logger.Panic("Programming error, configTx should never be nil here") 167 } 168 ledgerResources, err := r.newLedgerResources(configTx) 169 if err != nil { 170 logger.Panicf("Error creating ledger resources: %s", err) 171 } 172 channelID := ledgerResources.ConfigtxValidator().ChannelID() 173 174 if _, ok := ledgerResources.ConsortiumsConfig(); ok { 175 if r.systemChannelID != "" { 176 logger.Panicf("There appear to be two system channels %s and %s", r.systemChannelID, channelID) 177 } 178 179 chain, err := newChainSupport( 180 r, 181 ledgerResources, 182 r.consenters, 183 r.signer, 184 r.blockcutterMetrics, 185 r.bccsp, 186 ) 187 if err != nil { 188 logger.Panicf("Error creating chain support: %s", err) 189 } 190 r.templator = msgprocessor.NewDefaultTemplator(chain, r.bccsp) 191 chain.Processor = msgprocessor.NewSystemChannel( 192 chain, 193 r.templator, 194 msgprocessor.CreateSystemChannelFilters(r.config, r, chain, chain.MetadataValidator), 195 r.bccsp, 196 ) 197 198 // Retrieve genesis block to log its hash. See FAB-5450 for the purpose 199 iter, pos := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Oldest{Oldest: &ab.SeekOldest{}}}) 200 defer iter.Close() 201 if pos != uint64(0) { 202 logger.Panicf("Error iterating over system channel: '%s', expected position 0, got %d", channelID, pos) 203 } 204 genesisBlock, status := iter.Next() 205 if status != cb.Status_SUCCESS { 206 logger.Panicf("Error reading genesis block of system channel '%s'", channelID) 207 } 208 logger.Infof("Starting system channel '%s' with genesis block hash %x and orderer type %s", 209 channelID, protoutil.BlockHeaderHash(genesisBlock.Header), chain.SharedConfig().ConsensusType()) 210 211 r.chains[channelID] = chain 212 r.systemChannelID = channelID 213 r.systemChannel = chain 214 // We delay starting this channel, as it might try to copy and replace the channels map via newChannel before the map is fully built 215 defer chain.start() 216 } else { 217 logger.Debugf("Starting channel: %s", channelID) 218 chain, err := newChainSupport( 219 r, 220 ledgerResources, 221 r.consenters, 222 r.signer, 223 r.blockcutterMetrics, 224 r.bccsp, 225 ) 226 if err != nil { 227 logger.Panicf("Error creating chain support: %s", err) 228 } 229 r.chains[channelID] = chain 230 chain.start() 231 } 232 } 233 234 if r.systemChannelID == "" { 235 logger.Infof("Registrar initializing without a system channel, number of application channels: %d", len(r.chains)) 236 if _, etcdRaftFound := r.consenters["etcdraft"]; !etcdRaftFound { 237 logger.Panicf("Error initializing without a system channel: failed to find an etcdraft consenter") 238 } 239 } 240 } 241 242 // SystemChannelID returns the ChannelID for the system channel. 243 func (r *Registrar) SystemChannelID() string { 244 r.lock.RLock() 245 defer r.lock.RUnlock() 246 return r.systemChannelID 247 } 248 249 // SystemChannel returns the ChainSupport for the system channel. 250 func (r *Registrar) SystemChannel() *ChainSupport { 251 r.lock.RLock() 252 defer r.lock.RUnlock() 253 return r.systemChannel 254 } 255 256 // BroadcastChannelSupport returns the message channel header, whether the message is a config update 257 // and the channel resources for a message or an error if the message is not a message which can 258 // be processed directly (like CONFIG and ORDERER_TRANSACTION messages) 259 func (r *Registrar) BroadcastChannelSupport(msg *cb.Envelope) (*cb.ChannelHeader, bool, *ChainSupport, error) { 260 chdr, err := protoutil.ChannelHeader(msg) 261 if err != nil { 262 return nil, false, nil, fmt.Errorf("could not determine channel ID: %s", err) 263 } 264 265 cs := r.GetChain(chdr.ChannelId) 266 // New channel creation 267 if cs == nil { 268 sysChan := r.SystemChannel() 269 if sysChan == nil { 270 return nil, false, nil, errors.New("channel creation request not allowed because the orderer system channel is not defined") 271 } 272 cs = sysChan 273 } 274 275 isConfig := false 276 switch cs.ClassifyMsg(chdr) { 277 case msgprocessor.ConfigUpdateMsg: 278 isConfig = true 279 case msgprocessor.ConfigMsg: 280 return chdr, false, nil, errors.New("message is of type that cannot be processed directly") 281 default: 282 } 283 284 return chdr, isConfig, cs, nil 285 } 286 287 // GetChain retrieves the chain support for a chain if it exists. 288 func (r *Registrar) GetChain(chainID string) *ChainSupport { 289 r.lock.RLock() 290 defer r.lock.RUnlock() 291 292 return r.chains[chainID] 293 } 294 295 func (r *Registrar) newLedgerResources(configTx *cb.Envelope) (*ledgerResources, error) { 296 payload, err := protoutil.UnmarshalPayload(configTx.Payload) 297 if err != nil { 298 return nil, errors.Wrap(err, "error umarshaling envelope to payload") 299 } 300 301 if payload.Header == nil { 302 return nil, errors.New("missing channel header") 303 } 304 305 chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader) 306 if err != nil { 307 return nil, errors.Wrapf(err, "error unmarshaling channel header") 308 } 309 310 configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data) 311 if err != nil { 312 return nil, errors.Wrap(err, "error umarshaling config envelope from payload data") 313 } 314 315 bundle, err := channelconfig.NewBundle(chdr.ChannelId, configEnvelope.Config, r.bccsp) 316 if err != nil { 317 return nil, errors.Wrap(err, "error creating channelconfig bundle") 318 } 319 320 err = checkResources(bundle) 321 if err != nil { 322 return nil, errors.Wrapf(err, "error checking bundle for channel: %s", chdr.ChannelId) 323 } 324 325 ledger, err := r.ledgerFactory.GetOrCreate(chdr.ChannelId) 326 if err != nil { 327 return nil, errors.Wrapf(err, "error getting ledger for channel: %s", chdr.ChannelId) 328 } 329 330 return &ledgerResources{ 331 configResources: &configResources{ 332 mutableResources: channelconfig.NewBundleSource(bundle, r.callbacks...), 333 bccsp: r.bccsp, 334 }, 335 ReadWriter: ledger, 336 }, nil 337 } 338 339 // CreateChain makes the Registrar create a chain with the given name. 340 func (r *Registrar) CreateChain(chainName string) { 341 lf, err := r.ledgerFactory.GetOrCreate(chainName) 342 if err != nil { 343 logger.Panicf("Failed obtaining ledger factory for %s: %v", chainName, err) 344 } 345 chain := r.GetChain(chainName) 346 if chain != nil { 347 logger.Infof("A chain of type %T for channel %s already exists. "+ 348 "Halting it.", chain.Chain, chainName) 349 chain.Halt() 350 } 351 r.newChain(configTx(lf)) 352 } 353 354 func (r *Registrar) newChain(configtx *cb.Envelope) { 355 r.lock.Lock() 356 defer r.lock.Unlock() 357 358 ledgerResources, err := r.newLedgerResources(configtx) 359 if err != nil { 360 logger.Panicf("Error creating ledger resources: %s", err) 361 } 362 363 // If we have no blocks, we need to create the genesis block ourselves. 364 if ledgerResources.Height() == 0 { 365 ledgerResources.Append(blockledger.CreateNextBlock(ledgerResources, []*cb.Envelope{configtx})) 366 } 367 cs, err := newChainSupport(r, ledgerResources, r.consenters, r.signer, r.blockcutterMetrics, r.bccsp) 368 if err != nil { 369 logger.Panicf("Error creating chain support: %s", err) 370 } 371 372 chainID := ledgerResources.ConfigtxValidator().ChannelID() 373 r.chains[chainID] = cs 374 375 logger.Infof("Created and starting new channel %s", chainID) 376 cs.start() 377 } 378 379 // ChannelsCount returns the count of the current total number of channels. 380 func (r *Registrar) ChannelsCount() int { 381 r.lock.RLock() 382 defer r.lock.RUnlock() 383 384 return len(r.chains) 385 } 386 387 // NewChannelConfig produces a new template channel configuration based on the system channel's current config. 388 func (r *Registrar) NewChannelConfig(envConfigUpdate *cb.Envelope) (channelconfig.Resources, error) { 389 return r.templator.NewChannelConfig(envConfigUpdate) 390 } 391 392 // CreateBundle calls channelconfig.NewBundle 393 func (r *Registrar) CreateBundle(channelID string, config *cb.Config) (channelconfig.Resources, error) { 394 return channelconfig.NewBundle(channelID, config, r.bccsp) 395 } 396 397 // ChannelList returns a slice of ChannelInfoShort containing all application channels (excluding the system 398 // channel), and ChannelInfoShort of the system channel (nil if does not exist). 399 // The URL fields are empty, and are to be completed by the caller. 400 func (r *Registrar) ChannelList() types.ChannelList { 401 r.lock.RLock() 402 defer r.lock.RUnlock() 403 404 list := types.ChannelList{} 405 406 if len(r.chains) == 0 { 407 return list 408 } 409 410 if r.systemChannelID != "" { 411 list.SystemChannel = &types.ChannelInfoShort{Name: r.systemChannelID} 412 } 413 for name := range r.chains { 414 if name == r.systemChannelID { 415 continue 416 } 417 list.Channels = append(list.Channels, types.ChannelInfoShort{Name: name}) 418 } 419 420 return list 421 } 422 423 func (r *Registrar) ChannelInfo(channelID string) (types.ChannelInfo, error) { 424 r.lock.RLock() 425 defer r.lock.RUnlock() 426 427 info := types.ChannelInfo{} 428 cs, ok := r.chains[channelID] 429 if !ok { 430 return info, types.ErrChannelNotExist 431 } 432 433 info.Name = channelID 434 info.Height = cs.Height() 435 info.ClusterRelation, info.Status = cs.StatusReport() 436 437 return info, nil 438 } 439 440 func (r *Registrar) JoinChannel(channelID string, configBlock *cb.Block, isAppChannel bool) (types.ChannelInfo, error) { 441 r.lock.RLock() 442 defer r.lock.RUnlock() 443 444 if r.systemChannelID != "" { 445 return types.ChannelInfo{}, types.ErrSystemChannelExists 446 } 447 448 _, ok := r.chains[channelID] 449 if ok { 450 return types.ChannelInfo{}, types.ErrChannelAlreadyExists 451 } 452 453 if !isAppChannel && len(r.chains) > 0 { 454 return types.ChannelInfo{}, types.ErrAppChannelsAlreadyExists 455 } 456 457 configEnv, err := protoutil.ExtractEnvelope(configBlock, 0) 458 if err != nil { 459 return types.ChannelInfo{}, errors.Wrap(err, "failed extracting config envelope from block") 460 } 461 462 //TODO save the join-block in the file repo to make this action crash tolerant. 463 464 ledgerResources, err := r.newLedgerResources(configEnv) 465 if err != nil { 466 //TODO remove join block 467 return types.ChannelInfo{}, errors.Wrap(err, "failed creating ledger resources") 468 } 469 470 joinSupport, err := newChainSupportForJoin(configBlock, r, ledgerResources, r.consenters, r.signer, r.blockcutterMetrics, r.bccsp) 471 if err != nil { 472 //TODO remove join block, clean ledger resources 473 return types.ChannelInfo{}, errors.Wrap(err, "failed creating chain support for join") 474 } 475 476 info := types.ChannelInfo{ 477 Name: channelID, 478 URL: "", 479 Height: ledgerResources.Height(), 480 } 481 info.ClusterRelation, info.Status = joinSupport.StatusReport() 482 483 logger.Infof("Joining new channel %s", channelID) 484 485 r.chains[channelID] = joinSupport 486 joinSupport.start() 487 488 return info, nil 489 } 490 491 func (r *Registrar) RemoveChannel(channelID string, removeStorage bool) error { 492 //TODO 493 return errors.New("Not implemented yet") 494 }