-
Notifications
You must be signed in to change notification settings - Fork 8.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FAB-17466] Generate create channel transaction
Signed-off-by: Tiffany Harris <tiffany.harris@ibm.com> Signed-off-by: Danny Cao <dcao@us.ibm.com>
- Loading branch information
Showing
15 changed files
with
3,661 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/* | ||
Copyright IBM Corp. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package config | ||
|
||
import ( | ||
"fmt" | ||
|
||
cb "github.com/hyperledger/fabric-protos-go/common" | ||
mb "github.com/hyperledger/fabric-protos-go/msp" | ||
pb "github.com/hyperledger/fabric-protos-go/peer" | ||
) | ||
|
||
// Application encodes the application-level configuration needed in config | ||
// transactions. | ||
type Application struct { | ||
Organizations []*Organization | ||
Capabilities map[string]bool | ||
Resources *Resources | ||
Policies map[string]*Policy | ||
ACLs map[string]string | ||
} | ||
|
||
// AnchorPeer encodes the necessary fields to identify an anchor peer. | ||
type AnchorPeer struct { | ||
Host string | ||
Port int | ||
} | ||
|
||
// NewApplicationGroup returns the application component of the channel configuration. | ||
// It defines the organizations which are involved in application logic like chaincodes, | ||
// and how these members may interact with the orderer. | ||
// It sets the mod_policy of all elements to "Admins". | ||
func NewApplicationGroup(conf *Application, mspConfig *mb.MSPConfig) (*cb.ConfigGroup, error) { | ||
var err error | ||
|
||
applicationGroup := newConfigGroup() | ||
applicationGroup.ModPolicy = AdminsPolicyKey | ||
|
||
if err = addPolicies(applicationGroup, conf.Policies, AdminsPolicyKey); err != nil { | ||
return nil, fmt.Errorf("failed to add policies: %v", err) | ||
} | ||
|
||
if len(conf.ACLs) > 0 { | ||
err = addValue(applicationGroup, aclValues(conf.ACLs), AdminsPolicyKey) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to add acl values: %v", err) | ||
} | ||
} | ||
|
||
if len(conf.Capabilities) > 0 { | ||
err = addValue(applicationGroup, capabilitiesValue(conf.Capabilities), AdminsPolicyKey) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to add capabilities value: %v", err) | ||
} | ||
} | ||
|
||
for _, org := range conf.Organizations { | ||
applicationGroup.Groups[org.Name], err = newApplicationOrgGroup(org, mspConfig) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to create application org group %s: %v", org.Name, err) | ||
} | ||
} | ||
|
||
return applicationGroup, nil | ||
} | ||
|
||
// newApplicationOrgGroup returns an application org component of the channel configuration. | ||
// It defines the crypto material for the organization (its MSP), as well as its anchor peers | ||
// for use by the gossip network. | ||
// It sets the mod_policy of all elements to "Admins". | ||
func newApplicationOrgGroup(conf *Organization, mspConfig *mb.MSPConfig) (*cb.ConfigGroup, error) { | ||
var err error | ||
|
||
applicationOrgGroup := newConfigGroup() | ||
applicationOrgGroup.ModPolicy = AdminsPolicyKey | ||
|
||
if conf.SkipAsForeign { | ||
return applicationOrgGroup, nil | ||
} | ||
|
||
if err = addPolicies(applicationOrgGroup, conf.Policies, AdminsPolicyKey); err != nil { | ||
return nil, fmt.Errorf("failed to add policies: %v", err) | ||
} | ||
|
||
err = addValue(applicationOrgGroup, mspValue(mspConfig), AdminsPolicyKey) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to add msp value: %v", err) | ||
} | ||
|
||
var anchorProtos []*pb.AnchorPeer | ||
for _, anchorPeer := range conf.AnchorPeers { | ||
anchorProtos = append(anchorProtos, &pb.AnchorPeer{ | ||
Host: anchorPeer.Host, | ||
Port: int32(anchorPeer.Port), | ||
}) | ||
} | ||
|
||
// Avoid adding an unnecessary anchor peers element when one is not required | ||
// This helps prevent a delta from the orderer system channel when computing | ||
// more complex channel creation transactions | ||
if len(anchorProtos) > 0 { | ||
err = addValue(applicationOrgGroup, anchorPeersValue(anchorProtos), AdminsPolicyKey) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to add anchor peers value: %v", err) | ||
} | ||
} | ||
|
||
return applicationOrgGroup, nil | ||
} | ||
|
||
// aclValues returns the config definition for an application's resources based ACL definitions. | ||
// It is a value for the /Channel/Application/. | ||
func aclValues(acls map[string]string) *standardConfigValue { | ||
a := &pb.ACLs{ | ||
Acls: make(map[string]*pb.APIResource), | ||
} | ||
|
||
for apiResource, policyRef := range acls { | ||
a.Acls[apiResource] = &pb.APIResource{PolicyRef: policyRef} | ||
} | ||
|
||
return &standardConfigValue{ | ||
key: ACLsKey, | ||
value: a, | ||
} | ||
} | ||
|
||
// anchorPeersValue returns the config definition for an org's anchor peers. | ||
// It is a value for the /Channel/Application/*. | ||
func anchorPeersValue(anchorPeers []*pb.AnchorPeer) *standardConfigValue { | ||
return &standardConfigValue{ | ||
key: AnchorPeersKey, | ||
value: &pb.AnchorPeers{AnchorPeers: anchorPeers}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
/* | ||
Copyright IBM Corp All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package config | ||
|
||
import ( | ||
"errors" | ||
"testing" | ||
|
||
cb "github.com/hyperledger/fabric-protos-go/common" | ||
mb "github.com/hyperledger/fabric-protos-go/msp" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
func TestNewApplicationGroup(t *testing.T) { | ||
t.Parallel() | ||
|
||
gt := NewGomegaWithT(t) | ||
|
||
application := baseApplication() | ||
|
||
mspConfig := &mb.MSPConfig{} | ||
|
||
applicationGroup, err := NewApplicationGroup(application, mspConfig) | ||
gt.Expect(err).NotTo(HaveOccurred()) | ||
|
||
// ApplicationGroup checks | ||
gt.Expect(len(applicationGroup.Groups)).To(Equal(2)) | ||
gt.Expect(applicationGroup.Groups["Org1"]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Groups["Org2"]).NotTo(BeNil()) | ||
gt.Expect(len(applicationGroup.Values)).To(Equal(2)) | ||
gt.Expect(applicationGroup.Values[ACLsKey]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Values[CapabilitiesKey]).NotTo(BeNil()) | ||
gt.Expect(len(applicationGroup.Policies)).To(Equal(3)) | ||
gt.Expect(applicationGroup.Policies[AdminsPolicyKey]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Policies[ReadersPolicyKey]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Policies[WritersPolicyKey]).NotTo(BeNil()) | ||
|
||
// ApplicationOrgGroup checks | ||
gt.Expect(len(applicationGroup.Groups["Org1"].Groups)).To(Equal(0)) | ||
gt.Expect(len(applicationGroup.Groups["Org1"].Values)).To(Equal(2)) | ||
gt.Expect(applicationGroup.Groups["Org1"].Values[MSPKey]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Groups["Org1"].Values[AnchorPeersKey]).NotTo(BeNil()) | ||
gt.Expect(len(applicationGroup.Groups["Org1"].Policies)).To(Equal(5)) | ||
gt.Expect(applicationGroup.Groups["Org1"].Policies[AdminsPolicyKey]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Groups["Org1"].Policies[ReadersPolicyKey]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Groups["Org1"].Policies[WritersPolicyKey]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Groups["Org1"].Policies[EndorsementPolicyKey]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Groups["Org1"].Policies[LifecycleEndorsementPolicyKey]).NotTo(BeNil()) | ||
gt.Expect(len(applicationGroup.Groups["Org2"].Groups)).To(Equal(0)) | ||
gt.Expect(len(applicationGroup.Groups["Org2"].Values)).To(Equal(2)) | ||
gt.Expect(applicationGroup.Groups["Org2"].Values[MSPKey]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Groups["Org2"].Values[AnchorPeersKey]).NotTo(BeNil()) | ||
gt.Expect(len(applicationGroup.Groups["Org2"].Policies)).To(Equal(5)) | ||
gt.Expect(applicationGroup.Groups["Org2"].Policies[AdminsPolicyKey]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Groups["Org2"].Policies[ReadersPolicyKey]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Groups["Org2"].Policies[WritersPolicyKey]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Groups["Org2"].Policies[EndorsementPolicyKey]).NotTo(BeNil()) | ||
gt.Expect(applicationGroup.Groups["Org2"].Policies[LifecycleEndorsementPolicyKey]).NotTo(BeNil()) | ||
} | ||
|
||
func TestNewApplicationGroupFailure(t *testing.T) { | ||
t.Parallel() | ||
|
||
tests := []struct { | ||
testName string | ||
applicationMod func(*Application) | ||
expectedErr error | ||
}{ | ||
{ | ||
testName: "When application group policy is empty", | ||
applicationMod: func(a *Application) { | ||
a.Policies = nil | ||
}, | ||
expectedErr: errors.New("failed to add policies: no policies defined"), | ||
}, | ||
{ | ||
testName: "When adding policies to application group", | ||
applicationMod: func(a *Application) { | ||
a.Organizations[0].Policies = nil | ||
}, | ||
expectedErr: errors.New("failed to create application org group Org1: failed to add policies: " + | ||
"no policies defined"), | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
tt := tt // capture range variable | ||
t.Run(tt.testName, func(t *testing.T) { | ||
t.Parallel() | ||
|
||
gt := NewGomegaWithT(t) | ||
|
||
application := baseApplication() | ||
tt.applicationMod(application) | ||
|
||
mspConfig := &mb.MSPConfig{} | ||
|
||
configGrp, err := NewApplicationGroup(application, mspConfig) | ||
gt.Expect(err).To(MatchError(tt.expectedErr)) | ||
gt.Expect(configGrp).To(BeNil()) | ||
}) | ||
} | ||
} | ||
|
||
func TestNewApplicationGroupSkipAsForeign(t *testing.T) { | ||
t.Parallel() | ||
|
||
gt := NewGomegaWithT(t) | ||
|
||
application := baseApplication() | ||
application.Organizations[0].SkipAsForeign = true | ||
application.Organizations[1].SkipAsForeign = true | ||
|
||
mspConfig := &mb.MSPConfig{} | ||
|
||
applicationGroup, err := NewApplicationGroup(application, mspConfig) | ||
gt.Expect(err).NotTo(HaveOccurred()) | ||
gt.Expect(applicationGroup.Groups["Org1"]).To(Equal(&cb.ConfigGroup{ | ||
ModPolicy: AdminsPolicyKey, | ||
Groups: make(map[string]*cb.ConfigGroup), | ||
Values: make(map[string]*cb.ConfigValue), | ||
Policies: make(map[string]*cb.ConfigPolicy), | ||
})) | ||
gt.Expect(applicationGroup.Groups["Org2"]).To(Equal(&cb.ConfigGroup{ | ||
ModPolicy: AdminsPolicyKey, | ||
Groups: make(map[string]*cb.ConfigGroup), | ||
Values: make(map[string]*cb.ConfigValue), | ||
Policies: make(map[string]*cb.ConfigPolicy), | ||
})) | ||
} | ||
|
||
func baseApplication() *Application { | ||
return &Application{ | ||
Policies: createStandardPolicies(), | ||
Organizations: []*Organization{ | ||
{ | ||
Name: "Org1", | ||
ID: "Org1MSP", | ||
Policies: createApplicationOrgStandardPolicies(), | ||
AnchorPeers: []*AnchorPeer{ | ||
{Host: "host1", Port: 123}, | ||
}, | ||
}, | ||
{ | ||
Name: "Org2", | ||
ID: "Org2MSP", | ||
Policies: createApplicationOrgStandardPolicies(), | ||
AnchorPeers: []*AnchorPeer{ | ||
{Host: "host1", Port: 123}, | ||
}, | ||
}, | ||
}, | ||
Capabilities: map[string]bool{ | ||
"V1_3": true, | ||
}, | ||
ACLs: map[string]string{ | ||
"acl1": "hi", | ||
}, | ||
} | ||
} |
Oops, something went wrong.