Skip to content

Commit

Permalink
[FAB-17466] Generate create channel transaction
Browse files Browse the repository at this point in the history
Signed-off-by: Tiffany Harris <tiffany.harris@ibm.com>
Signed-off-by: Danny Cao <dcao@us.ibm.com>
  • Loading branch information
stephyee authored and caod123 committed Feb 19, 2020
1 parent bee7154 commit 6086aa9
Show file tree
Hide file tree
Showing 15 changed files with 3,661 additions and 23 deletions.
139 changes: 139 additions & 0 deletions pkg/config/application.go
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},
}
}
164 changes: 164 additions & 0 deletions pkg/config/application_test.go
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",
},
}
}
Loading

0 comments on commit 6086aa9

Please sign in to comment.