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 })