Skip to content

Commit a05cf54

Browse files
author
Jason Yellick
committed
[FAB-1765] Fix orderer crash
https://jira.hyperledger.org/browse/FAB-1765 When the orderer is initialized with an empty slice for ChainCreationPolicyNames, no chain is initialized as the system chain. This does not cause a panic, and leads to a nil pointer dereference when a new chain proposal tries to reference the system chain. This is a byproduct of the fact that empty slices marshal to nil under protobuf, so the sharedconfig code was setting the ChainCreationPolicyNames to nil rather than an empty slice. The system chain was detected by looking for a non-nil ChainCreationPolicyNames. Change-Id: I4c8bf40e89dc73ba4ee27646b3f66c65ecb22d38 Signed-off-by: Jason Yellick <[email protected]>
1 parent 7e52b66 commit a05cf54

File tree

4 files changed

+54
-11
lines changed

4 files changed

+54
-11
lines changed

orderer/common/sharedconfig/sharedconfig.go

+17-11
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,13 @@ type Manager interface {
8686
}
8787

8888
type ordererConfig struct {
89-
consensusType string
90-
batchSize *ab.BatchSize
91-
batchTimeout time.Duration
92-
chainCreationPolicies []string
93-
kafkaBrokers []string
94-
ingressPolicyNames []string
95-
egressPolicyNames []string
89+
consensusType string
90+
batchSize *ab.BatchSize
91+
batchTimeout time.Duration
92+
chainCreationPolicyNames []string
93+
kafkaBrokers []string
94+
ingressPolicyNames []string
95+
egressPolicyNames []string
9696
}
9797

9898
// ManagerImpl is an implementation of Manager and configtx.ConfigHandler
@@ -127,7 +127,7 @@ func (pm *ManagerImpl) BatchTimeout() time.Duration {
127127
// ChainCreationPolicyNames returns the policy names which are allowed for chain creation
128128
// This field is only set for the system ordering chain
129129
func (pm *ManagerImpl) ChainCreationPolicyNames() []string {
130-
return pm.config.chainCreationPolicies
130+
return pm.config.chainCreationPolicyNames
131131
}
132132

133133
// KafkaBrokers returns the addresses (IP:port notation) of a set of "bootstrap"
@@ -225,11 +225,17 @@ func (pm *ManagerImpl) ProposeConfig(configItem *cb.ConfigurationItem) error {
225225
}
226226
pm.pendingConfig.batchTimeout = timeoutValue
227227
case ChainCreationPolicyNamesKey:
228-
chainCreationPolicies := &ab.ChainCreationPolicyNames{}
229-
if err := proto.Unmarshal(configItem.Value, chainCreationPolicies); err != nil {
228+
chainCreationPolicyNames := &ab.ChainCreationPolicyNames{}
229+
if err := proto.Unmarshal(configItem.Value, chainCreationPolicyNames); err != nil {
230230
return fmt.Errorf("Unmarshaling error for ChainCreator: %s", err)
231231
}
232-
pm.pendingConfig.chainCreationPolicies = chainCreationPolicies.Names
232+
if chainCreationPolicyNames.Names == nil {
233+
// Proto unmarshals empty slices to nil, but this poses a problem for us in detecting the system chain
234+
// if it does not set this value, so explicitly set the policies to the empty string slice, if it is set
235+
pm.pendingConfig.chainCreationPolicyNames = []string{}
236+
} else {
237+
pm.pendingConfig.chainCreationPolicyNames = chainCreationPolicyNames.Names
238+
}
233239
case IngressPolicyNamesKey:
234240
ingressPolicyNames := &ab.IngressPolicyNames{}
235241
if err := proto.Unmarshal(configItem.Value, ingressPolicyNames); err != nil {

orderer/common/sharedconfig/sharedconfig_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,20 @@ func TestChainCreationPolicyNames(t *testing.T) {
319319
m := NewManagerImpl()
320320
testPolicyNames(m, ChainCreationPolicyNamesKey, TemplateChainCreationPolicyNames, m.ChainCreationPolicyNames, t)
321321
}
322+
323+
func TestEmptyChainCreationPolicyNames(t *testing.T) {
324+
m := NewManagerImpl()
325+
326+
m.BeginConfig()
327+
328+
err := m.ProposeConfig(TemplateChainCreationPolicyNames(nil))
329+
if err != nil {
330+
t.Fatalf("Error applying valid config: %s", err)
331+
}
332+
333+
m.CommitConfig()
334+
335+
if m.ChainCreationPolicyNames() == nil {
336+
t.Fatalf("Should have gotten back empty slice, not nil")
337+
}
338+
}

orderer/multichain/manager.go

+4
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ func NewManagerImpl(ledgerFactory ordererledger.Factory, consenters map[string]C
142142

143143
}
144144

145+
if ml.sysChain == nil {
146+
logger.Panicf("No system chain found")
147+
}
148+
145149
return ml
146150
}
147151

orderer/multichain/manager_test.go

+16
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,22 @@ func TestGetConfigTxFailure(t *testing.T) {
102102

103103
}
104104

105+
// This test essentially brings the entire system up and is ultimately what main.go will replicate
106+
func TestNoSystemChain(t *testing.T) {
107+
defer func() {
108+
if recover() == nil {
109+
t.Fatalf("Should have panicked when starting without a system chain")
110+
}
111+
}()
112+
113+
lf := ramledger.New(10)
114+
115+
consenters := make(map[string]Consenter)
116+
consenters[conf.Genesis.OrdererType] = &mockConsenter{}
117+
118+
NewManagerImpl(lf, consenters)
119+
}
120+
105121
// This test essentially brings the entire system up and is ultimately what main.go will replicate
106122
func TestManagerImpl(t *testing.T) {
107123
lf, rl := NewRAMLedgerAndFactory(10)

0 commit comments

Comments
 (0)