github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/orderer/common/onboarding/onboarding.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package onboarding 8 9 import ( 10 "os" 11 "sync" 12 "time" 13 14 "github.com/hyperledger/fabric-config/protolator" 15 16 "github.com/golang/protobuf/proto" 17 "github.com/hyperledger/fabric-protos-go/common" 18 "github.com/osdi23p228/fabric/bccsp" 19 "github.com/osdi23p228/fabric/common/channelconfig" 20 "github.com/osdi23p228/fabric/common/flogging" 21 "github.com/osdi23p228/fabric/common/ledger/blockledger" 22 "github.com/osdi23p228/fabric/internal/pkg/comm" 23 "github.com/osdi23p228/fabric/internal/pkg/identity" 24 "github.com/osdi23p228/fabric/orderer/common/cluster" 25 "github.com/osdi23p228/fabric/orderer/common/localconfig" 26 "github.com/osdi23p228/fabric/orderer/consensus/etcdraft" 27 "github.com/osdi23p228/fabric/protoutil" 28 "github.com/pkg/errors" 29 ) 30 31 const ( 32 DefaultReplicationBackgroundRefreshInterval = time.Minute * 5 33 replicationBackgroundInitialRefreshInterval = time.Second * 10 34 ) 35 36 var logger = flogging.MustGetLogger("orderer.common.onboarding") 37 38 type ReplicationInitiator struct { 39 RegisterChain func(chain string) 40 ChannelLister cluster.ChannelLister 41 42 verifierRetriever cluster.VerifierRetriever 43 logger *flogging.FabricLogger 44 secOpts comm.SecureOptions 45 conf *localconfig.TopLevel 46 lf cluster.LedgerFactory 47 signer identity.SignerSerializer 48 cryptoProvider bccsp.BCCSP 49 } 50 51 func NewReplicationInitiator( 52 lf blockledger.Factory, 53 bootstrapBlock *common.Block, 54 conf *localconfig.TopLevel, 55 secOpts comm.SecureOptions, 56 signer identity.SignerSerializer, 57 bccsp bccsp.BCCSP, 58 ) *ReplicationInitiator { 59 logger := flogging.MustGetLogger("orderer.common.cluster") 60 61 vl := &verifierLoader{ 62 verifierFactory: &cluster.BlockVerifierAssembler{Logger: logger, BCCSP: bccsp}, 63 onFailure: func(block *common.Block) { 64 protolator.DeepMarshalJSON(os.Stdout, block) 65 }, 66 ledgerFactory: lf, 67 logger: logger, 68 } 69 70 systemChannelName, err := protoutil.GetChannelIDFromBlock(bootstrapBlock) 71 if err != nil { 72 logger.Panicf("Failed extracting system channel name from bootstrap block: %v", err) 73 } 74 75 // System channel is not verified because we trust the bootstrap block 76 // and use backward hash chain verification. 77 verifiersByChannel := vl.loadVerifiers() 78 verifiersByChannel[systemChannelName] = &cluster.NoopBlockVerifier{} 79 80 vr := &cluster.VerificationRegistry{ 81 LoadVerifier: vl.loadVerifier, 82 Logger: logger, 83 VerifiersByChannel: verifiersByChannel, 84 VerifierFactory: &cluster.BlockVerifierAssembler{Logger: logger, BCCSP: bccsp}, 85 } 86 87 ledgerFactory := &ledgerFactory{ 88 Factory: lf, 89 onBlockCommit: vr.BlockCommitted, 90 } 91 return &ReplicationInitiator{ 92 RegisterChain: vr.RegisterVerifier, 93 verifierRetriever: vr, 94 logger: logger, 95 secOpts: secOpts, 96 conf: conf, 97 lf: ledgerFactory, 98 signer: signer, 99 cryptoProvider: bccsp, 100 } 101 } 102 103 func (ri *ReplicationInitiator) ReplicateIfNeeded(bootstrapBlock *common.Block) { 104 if bootstrapBlock.Header.Number == 0 { 105 ri.logger.Debug("Booted with a genesis block, replication isn't an option") 106 return 107 } 108 ri.replicateNeededChannels(bootstrapBlock) 109 } 110 111 func (ri *ReplicationInitiator) createReplicator(bootstrapBlock *common.Block, filter func(string) bool) *cluster.Replicator { 112 consenterCert := &etcdraft.ConsenterCertificate{ 113 Logger: ri.logger, 114 ConsenterCertificate: ri.secOpts.Certificate, 115 CryptoProvider: ri.cryptoProvider, 116 } 117 118 systemChannelName, err := protoutil.GetChannelIDFromBlock(bootstrapBlock) 119 if err != nil { 120 ri.logger.Panicf("Failed extracting system channel name from bootstrap block: %v", err) 121 } 122 pullerConfig := cluster.PullerConfigFromTopLevelConfig(systemChannelName, ri.conf, ri.secOpts.Key, ri.secOpts.Certificate, ri.signer) 123 puller, err := cluster.BlockPullerFromConfigBlock(pullerConfig, bootstrapBlock, ri.verifierRetriever, ri.cryptoProvider) 124 if err != nil { 125 ri.logger.Panicf("Failed creating puller config from bootstrap block: %v", err) 126 } 127 puller.MaxPullBlockRetries = uint64(ri.conf.General.Cluster.ReplicationMaxRetries) 128 puller.RetryTimeout = ri.conf.General.Cluster.ReplicationRetryTimeout 129 130 replicator := &cluster.Replicator{ 131 Filter: filter, 132 LedgerFactory: ri.lf, 133 SystemChannel: systemChannelName, 134 BootBlock: bootstrapBlock, 135 Logger: ri.logger, 136 AmIPartOfChannel: consenterCert.IsConsenterOfChannel, 137 Puller: puller, 138 ChannelLister: &cluster.ChainInspector{ 139 Logger: ri.logger, 140 Puller: puller, 141 LastConfigBlock: bootstrapBlock, 142 }, 143 } 144 145 // If a custom channel lister is requested, use it 146 if ri.ChannelLister != nil { 147 replicator.ChannelLister = ri.ChannelLister 148 } 149 150 return replicator 151 } 152 153 func (ri *ReplicationInitiator) replicateNeededChannels(bootstrapBlock *common.Block) { 154 replicator := ri.createReplicator(bootstrapBlock, cluster.AnyChannel) 155 defer replicator.Puller.Close() 156 replicationNeeded, err := replicator.IsReplicationNeeded() 157 if err != nil { 158 ri.logger.Panicf("Failed determining whether replication is needed: %v", err) 159 } 160 161 if !replicationNeeded { 162 ri.logger.Info("Replication isn't needed") 163 return 164 } 165 166 ri.logger.Info("Will now replicate chains") 167 replicator.ReplicateChains() 168 } 169 170 // ReplicateChains replicates the given chains with the assistance of the given last system channel config block, 171 // and returns the names of the chains that were successfully replicated. 172 func (ri *ReplicationInitiator) ReplicateChains(lastConfigBlock *common.Block, chains []string) []string { 173 ri.logger.Info("Will now replicate chains", chains) 174 wantedChannels := make(map[string]struct{}) 175 for _, chain := range chains { 176 wantedChannels[chain] = struct{}{} 177 } 178 filter := func(channelName string) bool { 179 _, exists := wantedChannels[channelName] 180 return exists 181 } 182 replicator := ri.createReplicator(lastConfigBlock, filter) 183 replicator.DoNotPanicIfClusterNotReachable = true 184 defer replicator.Puller.Close() 185 return replicator.ReplicateChains() 186 } 187 188 type ledgerFactory struct { 189 blockledger.Factory 190 onBlockCommit cluster.BlockCommitFunc 191 } 192 193 func (lf *ledgerFactory) GetOrCreate(chainID string) (cluster.LedgerWriter, error) { 194 ledger, err := lf.Factory.GetOrCreate(chainID) 195 if err != nil { 196 return nil, err 197 } 198 interceptedLedger := &cluster.LedgerInterceptor{ 199 LedgerWriter: ledger, 200 Channel: chainID, 201 InterceptBlockCommit: lf.onBlockCommit, 202 } 203 return interceptedLedger, nil 204 } 205 206 //go:generate mockery -dir . -name ChainReplicator -case underscore -output mocks 207 208 // ChainReplicator replicates chains 209 type ChainReplicator interface { 210 // ReplicateChains replicates the given chains using the given last system channel config block. 211 // It returns the names of the chains that were successfully replicated. 212 ReplicateChains(lastConfigBlock *common.Block, chains []string) []string 213 } 214 215 // InactiveChainReplicator tracks disabled chains and replicates them upon demand 216 type InactiveChainReplicator struct { 217 registerChain func(chain string) 218 logger *flogging.FabricLogger 219 retrieveLastSysChannelConfigBlock func() *common.Block 220 replicator ChainReplicator 221 scheduleChan <-chan time.Time 222 quitChan chan struct{} 223 lock sync.RWMutex 224 chains2CreationCallbacks map[string]chainCreation 225 } 226 227 func NewInactiveChainReplicator( 228 chainReplicator ChainReplicator, 229 getSysChannelConfigBlockFunc func() *common.Block, 230 registerChainFunc func(chain string), 231 replicationRefreshInterval time.Duration, 232 ) *InactiveChainReplicator { 233 if replicationRefreshInterval == 0 { 234 replicationRefreshInterval = DefaultReplicationBackgroundRefreshInterval 235 } 236 exponentialSleep := exponentialDurationSeries(replicationBackgroundInitialRefreshInterval, replicationRefreshInterval) 237 ticker := newTicker(exponentialSleep) 238 239 icr := &InactiveChainReplicator{ 240 logger: logger, 241 scheduleChan: ticker.C, 242 quitChan: make(chan struct{}), 243 replicator: chainReplicator, 244 chains2CreationCallbacks: make(map[string]chainCreation), 245 retrieveLastSysChannelConfigBlock: getSysChannelConfigBlockFunc, 246 registerChain: registerChainFunc, 247 } 248 249 return icr 250 } 251 252 func (dc *InactiveChainReplicator) Channels() []cluster.ChannelGenesisBlock { 253 dc.lock.RLock() 254 defer dc.lock.RUnlock() 255 256 var res []cluster.ChannelGenesisBlock 257 for name, chain := range dc.chains2CreationCallbacks { 258 res = append(res, cluster.ChannelGenesisBlock{ 259 ChannelName: name, 260 GenesisBlock: chain.genesisBlock, 261 }) 262 } 263 return res 264 } 265 266 func (dc *InactiveChainReplicator) Close() {} 267 268 type chainCreation struct { 269 create func() 270 genesisBlock *common.Block 271 } 272 273 // TrackChain tracks a chain with the given name, and calls the given callback 274 // when this chain should be activated. 275 func (dc *InactiveChainReplicator) TrackChain(chain string, genesisBlock *common.Block, createChainCallback func()) { 276 dc.lock.Lock() 277 defer dc.lock.Unlock() 278 279 dc.logger.Infof("Adding %s to the set of chains to track", chain) 280 dc.chains2CreationCallbacks[chain] = chainCreation{ 281 genesisBlock: genesisBlock, 282 create: createChainCallback, 283 } 284 } 285 286 func (dc *InactiveChainReplicator) Run() { 287 for { 288 select { 289 case <-dc.scheduleChan: 290 dc.replicateDisabledChains() 291 case <-dc.quitChan: 292 return 293 } 294 } 295 } 296 297 func (dc *InactiveChainReplicator) replicateDisabledChains() { 298 chains := dc.listInactiveChains() 299 if len(chains) == 0 { 300 dc.logger.Debugf("No inactive chains to try to replicate") 301 return 302 } 303 304 // For each chain, ensure we registered it into the verifier registry, otherwise 305 // we won't be able to verify its blocks. 306 for _, chain := range chains { 307 dc.registerChain(chain) 308 } 309 310 dc.logger.Infof("Found %d inactive chains: %v", len(chains), chains) 311 lastSystemChannelConfigBlock := dc.retrieveLastSysChannelConfigBlock() 312 replicatedChains := dc.replicator.ReplicateChains(lastSystemChannelConfigBlock, chains) 313 dc.logger.Infof("Successfully replicated %d chains: %v", len(replicatedChains), replicatedChains) 314 dc.lock.Lock() 315 defer dc.lock.Unlock() 316 for _, chainName := range replicatedChains { 317 chain := dc.chains2CreationCallbacks[chainName] 318 delete(dc.chains2CreationCallbacks, chainName) 319 chain.create() 320 } 321 } 322 323 func (dc *InactiveChainReplicator) stop() { 324 close(dc.quitChan) 325 } 326 327 func (dc *InactiveChainReplicator) listInactiveChains() []string { 328 dc.lock.RLock() 329 defer dc.lock.RUnlock() 330 var chains []string 331 for chain := range dc.chains2CreationCallbacks { 332 chains = append(chains, chain) 333 } 334 return chains 335 } 336 337 //go:generate mockery -dir . -name Factory -case underscore -output mocks/ 338 339 // Factory retrieves or creates new ledgers by chainID 340 type Factory interface { 341 // GetOrCreate gets an existing ledger (if it exists) 342 // or creates it if it does not 343 GetOrCreate(chainID string) (blockledger.ReadWriter, error) 344 345 // ChannelIDs returns the channel IDs the Factory is aware of 346 ChannelIDs() []string 347 348 // Close releases all resources acquired by the factory 349 Close() 350 } 351 352 type blockGetter struct { 353 ledger blockledger.Reader 354 } 355 356 func (bg *blockGetter) Block(number uint64) *common.Block { 357 return blockledger.GetBlock(bg.ledger, number) 358 } 359 360 type verifierLoader struct { 361 ledgerFactory blockledger.Factory 362 verifierFactory cluster.VerifierFactory 363 logger *flogging.FabricLogger 364 onFailure func(block *common.Block) 365 } 366 367 type verifiersByChannel map[string]cluster.BlockVerifier 368 369 func (vl *verifierLoader) loadVerifiers() verifiersByChannel { 370 res := make(verifiersByChannel) 371 372 for _, channel := range vl.ledgerFactory.ChannelIDs() { 373 v := vl.loadVerifier(channel) 374 if v == nil { 375 continue 376 } 377 res[channel] = v 378 } 379 380 return res 381 } 382 383 func (vl *verifierLoader) loadVerifier(chain string) cluster.BlockVerifier { 384 ledger, err := vl.ledgerFactory.GetOrCreate(chain) 385 if err != nil { 386 vl.logger.Panicf("Failed obtaining ledger for channel %s", chain) 387 } 388 389 blockRetriever := &blockGetter{ledger: ledger} 390 height := ledger.Height() 391 if height == 0 { 392 vl.logger.Errorf("Channel %s has no blocks, skipping it", chain) 393 return nil 394 } 395 lastBlockIndex := height - 1 396 lastBlock := blockRetriever.Block(lastBlockIndex) 397 if lastBlock == nil { 398 vl.logger.Panicf("Failed retrieving block [%d] for channel %s", lastBlockIndex, chain) 399 } 400 401 lastConfigBlock, err := cluster.LastConfigBlock(lastBlock, blockRetriever) 402 if err != nil { 403 vl.logger.Panicf("Failed retrieving config block [%d] for channel %s", lastBlockIndex, chain) 404 } 405 conf, err := cluster.ConfigFromBlock(lastConfigBlock) 406 if err != nil { 407 vl.onFailure(lastConfigBlock) 408 vl.logger.Panicf("Failed extracting configuration for channel %s from block [%d]: %v", 409 chain, lastConfigBlock.Header.Number, err) 410 } 411 412 verifier, err := vl.verifierFactory.VerifierFromConfig(conf, chain) 413 if err != nil { 414 vl.onFailure(lastConfigBlock) 415 vl.logger.Panicf("Failed creating verifier for channel %s from block [%d]: %v", chain, lastBlockIndex, err) 416 } 417 vl.logger.Infof("Loaded verifier for channel %s from config block at index %d", chain, lastBlockIndex) 418 return verifier 419 } 420 421 // ValidateBootstrapBlock returns whether this block can be used as a bootstrap block. 422 // A bootstrap block is a block of a system channel, and needs to have a ConsortiumsConfig. 423 func ValidateBootstrapBlock(block *common.Block, bccsp bccsp.BCCSP) error { 424 if block == nil { 425 return errors.New("nil block") 426 } 427 428 if block.Data == nil || len(block.Data.Data) == 0 { 429 return errors.New("empty block data") 430 } 431 432 firstTransaction := &common.Envelope{} 433 if err := proto.Unmarshal(block.Data.Data[0], firstTransaction); err != nil { 434 return errors.Wrap(err, "failed extracting envelope from block") 435 } 436 437 bundle, err := channelconfig.NewBundleFromEnvelope(firstTransaction, bccsp) 438 if err != nil { 439 return err 440 } 441 442 _, exists := bundle.ConsortiumsConfig() 443 if !exists { 444 return errors.New("the block isn't a system channel block because it lacks ConsortiumsConfig") 445 } 446 return nil 447 }