Skip to content

Commit 445fd06

Browse files
sykesmGerrit Code Review
authored and
Gerrit Code Review
committed
Merge "Allow orderer startup with no system channel defined"
2 parents 028d9fb + 727850f commit 445fd06

File tree

5 files changed

+169
-73
lines changed

5 files changed

+169
-73
lines changed

integration/e2e/e2e_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,49 @@ var _ = Describe("EndToEnd", func() {
311311
nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, network.Peer("Org1", "peer0"), network.Peer("Org2", "peer0"))
312312
})
313313
})
314+
315+
Describe("basic solo network without a system channel", func() {
316+
var ordererProcess ifrit.Process
317+
BeforeEach(func() {
318+
soloConfig := nwo.BasicSolo()
319+
soloConfig.RemovePeer("Org1", "peer1")
320+
soloConfig.RemovePeer("Org2", "peer1")
321+
network = nwo.New(soloConfig, testDir, client, StartPort(), components)
322+
network.GenerateConfigTree()
323+
324+
orderer := network.Orderer("orderer")
325+
ordererConfig := network.ReadOrdererConfig(orderer)
326+
ordererConfig.General.GenesisMethod = "none"
327+
network.WriteOrdererConfig(orderer, ordererConfig)
328+
network.Bootstrap()
329+
330+
ordererRunner := network.OrdererRunner(orderer)
331+
ordererProcess = ifrit.Invoke(ordererRunner)
332+
Eventually(ordererProcess.Ready, network.EventuallyTimeout).Should(BeClosed())
333+
Eventually(ordererRunner.Err(), network.EventuallyTimeout).Should(gbytes.Say("registrar initializing with no system channel"))
334+
})
335+
336+
AfterEach(func() {
337+
if ordererProcess != nil {
338+
ordererProcess.Signal(syscall.SIGTERM)
339+
Eventually(ordererProcess.Wait(), network.EventuallyTimeout).Should(Receive())
340+
}
341+
})
342+
343+
It("starts the orderer but rejects channel creation requests", func() {
344+
By("attempting to create a channel without a system channel defined")
345+
sess, err := network.PeerAdminSession(network.Peer("Org1", "peer0"), commands.ChannelCreate{
346+
ChannelID: "testchannel",
347+
Orderer: network.OrdererAddress(network.Orderer("orderer"), nwo.ListenPort),
348+
File: network.CreateChannelTxPath("testchannel"),
349+
OutputBlock: "/dev/null",
350+
ClientAuth: network.ClientAuthRequired,
351+
})
352+
Expect(err).NotTo(HaveOccurred())
353+
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1))
354+
Eventually(sess.Err, network.EventuallyTimeout).Should(gbytes.Say("channel creation request not allowed because the orderer system channel is not yet defined"))
355+
})
356+
})
314357
})
315358

316359
func RunQueryInvokeQuery(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer, channel string) {

orderer/common/multichannel/registrar.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ func (r *Registrar) Initialize(consenters map[string]consensus.Consenter) {
223223
}
224224

225225
if r.systemChannelID == "" {
226-
logger.Panicf("No system chain found. If bootstrapping, does your system channel contain a consortiums group definition?")
226+
logger.Info("registrar initializing with no system channel")
227227
}
228228
}
229229

@@ -244,6 +244,9 @@ func (r *Registrar) BroadcastChannelSupport(msg *cb.Envelope) (*cb.ChannelHeader
244244
cs := r.GetChain(chdr.ChannelId)
245245
// New channel creation
246246
if cs == nil {
247+
if r.systemChannel == nil {
248+
return nil, false, nil, errors.New("channel creation request not allowed because the orderer system channel is not yet defined")
249+
}
247250
cs = r.systemChannel
248251
}
249252

orderer/common/multichannel/registrar_test.go

+28-7
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,12 @@ func newLedgerAndFactory(dir string, chainID string, genesisBlockSys *cb.Block)
8484
if err != nil {
8585
panic(err)
8686
}
87-
err = rl.Append(genesisBlockSys)
88-
if err != nil {
89-
panic(err)
87+
88+
if genesisBlockSys != nil {
89+
err = rl.Append(genesisBlockSys)
90+
if err != nil {
91+
panic(err)
92+
}
9093
}
9194
return rlf, rl
9295
}
@@ -157,9 +160,9 @@ func TestNewRegistrar(t *testing.T) {
157160
consenters := make(map[string]consensus.Consenter)
158161
consenters[confSys.Orderer.OrdererType] = &mockConsenter{}
159162

160-
assert.Panics(t, func() {
163+
assert.NotPanics(t, func() {
161164
NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider).Initialize(consenters)
162-
}, "Should have panicked when starting without a system chain")
165+
}, "Should not panic when starting without a system channel")
163166
})
164167

