Skip to content

Commit f388cd9

Browse files
committed
[FAB-10451] discovery config uses MSP IDs
The discovery config returns a mapping with keys which are organization names, but it should really return keys that are the MSP IDs. This change set makes it so, and also adds a test that: - Generates the e2e_cli layout for 4 organizations: - Orderer org - BCCSP MSP org1, org2 - Idemix MSP org3 The names of the organizations in the config block are randomized, and the test ensures that: - The discovery processing ignores idemix MSPs when parsing config - The discovery processing uses the MSP IDs and not the org names. Change-Id: Ie4e15c7fa2987af3363fd7aae5183bafd22a0124 Signed-off-by: yacovm <yacovm@il.ibm.com>
1 parent e53554d commit f388cd9

File tree

2 files changed

+115
-6
lines changed

2 files changed

+115
-6
lines changed

discovery/support/config/support.go

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@ import (
1313

1414
"github.com/golang/protobuf/proto"
1515
"github.com/hyperledger/fabric/common/channelconfig"
16+
"github.com/hyperledger/fabric/common/flogging"
17+
mspconstants "github.com/hyperledger/fabric/msp"
1618
"github.com/hyperledger/fabric/protos/common"
1719
"github.com/hyperledger/fabric/protos/discovery"
1820
"github.com/hyperledger/fabric/protos/msp"
1921
"github.com/pkg/errors"
2022
)
2123

