Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FAB-17466] Generate create channel transaction #686

Merged
merged 1 commit into from
Feb 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
stephyee marked this conversation as resolved.
Show resolved Hide resolved
// 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