165168
// This test checks to make sure that the orderer refuses to come up if there are multiple system channels
@@ -421,8 +424,8 @@ func TestResourcesCheck(t *testing.T) {
421424
}
422425

423426
// The registrar's BroadcastChannelSupport implementation should reject message types which should not be processed directly.
424-
func TestBroadcastChannelSupportRejection(t *testing.T) {
425-
//system channel
427+
func TestBroadcastChannelSupport(t *testing.T) {
428+
// system channel
426429
confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
427430
genesisBlockSys := encoder.New(confSys).GenesisBlock()
428431

@@ -443,4 +446,22 @@ func TestBroadcastChannelSupportRejection(t *testing.T) {
443446
_, _, _, err = registrar.BroadcastChannelSupport(configTx)
444447
assert.Error(t, err, "Messages of type HeaderType_CONFIG should return an error.")
445448
})
449+
450+
t.Run("No system channel", func(t *testing.T) {
451+
tmpdir, err := ioutil.TempDir("", "registrar_test-")
452+
require.NoError(t, err)
453+
defer os.RemoveAll(tmpdir)
454+
455+
ledgerFactory, _ := newLedgerAndFactory(tmpdir, "", nil)
456+
mockConsenters := map[string]consensus.Consenter{confSys.Orderer.OrdererType: &mockConsenter{}}
457+
config := localconfig.TopLevel{}
458+
config.General.GenesisMethod = "none"
459+
config.General.GenesisFile = ""
460+
registrar := NewRegistrar(config, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider)
461+
registrar.Initialize(mockConsenters)
462+
configTx := makeConfigTxFull("testchannelid", 1)
463+
_, _, _, err = registrar.BroadcastChannelSupport(configTx)
464+
assert.Error(t, err)
465+
assert.Equal(t, "channel creation request not allowed because the orderer system channel is not yet defined", err.Error())
466+
})
446467
}

orderer/common/server/main.go

