Skip to content

Commit 52dc361

Browse files
author
Jason Yellick
committed
[FAB-6141] Add more flexible channel create helper
The original channel creation tx generation code assumes that no modifications have been made to the organization definitions in the ordering system channel. For longer running systems this assumption may not hold. Consequently, a new function which accepts the ordering system channel's config is required so that it can set the correct versions for the organization's in the channel creation transaction. This CR adds this new function. Change-Id: Iebeb247bbea5c688a14c6133f793373da7357c9b Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
1 parent 95b95e9 commit 52dc361

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed

common/tools/configtxgen/encoder/encoder.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
pb "github.com/hyperledger/fabric/protos/peer"
1919
"github.com/hyperledger/fabric/protos/utils"
2020

21+
"github.com/golang/protobuf/proto"
2122
"github.com/pkg/errors"
2223
)
2324

@@ -274,6 +275,72 @@ func NewConsortiumGroup(conf *genesisconfig.Consortium) (*cb.ConfigGroup, error)
274275
return consortiumGroup, nil
275276
}
276277

278+
// NewChannelCreateConfigUpdate generates a ConfigUpdate which can be sent to the orderer to create a new channel. Optionally, the channel group of the
279+
// ordering system channel may be passed in, and the resulting ConfigUpdate will extract the appropriate versions from this file.
280+
func NewChannelCreateConfigUpdate(channelID, consortiumName string, orgs []string, orderingSystemChannelGroup *cb.ConfigGroup) (*cb.ConfigUpdate, error) {
281+
var applicationGroup *cb.ConfigGroup
282+
channelGroupVersion := uint64(0)
283+
284+
if orderingSystemChannelGroup != nil {
285+
// In the case that a ordering system channel definition was provided, pull the appropriate versions
286+
if orderingSystemChannelGroup.Groups == nil {
287+
return nil, errors.New("missing all channel groups")
288+
}
289+
290+
consortiums, ok := orderingSystemChannelGroup.Groups[channelconfig.ConsortiumsGroupKey]
291+
if !ok {
292+
return nil, errors.New("bad consortiums group")
293+
}
294+
295+
consortium, ok := consortiums.Groups[consortiumName]
296+
if !ok || (len(orgs) > 0 && consortium.Groups == nil) {
297+
return nil, errors.Errorf("bad consortium: %s", consortiumName)
298+
}
299+
300+
applicationGroup = cb.NewConfigGroup()
301+
for _, org := range orgs {
302+
orgGroup, ok := consortium.Groups[org]
303+
if !ok {
304+
return nil, errors.Errorf("missing organization: %s", org)
305+
}
306+
applicationGroup.Groups[org] = &cb.ConfigGroup{Version: orgGroup.Version}
307+
}
308+
309+
channelGroupVersion = orderingSystemChannelGroup.Version
310+
} else {
311+
// Otherwise assume the orgs have not been modified
312+
applicationGroup = cb.NewConfigGroup()
313+
for _, org := range orgs {
314+
applicationGroup.Groups[org] = &cb.ConfigGroup{}
315+
}
316+
}
317+
318+
rSet := cb.NewConfigGroup()
319+
rSet.Version = channelGroupVersion
320+
321+
// add the consortium name to the rSet
322+
323+
addValue(rSet, channelconfig.ConsortiumValue(consortiumName), "") // TODO, this emulates the old behavior, but is it desirable?
324+
325+
// create the new channel's application group
326+
327+
rSet.Groups[channelconfig.ApplicationGroupKey] = applicationGroup
328+
329+
wSet := proto.Clone(rSet).(*cb.ConfigGroup)
330+
331+
applicationGroup = wSet.Groups[channelconfig.ApplicationGroupKey]
332+
applicationGroup.Version = 1
333+
applicationGroup.Policies = make(map[string]*cb.ConfigPolicy)
334+
addImplicitMetaPolicyDefaults(applicationGroup)
335+
applicationGroup.ModPolicy = channelconfig.AdminsPolicyKey
336+
337+
return &cb.ConfigUpdate{
338+
ChannelId: channelID,
339+
ReadSet: rSet,
340+
WriteSet: wSet,
341+
}, nil
342+
}
343+
277344
// Bootstrapper is a wrapper around NewChannelConfigGroup which can produce genesis blocks
278345
type Bootstrapper struct {
279346
channelGroup *cb.ConfigGroup

common/tools/configtxgen/encoder/encoder_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ import (
1010
"testing"
1111

1212
"github.com/hyperledger/fabric/common/channelconfig"
13+
"github.com/hyperledger/fabric/common/configtx"
1314
"github.com/hyperledger/fabric/common/flogging"
1415
genesisconfig "github.com/hyperledger/fabric/common/tools/configtxgen/localconfig"
1516
cb "github.com/hyperledger/fabric/protos/common"
1617

18+
"github.com/golang/protobuf/proto"
1719
"github.com/stretchr/testify/assert"
1820
)
1921

@@ -61,3 +63,80 @@ func TestConfigParsing(t *testing.T) {
6163
})
6264
}
6365
}
66+
67+
func TestGoodChannelCreateConfigUpdate(t *testing.T) {
68+
config := genesisconfig.Load(genesisconfig.SampleDevModeSoloProfile)
69+
group, err := NewChannelGroup(config)
70+
assert.NoError(t, err)
71+
assert.NotNil(t, group)
72+
73+
configUpdate, err := NewChannelCreateConfigUpdate("channel.id", genesisconfig.SampleConsortiumName, []string{genesisconfig.SampleOrgName}, group)
74+
assert.NoError(t, err)
75+
assert.NotNil(t, configUpdate)
76+
77+
defaultConfigUpdate, err := NewChannelCreateConfigUpdate("channel.id", genesisconfig.SampleConsortiumName, []string{genesisconfig.SampleOrgName}, nil)
78+
assert.NoError(t, err)
79+
assert.NotNil(t, configUpdate)
80+
81+
assert.True(t, proto.Equal(configUpdate, defaultConfigUpdate), "the config used has had no updates, so should equal default")
82+
}
83+
84+
func TestNegativeChannelCreateConfigUpdate(t *testing.T) {
85+
config := genesisconfig.Load(genesisconfig.SampleDevModeSoloProfile)
86+
group, err := NewChannelGroup(config)
87+
assert.NoError(t, err)
88+
assert.NotNil(t, group)
89+
90+
t.Run("NoGroups", func(t *testing.T) {
91+
channelGroup := proto.Clone(group).(*cb.ConfigGroup)
92+
channelGroup.Groups = nil
93+
_, err := NewChannelCreateConfigUpdate("channel.id", genesisconfig.SampleConsortiumName, []string{genesisconfig.SampleOrgName}, channelGroup)
94+
assert.Error(t, err)
95+
assert.Regexp(t, "missing all channel groups", err.Error())
96+
})
97+
98+
t.Run("NoConsortiumsGroup", func(t *testing.T) {
99+
channelGroup := proto.Clone(group).(*cb.ConfigGroup)
100+
delete(channelGroup.Groups, channelconfig.ConsortiumsGroupKey)
101+
_, err := NewChannelCreateConfigUpdate("channel.id", genesisconfig.SampleConsortiumName, []string{genesisconfig.SampleOrgName}, channelGroup)
102+
assert.Error(t, err)
103+
assert.Regexp(t, "bad consortiums group", err.Error())
104+
})
105+
106+
t.Run("NoConsortiums", func(t *testing.T) {
107+
channelGroup := proto.Clone(group).(*cb.ConfigGroup)
108+
delete(channelGroup.Groups[channelconfig.ConsortiumsGroupKey].Groups, genesisconfig.SampleConsortiumName)
109+
_, err := NewChannelCreateConfigUpdate("channel.id", genesisconfig.SampleConsortiumName, []string{genesisconfig.SampleOrgName}, channelGroup)
110+
assert.Error(t, err)
111+
assert.Regexp(t, "bad consortium:", err.Error())
112+
})
113+
114+
t.Run("MissingOrg", func(t *testing.T) {
115+
channelGroup := proto.Clone(group).(*cb.ConfigGroup)
116+
_, err := NewChannelCreateConfigUpdate("channel.id", genesisconfig.SampleConsortiumName, []string{genesisconfig.SampleOrgName + ".wrong"}, channelGroup)
117+
assert.Error(t, err)
118+
assert.Regexp(t, "missing organization:", err.Error())
119+
})
120+
}
121+
122+
// This is a temporary test to make sure that the newly implement channel creation method properly replicates
123+
// the old behavior
124+
func TestCompatability(t *testing.T) {
125+
config := genesisconfig.Load(genesisconfig.SampleDevModeSoloProfile)
126+
group, err := NewChannelGroup(config)
127+
assert.NoError(t, err)
128+
assert.NotNil(t, group)
129+
130+
channelID := "channel.id"
131+
orgs := []string{genesisconfig.SampleOrgName}
132+
configUpdate, err := NewChannelCreateConfigUpdate(channelID, genesisconfig.SampleConsortiumName, orgs, group)
133+
assert.NoError(t, err)
134+
assert.NotNil(t, configUpdate)
135+
136+
template := channelconfig.NewChainCreationTemplate(genesisconfig.SampleConsortiumName, orgs)
137+
configEnv, err := template.Envelope(channelID)
138+
assert.NoError(t, err)
139+
oldUpdate := configtx.UnmarshalConfigUpdateOrPanic(configEnv.ConfigUpdate)
140+
oldUpdate.IsolatedData = nil
141+
assert.True(t, proto.Equal(oldUpdate, configUpdate))
142+
}

0 commit comments

Comments
 (0)