From 84785702479637f9f97bf54c1b6dce49434d6b9c Mon Sep 17 00:00:00 2001 From: andrew-coleman Date: Fri, 7 May 2021 10:23:09 +0100 Subject: [PATCH] FABGW-20 Specify endorsing organizations Implementation of endorsingOrgs in gateway Endorse method. - The set of endorsing peers from the discovery service is filtered down to only include those from the specified orgs. - The discovery handling code has been upgraded to step through all given layouts to find a layout that satisfies the endorsingOrgs constraint. Signed-off-by: andrew-coleman --- go.mod | 2 +- go.sum | 4 +- internal/pkg/gateway/api.go | 10 +- internal/pkg/gateway/api_test.go | 211 +++++++++++++----- .../commit/mock/notificationsupplier.go | 7 +- .../pkg/gateway/commit/mock/queryprovider.go | 7 +- internal/pkg/gateway/mocks/abbclient.go | 56 ++--- internal/pkg/gateway/mocks/abclient.go | 14 +- internal/pkg/gateway/mocks/aclchecker.go | 7 +- internal/pkg/gateway/mocks/commitfinder.go | 7 +- internal/pkg/gateway/mocks/dialer.go | 8 +- internal/pkg/gateway/mocks/discovery.go | 28 +-- internal/pkg/gateway/mocks/endorserclient.go | 7 +- internal/pkg/gateway/registry.go | 122 ++++++++-- .../fabric-protos-go/gateway/gateway.pb.go | 103 +++++---- vendor/modules.txt | 2 +- 16 files changed, 385 insertions(+), 210 deletions(-) diff --git a/go.mod b/go.mod index 77d41488d5e..a2fc3647549 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20201119163726-f8ef75b17719 github.com/hyperledger/fabric-config v0.1.0 github.com/hyperledger/fabric-lib-go v1.0.0 - github.com/hyperledger/fabric-protos-go v0.0.0-20210422135545-37e930696e2a + github.com/hyperledger/fabric-protos-go v0.0.0-20210505131505-0ac7fd605762 github.com/kr/pretty v0.2.1 github.com/magiconair/properties v1.8.1 // indirect github.com/mattn/go-runewidth v0.0.4 // indirect diff --git a/go.sum b/go.sum index 9ae433fc0b7..7411724ad1a 100644 --- a/go.sum +++ b/go.sum @@ -161,8 +161,8 @@ github.com/hyperledger/fabric-lib-go v1.0.0 h1:UL1w7c9LvHZUSkIvHTDGklxFv2kTeva1Q github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc= github.com/hyperledger/fabric-protos-go v0.0.0-20190919234611-2a87503ac7c9/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= -github.com/hyperledger/fabric-protos-go v0.0.0-20210422135545-37e930696e2a h1:sJwXhCxTQ7euBj+4w7pomn0CzOgdHkLlUOqtDgsI8IA= -github.com/hyperledger/fabric-protos-go v0.0.0-20210422135545-37e930696e2a/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= +github.com/hyperledger/fabric-protos-go v0.0.0-20210505131505-0ac7fd605762 h1:7eZyv7Ly+AY8y0e/8WCitouShlWcjBT9QJGf/8DGqHQ= +github.com/hyperledger/fabric-protos-go v0.0.0-20210505131505-0ac7fd605762/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= diff --git a/internal/pkg/gateway/api.go b/internal/pkg/gateway/api.go index 246c3bcbdc7..19cb0b7710e 100644 --- a/internal/pkg/gateway/api.go +++ b/internal/pkg/gateway/api.go @@ -37,7 +37,7 @@ func (gs *Server) Evaluate(ctx context.Context, request *gp.EvaluateRequest) (*g return nil, status.Errorf(codes.InvalidArgument, "failed to unpack transaction proposal: %s", err) } - endorsers, err := gs.registry.endorsers(channel, chaincodeID) + endorsers, err := gs.registry.endorsers(channel, chaincodeID) // TODO next story, implement endorsingOrgs for Evaluate if err != nil { return nil, status.Errorf(codes.Unavailable, "%s", err) } @@ -95,7 +95,13 @@ func (gs *Server) Endorse(ctx context.Context, request *gp.EndorseRequest) (*gp. if err != nil { return nil, status.Errorf(codes.InvalidArgument, "failed to unpack transaction proposal: %s", err) } - endorsers, err := gs.registry.endorsers(channel, chaincodeID) + + var endorsers []*endorser + if len(request.EndorsingOrganizations) > 0 { + endorsers, err = gs.registry.endorsersForOrgs(channel, chaincodeID, request.EndorsingOrganizations) + } else { + endorsers, err = gs.registry.endorsers(channel, chaincodeID) + } if err != nil { return nil, status.Errorf(codes.Unavailable, "%s", err) } diff --git a/internal/pkg/gateway/api_test.go b/internal/pkg/gateway/api_test.go index 619d2248c07..55801078d47 100644 --- a/internal/pkg/gateway/api_test.go +++ b/internal/pkg/gateway/api_test.go @@ -67,7 +67,10 @@ type aclChecker interface { ACLChecker } -type endorsementPlan map[string][]endorserState +type ( + endorsementPlan map[string][]endorserState + endorsementLayout map[string]uint32 +) type networkMember struct { id string @@ -103,11 +106,13 @@ const ( type testDef struct { name string plan endorsementPlan + layouts []endorsementLayout identity []byte localResponse string errString string errDetails []*pb.EndpointError endpointDefinition *endpointDef + endorsingOrgs []string postSetup func(t *testing.T, def *preparedTest) expectedEndorsers []string finderStatus peer.TxValidationCode @@ -129,12 +134,23 @@ type preparedTest struct { type contextKey string +var ( + localhostMock = &endorser{endpointConfig: &endpointConfig{address: "localhost:7051"}} + peer1Mock = &endorser{endpointConfig: &endpointConfig{address: "peer1:8051"}} + peer2Mock = &endorser{endpointConfig: &endpointConfig{address: "peer2:9051"}} + peer3Mock = &endorser{endpointConfig: &endpointConfig{address: "peer3:10051"}} + peer4Mock = &endorser{endpointConfig: &endpointConfig{address: "peer4:11051"}} + unavailable1Mock = &endorser{endpointConfig: &endpointConfig{address: "unavailable1:12051"}} + unavailable2Mock = &endorser{endpointConfig: &endpointConfig{address: "unavailable1:13051"}} + unavailable3Mock = &endorser{endpointConfig: &endpointConfig{address: "unavailable1:14051"}} +) + func TestEvaluate(t *testing.T) { tests := []testDef{ { name: "single endorser", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051"}}, + "g1": {{endorser: localhostMock}}, }, }, { @@ -145,23 +161,23 @@ func TestEvaluate(t *testing.T) { { name: "five endorsers, two groups, prefer largest ledger height", plan: endorsementPlan{ - "g1": {{endpoint: "peer3:10051", height: 4}, {endpoint: "localhost:7051", height: 4}, {endpoint: "peer4:11051", height: 4}}, - "g2": {{endpoint: "peer1:8051", height: 3}, {endpoint: "peer2:9051", height: 5}}, + "g1": {{endorser: peer3Mock, height: 4}, {endorser: localhostMock, height: 4}, {endorser: peer4Mock, height: 4}}, + "g2": {{endorser: peer1Mock, height: 3}, {endorser: peer2Mock, height: 5}}, }, expectedEndorsers: []string{"peer2:9051"}, }, { name: "five endorsers, two groups, prefer host peer", plan: endorsementPlan{ - "g1": {{endpoint: "peer3:10051", height: 4}, {endpoint: "localhost:7051", height: 4}, {endpoint: "peer4:11051", height: 4}}, - "g2": {{endpoint: "peer1:8051", height: 3}, {endpoint: "peer2:9051", height: 4}}, + "g1": {{endorser: peer3Mock, height: 4}, {endorser: localhostMock, height: 4}, {endorser: peer4Mock, height: 4}}, + "g2": {{endorser: peer1Mock, height: 3}, {endorser: peer2Mock, height: 4}}, }, expectedEndorsers: []string{"localhost:7051"}, }, { name: "discovery fails", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051"}}, + "g1": {{endorser: localhostMock}}, }, postSetup: func(t *testing.T, def *preparedTest) { def.discovery.PeersForEndorsementReturns(nil, fmt.Errorf("mango-tango")) @@ -171,7 +187,7 @@ func TestEvaluate(t *testing.T) { { name: "process proposal fails", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051"}}, + "g1": {{endorser: localhostMock}}, }, endpointDefinition: &endpointDef{ proposalError: status.Error(codes.Aborted, "mumbo-jumbo"), @@ -186,7 +202,7 @@ func TestEvaluate(t *testing.T) { { name: "process proposal chaincode error", plan: endorsementPlan{ - "g1": {{endpoint: "peer1:8051"}}, + "g1": {{endorser: peer1Mock}}, }, endpointDefinition: &endpointDef{ proposalResponseStatus: 400, @@ -202,7 +218,7 @@ func TestEvaluate(t *testing.T) { { name: "dialing endorser endpoint fails", plan: endorsementPlan{ - "g1": {{endpoint: "peer2:9051"}}, + "g1": {{endorser: peer2Mock}}, }, postSetup: func(t *testing.T, def *preparedTest) { def.dialer.Calls(func(_ context.Context, target string, _ ...grpc.DialOption) (*grpc.ClientConn, error) { @@ -217,7 +233,7 @@ func TestEvaluate(t *testing.T) { { name: "dialing orderer endpoint fails", plan: endorsementPlan{ - "g1": {{endpoint: "peer2:9051"}}, + "g1": {{endorser: peer2Mock}}, }, postSetup: func(t *testing.T, def *preparedTest) { def.dialer.Calls(func(_ context.Context, target string, _ ...grpc.DialOption) (*grpc.ClientConn, error) { @@ -277,26 +293,89 @@ func TestEndorse(t *testing.T) { { name: "two endorsers", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051", height: 3}}, - "g2": {{endpoint: "peer1:8051", height: 3}}, + "g1": {{endorser: localhostMock, height: 3}}, + "g2": {{endorser: peer1Mock, height: 3}}, }, + expectedEndorsers: []string{"localhost:7051", "peer1:8051"}, }, { name: "three endorsers, two groups", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051", height: 4}}, - "g2": {{endpoint: "peer1:8051", height: 4}, {endpoint: "peer2:9051", height: 5}}, + "g1": {{endorser: localhostMock, height: 4}}, + "g2": {{endorser: peer1Mock, height: 4}, {endorser: peer2Mock, height: 5}}, }, expectedEndorsers: []string{"localhost:7051", "peer2:9051"}, }, { - name: "three endorsers, two groups, prefer host peer", + name: "multiple endorsers, two groups, prefer host peer", plan: endorsementPlan{ - "g1": {{endpoint: "peer3:10051", height: 4}, {endpoint: "localhost:7051", height: 4}, {endpoint: "peer4:11051", height: 4}}, - "g2": {{endpoint: "peer1:8051", height: 4}, {endpoint: "peer2:9051", height: 5}}, + "g1": {{endorser: peer3Mock, height: 4}, {endorser: localhostMock, height: 4}, {endorser: unavailable1Mock, height: 4}}, + "g2": {{endorser: peer1Mock, height: 4}, {endorser: peer2Mock, height: 5}}, }, expectedEndorsers: []string{"localhost:7051", "peer2:9051"}, }, + { + name: "endorse with specified orgs, despite block height", + endorsingOrgs: []string{"msp1", "msp3"}, + expectedEndorsers: []string{"localhost:7051", "peer4:11051"}, + }, + { + name: "endorse with specified orgs, doesn't include local peer", + endorsingOrgs: []string{"msp2", "msp3"}, + expectedEndorsers: []string{"peer2:9051", "peer4:11051"}, + }, + { + name: "endorse with specified orgs, but fails to satisfy one org", + endorsingOrgs: []string{"msp2", "msp4"}, + errString: "failed to find any endorsing peers for org(s): msp4", + }, + { + name: "endorse with specified orgs, but fails to satisfy two orgs", + endorsingOrgs: []string{"msp2", "msp4", "msp5"}, + errString: "failed to find any endorsing peers for org(s): msp4, msp5", + }, + { + name: "endorse with multiple layouts - default choice first layout", + plan: endorsementPlan{ + "g1": {{endorser: localhostMock, height: 4}, {endorser: peer1Mock, height: 4}}, // msp1 + "g2": {{endorser: peer2Mock, height: 3}, {endorser: peer3Mock, height: 4}}, // msp2 + "g3": {{endorser: peer4Mock, height: 5}}, // msp3 + }, + layouts: []endorsementLayout{ + {"g1": 1, "g2": 1}, + {"g1": 1, "g3": 1}, + {"g2": 1, "g3": 1}, + }, + expectedEndorsers: []string{"localhost:7051", "peer3:10051"}, + }, + { + name: "endorse with multiple layouts - non-availability forces second layout", + plan: endorsementPlan{ + "g1": {{endorser: localhostMock, height: 4}, {endorser: peer1Mock, height: 4}}, // msp1 + "g2": {{endorser: unavailable1Mock, height: 3}, {endorser: unavailable2Mock, height: 4}}, // msp2 + "g3": {{endorser: peer4Mock, height: 5}}, // msp3 + }, + layouts: []endorsementLayout{ + {"g1": 1, "g2": 1}, + {"g1": 1, "g3": 1}, + {"g2": 1, "g3": 1}, + }, + expectedEndorsers: []string{"localhost:7051", "peer4:11051"}, + }, + { + name: "endorse with multiple layouts - non-availability of peers fails on all layouts", + plan: endorsementPlan{ + "g1": {{endorser: localhostMock, height: 4}, {endorser: peer1Mock, height: 4}}, // msp1 + "g2": {{endorser: unavailable1Mock, height: 3}, {endorser: unavailable2Mock, height: 4}}, // msp2 + "g3": {{endorser: unavailable3Mock, height: 5}}, // msp3 + }, + layouts: []endorsementLayout{ + {"g1": 1, "g2": 1}, + {"g1": 1, "g3": 1}, + {"g2": 1, "g3": 1}, + }, + errString: "failed to select a set of endorsers that satisfy the endorsement policy", + }, { name: "no endorsers", plan: endorsementPlan{}, @@ -305,8 +384,8 @@ func TestEndorse(t *testing.T) { { name: "non-matching responses", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051", height: 4}}, - "g2": {{endpoint: "peer1:8051", height: 5}}, + "g1": {{endorser: localhostMock, height: 4}}, + "g2": {{endorser: peer1Mock, height: 5}}, }, localResponse: "different_response", errString: "failed to assemble transaction: ProposalResponsePayloads do not match", @@ -314,7 +393,7 @@ func TestEndorse(t *testing.T) { { name: "discovery fails", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051", height: 2}}, + "g1": {{endorser: localhostMock, height: 2}}, }, postSetup: func(t *testing.T, def *preparedTest) { def.discovery.PeersForEndorsementReturns(nil, fmt.Errorf("peach-melba")) @@ -324,7 +403,7 @@ func TestEndorse(t *testing.T) { { name: "process proposal fails", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051", height: 1}}, + "g1": {{endorser: localhostMock, height: 1}}, }, endpointDefinition: &endpointDef{ proposalError: status.Error(codes.Aborted, "wibble"), @@ -339,7 +418,7 @@ func TestEndorse(t *testing.T) { { name: "process proposal chaincode error", plan: endorsementPlan{ - "g1": {{endpoint: "peer1:8051", height: 2}}, + "g1": {{endorser: peer1Mock, height: 2}}, }, endpointDefinition: &endpointDef{ proposalResponseStatus: 400, @@ -357,7 +436,7 @@ func TestEndorse(t *testing.T) { t.Run(tt.name, func(t *testing.T) { test := prepareTest(t, &tt) - response, err := test.server.Endorse(test.ctx, &pb.EndorseRequest{ProposedTransaction: test.signedProposal}) + response, err := test.server.Endorse(test.ctx, &pb.EndorseRequest{ProposedTransaction: test.signedProposal, EndorsingOrganizations: tt.endorsingOrgs}) if tt.errString != "" { checkError(t, err, tt.errString, tt.errDetails) @@ -381,23 +460,32 @@ func TestEndorse(t *testing.T) { cap, err := protoutil.UnmarshalChaincodeActionPayload(txn.Actions[0].Payload) require.NoError(t, err) endorsements := cap.Action.Endorsements - require.Len(t, endorsements, len(tt.plan)) + expectedLen := len(tt.expectedEndorsers) + require.Len(t, endorsements, expectedLen) // check the discovery service (mock) was invoked as expected - require.Equal(t, 1, test.discovery.PeersForEndorsementCallCount()) - channel, interest := test.discovery.PeersForEndorsementArgsForCall(0) expectedChannel := common.ChannelID(testChannel) expectedInterest := &dp.ChaincodeInterest{ Chaincodes: []*dp.ChaincodeCall{{ Name: testChaincode, }}, } - require.Equal(t, expectedChannel, channel) - require.Equal(t, expectedInterest, interest) - - require.Equal(t, 1, test.discovery.PeersOfChannelCallCount()) - channel = test.discovery.PeersOfChannelArgsForCall(0) - require.Equal(t, expectedChannel, channel) + if tt.endorsingOrgs != nil { + require.Equal(t, 2, test.discovery.PeersOfChannelCallCount()) + channel := test.discovery.PeersOfChannelArgsForCall(0) + require.Equal(t, expectedChannel, channel) + channel = test.discovery.PeersOfChannelArgsForCall(1) + require.Equal(t, expectedChannel, channel) + } else { + require.Equal(t, 1, test.discovery.PeersForEndorsementCallCount()) + channel, interest := test.discovery.PeersForEndorsementArgsForCall(0) + require.Equal(t, expectedChannel, channel) + require.Equal(t, expectedInterest, interest) + + require.Equal(t, 1, test.discovery.PeersOfChannelCallCount()) + channel = test.discovery.PeersOfChannelArgsForCall(0) + require.Equal(t, expectedChannel, channel) + } require.Equal(t, 1, test.discovery.IdentityInfoCallCount()) }) @@ -409,14 +497,14 @@ func TestSubmit(t *testing.T) { { name: "two endorsers", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051", height: 3}}, - "g2": {{endpoint: "peer1:8051", height: 3}}, + "g1": {{endorser: localhostMock, height: 3}}, + "g2": {{endorser: peer1Mock, height: 3}}, }, }, { name: "discovery fails", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051"}}, + "g1": {{endorser: localhostMock}}, }, postSetup: func(t *testing.T, def *preparedTest) { def.discovery.ConfigReturnsOnCall(1, nil, fmt.Errorf("jabberwocky")) @@ -426,7 +514,7 @@ func TestSubmit(t *testing.T) { { name: "no orderers", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051"}}, + "g1": {{endorser: localhostMock}}, }, postSetup: func(t *testing.T, def *preparedTest) { def.discovery.ConfigReturns(&dp.ConfigResult{ @@ -439,7 +527,7 @@ func TestSubmit(t *testing.T) { { name: "orderer broadcast fails", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051"}}, + "g1": {{endorser: localhostMock}}, }, endpointDefinition: &endpointDef{ proposalResponseStatus: 200, @@ -455,7 +543,7 @@ func TestSubmit(t *testing.T) { { name: "send to orderer fails", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051"}}, + "g1": {{endorser: localhostMock}}, }, endpointDefinition: &endpointDef{ proposalResponseStatus: 200, @@ -471,7 +559,7 @@ func TestSubmit(t *testing.T) { { name: "receive from orderer fails", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051"}}, + "g1": {{endorser: localhostMock}}, }, endpointDefinition: &endpointDef{ proposalResponseStatus: 200, @@ -487,7 +575,7 @@ func TestSubmit(t *testing.T) { { name: "orderer Send() returns nil", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051"}}, + "g1": {{endorser: localhostMock}}, }, postSetup: func(t *testing.T, def *preparedTest) { def.server.registry.endpointFactory.connectOrderer = func(_ *grpc.ClientConn) ab.AtomicBroadcastClient { @@ -503,7 +591,7 @@ func TestSubmit(t *testing.T) { { name: "orderer returns unsuccessful response", plan: endorsementPlan{ - "g1": {{endpoint: "localhost:7051"}}, + "g1": {{endorser: localhostMock}}, }, postSetup: func(t *testing.T, def *preparedTest) { def.server.registry.endpointFactory.connectOrderer = func(_ *grpc.ClientConn) ab.AtomicBroadcastClient { @@ -746,10 +834,12 @@ func prepareTest(t *testing.T, tt *testDef) *preparedTest { members := []networkMember{ {"id1", "localhost:7051", "msp1"}, {"id2", "peer1:8051", "msp1"}, - {"id3", "peer2:9051", "msp1"}, + {"id3", "peer2:9051", "msp2"}, + {"id4", "peer3:10051", "msp2"}, + {"id5", "peer4:11051", "msp3"}, } - disc := mockDiscovery(t, tt.plan, members, configResult) + disc := mockDiscovery(t, tt.plan, tt.layouts, members, configResult) options := config.Options{ Enabled: true, @@ -805,7 +895,7 @@ func checkEndorsers(t *testing.T, endorsers []string, test *preparedTest) { } else { ec = test.server.registry.remoteEndorsers[e].client.(*mocks.EndorserClient) } - require.Equal(t, 1, ec.ProcessProposalCallCount()) + require.Equal(t, 1, ec.ProcessProposalCallCount(), "Expected ProcessProposal() to be invoked on %s", e) ectx, prop, _ := ec.ProcessProposalArgsForCall(0) require.Equal(t, test.signedProposal, prop) require.Equal(t, "apples", ectx.Value(contextKey("orange"))) @@ -816,16 +906,20 @@ func checkEndorsers(t *testing.T, endorsers []string, test *preparedTest) { } } -func mockDiscovery(t *testing.T, plan endorsementPlan, members []networkMember, config *dp.ConfigResult) *mocks.Discovery { +func mockDiscovery(t *testing.T, plan endorsementPlan, layouts []endorsementLayout, members []networkMember, config *dp.ConfigResult) *mocks.Discovery { discovery := &mocks.Discovery{} var peers []gdiscovery.NetworkMember var infoset []api.PeerIdentityInfo for _, member := range members { - peers = append(peers, gdiscovery.NetworkMember{Endpoint: member.endpoint, PKIid: []byte(member.id)}) + peers = append(peers, gdiscovery.NetworkMember{ + Endpoint: member.endpoint, + PKIid: []byte(member.id), + Properties: &gossip.Properties{Chaincodes: []*gossip.Chaincode{{Name: testChaincode}}}, + }) infoset = append(infoset, api.PeerIdentityInfo{Organization: []byte(member.mspid), PKIId: []byte(member.id)}) } - ed := createMockEndorsementDescriptor(t, plan) + ed := createMockEndorsementDescriptor(t, plan, layouts) discovery.PeersForEndorsementReturns(ed, nil) discovery.PeersOfChannelReturns(peers) discovery.IdentityInfoReturns(infoset) @@ -833,24 +927,29 @@ func mockDiscovery(t *testing.T, plan endorsementPlan, members []networkMember, return discovery } -func createMockEndorsementDescriptor(t *testing.T, plan map[string][]endorserState) *dp.EndorsementDescriptor { +func createMockEndorsementDescriptor(t *testing.T, plan endorsementPlan, layouts []endorsementLayout) *dp.EndorsementDescriptor { quantitiesByGroup := map[string]uint32{} endorsersByGroups := map[string]*dp.Peers{} for group, endorsers := range plan { quantitiesByGroup[group] = 1 // for now var peers []*dp.Peer for _, endorser := range endorsers { - peers = append(peers, createMockPeer(t, endorser.endpoint, endorser.height)) + peers = append(peers, createMockPeer(t, endorser.endorser.address, endorser.height)) } endorsersByGroups[group] = &dp.Peers{Peers: peers} } + var layoutDef []*dp.Layout + if layouts != nil { + for _, layout := range layouts { + layoutDef = append(layoutDef, &dp.Layout{QuantitiesByGroup: layout}) + } + } else { + // default single layout - one from each group + layoutDef = []*dp.Layout{{QuantitiesByGroup: quantitiesByGroup}} + } descriptor := &dp.EndorsementDescriptor{ - Chaincode: "my_channel", - Layouts: []*dp.Layout{ - { - QuantitiesByGroup: quantitiesByGroup, - }, - }, + Chaincode: "my_channel", + Layouts: layoutDef, EndorsersByGroups: endorsersByGroups, } return descriptor diff --git a/internal/pkg/gateway/commit/mock/notificationsupplier.go b/internal/pkg/gateway/commit/mock/notificationsupplier.go index ebeaeb0f582..c7dec33552c 100644 --- a/internal/pkg/gateway/commit/mock/notificationsupplier.go +++ b/internal/pkg/gateway/commit/mock/notificationsupplier.go @@ -33,16 +33,15 @@ func (fake *NotificationSupplier) CommitNotifications(arg1 <-chan struct{}, arg2 arg1 <-chan struct{} arg2 string }{arg1, arg2}) - stub := fake.CommitNotificationsStub - fakeReturns := fake.commitNotificationsReturns fake.recordInvocation("CommitNotifications", []interface{}{arg1, arg2}) fake.commitNotificationsMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) + if fake.CommitNotificationsStub != nil { + return fake.CommitNotificationsStub(arg1, arg2) } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.commitNotificationsReturns return fakeReturns.result1, fakeReturns.result2 } diff --git a/internal/pkg/gateway/commit/mock/queryprovider.go b/internal/pkg/gateway/commit/mock/queryprovider.go index e03c506d992..3de82c4a4fc 100644 --- a/internal/pkg/gateway/commit/mock/queryprovider.go +++ b/internal/pkg/gateway/commit/mock/queryprovider.go @@ -33,16 +33,15 @@ func (fake *QueryProvider) TransactionStatus(arg1 string, arg2 string) (peer.TxV arg1 string arg2 string }{arg1, arg2}) - stub := fake.TransactionStatusStub - fakeReturns := fake.transactionStatusReturns fake.recordInvocation("TransactionStatus", []interface{}{arg1, arg2}) fake.transactionStatusMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) + if fake.TransactionStatusStub != nil { + return fake.TransactionStatusStub(arg1, arg2) } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.transactionStatusReturns return fakeReturns.result1, fakeReturns.result2 } diff --git a/internal/pkg/gateway/mocks/abbclient.go b/internal/pkg/gateway/mocks/abbclient.go index 7a5222d5a43..7a8b2109488 100644 --- a/internal/pkg/gateway/mocks/abbclient.go +++ b/internal/pkg/gateway/mocks/abbclient.go @@ -107,16 +107,15 @@ func (fake *ABBClient) CloseSend() error { ret, specificReturn := fake.closeSendReturnsOnCall[len(fake.closeSendArgsForCall)] fake.closeSendArgsForCall = append(fake.closeSendArgsForCall, struct { }{}) - stub := fake.CloseSendStub - fakeReturns := fake.closeSendReturns fake.recordInvocation("CloseSend", []interface{}{}) fake.closeSendMutex.Unlock() - if stub != nil { - return stub() + if fake.CloseSendStub != nil { + return fake.CloseSendStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.closeSendReturns return fakeReturns.result1 } @@ -160,16 +159,15 @@ func (fake *ABBClient) Context() context.Context { ret, specificReturn := fake.contextReturnsOnCall[len(fake.contextArgsForCall)] fake.contextArgsForCall = append(fake.contextArgsForCall, struct { }{}) - stub := fake.ContextStub - fakeReturns := fake.contextReturns fake.recordInvocation("Context", []interface{}{}) fake.contextMutex.Unlock() - if stub != nil { - return stub() + if fake.ContextStub != nil { + return fake.ContextStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.contextReturns return fakeReturns.result1 } @@ -213,16 +211,15 @@ func (fake *ABBClient) Header() (metadata.MD, error) { ret, specificReturn := fake.headerReturnsOnCall[len(fake.headerArgsForCall)] fake.headerArgsForCall = append(fake.headerArgsForCall, struct { }{}) - stub := fake.HeaderStub - fakeReturns := fake.headerReturns fake.recordInvocation("Header", []interface{}{}) fake.headerMutex.Unlock() - if stub != nil { - return stub() + if fake.HeaderStub != nil { + return fake.HeaderStub() } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.headerReturns return fakeReturns.result1, fakeReturns.result2 } @@ -269,16 +266,15 @@ func (fake *ABBClient) Recv() (*orderer.BroadcastResponse, error) { ret, specificReturn := fake.recvReturnsOnCall[len(fake.recvArgsForCall)] fake.recvArgsForCall = append(fake.recvArgsForCall, struct { }{}) - stub := fake.RecvStub - fakeReturns := fake.recvReturns fake.recordInvocation("Recv", []interface{}{}) fake.recvMutex.Unlock() - if stub != nil { - return stub() + if fake.RecvStub != nil { + return fake.RecvStub() } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.recvReturns return fakeReturns.result1, fakeReturns.result2 } @@ -326,16 +322,15 @@ func (fake *ABBClient) RecvMsg(arg1 interface{}) error { fake.recvMsgArgsForCall = append(fake.recvMsgArgsForCall, struct { arg1 interface{} }{arg1}) - stub := fake.RecvMsgStub - fakeReturns := fake.recvMsgReturns fake.recordInvocation("RecvMsg", []interface{}{arg1}) fake.recvMsgMutex.Unlock() - if stub != nil { - return stub(arg1) + if fake.RecvMsgStub != nil { + return fake.RecvMsgStub(arg1) } if specificReturn { return ret.result1 } + fakeReturns := fake.recvMsgReturns return fakeReturns.result1 } @@ -387,16 +382,15 @@ func (fake *ABBClient) Send(arg1 *common.Envelope) error { fake.sendArgsForCall = append(fake.sendArgsForCall, struct { arg1 *common.Envelope }{arg1}) - stub := fake.SendStub - fakeReturns := fake.sendReturns fake.recordInvocation("Send", []interface{}{arg1}) fake.sendMutex.Unlock() - if stub != nil { - return stub(arg1) + if fake.SendStub != nil { + return fake.SendStub(arg1) } if specificReturn { return ret.result1 } + fakeReturns := fake.sendReturns return fakeReturns.result1 } @@ -448,16 +442,15 @@ func (fake *ABBClient) SendMsg(arg1 interface{}) error { fake.sendMsgArgsForCall = append(fake.sendMsgArgsForCall, struct { arg1 interface{} }{arg1}) - stub := fake.SendMsgStub - fakeReturns := fake.sendMsgReturns fake.recordInvocation("SendMsg", []interface{}{arg1}) fake.sendMsgMutex.Unlock() - if stub != nil { - return stub(arg1) + if fake.SendMsgStub != nil { + return fake.SendMsgStub(arg1) } if specificReturn { return ret.result1 } + fakeReturns := fake.sendMsgReturns return fakeReturns.result1 } @@ -508,16 +501,15 @@ func (fake *ABBClient) Trailer() metadata.MD { ret, specificReturn := fake.trailerReturnsOnCall[len(fake.trailerArgsForCall)] fake.trailerArgsForCall = append(fake.trailerArgsForCall, struct { }{}) - stub := fake.TrailerStub - fakeReturns := fake.trailerReturns fake.recordInvocation("Trailer", []interface{}{}) fake.trailerMutex.Unlock() - if stub != nil { - return stub() + if fake.TrailerStub != nil { + return fake.TrailerStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.trailerReturns return fakeReturns.result1 } diff --git a/internal/pkg/gateway/mocks/abclient.go b/internal/pkg/gateway/mocks/abclient.go index 09624741d2a..4ea5ba66af9 100644 --- a/internal/pkg/gateway/mocks/abclient.go +++ b/internal/pkg/gateway/mocks/abclient.go @@ -49,16 +49,15 @@ func (fake *ABClient) Broadcast(arg1 context.Context, arg2 ...grpc.CallOption) ( arg1 context.Context arg2 []grpc.CallOption }{arg1, arg2}) - stub := fake.BroadcastStub - fakeReturns := fake.broadcastReturns fake.recordInvocation("Broadcast", []interface{}{arg1, arg2}) fake.broadcastMutex.Unlock() - if stub != nil { - return stub(arg1, arg2...) + if fake.BroadcastStub != nil { + return fake.BroadcastStub(arg1, arg2...) } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.broadcastReturns return fakeReturns.result1, fakeReturns.result2 } @@ -114,16 +113,15 @@ func (fake *ABClient) Deliver(arg1 context.Context, arg2 ...grpc.CallOption) (or arg1 context.Context arg2 []grpc.CallOption }{arg1, arg2}) - stub := fake.DeliverStub - fakeReturns := fake.deliverReturns fake.recordInvocation("Deliver", []interface{}{arg1, arg2}) fake.deliverMutex.Unlock() - if stub != nil { - return stub(arg1, arg2...) + if fake.DeliverStub != nil { + return fake.DeliverStub(arg1, arg2...) } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.deliverReturns return fakeReturns.result1, fakeReturns.result2 } diff --git a/internal/pkg/gateway/mocks/aclchecker.go b/internal/pkg/gateway/mocks/aclchecker.go index 26edba54100..1ef48c10eb2 100644 --- a/internal/pkg/gateway/mocks/aclchecker.go +++ b/internal/pkg/gateway/mocks/aclchecker.go @@ -31,16 +31,15 @@ func (fake *ACLChecker) CheckACL(arg1 string, arg2 string, arg3 interface{}) err arg2 string arg3 interface{} }{arg1, arg2, arg3}) - stub := fake.CheckACLStub - fakeReturns := fake.checkACLReturns fake.recordInvocation("CheckACL", []interface{}{arg1, arg2, arg3}) fake.checkACLMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) + if fake.CheckACLStub != nil { + return fake.CheckACLStub(arg1, arg2, arg3) } if specificReturn { return ret.result1 } + fakeReturns := fake.checkACLReturns return fakeReturns.result1 } diff --git a/internal/pkg/gateway/mocks/commitfinder.go b/internal/pkg/gateway/mocks/commitfinder.go index 546cc322e62..43466abbfb7 100644 --- a/internal/pkg/gateway/mocks/commitfinder.go +++ b/internal/pkg/gateway/mocks/commitfinder.go @@ -36,16 +36,15 @@ func (fake *CommitFinder) TransactionStatus(arg1 context.Context, arg2 string, a arg2 string arg3 string }{arg1, arg2, arg3}) - stub := fake.TransactionStatusStub - fakeReturns := fake.transactionStatusReturns fake.recordInvocation("TransactionStatus", []interface{}{arg1, arg2, arg3}) fake.transactionStatusMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) + if fake.TransactionStatusStub != nil { + return fake.TransactionStatusStub(arg1, arg2, arg3) } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.transactionStatusReturns return fakeReturns.result1, fakeReturns.result2 } diff --git a/internal/pkg/gateway/mocks/dialer.go b/internal/pkg/gateway/mocks/dialer.go index bda7357283e..0cea2a58819 100644 --- a/internal/pkg/gateway/mocks/dialer.go +++ b/internal/pkg/gateway/mocks/dialer.go @@ -36,17 +36,15 @@ func (fake *Dialer) Spy(arg1 context.Context, arg2 string, arg3 ...grpc.DialOpti arg2 string arg3 []grpc.DialOption }{arg1, arg2, arg3}) - stub := fake.Stub - returns := fake.returns fake.recordInvocation("dialer", []interface{}{arg1, arg2, arg3}) fake.mutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3...) + if fake.Stub != nil { + return fake.Stub(arg1, arg2, arg3...) } if specificReturn { return ret.result1, ret.result2 } - return returns.result1, returns.result2 + return fake.returns.result1, fake.returns.result2 } func (fake *Dialer) CallCount() int { diff --git a/internal/pkg/gateway/mocks/discovery.go b/internal/pkg/gateway/mocks/discovery.go index 841facfe243..803ee62ddcb 100644 --- a/internal/pkg/gateway/mocks/discovery.go +++ b/internal/pkg/gateway/mocks/discovery.go @@ -69,16 +69,15 @@ func (fake *Discovery) Config(arg1 string) (*discovery.ConfigResult, error) { fake.configArgsForCall = append(fake.configArgsForCall, struct { arg1 string }{arg1}) - stub := fake.ConfigStub - fakeReturns := fake.configReturns fake.recordInvocation("Config", []interface{}{arg1}) fake.configMutex.Unlock() - if stub != nil { - return stub(arg1) + if fake.ConfigStub != nil { + return fake.ConfigStub(arg1) } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.configReturns return fakeReturns.result1, fakeReturns.result2 } @@ -132,16 +131,15 @@ func (fake *Discovery) IdentityInfo() api.PeerIdentitySet { ret, specificReturn := fake.identityInfoReturnsOnCall[len(fake.identityInfoArgsForCall)] fake.identityInfoArgsForCall = append(fake.identityInfoArgsForCall, struct { }{}) - stub := fake.IdentityInfoStub - fakeReturns := fake.identityInfoReturns fake.recordInvocation("IdentityInfo", []interface{}{}) fake.identityInfoMutex.Unlock() - if stub != nil { - return stub() + if fake.IdentityInfoStub != nil { + return fake.IdentityInfoStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.identityInfoReturns return fakeReturns.result1 } @@ -187,16 +185,15 @@ func (fake *Discovery) PeersForEndorsement(arg1 common.ChannelID, arg2 *discover arg1 common.ChannelID arg2 *discovery.ChaincodeInterest }{arg1, arg2}) - stub := fake.PeersForEndorsementStub - fakeReturns := fake.peersForEndorsementReturns fake.recordInvocation("PeersForEndorsement", []interface{}{arg1, arg2}) fake.peersForEndorsementMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) + if fake.PeersForEndorsementStub != nil { + return fake.PeersForEndorsementStub(arg1, arg2) } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.peersForEndorsementReturns return fakeReturns.result1, fakeReturns.result2 } @@ -251,16 +248,15 @@ func (fake *Discovery) PeersOfChannel(arg1 common.ChannelID) discoverya.Members fake.peersOfChannelArgsForCall = append(fake.peersOfChannelArgsForCall, struct { arg1 common.ChannelID }{arg1}) - stub := fake.PeersOfChannelStub - fakeReturns := fake.peersOfChannelReturns fake.recordInvocation("PeersOfChannel", []interface{}{arg1}) fake.peersOfChannelMutex.Unlock() - if stub != nil { - return stub(arg1) + if fake.PeersOfChannelStub != nil { + return fake.PeersOfChannelStub(arg1) } if specificReturn { return ret.result1 } + fakeReturns := fake.peersOfChannelReturns return fakeReturns.result1 } diff --git a/internal/pkg/gateway/mocks/endorserclient.go b/internal/pkg/gateway/mocks/endorserclient.go index f363a343508..dfc7374abec 100644 --- a/internal/pkg/gateway/mocks/endorserclient.go +++ b/internal/pkg/gateway/mocks/endorserclient.go @@ -37,16 +37,15 @@ func (fake *EndorserClient) ProcessProposal(arg1 context.Context, arg2 *peer.Sig arg2 *peer.SignedProposal arg3 []grpc.CallOption }{arg1, arg2, arg3}) - stub := fake.ProcessProposalStub - fakeReturns := fake.processProposalReturns fake.recordInvocation("ProcessProposal", []interface{}{arg1, arg2, arg3}) fake.processProposalMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3...) + if fake.ProcessProposalStub != nil { + return fake.ProcessProposalStub(arg1, arg2, arg3...) } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.processProposalReturns return fakeReturns.result1, fakeReturns.result2 } diff --git a/internal/pkg/gateway/registry.go b/internal/pkg/gateway/registry.go index e159462ffe6..4009afdb2ac 100644 --- a/internal/pkg/gateway/registry.go +++ b/internal/pkg/gateway/registry.go @@ -9,6 +9,7 @@ package gateway import ( "fmt" "sort" + "strings" "sync" "github.com/golang/protobuf/proto" @@ -41,7 +42,7 @@ type registry struct { type endorserState struct { peer *dp.Peer - endpoint string + endorser *endorser height uint64 } @@ -65,21 +66,18 @@ func (reg *registry) endorsers(channel string, chaincode string) ([]*endorser, e return nil, err } - e := descriptor.EndorsersByGroups - reg.configLock.RLock() defer reg.configLock.RUnlock() - // choose first layout for now - todo implement retry logic - if len(descriptor.Layouts) > 0 { - layout := descriptor.Layouts[0].QuantitiesByGroup - var r []*endorserState - for group, quantity := range layout { + for _, layout := range descriptor.Layouts { + var receivers []*endorserState // The set of peers the client needs to request endorsements from + abandonLayout := false + for group, quantity := range layout.QuantitiesByGroup { // Select n remoteEndorsers from each group sorted by block height // block heights var groupPeers []*endorserState - for _, peer := range e[group].Peers { + for _, peer := range descriptor.EndorsersByGroups[group].Peers { msg := &gossip.GossipMessage{} err := proto.Unmarshal(peer.StateInfo.Payload, msg) if err != nil { @@ -93,26 +91,97 @@ func (reg *registry) endorsers(channel string, chaincode string) ([]*endorser, e } endpoint := msg.GetAliveMsg().Membership.Endpoint - groupPeers = append(groupPeers, &endorserState{peer: peer, endpoint: endpoint, height: height}) + // find the endorser in the registry for this endpoint + var endorser *endorser + if endpoint == reg.localEndorser.address { + endorser = reg.localEndorser + } else if e, ok := reg.remoteEndorsers[endpoint]; ok { + endorser = e + } else { + reg.logger.Warnf("Failed to find endorser at %s", endpoint) + continue + } + + groupPeers = append(groupPeers, &endorserState{peer: peer, endorser: endorser, height: height}) + } + + // If the number of available endorsers less than the quantity required, try the next layout + if len(groupPeers) < int(quantity) { + abandonLayout = true + break } + // sort by decreasing height sort.Slice(groupPeers, sorter(groupPeers, reg.localEndorser.address)) - peerGroup := groupPeers[0:quantity] - r = append(r, peerGroup...) + receivers = append(receivers, groupPeers[0:quantity]...) + } + + if abandonLayout { + // try the next layout + continue } + // sort the group of groups by decreasing height (since Evaluate will just choose the first one) - sort.Slice(r, sorter(r, reg.localEndorser.address)) - - for _, peer := range r { - if peer.endpoint == reg.localEndorser.address { - endorsers = append(endorsers, reg.localEndorser) - } else if endorser, ok := reg.remoteEndorsers[peer.endpoint]; ok { - endorsers = append(endorsers, endorser) - } else { - reg.logger.Warnf("Failed to find endorser at %s", peer.endpoint) + sort.Slice(receivers, sorter(receivers, reg.localEndorser.address)) + + for _, peer := range receivers { + endorsers = append(endorsers, peer.endorser) + } + return endorsers, nil + } + + return nil, fmt.Errorf("failed to select a set of endorsers that satisfy the endorsement policy") +} + +// endorsersForOrgs returns a set of endorsers owned by the given orgs for the given chaincode on a channel. +func (reg *registry) endorsersForOrgs(channel string, chaincode string, endorsingOrgs []string) ([]*endorser, error) { + err := reg.registerChannel(channel) + if err != nil { + return nil, err + } + + endorsersByOrg := make(map[string][]*endorserState) + + members := reg.discovery.PeersOfChannel(common.ChannelID(channel)) + for _, member := range members { + endpoint := member.Endpoint + // find the endorser in the registry for this endpoint + var endorser *endorser + if endpoint == reg.localEndorser.address { + endorser = reg.localEndorser + } else if e, ok := reg.remoteEndorsers[endpoint]; ok { + endorser = e + } else { + reg.logger.Warnf("Failed to find endorser at %s", endpoint) + continue + } + // check the org membership + if contains(endorsingOrgs, endorser.mspid) && member.Properties != nil { + for _, installedChaincode := range member.Properties.Chaincodes { + // only consider the peers that have our chaincode installed + if installedChaincode.Name == chaincode { + endorsersByOrg[endorser.mspid] = append(endorsersByOrg[endorser.mspid], &endorserState{endorser: endorser, height: member.Properties.LedgerHeight}) + } + } + } + } + + if len(endorsersByOrg) != len(endorsingOrgs) { + missingOrgs := []string{} + for _, required := range endorsingOrgs { + if _, ok := endorsersByOrg[required]; !ok { + missingOrgs = append(missingOrgs, required) } } + return nil, fmt.Errorf("failed to find any endorsing peers for org(s): %s", strings.Join(missingOrgs, ", ")) + } + + var endorsers []*endorser + for _, es := range endorsersByOrg { + // sort by decreasing height and select the highest one from each org + sort.Slice(es, sorter(es, reg.localEndorser.address)) + endorsers = append(endorsers, es[0].endorser) } return endorsers, nil @@ -122,12 +191,21 @@ func sorter(e []*endorserState, host string) func(i, j int) bool { return func(i, j int) bool { if e[i].height == e[j].height { // prefer host peer - return e[i].endpoint == host + return e[i].endorser.address == host } return e[i].height > e[j].height } } +func contains(slice []string, entry string) bool { + for _, item := range slice { + if entry == item { + return true + } + } + return false +} + // Returns a set of broadcastClients that can order a transaction for the given channel. func (reg *registry) orderers(channel string) ([]*orderer, error) { err := reg.registerChannel(channel) diff --git a/vendor/github.com/hyperledger/fabric-protos-go/gateway/gateway.pb.go b/vendor/github.com/hyperledger/fabric-protos-go/gateway/gateway.pb.go index ecac0a1795d..16ff93ef199 100644 --- a/vendor/github.com/hyperledger/fabric-protos-go/gateway/gateway.pb.go +++ b/vendor/github.com/hyperledger/fabric-protos-go/gateway/gateway.pb.go @@ -34,10 +34,13 @@ type EndorseRequest struct { // Identifier of the channel this request is bound for. ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` // The signed proposal ready for endorsement. - ProposedTransaction *peer.SignedProposal `protobuf:"bytes,3,opt,name=proposed_transaction,json=proposedTransaction,proto3" json:"proposed_transaction,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + ProposedTransaction *peer.SignedProposal `protobuf:"bytes,3,opt,name=proposed_transaction,json=proposedTransaction,proto3" json:"proposed_transaction,omitempty"` + // If targeting the peers of specific organizations (e.g. for private data scenarios), + // the list of organizations should be supplied here. + EndorsingOrganizations []string `protobuf:"bytes,4,rep,name=endorsing_organizations,json=endorsingOrganizations,proto3" json:"endorsing_organizations,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *EndorseRequest) Reset() { *m = EndorseRequest{} } @@ -86,6 +89,13 @@ func (m *EndorseRequest) GetProposedTransaction() *peer.SignedProposal { return nil } +func (m *EndorseRequest) GetEndorsingOrganizations() []string { + if m != nil { + return m.EndorsingOrganizations + } + return nil +} + // EndorseResponse returns the result of endorsing a transaction. type EndorseResponse struct { // The response that is returned by the transaction function, as defined @@ -675,47 +685,50 @@ func init() { func init() { proto.RegisterFile("gateway/gateway.proto", fileDescriptor_285396c8df15061f) } var fileDescriptor_285396c8df15061f = []byte{ - // 639 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0x4d, 0x6b, 0xdb, 0x40, - 0x10, 0x45, 0x09, 0xf5, 0xc7, 0xc4, 0x71, 0xc3, 0x3a, 0x1f, 0x8e, 0x48, 0x20, 0x08, 0x02, 0x39, - 0x34, 0x76, 0x71, 0x4f, 0x85, 0x40, 0x21, 0xc1, 0xb4, 0xbe, 0xb9, 0x72, 0xe8, 0x21, 0x97, 0xb0, - 0xf6, 0x6e, 0x65, 0x81, 0xb4, 0xab, 0xee, 0xae, 0x92, 0xe6, 0xd6, 0x1f, 0x51, 0x7a, 0xe8, 0xad, - 0xfd, 0xa5, 0x45, 0xda, 0x5d, 0x59, 0xaa, 0xed, 0x92, 0x40, 0x0e, 0x3d, 0xc9, 0x3b, 0x33, 0x6f, - 0xe7, 0xcd, 0xdb, 0x99, 0x31, 0xec, 0x05, 0x58, 0xd1, 0x7b, 0xfc, 0xd0, 0x37, 0xdf, 0x5e, 0x22, - 0xb8, 0xe2, 0xa8, 0x6e, 0x8e, 0x6e, 0x27, 0xa1, 0x54, 0xf4, 0x13, 0xc1, 0x13, 0x2e, 0x71, 0xa4, - 0xbd, 0xee, 0x51, 0xc5, 0x78, 0x2b, 0xa8, 0x4c, 0x38, 0x93, 0xd4, 0x78, 0xf7, 0x73, 0xaf, 0x12, - 0x98, 0x49, 0x3c, 0x53, 0x21, 0x67, 0xc6, 0xde, 0x99, 0xf1, 0x38, 0xe6, 0xac, 0xaf, 0x3f, 0xda, - 0xe8, 0xfd, 0x72, 0xa0, 0x3d, 0x64, 0x84, 0x0b, 0x49, 0x7d, 0xfa, 0x25, 0xa5, 0x52, 0xa1, 0x53, - 0x68, 0x97, 0xc0, 0xb7, 0x21, 0xe9, 0x3a, 0x27, 0xce, 0x59, 0xd3, 0xdf, 0x2e, 0x59, 0x47, 0x04, - 0x1d, 0x03, 0xcc, 0xe6, 0x98, 0x31, 0x1a, 0x65, 0x21, 0x1b, 0x79, 0x48, 0xd3, 0x58, 0x46, 0x04, - 0x8d, 0x60, 0x57, 0x13, 0xa4, 0xe4, 0xb6, 0x04, 0xec, 0x6e, 0x9e, 0x38, 0x67, 0x5b, 0x83, 0x7d, - 0x9d, 0x5e, 0xf6, 0x26, 0x61, 0xc0, 0x28, 0x19, 0x9b, 0x52, 0xfc, 0x8e, 0xc5, 0x5c, 0x2f, 0x20, - 0xde, 0x37, 0x07, 0x5e, 0x16, 0x1c, 0x75, 0xa9, 0xe8, 0x0c, 0x6a, 0x82, 0xca, 0x34, 0x52, 0x39, - 0xb9, 0xad, 0xc1, 0x8e, 0xbd, 0xd0, 0x46, 0xf8, 0xc6, 0x8f, 0xae, 0x32, 0x22, 0x34, 0xc1, 0xe2, - 0x2f, 0x22, 0x1b, 0x06, 0x67, 0xe4, 0x18, 0xb2, 0x3b, 0x1a, 0xf1, 0x84, 0x66, 0x14, 0x74, 0x74, - 0x99, 0xc2, 0x4f, 0x07, 0xb6, 0x27, 0xe9, 0x34, 0x0e, 0xd5, 0xf3, 0xaa, 0xb4, 0x8e, 0xdc, 0xe6, - 0x53, 0xc8, 0xed, 0x40, 0xdb, 0x72, 0xd3, 0xb5, 0x7b, 0x13, 0x38, 0xd4, 0xc2, 0x5e, 0xf1, 0x38, - 0x0e, 0xd5, 0x44, 0x61, 0x95, 0x4a, 0xcb, 0xbc, 0x0b, 0x75, 0xa1, 0x7f, 0xe6, 0x94, 0x5b, 0xbe, - 0x3d, 0xa2, 0x23, 0x68, 0xca, 0x30, 0x60, 0x58, 0xa5, 0x82, 0xe6, 0x5c, 0x5b, 0xfe, 0xc2, 0xe0, - 0xdd, 0x43, 0x67, 0xd5, 0x75, 0xcf, 0x23, 0x84, 0x0b, 0x8d, 0x90, 0x50, 0xa6, 0x42, 0xf5, 0x90, - 0x17, 0xdf, 0xf2, 0x8b, 0xb3, 0xf7, 0x01, 0x76, 0xab, 0x89, 0x4d, 0x0f, 0xbc, 0xae, 0xf4, 0x40, - 0x7b, 0xd0, 0xb5, 0x3d, 0x70, 0xfd, 0xf5, 0x13, 0x8e, 0x42, 0x82, 0xb3, 0xd4, 0x57, 0x9c, 0x14, - 0xbd, 0xe0, 0xfd, 0xce, 0x3a, 0xe9, 0x0e, 0x47, 0x29, 0x56, 0xff, 0x6f, 0xbb, 0x5f, 0xc0, 0xce, - 0x82, 0xe3, 0x53, 0xdb, 0xdd, 0xbb, 0x81, 0xed, 0x21, 0x23, 0x09, 0x0f, 0x99, 0x1a, 0x0a, 0xc1, - 0x45, 0xf6, 0xdc, 0x98, 0x10, 0x41, 0xa5, 0x34, 0x85, 0xd9, 0x23, 0xda, 0x83, 0x5a, 0x2c, 0x93, - 0x45, 0x39, 0x2f, 0x62, 0x99, 0x8c, 0x48, 0x06, 0x88, 0xa9, 0x94, 0x38, 0xa0, 0x39, 0xfb, 0xa6, - 0x6f, 0x8f, 0x5e, 0x02, 0x9d, 0xf1, 0x32, 0xe1, 0xc7, 0x2a, 0x38, 0x80, 0x86, 0x5d, 0x59, 0x66, - 0xf8, 0xd6, 0xc9, 0x52, 0xc4, 0x79, 0xdf, 0x9d, 0x2c, 0xe5, 0x52, 0xcb, 0x3f, 0x36, 0xe5, 0x2b, - 0x68, 0x50, 0x33, 0x3a, 0x6b, 0xe7, 0xbd, 0x88, 0x28, 0x89, 0xbc, 0xf9, 0x6f, 0x91, 0x07, 0x3f, - 0x36, 0xa0, 0xfe, 0x5e, 0x6f, 0x68, 0x74, 0x01, 0x75, 0xb3, 0x9c, 0xd0, 0x41, 0xcf, 0x6e, 0xf1, - 0xea, 0x4a, 0x75, 0xbb, 0xcb, 0x0e, 0xf3, 0xb0, 0x6f, 0xa1, 0xa6, 0x67, 0x17, 0xed, 0x17, 0x31, - 0x95, 0x45, 0xe3, 0x1e, 0x2c, 0xd9, 0x0d, 0xf4, 0x23, 0xb4, 0xca, 0x63, 0x81, 0xbc, 0x45, 0xe0, - 0xba, 0xd9, 0x77, 0x8f, 0x8b, 0x98, 0x95, 0x13, 0xf5, 0x0e, 0x1a, 0xb6, 0xf5, 0x50, 0x89, 0x73, - 0x75, 0x62, 0xdc, 0xc3, 0x15, 0x1e, 0x7d, 0xc1, 0xe5, 0x1c, 0x4e, 0xb9, 0x08, 0x7a, 0xf3, 0x87, - 0x84, 0x8a, 0x88, 0x92, 0x80, 0x8a, 0xde, 0x67, 0x3c, 0x15, 0xe1, 0xcc, 0x4a, 0x69, 0x90, 0x97, - 0x2d, 0x23, 0xdf, 0x38, 0x33, 0x8f, 0x9d, 0x9b, 0x7e, 0x10, 0xaa, 0x79, 0x3a, 0xcd, 0x5e, 0xa7, - 0x5f, 0x42, 0xf7, 0x35, 0xfa, 0x5c, 0xa3, 0xcf, 0x03, 0x6e, 0xff, 0x27, 0xa7, 0xb5, 0xdc, 0xf4, - 0xe6, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x96, 0x83, 0x28, 0x51, 0x41, 0x07, 0x00, 0x00, + // 674 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0xcd, 0x6a, 0x1b, 0x3b, + 0x14, 0x66, 0xe2, 0x7b, 0xfd, 0x73, 0xe2, 0xf8, 0x06, 0x39, 0x71, 0x1c, 0x93, 0x40, 0x18, 0x08, + 0x78, 0x71, 0x63, 0x17, 0x77, 0x51, 0x0a, 0x81, 0x42, 0x82, 0x69, 0xbd, 0xaa, 0x3b, 0x0e, 0x5d, + 0x64, 0x63, 0x64, 0x4b, 0x1d, 0x0b, 0x3c, 0xd2, 0x54, 0x92, 0x93, 0xa6, 0xab, 0x3e, 0x44, 0xe9, + 0xa2, 0xcb, 0x3e, 0x56, 0x9f, 0xa6, 0xcc, 0x48, 0x1a, 0x8f, 0x1b, 0xbb, 0x24, 0x90, 0x45, 0x57, + 0xe3, 0xf3, 0xf3, 0x49, 0xdf, 0x39, 0x3a, 0xdf, 0x31, 0xec, 0x87, 0x58, 0xd3, 0x5b, 0x7c, 0xd7, + 0xb5, 0xdf, 0x4e, 0x2c, 0x85, 0x16, 0xa8, 0x64, 0xcd, 0x56, 0x3d, 0xa6, 0x54, 0x76, 0x63, 0x29, + 0x62, 0xa1, 0xf0, 0xdc, 0x44, 0x5b, 0x47, 0x2b, 0xce, 0xb1, 0xa4, 0x2a, 0x16, 0x5c, 0x51, 0x1b, + 0x6d, 0xa4, 0x51, 0x2d, 0x31, 0x57, 0x78, 0xaa, 0x99, 0xe0, 0xd6, 0x5f, 0x9f, 0x8a, 0x28, 0x12, + 0xbc, 0x6b, 0x3e, 0xc6, 0xe9, 0xff, 0xf4, 0xa0, 0xd6, 0xe7, 0x44, 0x48, 0x45, 0x03, 0xfa, 0x71, + 0x41, 0x95, 0x46, 0xa7, 0x50, 0xcb, 0x81, 0xc7, 0x8c, 0x34, 0xbd, 0x13, 0xaf, 0x5d, 0x09, 0x76, + 0x72, 0xde, 0x01, 0x41, 0xc7, 0x00, 0xd3, 0x19, 0xe6, 0x9c, 0xce, 0x93, 0x94, 0xad, 0x34, 0xa5, + 0x62, 0x3d, 0x03, 0x82, 0x06, 0xb0, 0x67, 0x08, 0x52, 0x32, 0xce, 0x01, 0x9b, 0x85, 0x13, 0xaf, + 0xbd, 0xdd, 0x6b, 0x98, 0xeb, 0x55, 0x67, 0xc4, 0x42, 0x4e, 0xc9, 0xd0, 0x96, 0x12, 0xd4, 0x1d, + 0xe6, 0x6a, 0x09, 0x41, 0x2f, 0xe0, 0x80, 0xa6, 0x14, 0x19, 0x0f, 0xc7, 0x42, 0x86, 0x98, 0xb3, + 0xcf, 0x38, 0x89, 0xa8, 0xe6, 0x3f, 0x27, 0x85, 0x76, 0x25, 0x68, 0x64, 0xe1, 0xb7, 0xf9, 0xa8, + 0xff, 0xc5, 0x83, 0xff, 0xb2, 0xe2, 0x4c, 0x8f, 0x50, 0x1b, 0x8a, 0x92, 0xaa, 0xc5, 0x5c, 0xa7, + 0x55, 0x6d, 0xf7, 0x76, 0x1d, 0x13, 0x97, 0x11, 0xd8, 0x38, 0xba, 0x4c, 0x2a, 0xa0, 0x31, 0x96, + 0xbf, 0x55, 0xb0, 0x65, 0x71, 0xb6, 0x8f, 0x7d, 0x7e, 0x43, 0xe7, 0x22, 0xa6, 0x09, 0x77, 0x93, + 0x9d, 0xe3, 0xee, 0x7f, 0xf7, 0x60, 0x67, 0xb4, 0x98, 0x44, 0x4c, 0x3f, 0x6d, 0x7b, 0x37, 0x91, + 0x2b, 0x3c, 0x86, 0xdc, 0x2e, 0xd4, 0x1c, 0x37, 0x53, 0xbb, 0x3f, 0x82, 0x43, 0xf3, 0x22, 0x97, + 0x22, 0x8a, 0x98, 0x1e, 0x69, 0xac, 0x17, 0xca, 0x31, 0x6f, 0x42, 0x49, 0x9a, 0x9f, 0x29, 0xe5, + 0x6a, 0xe0, 0x4c, 0x74, 0x04, 0x15, 0xc5, 0x42, 0x8e, 0xf5, 0x42, 0xd2, 0x94, 0x6b, 0x35, 0x58, + 0x3a, 0xfc, 0x5b, 0xa8, 0xaf, 0x3b, 0xee, 0x69, 0x1a, 0xd1, 0x82, 0x32, 0x23, 0x94, 0x6b, 0xa6, + 0xef, 0xd2, 0xe2, 0xab, 0x41, 0x66, 0xfb, 0x6f, 0x60, 0x6f, 0xf5, 0x62, 0x3b, 0x03, 0xcf, 0x56, + 0x66, 0xa0, 0xd6, 0x6b, 0xba, 0x19, 0xb8, 0xfa, 0xf4, 0x1e, 0xcf, 0x19, 0x49, 0xc7, 0xe7, 0x52, + 0x90, 0x6c, 0x16, 0xfc, 0x1f, 0xc9, 0x24, 0xdd, 0xe0, 0xf9, 0x02, 0xeb, 0xbf, 0x56, 0x27, 0xfe, + 0x39, 0xec, 0x2e, 0x39, 0x3e, 0x76, 0xdc, 0xfd, 0x6b, 0xd8, 0xe9, 0x73, 0x12, 0x0b, 0xc6, 0x75, + 0x5f, 0x4a, 0x21, 0x93, 0xe7, 0xc6, 0x84, 0x48, 0xaa, 0x94, 0x2d, 0xcc, 0x99, 0x68, 0x1f, 0x8a, + 0x91, 0x8a, 0x97, 0xe5, 0xfc, 0x1b, 0xa9, 0x78, 0x40, 0x12, 0x40, 0x44, 0x95, 0xc2, 0x21, 0x4d, + 0xd9, 0x57, 0x02, 0x67, 0xfa, 0x31, 0xd4, 0x87, 0x6b, 0x84, 0xfd, 0xc0, 0x0e, 0xf6, 0xa0, 0xec, + 0x76, 0x9d, 0x15, 0xdf, 0xa6, 0xb6, 0x64, 0x79, 0xfe, 0x57, 0x2f, 0xb9, 0xf2, 0xde, 0xc8, 0x3f, + 0xf4, 0xca, 0xff, 0xa1, 0x4c, 0xad, 0x74, 0x36, 0xea, 0x3d, 0xcb, 0xc8, 0x35, 0xb9, 0xf0, 0xe7, + 0x26, 0xf7, 0xbe, 0x6d, 0x41, 0xe9, 0xb5, 0x59, 0xed, 0xe8, 0x1c, 0x4a, 0x76, 0x39, 0xa1, 0x83, + 0x8e, 0x5b, 0xff, 0xab, 0xbb, 0xb8, 0xd5, 0xbc, 0x1f, 0xb0, 0x0f, 0xfb, 0x12, 0x8a, 0x46, 0xbb, + 0xa8, 0x91, 0xe5, 0xac, 0x2c, 0x9a, 0xd6, 0xc1, 0x3d, 0xbf, 0x85, 0xbe, 0x83, 0x6a, 0x5e, 0x16, + 0xc8, 0x5f, 0x26, 0x6e, 0xd2, 0x7e, 0xeb, 0x38, 0xcb, 0x59, 0xab, 0xa8, 0x57, 0x50, 0x76, 0xa3, + 0x87, 0x72, 0x9c, 0x57, 0x15, 0xd3, 0x3a, 0x5c, 0x13, 0x31, 0x07, 0x5c, 0xcc, 0xe0, 0x54, 0xc8, + 0xb0, 0x33, 0xbb, 0x8b, 0xa9, 0x9c, 0x53, 0x12, 0x52, 0xd9, 0xf9, 0x80, 0x27, 0x92, 0x4d, 0x5d, + 0x2b, 0x2d, 0xf2, 0xa2, 0x6a, 0xdb, 0x37, 0x4c, 0xdc, 0x43, 0xef, 0xba, 0x1b, 0x32, 0x3d, 0x5b, + 0x4c, 0x92, 0xd7, 0xe9, 0xe6, 0xd0, 0x5d, 0x83, 0x3e, 0x33, 0xe8, 0xb3, 0x50, 0xb8, 0x3f, 0xd8, + 0x49, 0x31, 0x75, 0x3d, 0xff, 0x15, 0x00, 0x00, 0xff, 0xff, 0xc6, 0xbb, 0xec, 0xa0, 0x7a, 0x07, + 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/vendor/modules.txt b/vendor/modules.txt index 070f95bfd05..9c25c1ce4ff 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -195,7 +195,7 @@ github.com/hyperledger/fabric-config/protolator/protoext/peerext # github.com/hyperledger/fabric-lib-go v1.0.0 ## explicit github.com/hyperledger/fabric-lib-go/healthz -# github.com/hyperledger/fabric-protos-go v0.0.0-20210422135545-37e930696e2a +# github.com/hyperledger/fabric-protos-go v0.0.0-20210505131505-0ac7fd605762 ## explicit github.com/hyperledger/fabric-protos-go/common github.com/hyperledger/fabric-protos-go/discovery