-
Notifications
You must be signed in to change notification settings - Fork 8.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FAB-17774] support orderer restart without genesis block #1197
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -124,44 +124,49 @@ func Main() { | |
var clusterDialer *cluster.PredicateDialer | ||
var clusterType, reuseGrpcListener bool | ||
var serversToUpdate []*comm.GRPCServer | ||
if conf.General.BootstrapMethod == "file" { | ||
bootstrapMethod := conf.General.BootstrapMethod | ||
if bootstrapMethod == "file" || bootstrapMethod == "none" { | ||
bootstrapBlock := extractBootstrapBlock(conf) | ||
if err := ValidateBootstrapBlock(bootstrapBlock, cryptoProvider); err != nil { | ||
logger.Panicf("Failed validating bootstrap block: %v", err) | ||
if bootstrapBlock == nil { | ||
bootstrapBlock = extractSystemChannel(lf, cryptoProvider) | ||
} | ||
sysChanLastConfigBlock := extractSysChanLastConfig(lf, bootstrapBlock) | ||
clusterBootBlock = selectClusterBootBlock(bootstrapBlock, sysChanLastConfigBlock) | ||
|
||
typ := consensusType(bootstrapBlock, cryptoProvider) | ||
clusterType = isClusterType(clusterBootBlock, cryptoProvider) | ||
if clusterType { | ||
logger.Infof("Setting up cluster for orderer type %s", typ) | ||
clusterClientConfig = initializeClusterClientConfig(conf) | ||
clusterDialer = &cluster.PredicateDialer{ | ||
Config: clusterClientConfig, | ||
if bootstrapBlock != nil { | ||
if err := ValidateBootstrapBlock(bootstrapBlock, cryptoProvider); err != nil { | ||
logger.Panicf("Failed validating bootstrap block: %v", err) | ||
} | ||
sysChanLastConfigBlock := extractSysChanLastConfig(lf, bootstrapBlock) | ||
clusterBootBlock = selectClusterBootBlock(bootstrapBlock, sysChanLastConfigBlock) | ||
|
||
typ := consensusType(bootstrapBlock, cryptoProvider) | ||
clusterType = isClusterType(clusterBootBlock, cryptoProvider) | ||
if clusterType { | ||
logger.Infof("Setting up cluster for orderer type %s", typ) | ||
clusterClientConfig = initializeClusterClientConfig(conf) | ||
clusterDialer = &cluster.PredicateDialer{ | ||
Config: clusterClientConfig, | ||
} | ||
|
||
r = createReplicator(lf, bootstrapBlock, conf, clusterClientConfig.SecOpts, signer, cryptoProvider) | ||
// Only clusters that are equipped with a recent config block can replicate. | ||
if conf.General.BootstrapMethod == "file" { | ||
r.replicateIfNeeded(bootstrapBlock) | ||
} | ||
r = createReplicator(lf, bootstrapBlock, conf, clusterClientConfig.SecOpts, signer, cryptoProvider) | ||
// Only clusters that are equipped with a recent config block can replicate. | ||
if conf.General.BootstrapMethod == "file" { | ||
r.replicateIfNeeded(bootstrapBlock) | ||
} | ||
|
||
if reuseGrpcListener = reuseListener(conf, typ); !reuseGrpcListener { | ||
clusterServerConfig, clusterGRPCServer = configureClusterListener(conf, serverConfig, ioutil.ReadFile) | ||
} | ||
if reuseGrpcListener = reuseListener(conf, typ); !reuseGrpcListener { | ||
clusterServerConfig, clusterGRPCServer = configureClusterListener(conf, serverConfig, ioutil.ReadFile) | ||
} | ||
|
||
// If we have a separate gRPC server for the cluster, | ||
// we need to update its TLS CA certificate pool. | ||
serversToUpdate = append(serversToUpdate, clusterGRPCServer) | ||
} | ||
// Are we bootstrapping? | ||
if len(lf.ChannelIDs()) == 0 { | ||
initializeBootstrapChannel(clusterBootBlock, lf) | ||
} else { | ||
logger.Info("Not bootstrapping because of existing channels") | ||
// If we have a separate gRPC server for the cluster, | ||
// we need to update its TLS CA certificate pool. | ||
serversToUpdate = append(serversToUpdate, clusterGRPCServer) | ||
} | ||
// Are we bootstrapping? | ||
if len(lf.ChannelIDs()) == 0 { | ||
initializeBootstrapChannel(clusterBootBlock, lf) | ||
} else { | ||
logger.Info("Not bootstrapping because of existing channels") | ||
} | ||
} | ||
|
||
} | ||
|
||
identityBytes, err := signer.Serialize() | ||
|
@@ -292,6 +297,25 @@ func extractSysChanLastConfig(lf blockledger.Factory, bootstrapBlock *cb.Block) | |
return lastConfigBlock | ||
} | ||
|
||
// extractSystemChannel loops through all channels, and return the last | ||
// config block for the system channel. Returns nil if no system channel | ||
// was found. | ||
func extractSystemChannel(lf blockledger.Factory, bccsp bccsp.BCCSP) *cb.Block { | ||
for _, cID := range lf.ChannelIDs() { | ||
channelLedger, err := lf.GetOrCreate(cID) | ||
if err != nil { | ||
logger.Panicf("Failed getting channel %v's ledger: %v", cID, err) | ||
} | ||
channelConfigBlock := multichannel.ConfigBlock(channelLedger) | ||
|
||
err = ValidateBootstrapBlock(channelConfigBlock, bccsp) | ||
if err == nil { | ||
return channelConfigBlock | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// Select cluster boot block | ||
func selectClusterBootBlock(bootstrapBlock, sysChanLastConfig *cb.Block) *cb.Block { | ||
if sysChanLastConfig == nil { | ||
|
@@ -703,15 +727,16 @@ func initializeMultichannelRegistrar( | |
bccsp bccsp.BCCSP, | ||
callbacks ...channelconfig.BundleActor, | ||
) *multichannel.Registrar { | ||
|
||
registrar := multichannel.NewRegistrar(*conf, lf, signer, metricsProvider, bccsp, callbacks...) | ||
|
||
consenters := map[string]consensus.Consenter{} | ||
|
||
var icr etcdraft.InactiveChainRegistry | ||
if conf.General.BootstrapMethod == "file" && isClusterType(bootstrapBlock, bccsp) { | ||
etcdConsenter := initializeEtcdraftConsenter(consenters, conf, lf, clusterDialer, bootstrapBlock, ri, srvConf, srv, registrar, metricsProvider, bccsp) | ||
icr = etcdConsenter.InactiveChainRegistry | ||
if conf.General.BootstrapMethod == "file" || conf.General.BootstrapMethod == "none" { | ||
if bootstrapBlock != nil && isClusterType(bootstrapBlock, bccsp) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can the bootstrapBlock be nil here? We don't have the check on the left side, so how can it be nil? Wouldn't we have crashed because we didn't have this check in the past? And let's say bootstrap block is nil, doesn't that mean that you don't initialize the etcdraft? Isn't that a problem? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. bootstrapBlock should not be nil here, however, in test TestInitializeMultichannelRegistrar/"registrar without a system channel", it directly calls initializeMultichannelRegistrar, and passed in bootstrapBlock as nil, and BootstrapMethod as "none". In this case, the test will pass the old code as it will only check cluster type if BootstrapMethod is "file", but not the new code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So why not not pass a nil bootstrap block then? we shouldn't change the production code just to fit tests... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's definitely good point, we should never change production code to just fit tests. However, currently orderer supports an action to startup without system channel defined (FAB-15709), which sets BootstrapMethod to "none" and bootstrapBlock to be nil. And in this PR, we are supporting restarting orderer without providing genesisblock, which was being requested to set BootstrapMethod to "none", and obtain bootstrapBlock from system channel (FAB-17774). Hence, the nil check here is to distinguish the two cases. We can also adding a new bootstrapMethod phrase here, instead of using "none" for both use cases. I'm opening to any suggestions. |
||
etcdConsenter := initializeEtcdraftConsenter(consenters, conf, lf, clusterDialer, bootstrapBlock, ri, srvConf, srv, registrar, metricsProvider, bccsp) | ||
icr = etcdConsenter.InactiveChainRegistry | ||
} | ||
} | ||
|
||
consenters["solo"] = solo.New() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure this is enough... shouldn't we also delete the file?