550 lines
19 KiB
Go
550 lines
19 KiB
Go
/*
|
|
Copyright IBM Corp All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package gateway
|
|
|
|
import (
|
|
"context"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
"time"
|
|
|
|
docker "github.com/fsouza/go-dockerclient"
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/hyperledger/fabric-protos-go/common"
|
|
"github.com/hyperledger/fabric-protos-go/gateway"
|
|
"github.com/hyperledger/fabric-protos-go/orderer"
|
|
"github.com/hyperledger/fabric-protos-go/peer"
|
|
"github.com/hyperledger/fabric-protos-go/peer/lifecycle"
|
|
"github.com/hyperledger/fabric/integration/channelparticipation"
|
|
"github.com/hyperledger/fabric/integration/nwo"
|
|
"github.com/hyperledger/fabric/protoutil"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
"github.com/tedsuo/ifrit"
|
|
ginkgomon "github.com/tedsuo/ifrit/ginkgomon_v2"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
|
|
func NewProposedTransaction(signingIdentity *nwo.SigningIdentity, channelName, chaincodeName, transactionName string, transientData map[string][]byte, args ...[]byte) (*peer.SignedProposal, string) {
|
|
proposal, transactionID := newProposalProto(signingIdentity, channelName, chaincodeName, transactionName, transientData, args...)
|
|
signedProposal, err := protoutil.GetSignedProposal(proposal, signingIdentity)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
return signedProposal, transactionID
|
|
}
|
|
|
|
func newProposalProto(signingIdentity *nwo.SigningIdentity, channelName, chaincodeName, transactionName string, transientData map[string][]byte, args ...[]byte) (*peer.Proposal, string) {
|
|
creator, err := signingIdentity.Serialize()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
invocationSpec := &peer.ChaincodeInvocationSpec{
|
|
ChaincodeSpec: &peer.ChaincodeSpec{
|
|
Type: peer.ChaincodeSpec_NODE,
|
|
ChaincodeId: &peer.ChaincodeID{Name: chaincodeName},
|
|
Input: &peer.ChaincodeInput{Args: chaincodeArgs(transactionName, args...)},
|
|
},
|
|
}
|
|
|
|
result, transactionID, err := protoutil.CreateChaincodeProposalWithTransient(
|
|
common.HeaderType_ENDORSER_TRANSACTION,
|
|
channelName,
|
|
invocationSpec,
|
|
creator,
|
|
transientData,
|
|
)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
return result, transactionID
|
|
}
|
|
|
|
func chaincodeArgs(transactionName string, args ...[]byte) [][]byte {
|
|
result := make([][]byte, len(args)+1)
|
|
|
|
result[0] = []byte(transactionName)
|
|
copy(result[1:], args)
|
|
|
|
return result
|
|
}
|
|
|
|
var _ = Describe("GatewayService basic", func() {
|
|
var (
|
|
testDir string
|
|
network *nwo.Network
|
|
org1Peer0 *nwo.Peer
|
|
ordererRunner *ginkgomon.Runner
|
|
ordererProcess, peerProcess ifrit.Process
|
|
conn *grpc.ClientConn
|
|
gatewayClient gateway.GatewayClient
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
signingIdentity *nwo.SigningIdentity
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
var err error
|
|
testDir, err = ioutil.TempDir("", "gateway")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
client, err := docker.NewClientFromEnv()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
config := nwo.BasicEtcdRaft()
|
|
network = nwo.New(config, testDir, client, StartPort(), components)
|
|
|
|
network.GenerateConfigTree()
|
|
network.Bootstrap()
|
|
|
|
// Start all the fabric processes
|
|
ordererRunner, ordererProcess, peerProcess = network.StartSingleOrdererNetwork("orderer")
|
|
|
|
By("setting up the channel")
|
|
orderer := network.Orderer("orderer")
|
|
channelparticipation.JoinOrdererJoinPeersAppChannel(network, "testchannel", orderer, ordererRunner)
|
|
|
|
network.VerifyMembership(
|
|
network.PeersWithChannel("testchannel"),
|
|
"testchannel",
|
|
)
|
|
nwo.EnableCapabilities(
|
|
network,
|
|
"testchannel",
|
|
"Application", "V2_0",
|
|
orderer,
|
|
network.PeersWithChannel("testchannel")...,
|
|
)
|
|
|
|
chaincode := nwo.Chaincode{
|
|
Name: "gatewaycc",
|
|
Version: "0.0",
|
|
Path: components.Build("github.com/hyperledger/fabric/integration/chaincode/simple/cmd"),
|
|
Lang: "binary",
|
|
PackageFile: filepath.Join(testDir, "gatewaycc.tar.gz"),
|
|
Ctor: `{"Args":[]}`,
|
|
SignaturePolicy: `AND ('Org1MSP.peer')`,
|
|
Sequence: "1",
|
|
InitRequired: false,
|
|
Label: "gatewaycc_label",
|
|
}
|
|
|
|
nwo.DeployChaincode(network, "testchannel", orderer, chaincode)
|
|
|
|
org1Peer0 = network.Peer("Org1", "peer0")
|
|
|
|
conn = network.PeerClientConn(org1Peer0)
|
|
gatewayClient = gateway.NewGatewayClient(conn)
|
|
ctx, cancel = context.WithTimeout(context.Background(), network.EventuallyTimeout)
|
|
|
|
signingIdentity = network.PeerUserSigner(org1Peer0, "User1")
|
|
})
|
|
|
|
AfterEach(func() {
|
|
conn.Close()
|
|
cancel()
|
|
|
|
if ordererProcess != nil {
|
|
ordererProcess.Signal(syscall.SIGTERM)
|
|
Eventually(ordererProcess.Wait(), network.EventuallyTimeout).Should(Receive())
|
|
}
|
|
|
|
if peerProcess != nil {
|
|
peerProcess.Signal(syscall.SIGTERM)
|
|
Eventually(peerProcess.Wait(), network.EventuallyTimeout).Should(Receive())
|
|
}
|
|
|
|
if network != nil {
|
|
network.Cleanup()
|
|
}
|
|
os.RemoveAll(testDir)
|
|
})
|
|
|
|
submitTransaction := func(transactionName string, args ...[]byte) (*peer.Response, string) {
|
|
proposedTransaction, transactionID := NewProposedTransaction(signingIdentity, "testchannel", "gatewaycc", transactionName, nil, args...)
|
|
|
|
endorseRequest := &gateway.EndorseRequest{
|
|
TransactionId: transactionID,
|
|
ChannelId: "testchannel",
|
|
ProposedTransaction: proposedTransaction,
|
|
}
|
|
|
|
endorseResponse, err := gatewayClient.Endorse(ctx, endorseRequest)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
preparedTransaction := endorseResponse.GetPreparedTransaction()
|
|
preparedTransaction.Signature, err = signingIdentity.Sign(preparedTransaction.Payload)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
submitRequest := &gateway.SubmitRequest{
|
|
TransactionId: transactionID,
|
|
ChannelId: "testchannel",
|
|
PreparedTransaction: preparedTransaction,
|
|
}
|
|
_, err = gatewayClient.Submit(ctx, submitRequest)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
chaincodeAction, err := protoutil.GetActionFromEnvelopeMsg(endorseResponse.GetPreparedTransaction())
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
return chaincodeAction.GetResponse(), transactionID
|
|
}
|
|
|
|
commitStatus := func(transactionID string, identity func() ([]byte, error), sign func(msg []byte) ([]byte, error)) (*gateway.CommitStatusResponse, error) {
|
|
idBytes, err := identity()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
statusRequest := &gateway.CommitStatusRequest{
|
|
ChannelId: "testchannel",
|
|
Identity: idBytes,
|
|
TransactionId: transactionID,
|
|
}
|
|
statusRequestBytes, err := proto.Marshal(statusRequest)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
signature, err := sign(statusRequestBytes)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
signedStatusRequest := &gateway.SignedCommitStatusRequest{
|
|
Request: statusRequestBytes,
|
|
Signature: signature,
|
|
}
|
|
|
|
return gatewayClient.CommitStatus(ctx, signedStatusRequest)
|
|
}
|
|
|
|
chaincodeEvents := func(
|
|
ctx context.Context,
|
|
startPosition *orderer.SeekPosition,
|
|
afterTxID string,
|
|
identity func() ([]byte, error),
|
|
sign func(msg []byte) ([]byte, error),
|
|
) (gateway.Gateway_ChaincodeEventsClient, error) {
|
|
identityBytes, err := identity()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
request := &gateway.ChaincodeEventsRequest{
|
|
ChannelId: "testchannel",
|
|
ChaincodeId: "gatewaycc",
|
|
Identity: identityBytes,
|
|
}
|
|
if startPosition != nil {
|
|
request.StartPosition = startPosition
|
|
}
|
|
if len(afterTxID) > 0 {
|
|
request.AfterTransactionId = afterTxID
|
|
}
|
|
|
|
requestBytes, err := proto.Marshal(request)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
signature, err := sign(requestBytes)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
signedRequest := &gateway.SignedChaincodeEventsRequest{
|
|
Request: requestBytes,
|
|
Signature: signature,
|
|
}
|
|
|
|
return gatewayClient.ChaincodeEvents(ctx, signedRequest)
|
|
}
|
|
|
|
Describe("Evaluate", func() {
|
|
It("should respond with the expected result", func() {
|
|
proposedTransaction, transactionID := NewProposedTransaction(signingIdentity, "testchannel", "gatewaycc", "respond", nil, []byte("200"), []byte("conga message"), []byte("conga payload"))
|
|
|
|
request := &gateway.EvaluateRequest{
|
|
TransactionId: transactionID,
|
|
ChannelId: "testchannel",
|
|
ProposedTransaction: proposedTransaction,
|
|
}
|
|
|
|
response, err := gatewayClient.Evaluate(ctx, request)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
expectedResponse := &gateway.EvaluateResponse{
|
|
Result: &peer.Response{
|
|
Status: 200,
|
|
Message: "conga message",
|
|
Payload: []byte("conga payload"),
|
|
},
|
|
}
|
|
Expect(response.Result.Payload).To(Equal(expectedResponse.Result.Payload))
|
|
Expect(proto.Equal(response, expectedResponse)).To(BeTrue(), "Expected\n\t%#v\nto proto.Equal\n\t%#v", response, expectedResponse)
|
|
})
|
|
|
|
It("should respond with system chaincode result", func() {
|
|
proposedTransaction, transactionID := NewProposedTransaction(signingIdentity, "testchannel", "qscc", "GetChainInfo", nil, []byte("testchannel"))
|
|
|
|
request := &gateway.EvaluateRequest{
|
|
TransactionId: transactionID,
|
|
ChannelId: "testchannel",
|
|
ProposedTransaction: proposedTransaction,
|
|
}
|
|
|
|
response, err := gatewayClient.Evaluate(ctx, request)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
status := common.Status(response.GetResult().GetStatus())
|
|
Expect(status).To(Equal(common.Status_SUCCESS))
|
|
|
|
blockchainInfo := new(common.BlockchainInfo)
|
|
Expect(proto.Unmarshal(response.GetResult().GetPayload(), blockchainInfo)).NotTo(HaveOccurred())
|
|
})
|
|
})
|
|
|
|
Describe("Submit", func() {
|
|
It("should respond with the expected result", func() {
|
|
result, _ := submitTransaction("respond", []byte("200"), []byte("conga message"), []byte("conga payload"))
|
|
expectedResult := &peer.Response{
|
|
Status: 200,
|
|
Message: "conga message",
|
|
Payload: []byte("conga payload"),
|
|
}
|
|
Expect(result.Payload).To(Equal(expectedResult.Payload))
|
|
Expect(proto.Equal(result, expectedResult)).To(BeTrue(), "Expected\n\t%#v\nto proto.Equal\n\t%#v", result, expectedResult)
|
|
})
|
|
|
|
It("should endorse a system chaincode transaction", func() {
|
|
arg, err := proto.Marshal(&lifecycle.QueryInstalledChaincodesArgs{})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
adminSigner := network.PeerUserSigner(org1Peer0, "Admin")
|
|
proposedTransaction, transactionID := NewProposedTransaction(adminSigner, "testchannel", "_lifecycle", "QueryInstalledChaincodes", nil, arg)
|
|
|
|
request := &gateway.EndorseRequest{
|
|
TransactionId: transactionID,
|
|
ChannelId: "testchannel",
|
|
ProposedTransaction: proposedTransaction,
|
|
EndorsingOrganizations: []string{adminSigner.MSPID}, // Only use peers for our admin ID org
|
|
}
|
|
|
|
response, err := gatewayClient.Endorse(ctx, request)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
chaincodeAction, err := protoutil.GetActionFromEnvelopeMsg(response.GetPreparedTransaction())
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
queryResult := new(lifecycle.QueryInstalledChaincodesResult)
|
|
Expect(proto.Unmarshal(chaincodeAction.GetResponse().GetPayload(), queryResult)).NotTo(HaveOccurred())
|
|
})
|
|
})
|
|
|
|
Describe("CommitStatus", func() {
|
|
It("should respond with status of submitted transaction", func() {
|
|
_, transactionID := submitTransaction("respond", []byte("200"), []byte("conga message"), []byte("conga payload"))
|
|
statusResult, err := commitStatus(transactionID, signingIdentity.Serialize, signingIdentity.Sign)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(statusResult.Result).To(Equal(peer.TxValidationCode_VALID))
|
|
})
|
|
|
|
It("should respond with block number", func() {
|
|
_, transactionID := submitTransaction("respond", []byte("200"), []byte("conga message"), []byte("conga payload"))
|
|
firstStatus, err := commitStatus(transactionID, signingIdentity.Serialize, signingIdentity.Sign)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
_, transactionID = submitTransaction("respond", []byte("200"), []byte("conga message"), []byte("conga payload"))
|
|
nextStatus, err := commitStatus(transactionID, signingIdentity.Serialize, signingIdentity.Sign)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(nextStatus.BlockNumber).To(Equal(firstStatus.BlockNumber + 1))
|
|
})
|
|
|
|
It("should fail on unauthorized identity", func() {
|
|
_, transactionID := submitTransaction("respond", []byte("200"), []byte("conga message"), []byte("conga payload"))
|
|
badIdentity := network.OrdererUserSigner(network.Orderer("orderer"), "Admin")
|
|
_, err := commitStatus(transactionID, badIdentity.Serialize, signingIdentity.Sign)
|
|
Expect(err).To(HaveOccurred())
|
|
|
|
grpcErr, _ := status.FromError(err)
|
|
Expect(grpcErr.Code()).To(Equal(codes.PermissionDenied))
|
|
})
|
|
|
|
It("should fail on bad signature", func() {
|
|
_, transactionID := submitTransaction("respond", []byte("200"), []byte("conga message"), []byte("conga payload"))
|
|
badSign := func(digest []byte) ([]byte, error) {
|
|
return signingIdentity.Sign([]byte("WRONG"))
|
|
}
|
|
_, err := commitStatus(transactionID, signingIdentity.Serialize, badSign)
|
|
Expect(err).To(HaveOccurred())
|
|
|
|
grpcErr, _ := status.FromError(err)
|
|
Expect(grpcErr.Code()).To(Equal(codes.PermissionDenied))
|
|
})
|
|
})
|
|
|
|
Describe("ChaincodeEvents", func() {
|
|
It("should respond with emitted chaincode events", func() {
|
|
eventCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
|
defer cancel()
|
|
|
|
startPosition := &orderer.SeekPosition{
|
|
Type: &orderer.SeekPosition_NextCommit{
|
|
NextCommit: &orderer.SeekNextCommit{},
|
|
},
|
|
}
|
|
|
|
eventsClient, err := chaincodeEvents(eventCtx, startPosition, "", signingIdentity.Serialize, signingIdentity.Sign)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
_, transactionID := submitTransaction("event", []byte("EVENT_NAME"), []byte("EVENT_PAYLOAD"))
|
|
|
|
event, err := eventsClient.Recv()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(event.Events).To(HaveLen(1), "number of events")
|
|
expectedEvent := &peer.ChaincodeEvent{
|
|
ChaincodeId: "gatewaycc",
|
|
TxId: transactionID,
|
|
EventName: "EVENT_NAME",
|
|
Payload: []byte("EVENT_PAYLOAD"),
|
|
}
|
|
Expect(proto.Equal(event.Events[0], expectedEvent)).To(BeTrue(), "Expected\n\t%#v\nto proto.Equal\n\t%#v", event.Events[0], expectedEvent)
|
|
})
|
|
|
|
It("should respond with replayed chaincode events", func() {
|
|
_, transactionID := submitTransaction("event", []byte("EVENT_NAME"), []byte("EVENT_PAYLOAD"))
|
|
statusResult, err := commitStatus(transactionID, signingIdentity.Serialize, signingIdentity.Sign)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
eventCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
|
defer cancel()
|
|
|
|
startPosition := &orderer.SeekPosition{
|
|
Type: &orderer.SeekPosition_Specified{
|
|
Specified: &orderer.SeekSpecified{
|
|
Number: statusResult.BlockNumber,
|
|
},
|
|
},
|
|
}
|
|
|
|
eventsClient, err := chaincodeEvents(eventCtx, startPosition, "", signingIdentity.Serialize, signingIdentity.Sign)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
event, err := eventsClient.Recv()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(event.BlockNumber).To(Equal(statusResult.BlockNumber), "block number")
|
|
Expect(event.Events).To(HaveLen(1), "number of events")
|
|
expectedEvent := &peer.ChaincodeEvent{
|
|
ChaincodeId: "gatewaycc",
|
|
TxId: transactionID,
|
|
EventName: "EVENT_NAME",
|
|
Payload: []byte("EVENT_PAYLOAD"),
|
|
}
|
|
Expect(proto.Equal(event.Events[0], expectedEvent)).To(BeTrue(), "Expected\n\t%#v\nto proto.Equal\n\t%#v", event.Events[0], expectedEvent)
|
|
})
|
|
|
|
It("should respond with replayed chaincode events after specified transaction ID", func() {
|
|
_, afterTransactionID := submitTransaction("event", []byte("WRONG_EVENT_NAME"), []byte("WRONG_EVENT_PAYLOAD"))
|
|
_, nextTransactionID := submitTransaction("event", []byte("CORRECT_EVENT_NAME"), []byte("CORRECT_EVENT_PAYLOAD"))
|
|
|
|
statusResult, err := commitStatus(afterTransactionID, signingIdentity.Serialize, signingIdentity.Sign)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
_, err = commitStatus(nextTransactionID, signingIdentity.Serialize, signingIdentity.Sign)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
eventCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
|
defer cancel()
|
|
|
|
startPosition := &orderer.SeekPosition{
|
|
Type: &orderer.SeekPosition_Specified{
|
|
Specified: &orderer.SeekSpecified{
|
|
Number: statusResult.BlockNumber,
|
|
},
|
|
},
|
|
}
|
|
|
|
eventsClient, err := chaincodeEvents(eventCtx, startPosition, afterTransactionID, signingIdentity.Serialize, signingIdentity.Sign)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
event, err := eventsClient.Recv()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(event.Events).To(HaveLen(1), "number of events")
|
|
expectedEvent := &peer.ChaincodeEvent{
|
|
ChaincodeId: "gatewaycc",
|
|
TxId: nextTransactionID,
|
|
EventName: "CORRECT_EVENT_NAME",
|
|
Payload: []byte("CORRECT_EVENT_PAYLOAD"),
|
|
}
|
|
Expect(proto.Equal(event.Events[0], expectedEvent)).To(BeTrue(), "Expected\n\t%#v\nto proto.Equal\n\t%#v", event.Events[0], expectedEvent)
|
|
})
|
|
|
|
It("should default to next commit if start position not specified", func() {
|
|
eventCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
|
defer cancel()
|
|
|
|
var startPosition *orderer.SeekPosition
|
|
|
|
eventsClient, err := chaincodeEvents(eventCtx, startPosition, "", signingIdentity.Serialize, signingIdentity.Sign)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
_, transactionID := submitTransaction("event", []byte("EVENT_NAME"), []byte("EVENT_PAYLOAD"))
|
|
|
|
event, err := eventsClient.Recv()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(event.Events).To(HaveLen(1), "number of events")
|
|
expectedEvent := &peer.ChaincodeEvent{
|
|
ChaincodeId: "gatewaycc",
|
|
TxId: transactionID,
|
|
EventName: "EVENT_NAME",
|
|
Payload: []byte("EVENT_PAYLOAD"),
|
|
}
|
|
Expect(proto.Equal(event.Events[0], expectedEvent)).To(BeTrue(), "Expected\n\t%#v\nto proto.Equal\n\t%#v", event.Events[0], expectedEvent)
|
|
})
|
|
|
|
It("should fail on unauthorized identity", func() {
|
|
badIdentity := network.OrdererUserSigner(network.Orderer("orderer"), "Admin")
|
|
|
|
eventCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
|
defer cancel()
|
|
|
|
startPosition := &orderer.SeekPosition{
|
|
Type: &orderer.SeekPosition_NextCommit{
|
|
NextCommit: &orderer.SeekNextCommit{},
|
|
},
|
|
}
|
|
|
|
eventsClient, err := chaincodeEvents(eventCtx, startPosition, "", badIdentity.Serialize, signingIdentity.Sign)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
event, err := eventsClient.Recv()
|
|
Expect(err).To(HaveOccurred(), "expected error but got event: %v", event)
|
|
|
|
grpcErr, _ := status.FromError(err)
|
|
Expect(grpcErr.Code()).To(Equal(codes.PermissionDenied))
|
|
})
|
|
|
|
It("should fail on bad signature", func() {
|
|
badSign := func(digest []byte) ([]byte, error) {
|
|
return signingIdentity.Sign([]byte("WRONG"))
|
|
}
|
|
|
|
eventCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
|
defer cancel()
|
|
|
|
startPosition := &orderer.SeekPosition{
|
|
Type: &orderer.SeekPosition_NextCommit{
|
|
NextCommit: &orderer.SeekNextCommit{},
|
|
},
|
|
}
|
|
|
|
eventsClient, err := chaincodeEvents(eventCtx, startPosition, "", signingIdentity.Serialize, badSign)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
event, err := eventsClient.Recv()
|
|
Expect(err).To(HaveOccurred(), "expected error but got event: %v", event)
|
|
|
|
grpcErr, _ := status.FromError(err)
|
|
Expect(grpcErr.Code()).To(Equal(codes.PermissionDenied))
|
|
})
|
|
})
|
|
})
|