Skip to content

Commit

Permalink
[FAB-6981] Channel Management Client
Browse files Browse the repository at this point in the history
Channel management client is responsible for managing channels(create/update).

Change-Id: Ib2cb7dbc2496b7e081785f6fda73678637899821
Signed-off-by: Sandra Vrtikapa <[email protected]>
  • Loading branch information
sandrask committed Nov 16, 2017
1 parent 23a0767 commit 231ec6c
Show file tree
Hide file tree
Showing 20 changed files with 501 additions and 104 deletions.
2 changes: 1 addition & 1 deletion api/apifabclient/fabricclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type FabricClient interface {
NewChannel(name string) (Channel, error)
Channel(name string) Channel
ExtractChannelConfig(configEnvelope []byte) ([]byte, error)
SignChannelConfig(config []byte) (*common.ConfigSignature, error)
SignChannelConfig(config []byte, signer User) (*common.ConfigSignature, error)
CreateChannel(request CreateChannelRequest) (txn.TransactionID, error)
QueryChannelInfo(name string, peers []Peer) (Channel, error)
StateStore() KeyValueStore
Expand Down
34 changes: 34 additions & 0 deletions api/apitxn/chmgmtclient/chmgmt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package chmgmtclient

import fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"

// SaveChannelRequest contains parameters for creating or updating channel
type SaveChannelRequest struct {
// Channel Name (ID)
ChannelID string
// Path to channel configuration file
ChannelConfig string
// User that signs channel configuration
SigningUser fab.User
}

// SaveChannelOpts contains options for saving channel
type SaveChannelOpts struct {
OrdererID string // use specific orderer
}

// ChannelMgmtClient supports creating new channels
type ChannelMgmtClient interface {

// SaveChannel creates or updates channel
SaveChannel(req SaveChannelRequest) error

// SaveChannel creates or updates channel with custom options
SaveChannelWithOpts(req SaveChannelRequest, opts SaveChannelOpts) error
}
20 changes: 16 additions & 4 deletions def/fabapi/context/defprovider/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import (
"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
"github.com/hyperledger/fabric-sdk-go/api/apitxn"

chmgmt "github.com/hyperledger/fabric-sdk-go/api/apitxn/chmgmtclient"
"github.com/hyperledger/fabric-sdk-go/def/fabapi/context"

"github.com/hyperledger/fabric-sdk-go/pkg/errors"
clientImpl "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client"
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/events"
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/orderer"
chImpl "github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/chclient"
chmgmtImpl "github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/chmgmtclient"
)

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

// NewChannelMgmtClient returns a client that manages channels (create/join channel)
func (f *SessionClientFactory) NewChannelMgmtClient(sdk context.SDK, session context.Session, config apiconfig.Config) (chmgmt.ChannelMgmtClient, error) {
// For now settings are the same as for system client
client, err := f.NewSystemClient(sdk, session, config)
if err != nil {
return nil, err
}
return chmgmtImpl.NewChannelMgmtClient(client, config)
}

// NewChannelClient returns a client that can execute transactions on specified channel
func (f *SessionClientFactory) NewChannelClient(sdk context.SDK, session context.Session, config apiconfig.Config, channelID string) (apitxn.ChannelClient, error) {

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

_, err = client.Config().ChannelConfig(channel.Name())
if err != nil {
return nil, errors.WithMessage(err, "reading channel config failed")
chCfg, err := client.Config().ChannelConfig(channel.Name())
if err != nil || chCfg == nil {
return nil, errors.Errorf("reading channel config failed: %s", err)
}

chOrderers, err := client.Config().ChannelOrderers(channel.Name())
Expand Down
2 changes: 2 additions & 0 deletions def/fabapi/context/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
fabca "github.com/hyperledger/fabric-sdk-go/api/apifabca"
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
txn "github.com/hyperledger/fabric-sdk-go/api/apitxn"
chmgmt "github.com/hyperledger/fabric-sdk-go/api/apitxn/chmgmtclient"
"github.com/hyperledger/fabric-sdk-go/def/fabapi/opt"
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp"
bccspFactory "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp/factory"
Expand All @@ -36,5 +37,6 @@ type OrgClientFactory interface {
// SessionClientFactory allows overriding default clients and providers of a session
type SessionClientFactory interface {
NewSystemClient(context SDK, session Session, config apiconfig.Config) (fab.FabricClient, error)
NewChannelMgmtClient(context SDK, session Session, config apiconfig.Config) (chmgmt.ChannelMgmtClient, error)
NewChannelClient(context SDK, session Session, config apiconfig.Config, channelID string) (txn.ChannelClient, error)
}
51 changes: 51 additions & 0 deletions def/fabapi/fabapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"github.com/hyperledger/fabric-sdk-go/pkg/logging"
"github.com/hyperledger/fabric-sdk-go/pkg/logging/deflogger"
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp"

chmgmt "github.com/hyperledger/fabric-sdk-go/api/apitxn/chmgmtclient"
)

// Options encapsulates configuration for the SDK
Expand Down Expand Up @@ -58,6 +60,12 @@ type ChannelClientOpts struct {
ConfigProvider apiconfig.Config
}

// ChannelMgmtClientOpts provides options for creating channel management client
type ChannelMgmtClientOpts struct {
OrgName string
ConfigProvider apiconfig.Config
}

// ProviderInit interface allows for initializing providers
type ProviderInit interface {
Initialize(sdk *FabricSDK) error
Expand Down Expand Up @@ -195,6 +203,49 @@ func (sdk *FabricSDK) NewSystemClient(s context.Session) (apifabclient.FabricCli
return client, nil
}

// NewChannelMgmtClient returns a new client for managing channels
func (sdk *FabricSDK) NewChannelMgmtClient(userName string) (chmgmt.ChannelMgmtClient, error) {

// Read default org name from configuration
client, err := sdk.configProvider.Client()
if err != nil {
return nil, errors.WithMessage(err, "unable to retrieve client from network config")
}

if client.Organization == "" {
return nil, errors.New("must provide default organisation name in configuration")
}

opt := &ChannelMgmtClientOpts{OrgName: client.Organization, ConfigProvider: sdk.configProvider}

return sdk.NewChannelMgmtClientWithOpts(userName, opt)
}

// NewChannelMgmtClientWithOpts returns a new client for managing channels with options
func (sdk *FabricSDK) NewChannelMgmtClientWithOpts(userName string, opt *ChannelMgmtClientOpts) (chmgmt.ChannelMgmtClient, error) {

if opt == nil || opt.OrgName == "" {
return nil, errors.New("organization name must be provided")
}

session, err := sdk.NewPreEnrolledUserSession(opt.OrgName, userName)
if err != nil {
return nil, errors.WithMessage(err, "failed to get pre-enrolled user session")
}

configProvider := sdk.ConfigProvider()
if opt.ConfigProvider != nil {
configProvider = opt.ConfigProvider
}

client, err := sdk.SessionFactory.NewChannelMgmtClient(sdk, session, configProvider)
if err != nil {
return nil, errors.WithMessage(err, "failed to create new channel management client")
}

return client, nil
}

// NewChannelClient returns a new client for a channel
func (sdk *FabricSDK) NewChannelClient(channelID string, userName string) (apitxn.ChannelClient, error) {

Expand Down
24 changes: 24 additions & 0 deletions def/fabapi/fabapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,30 @@ func TestNewDefaultSDK(t *testing.T) {
t.Fatalf("Failed to create new channel client: %s", err)
}

// Test configuration failure for channel management client (invalid user/default organisation)
_, err = sdk.NewChannelMgmtClient("Invalid")
if err == nil {
t.Fatalf("Should have failed to create channel client due to invalid user")
}

// Test valid configuration for channel management client
_, err = sdk.NewChannelMgmtClient("Admin")
if err != nil {
t.Fatalf("Failed to create new channel client: %s", err)
}

// Test configuration failure for new channel management client with options (invalid org)
_, err = sdk.NewChannelMgmtClientWithOpts("Admin", &ChannelMgmtClientOpts{OrgName: "Invalid"})
if err == nil {
t.Fatalf("Should have failed to create channel client due to invalid organisation")
}

// Test new channel management client with options (orderer admin configuration)
_, err = sdk.NewChannelMgmtClientWithOpts("Admin", &ChannelMgmtClientOpts{OrgName: "ordererorg"})
if err != nil {
t.Fatalf("Failed to create new channel client with opts: %s", err)
}

}

func TestNewDefaultTwoValidSDK(t *testing.T) {
Expand Down
17 changes: 10 additions & 7 deletions def/fabapi/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
fabca "github.com/hyperledger/fabric-sdk-go/api/apifabca"
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
"github.com/hyperledger/fabric-sdk-go/def/fabapi/context"
"github.com/hyperledger/fabric-sdk-go/pkg/errors"
)

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

// Initialize MSP client
client, err := factory.NewMSPClient(orgID, config)
if err != nil {
return nil, errors.WithMessage(err, "MSP client init failed")
}
c.mspClient = client
// TODO: Evaluate context contents during credential client design

/*
// Initialize MSP client
client, err := factory.NewMSPClient(orgID, config)
if err != nil {
return nil, errors.WithMessage(err, "MSP client init failed")
}
c.mspClient = client
*/

return &c, nil
}
Expand Down
24 changes: 17 additions & 7 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,11 @@ func (c *Config) OrdererConfig(name string) (*apiconfig.OrdererConfig, error) {
if err != nil {
return nil, err
}
orderer := config.Orderers[strings.ToLower(name)]
orderer, ok := config.Orderers[strings.ToLower(name)]
if !ok {
return nil, nil
}

if orderer.TLSCACerts.Path != "" {
orderer.TLSCACerts.Path = strings.Replace(orderer.TLSCACerts.Path, "$GOPATH",
os.Getenv("GOPATH"), -1)
Expand Down Expand Up @@ -394,7 +398,12 @@ func (c *Config) PeerConfig(org string, name string) (*apiconfig.PeerConfig, err
if !peerInOrg {
return nil, errors.Errorf("peer %s is not part of organization %s", name, org)
}
peerConfig := config.Peers[strings.ToLower(name)]

peerConfig, ok := config.Peers[strings.ToLower(name)]
if !ok {
return nil, nil
}

if peerConfig.TLSCACerts.Path != "" {
peerConfig.TLSCACerts.Path = strings.Replace(peerConfig.TLSCACerts.Path, "$GOPATH",
os.Getenv("GOPATH"), -1)
Expand Down Expand Up @@ -424,7 +433,7 @@ func (c *Config) ChannelConfig(name string) (*apiconfig.ChannelConfig, error) {
// viper lowercases all key maps
ch, ok := config.Channels[strings.ToLower(name)]
if !ok {
return nil, errors.Errorf("channel config not found for %s", name)
return nil, nil
}

return &ch, nil
Expand All @@ -434,15 +443,16 @@ func (c *Config) ChannelConfig(name string) (*apiconfig.ChannelConfig, error) {
func (c *Config) ChannelOrderers(name string) ([]apiconfig.OrdererConfig, error) {
orderers := []apiconfig.OrdererConfig{}
channel, err := c.ChannelConfig(name)
if err != nil {
return nil, err
if err != nil || channel == nil {
return nil, errors.Errorf("Unable to retrieve channel config: %s", err)
}

for _, chOrderer := range channel.Orderers {
orderer, err := c.OrdererConfig(chOrderer)
if err != nil {
return nil, errors.Errorf("orderer config not found for channel orderer: %s", chOrderer)
if err != nil || orderer == nil {
return nil, errors.Errorf("unable to retrieve orderer config: %s", err)
}

orderers = append(orderers, *orderer)
}

Expand Down
6 changes: 3 additions & 3 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,10 +356,10 @@ func TestOrdererConfig(t *testing.T) {
t.Fatal("Testing get RandomOrdererConfig failed")
}

oConfig, err = configImpl.OrdererConfig("peerorg1")
oConfig, err = configImpl.OrdererConfig("invalid")

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

orderers, err := configImpl.OrderersConfig()
Expand Down
20 changes: 11 additions & 9 deletions pkg/fabric-client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,17 +244,24 @@ func (c *Client) ExtractChannelConfig(configEnvelope []byte) ([]byte, error) {
* @param {byte[]} config - The Configuration Update in byte form
* @return {ConfigSignature} - The signature of the current user on the config bytes
*/
func (c *Client) SignChannelConfig(config []byte) (*common.ConfigSignature, error) {
func (c *Client) SignChannelConfig(config []byte, signer fab.User) (*common.ConfigSignature, error) {
logger.Debug("SignChannelConfig - start")

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

if c.userContext == nil {
signingUser := signer
// If signing user is not provided default to client's user context
if signingUser == nil {
signingUser = c.userContext
}

if signingUser == nil {
return nil, errors.New("user context required")
}
creator, err := c.userContext.Identity()

creator, err := signingUser.Identity()
if err != nil {
return nil, errors.WithMessage(err, "failed to get user context's identity")
}
Expand All @@ -273,19 +280,14 @@ func (c *Client) SignChannelConfig(config []byte) (*common.ConfigSignature, erro
return nil, errors.Wrap(err, "marshal signatureHeader failed")
}

user := c.UserContext()
if user == nil {
return nil, errors.New("UserContext is nil")
}

signingMgr := c.SigningManager()
if signingMgr == nil {
return nil, errors.New("signing manager is nil")
}

// get all the bytes to be signed together, then sign
signingBytes := fcutils.ConcatenateBytes(signatureHeaderBytes, config)
signature, err := signingMgr.Sign(signingBytes, user.PrivateKey())
signature, err := signingMgr.Sign(signingBytes, signingUser.PrivateKey())
if err != nil {
return nil, errors.WithMessage(err, "signing of channel config failed")
}
Expand Down
Loading

0 comments on commit 231ec6c

Please sign in to comment.