github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/integration/gateway/gateway_test.go (about)

     1  /*
     2  Copyright hechain All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package gateway
     8  
     9  import (
    10  	"context"
    11  	"io/ioutil"
    12  	"os"
    13  	"path/filepath"
    14  	"syscall"
    15  	"time"
    16  
    17  	docker "github.com/fsouza/go-dockerclient"
    18  	"github.com/golang/protobuf/proto"
    19  	"github.com/hechain20/hechain/integration/nwo"
    20  	"github.com/hechain20/hechain/protoutil"
    21  	"github.com/hyperledger/fabric-protos-go/common"
    22  	"github.com/hyperledger/fabric-protos-go/gateway"
    23  	"github.com/hyperledger/fabric-protos-go/orderer"
    24  	"github.com/hyperledger/fabric-protos-go/peer"
    25  	. "github.com/onsi/ginkgo"
    26  	. "github.com/onsi/gomega"
    27  	"github.com/tedsuo/ifrit"
    28  	"google.golang.org/grpc"
    29  	"google.golang.org/grpc/codes"
    30  	"google.golang.org/grpc/status"
    31  )
    32  
    33  func NewProposedTransaction(signingIdentity *nwo.SigningIdentity, channelName, chaincodeName, transactionName string, transientData map[string][]byte, args ...[]byte) (*peer.SignedProposal, string) {
    34  	proposal, transactionID := newProposalProto(signingIdentity, channelName, chaincodeName, transactionName, transientData, args...)
    35  	signedProposal, err := protoutil.GetSignedProposal(proposal, signingIdentity)
    36  	Expect(err).NotTo(HaveOccurred())
    37  
    38  	return signedProposal, transactionID
    39  }
    40  
    41  func newProposalProto(signingIdentity *nwo.SigningIdentity, channelName, chaincodeName, transactionName string, transientData map[string][]byte, args ...[]byte) (*peer.Proposal, string) {
    42  	creator, err := signingIdentity.Serialize()
    43  	Expect(err).NotTo(HaveOccurred())
    44  
    45  	invocationSpec := &peer.ChaincodeInvocationSpec{
    46  		ChaincodeSpec: &peer.ChaincodeSpec{
    47  			Type:        peer.ChaincodeSpec_NODE,
    48  			ChaincodeId: &peer.ChaincodeID{Name: chaincodeName},
    49  			Input:       &peer.ChaincodeInput{Args: chaincodeArgs(transactionName, args...)},
    50  		},
    51  	}
    52  
    53  	result, transactionID, err := protoutil.CreateChaincodeProposalWithTransient(
    54  		common.HeaderType_ENDORSER_TRANSACTION,
    55  		channelName,
    56  		invocationSpec,
    57  		creator,
    58  		transientData,
    59  	)
    60  	Expect(err).NotTo(HaveOccurred())
    61  
    62  	return result, transactionID
    63  }
    64  
    65  func chaincodeArgs(transactionName string, args ...[]byte) [][]byte {
    66  	result := make([][]byte, len(args)+1)
    67  
    68  	result[0] = []byte(transactionName)
    69  	copy(result[1:], args)
    70  
    71  	return result
    72  }
    73  
    74  var _ = Describe("GatewayService", func() {
    75  	var (
    76  		testDir         string
    77  		network         *nwo.Network
    78  		org1Peer0       *nwo.Peer
    79  		process         ifrit.Process
    80  		conn            *grpc.ClientConn
    81  		gatewayClient   gateway.GatewayClient
    82  		ctx             context.Context
    83  		cancel          context.CancelFunc
    84  		signingIdentity *nwo.SigningIdentity
    85  	)
    86  
    87  	BeforeEach(func() {
    88  		var err error
    89  		testDir, err = ioutil.TempDir("", "gateway")
    90  		Expect(err).NotTo(HaveOccurred())
    91  
    92  		client, err := docker.NewClientFromEnv()
    93  		Expect(err).NotTo(HaveOccurred())
    94  
    95  		config := nwo.BasicEtcdRaft()
    96  		network = nwo.New(config, testDir, client, StartPort(), components)
    97  
    98  		network.GenerateConfigTree()
    99  		network.Bootstrap()
   100  
   101  		networkRunner := network.NetworkGroupRunner()
   102  		process = ifrit.Invoke(networkRunner)
   103  		Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed())
   104  
   105  		orderer := network.Orderer("orderer")
   106  		network.CreateAndJoinChannel(orderer, "testchannel")
   107  		network.UpdateChannelAnchors(orderer, "testchannel")
   108  		network.VerifyMembership(
   109  			network.PeersWithChannel("testchannel"),
   110  			"testchannel",
   111  		)
   112  		nwo.EnableCapabilities(
   113  			network,
   114  			"testchannel",
   115  			"Application", "V2_0",
   116  			orderer,
   117  			network.PeersWithChannel("testchannel")...,
   118  		)
   119  
   120  		chaincode := nwo.Chaincode{
   121  			Name:            "gatewaycc",
   122  			Version:         "0.0",
   123  			Path:            components.Build("github.com/hechain20/hechain/integration/chaincode/simple/cmd"),
   124  			Lang:            "binary",
   125  			PackageFile:     filepath.Join(testDir, "gatewaycc.tar.gz"),
   126  			Ctor:            `{"Args":[]}`,
   127  			SignaturePolicy: `AND ('Org1MSP.peer')`,
   128  			Sequence:        "1",
   129  			InitRequired:    false,
   130  			Label:           "gatewaycc_label",
   131  		}
   132  
   133  		nwo.DeployChaincode(network, "testchannel", orderer, chaincode)
   134  
   135  		org1Peer0 = network.Peer("Org1", "peer0")
   136  
   137  		conn = network.PeerClientConn(org1Peer0)
   138  		gatewayClient = gateway.NewGatewayClient(conn)
   139  		ctx, cancel = context.WithTimeout(context.Background(), network.EventuallyTimeout)
   140  
   141  		signingIdentity = network.PeerUserSigner(org1Peer0, "User1")
   142  	})
   143  
   144  	AfterEach(func() {
   145  		conn.Close()
   146  		cancel()
   147  
   148  		if process != nil {
   149  			process.Signal(syscall.SIGTERM)
   150  			Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive())
   151  		}
   152  		if network != nil {
   153  			network.Cleanup()
   154  		}
   155  		os.RemoveAll(testDir)
   156  	})
   157  
   158  	submitTransaction := func(transactionName string, args ...[]byte) (*peer.Response, string) {
   159  		proposedTransaction, transactionID := NewProposedTransaction(signingIdentity, "testchannel", "gatewaycc", transactionName, nil, args...)
   160  
   161  		endorseRequest := &gateway.EndorseRequest{
   162  			TransactionId:       transactionID,
   163  			ChannelId:           "testchannel",
   164  			ProposedTransaction: proposedTransaction,
   165  		}
   166  
   167  		endorseResponse, err := gatewayClient.Endorse(ctx, endorseRequest)
   168  		Expect(err).NotTo(HaveOccurred())
   169  
   170  		preparedTransaction := endorseResponse.GetPreparedTransaction()
   171  		preparedTransaction.Signature, err = signingIdentity.Sign(preparedTransaction.Payload)
   172  		Expect(err).NotTo(HaveOccurred())
   173  
   174  		submitRequest := &gateway.SubmitRequest{
   175  			TransactionId:       transactionID,
   176  			ChannelId:           "testchannel",
   177  			PreparedTransaction: preparedTransaction,
   178  		}
   179  		_, err = gatewayClient.Submit(ctx, submitRequest)
   180  		Expect(err).NotTo(HaveOccurred())
   181  
   182  		chaincodeAction, err := protoutil.GetActionFromEnvelopeMsg(endorseResponse.GetPreparedTransaction())
   183  		Expect(err).NotTo(HaveOccurred())
   184  
   185  		return chaincodeAction.GetResponse(), transactionID
   186  	}
   187  
   188  	commitStatus := func(transactionID string, identity func() ([]byte, error), sign func(msg []byte) ([]byte, error)) (*gateway.CommitStatusResponse, error) {
   189  		idBytes, err := identity()
   190  		Expect(err).NotTo(HaveOccurred())
   191  
   192  		statusRequest := &gateway.CommitStatusRequest{
   193  			ChannelId:     "testchannel",
   194  			Identity:      idBytes,
   195  			TransactionId: transactionID,
   196  		}
   197  		statusRequestBytes, err := proto.Marshal(statusRequest)
   198  		Expect(err).NotTo(HaveOccurred())
   199  
   200  		signature, err := sign(statusRequestBytes)
   201  		Expect(err).NotTo(HaveOccurred())
   202  
   203  		signedStatusRequest := &gateway.SignedCommitStatusRequest{
   204  			Request:   statusRequestBytes,
   205  			Signature: signature,
   206  		}
   207  
   208  		return gatewayClient.CommitStatus(ctx, signedStatusRequest)
   209  	}
   210  
   211  	chaincodeEvents := func(
   212  		ctx context.Context,
   213  		startPosition *orderer.SeekPosition,
   214  		identity func() ([]byte, error),
   215  		sign func(msg []byte) ([]byte, error),
   216  	) (gateway.Gateway_ChaincodeEventsClient, error) {
   217  		identityBytes, err := identity()
   218  		Expect(err).NotTo(HaveOccurred())
   219  
   220  		request := &gateway.ChaincodeEventsRequest{
   221  			ChannelId:   "testchannel",
   222  			ChaincodeId: "gatewaycc",
   223  			Identity:    identityBytes,
   224  		}
   225  		if startPosition != nil {
   226  			request.StartPosition = startPosition
   227  		}
   228  
   229  		requestBytes, err := proto.Marshal(request)
   230  		Expect(err).NotTo(HaveOccurred())
   231  
   232  		signature, err := sign(requestBytes)
   233  		Expect(err).NotTo(HaveOccurred())
   234  
   235  		signedRequest := &gateway.SignedChaincodeEventsRequest{
   236  			Request:   requestBytes,
   237  			Signature: signature,
   238  		}
   239  
   240  		return gatewayClient.ChaincodeEvents(ctx, signedRequest)
   241  	}
   242  
   243  	Describe("Evaluate", func() {
   244  		It("should respond with the expected result", func() {
   245  			proposedTransaction, transactionID := NewProposedTransaction(signingIdentity, "testchannel", "gatewaycc", "respond", nil, []byte("200"), []byte("conga message"), []byte("conga payload"))
   246  
   247  			request := &gateway.EvaluateRequest{
   248  				TransactionId:       transactionID,
   249  				ChannelId:           "testchannel",
   250  				ProposedTransaction: proposedTransaction,
   251  			}
   252  
   253  			response, err := gatewayClient.Evaluate(ctx, request)
   254  			Expect(err).NotTo(HaveOccurred())
   255  			expectedResponse := &gateway.EvaluateResponse{
   256  				Result: &peer.Response{
   257  					Status:  200,
   258  					Message: "conga message",
   259  					Payload: []byte("conga payload"),
   260  				},
   261  			}
   262  			Expect(response.Result.Payload).To(Equal(expectedResponse.Result.Payload))
   263  			Expect(proto.Equal(response, expectedResponse)).To(BeTrue(), "Expected\n\t%#v\nto proto.Equal\n\t%#v", response, expectedResponse)
   264  		})
   265  	})
   266  
   267  	Describe("Submit", func() {
   268  		It("should respond with the expected result", func() {
   269  			result, _ := submitTransaction("respond", []byte("200"), []byte("conga message"), []byte("conga payload"))
   270  			expectedResult := &peer.Response{
   271  				Status:  200,
   272  				Message: "conga message",
   273  				Payload: []byte("conga payload"),
   274  			}
   275  			Expect(result.Payload).To(Equal(expectedResult.Payload))
   276  			Expect(proto.Equal(result, expectedResult)).To(BeTrue(), "Expected\n\t%#v\nto proto.Equal\n\t%#v", result, expectedResult)
   277  		})
   278  	})
   279  
   280  	Describe("CommitStatus", func() {
   281  		It("should respond with status of submitted transaction", func() {
   282  			_, transactionID := submitTransaction("respond", []byte("200"), []byte("conga message"), []byte("conga payload"))
   283  			statusResult, err := commitStatus(transactionID, signingIdentity.Serialize, signingIdentity.Sign)
   284  			Expect(err).NotTo(HaveOccurred())
   285  
   286  			Expect(statusResult.Result).To(Equal(peer.TxValidationCode_VALID))
   287  		})
   288  
   289  		It("should respond with block number", func() {
   290  			_, transactionID := submitTransaction("respond", []byte("200"), []byte("conga message"), []byte("conga payload"))
   291  			firstStatus, err := commitStatus(transactionID, signingIdentity.Serialize, signingIdentity.Sign)
   292  			Expect(err).NotTo(HaveOccurred())
   293  
   294  			_, transactionID = submitTransaction("respond", []byte("200"), []byte("conga message"), []byte("conga payload"))
   295  			nextStatus, err := commitStatus(transactionID, signingIdentity.Serialize, signingIdentity.Sign)
   296  			Expect(err).NotTo(HaveOccurred())
   297  
   298  			Expect(nextStatus.BlockNumber).To(Equal(firstStatus.BlockNumber + 1))
   299  		})
   300  
   301  		It("should fail on unauthorized identity", func() {
   302  			_, transactionID := submitTransaction("respond", []byte("200"), []byte("conga message"), []byte("conga payload"))
   303  			badIdentity := network.OrdererUserSigner(network.Orderer("orderer"), "Admin")
   304  			_, err := commitStatus(transactionID, badIdentity.Serialize, signingIdentity.Sign)
   305  			Expect(err).To(HaveOccurred())
   306  
   307  			grpcErr, _ := status.FromError(err)
   308  			Expect(grpcErr.Code()).To(Equal(codes.PermissionDenied))
   309  		})
   310  
   311  		It("should fail on bad signature", func() {
   312  			_, transactionID := submitTransaction("respond", []byte("200"), []byte("conga message"), []byte("conga payload"))
   313  			badSign := func(digest []byte) ([]byte, error) {
   314  				return signingIdentity.Sign([]byte("WRONG"))
   315  			}
   316  			_, err := commitStatus(transactionID, signingIdentity.Serialize, badSign)
   317  			Expect(err).To(HaveOccurred())
   318  
   319  			grpcErr, _ := status.FromError(err)
   320  			Expect(grpcErr.Code()).To(Equal(codes.PermissionDenied))
   321  		})
   322  	})
   323  
   324  	Describe("ChaincodeEvents", func() {
   325  		It("should respond with emitted chaincode events", func() {
   326  			eventCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
   327  			defer cancel()
   328  
   329  			startPosition := &orderer.SeekPosition{
   330  				Type: &orderer.SeekPosition_NextCommit{
   331  					NextCommit: &orderer.SeekNextCommit{},
   332  				},
   333  			}
   334  
   335  			eventsClient, err := chaincodeEvents(eventCtx, startPosition, signingIdentity.Serialize, signingIdentity.Sign)
   336  			Expect(err).NotTo(HaveOccurred())
   337  
   338  			_, transactionID := submitTransaction("event", []byte("EVENT_NAME"), []byte("EVENT_PAYLOAD"))
   339  
   340  			event, err := eventsClient.Recv()
   341  			Expect(err).NotTo(HaveOccurred())
   342  
   343  			Expect(event.Events).To(HaveLen(1), "number of events")
   344  			expectedEvent := &peer.ChaincodeEvent{
   345  				ChaincodeId: "gatewaycc",
   346  				TxId:        transactionID,
   347  				EventName:   "EVENT_NAME",
   348  				Payload:     []byte("EVENT_PAYLOAD"),
   349  			}
   350  			Expect(proto.Equal(event.Events[0], expectedEvent)).To(BeTrue(), "Expected\n\t%#v\nto proto.Equal\n\t%#v", event.Events[0], expectedEvent)
   351  		})
   352  
   353  		It("should respond with replayed chaincode events", func() {
   354  			_, transactionID := submitTransaction("event", []byte("EVENT_NAME"), []byte("EVENT_PAYLOAD"))
   355  			statusResult, err := commitStatus(transactionID, signingIdentity.Serialize, signingIdentity.Sign)
   356  			Expect(err).NotTo(HaveOccurred())
   357  
   358  			eventCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
   359  			defer cancel()
   360  
   361  			startPosition := &orderer.SeekPosition{
   362  				Type: &orderer.SeekPosition_Specified{
   363  					Specified: &orderer.SeekSpecified{
   364  						Number: statusResult.BlockNumber,
   365  					},
   366  				},
   367  			}
   368  
   369  			eventsClient, err := chaincodeEvents(eventCtx, startPosition, signingIdentity.Serialize, signingIdentity.Sign)
   370  			Expect(err).NotTo(HaveOccurred())
   371  
   372  			event, err := eventsClient.Recv()
   373  			Expect(err).NotTo(HaveOccurred())
   374  
   375  			Expect(event.BlockNumber).To(Equal(statusResult.BlockNumber), "block number")
   376  			Expect(event.Events).To(HaveLen(1), "number of events")
   377  			expectedEvent := &peer.ChaincodeEvent{
   378  				ChaincodeId: "gatewaycc",
   379  				TxId:        transactionID,
   380  				EventName:   "EVENT_NAME",
   381  				Payload:     []byte("EVENT_PAYLOAD"),
   382  			}
   383  			Expect(proto.Equal(event.Events[0], expectedEvent)).To(BeTrue(), "Expected\n\t%#v\nto proto.Equal\n\t%#v", event.Events[0], expectedEvent)
   384  		})
   385  
   386  		It("should default to next commit if start position not specified", func() {
   387  			eventCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
   388  			defer cancel()
   389  
   390  			var startPosition *orderer.SeekPosition
   391  
   392  			eventsClient, err := chaincodeEvents(eventCtx, startPosition, signingIdentity.Serialize, signingIdentity.Sign)
   393  			Expect(err).NotTo(HaveOccurred())
   394  
   395  			_, transactionID := submitTransaction("event", []byte("EVENT_NAME"), []byte("EVENT_PAYLOAD"))
   396  
   397  			event, err := eventsClient.Recv()
   398  			Expect(err).NotTo(HaveOccurred())
   399  
   400  			Expect(event.Events).To(HaveLen(1), "number of events")
   401  			expectedEvent := &peer.ChaincodeEvent{
   402  				ChaincodeId: "gatewaycc",
   403  				TxId:        transactionID,
   404  				EventName:   "EVENT_NAME",
   405  				Payload:     []byte("EVENT_PAYLOAD"),
   406  			}
   407  			Expect(proto.Equal(event.Events[0], expectedEvent)).To(BeTrue(), "Expected\n\t%#v\nto proto.Equal\n\t%#v", event.Events[0], expectedEvent)
   408  		})
   409  
   410  		It("should fail on unauthorized identity", func() {
   411  			badIdentity := network.OrdererUserSigner(network.Orderer("orderer"), "Admin")
   412  
   413  			eventCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
   414  			defer cancel()
   415  
   416  			startPosition := &orderer.SeekPosition{
   417  				Type: &orderer.SeekPosition_NextCommit{
   418  					NextCommit: &orderer.SeekNextCommit{},
   419  				},
   420  			}
   421  
   422  			eventsClient, err := chaincodeEvents(eventCtx, startPosition, badIdentity.Serialize, signingIdentity.Sign)
   423  			Expect(err).NotTo(HaveOccurred())
   424  
   425  			event, err := eventsClient.Recv()
   426  			Expect(err).To(HaveOccurred(), "expected error but got event: %v", event)
   427  
   428  			grpcErr, _ := status.FromError(err)
   429  			Expect(grpcErr.Code()).To(Equal(codes.PermissionDenied))
   430  		})
   431  
   432  		It("should fail on bad signature", func() {
   433  			badSign := func(digest []byte) ([]byte, error) {
   434  				return signingIdentity.Sign([]byte("WRONG"))
   435  			}
   436  
   437  			eventCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
   438  			defer cancel()
   439  
   440  			startPosition := &orderer.SeekPosition{
   441  				Type: &orderer.SeekPosition_NextCommit{
   442  					NextCommit: &orderer.SeekNextCommit{},
   443  				},
   444  			}
   445  
   446  			eventsClient, err := chaincodeEvents(eventCtx, startPosition, signingIdentity.Serialize, badSign)
   447  			Expect(err).NotTo(HaveOccurred())
   448  
   449  			event, err := eventsClient.Recv()
   450  			Expect(err).To(HaveOccurred(), "expected error but got event: %v", event)
   451  
   452  			grpcErr, _ := status.FromError(err)
   453  			Expect(grpcErr.Code()).To(Equal(codes.PermissionDenied))
   454  		})
   455  	})
   456  })