Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Commit c776993

Browse files
committed
[FAB-10178] Add Capabilities to Channel Config
Added capabilities to Channel Config. Users can query the channel config whether or not a capability is supported for a particular config group. Change-Id: I758036401bebb9223b84319c51f8c75b52a374e5 Signed-off-by: Bob Stasyszyn <Bob.Stasyszyn@securekey.com>
1 parent f3fee0e commit c776993

23 files changed

+302
-30
lines changed

pkg/common/providers/fab/channel.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,25 @@ type ChannelConfig interface {
2727
Query(reqCtx reqContext.Context) (ChannelCfg, error)
2828
}
2929

30+
// ConfigGroupKey is the config group key
31+
type ConfigGroupKey string
32+
33+
const (
34+
// ChannelGroupKey is the Channel config group key
35+
ChannelGroupKey ConfigGroupKey = ""
36+
// OrdererGroupKey is the Orderer config group key
37+
OrdererGroupKey ConfigGroupKey = "Orderer"
38+
// ApplicationGroupKey is the Application config group key
39+
ApplicationGroupKey ConfigGroupKey = "Application"
40+
)
41+
42+
const (
43+
// V1_1Capability indicates that Fabric 1.1 features are supported
44+
V1_1Capability = "V1_1"
45+
// V1_2Capability indicates that Fabric 1.2 features are supported
46+
V1_2Capability = "V1_2"
47+
)
48+
3049
// ChannelCfg contains channel configuration
3150
type ChannelCfg interface {
3251
ID() string
@@ -35,6 +54,7 @@ type ChannelCfg interface {
3554
AnchorPeers() []*OrgAnchorPeer
3655
Orderers() []string
3756
Versions() *Versions
57+
HasCapability(group ConfigGroupKey, capability string) bool
3858
}
3959

4060
// ChannelMembership helps identify a channel's members

pkg/fab/chconfig/chconfig.go

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,13 @@ type ChannelConfig struct {
6565

6666
// ChannelCfg contains channel configuration
6767
type ChannelCfg struct {
68-
id string
69-
blockNumber uint64
70-
msps []*mb.MSPConfig
71-
anchorPeers []*fab.OrgAnchorPeer
72-
orderers []string
73-
versions *fab.Versions
68+
id string
69+
blockNumber uint64
70+
msps []*mb.MSPConfig
71+
anchorPeers []*fab.OrgAnchorPeer
72+
orderers []string
73+
versions *fab.Versions
74+
capabilities map[fab.ConfigGroupKey]map[string]bool
7475
}
7576

7677
// NewChannelCfg creates channel cfg
@@ -109,6 +110,22 @@ func (cfg *ChannelCfg) Versions() *fab.Versions {
109110
return cfg.versions
110111
}
111112

113+
// HasCapability indicates whether or not the given group has the given capability
114+
func (cfg *ChannelCfg) HasCapability(group fab.ConfigGroupKey, capability string) bool {
115+
groupCapabilities, ok := cfg.capabilities[group]
116+
if !ok {
117+
return false
118+
}
119+
if groupCapabilities[capability] {
120+
return true
121+
}
122+
if capability == fab.V1_1Capability {
123+
// If V1_2 capability is supported then V1_1 is also supported
124+
return groupCapabilities[fab.V1_2Capability]
125+
}
126+
return false
127+
}
128+
112129
// New channel config implementation
113130
func New(channelID string, options ...Option) (*ChannelConfig, error) {
114131
opts, err := prepareOpts(options...)
@@ -130,7 +147,6 @@ func (c *ChannelConfig) Query(reqCtx reqContext.Context) (fab.ChannelCfg, error)
130147
}
131148

132149
func (c *ChannelConfig) queryPeers(reqCtx reqContext.Context) (*ChannelCfg, error) {
133-
134150
ctx, ok := contextImpl.RequestClientContext(reqCtx)
135151
if !ok {
136152
return nil, errors.New("failed get client context from reqContext for signPayload")
@@ -351,15 +367,16 @@ func extractConfig(channelID string, block *common.Block) (*ChannelCfg, error) {
351367
}
352368

353369
config := &ChannelCfg{
354-
id: channelID,
355-
blockNumber: block.Header.Number,
356-
msps: []*mb.MSPConfig{},
357-
anchorPeers: []*fab.OrgAnchorPeer{},
358-
orderers: []string{},
359-
versions: versions,
370+
id: channelID,
371+
blockNumber: block.Header.Number,
372+
msps: []*mb.MSPConfig{},
373+
anchorPeers: []*fab.OrgAnchorPeer{},
374+
orderers: []string{},
375+
versions: versions,
376+
capabilities: make(map[fab.ConfigGroupKey]map[string]bool),
360377
}
361378

362-
err = loadConfig(config, config.versions.Channel, group, "base", "")
379+
err = loadConfig(config, config.versions.Channel, group, "", "")
363380
if err != nil {
364381
return nil, errors.WithMessage(err, "load config items from config group failed")
365382
}
@@ -387,7 +404,7 @@ func loadConfig(configItems *ChannelCfg, versionsGroup *common.ConfigGroup, grou
387404
logger.Debugf("loadConfigGroup - %s - found config group ==> %s", name, key)
388405
// The Application group is where config settings are that we want to find
389406
versionsGroup.Groups[key] = &common.ConfigGroup{}
390-
err := loadConfig(configItems, versionsGroup.Groups[key], configGroup, name+"."+key, key)
407+
err := loadConfig(configItems, versionsGroup.Groups[key], configGroup, key, key)
391408
if err != nil {
392409
return err
393410
}
@@ -540,6 +557,21 @@ func loadOrdererAddressesKey(configValue *common.ConfigValue, configItems *Chann
540557

541558
}
542559

560+
func loadCapabilities(configValue *common.ConfigValue, configItems *ChannelCfg, groupName string) error {
561+
capabilities := &common.Capabilities{}
562+
err := proto.Unmarshal(configValue.Value, capabilities)
563+
if err != nil {
564+
return errors.Wrap(err, "unmarshal capabilities from config failed")
565+
}
566+
capabilityMap := make(map[string]bool)
567+
for capability := range capabilities.Capabilities {
568+
logger.Debugf("Adding capability for group [%s]: [%s]", groupName, capability)
569+
capabilityMap[capability] = true
570+
}
571+
configItems.capabilities[fab.ConfigGroupKey(groupName)] = capabilityMap
572+
return nil
573+
}
574+
543575
func loadConfigValue(configItems *ChannelCfg, key string, versionsValue *common.ConfigValue, configValue *common.ConfigValue, groupName string, org string) error {
544576
logger.Debugf("loadConfigValue - %s - START value name: %s", groupName, key)
545577
logger.Debugf("loadConfigValue - %s - version: %d", groupName, configValue.Version)
@@ -556,6 +588,10 @@ func loadConfigValue(configItems *ChannelCfg, key string, versionsValue *common.
556588
if err := loadMSPKey(configValue, configItems, groupName); err != nil {
557589
return err
558590
}
591+
case channelConfig.CapabilitiesKey:
592+
if err := loadCapabilities(configValue, configItems, groupName); err != nil {
593+
return err
594+
}
559595
//case channelConfig.ConsensusTypeKey:
560596
// consensusType := &ab.ConsensusType{}
561597
// err := proto.Unmarshal(configValue.Value, consensusType)

pkg/fab/chconfig/chconfig_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
2727
fabImpl "github.com/hyperledger/fabric-sdk-go/pkg/fab"
2828
"github.com/stretchr/testify/assert"
29+
"github.com/stretchr/testify/require"
2930
)
3031

3132
const (
@@ -233,6 +234,39 @@ func TestResolveOptsDefaultValuesWithInvalidChannel(t *testing.T) {
233234
testResolveOptsDefaultValues(t, "INVALID-CHANNEL-ID")
234235
}
235236

237+
func TestCapabilities(t *testing.T) {
238+
capability1 := fab.V1_1Capability
239+
capability2 := fab.V1_2Capability
240+
capability3 := "V1_1_PVTDATA_EXPERIMENTAL"
241+
capability4 := "V1_1_RESOURCETREE_EXPERIMENTAL"
242+
243+
builder := &mocks.MockConfigBlockBuilder{
244+
MockConfigGroupBuilder: mocks.MockConfigGroupBuilder{
245+
ModPolicy: "Admins",
246+
MSPNames: []string{
247+
"Org1MSP",
248+
"Org2MSP",
249+
},
250+
OrdererAddress: "localhost:9999",
251+
RootCA: validRootCA,
252+
ChannelCapabilities: []string{capability1},
253+
OrdererCapabilities: []string{capability1},
254+
ApplicationCapabilities: []string{capability2, capability3},
255+
},
256+
Index: 0,
257+
LastConfigIndex: 0,
258+
}
259+
260+
chConfig, err := extractConfig("mychannel", builder.Build())
261+
require.NoError(t, err)
262+
263+
assert.Truef(t, chConfig.HasCapability(fab.ChannelGroupKey, capability1), "expecting channel capability [%s]", capability1)
264+
assert.Truef(t, chConfig.HasCapability(fab.OrdererGroupKey, capability1), "expecting orderer capability [%s]", capability1)
265+
assert.Truef(t, chConfig.HasCapability(fab.ApplicationGroupKey, capability2), "expecting application capability [%s]", capability2)
266+
assert.Truef(t, chConfig.HasCapability(fab.ApplicationGroupKey, capability3), "expecting application capability [%s]", capability3)
267+
assert.Falsef(t, chConfig.HasCapability(fab.ApplicationGroupKey, capability4), "not expecting application capability [%s]", capability4)
268+
}
269+
236270
func testResolveOptsDefaultValues(t *testing.T, channelID string) {
237271
user := mspmocks.NewMockSigningIdentity("test", "test")
238272
ctx := mocks.NewMockContext(user)

pkg/fab/mocks/mockchconfig.go

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,27 @@ import (
1616

1717
// MockChannelCfg contains mock channel configuration
1818
type MockChannelCfg struct {
19-
MockID string
20-
MockBlockNumber uint64
21-
MockMSPs []*msp.MSPConfig
22-
MockAnchorPeers []*fab.OrgAnchorPeer
23-
MockOrderers []string
24-
MockVersions *fab.Versions
25-
MockMembership fab.ChannelMembership
19+
MockID string
20+
MockBlockNumber uint64
21+
MockMSPs []*msp.MSPConfig
22+
MockAnchorPeers []*fab.OrgAnchorPeer
23+
MockOrderers []string
24+
MockVersions *fab.Versions
25+
MockMembership fab.ChannelMembership
26+
MockCapabilities map[fab.ConfigGroupKey]map[string]bool
2627
}
2728

2829
// NewMockChannelCfg ...
2930
func NewMockChannelCfg(id string) *MockChannelCfg {
30-
return &MockChannelCfg{MockID: id}
31+
capabilities := make(map[fab.ConfigGroupKey]map[string]bool)
32+
capabilities[fab.ChannelGroupKey] = make(map[string]bool)
33+
capabilities[fab.ApplicationGroupKey] = make(map[string]bool)
34+
capabilities[fab.OrdererGroupKey] = make(map[string]bool)
35+
36+
return &MockChannelCfg{
37+
MockID: id,
38+
MockCapabilities: capabilities,
39+
}
3140
}
3241

3342
// ID returns name
@@ -60,6 +69,15 @@ func (cfg *MockChannelCfg) Versions() *fab.Versions {
6069
return cfg.MockVersions
6170
}
6271

72+
// HasCapability indicates whether or not the given group has the given capability
73+
func (cfg *MockChannelCfg) HasCapability(group fab.ConfigGroupKey, capability string) bool {
74+
capabilities, ok := cfg.MockCapabilities[group]
75+
if !ok {
76+
return false
77+
}
78+
return capabilities[capability]
79+
}
80+
6381
// MockChannelConfig mockcore query channel configuration
6482
type MockChannelConfig struct {
6583
channelID string

pkg/fab/mocks/mockdata.go

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,15 @@ func NewMockGenesisBlock() *common.Block {
5353

5454
// MockConfigGroupBuilder is used to build a mock ConfigGroup
5555
type MockConfigGroupBuilder struct {
56-
Version uint64
57-
ModPolicy string
58-
OrdererAddress string
59-
MSPNames []string
60-
RootCA string
61-
Groups map[string]*common.ConfigGroup
56+
Version uint64
57+
ModPolicy string
58+
OrdererAddress string
59+
MSPNames []string
60+
RootCA string
61+
Groups map[string]*common.ConfigGroup
62+
ChannelCapabilities []string
63+
ApplicationCapabilities []string
64+
OrdererCapabilities []string
6265
}
6366

6467
// MockConfigBlockBuilder is used to build a mock Chain configuration block
@@ -180,6 +183,7 @@ func (b *MockConfigGroupBuilder) buildConfigGroup() *common.ConfigGroup {
180183
},
181184
Values: map[string]*common.ConfigValue{
182185
channelConfig.OrdererAddressesKey: b.buildOrdererAddressesConfigValue(),
186+
channelConfig.CapabilitiesKey: b.buildCapabilitiesConfigValue(b.ChannelCapabilities),
183187
},
184188
Version: b.Version,
185189
ModPolicy: b.ModPolicy,
@@ -218,6 +222,7 @@ func (b *MockConfigGroupBuilder) buildOrdererGroup() *common.ConfigGroup {
218222
channelConfig.ChannelRestrictionsKey: b.buildChannelRestrictionsConfigValue(),
219223
channelConfig.HashingAlgorithmKey: b.buildHashingAlgorithmConfigValue(),
220224
channelConfig.BlockDataHashingStructureKey: b.buildBlockDataHashingStructureConfigValue(),
225+
channelConfig.CapabilitiesKey: b.buildCapabilitiesConfigValue(b.OrdererCapabilities),
221226
},
222227
Version: b.Version,
223228
ModPolicy: b.ModPolicy,
@@ -297,6 +302,13 @@ func (b *MockConfigGroupBuilder) buildBlockDataHashingStructureConfigValue() *co
297302
Value: marshalOrPanic(b.buildBlockDataHashingStructure())}
298303
}
299304

305+
func (b *MockConfigGroupBuilder) buildCapabilitiesConfigValue(capabilityNames []string) *common.ConfigValue {
306+
return &common.ConfigValue{
307+
Version: b.Version,
308+
ModPolicy: b.ModPolicy,
309+
Value: marshalOrPanic(b.buildCapabilities(capabilityNames))}
310+
}
311+
300312
func (b *MockConfigGroupBuilder) buildBatchSize() *ab.BatchSize {
301313
return &ab.BatchSize{
302314
MaxMessageCount: 10,
@@ -342,6 +354,16 @@ func (b *MockConfigGroupBuilder) buildBlockDataHashingStructure() *common.BlockD
342354
}
343355
}
344356

357+
func (b *MockConfigGroupBuilder) buildCapabilities(capabilityNames []string) *common.Capabilities {
358+
capabilities := make(map[string]*common.Capability)
359+
for _, capability := range capabilityNames {
360+
capabilities[capability] = &common.Capability{}
361+
}
362+
return &common.Capabilities{
363+
Capabilities: capabilities,
364+
}
365+
}
366+
345367
func (b *MockConfigGroupBuilder) buildMSPConfig(name string) *mb.MSPConfig {
346368
return &mb.MSPConfig{
347369
Type: 0,
@@ -406,7 +428,8 @@ func (b *MockConfigGroupBuilder) buildApplicationGroup() *common.ConfigGroup {
406428
"Readers": b.buildSignatureConfigPolicy(),
407429
},
408430
Values: map[string]*common.ConfigValue{
409-
channelConfig.BatchSizeKey: b.buildBatchSizeConfigValue(),
431+
channelConfig.BatchSizeKey: b.buildBatchSizeConfigValue(),
432+
channelConfig.CapabilitiesKey: b.buildCapabilitiesConfigValue(b.ApplicationCapabilities),
410433
// TODO: More
411434
},
412435
Version: b.Version,
38 Bytes
Binary file not shown.
38 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.
38 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)