@@ -7,10 +7,11 @@ SPDX-License-Identifier: Apache-2.0
77package cryptogen
88
99import (
10- "net"
10+ "fmt"
11+ "maps"
1112 "os"
1213 "path"
13- "strconv "
14+ "slices "
1415 "strings"
1516
1617 "github.com/cockroachdb/errors"
@@ -36,7 +37,7 @@ type ConfigBlockParameters struct {
3637type OrganizationParameters struct {
3738 Name string
3839 Domain string
39- OrdererEndpoints []OrdererEndpoint
40+ OrdererEndpoints []* types. OrdererEndpoint
4041 ConsenterNodes []Node
4142 OrdererNodes []Node
4243 PeerNodes []Node
@@ -46,14 +47,19 @@ type OrganizationParameters struct {
4647type Node struct {
4748 CommonName string
4849 Hostname string
49- Party string
5050 SANS []string
51- }
52-
53- // OrdererEndpoint address should be in the format of <host>:<port>, not the full [types.OrdererEndpoint] format.
54- type OrdererEndpoint struct {
55- Address string
56- API []string
51+ // Fabric-X supports multiple parties per organizations.
52+ // Thus, in such case, we can create multiple Orderer's nodes
53+ // for each organization.
54+ // We organize them such that each party's nodes will be under
55+ // a dedicated party folder.
56+ // This folder name is inffered from PartyName, if given.
57+ // Otherwise, a default name will be used.
58+ // If it is not set, and we have only one party for the organization,
59+ // the folder structure will collapse one step down.
60+ // If it is not set, and we have multiple parties for the organization,
61+ // The party assigned named will be party-<party-ID>.
62+ PartyName string
5763}
5864
5965// file names.
@@ -84,19 +90,14 @@ func LoadSampleConfig(profile string) (*configtxgen.Profile, error) {
8490 return result , nil
8591}
8692
87- // CreateDefaultConfigBlockWithCrypto creates a config block with default values and a crypto material.
93+ // CreateOrExtendConfigBlockWithCrypto creates a config block with default values and a crypto material.
8894// It uses the first orderer organization as a template and creates the given organizations.
8995// It uses the same organizations for the orderer and the application.
90- func CreateDefaultConfigBlockWithCrypto (conf ConfigBlockParameters ) (* common.Block , error ) {
91- if conf .BaseProfile == "" {
92- conf .BaseProfile = configtxgen .SampleFabricX
93- }
94- if conf .ChannelID == "" {
95- conf .ChannelID = "chan"
96- }
97- profile , err := LoadSampleConfig (conf .BaseProfile )
98- if err != nil {
99- return nil , err
96+ func CreateOrExtendConfigBlockWithCrypto (conf ConfigBlockParameters ) (* common.Block , error ) {
97+ initConfigDefault (& conf )
98+ profile , loadErr := LoadSampleConfig (conf .BaseProfile )
99+ if loadErr != nil {
100+ return nil , loadErr
100101 }
101102
102103 if len (profile .Orderer .Organizations ) < 1 {
@@ -110,17 +111,23 @@ func CreateDefaultConfigBlockWithCrypto(conf ConfigBlockParameters) (*common.Blo
110111 profile .Orderer .Organizations = make ([]* configtxgen.Organization , 0 , len (conf .Organizations ))
111112 profile .Application .Organizations = make ([]* configtxgen.Organization , 0 , len (conf .Organizations ))
112113 cryptoConf := & Config {}
113- for i , o := range conf .Organizations {
114- spec := createOrgSpec (& o )
115114
116- id := uint32 (i ) //nolint:gosec // int -> uint32.
117- org , orgErr := createOrg (id , sourceOrg , & o )
118- if orgErr != nil {
119- return nil , orgErr
115+ allOrdererIDs := make (map [uint32 ]any )
116+ for _ , o := range conf .Organizations {
117+ org , orgOrdererIDs := createOrg (sourceOrg , & o )
118+ for _ , id := range orgOrdererIDs {
119+ if _ , ok := allOrdererIDs [id ]; ok {
120+ return nil , errors .Errorf ("duplicate party id [%d] found in org %s" , id , o .Name )
121+ }
122+ allOrdererIDs [id ] = nil
120123 }
124+ allConsenters , err := createConsenter (& o , orgOrdererIDs )
125+ if err != nil {
126+ return nil , err
127+ }
128+ profile .Orderer .ConsenterMapping = append (profile .Orderer .ConsenterMapping , allConsenters ... )
121129
122- profile .Orderer .ConsenterMapping = append (profile .Orderer .ConsenterMapping , createConsenter (id , & o )... )
123-
130+ spec := createOrgSpec (& o )
124131 switch orgOU (& o ) {
125132 case PeerOU :
126133 profile .Application .Organizations = append (profile .Application .Organizations , org )
@@ -135,13 +142,13 @@ func CreateDefaultConfigBlockWithCrypto(conf ConfigBlockParameters) (*common.Blo
135142 }
136143 }
137144
138- err = os .WriteFile (path .Join (conf .TargetPath , armaDataFile ), conf .ArmaMetaBytes , 0o644 )
145+ err : = os .WriteFile (path .Join (conf .TargetPath , armaDataFile ), conf .ArmaMetaBytes , 0o644 )
139146 if err != nil {
140147 return nil , errors .Wrap (err , "failed to write ARMA data file" )
141148 }
142149 profile .Orderer .Arma .Path = armaDataFile
143150
144- err = Generate (conf .TargetPath , cryptoConf )
151+ err = Extend (conf .TargetPath , cryptoConf )
145152 if err != nil {
146153 return nil , err
147154 }
@@ -156,6 +163,15 @@ func CreateDefaultConfigBlockWithCrypto(conf ConfigBlockParameters) (*common.Blo
156163 return block , errors .Wrap (err , "failed to write block" )
157164}
158165
166+ func initConfigDefault (conf * ConfigBlockParameters ) {
167+ if conf .BaseProfile == "" {
168+ conf .BaseProfile = configtxgen .SampleFabricX
169+ }
170+ if conf .ChannelID == "" {
171+ conf .ChannelID = "chan"
172+ }
173+ }
174+
159175func orgOU (o * OrganizationParameters ) string {
160176 ordererNodeCount := len (o .ConsenterNodes ) + len (o .OrdererNodes )
161177 peerNodeCount := len (o .PeerNodes )
@@ -178,7 +194,7 @@ func createOrgSpec(o *OrganizationParameters) OrgSpec {
178194 CommonName : n .CommonName ,
179195 Hostname : n .Hostname ,
180196 SANS : n .SANS ,
181- Party : n .Party ,
197+ Party : n .PartyName ,
182198 OrganizationalUnit : OrdererOU ,
183199 })
184200 }
@@ -187,7 +203,7 @@ func createOrgSpec(o *OrganizationParameters) OrgSpec {
187203 CommonName : n .CommonName ,
188204 Hostname : n .Hostname ,
189205 SANS : n .SANS ,
190- Party : n .Party ,
206+ Party : n .PartyName ,
191207 OrganizationalUnit : OrdererOU ,
192208 })
193209 }
@@ -196,7 +212,7 @@ func createOrgSpec(o *OrganizationParameters) OrgSpec {
196212 CommonName : n .CommonName ,
197213 Hostname : n .Hostname ,
198214 SANS : n .SANS ,
199- Party : n .Party ,
215+ Party : n .PartyName ,
200216 OrganizationalUnit : PeerOU ,
201217 })
202218 }
@@ -218,19 +234,17 @@ func createOrgSpec(o *OrganizationParameters) OrgSpec {
218234}
219235
220236func createOrg (
221- id uint32 , sourceOrg configtxgen.Organization , o * OrganizationParameters ,
222- ) (* configtxgen.Organization , error ) {
237+ sourceOrg configtxgen.Organization , o * OrganizationParameters ,
238+ ) (* configtxgen.Organization , [] uint32 ) {
223239 org := sourceOrg
224240 org .ID = o .Name
225241 org .Name = o .Name
226242 org .MSPDir = path .Join (getOrgPath (o ), MSPDir )
227- org .OrdererEndpoints = make ([]* types.OrdererEndpoint , len (o .OrdererEndpoints ))
228- for epIdx , ep := range o .OrdererEndpoints {
229- var err error
230- org .OrdererEndpoints [epIdx ], err = newOrdererEndpoint (id , ep .Address , o .Name , ep .API )
231- if err != nil {
232- return nil , errors .Wrapf (err , "invalid %+v" , ep )
233- }
243+ org .OrdererEndpoints = o .OrdererEndpoints
244+ allOrdererIDsMap := make (map [uint32 ]any )
245+ for _ , ep := range org .OrdererEndpoints {
246+ ep .MspID = o .Name
247+ allOrdererIDsMap [ep .ID ] = nil
234248 }
235249 org .Policies = make (map [string ]* configtxgen.Policy )
236250 for k , p := range sourceOrg .Policies {
@@ -239,14 +253,23 @@ func createOrg(
239253 Rule : strings .ReplaceAll (p .Rule , sourceOrg .Name , o .Name ),
240254 }
241255 }
242- return & org , nil
256+ allOrdererIDs := slices .Collect (maps .Keys (allOrdererIDsMap ))
257+ // We sort the IDs for deterministic output.
258+ slices .Sort (allOrdererIDs )
259+ return & org , allOrdererIDs
243260}
244261
245- func createConsenter (id uint32 , o * OrganizationParameters ) []* configtxgen.Consenter {
262+ func createConsenter (o * OrganizationParameters , ids []uint32 ) ([]* configtxgen.Consenter , error ) {
263+ if len (ids ) != len (o .ConsenterNodes ) {
264+ return nil , errors .Errorf ("number of consenters doesn't match number of parties in org: %s" , o .Name )
265+ }
246266 consenter := make ([]* configtxgen.Consenter , len (o .ConsenterNodes ))
247267 for i , n := range o .ConsenterNodes {
248- // We use the org's admin certificate as the consenter nodes.
249- identity := path .Join (getOrgPath (o ), OrdererNodesDir , n .Party , n .CommonName , MSPDir ,
268+ id := ids [i ]
269+ if len (n .PartyName ) == 0 && len (ids ) > 1 {
270+ n .PartyName = fmt .Sprintf ("party-%d" , id )
271+ }
272+ identity := path .Join (getOrgPath (o ), OrdererNodesDir , n .PartyName , n .CommonName , MSPDir ,
250273 SignCertsDir , n .CommonName + CertSuffix )
251274 consenter [i ] = & configtxgen.Consenter {
252275 ID : id ,
@@ -258,7 +281,7 @@ func createConsenter(id uint32, o *OrganizationParameters) []*configtxgen.Consen
258281 ServerTLSCert : identity ,
259282 }
260283 }
261- return consenter
284+ return consenter , nil
262285}
263286
264287func getOrgPath (o * OrganizationParameters ) string {
@@ -271,21 +294,3 @@ func getOrgPath(o *OrganizationParameters) string {
271294 return path .Join (GenericOrganizationsDir , o .Name )
272295 }
273296}
274-
275- func newOrdererEndpoint (id uint32 , address , name string , api []string ) (* types.OrdererEndpoint , error ) {
276- host , portStr , err := net .SplitHostPort (address )
277- if err != nil {
278- return nil , errors .Wrapf (err , "invalid address: %s" , address )
279- }
280- port , err := strconv .Atoi (portStr )
281- if err != nil {
282- return nil , errors .Wrapf (err , "invalid port: %s" , portStr )
283- }
284- return & types.OrdererEndpoint {
285- Host : host ,
286- Port : port ,
287- MspID : name ,
288- ID : id ,
289- API : api ,
290- }, nil
291- }
0 commit comments