24+
var logger = flogging.MustGetLogger("discovery/config")
25+
2226
// CurrentConfigBlockGetter enables to fetch the last config block
2327
type CurrentConfigBlockGetter interface {
2428
// GetCurrConfigBlock returns the current config block for the given channel
@@ -99,8 +103,23 @@ func (s *DiscoverySupport) Config(channel string) (*discovery.ConfigResult, erro
99103

100104
func computeOrdererEndpoints(ordererGrp map[string]*common.ConfigGroup, ordererAddresses *common.OrdererAddresses) (map[string]*discovery.Endpoints, error) {
101105
res := make(map[string]*discovery.Endpoints)
102-
for ordererOrg := range ordererGrp {
103-
res[ordererOrg] = &discovery.Endpoints{}
106+
for name, group := range ordererGrp {
107+
mspConfig := &msp.MSPConfig{}
108+
if err := proto.Unmarshal(group.Values[channelconfig.MSPKey].Value, mspConfig); err != nil {
109+
return nil, errors.Wrap(err, "failed parsing MSPConfig")
110+
}
111+
// Skip non fabric MSPs, as they don't carry useful information for service discovery.
112+
// An idemix MSP shouldn't appear inside an orderer group, but this isn't a fatal error
113+
// for the discovery service and we can just ignore it.
114+
if mspConfig.Type != int32(mspconstants.FABRIC) {
115+
logger.Error("Orderer group", name, "is not a FABRIC MSP, but is of type", mspConfig.Type)
116+
continue
117+
}
118+
fabricConfig := &msp.FabricMSPConfig{}
119+
if err := proto.Unmarshal(mspConfig.Config, fabricConfig); err != nil {
120+
return nil, errors.Wrap(err, "failed marshaling FabricMSPConfig")
121+
}
122+
res[fabricConfig.Name] = &discovery.Endpoints{}
104123
for _, endpoint := range ordererAddresses.Addresses {
105124
host, portStr, err := net.SplitHostPort(endpoint)
106125
if err != nil {
@@ -110,7 +129,7 @@ func computeOrdererEndpoints(ordererGrp map[string]*common.ConfigGroup, ordererA
110129
if err != nil {
111130
return nil, errors.Errorf("%s is not a valid port number", portStr)
112131
}
113-
res[ordererOrg].Endpoint = append(res[ordererOrg].Endpoint, &discovery.Endpoint{
132+
res[fabricConfig.Name].Endpoint = append(res[fabricConfig.Name].Endpoint, &discovery.Endpoint{
114133
Host: host,
115134
Port: uint32(port),
116135
})
@@ -121,19 +140,23 @@ func computeOrdererEndpoints(ordererGrp map[string]*common.ConfigGroup, ordererA
121140

122141
func appendMSPConfigs(ordererGrp, appGrp map[string]*common.ConfigGroup, output map[string]*msp.FabricMSPConfig) error {
123142
for _, group := range []map[string]*common.ConfigGroup{ordererGrp, appGrp} {
124-
for orgID, grp := range group {
143+
for _, grp := range group {
125144
mspConfig := &msp.MSPConfig{}
126145
if err := proto.Unmarshal(grp.Values[channelconfig.MSPKey].Value, mspConfig); err != nil {
127146
return errors.Wrap(err, "failed parsing MSPConfig")
128147
}
148+
// Skip non fabric MSPs, as they don't carry useful information for service discovery
149+
if mspConfig.Type != int32(mspconstants.FABRIC) {
150+
continue
151+
}
129152
fabricConfig := &msp.FabricMSPConfig{}
130153
if err := proto.Unmarshal(mspConfig.Config, fabricConfig); err != nil {
131154
return errors.Wrap(err, "failed marshaling FabricMSPConfig")
132155
}
133-
if _, exists := output[orgID]; exists {
156+
if _, exists := output[fabricConfig.Name]; exists {
134157
continue
135158
}
136-
output[orgID] = fabricConfig
159+
output[fabricConfig.Name] = fabricConfig
137160
}
138161
}
139162

discovery/support/config/support_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,23 @@ SPDX-License-Identifier: Apache-2.0
77
package config_test
88

99
import (
10+
"crypto/rand"
11+
"encoding/hex"
12+
"fmt"
13+
"os"
14+
"os/exec"
15+
"path/filepath"
1016
"testing"
1117

1218
"github.com/golang/protobuf/proto"
1319
"github.com/hyperledger/fabric/common/channelconfig"
1420
"github.com/hyperledger/fabric/common/configtx/test"
21+
"github.com/hyperledger/fabric/common/tools/configtxgen/encoder"
22+
genesisconfig "github.com/hyperledger/fabric/common/tools/configtxgen/localconfig"
1523
"github.com/hyperledger/fabric/discovery/support/config"
1624
"github.com/hyperledger/fabric/discovery/support/mocks"
1725
"github.com/hyperledger/fabric/protos/common"
26+
"github.com/onsi/gomega/gexec"
1827
"github.com/stretchr/testify/assert"
1928
)
2029

@@ -46,6 +55,83 @@ func blockWithConfigEnvelope() *common.Block {
4655
}
4756
}
4857

58+
func TestMSPIDMapping(t *testing.T) {
59+
randString := func() string {
60+
buff := make([]byte, 10)
61+
rand.Read(buff)
62+
return hex.EncodeToString(buff)
63+
}
64+
65+
dir := filepath.Join(os.TempDir(), fmt.Sprintf("TestMSPIDMapping_%s", randString()))
66+
os.Mkdir(dir, 0700)
67+
defer os.RemoveAll(dir)
68+
69+
cryptogen, err := gexec.Build(filepath.Join("github.com", "hyperledger", "fabric", "common", "tools", "cryptogen"))
70+
assert.NoError(t, err)
71+
defer os.Remove(cryptogen)
72+
73+
idemixgen, err := gexec.Build(filepath.Join("github.com", "hyperledger", "fabric", "common", "tools", "idemixgen"))
74+
assert.NoError(t, err)
75+
defer os.Remove(idemixgen)
76+
77+
cryptoConfigDir := filepath.Join(dir, "crypto-config")
78+
b, err := exec.Command(cryptogen, "generate", fmt.Sprintf("--output=%s", cryptoConfigDir)).CombinedOutput()
79+
assert.NoError(t, err, string(b))
80+
81+
idemixConfigDir := filepath.Join(dir, "crypto-config", "idemix")
82+
b, err = exec.Command(idemixgen, "ca-keygen", fmt.Sprintf("--output=%s", idemixConfigDir)).CombinedOutput()
83+
assert.NoError(t, err, string(b))
84+
85+
profileConfig := genesisconfig.Load("TwoOrgsChannel", "../../../examples/e2e_cli/")
86+
ordererConfig := genesisconfig.Load("TwoOrgsOrdererGenesis", "../../../examples/e2e_cli/")
87+
profileConfig.Orderer = ordererConfig.Orderer
88+
89+
// Override the MSP directory with our randomly generated and populated path
90+
for _, org := range ordererConfig.Orderer.Organizations {
91+
org.MSPDir = filepath.Join(cryptoConfigDir, "ordererOrganizations", "example.com", "msp")
92+
org.Name = randString()
93+
}
94+
95+
// Randomize organization names
96+
for _, org := range profileConfig.Application.Organizations {
97+
org.Name = randString()
98+
// Non bccsp-msp orgs don't have the crypto material produced by cryptogen,
99+
// we need to use the idemix crypto folder instead.
100+
if org.MSPType != "bccsp" {
101+
org.MSPDir = filepath.Join(idemixConfigDir)
102+
continue
103+
}
104+
org.MSPDir = filepath.Join(cryptoConfigDir, "peerOrganizations", "org1.example.com", "msp")
105+
}
106+
107+
gen := encoder.New(profileConfig)
108+
block := gen.GenesisBlockForChannel("mychannel")
109+
110+
fakeBlockGetter := &mocks.ConfigBlockGetter{}
111+
fakeBlockGetter.GetCurrConfigBlockReturnsOnCall(0, block)
112+
113+
cs := config.NewDiscoverySupport(fakeBlockGetter)
114+
res, err := cs.Config("mychannel")
115+
116+
actualKeys := make(map[string]struct{})
117+
for key := range res.Orderers {
118+
actualKeys[key] = struct{}{}
119+
}
120+
121+
for key := range res.Msps {
122+
actualKeys[key] = struct{}{}
123+
}
124+
125+
// Note that Org3MSP is an idemix org, but it shouldn't be listed here
126+
// because peers can't have idemix credentials
127+
expected := map[string]struct{}{
128+
"OrdererMSP": {},
129+
"Org1MSP": {},
130+
"Org2MSP": {},
131+
}
132+
assert.Equal(t, expected, actualKeys)
133+
}
134+
49135
func TestSupportGreenPath(t *testing.T) {
50136
fakeBlockGetter := &mocks.ConfigBlockGetter{}
51137
fakeBlockGetter.GetCurrConfigBlockReturnsOnCall(0, nil)

0 commit comments

Comments
 (0)