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

Commit e84f33e

Browse files
authored
[FABG-1021] Add properties to Peer (#155)
Properties from the discovery service are added to the fab.Peer. The properties are exposed as a map of string key to interface{} value so that extended properties may be added without requiring modifications to this interface. Signed-off-by: Bob Stasyszyn <[email protected]>
1 parent 5b6912c commit e84f33e

File tree

17 files changed

+295
-30
lines changed

17 files changed

+295
-30
lines changed

pkg/client/common/discovery/dynamicdiscovery/chservice_test.go

+17-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ SPDX-License-Identifier: Apache-2.0
99
package dynamicdiscovery
1010

1111
import (
12-
fabDiscovery "github.com/hyperledger/fabric-sdk-go/pkg/fab/discovery"
12+
"github.com/hyperledger/fabric-protos-go/gossip"
1313
"github.com/pkg/errors"
1414
"testing"
1515
"time"
@@ -18,6 +18,7 @@ import (
1818
contextAPI "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/context"
1919
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
2020
pfab "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
21+
fabDiscovery "github.com/hyperledger/fabric-sdk-go/pkg/fab/discovery"
2122
discmocks "github.com/hyperledger/fabric-sdk-go/pkg/fab/discovery/mocks"
2223
"github.com/hyperledger/fabric-sdk-go/pkg/fab/mocks"
2324
mspmocks "github.com/hyperledger/fabric-sdk-go/pkg/msp/test/mockmsp"
@@ -90,13 +91,22 @@ func TestDiscoveryService(t *testing.T) {
9091
assert.NoError(t, err)
9192
assert.Equal(t, 0, len(peers))
9293

94+
chaincodes := []*gossip.Chaincode{
95+
{
96+
Name: "cc1",
97+
Version: "v1",
98+
},
99+
}
100+
93101
discClient.SetResponses(
94102
&fabDiscovery.MockDiscoverEndpointResponse{
95103
PeerEndpoints: []*discmocks.MockDiscoveryPeerEndpoint{
96104
{
97105
MSPID: mspID1,
98106
Endpoint: peer1MSP1,
99107
LedgerHeight: 5,
108+
Chaincodes: chaincodes,
109+
LeftChannel: false,
100110
},
101111
},
102112
Target: peer1MSP2,
@@ -109,6 +119,12 @@ func TestDiscoveryService(t *testing.T) {
109119
assert.NoError(t, err)
110120
assert.Equalf(t, 1, len(peers), "Expected 1 peer")
111121

122+
peer := peers[0]
123+
require.NotEmpty(t, peer.Properties())
124+
require.Equal(t, uint64(5), peer.Properties()[fab.PropertyLedgerHeight])
125+
require.Equal(t, false, peer.Properties()[fab.PropertyLeftChannel])
126+
require.Equal(t, chaincodes, peer.Properties()[fab.PropertyChaincodes])
127+
112128
discClient.SetResponses(
113129
&fabDiscovery.MockDiscoverEndpointResponse{
114130
PeerEndpoints: []*discmocks.MockDiscoveryPeerEndpoint{

pkg/client/common/discovery/dynamicdiscovery/service.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,11 @@ func asPeer(ctx contextAPI.Client, endpoint *discclient.Peer) (fab.Peer, bool) {
145145
return nil, false
146146
}
147147

148-
peer, err := ctx.InfraProvider().CreatePeerFromConfig(&fab.NetworkPeer{PeerConfig: *peerConfig, MSPID: endpoint.MSPID})
148+
peer, err := ctx.InfraProvider().CreatePeerFromConfig(&fab.NetworkPeer{
149+
PeerConfig: *peerConfig,
150+
MSPID: endpoint.MSPID,
151+
Properties: fabdiscovery.GetProperties(endpoint),
152+
})
149153
if err != nil {
150154
logger.Warnf("Unable to create peer config for [%s]: %s", url, err)
151155
return nil, false

pkg/client/common/selection/fabricselection/fabricselection.go

+12-5
Original file line numberDiff line numberDiff line change
@@ -337,14 +337,17 @@ func asPeer(ctx contextAPI.Client, endpoint *discclient.Peer) (fab.Peer, error)
337337
return nil, errors.Errorf("peer config not found for [%s]", url)
338338
}
339339

340-
peer, err := ctx.InfraProvider().CreatePeerFromConfig(&fab.NetworkPeer{PeerConfig: *peerConfig, MSPID: endpoint.MSPID})
340+
peer, err := ctx.InfraProvider().CreatePeerFromConfig(&fab.NetworkPeer{
341+
PeerConfig: *peerConfig,
342+
MSPID: endpoint.MSPID,
343+
Properties: fabdiscovery.GetProperties(endpoint),
344+
})
341345
if err != nil {
342346
return nil, errors.Wrapf(err, "unable to create peer config for [%s]", url)
343347
}
344348

345349
return &peerEndpoint{
346-
Peer: peer,
347-
blockHeight: endpoint.StateInfoMessage.GetStateInfo().GetProperties().LedgerHeight,
350+
Peer: peer,
348351
}, nil
349352
}
350353

@@ -354,11 +357,15 @@ func getDefaultRetryOpts(ctx contextAPI.Client, channelID string) retry.Opts {
354357

355358
type peerEndpoint struct {
356359
fab.Peer
357-
blockHeight uint64
358360
}
359361

360362
func (p *peerEndpoint) BlockHeight() uint64 {
361-
return p.blockHeight
363+
ledgerHeight, ok := p.Properties()[fab.PropertyLedgerHeight]
364+
if !ok {
365+
return 0
366+
}
367+
368+
return ledgerHeight.(uint64)
362369
}
363370

364371
// DiscoveryError is an error originating at the Discovery service

pkg/client/common/selection/fabricselection/selection_test.go

+16
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"testing"
1515
"time"
1616

17+
"github.com/hyperledger/fabric-protos-go/gossip"
18+
1719
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/balancer"
1820
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/options"
1921
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/sorter/blockheightsorter"
@@ -164,6 +166,13 @@ func TestSelection(t *testing.T) {
164166
})
165167

166168
t.Run("Success on one target", func(t *testing.T) {
169+
chaincodes := []*gossip.Chaincode{
170+
{
171+
Name: cc1,
172+
Version: "v1",
173+
},
174+
}
175+
167176
discClient.SetResponses(
168177
&discovery.MockDiscoverEndpointResponse{
169178
EndorsersErr: fmt.Errorf("no endorsement combination can be satisfied"),
@@ -177,13 +186,20 @@ func TestSelection(t *testing.T) {
177186
MSPID: mspID1,
178187
Endpoint: peer1Org1URL,
179188
LedgerHeight: 10,
189+
Chaincodes: chaincodes,
180190
},
181191
},
182192
},
183193
)
184194
endorsers, err := service.GetEndorsersForChaincode([]*fab.ChaincodeCall{{ID: cc1}})
185195
require.NoError(t, err)
186196
require.Len(t, endorsers, 1)
197+
198+
endorser := endorsers[0]
199+
require.NotEmpty(t, endorser.Properties())
200+
require.Equal(t, uint64(10), endorser.Properties()[fab.PropertyLedgerHeight])
201+
require.Equal(t, false, endorser.Properties()[fab.PropertyLeftChannel])
202+
require.Equal(t, chaincodes, endorser.Properties()[fab.PropertyChaincodes])
187203
})
188204

189205
t.Run("CCtoCC", func(t *testing.T) {

pkg/client/common/selection/fabricselection/selectionfilter.go

+19-10
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ import (
1010
"context"
1111
"sort"
1212

13-
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/sorter/balancedsorter"
14-
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/sorter/blockheightsorter"
15-
1613
discclient "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/discovery/client"
1714
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/balancer"
1815
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/options"
16+
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/sorter/balancedsorter"
17+
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/sorter/blockheightsorter"
1918
contextAPI "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/context"
2019
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
20+
fabdiscovery "github.com/hyperledger/fabric-sdk-go/pkg/fab/discovery"
2121
)
2222

2323
type selectionFilter struct {
@@ -149,9 +149,9 @@ func (s *selectionFilter) asPeerValue(endpoint *discclient.Peer) fab.Peer {
149149
}
150150

151151
return &peerEndpointValue{
152-
mspID: endpoint.MSPID,
153-
url: url,
154-
blockHeight: endpoint.StateInfoMessage.GetStateInfo().GetProperties().LedgerHeight,
152+
mspID: endpoint.MSPID,
153+
url: url,
154+
properties: fabdiscovery.GetProperties(endpoint),
155155
}
156156
}
157157

@@ -207,9 +207,9 @@ func containsPeer(peers []fab.Peer, peer fab.Peer) bool {
207207
}
208208

209209
type peerEndpointValue struct {
210-
mspID string
211-
url string
212-
blockHeight uint64
210+
mspID string
211+
url string
212+
properties fab.Properties
213213
}
214214

215215
func (p *peerEndpointValue) MSPID() string {
@@ -220,8 +220,17 @@ func (p *peerEndpointValue) URL() string {
220220
return p.url
221221
}
222222

223+
func (p *peerEndpointValue) Properties() fab.Properties {
224+
return p.properties
225+
}
226+
223227
func (p *peerEndpointValue) BlockHeight() uint64 {
224-
return p.blockHeight
228+
ledgerHeight, ok := p.properties[fab.PropertyLedgerHeight]
229+
if !ok {
230+
return 0
231+
}
232+
233+
return ledgerHeight.(uint64)
225234
}
226235

227236
func (p *peerEndpointValue) ProcessTransactionProposal(context.Context, fab.ProcessProposalRequest) (*fab.TransactionProposalResponse, error) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
Copyright SecureKey Technologies Inc. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package fabricselection
8+
9+
import (
10+
"testing"
11+
12+
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
func TestPeerEndpointValue(t *testing.T) {
17+
const mspID = "org1"
18+
const url = "peer1.org1.com"
19+
20+
t.Run("Success", func(t *testing.T) {
21+
ep := &peerEndpointValue{
22+
mspID: mspID,
23+
url: url,
24+
properties: fab.Properties{
25+
fab.PropertyLedgerHeight: uint64(1001),
26+
},
27+
}
28+
29+
require.Equal(t, mspID, ep.MSPID())
30+
require.Equal(t, url, ep.URL())
31+
require.NotEmpty(t, ep.Properties())
32+
require.Equal(t, uint64(1001), ep.Properties()[fab.PropertyLedgerHeight])
33+
require.Equal(t, uint64(1001), ep.BlockHeight())
34+
require.Panics(t, func() {
35+
_, err := ep.ProcessTransactionProposal(nil, fab.ProcessProposalRequest{})
36+
require.NoError(t, err)
37+
})
38+
})
39+
40+
t.Run("No ledger height property", func(t *testing.T) {
41+
ep := &peerEndpointValue{
42+
mspID: mspID,
43+
url: url,
44+
properties: fab.Properties{},
45+
}
46+
47+
require.Equal(t, mspID, ep.MSPID())
48+
require.Equal(t, url, ep.URL())
49+
require.Empty(t, ep.Properties())
50+
require.Equal(t, uint64(0), ep.BlockHeight())
51+
})
52+
}

pkg/common/providers/fab/network.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ type ChannelPeer struct {
111111
// NetworkPeer combines peer info with MSP info
112112
type NetworkPeer struct {
113113
PeerConfig
114-
MSPID string
114+
MSPID string
115+
Properties map[Property]interface{}
115116
}
116117

117118
// OrganizationConfig provides the definition of an organization in the network

pkg/common/providers/fab/peer.go

+20-1
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,29 @@ type Peer interface {
1616
//URL gets the peer address
1717
URL() string
1818

19-
// TODO: Roles, Name, EnrollmentCertificate (if needed)
19+
// Properties returns properties of the peer.
20+
Properties() Properties
21+
22+
// TODO: Name, EnrollmentCertificate (if needed)
2023
}
2124

2225
// PeerState provides state information about the Peer
2326
type PeerState interface {
2427
BlockHeight() uint64
2528
}
29+
30+
// Properties defines the properties of a peer
31+
type Properties map[Property]interface{}
32+
33+
// Property is the key into the Properties map
34+
type Property = string
35+
36+
// Following is a well-known list of properties of a peer, although this list may be extended.
37+
const (
38+
// PropertyChaincodes defines the chaincodes that are deployed on the peer. Value type:[]*github.com/hyperledger/fabric-protos-go/gossip.Chaincode
39+
PropertyChaincodes Property = "Chaincodes"
40+
// PropertyLedgerHeight defines the ledger height property. Value type: uint64
41+
PropertyLedgerHeight Property = "LedgerHeight"
42+
// PropertyLeftChannel defines the "left-channel" property which indicates whether the peer left the channel. Value type: bool
43+
PropertyLeftChannel Property = "LeftChannel"
44+
)

pkg/fab/discovery/mockdiscoveryclient.go

+2
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ func newStateInfoMessage(endpoint *mocks.MockDiscoveryPeerEndpoint) *gprotoext.S
196196
StateInfo: &gossip.StateInfo{
197197
Properties: &gossip.Properties{
198198
LedgerHeight: endpoint.LedgerHeight,
199+
Chaincodes: endpoint.Chaincodes,
200+
LeftChannel: endpoint.LeftChannel,
199201
},
200202
},
201203
},

pkg/fab/discovery/mocks/mockdiscoveryserver.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,9 @@ func asDiscoveryPeer(p *MockDiscoveryPeerEndpoint) *discovery.Peer {
178178
Content: &gossip.GossipMessage_StateInfo{
179179
StateInfo: &gossip.StateInfo{
180180
Properties: &gossip.Properties{
181-
Chaincodes: nil,
182181
LedgerHeight: p.LedgerHeight,
182+
Chaincodes: p.Chaincodes,
183+
LeftChannel: p.LeftChannel,
183184
},
184185
Timestamp: &gossip.PeerTime{
185186
SeqNum: uint64(1000),
@@ -208,6 +209,8 @@ type MockDiscoveryPeerEndpoint struct {
208209
MSPID string
209210
Endpoint string
210211
LedgerHeight uint64
212+
Chaincodes []*gossip.Chaincode
213+
LeftChannel bool
211214
}
212215

213216
func asPeersByOrg(peers []*MockDiscoveryPeerEndpoint) map[string]*discovery.Peers {

pkg/fab/discovery/util.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
Copyright SecureKey Technologies Inc. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package discovery
8+
9+
import (
10+
"reflect"
11+
"strings"
12+
13+
discclient "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/discovery/client"
14+
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
15+
)
16+
17+
// GetProperties extracts the properties from the discovered peer.
18+
func GetProperties(endpoint *discclient.Peer) fab.Properties {
19+
if endpoint.StateInfoMessage == nil {
20+
return nil
21+
}
22+
23+
stateInfo := endpoint.StateInfoMessage.GetStateInfo()
24+
if stateInfo == nil || stateInfo.Properties == nil {
25+
return nil
26+
}
27+
28+
properties := make(fab.Properties)
29+
30+
val := reflect.ValueOf(stateInfo.Properties).Elem()
31+
32+
for i := 0; i < val.NumField(); i++ {
33+
fType := val.Type().Field(i)
34+
35+
// Exclude protobuf fields
36+
if !strings.HasPrefix(fType.Name, "XXX_") {
37+
properties[fType.Name] = val.Field(i).Interface()
38+
}
39+
}
40+
41+
return properties
42+
}

0 commit comments

Comments
 (0)