diff --git a/internal/pkg/gateway/api.go b/internal/pkg/gateway/api.go index f89e9fe8ec0..86ad6ffb294 100644 --- a/internal/pkg/gateway/api.go +++ b/internal/pkg/gateway/api.go @@ -32,7 +32,7 @@ func (gs *Server) Evaluate(ctx context.Context, request *gp.EvaluateRequest) (*g return nil, status.Error(codes.InvalidArgument, "an evaluate request is required") } signedProposal := request.GetProposedTransaction() - channel, chaincodeID, _, err := getChannelAndChaincodeFromSignedProposal(signedProposal) + channel, chaincodeID, hasTransientData, err := getChannelAndChaincodeFromSignedProposal(signedProposal) if err != nil { return nil, status.Errorf(codes.InvalidArgument, "failed to unpack transaction proposal: %s", err) } @@ -42,8 +42,18 @@ func (gs *Server) Evaluate(ctx context.Context, request *gp.EvaluateRequest) (*g return nil, status.Errorf(codes.Unavailable, "%s", err) } - endorser, err := gs.registry.evaluator(channel, chaincodeID, request.GetTargetOrganizations()) + targetOrgs := request.GetTargetOrganizations() + transientProtected := false + if hasTransientData && targetOrgs == nil { + targetOrgs = []string{gs.registry.localEndorser.mspid} + transientProtected = true + } + + endorser, err := gs.registry.evaluator(channel, chaincodeID, targetOrgs) if err != nil { + if transientProtected { + return nil, status.Error(codes.Unavailable, "no endorsers found in the gateway's organization; retry specifying target organization(s) to protect transient data") + } 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 fe10886ee62..0bf96f515fd 100644 --- a/internal/pkg/gateway/api_test.go +++ b/internal/pkg/gateway/api_test.go @@ -233,6 +233,41 @@ func TestEvaluate(t *testing.T) { endorsingOrgs: []string{"msp2", "msp3"}, expectedEndorsers: []string{"peer4:11051"}, }, + { + name: "evaluate with transient data should select local org, highest block height", + members: []networkMember{ + {"id1", "localhost:7051", "msp1", 4}, + {"id2", "peer1:8051", "msp1", 5}, + {"id3", "peer2:9051", "msp2", 6}, + {"id4", "peer3:10051", "msp2", 5}, + {"id5", "peer4:11051", "msp3", 7}, + }, + transientData: map[string][]byte{"transient-key": []byte("transient-value")}, + expectedEndorsers: []string{"peer1:8051"}, + }, + { + name: "evaluate with transient data should fail if local org not available", + members: []networkMember{ + {"id3", "peer2:9051", "msp2", 6}, + {"id4", "peer3:10051", "msp2", 5}, + {"id5", "peer4:11051", "msp3", 7}, + }, + transientData: map[string][]byte{"transient-key": []byte("transient-value")}, + errString: "rpc error: code = Unavailable desc = no endorsers found in the gateway's organization; retry specifying target organization(s) to protect transient data", + }, + { + name: "evaluate with transient data and target (non-local) orgs should select the highest block height peer", + members: []networkMember{ + {"id1", "localhost:7051", "msp1", 11}, + {"id2", "peer1:8051", "msp1", 5}, + {"id3", "peer2:9051", "msp2", 6}, + {"id4", "peer3:10051", "msp2", 9}, + {"id5", "peer4:11051", "msp3", 7}, + }, + transientData: map[string][]byte{"transient-key": []byte("transient-value")}, + endorsingOrgs: []string{"msp2", "msp3"}, + expectedEndorsers: []string{"peer3:10051"}, + }, { name: "process proposal fails", members: []networkMember{