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

Commit d2abffb

Browse files
committed
[FAB-9445] Endpoint Options: cc query, endorsing peer
Change-Id: If4a6f960b794bfb68f10636628fa0285726da074 Signed-off-by: Sandra Vrtikapa <sandra.vrtikapa@securekey.com>
1 parent 65c0afe commit d2abffb

File tree

7 files changed

+278
-65
lines changed

7 files changed

+278
-65
lines changed

pkg/client/channel/chclient.go

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
"github.com/hyperledger/fabric-sdk-go/pkg/client/channel/invoke"
1515
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/discovery/greylist"
16+
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/filter"
1617
"github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry"
1718
"github.com/hyperledger/fabric-sdk-go/pkg/common/errors/status"
1819
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/context"
@@ -79,22 +80,39 @@ func New(channelProvider context.ChannelProvider, opts ...ClientOption) (*Client
7980

8081
// Query chaincode using request and optional options provided
8182
func (cc *Client) Query(request Request, options ...RequestOption) (Response, error) {
82-
optsWithTimeout, err := cc.addDefaultTimeout(cc.context, fab.Query, options...)
83-
if err != nil {
84-
return Response{}, errors.WithMessage(err, "option failed")
85-
}
8683

87-
return cc.InvokeHandler(invoke.NewQueryHandler(), request, optsWithTimeout...)
84+
options = append(options, addDefaultTimeout(fab.Query))
85+
options = append(options, addDefaultTargetFilter(cc.context, filter.ChaincodeQuery))
86+
87+
return cc.InvokeHandler(invoke.NewQueryHandler(), request, options...)
8888
}
8989

9090
// Execute prepares and executes transaction using request and optional options provided
9191
func (cc *Client) Execute(request Request, options ...RequestOption) (Response, error) {
92-
optsWithTimeout, err := cc.addDefaultTimeout(cc.context, fab.Execute, options...)
93-
if err != nil {
94-
return Response{}, errors.WithMessage(err, "option failed")
92+
options = append(options, addDefaultTimeout(fab.Execute))
93+
options = append(options, addDefaultTargetFilter(cc.context, filter.EndorsingPeer))
94+
95+
return cc.InvokeHandler(invoke.NewExecuteHandler(), request, options...)
96+
}
97+
98+
// addDefaultTargetFilter adds default target filter if target filter is not specified
99+
func addDefaultTargetFilter(chCtx context.Channel, ft filter.EndpointType) RequestOption {
100+
return func(ctx context.Client, o *requestOptions) error {
101+
if len(o.Targets) == 0 && o.TargetFilter == nil {
102+
return WithTargetFilter(filter.NewEndpointFilter(chCtx, ft))(ctx, o)
103+
}
104+
return nil
95105
}
106+
}
96107

97-
return cc.InvokeHandler(invoke.NewExecuteHandler(), request, optsWithTimeout...)
108+
// addDefaultTimeout adds default timeout if timeout is not specified
109+
func addDefaultTimeout(tt fab.TimeoutType) RequestOption {
110+
return func(ctx context.Client, o *requestOptions) error {
111+
if o.Timeouts[tt] == 0 {
112+
return WithTimeout(tt, ctx.EndpointConfig().Timeout(tt))(ctx, o)
113+
}
114+
return nil
115+
}
98116
}
99117

100118
//InvokeHandler invokes handler using request and options provided
@@ -224,23 +242,6 @@ func (cc *Client) prepareOptsFromOptions(ctx context.Client, options ...RequestO
224242
return txnOpts, nil
225243
}
226244

227-
//addDefaultTimeout adds given default timeout if it is missing in options
228-
func (cc *Client) addDefaultTimeout(ctx context.Client, timeOutType fab.TimeoutType, options ...RequestOption) ([]RequestOption, error) {
229-
txnOpts := requestOptions{}
230-
for _, option := range options {
231-
err := option(ctx, &txnOpts)
232-
if err != nil {
233-
return nil, errors.WithMessage(err, "option failed")
234-
}
235-
}
236-
237-
if txnOpts.Timeouts[timeOutType] == 0 {
238-
//InvokeHandler relies on Execute timeout
239-
return append(options, WithTimeout(fab.Execute, cc.context.EndpointConfig().Timeout(timeOutType))), nil
240-
}
241-
return options, nil
242-
}
243-
244245
// RegisterChaincodeEvent registers chain code event
245246
// @param {chan bool} channel which receives event details when the event is complete
246247
// @returns {object} object handle that should be used to unregister
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
Copyright SecureKey Technologies Inc. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
// Package filter provides common filters (e.g. Endpoint)
8+
package filter
9+
10+
import (
11+
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/context"
12+
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
13+
)
14+
15+
// EndpointType represents endpoint type
16+
type EndpointType int32
17+
18+
// Endpoint types
19+
const (
20+
ChaincodeQuery EndpointType = iota
21+
EndorsingPeer
22+
LedgerQuery
23+
EventSource
24+
)
25+
26+
// NewEndpointFilter creates a new endpoint filter that is based on configuration.
27+
// If channel peer is not configured it will be selected by default.
28+
func NewEndpointFilter(ctx context.Channel, et EndpointType) *EndpointFilter {
29+
30+
// Retrieve channel peers
31+
chPeers, err := ctx.EndpointConfig().ChannelPeers(ctx.ChannelID())
32+
if err != nil {
33+
// Setting channel peers to empty due to config error, should not happen
34+
chPeers = []fab.ChannelPeer{}
35+
}
36+
37+
return &EndpointFilter{endpointType: et, ctx: ctx, chPeers: chPeers}
38+
39+
}
40+
41+
// EndpointFilter filters based on endpoint config options
42+
type EndpointFilter struct {
43+
endpointType EndpointType
44+
ctx context.Channel
45+
chPeers []fab.ChannelPeer // configured channel peers
46+
}
47+
48+
// Accept returns false if this peer is to be excluded from the target list
49+
func (f *EndpointFilter) Accept(peer fab.Peer) bool {
50+
51+
peerConfig, err := f.ctx.EndpointConfig().PeerConfigByURL(peer.URL())
52+
if err != nil || peerConfig == nil {
53+
return true
54+
}
55+
56+
chPeer := f.getChannelPeer(peerConfig)
57+
if chPeer == nil {
58+
return true
59+
}
60+
61+
switch t := f.endpointType; t {
62+
case ChaincodeQuery:
63+
return chPeer.ChaincodeQuery
64+
case EndorsingPeer:
65+
return chPeer.EndorsingPeer
66+
case LedgerQuery:
67+
return chPeer.LedgerQuery
68+
case EventSource:
69+
return chPeer.EventSource
70+
}
71+
72+
return true
73+
}
74+
75+
func (f *EndpointFilter) getChannelPeer(peerConfig *fab.PeerConfig) *fab.ChannelPeer {
76+
for _, chpeer := range f.chPeers {
77+
if chpeer.URL == peerConfig.URL {
78+
return &chpeer
79+
}
80+
}
81+
return nil
82+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
Copyright SecureKey Technologies Inc. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
package filter
7+
8+
import (
9+
"testing"
10+
11+
"github.com/hyperledger/fabric-sdk-go/pkg/fab/mocks"
12+
)
13+
14+
const channelID = "mychannel"
15+
16+
func TestInvalidOpt(t *testing.T) {
17+
18+
channel, err := mocks.NewMockChannel(channelID)
19+
if err != nil {
20+
t.Fatalf("Failed to create mock channel: %s", err)
21+
}
22+
23+
ef := NewEndpointFilter(channel, 10)
24+
25+
peer := mocks.NewMockPeer("Peer1", "example.com")
26+
if !ef.Accept(peer) {
27+
t.Fatalf("Should have accepted peer")
28+
}
29+
30+
}
31+
32+
func TestChaincodeQueryFilter(t *testing.T) {
33+
34+
channel, err := mocks.NewMockChannel(channelID)
35+
if err != nil {
36+
t.Fatalf("Failed to create mock channel: %s", err)
37+
}
38+
39+
ef := NewEndpointFilter(channel, ChaincodeQuery)
40+
41+
if !ef.Accept(mocks.NewMockPeer("Peer1", "non-configured.com")) {
42+
t.Fatalf("Should have accepted peer that is not configured")
43+
}
44+
45+
// Configured peer
46+
peer := mocks.NewMockPeer("Peer1", "example.com")
47+
if !ef.Accept(peer) {
48+
t.Fatalf("Should have accepted peer")
49+
}
50+
51+
channel, err = mocks.NewMockChannel("noEndpoints")
52+
ef = NewEndpointFilter(channel, ChaincodeQuery)
53+
if err != nil {
54+
t.Fatalf("Failed to create mock channel: %s", err)
55+
}
56+
if ef.Accept(peer) {
57+
t.Fatalf("Should NOT have accepted peer since peers chaincode query option is configured to false")
58+
}
59+
60+
channel, err = mocks.NewMockChannel("noChannelPeers")
61+
ef = NewEndpointFilter(channel, ChaincodeQuery)
62+
if err != nil {
63+
t.Fatalf("Failed to create mock channel: %s", err)
64+
}
65+
if !ef.Accept(peer) {
66+
t.Fatalf("Should have accepted peer since no peers configured")
67+
}
68+
69+
}
70+
71+
func TestLedgerQueryFilter(t *testing.T) {
72+
73+
channel, err := mocks.NewMockChannel(channelID)
74+
if err != nil {
75+
t.Fatalf("Failed to create mock channel: %s", err)
76+
}
77+
78+
ef := NewEndpointFilter(channel, LedgerQuery)
79+
80+
peer := mocks.NewMockPeer("Peer1", "example.com")
81+
if !ef.Accept(peer) {
82+
t.Fatalf("Should have accepted peer")
83+
}
84+
85+
}
86+
87+
func TestEndorsingPeerFilter(t *testing.T) {
88+
89+
channel, err := mocks.NewMockChannel(channelID)
90+
if err != nil {
91+
t.Fatalf("Failed to create mock channel: %s", err)
92+
}
93+
94+
ef := NewEndpointFilter(channel, EndorsingPeer)
95+
96+
peer := mocks.NewMockPeer("Peer1", "example.com")
97+
if !ef.Accept(peer) {
98+
t.Fatalf("Should have accepted peer")
99+
}
100+
101+
}
102+
103+
func TestEventSourceFilter(t *testing.T) {
104+
105+
channel, err := mocks.NewMockChannel(channelID)
106+
if err != nil {
107+
t.Fatalf("Failed to create mock channel: %s", err)
108+
}
109+
110+
ef := NewEndpointFilter(channel, EventSource)
111+
112+
peer := mocks.NewMockPeer("Peer1", "example.com")
113+
if !ef.Accept(peer) {
114+
t.Fatalf("Should have accepted peer")
115+
}
116+
117+
}

pkg/client/ledger/ledger.go

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/golang/protobuf/proto"
1616

1717
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/discovery"
18+
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/filter"
1819
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/verifier"
1920
"github.com/hyperledger/fabric-sdk-go/pkg/common/errors/status"
2021
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/context"
@@ -74,12 +75,7 @@ func New(channelProvider context.ChannelProvider, opts ...ClientOption) (*Client
7475
return nil, err
7576
}
7677

77-
chpeers, err := channelContext.EndpointConfig().ChannelPeers(channelContext.ChannelID())
78-
if err != nil {
79-
return nil, status.New(status.ClientStatus, status.NoPeersFound.ToInt32(), err.Error(), nil)
80-
}
81-
82-
ledgerFilter := &ledgerFilter{ctx: channelContext, chPeers: chpeers}
78+
ledgerFilter := filter.NewEndpointFilter(channelContext, filter.LedgerQuery)
8379

8480
// Apply filter to discovery service
8581
discovery := discovery.NewDiscoveryFilterService(channelContext.DiscoveryService(), ledgerFilter)
@@ -420,34 +416,3 @@ func shuffle(a []fab.Peer) {
420416
a[i], a[j] = a[j], a[i]
421417
}
422418
}
423-
424-
// ledgerFilter filters based on ledgerQuery config option
425-
type ledgerFilter struct {
426-
ctx context.Channel
427-
chPeers []fab.ChannelPeer // configured channel peers
428-
}
429-
430-
// Accept returns false if this peer is to be excluded from the target list
431-
func (f *ledgerFilter) Accept(peer fab.Peer) bool {
432-
433-
peerConfig, err := f.ctx.EndpointConfig().PeerConfigByURL(peer.URL())
434-
if err != nil || peerConfig == nil {
435-
return true
436-
}
437-
438-
chPeer := f.getChannelPeer(peerConfig)
439-
if chPeer == nil {
440-
return true
441-
}
442-
443-
return chPeer.LedgerQuery
444-
}
445-
446-
func (f *ledgerFilter) getChannelPeer(peerConfig *fab.PeerConfig) *fab.ChannelPeer {
447-
for _, chpeer := range f.chPeers {
448-
if chpeer.URL == peerConfig.URL {
449-
return &chpeer
450-
}
451-
}
452-
return nil
453-
}

pkg/fab/mocks/mockconfig.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,18 @@ func (c *MockConfig) ChannelConfig(name string) (*fab.ChannelNetworkConfig, erro
274274

275275
// ChannelPeers returns the channel peers configuration
276276
func (c *MockConfig) ChannelPeers(name string) ([]fab.ChannelPeer, error) {
277-
return nil, nil
277+
278+
if name == "noChannelPeers" {
279+
return nil, nil
280+
}
281+
282+
peerChCfg := fab.PeerChannelConfig{EndorsingPeer: true, ChaincodeQuery: true, LedgerQuery: true, EventSource: true}
283+
if name == "noEndpoints" {
284+
peerChCfg = fab.PeerChannelConfig{EndorsingPeer: false, ChaincodeQuery: false, LedgerQuery: false, EventSource: false}
285+
}
286+
287+
mockPeer := fab.ChannelPeer{PeerChannelConfig: peerChCfg, NetworkPeer: fab.NetworkPeer{PeerConfig: fab.PeerConfig{URL: "example.com"}}}
288+
return []fab.ChannelPeer{mockPeer}, nil
278289
}
279290

280291
// ChannelOrderers returns a list of channel orderers

test/fixtures/config/config_test_endpoints.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ channels:
134134
# [Optional]. will this peer be the target of the SDK's listener registration? All peers can
135135
# produce events but the app typically only needs to connect to one to listen to events.
136136
# Default: true
137-
eventSource: false
137+
eventSource: true
138138

139139
#
140140
# list of participating organizations in this network

0 commit comments

Comments
 (0)