Skip to content

Commit

Permalink
[FAB-7972] Whitelist discovery filter
Browse files Browse the repository at this point in the history
Change-Id: Id36a762e260fcd38ff6b7f7783a2c8cc67e92adc
Signed-off-by: Firas Qutishat <firas.qutishat@securekey.com>
  • Loading branch information
fqutishat committed Jan 30, 2018
1 parent e985ca4 commit 4529702
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 51 deletions.
6 changes: 6 additions & 0 deletions api/apifabclient/discoveryprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ type DiscoveryProvider interface {
type DiscoveryService interface {
GetPeers() ([]Peer, error)
}

// TargetFilter allows for filtering target peers
type TargetFilter interface {
// Accept returns true if peer should be included in the list of target peers
Accept(peer Peer) bool
}
49 changes: 49 additions & 0 deletions pkg/fabric-txn/discovery/discoveryfilter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package discovery

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

// filterService implements discovery service
type filterService struct {
discoveryService apifabclient.DiscoveryService
targetFilter apifabclient.TargetFilter
}

// NewDiscoveryFilterService return discovery service with filter
func NewDiscoveryFilterService(discoveryService apifabclient.DiscoveryService, targetFilter apifabclient.TargetFilter) apifabclient.DiscoveryService {
return &filterService{discoveryService: discoveryService, targetFilter: targetFilter}
}

// GetPeers is used to get peers
func (fs *filterService) GetPeers() ([]apifabclient.Peer, error) {
peers, err := fs.discoveryService.GetPeers()
if err != nil {
return nil, err
}
targets := filterTargets(peers, fs.targetFilter)
return targets, nil
}

// filterTargets is helper method to filter peers
func filterTargets(peers []apifabclient.Peer, filter apifabclient.TargetFilter) []apifabclient.Peer {

if filter == nil {
return peers
}

filteredPeers := []apifabclient.Peer{}
for _, peer := range peers {
if filter.Accept(peer) {
filteredPeers = append(filteredPeers, peer)
}
}

return filteredPeers
}
63 changes: 63 additions & 0 deletions pkg/fabric-txn/discovery/discoveryfilter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package discovery

import (
"testing"

"github.com/hyperledger/fabric-sdk-go/api/apifabclient"
"github.com/hyperledger/fabric-sdk-go/pkg/config"
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/discovery/staticdiscovery"
)

type mockFilter struct {
called bool
}

// Accept returns true if this peer is to be included in the target list
func (df *mockFilter) Accept(peer apifabclient.Peer) bool {
df.called = true
return true
}

func TestDiscoveryFilter(t *testing.T) {

config, err := config.FromFile("../../../test/fixtures/config/config_test.yaml")()
if err != nil {
t.Fatalf(err.Error())
}

discoveryProvider, err := staticdiscovery.NewDiscoveryProvider(config)
if err != nil {
t.Fatalf("Failed to setup discovery provider: %s", err)
}

discoveryService, err := discoveryProvider.NewDiscoveryService("mychannel")
if err != nil {
t.Fatalf("Failed to setup discovery service: %s", err)
}

discoveryFilter := &mockFilter{called: false}

discoveryService = NewDiscoveryFilterService(discoveryService, discoveryFilter)

peers, err := discoveryService.GetPeers()
if err != nil {
t.Fatalf("Failed to get peers from discovery service: %s", err)
}

// One peer is configured for "mychannel"
expectedNumOfPeers := 1
if len(peers) != expectedNumOfPeers {
t.Fatalf("Expecting %d, got %d peers", expectedNumOfPeers, len(peers))
}

if !discoveryFilter.called {
t.Fatalf("Expecting true, got false")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func newCCPolicyProvider(sdk *fabsdk.FabricSDK, channelID string, userName strin

type ccPolicyProvider struct {
config apiconfig.Config
client *fabsdk.Client
client *fabsdk.ClientContext
channelID string
targetPeers []apiconfig.ChannelPeer
ccDataMap map[string]*ccprovider.ChaincodeData // TODO: Add expiry and configurable timeout for map entries
Expand Down
2 changes: 1 addition & 1 deletion pkg/fabsdk/api/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type OrgClientFactory interface {
type SessionClientFactory interface {
NewChannelMgmtClient(sdk Providers, session SessionContext) (chmgmt.ChannelMgmtClient, error)
NewResourceMgmtClient(sdk Providers, session SessionContext, filter resmgmt.TargetFilter) (resmgmt.ResourceMgmtClient, error)
NewChannelClient(sdk Providers, session SessionContext, channelID string) (txn.ChannelClient, error)
NewChannelClient(sdk Providers, session SessionContext, channelID string, targetFilter fab.TargetFilter) (txn.ChannelClient, error)
}

// PkgSuite provides the package factories that create clients and providers
Expand Down
8 changes: 4 additions & 4 deletions pkg/fabsdk/api/mocks/mocksdkapi.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 49 additions & 23 deletions pkg/fabsdk/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,30 @@ import (
apisdk "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk/api"
)

// Client represents the fabric transaction clients
type Client struct {
// ClientContext represents the fabric transaction clients
type ClientContext struct {
provider clientProvider
}

// ContextOption configures the client context created by the SDK.
type ContextOption func(opts *contextOptions) error

type contextOptions struct {
orgID string
config apiconfig.Config
}

// ClientOption configures the clients created by the SDK.
type ClientOption func(opts *clientOptions) error

type clientOptions struct {
orgID string
config apiconfig.Config
targetFilter resmgmt.TargetFilter
targetFilter apifabclient.TargetFilter
}

type clientProvider func() (*clientContext, error)

type clientContext struct {
opts *clientOptions
opts *contextOptions
identity apifabclient.IdentityContext
providers providers
clientFactory apisdk.SessionClientFactory
Expand All @@ -44,15 +50,15 @@ type providers interface {
}

// WithOrg uses the configuration and users from the named organization.
func WithOrg(name string) ClientOption {
return func(opts *clientOptions) error {
func WithOrg(name string) ContextOption {
return func(opts *contextOptions) error {
opts.orgID = name
return nil
}
}

// WithTargetFilter allows for filtering target peers.
func WithTargetFilter(targetFilter resmgmt.TargetFilter) ClientOption {
func WithTargetFilter(targetFilter apifabclient.TargetFilter) ClientOption {
return func(opts *clientOptions) error {
opts.targetFilter = targetFilter
return nil
Expand All @@ -61,19 +67,19 @@ func WithTargetFilter(targetFilter resmgmt.TargetFilter) ClientOption {

// withConfig allows for overriding the configuration of the client.
// TODO: This should be removed once the depreacted functions are removed.
func withConfig(config apiconfig.Config) ClientOption {
return func(opts *clientOptions) error {
func withConfig(config apiconfig.Config) ContextOption {
return func(opts *contextOptions) error {
opts.config = config
return nil
}
}

// NewClient allows creation of transactions using the supplied identity as the credential.
func (sdk *FabricSDK) NewClient(identityOpt IdentityOption, opts ...ClientOption) *Client {
func (sdk *FabricSDK) NewClient(identityOpt IdentityOption, opts ...ContextOption) *ClientContext {
// delay execution of the following logic to avoid error return from this function.
// this is done to allow a cleaner API - i.e., client, err := sdk.NewClient(args).<Desired Interface>(extra args)
provider := func() (*clientContext, error) {
o, err := newClientOptions(sdk.config, opts)
o, err := newContextOptions(sdk.config, opts)
if err != nil {
return nil, errors.WithMessage(err, "unable to retrieve configuration from SDK")
}
Expand All @@ -91,20 +97,20 @@ func (sdk *FabricSDK) NewClient(identityOpt IdentityOption, opts ...ClientOption
}
return &cc, nil
}
client := Client{
client := ClientContext{
provider: provider,
}
return &client
}

func newClientOptions(config apiconfig.Config, options []ClientOption) (*clientOptions, error) {
func newContextOptions(config apiconfig.Config, options []ContextOption) (*contextOptions, error) {
// Read default org name from configuration
client, err := config.Client()
if err != nil {
return nil, errors.WithMessage(err, "unable to retrieve client from network config")
}

opts := clientOptions{
opts := contextOptions{
orgID: client.Organization,
config: config,
}
Expand All @@ -123,8 +129,21 @@ func newClientOptions(config apiconfig.Config, options []ClientOption) (*clientO
return &opts, nil
}

func newClientOptions(options []ClientOption) (*clientOptions, error) {
opts := clientOptions{}

for _, option := range options {
err := option(&opts)
if err != nil {
return nil, errors.WithMessage(err, "error in option passed to client")
}
}

return &opts, nil
}

// ChannelMgmt returns a client API for managing channels.
func (c *Client) ChannelMgmt() (chmgmt.ChannelMgmtClient, error) {
func (c *ClientContext) ChannelMgmt() (chmgmt.ChannelMgmtClient, error) {
p, err := c.provider()
if err != nil {
return nil, errors.WithMessage(err, "unable to get client provider context")
Expand All @@ -140,14 +159,18 @@ func (c *Client) ChannelMgmt() (chmgmt.ChannelMgmtClient, error) {
}

// ResourceMgmt returns a client API for managing system resources.
func (c *Client) ResourceMgmt() (resmgmt.ResourceMgmtClient, error) {
func (c *ClientContext) ResourceMgmt(opts ...ClientOption) (resmgmt.ResourceMgmtClient, error) {
p, err := c.provider()
if err != nil {
return nil, errors.WithMessage(err, "unable to get client provider context")
}
o, err := newClientOptions(opts)
if err != nil {
return nil, errors.WithMessage(err, "unable to retrieve client options")
}

session := newSession(p.identity, p.providers.ChannelProvider())
client, err := p.clientFactory.NewResourceMgmtClient(p.providers, session, p.opts.targetFilter)
client, err := p.clientFactory.NewResourceMgmtClient(p.providers, session, o.targetFilter)
if err != nil {
return nil, errors.WithMessage(err, "failed to created new resource management client")
}
Expand All @@ -156,14 +179,17 @@ func (c *Client) ResourceMgmt() (resmgmt.ResourceMgmtClient, error) {
}

// Channel returns a client API for transacting on a channel.
func (c *Client) Channel(id string) (apitxn.ChannelClient, error) {
func (c *ClientContext) Channel(id string, opts ...ClientOption) (apitxn.ChannelClient, error) {
p, err := c.provider()
if err != nil {
return nil, errors.WithMessage(err, "unable to get client provider context")
}

o, err := newClientOptions(opts)
if err != nil {
return nil, errors.WithMessage(err, "unable to retrieve client options")
}
session := newSession(p.identity, p.providers.ChannelProvider())
client, err := p.clientFactory.NewChannelClient(p.providers, session, id)
client, err := p.clientFactory.NewChannelClient(p.providers, session, id, o.targetFilter)
if err != nil {
return nil, errors.WithMessage(err, "failed to created new resource management client")
}
Expand All @@ -174,7 +200,7 @@ func (c *Client) Channel(id string) (apitxn.ChannelClient, error) {
// Session returns the underlying identity of the client.
//
// Deprecated: this method is temporary.
func (c *Client) Session() (apisdk.SessionContext, error) {
func (c *ClientContext) Session() (apisdk.SessionContext, error) {
p, err := c.provider()
if err != nil {
return nil, errors.WithMessage(err, "unable to get client provider context")
Expand Down
10 changes: 5 additions & 5 deletions pkg/fabsdk/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ func TestFromConfigGoodClientOpt(t *testing.T) {
}
}

func goodClientOpt() ClientOption {
return func(opts *clientOptions) error {
func goodClientOpt() ContextOption {
return func(opts *contextOptions) error {
return nil
}
}
Expand All @@ -69,8 +69,8 @@ func TestNewBadClientOpt(t *testing.T) {
}
}

func badClientOpt() ClientOption {
return func(opts *clientOptions) error {
func badClientOpt() ContextOption {
return func(opts *contextOptions) error {
return errors.New("Bad Opt")
}
}
Expand Down Expand Up @@ -126,7 +126,7 @@ func TestWithConfig(t *testing.T) {
}
opt := withConfig(c)

opts := clientOptions{}
opts := contextOptions{}
err = opt(&opts)
if err != nil {
t.Fatalf("Expected no error from option, but got %v", err)
Expand Down
Loading

0 comments on commit 4529702

Please sign in to comment.