+48-48
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,11 @@ func Main() {
8686

8787
prettyPrintStruct(conf)
8888

89-
bootstrapBlock := extractBootstrapBlock(conf)
90-
9189
cryptoProvider := factory.GetDefault()
9290

93-
if err := ValidateBootstrapBlock(bootstrapBlock, cryptoProvider); err != nil {
94-
logger.Panicf("Failed validating bootstrap block: %v", err)
91+
signer, signErr := loadLocalMSP(conf).GetDefaultSigningIdentity()
92+
if signErr != nil {
93+
logger.Panicf("Failed to get local MSP identity: %s", signErr)
9594
}
9695

9796
opsSystem := newOperationsSystem(conf.Operations, conf.Metrics)
@@ -100,19 +99,6 @@ func Main() {
10099
}
101100
defer opsSystem.Stop()
102101
metricsProvider := opsSystem.Provider
103-
104-
lf, _, err := createLedgerFactory(conf, metricsProvider)
105-
if err != nil {
106-
logger.Panicf("Failed in creating ledger factory: %v", err)
107-
}
108-
sysChanLastConfigBlock := extractSysChanLastConfig(lf, bootstrapBlock)
109-
clusterBootBlock := selectClusterBootBlock(bootstrapBlock, sysChanLastConfigBlock)
110-
111-
signer, signErr := loadLocalMSP(conf).GetDefaultSigningIdentity()
112-
if signErr != nil {
113-
logger.Panicf("Failed to get local MSP identity: %s", signErr)
114-
}
115-
116102
logObserver := floggingmetrics.NewObserver(metricsProvider)
117103
flogging.SetObserver(logObserver)
118104

@@ -124,38 +110,58 @@ func Main() {
124110
clientRootCAs: serverConfig.SecOpts.ClientRootCAs,
125111
}
126112

113+
lf, _, err := createLedgerFactory(conf, metricsProvider)
114+
if err != nil {
115+
logger.Panicf("Failed to create ledger factory: %v", err)
116+
}
117+
118+
var clusterBootBlock *cb.Block
127119
// configure following artifacts properly if orderer is of cluster type
128120
var r *replicationInitiator
129121
clusterServerConfig := serverConfig
130122
clusterGRPCServer := grpcServer // by default, cluster shares the same grpc server
131123
var clusterClientConfig comm.ClientConfig
132124
var clusterDialer *cluster.PredicateDialer
133-
134-
var reuseGrpcListener bool
135-
typ := consensusType(bootstrapBlock, cryptoProvider)
125+
var clusterType, reuseGrpcListener bool
136126
var serversToUpdate []*comm.GRPCServer
137-
138-
clusterType := isClusterType(clusterBootBlock, cryptoProvider)
139-
if clusterType {
140-
logger.Infof("Setting up cluster for orderer type %s", typ)
141-
clusterClientConfig = initializeClusterClientConfig(conf)
142-
clusterDialer = &cluster.PredicateDialer{
143-
Config: clusterClientConfig,
127+
if conf.General.GenesisMethod == "file" {
128+
bootstrapBlock := extractBootstrapBlock(conf)
129+
if err := ValidateBootstrapBlock(bootstrapBlock, cryptoProvider); err != nil {
130+
logger.Panicf("Failed validating bootstrap block: %v", err)
144131
}
132+
sysChanLastConfigBlock := extractSysChanLastConfig(lf, bootstrapBlock)
133+
clusterBootBlock = selectClusterBootBlock(bootstrapBlock, sysChanLastConfigBlock)
145134

146-
r = createReplicator(lf, bootstrapBlock, conf, clusterClientConfig.SecOpts, signer, cryptoProvider)
147-
// Only clusters that are equipped with a recent config block can replicate.
148-
if conf.General.GenesisMethod == "file" {
149-
r.replicateIfNeeded(bootstrapBlock)
150-
}
135+
typ := consensusType(bootstrapBlock, cryptoProvider)
136+
clusterType = isClusterType(clusterBootBlock, cryptoProvider)
137+
if clusterType {
138+
logger.Infof("Setting up cluster for orderer type %s", typ)
139+
clusterClientConfig = initializeClusterClientConfig(conf)
140+
clusterDialer = &cluster.PredicateDialer{
141+
Config: clusterClientConfig,
142+
}
143+
144+
r = createReplicator(lf, bootstrapBlock, conf, clusterClientConfig.SecOpts, signer, cryptoProvider)
145+
// Only clusters that are equipped with a recent config block can replicate.
146+
if conf.General.GenesisMethod == "file" {
147+
r.replicateIfNeeded(bootstrapBlock)
148+
}
151149

152-
if reuseGrpcListener = reuseListener(conf, typ); !reuseGrpcListener {
153-
clusterServerConfig, clusterGRPCServer = configureClusterListener(conf, serverConfig, ioutil.ReadFile)
150+
if reuseGrpcListener = reuseListener(conf, typ); !reuseGrpcListener {
151+
clusterServerConfig, clusterGRPCServer = configureClusterListener(conf, serverConfig, ioutil.ReadFile)
152+
}
153+
154+
// If we have a separate gRPC server for the cluster,
155+
// we need to update its TLS CA certificate pool.
156+
serversToUpdate = append(serversToUpdate, clusterGRPCServer)
157+
}
158+
// Are we bootstrapping?
159+
if len(lf.ChannelIDs()) == 0 {
160+
initializeBootstrapChannel(clusterBootBlock, lf)
161+
} else {
162+
logger.Info("Not bootstrapping because of existing channels")
154163
}
155164

156-
// If we have a separate gRPC server for the cluster,
157-
// we need to update its TLS CA certificate pool.
158-
serversToUpdate = append(serversToUpdate, clusterGRPCServer)
159165
}
160166

161167
identityBytes, err := signer.Serialize()
@@ -697,25 +703,19 @@ func initializeMultichannelRegistrar(
697703
bccsp bccsp.BCCSP,
698704
callbacks ...channelconfig.BundleActor,
699705
) *multichannel.Registrar {
700-
// Are we bootstrapping?
701-
if len(lf.ChannelIDs()) == 0 {
702-
initializeBootstrapChannel(bootstrapBlock, lf)
703-
} else {
704-
logger.Info("Not bootstrapping because of existing channels")
705-
}
706-
707-
consenters := make(map[string]consensus.Consenter)
708-
709706
registrar := multichannel.NewRegistrar(*conf, lf, signer, metricsProvider, bccsp, callbacks...)
710707

708+
consenters := map[string]consensus.Consenter{}
711709
consenters["solo"] = solo.New()
712710
var kafkaMetrics *kafka.Metrics
713711
consenters["kafka"], kafkaMetrics = kafka.New(conf.Kafka, metricsProvider, healthChecker)
714712
// Note, we pass a 'nil' channel here, we could pass a channel that
715713
// closes if we wished to cleanup this routine on exit.
716714
go kafkaMetrics.PollGoMetricsUntilStop(time.Minute, nil)
717-
if isClusterType(bootstrapBlock, bccsp) {
718-
initializeEtcdraftConsenter(consenters, conf, lf, clusterDialer, bootstrapBlock, ri, srvConf, srv, registrar, metricsProvider, bccsp)
715+
if conf.General.GenesisMethod == "file" {
716+
if isClusterType(bootstrapBlock, bccsp) {
717+
initializeEtcdraftConsenter(consenters, conf, lf, clusterDialer, bootstrapBlock, ri, srvConf, srv, registrar, metricsProvider, bccsp)
718+
}
719719
}
720720
registrar.Initialize(consenters)
721721
return registrar

orderer/common/server/main_test.go

+46-17
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ func TestLoadLocalMSP(t *testing.T) {
371371
})
372372
}
373373

374-
func TestInitializeMultiChainManager(t *testing.T) {
374+
func TestInitializeMultichannelRegistrar(t *testing.T) {
375375
cleanup := configtest.SetDevFabricConfigPath(t)
376376
defer cleanup()
377377
genesisFile := produceGenesisFile(t, genesisconfig.SampleDevModeSoloProfile, "testchannelid")
@@ -382,22 +382,50 @@ func TestInitializeMultiChainManager(t *testing.T) {
382382
assert.NoError(t, err)
383383

384384
signer := &server_mocks.SignerSerializer{}
385-
lf, _, err := createLedgerFactory(conf, &disabled.Provider{})
386-
assert.NoError(t, err)
387-
bootBlock := file.New(genesisFile).GenesisBlock()
388-
initializeMultichannelRegistrar(
389-
bootBlock,
390-
&replicationInitiator{cryptoProvider: cryptoProvider},
391-
&cluster.PredicateDialer{},
392-
comm.ServerConfig{},
393-
nil,
394-
conf,
395-
signer,
396-
&disabled.Provider{},
397-
&server_mocks.HealthChecker{},
398-
lf,
399-
cryptoProvider,
400-
)
385+
386+
t.Run("registrar with system channel", func(t *testing.T) {
387+
lf, _, err := createLedgerFactory(conf, &disabled.Provider{})
388+
assert.NoError(t, err)
389+
bootBlock := file.New(genesisFile).GenesisBlock()
390+
initializeBootstrapChannel(bootBlock, lf)
391+
registrar := initializeMultichannelRegistrar(
392+
bootBlock,
393+
&replicationInitiator{cryptoProvider: cryptoProvider},
394+
&cluster.PredicateDialer{},
395+
comm.ServerConfig{},
396+
nil,
397+
conf,
398+
signer,
399+
&disabled.Provider{},
400+
&server_mocks.HealthChecker{},
401+
lf,
402+
cryptoProvider,
403+
)
404+
assert.NotNil(t, registrar)
405+
assert.Equal(t, "testchannelid", registrar.SystemChannelID())
406+
})
407+
408+
t.Run("registrar with no system channel", func(t *testing.T) {
409+
conf.General.GenesisMethod = "none"
410+
conf.General.GenesisFile = ""
411+
lf, _, err := createLedgerFactory(conf, &disabled.Provider{})
412+
assert.NoError(t, err)
413+
registrar := initializeMultichannelRegistrar(
414+
nil,
415+
&replicationInitiator{cryptoProvider: cryptoProvider},
416+
&cluster.PredicateDialer{},
417+
comm.ServerConfig{},
418+
nil,
419+
conf,
420+
signer,
421+
&disabled.Provider{},
422+
&server_mocks.HealthChecker{},
423+
lf,
424+
cryptoProvider,
425+
)
426+
assert.NotNil(t, registrar)
427+
assert.Empty(t, registrar.SystemChannelID())
428+
})
401429
}
402430

403431
func TestInitializeGrpcServer(t *testing.T) {
@@ -465,6 +493,7 @@ func TestUpdateTrustedRoots(t *testing.T) {
465493
lf, _, err := createLedgerFactory(conf, &disabled.Provider{})
466494
assert.NoError(t, err)
467495
bootBlock := file.New(genesisFile).GenesisBlock()
496+
initializeBootstrapChannel(bootBlock, lf)
468497
signer := &server_mocks.SignerSerializer{}
469498

470499
cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())

0 commit comments

Comments
 (0)