Skip to content

Commit

Permalink
Use local peer ledger height from ledger instead of discovery in Gate…
Browse files Browse the repository at this point in the history
…way (hyperledger#4047)

Discovery ledger heights can be slightly behind the actual peer ledger height. Ensure the most up-to-date information is used for the local peer by querying the ledger height directly. This avoids the possibility of a remote peer with a lower ledger height being selected as an endorser.

Signed-off-by: Mark S. Lewis <[email protected]>
  • Loading branch information
bestbeforetoday authored Feb 20, 2023
1 parent 3d5ba57 commit ee26119
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 1 deletion.
24 changes: 24 additions & 0 deletions internal/pkg/gateway/endorse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,30 @@ func TestEndorse(t *testing.T) {
},
expectedEndorsers: []string{"localhost:7051", "peer2:9051"},
},
{
name: "use highest block height local org peer",
plan: endorsementPlan{
"g1": {{endorser: peer1Mock, height: 5}, {endorser: localhostMock, height: 4}}, // msp1
},
members: []networkMember{
{string(localhostMock.pkiid), localhostMock.address, localhostMock.mspid, 4},
{string(peer1Mock.pkiid), peer1Mock.address, peer1Mock.mspid, 5},
},
localLedgerHeight: 4,
expectedEndorsers: []string{peer1Mock.address},
},
{
name: "use local host ledger height",
plan: endorsementPlan{
"g1": {{endorser: peer1Mock, height: 5}, {endorser: localhostMock, height: 4}}, // msp1
},
members: []networkMember{
{string(localhostMock.pkiid), localhostMock.address, localhostMock.mspid, 4},
{string(peer1Mock.pkiid), peer1Mock.address, peer1Mock.mspid, 5},
},
localLedgerHeight: 6,
expectedEndorsers: []string{localhostMock.address},
},
{
name: "endorse with specified orgs, despite block height",
endorsingOrgs: []string{"msp1", "msp3"},
Expand Down
9 changes: 9 additions & 0 deletions internal/pkg/gateway/evaluate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,15 @@ func TestEvaluate(t *testing.T) {
errCode: codes.DeadlineExceeded,
errString: "evaluate timeout expired",
},
{
name: "uses local host ledger height",
members: []networkMember{
{"id2", "peer1:8051", "msp1", 6},
{"id1", "localhost:7051", "msp1", 5},
},
localLedgerHeight: 7,
expectedEndorsers: []string{"localhost:7051"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions internal/pkg/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ func newServer(localEndorser peerproto.EndorserClient,
remoteEndorsers: map[string]*endorser{},
channelInitialized: map[string]bool{},
systemChaincodes: systemChaincodes,
localProvider: ledgerProvider,
},
commitFinder: finder,
policy: policy,
Expand Down
33 changes: 32 additions & 1 deletion internal/pkg/gateway/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
gossipapi "github.com/hyperledger/fabric/gossip/api"
gossipcommon "github.com/hyperledger/fabric/gossip/common"
gossipdiscovery "github.com/hyperledger/fabric/gossip/discovery"
"github.com/hyperledger/fabric/internal/pkg/gateway/ledger"
"github.com/pkg/errors"
)

Expand All @@ -44,6 +45,7 @@ type registry struct {
configLock sync.RWMutex
channelOrderers sync.Map // channel (string) -> orderer addresses (endpointConfig)
systemChaincodes scc.BuiltinSCCs
localProvider ledger.Provider
}

type endorserState struct {
Expand Down Expand Up @@ -200,13 +202,42 @@ func (reg *registry) endorsersByOrg(channel string, chaincode string) map[string
}

func (reg *registry) channelMembers(channel string) gossipdiscovery.Members {
return reg.discovery.PeersOfChannel(gossipcommon.ChannelID(channel))
members := reg.discovery.PeersOfChannel(gossipcommon.ChannelID(channel))

// Ensure local endorser ledger height is up-to-date
for _, member := range members {
if reg.isLocalEndorserID(member.PKIid) {
if ledgerHeight, ok := reg.localLedgerHeight(channel); ok {
member.Properties.LedgerHeight = ledgerHeight
}

break
}
}

return members
}

func (reg *registry) isLocalEndorserID(pkiID gossipcommon.PKIidType) bool {
return !pkiID.IsNotSameFilter(reg.localEndorser.pkiid)
}

func (reg *registry) localLedgerHeight(channel string) (height uint64, ok bool) {
ledger, err := reg.localProvider.Ledger(channel)
if err != nil {
reg.logger.Warnw("local endorser is not a member of channel", "channel", channel, "err", err)
return 0, false
}

info, err := ledger.GetBlockchainInfo()
if err != nil {
logger.Errorw("failed to get local ledger info", "err", err)
return 0, false
}

return info.GetHeight(), true
}

// evaluator returns a plan representing a single endorsement, preferably from local org, if available
// targetOrgs specifies the orgs that are allowed receive the request, due to private data restrictions
func (reg *registry) evaluator(channel string, chaincode string, targetOrgs []string) (*plan, error) {
Expand Down

0 comments on commit ee26119

Please sign in to comment.