github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/protos/utils/proputils_test.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package utils_test 18 19 import ( 20 "bytes" 21 "crypto/sha256" 22 "encoding/hex" 23 "fmt" 24 "os" 25 "reflect" 26 "testing" 27 28 "github.com/golang/protobuf/proto" 29 "github.com/hyperledger/fabric/common/util" 30 "github.com/hyperledger/fabric/msp" 31 mspmgmt "github.com/hyperledger/fabric/msp/mgmt" 32 "github.com/hyperledger/fabric/msp/mgmt/testtools" 33 "github.com/hyperledger/fabric/protos/common" 34 pb "github.com/hyperledger/fabric/protos/peer" 35 "github.com/hyperledger/fabric/protos/utils" 36 "github.com/stretchr/testify/assert" 37 ) 38 39 func createCIS() *pb.ChaincodeInvocationSpec { 40 return &pb.ChaincodeInvocationSpec{ 41 ChaincodeSpec: &pb.ChaincodeSpec{ 42 Type: pb.ChaincodeSpec_GOLANG, 43 ChaincodeId: &pb.ChaincodeID{Name: "chaincode_name"}, 44 Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("arg1"), []byte("arg2")}}}} 45 } 46 47 func TestNilProposal(t *testing.T) { 48 // pass nil to all function which accept *peer.Proposal 49 _, err := utils.GetChaincodeInvocationSpec(nil) 50 assert.Error(t, err, "Expected error with nil proposal") 51 _, _, err = utils.GetChaincodeProposalContext(nil) 52 assert.Error(t, err, "Expected error with nil proposal") 53 _, err = utils.GetNonce(nil) 54 assert.Error(t, err, "Expected error with nil proposal") 55 _, err = utils.GetBytesProposal(nil) 56 assert.Error(t, err, "Expected error with nil proposal") 57 _, err = utils.ComputeProposalBinding(nil) 58 assert.Error(t, err, "Expected error with nil proposal") 59 } 60 61 func TestBadProposalHeaders(t *testing.T) { 62 // NOTE: There is a lot of repetitive proposal validation code 63 // in multiple functions which should be refactored in the future. 64 // For now, simply consolidating the test cases 65 66 // emty header 67 prop := &pb.Proposal{ 68 Header: []byte{}, 69 } 70 _, _, err := utils.GetChaincodeProposalContext(prop) 71 assert.Error(t, err, "Expected error with empty proposal header") 72 _, err = utils.ComputeProposalBinding(prop) 73 assert.Error(t, err, "Expected error with empty proposal header") 74 75 // malformed proposal header 76 prop = &pb.Proposal{ 77 Header: []byte("bad header"), 78 Payload: []byte("payload"), 79 } 80 _, err = utils.GetHeader(prop.Header) 81 assert.Error(t, err, "Expected error with malformed proposal header") 82 _, err = utils.GetChaincodeInvocationSpec(prop) 83 assert.Error(t, err, "Expected error with malformed proposal header") 84 _, _, err = utils.GetChaincodeProposalContext(prop) 85 assert.Error(t, err, "Expected error with malformed proposal header") 86 _, err = utils.GetNonce(prop) 87 assert.Error(t, err, "Expected error with malformed proposal header") 88 _, err = utils.ComputeProposalBinding(prop) 89 assert.Error(t, err, "Expected error with malformed proposal header") 90 91 // malformed signature header 92 chdr, _ := proto.Marshal(&common.ChannelHeader{ 93 Type: int32(common.HeaderType_ENDORSER_TRANSACTION), 94 }) 95 hdr := &common.Header{ 96 ChannelHeader: chdr, 97 SignatureHeader: []byte("bad signature header"), 98 } 99 _, err = utils.GetSignatureHeader(hdr.SignatureHeader) 100 assert.Error(t, err, "Expected error with malformed signature header") 101 hdrBytes, _ := proto.Marshal(hdr) 102 prop.Header = hdrBytes 103 _, err = utils.GetChaincodeInvocationSpec(prop) 104 assert.Error(t, err, "Expected error with malformed signature header") 105 _, _, err = utils.GetChaincodeProposalContext(prop) 106 assert.Error(t, err, "Expected error with malformed signature header") 107 _, err = utils.GetNonce(prop) 108 assert.Error(t, err, "Expected error with malformed signature header") 109 _, err = utils.ComputeProposalBinding(prop) 110 assert.Error(t, err, "Expected error with malformed signature header") 111 112 // wrong channel header type 113 chdr, _ = proto.Marshal(&common.ChannelHeader{ 114 Type: int32(common.HeaderType_DELIVER_SEEK_INFO), 115 }) 116 hdr.ChannelHeader = chdr 117 hdrBytes, _ = proto.Marshal(hdr) 118 prop.Header = hdrBytes 119 _, _, err = utils.GetChaincodeProposalContext(prop) 120 assert.Error(t, err, "Expected error with wrong header type") 121 _, err = utils.GetNonce(prop) 122 assert.Error(t, err, "Expected error with wrong header type") 123 124 // malformed channel header 125 hdr.ChannelHeader = []byte("bad channel header") 126 hdrBytes, _ = proto.Marshal(hdr) 127 prop.Header = hdrBytes 128 _, _, err = utils.GetChaincodeProposalContext(prop) 129 assert.Error(t, err, "Expected error with malformed channel header") 130 _, err = utils.GetNonce(prop) 131 assert.Error(t, err, "Expected error with malformed channel header") 132 _, err = utils.GetChaincodeHeaderExtension(hdr) 133 assert.Error(t, err, "Expected error with malformed channel header") 134 _, err = utils.ComputeProposalBinding(prop) 135 assert.Error(t, err, "Expected error with malformed channel header") 136 137 } 138 139 func TestGetNonce(t *testing.T) { 140 chdr, _ := proto.Marshal(&common.ChannelHeader{ 141 Type: int32(common.HeaderType_ENDORSER_TRANSACTION), 142 }) 143 hdr, _ := proto.Marshal(&common.Header{ 144 ChannelHeader: chdr, 145 SignatureHeader: []byte{}, 146 }) 147 prop := &pb.Proposal{ 148 Header: hdr, 149 } 150 _, err := utils.GetNonce(prop) 151 assert.Error(t, err, "Expected error with nil signature header") 152 153 shdr, _ := proto.Marshal(&common.SignatureHeader{ 154 Nonce: []byte("nonce"), 155 }) 156 hdr, _ = proto.Marshal(&common.Header{ 157 ChannelHeader: chdr, 158 SignatureHeader: shdr, 159 }) 160 prop = &pb.Proposal{ 161 Header: hdr, 162 } 163 nonce, err := utils.GetNonce(prop) 164 assert.NoError(t, err, "Unexpected error getting nonce") 165 assert.Equal(t, "nonce", string(nonce), "Failed to return the expected nonce") 166 167 } 168 169 func TestGetChaincodeDeploymentSpec(t *testing.T) { 170 _, err := utils.GetChaincodeDeploymentSpec([]byte("bad spec")) 171 assert.Error(t, err, "Expected error with malformed spec") 172 173 cds, _ := proto.Marshal(&pb.ChaincodeDeploymentSpec{ 174 ChaincodeSpec: &pb.ChaincodeSpec{ 175 Type: pb.ChaincodeSpec_GOLANG, 176 }, 177 }) 178 _, err = utils.GetChaincodeDeploymentSpec(cds) 179 assert.NoError(t, err, "Unexpected error getting deployment spec") 180 181 cds, _ = proto.Marshal(&pb.ChaincodeDeploymentSpec{ 182 ChaincodeSpec: &pb.ChaincodeSpec{ 183 Type: pb.ChaincodeSpec_UNDEFINED, 184 }, 185 }) 186 _, err = utils.GetChaincodeDeploymentSpec(cds) 187 assert.Error(t, err, "Expected error with invalid spec type") 188 189 } 190 191 func TestCDSProposals(t *testing.T) { 192 var prop *pb.Proposal 193 var err error 194 var txid string 195 creator := []byte("creator") 196 cds := &pb.ChaincodeDeploymentSpec{ 197 ChaincodeSpec: &pb.ChaincodeSpec{ 198 Type: pb.ChaincodeSpec_GOLANG, 199 }, 200 } 201 policy := []byte("policy") 202 escc := []byte("escc") 203 vscc := []byte("vscc") 204 chainID := "testchainid" 205 206 // install 207 prop, txid, err = utils.CreateInstallProposalFromCDS(cds, creator) 208 assert.NotNil(t, prop, "Install proposal should not be nil") 209 assert.NoError(t, err, "Unexpected error creating install proposal") 210 assert.NotEqual(t, "", txid, "txid should not be empty") 211 212 // deploy 213 prop, txid, err = utils.CreateDeployProposalFromCDS(chainID, cds, creator, policy, escc, vscc) 214 assert.NotNil(t, prop, "Deploy proposal should not be nil") 215 assert.NoError(t, err, "Unexpected error creating deploy proposal") 216 assert.NotEqual(t, "", txid, "txid should not be empty") 217 218 // upgrade 219 prop, txid, err = utils.CreateUpgradeProposalFromCDS(chainID, cds, creator, policy, escc, vscc) 220 assert.NotNil(t, prop, "Upgrade proposal should not be nil") 221 assert.NoError(t, err, "Unexpected error creating upgrade proposal") 222 assert.NotEqual(t, "", txid, "txid should not be empty") 223 224 } 225 226 func TestComputeProposalBinding(t *testing.T) { 227 expectedDigestHex := "5093dd4f4277e964da8f4afbde0a9674d17f2a6a5961f0670fc21ae9b67f2983" 228 expectedDigest, _ := hex.DecodeString(expectedDigestHex) 229 chdr, _ := proto.Marshal(&common.ChannelHeader{ 230 Epoch: uint64(10), 231 }) 232 shdr, _ := proto.Marshal(&common.SignatureHeader{ 233 Nonce: []byte("nonce"), 234 Creator: []byte("creator"), 235 }) 236 hdr, _ := proto.Marshal(&common.Header{ 237 ChannelHeader: chdr, 238 SignatureHeader: shdr, 239 }) 240 prop := &pb.Proposal{ 241 Header: hdr, 242 } 243 binding, _ := utils.ComputeProposalBinding(prop) 244 assert.Equal(t, expectedDigest, binding, "Binding does not match expected digest") 245 } 246 247 func TestProposal(t *testing.T) { 248 // create a proposal from a ChaincodeInvocationSpec 249 prop, _, err := utils.CreateChaincodeProposalWithTransient( 250 common.HeaderType_ENDORSER_TRANSACTION, 251 util.GetTestChainID(), createCIS(), 252 []byte("creator"), 253 map[string][]byte{"certx": []byte("transient")}) 254 if err != nil { 255 t.Fatalf("Could not create chaincode proposal, err %s\n", err) 256 return 257 } 258 259 // serialize the proposal 260 pBytes, err := utils.GetBytesProposal(prop) 261 if err != nil { 262 t.Fatalf("Could not serialize the chaincode proposal, err %s\n", err) 263 return 264 } 265 266 // deserialize it and expect it to be the same 267 propBack, err := utils.GetProposal(pBytes) 268 if err != nil { 269 t.Fatalf("Could not deserialize the chaincode proposal, err %s\n", err) 270 return 271 } 272 if !reflect.DeepEqual(prop, propBack) { 273 t.Fatalf("Proposal and deserialized proposals don't match\n") 274 return 275 } 276 277 // get back the header 278 hdr, err := utils.GetHeader(prop.Header) 279 if err != nil { 280 t.Fatalf("Could not extract the header from the proposal, err %s\n", err) 281 } 282 283 hdrBytes, err := utils.GetBytesHeader(hdr) 284 if err != nil { 285 t.Fatalf("Could not marshal the header, err %s\n", err) 286 } 287 288 hdr, err = utils.GetHeader(hdrBytes) 289 if err != nil { 290 t.Fatalf("Could not unmarshal the header, err %s\n", err) 291 } 292 293 chdr, err := utils.UnmarshalChannelHeader(hdr.ChannelHeader) 294 if err != nil { 295 t.Fatalf("Could not unmarshal channel header, err %s", err) 296 } 297 298 shdr, err := utils.GetSignatureHeader(hdr.SignatureHeader) 299 if err != nil { 300 t.Fatalf("Could not unmarshal signature header, err %s", err) 301 } 302 303 _, err = utils.GetBytesSignatureHeader(shdr) 304 if err != nil { 305 t.Fatalf("Could not marshal signature header, err %s", err) 306 } 307 308 // sanity check on header 309 if chdr.Type != int32(common.HeaderType_ENDORSER_TRANSACTION) || 310 shdr.Nonce == nil || 311 string(shdr.Creator) != "creator" { 312 t.Fatalf("Invalid header after unmarshalling\n") 313 return 314 } 315 316 // get back the header extension 317 hdrExt, err := utils.GetChaincodeHeaderExtension(hdr) 318 if err != nil { 319 t.Fatalf("Could not extract the header extensions from the proposal, err %s\n", err) 320 return 321 } 322 323 // sanity check on header extension 324 if string(hdrExt.ChaincodeId.Name) != "chaincode_name" { 325 t.Fatalf("Invalid header extension after unmarshalling\n") 326 return 327 } 328 329 // get back the ChaincodeInvocationSpec 330 cis, err := utils.GetChaincodeInvocationSpec(prop) 331 if err != nil { 332 t.Fatalf("Could not extract chaincode invocation spec from header, err %s\n", err) 333 return 334 } 335 336 // sanity check on cis 337 if cis.ChaincodeSpec.Type != pb.ChaincodeSpec_GOLANG || 338 cis.ChaincodeSpec.ChaincodeId.Name != "chaincode_name" || 339 len(cis.ChaincodeSpec.Input.Args) != 2 || 340 string(cis.ChaincodeSpec.Input.Args[0]) != "arg1" || 341 string(cis.ChaincodeSpec.Input.Args[1]) != "arg2" { 342 t.Fatalf("Invalid chaincode invocation spec after unmarshalling\n") 343 return 344 } 345 346 creator, transient, err := utils.GetChaincodeProposalContext(prop) 347 if err != nil { 348 t.Fatalf("Failed getting chaincode proposal context [%s]", err) 349 } 350 if string(creator) != "creator" { 351 t.Fatalf("Failed checking Creator field. Invalid value, expectext 'creator', got [%s]", string(creator)) 352 return 353 } 354 value, ok := transient["certx"] 355 if !ok || string(value) != "transient" { 356 t.Fatalf("Failed checking Transient field. Invalid value, expectext 'transient', got [%s]", string(value)) 357 return 358 } 359 } 360 361 func TestProposalResponse(t *testing.T) { 362 events := &pb.ChaincodeEvent{ 363 ChaincodeId: "ccid", 364 EventName: "EventName", 365 Payload: []byte("EventPayload"), 366 TxId: "TxID"} 367 ccid := &pb.ChaincodeID{ 368 Name: "ccid", 369 Version: "v1", 370 } 371 372 pHashBytes := []byte("proposal_hash") 373 pResponse := &pb.Response{Status: 200} 374 results := []byte("results") 375 eventBytes, err := utils.GetBytesChaincodeEvent(events) 376 if err != nil { 377 t.Fatalf("Failure while marshalling the ProposalResponsePayload") 378 return 379 } 380 381 // get the bytes of the response 382 pResponseBytes, err := utils.GetBytesResponse(pResponse) 383 if err != nil { 384 t.Fatalf("Failure while marshalling the Response") 385 return 386 } 387 388 // get the response from bytes 389 _, err = utils.GetResponse(pResponseBytes) 390 if err != nil { 391 t.Fatalf("Failure while unmarshalling the Response") 392 return 393 } 394 395 // get the bytes of the ProposalResponsePayload 396 prpBytes, err := utils.GetBytesProposalResponsePayload(pHashBytes, pResponse, results, eventBytes, ccid) 397 if err != nil { 398 t.Fatalf("Failure while marshalling the ProposalResponsePayload") 399 return 400 } 401 402 // get the ProposalResponsePayload message 403 prp, err := utils.GetProposalResponsePayload(prpBytes) 404 if err != nil { 405 t.Fatalf("Failure while unmarshalling the ProposalResponsePayload") 406 return 407 } 408 409 // get the ChaincodeAction message 410 act, err := utils.GetChaincodeAction(prp.Extension) 411 if err != nil { 412 t.Fatalf("Failure while unmarshalling the ChaincodeAction") 413 return 414 } 415 416 // sanity check on the action 417 if string(act.Results) != "results" { 418 t.Fatalf("Invalid actions after unmarshalling") 419 return 420 } 421 422 event, err := utils.GetChaincodeEvents(act.Events) 423 if err != nil { 424 t.Fatalf("Failure while unmarshalling the ChainCodeEvents") 425 return 426 } 427 428 // sanity check on the event 429 if string(event.ChaincodeId) != "ccid" { 430 t.Fatalf("Invalid actions after unmarshalling") 431 return 432 } 433 434 pr := &pb.ProposalResponse{ 435 Payload: prpBytes, 436 Endorsement: &pb.Endorsement{Endorser: []byte("endorser"), Signature: []byte("signature")}, 437 Version: 1, // TODO: pick right version number 438 Response: &pb.Response{Status: 200, Message: "OK"}} 439 440 // create a proposal response 441 prBytes, err := utils.GetBytesProposalResponse(pr) 442 if err != nil { 443 t.Fatalf("Failure while marshalling the ProposalResponse") 444 return 445 } 446 447 // get the proposal response message back 448 prBack, err := utils.GetProposalResponse(prBytes) 449 if err != nil { 450 t.Fatalf("Failure while unmarshalling the ProposalResponse") 451 return 452 } 453 454 // sanity check on pr 455 if prBack.Response.Status != 200 || 456 string(prBack.Endorsement.Signature) != "signature" || 457 string(prBack.Endorsement.Endorser) != "endorser" || 458 bytes.Compare(prBack.Payload, prpBytes) != 0 { 459 t.Fatalf("Invalid ProposalResponse after unmarshalling") 460 return 461 } 462 } 463 464 func TestEnvelope(t *testing.T) { 465 // create a proposal from a ChaincodeInvocationSpec 466 prop, _, err := utils.CreateChaincodeProposal(common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), createCIS(), signerSerialized) 467 if err != nil { 468 t.Fatalf("Could not create chaincode proposal, err %s\n", err) 469 return 470 } 471 472 response := &pb.Response{Status: 200, Payload: []byte("payload")} 473 result := []byte("res") 474 ccid := &pb.ChaincodeID{Name: "foo", Version: "v1"} 475 476 presp, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response, result, nil, ccid, nil, signer) 477 if err != nil { 478 t.Fatalf("Could not create proposal response, err %s\n", err) 479 return 480 } 481 482 tx, err := utils.CreateSignedTx(prop, signer, presp) 483 if err != nil { 484 t.Fatalf("Could not create signed tx, err %s\n", err) 485 return 486 } 487 488 envBytes, err := utils.GetBytesEnvelope(tx) 489 if err != nil { 490 t.Fatalf("Could not marshal envelope, err %s\n", err) 491 return 492 } 493 494 tx, err = utils.GetEnvelopeFromBlock(envBytes) 495 if err != nil { 496 t.Fatalf("Could not unmarshal envelope, err %s\n", err) 497 return 498 } 499 500 act2, err := utils.GetActionFromEnvelope(envBytes) 501 if err != nil { 502 t.Fatalf("Could not extract actions from envelop, err %s\n", err) 503 return 504 } 505 506 if act2.Response.Status != response.Status { 507 t.Fatalf("response staus don't match") 508 return 509 } 510 if bytes.Compare(act2.Response.Payload, response.Payload) != 0 { 511 t.Fatalf("response payload don't match") 512 return 513 } 514 515 if bytes.Compare(act2.Results, result) != 0 { 516 t.Fatalf("results don't match") 517 return 518 } 519 520 txpayl, err := utils.GetPayload(tx) 521 if err != nil { 522 t.Fatalf("Could not unmarshal payload, err %s\n", err) 523 return 524 } 525 526 tx2, err := utils.GetTransaction(txpayl.Data) 527 if err != nil { 528 t.Fatalf("Could not unmarshal Transaction, err %s\n", err) 529 return 530 } 531 532 sh, err := utils.GetSignatureHeader(tx2.Actions[0].Header) 533 if err != nil { 534 t.Fatalf("Could not unmarshal SignatureHeader, err %s\n", err) 535 return 536 } 537 538 if bytes.Compare(sh.Creator, signerSerialized) != 0 { 539 t.Fatalf("creator does not match") 540 return 541 } 542 543 cap, err := utils.GetChaincodeActionPayload(tx2.Actions[0].Payload) 544 if err != nil { 545 t.Fatalf("Could not unmarshal ChaincodeActionPayload, err %s\n", err) 546 return 547 } 548 assert.NotNil(t, cap) 549 550 prp, err := utils.GetProposalResponsePayload(cap.Action.ProposalResponsePayload) 551 if err != nil { 552 t.Fatalf("Could not unmarshal ProposalResponsePayload, err %s\n", err) 553 return 554 } 555 556 ca, err := utils.GetChaincodeAction(prp.Extension) 557 if err != nil { 558 t.Fatalf("Could not unmarshal ChaincodeAction, err %s\n", err) 559 return 560 } 561 562 if ca.Response.Status != response.Status { 563 t.Fatalf("response staus don't match") 564 return 565 } 566 if bytes.Compare(ca.Response.Payload, response.Payload) != 0 { 567 t.Fatalf("response payload don't match") 568 return 569 } 570 571 if bytes.Compare(ca.Results, result) != 0 { 572 t.Fatalf("results don't match") 573 return 574 } 575 } 576 577 func TestProposalTxID(t *testing.T) { 578 nonce := []byte{1} 579 creator := []byte{2} 580 581 txid, err := utils.ComputeProposalTxID(nonce, creator) 582 assert.NotEmpty(t, txid, "TxID cannot be empty.") 583 assert.NoError(t, err, "Failed computing txID") 584 assert.Nil(t, utils.CheckProposalTxID(txid, nonce, creator)) 585 assert.Error(t, utils.CheckProposalTxID("", nonce, creator)) 586 587 txid, err = utils.ComputeProposalTxID(nil, nil) 588 assert.NotEmpty(t, txid, "TxID cannot be empty.") 589 assert.NoError(t, err, "Failed computing txID") 590 } 591 592 func TestComputeProposalTxID(t *testing.T) { 593 txid, err := utils.ComputeProposalTxID([]byte{1}, []byte{1}) 594 assert.NoError(t, err, "Failed computing TxID") 595 596 // Compute the function computed by ComputeProposalTxID, 597 // namely, base64(sha256(nonce||creator)) 598 hf := sha256.New() 599 hf.Write([]byte{1}) 600 hf.Write([]byte{1}) 601 hashOut := hf.Sum(nil) 602 txid2 := hex.EncodeToString(hashOut) 603 604 t.Logf("% x\n", hashOut) 605 t.Logf("% s\n", txid) 606 t.Logf("% s\n", txid2) 607 608 assert.Equal(t, txid, txid2) 609 } 610 611 var signer msp.SigningIdentity 612 var signerSerialized []byte 613 614 func TestMain(m *testing.M) { 615 // setup the MSP manager so that we can sign/verify 616 err := msptesttools.LoadMSPSetupForTesting() 617 if err != nil { 618 os.Exit(-1) 619 fmt.Printf("Could not initialize msp") 620 return 621 } 622 signer, err = mspmgmt.GetLocalMSP().GetDefaultSigningIdentity() 623 if err != nil { 624 os.Exit(-1) 625 fmt.Printf("Could not get signer") 626 return 627 } 628 629 signerSerialized, err = signer.Serialize() 630 if err != nil { 631 os.Exit(-1) 632 fmt.Printf("Could not serialize identity") 633 return 634 } 635 636 os.Exit(m.Run()) 637 }