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