github.com/lzy4123/fabric@v2.1.1+incompatible/protoutil/txutils_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package protoutil_test 8 9 import ( 10 "encoding/hex" 11 "errors" 12 "strconv" 13 "testing" 14 15 "github.com/golang/protobuf/proto" 16 cb "github.com/hyperledger/fabric-protos-go/common" 17 pb "github.com/hyperledger/fabric-protos-go/peer" 18 19 "github.com/hyperledger/fabric/protoutil" 20 "github.com/hyperledger/fabric/protoutil/fakes" 21 "github.com/stretchr/testify/assert" 22 ) 23 24 func TestGetPayloads(t *testing.T) { 25 var txAction *pb.TransactionAction 26 var err error 27 28 // good 29 ccActionBytes, _ := proto.Marshal(&pb.ChaincodeAction{ 30 Results: []byte("results"), 31 }) 32 proposalResponsePayload := &pb.ProposalResponsePayload{ 33 Extension: ccActionBytes, 34 } 35 proposalResponseBytes, err := proto.Marshal(proposalResponsePayload) 36 ccActionPayload := &pb.ChaincodeActionPayload{ 37 Action: &pb.ChaincodeEndorsedAction{ 38 ProposalResponsePayload: proposalResponseBytes, 39 }, 40 } 41 ccActionPayloadBytes, _ := proto.Marshal(ccActionPayload) 42 txAction = &pb.TransactionAction{ 43 Payload: ccActionPayloadBytes, 44 } 45 _, _, err = protoutil.GetPayloads(txAction) 46 assert.NoError(t, err, "Unexpected error getting payload bytes") 47 t.Logf("error1 [%s]", err) 48 49 // nil proposal response extension 50 proposalResponseBytes, err = proto.Marshal(&pb.ProposalResponsePayload{ 51 Extension: nil, 52 }) 53 ccActionPayloadBytes, _ = proto.Marshal(&pb.ChaincodeActionPayload{ 54 Action: &pb.ChaincodeEndorsedAction{ 55 ProposalResponsePayload: proposalResponseBytes, 56 }, 57 }) 58 txAction = &pb.TransactionAction{ 59 Payload: ccActionPayloadBytes, 60 } 61 _, _, err = protoutil.GetPayloads(txAction) 62 assert.Error(t, err, "Expected error with nil proposal response extension") 63 t.Logf("error2 [%s]", err) 64 65 // malformed proposal response payload 66 ccActionPayloadBytes, _ = proto.Marshal(&pb.ChaincodeActionPayload{ 67 Action: &pb.ChaincodeEndorsedAction{ 68 ProposalResponsePayload: []byte("bad payload"), 69 }, 70 }) 71 txAction = &pb.TransactionAction{ 72 Payload: ccActionPayloadBytes, 73 } 74 _, _, err = protoutil.GetPayloads(txAction) 75 assert.Error(t, err, "Expected error with malformed proposal response payload") 76 t.Logf("error3 [%s]", err) 77 78 // malformed proposal response payload extension 79 proposalResponseBytes, _ = proto.Marshal(&pb.ProposalResponsePayload{ 80 Extension: []byte("bad extension"), 81 }) 82 ccActionPayloadBytes, _ = proto.Marshal(&pb.ChaincodeActionPayload{ 83 Action: &pb.ChaincodeEndorsedAction{ 84 ProposalResponsePayload: proposalResponseBytes, 85 }, 86 }) 87 txAction = &pb.TransactionAction{ 88 Payload: ccActionPayloadBytes, 89 } 90 _, _, err = protoutil.GetPayloads(txAction) 91 assert.Error(t, err, "Expected error with malformed proposal response extension") 92 t.Logf("error4 [%s]", err) 93 94 // nil proposal response payload extension 95 proposalResponseBytes, _ = proto.Marshal(&pb.ProposalResponsePayload{ 96 ProposalHash: []byte("hash"), 97 }) 98 ccActionPayloadBytes, _ = proto.Marshal(&pb.ChaincodeActionPayload{ 99 Action: &pb.ChaincodeEndorsedAction{ 100 ProposalResponsePayload: proposalResponseBytes, 101 }, 102 }) 103 txAction = &pb.TransactionAction{ 104 Payload: ccActionPayloadBytes, 105 } 106 _, _, err = protoutil.GetPayloads(txAction) 107 assert.Error(t, err, "Expected error with nil proposal response extension") 108 t.Logf("error5 [%s]", err) 109 110 // malformed transaction action payload 111 txAction = &pb.TransactionAction{ 112 Payload: []byte("bad payload"), 113 } 114 _, _, err = protoutil.GetPayloads(txAction) 115 assert.Error(t, err, "Expected error with malformed transaction action payload") 116 t.Logf("error6 [%s]", err) 117 118 } 119 120 func TestCreateSignedTx(t *testing.T) { 121 var err error 122 prop := &pb.Proposal{} 123 124 signID := &fakes.SignerSerializer{} 125 signID.SerializeReturns([]byte("signer"), nil) 126 signerBytes, err := signID.Serialize() 127 assert.NoError(t, err, "Unexpected error serializing signing identity") 128 129 ccHeaderExtensionBytes := protoutil.MarshalOrPanic(&pb.ChaincodeHeaderExtension{}) 130 chdrBytes := protoutil.MarshalOrPanic(&cb.ChannelHeader{ 131 Extension: ccHeaderExtensionBytes, 132 }) 133 shdrBytes := protoutil.MarshalOrPanic(&cb.SignatureHeader{ 134 Creator: signerBytes, 135 }) 136 responses := []*pb.ProposalResponse{{}} 137 138 // malformed signature header 139 headerBytes := protoutil.MarshalOrPanic(&cb.Header{ 140 SignatureHeader: []byte("bad signature header"), 141 }) 142 prop.Header = headerBytes 143 _, err = protoutil.CreateSignedTx(prop, signID, responses...) 144 assert.Error(t, err, "Expected error with malformed signature header") 145 146 // set up the header bytes for the remaining tests 147 headerBytes, _ = proto.Marshal(&cb.Header{ 148 ChannelHeader: chdrBytes, 149 SignatureHeader: shdrBytes, 150 }) 151 prop.Header = headerBytes 152 153 nonMatchingTests := []struct { 154 responses []*pb.ProposalResponse 155 expectedError string 156 }{ 157 // good responses, but different payloads 158 { 159 []*pb.ProposalResponse{ 160 {Payload: []byte("payload"), Response: &pb.Response{Status: int32(200)}}, 161 {Payload: []byte("payload2"), Response: &pb.Response{Status: int32(200)}}, 162 }, 163 "ProposalResponsePayloads do not match", 164 }, 165 // good response followed by bad response 166 { 167 []*pb.ProposalResponse{ 168 {Payload: []byte("payload"), Response: &pb.Response{Status: int32(200)}}, 169 {Payload: []byte{}, Response: &pb.Response{Status: int32(500), Message: "failed to endorse"}}, 170 }, 171 "proposal response was not successful, error code 500, msg failed to endorse", 172 }, 173 // bad response followed by good response 174 { 175 []*pb.ProposalResponse{ 176 {Payload: []byte{}, Response: &pb.Response{Status: int32(500), Message: "failed to endorse"}}, 177 {Payload: []byte("payload"), Response: &pb.Response{Status: int32(200)}}, 178 }, 179 "proposal response was not successful, error code 500, msg failed to endorse", 180 }, 181 } 182 for i, nonMatchingTest := range nonMatchingTests { 183 _, err = protoutil.CreateSignedTx(prop, signID, nonMatchingTest.responses...) 184 assert.EqualErrorf(t, err, nonMatchingTest.expectedError, "Expected non-matching response error '%v' for test %d", nonMatchingTest.expectedError, i) 185 } 186 187 // no endorsement 188 responses = []*pb.ProposalResponse{{ 189 Payload: []byte("payload"), 190 Response: &pb.Response{ 191 Status: int32(200), 192 }, 193 }} 194 _, err = protoutil.CreateSignedTx(prop, signID, responses...) 195 assert.Error(t, err, "Expected error with no endorsements") 196 197 // success 198 responses = []*pb.ProposalResponse{{ 199 Payload: []byte("payload"), 200 Endorsement: &pb.Endorsement{}, 201 Response: &pb.Response{ 202 Status: int32(200), 203 }, 204 }} 205 _, err = protoutil.CreateSignedTx(prop, signID, responses...) 206 assert.NoError(t, err, "Unexpected error creating signed transaction") 207 t.Logf("error: [%s]", err) 208 209 // 210 // 211 // additional failure cases 212 prop = &pb.Proposal{} 213 responses = []*pb.ProposalResponse{} 214 // no proposal responses 215 _, err = protoutil.CreateSignedTx(prop, signID, responses...) 216 assert.Error(t, err, "Expected error with no proposal responses") 217 218 // missing proposal header 219 responses = append(responses, &pb.ProposalResponse{}) 220 _, err = protoutil.CreateSignedTx(prop, signID, responses...) 221 assert.Error(t, err, "Expected error with no proposal header") 222 223 // bad proposal payload 224 prop.Payload = []byte("bad payload") 225 _, err = protoutil.CreateSignedTx(prop, signID, responses...) 226 assert.Error(t, err, "Expected error with malformed proposal payload") 227 228 // bad payload header 229 prop.Header = []byte("bad header") 230 _, err = protoutil.CreateSignedTx(prop, signID, responses...) 231 assert.Error(t, err, "Expected error with malformed proposal header") 232 233 } 234 235 func TestCreateSignedTxStatus(t *testing.T) { 236 serializedExtension, err := proto.Marshal(&pb.ChaincodeHeaderExtension{}) 237 assert.NoError(t, err) 238 serializedChannelHeader, err := proto.Marshal(&cb.ChannelHeader{ 239 Extension: serializedExtension, 240 }) 241 assert.NoError(t, err) 242 243 signingID := &fakes.SignerSerializer{} 244 signingID.SerializeReturns([]byte("signer"), nil) 245 serializedSigningID, err := signingID.Serialize() 246 assert.NoError(t, err) 247 serializedSignatureHeader, err := proto.Marshal(&cb.SignatureHeader{ 248 Creator: serializedSigningID, 249 }) 250 assert.NoError(t, err) 251 252 header := &cb.Header{ 253 ChannelHeader: serializedChannelHeader, 254 SignatureHeader: serializedSignatureHeader, 255 } 256 257 serializedHeader, err := proto.Marshal(header) 258 assert.NoError(t, err) 259 260 proposal := &pb.Proposal{ 261 Header: serializedHeader, 262 } 263 264 tests := []struct { 265 status int32 266 expectedErr string 267 }{ 268 {status: 0, expectedErr: "proposal response was not successful, error code 0, msg response-message"}, 269 {status: 199, expectedErr: "proposal response was not successful, error code 199, msg response-message"}, 270 {status: 200, expectedErr: ""}, 271 {status: 201, expectedErr: ""}, 272 {status: 399, expectedErr: ""}, 273 {status: 400, expectedErr: "proposal response was not successful, error code 400, msg response-message"}, 274 } 275 for _, tc := range tests { 276 t.Run(strconv.Itoa(int(tc.status)), func(t *testing.T) { 277 response := &pb.ProposalResponse{ 278 Payload: []byte("payload"), 279 Endorsement: &pb.Endorsement{}, 280 Response: &pb.Response{ 281 Status: tc.status, 282 Message: "response-message", 283 }, 284 } 285 286 _, err := protoutil.CreateSignedTx(proposal, signingID, response) 287 if tc.expectedErr == "" { 288 assert.NoError(t, err) 289 } else { 290 assert.EqualError(t, err, tc.expectedErr) 291 } 292 }) 293 } 294 } 295 296 func TestCreateSignedEnvelope(t *testing.T) { 297 var env *cb.Envelope 298 channelID := "mychannelID" 299 msg := &cb.ConfigEnvelope{} 300 301 id := &fakes.SignerSerializer{} 302 id.SignReturnsOnCall(0, []byte("goodsig"), nil) 303 id.SignReturnsOnCall(1, nil, errors.New("bad signature")) 304 env, err := protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, channelID, 305 id, msg, int32(1), uint64(1)) 306 assert.NoError(t, err, "Unexpected error creating signed envelope") 307 assert.NotNil(t, env, "Envelope should not be nil") 308 // mock sign returns the bytes to be signed 309 assert.Equal(t, []byte("goodsig"), env.Signature, "Unexpected signature returned") 310 payload := &cb.Payload{} 311 err = proto.Unmarshal(env.Payload, payload) 312 assert.NoError(t, err, "Failed to unmarshal payload") 313 data := &cb.ConfigEnvelope{} 314 err = proto.Unmarshal(payload.Data, data) 315 assert.NoError(t, err, "Expected payload data to be a config envelope") 316 assert.Equal(t, msg, data, "Payload data does not match expected value") 317 318 _, err = protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, channelID, 319 id, &cb.ConfigEnvelope{}, int32(1), uint64(1)) 320 assert.Error(t, err, "Expected sign error") 321 } 322 323 func TestCreateSignedEnvelopeNilSigner(t *testing.T) { 324 var env *cb.Envelope 325 channelID := "mychannelID" 326 msg := &cb.ConfigEnvelope{} 327 328 env, err := protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, channelID, 329 nil, msg, int32(1), uint64(1)) 330 assert.NoError(t, err, "Unexpected error creating signed envelope") 331 assert.NotNil(t, env, "Envelope should not be nil") 332 assert.Empty(t, env.Signature, "Signature should have been empty") 333 payload := &cb.Payload{} 334 err = proto.Unmarshal(env.Payload, payload) 335 assert.NoError(t, err, "Failed to unmarshal payload") 336 data := &cb.ConfigEnvelope{} 337 err = proto.Unmarshal(payload.Data, data) 338 assert.NoError(t, err, "Expected payload data to be a config envelope") 339 assert.Equal(t, msg, data, "Payload data does not match expected value") 340 } 341 342 func TestGetSignedProposal(t *testing.T) { 343 var signedProp *pb.SignedProposal 344 var err error 345 346 sig := []byte("signature") 347 348 signID := &fakes.SignerSerializer{} 349 signID.SignReturns(sig, nil) 350 351 prop := &pb.Proposal{} 352 propBytes, _ := proto.Marshal(prop) 353 signedProp, err = protoutil.GetSignedProposal(prop, signID) 354 assert.NoError(t, err, "Unexpected error getting signed proposal") 355 assert.Equal(t, propBytes, signedProp.ProposalBytes, 356 "Proposal bytes did not match expected value") 357 assert.Equal(t, sig, signedProp.Signature, 358 "Signature did not match expected value") 359 360 _, err = protoutil.GetSignedProposal(nil, signID) 361 assert.Error(t, err, "Expected error with nil proposal") 362 _, err = protoutil.GetSignedProposal(prop, nil) 363 assert.Error(t, err, "Expected error with nil signing identity") 364 365 } 366 367 func TestMockSignedEndorserProposalOrPanic(t *testing.T) { 368 var prop *pb.Proposal 369 var signedProp *pb.SignedProposal 370 371 ccProposal := &pb.ChaincodeProposalPayload{} 372 cis := &pb.ChaincodeInvocationSpec{} 373 chainID := "testchannelid" 374 sig := []byte("signature") 375 creator := []byte("creator") 376 cs := &pb.ChaincodeSpec{ 377 ChaincodeId: &pb.ChaincodeID{ 378 Name: "mychaincode", 379 }, 380 } 381 382 signedProp, prop = protoutil.MockSignedEndorserProposalOrPanic(chainID, cs, 383 creator, sig) 384 assert.Equal(t, sig, signedProp.Signature, 385 "Signature did not match expected result") 386 propBytes, _ := proto.Marshal(prop) 387 assert.Equal(t, propBytes, signedProp.ProposalBytes, 388 "Proposal bytes do not match expected value") 389 err := proto.Unmarshal(prop.Payload, ccProposal) 390 assert.NoError(t, err, "Expected ChaincodeProposalPayload") 391 err = proto.Unmarshal(ccProposal.Input, cis) 392 assert.NoError(t, err, "Expected ChaincodeInvocationSpec") 393 assert.Equal(t, cs.ChaincodeId.Name, cis.ChaincodeSpec.ChaincodeId.Name, 394 "Chaincode name did not match expected value") 395 } 396 397 func TestMockSignedEndorserProposal2OrPanic(t *testing.T) { 398 var prop *pb.Proposal 399 var signedProp *pb.SignedProposal 400 401 ccProposal := &pb.ChaincodeProposalPayload{} 402 cis := &pb.ChaincodeInvocationSpec{} 403 chainID := "testchannelid" 404 sig := []byte("signature") 405 signID := &fakes.SignerSerializer{} 406 signID.SignReturns(sig, nil) 407 408 signedProp, prop = protoutil.MockSignedEndorserProposal2OrPanic(chainID, 409 &pb.ChaincodeSpec{}, signID) 410 assert.Equal(t, sig, signedProp.Signature, 411 "Signature did not match expected result") 412 propBytes, _ := proto.Marshal(prop) 413 assert.Equal(t, propBytes, signedProp.ProposalBytes, 414 "Proposal bytes do not match expected value") 415 err := proto.Unmarshal(prop.Payload, ccProposal) 416 assert.NoError(t, err, "Expected ChaincodeProposalPayload") 417 err = proto.Unmarshal(ccProposal.Input, cis) 418 assert.NoError(t, err, "Expected ChaincodeInvocationSpec") 419 } 420 421 func TestGetBytesProposalPayloadForTx(t *testing.T) { 422 input := &pb.ChaincodeProposalPayload{ 423 Input: []byte("input"), 424 TransientMap: make(map[string][]byte), 425 } 426 expected, _ := proto.Marshal(&pb.ChaincodeProposalPayload{ 427 Input: []byte("input"), 428 }) 429 430 result, err := protoutil.GetBytesProposalPayloadForTx(input) 431 assert.NoError(t, err, "Unexpected error getting proposal payload") 432 assert.Equal(t, expected, result, "Payload does not match expected value") 433 434 _, err = protoutil.GetBytesProposalPayloadForTx(nil) 435 assert.Error(t, err, "Expected error with nil proposal payload") 436 } 437 438 func TestGetProposalHash2(t *testing.T) { 439 expectedHashHex := "7b622ef4e1ab9b7093ec3bbfbca17d5d6f14a437914a6839319978a7034f7960" 440 expectedHash, _ := hex.DecodeString(expectedHashHex) 441 hdr := &cb.Header{ 442 ChannelHeader: []byte("chdr"), 443 SignatureHeader: []byte("shdr"), 444 } 445 propHash, err := protoutil.GetProposalHash2(hdr, []byte("ccproppayload")) 446 assert.NoError(t, err, "Unexpected error getting hash2 for proposal") 447 t.Logf("%x", propHash) 448 assert.Equal(t, expectedHash, propHash, 449 "Proposal hash did not match expected hash") 450 451 propHash, err = protoutil.GetProposalHash2(&cb.Header{}, 452 []byte("ccproppayload")) 453 assert.Error(t, err, "Expected error with nil arguments") 454 } 455 456 func TestGetProposalHash1(t *testing.T) { 457 expectedHashHex := "d4c1e3cac2105da5fddc2cfe776d6ec28e4598cf1e6fa51122c7f70d8076437b" 458 expectedHash, _ := hex.DecodeString(expectedHashHex) 459 hdr := &cb.Header{ 460 ChannelHeader: []byte("chdr"), 461 SignatureHeader: []byte("shdr"), 462 } 463 464 ccProposal, _ := proto.Marshal(&pb.ChaincodeProposalPayload{}) 465 466 propHash, err := protoutil.GetProposalHash1(hdr, ccProposal) 467 assert.NoError(t, err, "Unexpected error getting hash for proposal") 468 t.Logf("%x", propHash) 469 assert.Equal(t, expectedHash, propHash, 470 "Proposal hash did not match expected hash") 471 472 propHash, err = protoutil.GetProposalHash1(hdr, []byte("ccproppayload")) 473 assert.Error(t, err, 474 "Expected error with malformed chaincode proposal payload") 475 476 propHash, err = protoutil.GetProposalHash1(&cb.Header{}, []byte("ccproppayload")) 477 assert.Error(t, err, "Expected error with nil arguments") 478 } 479 480 func TestCreateProposalResponseFailure(t *testing.T) { 481 // create a proposal from a ChaincodeInvocationSpec 482 prop, _, err := protoutil.CreateChaincodeProposal(cb.HeaderType_ENDORSER_TRANSACTION, testChannelID, createCIS(), signerSerialized) 483 if err != nil { 484 t.Fatalf("Could not create chaincode proposal, err %s\n", err) 485 return 486 } 487 488 response := &pb.Response{Status: 502, Payload: []byte("Invalid function name")} 489 result := []byte("res") 490 491 prespFailure, err := protoutil.CreateProposalResponseFailure(prop.Header, prop.Payload, response, result, nil, "foo") 492 if err != nil { 493 t.Fatalf("Could not create proposal response failure, err %s\n", err) 494 return 495 } 496 497 assert.Equal(t, int32(502), prespFailure.Response.Status) 498 // drilldown into the response to find the chaincode response 499 pRespPayload, err := protoutil.UnmarshalProposalResponsePayload(prespFailure.Payload) 500 assert.NoError(t, err, "Error while unmarshaling proposal response payload: %s", err) 501 ca, err := protoutil.UnmarshalChaincodeAction(pRespPayload.Extension) 502 assert.NoError(t, err, "Error while unmarshaling chaincode action: %s", err) 503 504 assert.Equal(t, int32(502), ca.Response.Status) 505 assert.Equal(t, "Invalid function name", string(ca.Response.Payload)) 506 } 507 508 func TestGetorComputeTxIDFromEnvelope(t *testing.T) { 509 t.Run("txID is present in the envelope", func(t *testing.T) { 510 txID := "709184f9d24f6ade8fcd4d6521a6eef295fef6c2e67216c58b68ac15e8946492" 511 envelopeBytes := createSampleTxEnvelopeBytes(txID) 512 actualTxID, err := protoutil.GetOrComputeTxIDFromEnvelope(envelopeBytes) 513 assert.Nil(t, err) 514 assert.Equal(t, "709184f9d24f6ade8fcd4d6521a6eef295fef6c2e67216c58b68ac15e8946492", actualTxID) 515 }) 516 517 t.Run("txID is not present in the envelope", func(t *testing.T) { 518 txID := "" 519 envelopeBytes := createSampleTxEnvelopeBytes(txID) 520 actualTxID, err := protoutil.GetOrComputeTxIDFromEnvelope(envelopeBytes) 521 assert.Nil(t, err) 522 assert.Equal(t, "709184f9d24f6ade8fcd4d6521a6eef295fef6c2e67216c58b68ac15e8946492", actualTxID) 523 524 }) 525 } 526 527 func createSampleTxEnvelopeBytes(txID string) []byte { 528 chdr := &cb.ChannelHeader{ 529 TxId: "709184f9d24f6ade8fcd4d6521a6eef295fef6c2e67216c58b68ac15e8946492", 530 } 531 chdrBytes := protoutil.MarshalOrPanic(chdr) 532 533 shdr := &cb.SignatureHeader{ 534 Nonce: []byte("nonce"), 535 Creator: []byte("creator"), 536 } 537 shdrBytes := protoutil.MarshalOrPanic(shdr) 538 539 hdr := &cb.Header{ 540 ChannelHeader: chdrBytes, 541 SignatureHeader: shdrBytes, 542 } 543 544 payload := &cb.Payload{ 545 Header: hdr, 546 } 547 payloadBytes := protoutil.MarshalOrPanic(payload) 548 549 envelope := &cb.Envelope{ 550 Payload: payloadBytes, 551 } 552 return protoutil.MarshalOrPanic(envelope) 553 554 }