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

Commit 231ec6c

Browse files
committed
[FAB-6981] Channel Management Client
Channel management client is responsible for managing channels(create/update). Change-Id: Ib2cb7dbc2496b7e081785f6fda73678637899821 Signed-off-by: Sandra Vrtikapa <sandra.vrtikapa@securekey.com>
1 parent 23a0767 commit 231ec6c

File tree

20 files changed

+501
-104
lines changed

20 files changed

+501
-104
lines changed

api/apifabclient/fabricclient.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ type FabricClient interface {
3535
NewChannel(name string) (Channel, error)
3636
Channel(name string) Channel
3737
ExtractChannelConfig(configEnvelope []byte) ([]byte, error)
38-
SignChannelConfig(config []byte) (*common.ConfigSignature, error)
38+
SignChannelConfig(config []byte, signer User) (*common.ConfigSignature, error)
3939
CreateChannel(request CreateChannelRequest) (txn.TransactionID, error)
4040
QueryChannelInfo(name string, peers []Peer) (Channel, error)
4141
StateStore() KeyValueStore

api/apitxn/chmgmtclient/chmgmt.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
Copyright SecureKey Technologies Inc. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package chmgmtclient
8+
9+
import fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
10+
11+
// SaveChannelRequest contains parameters for creating or updating channel
12+
type SaveChannelRequest struct {
13+
// Channel Name (ID)
14+
ChannelID string
15+
// Path to channel configuration file
16+
ChannelConfig string
17+
// User that signs channel configuration
18+
SigningUser fab.User
19+
}
20+
21+
// SaveChannelOpts contains options for saving channel
22+
type SaveChannelOpts struct {
23+
OrdererID string // use specific orderer
24+
}
25+
26+
// ChannelMgmtClient supports creating new channels
27+
type ChannelMgmtClient interface {
28+
29+
// SaveChannel creates or updates channel
30+
SaveChannel(req SaveChannelRequest) error
31+
32+
// SaveChannel creates or updates channel with custom options
33+
SaveChannelWithOpts(req SaveChannelRequest, opts SaveChannelOpts) error
34+
}

def/fabapi/context/defprovider/session.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import (
1010
"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
1111
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
1212
"github.com/hyperledger/fabric-sdk-go/api/apitxn"
13-
13+
chmgmt "github.com/hyperledger/fabric-sdk-go/api/apitxn/chmgmtclient"
1414
"github.com/hyperledger/fabric-sdk-go/def/fabapi/context"
15+
1516
"github.com/hyperledger/fabric-sdk-go/pkg/errors"
1617
clientImpl "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client"
1718
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/events"
1819
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/orderer"
1920
chImpl "github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/chclient"
21+
chmgmtImpl "github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/chmgmtclient"
2022
)
2123

2224
// SessionClientFactory represents the default implementation of a session client.
@@ -40,6 +42,16 @@ func (f *SessionClientFactory) NewSystemClient(sdk context.SDK, session context.
4042
return client, nil
4143
}
4244

45+
// NewChannelMgmtClient returns a client that manages channels (create/join channel)
46+
func (f *SessionClientFactory) NewChannelMgmtClient(sdk context.SDK, session context.Session, config apiconfig.Config) (chmgmt.ChannelMgmtClient, error) {
47+
// For now settings are the same as for system client
48+
client, err := f.NewSystemClient(sdk, session, config)
49+
if err != nil {
50+
return nil, err
51+
}
52+
return chmgmtImpl.NewChannelMgmtClient(client, config)
53+
}
54+
4355
// NewChannelClient returns a client that can execute transactions on specified channel
4456
func (f *SessionClientFactory) NewChannelClient(sdk context.SDK, session context.Session, config apiconfig.Config, channelID string) (apitxn.ChannelClient, error) {
4557

@@ -82,9 +94,9 @@ func getChannel(client fab.FabricClient, channelID string) (fab.Channel, error)
8294
return nil, errors.WithMessage(err, "NewChannel failed")
8395
}
8496

85-
_, err = client.Config().ChannelConfig(channel.Name())
86-
if err != nil {
87-
return nil, errors.WithMessage(err, "reading channel config failed")
97+
chCfg, err := client.Config().ChannelConfig(channel.Name())
98+
if err != nil || chCfg == nil {
99+
return nil, errors.Errorf("reading channel config failed: %s", err)
88100
}
89101

90102
chOrderers, err := client.Config().ChannelOrderers(channel.Name())

def/fabapi/context/provider.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
fabca "github.com/hyperledger/fabric-sdk-go/api/apifabca"
1212
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
1313
txn "github.com/hyperledger/fabric-sdk-go/api/apitxn"
14+
chmgmt "github.com/hyperledger/fabric-sdk-go/api/apitxn/chmgmtclient"
1415
"github.com/hyperledger/fabric-sdk-go/def/fabapi/opt"
1516
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp"
1617
bccspFactory "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp/factory"
@@ -36,5 +37,6 @@ type OrgClientFactory interface {
3637
// SessionClientFactory allows overriding default clients and providers of a session
3738
type SessionClientFactory interface {
3839
NewSystemClient(context SDK, session Session, config apiconfig.Config) (fab.FabricClient, error)
40+
NewChannelMgmtClient(context SDK, session Session, config apiconfig.Config) (chmgmt.ChannelMgmtClient, error)
3941
NewChannelClient(context SDK, session Session, config apiconfig.Config, channelID string) (txn.ChannelClient, error)
4042
}

def/fabapi/fabapi.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
"github.com/hyperledger/fabric-sdk-go/pkg/logging"
2020
"github.com/hyperledger/fabric-sdk-go/pkg/logging/deflogger"
2121
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp"
22+
23+
chmgmt "github.com/hyperledger/fabric-sdk-go/api/apitxn/chmgmtclient"
2224
)
2325

2426
// Options encapsulates configuration for the SDK
@@ -58,6 +60,12 @@ type ChannelClientOpts struct {
5860
ConfigProvider apiconfig.Config
5961
}
6062

63+
// ChannelMgmtClientOpts provides options for creating channel management client
64+
type ChannelMgmtClientOpts struct {
65+
OrgName string
66+
ConfigProvider apiconfig.Config
67+
}
68+
6169
// ProviderInit interface allows for initializing providers
6270
type ProviderInit interface {
6371
Initialize(sdk *FabricSDK) error
@@ -195,6 +203,49 @@ func (sdk *FabricSDK) NewSystemClient(s context.Session) (apifabclient.FabricCli
195203
return client, nil
196204
}
197205

206+
// NewChannelMgmtClient returns a new client for managing channels
207+
func (sdk *FabricSDK) NewChannelMgmtClient(userName string) (chmgmt.ChannelMgmtClient, error) {
208+
209+
// Read default org name from configuration
210+
client, err := sdk.configProvider.Client()
211+
if err != nil {
212+
return nil, errors.WithMessage(err, "unable to retrieve client from network config")
213+
}
214+
215+
if client.Organization == "" {
216+
return nil, errors.New("must provide default organisation name in configuration")
217+
}
218+
219+
opt := &ChannelMgmtClientOpts{OrgName: client.Organization, ConfigProvider: sdk.configProvider}
220+
221+
return sdk.NewChannelMgmtClientWithOpts(userName, opt)
222+
}
223+
224+
// NewChannelMgmtClientWithOpts returns a new client for managing channels with options
225+
func (sdk *FabricSDK) NewChannelMgmtClientWithOpts(userName string, opt *ChannelMgmtClientOpts) (chmgmt.ChannelMgmtClient, error) {
226+
227+
if opt == nil || opt.OrgName == "" {
228+
return nil, errors.New("organization name must be provided")
229+
}
230+
231+
session, err := sdk.NewPreEnrolledUserSession(opt.OrgName, userName)
232+
if err != nil {
233+
return nil, errors.WithMessage(err, "failed to get pre-enrolled user session")
234+
}
235+
236+
configProvider := sdk.ConfigProvider()
237+
if opt.ConfigProvider != nil {
238+
configProvider = opt.ConfigProvider
239+
}
240+
241+
client, err := sdk.SessionFactory.NewChannelMgmtClient(sdk, session, configProvider)
242+
if err != nil {
243+
return nil, errors.WithMessage(err, "failed to create new channel management client")
244+
}
245+
246+
return client, nil
247+
}
248+
198249
// NewChannelClient returns a new client for a channel
199250
func (sdk *FabricSDK) NewChannelClient(channelID string, userName string) (apitxn.ChannelClient, error) {
200251

def/fabapi/fabapi_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,30 @@ func TestNewDefaultSDK(t *testing.T) {
5252
t.Fatalf("Failed to create new channel client: %s", err)
5353
}
5454

55+
// Test configuration failure for channel management client (invalid user/default organisation)
56+
_, err = sdk.NewChannelMgmtClient("Invalid")
57+
if err == nil {
58+
t.Fatalf("Should have failed to create channel client due to invalid user")
59+
}
60+
61+
// Test valid configuration for channel management client
62+
_, err = sdk.NewChannelMgmtClient("Admin")
63+
if err != nil {
64+
t.Fatalf("Failed to create new channel client: %s", err)
65+
}
66+
67+
// Test configuration failure for new channel management client with options (invalid org)
68+
_, err = sdk.NewChannelMgmtClientWithOpts("Admin", &ChannelMgmtClientOpts{OrgName: "Invalid"})
69+
if err == nil {
70+
t.Fatalf("Should have failed to create channel client due to invalid organisation")
71+
}
72+
73+
// Test new channel management client with options (orderer admin configuration)
74+
_, err = sdk.NewChannelMgmtClientWithOpts("Admin", &ChannelMgmtClientOpts{OrgName: "ordererorg"})
75+
if err != nil {
76+
t.Fatalf("Failed to create new channel client with opts: %s", err)
77+
}
78+
5579
}
5680

5781
func TestNewDefaultTwoValidSDK(t *testing.T) {

def/fabapi/session.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
fabca "github.com/hyperledger/fabric-sdk-go/api/apifabca"
1212
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
1313
"github.com/hyperledger/fabric-sdk-go/def/fabapi/context"
14-
"github.com/hyperledger/fabric-sdk-go/pkg/errors"
1514
)
1615

1716
// OrgContext currently represents the clients for an organization that the app is dealing with.
@@ -24,12 +23,16 @@ type OrgContext struct {
2423
func NewOrgContext(factory context.OrgClientFactory, orgID string, config apiconfig.Config) (*OrgContext, error) {
2524
c := OrgContext{}
2625

27-
// Initialize MSP client
28-
client, err := factory.NewMSPClient(orgID, config)
29-
if err != nil {
30-
return nil, errors.WithMessage(err, "MSP client init failed")
31-
}
32-
c.mspClient = client
26+
// TODO: Evaluate context contents during credential client design
27+
28+
/*
29+
// Initialize MSP client
30+
client, err := factory.NewMSPClient(orgID, config)
31+
if err != nil {
32+
return nil, errors.WithMessage(err, "MSP client init failed")
33+
}
34+
c.mspClient = client
35+
*/
3336

3437
return &c, nil
3538
}

pkg/config/config.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,11 @@ func (c *Config) OrdererConfig(name string) (*apiconfig.OrdererConfig, error) {
342342
if err != nil {
343343
return nil, err
344344
}
345-
orderer := config.Orderers[strings.ToLower(name)]
345+
orderer, ok := config.Orderers[strings.ToLower(name)]
346+
if !ok {
347+
return nil, nil
348+
}
349+
346350
if orderer.TLSCACerts.Path != "" {
347351
orderer.TLSCACerts.Path = strings.Replace(orderer.TLSCACerts.Path, "$GOPATH",
348352
os.Getenv("GOPATH"), -1)
@@ -394,7 +398,12 @@ func (c *Config) PeerConfig(org string, name string) (*apiconfig.PeerConfig, err
394398
if !peerInOrg {
395399
return nil, errors.Errorf("peer %s is not part of organization %s", name, org)
396400
}
397-
peerConfig := config.Peers[strings.ToLower(name)]
401+
402+
peerConfig, ok := config.Peers[strings.ToLower(name)]
403+
if !ok {
404+
return nil, nil
405+
}
406+
398407
if peerConfig.TLSCACerts.Path != "" {
399408
peerConfig.TLSCACerts.Path = strings.Replace(peerConfig.TLSCACerts.Path, "$GOPATH",
400409
os.Getenv("GOPATH"), -1)
@@ -424,7 +433,7 @@ func (c *Config) ChannelConfig(name string) (*apiconfig.ChannelConfig, error) {
424433
// viper lowercases all key maps
425434
ch, ok := config.Channels[strings.ToLower(name)]
426435
if !ok {
427-
return nil, errors.Errorf("channel config not found for %s", name)
436+
return nil, nil
428437
}
429438

430439
return &ch, nil
@@ -434,15 +443,16 @@ func (c *Config) ChannelConfig(name string) (*apiconfig.ChannelConfig, error) {
434443
func (c *Config) ChannelOrderers(name string) ([]apiconfig.OrdererConfig, error) {
435444
orderers := []apiconfig.OrdererConfig{}
436445
channel, err := c.ChannelConfig(name)
437-
if err != nil {
438-
return nil, err
446+
if err != nil || channel == nil {
447+
return nil, errors.Errorf("Unable to retrieve channel config: %s", err)
439448
}
440449

441450
for _, chOrderer := range channel.Orderers {
442451
orderer, err := c.OrdererConfig(chOrderer)
443-
if err != nil {
444-
return nil, errors.Errorf("orderer config not found for channel orderer: %s", chOrderer)
452+
if err != nil || orderer == nil {
453+
return nil, errors.Errorf("unable to retrieve orderer config: %s", err)
445454
}
455+
446456
orderers = append(orderers, *orderer)
447457
}
448458

pkg/config/config_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,10 +356,10 @@ func TestOrdererConfig(t *testing.T) {
356356
t.Fatal("Testing get RandomOrdererConfig failed")
357357
}
358358

359-
oConfig, err = configImpl.OrdererConfig("peerorg1")
359+
oConfig, err = configImpl.OrdererConfig("invalid")
360360

361-
if oConfig == nil || err != nil {
362-
t.Fatal("Testing get OrdererConfig failed")
361+
if oConfig != nil || err != nil {
362+
t.Fatal("Testing non-existing OrdererConfig failed")
363363
}
364364

365365
orderers, err := configImpl.OrderersConfig()

pkg/fabric-client/client.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -244,17 +244,24 @@ func (c *Client) ExtractChannelConfig(configEnvelope []byte) ([]byte, error) {
244244
* @param {byte[]} config - The Configuration Update in byte form
245245
* @return {ConfigSignature} - The signature of the current user on the config bytes
246246
*/
247-
func (c *Client) SignChannelConfig(config []byte) (*common.ConfigSignature, error) {
247+
func (c *Client) SignChannelConfig(config []byte, signer fab.User) (*common.ConfigSignature, error) {
248248
logger.Debug("SignChannelConfig - start")
249249

250250
if config == nil {
251251
return nil, errors.New("channel configuration required")
252252
}
253253

254-
if c.userContext == nil {
254+
signingUser := signer
255+
// If signing user is not provided default to client's user context
256+
if signingUser == nil {
257+
signingUser = c.userContext
258+
}
259+
260+
if signingUser == nil {
255261
return nil, errors.New("user context required")
256262
}
257-
creator, err := c.userContext.Identity()
263+
264+
creator, err := signingUser.Identity()
258265
if err != nil {
259266
return nil, errors.WithMessage(err, "failed to get user context's identity")
260267
}
@@ -273,19 +280,14 @@ func (c *Client) SignChannelConfig(config []byte) (*common.ConfigSignature, erro
273280
return nil, errors.Wrap(err, "marshal signatureHeader failed")
274281
}
275282

276-
user := c.UserContext()
277-
if user == nil {
278-
return nil, errors.New("UserContext is nil")
279-
}
280-
281283
signingMgr := c.SigningManager()
282284
if signingMgr == nil {
283285
return nil, errors.New("signing manager is nil")
284286
}
285287

286288
// get all the bytes to be signed together, then sign
287289
signingBytes := fcutils.ConcatenateBytes(signatureHeaderBytes, config)
288-
signature, err := signingMgr.Sign(signingBytes, user.PrivateKey())
290+
signature, err := signingMgr.Sign(signingBytes, signingUser.PrivateKey())
289291
if err != nil {
290292
return nil, errors.WithMessage(err, "signing of channel config failed")
291293
}

0 commit comments

Comments
 (0)