github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/endorser/msgvalidation_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package endorser_test 8 9 import ( 10 "fmt" 11 12 . "github.com/onsi/ginkgo" 13 . "github.com/onsi/gomega" 14 15 "github.com/hechain20/hechain/core/endorser" 16 "github.com/hechain20/hechain/core/endorser/fake" 17 "github.com/hechain20/hechain/protoutil" 18 cb "github.com/hyperledger/fabric-protos-go/common" 19 mspproto "github.com/hyperledger/fabric-protos-go/msp" 20 pb "github.com/hyperledger/fabric-protos-go/peer" 21 22 "github.com/golang/protobuf/proto" 23 ) 24 25 var _ = Describe("UnpackProposal", func() { 26 var ( 27 signedProposal *pb.SignedProposal 28 proposal *pb.Proposal 29 header *cb.Header 30 channelHeader *cb.ChannelHeader 31 signatureHeader *cb.SignatureHeader 32 chaincodeHeaderExtension *pb.ChaincodeHeaderExtension 33 chaincodeProposalPayload *pb.ChaincodeProposalPayload 34 chaincodeInvocationSpec *pb.ChaincodeInvocationSpec 35 chaincodeSpec *pb.ChaincodeSpec 36 chaincodeInput *pb.ChaincodeInput 37 chaincodeID *pb.ChaincodeID 38 39 marshalProposal func() []byte 40 marshalHeader func() []byte 41 marshalSignatureHeader func() []byte 42 marshalChannelHeader func() []byte 43 marshalChaincodeHeaderExtension func() []byte 44 marshalChaincodeProposalPayload func() []byte 45 marshalChaincodeInvocationSpec func() []byte 46 ) 47 48 BeforeEach(func() { 49 /* 50 // This is the natural signed proposal structure, however, for test, we need 51 // to be able to control each of the elements, including the nested ones, so 52 // we build it awkwardly through function pointers 53 54 signedProposal = &pb.SignedProposal{ 55 ProposalBytes: protoutil.MarshalOrPanic(&pb.Proposal{ 56 Header: protoutil.MarshalOrPanic(&cb.Header{ 57 ChannelHeader: protoutil.MarshalOrPanic(&cb.ChannelHeader{ 58 Type: int32(cb.HeaderType_ENDORSER_TRANSACTION), 59 Extension: protoutil.MarshalOrPanic(&pb.ChaincodeHeaderExtension{ 60 ChaincodeId: &pb.ChaincodeID{ 61 Name: "chaincode-name", 62 }, 63 }), 64 }), 65 SignatureHeader: protoutil.MarshalOrPanic(&cb.SignatureHeader{}), 66 }), 67 Payload: protoutil.MarshalOrPanic(&pb.ChaincodeProposalPayload{ 68 Input: protoutil.MarshalOrPanic(&pb.ChaincodeInvocationSpec{ 69 ChaincodeSpec: &pb.ChaincodeSpec{ 70 Input: &pb.ChaincodeInput{ 71 Args: [][]byte{[]byte("arg1"), []byte("arg2"), []byte("arg3")}, 72 }, 73 }, 74 }), 75 }), 76 }), 77 } 78 */ 79 chaincodeID = &pb.ChaincodeID{ 80 Name: "chaincode-name", 81 } 82 83 chaincodeHeaderExtension = &pb.ChaincodeHeaderExtension{ 84 ChaincodeId: chaincodeID, 85 } 86 87 marshalChaincodeHeaderExtension = func() []byte { 88 return protoutil.MarshalOrPanic(chaincodeHeaderExtension) 89 } 90 91 channelHeader = &cb.ChannelHeader{ 92 Type: int32(cb.HeaderType_ENDORSER_TRANSACTION), 93 } 94 95 marshalChannelHeader = func() []byte { 96 channelHeader.Extension = marshalChaincodeHeaderExtension() 97 return protoutil.MarshalOrPanic(channelHeader) 98 } 99 100 signatureHeader = &cb.SignatureHeader{ 101 Creator: []byte("creator"), 102 Nonce: []byte("nonce"), 103 } 104 105 marshalSignatureHeader = func() []byte { 106 return protoutil.MarshalOrPanic(signatureHeader) 107 } 108 109 header = &cb.Header{} 110 111 marshalHeader = func() []byte { 112 header.ChannelHeader = marshalChannelHeader() 113 header.SignatureHeader = marshalSignatureHeader() 114 return protoutil.MarshalOrPanic(header) 115 } 116 117 chaincodeInput = &pb.ChaincodeInput{ 118 Args: [][]byte{[]byte("arg1"), []byte("arg2"), []byte("arg3")}, 119 } 120 121 chaincodeSpec = &pb.ChaincodeSpec{ 122 Input: chaincodeInput, 123 } 124 125 chaincodeInvocationSpec = &pb.ChaincodeInvocationSpec{ 126 ChaincodeSpec: chaincodeSpec, 127 } 128 129 marshalChaincodeInvocationSpec = func() []byte { 130 return protoutil.MarshalOrPanic(chaincodeInvocationSpec) 131 } 132 133 chaincodeProposalPayload = &pb.ChaincodeProposalPayload{} 134 135 marshalChaincodeProposalPayload = func() []byte { 136 chaincodeProposalPayload.Input = marshalChaincodeInvocationSpec() 137 return protoutil.MarshalOrPanic(chaincodeProposalPayload) 138 } 139 140 proposal = &pb.Proposal{} 141 142 marshalProposal = func() []byte { 143 proposal.Header = marshalHeader() 144 proposal.Payload = marshalChaincodeProposalPayload() 145 return protoutil.MarshalOrPanic(proposal) 146 } 147 }) 148 149 JustBeforeEach(func() { 150 signedProposal = &pb.SignedProposal{ 151 ProposalBytes: marshalProposal(), 152 } 153 }) 154 155 It("unmarshals the signed proposal into the interesting bits and returns them as a struct", func() { 156 up, err := endorser.UnpackProposal(signedProposal) 157 Expect(err).NotTo(HaveOccurred()) 158 Expect(up.ChaincodeName).To(Equal("chaincode-name")) 159 Expect(up.SignedProposal).To(Equal(signedProposal)) 160 Expect(proto.Equal(up.Proposal, proposal)).To(BeTrue()) 161 Expect(proto.Equal(up.Input, chaincodeInput)).To(BeTrue()) 162 Expect(proto.Equal(up.SignatureHeader, signatureHeader)).To(BeTrue()) 163 Expect(proto.Equal(up.ChannelHeader, channelHeader)).To(BeTrue()) 164 }) 165 166 Context("when the proposal bytes are invalid", func() { 167 BeforeEach(func() { 168 marshalProposal = func() []byte { 169 return []byte("garbage") 170 } 171 }) 172 173 It("wraps and returns an error", func() { 174 _, err := endorser.UnpackProposal(signedProposal) 175 Expect(err).To(MatchError("error unmarshalling Proposal: proto: can't skip unknown wire type 7")) 176 }) 177 }) 178 179 Context("when the header bytes are invalid", func() { 180 BeforeEach(func() { 181 marshalHeader = func() []byte { 182 return []byte("garbage") 183 } 184 }) 185 186 It("wraps and returns the error", func() { 187 _, err := endorser.UnpackProposal(signedProposal) 188 Expect(err).To(MatchError("error unmarshalling Header: proto: can't skip unknown wire type 7")) 189 }) 190 }) 191 192 Context("when the channel header bytes are invalid", func() { 193 BeforeEach(func() { 194 marshalChannelHeader = func() []byte { 195 return []byte("garbage") 196 } 197 }) 198 199 It("wraps and returns an error", func() { 200 _, err := endorser.UnpackProposal(signedProposal) 201 Expect(err).To(MatchError("error unmarshalling ChannelHeader: proto: can't skip unknown wire type 7")) 202 }) 203 }) 204 205 Context("when the signature header bytes are invalid", func() { 206 BeforeEach(func() { 207 marshalSignatureHeader = func() []byte { 208 return []byte("garbage") 209 } 210 }) 211 212 It("wraps and returns an error", func() { 213 _, err := endorser.UnpackProposal(signedProposal) 214 Expect(err).To(MatchError("error unmarshalling SignatureHeader: proto: can't skip unknown wire type 7")) 215 }) 216 }) 217 218 Context("when the chaincode header extension bytes are invalid", func() { 219 BeforeEach(func() { 220 marshalChaincodeHeaderExtension = func() []byte { 221 return []byte("garbage") 222 } 223 }) 224 225 It("wraps and returns an error", func() { 226 _, err := endorser.UnpackProposal(signedProposal) 227 Expect(err).To(MatchError("error unmarshalling ChaincodeHeaderExtension: proto: can't skip unknown wire type 7")) 228 }) 229 }) 230 231 Context("when the chaincode proposal payload is invalid", func() { 232 BeforeEach(func() { 233 marshalChaincodeProposalPayload = func() []byte { 234 return []byte("garbage") 235 } 236 }) 237 238 It("wraps and returns an error", func() { 239 _, err := endorser.UnpackProposal(signedProposal) 240 Expect(err).To(MatchError("error unmarshalling ChaincodeProposalPayload: proto: can't skip unknown wire type 7")) 241 }) 242 }) 243 244 Context("when the chaincode id is empty", func() { 245 BeforeEach(func() { 246 chaincodeHeaderExtension.ChaincodeId = nil 247 }) 248 249 It("wraps and returns an error", func() { 250 _, err := endorser.UnpackProposal(signedProposal) 251 Expect(err).To(MatchError("ChaincodeHeaderExtension.ChaincodeId is nil")) 252 }) 253 }) 254 255 Context("when the chaincode id name is empty", func() { 256 BeforeEach(func() { 257 chaincodeHeaderExtension.ChaincodeId.Name = "" 258 }) 259 260 It("wraps and returns an error", func() { 261 _, err := endorser.UnpackProposal(signedProposal) 262 Expect(err).To(MatchError("ChaincodeHeaderExtension.ChaincodeId.Name is empty")) 263 }) 264 }) 265 266 Context("when the chaincode invocation spec is invalid", func() { 267 BeforeEach(func() { 268 marshalChaincodeInvocationSpec = func() []byte { 269 return []byte("garbage") 270 } 271 }) 272 273 It("wraps and returns an error", func() { 274 _, err := endorser.UnpackProposal(signedProposal) 275 Expect(err).To(MatchError("error unmarshalling ChaincodeInvocationSpec: proto: can't skip unknown wire type 7")) 276 }) 277 }) 278 279 Context("when the chaincode invocation spec is has a nil chaincodespec", func() { 280 BeforeEach(func() { 281 chaincodeInvocationSpec.ChaincodeSpec = nil 282 }) 283 284 It("wraps and returns an error", func() { 285 _, err := endorser.UnpackProposal(signedProposal) 286 Expect(err).To(MatchError("chaincode invocation spec did not contain chaincode spec")) 287 }) 288 }) 289 290 Context("when the input is missing", func() { 291 BeforeEach(func() { 292 chaincodeSpec.Input = nil 293 }) 294 295 It("wraps and returns an error", func() { 296 _, err := endorser.UnpackProposal(signedProposal) 297 Expect(err).To(MatchError("chaincode input did not contain any input")) 298 }) 299 }) 300 }) 301 302 var _ = Describe("Validate", func() { 303 var ( 304 up *endorser.UnpackedProposal 305 306 fakeIdentity *fake.Identity 307 fakeIdentityDeserializer *fake.IdentityDeserializer 308 ) 309 310 BeforeEach(func() { 311 up = &endorser.UnpackedProposal{ 312 SignedProposal: &pb.SignedProposal{ 313 Signature: []byte("signature"), 314 ProposalBytes: []byte("payload"), 315 }, 316 ChannelHeader: &cb.ChannelHeader{ 317 ChannelId: "channel-id", 318 Type: int32(cb.HeaderType_ENDORSER_TRANSACTION), 319 TxId: "876a1777b78e5e3a6d1aabf8b5a11b893c3838285b2f5eedca7d23e25365fcfd", 320 }, 321 SignatureHeader: &cb.SignatureHeader{ 322 Nonce: []byte("nonce"), 323 Creator: protoutil.MarshalOrPanic(&mspproto.SerializedIdentity{ 324 Mspid: "mspid", 325 IdBytes: []byte("identity"), 326 }), 327 }, 328 } 329 330 fakeIdentity = &fake.Identity{} 331 332 fakeIdentityDeserializer = &fake.IdentityDeserializer{} 333 fakeIdentityDeserializer.DeserializeIdentityReturns(fakeIdentity, nil) 334 }) 335 336 It("validates the proposal", func() { 337 err := up.Validate(fakeIdentityDeserializer) 338 Expect(err).NotTo(HaveOccurred()) 339 340 Expect(fakeIdentityDeserializer.DeserializeIdentityCallCount()).To(Equal(1)) 341 creator := fakeIdentityDeserializer.DeserializeIdentityArgsForCall(0) 342 Expect(creator).To(Equal(protoutil.MarshalOrPanic(&mspproto.SerializedIdentity{ 343 Mspid: "mspid", 344 IdBytes: []byte("identity"), 345 }))) 346 347 Expect(fakeIdentity.ValidateCallCount()).To(Equal(1)) 348 Expect(fakeIdentity.VerifyCallCount()).To(Equal(1)) 349 payload, sig := fakeIdentity.VerifyArgsForCall(0) 350 Expect(payload).To(Equal([]byte("payload"))) 351 Expect(sig).To(Equal([]byte("signature"))) 352 }) 353 354 Context("when the header type is config", func() { 355 BeforeEach(func() { 356 up.ChannelHeader = &cb.ChannelHeader{ 357 Type: int32(cb.HeaderType_CONFIG), 358 TxId: "876a1777b78e5e3a6d1aabf8b5a11b893c3838285b2f5eedca7d23e25365fcfd", 359 } 360 }) 361 362 It("preserves buggy behavior and does not error", func() { 363 err := up.Validate(fakeIdentityDeserializer) 364 Expect(err).NotTo(HaveOccurred()) 365 }) 366 }) 367 368 Context("when the header type is bad", func() { 369 BeforeEach(func() { 370 up.ChannelHeader = &cb.ChannelHeader{ 371 Type: int32(0), 372 TxId: "876a1777b78e5e3a6d1aabf8b5a11b893c3838285b2f5eedca7d23e25365fcfd", 373 } 374 }) 375 376 It("returns an error", func() { 377 err := up.Validate(fakeIdentityDeserializer) 378 Expect(err).To(MatchError("invalid header type MESSAGE")) 379 }) 380 }) 381 382 Context("when the signature is missing", func() { 383 BeforeEach(func() { 384 up.SignedProposal.Signature = nil 385 }) 386 387 It("returns an error", func() { 388 err := up.Validate(fakeIdentityDeserializer) 389 Expect(err).To(MatchError("empty signature bytes")) 390 }) 391 }) 392 393 Context("when the nonce is missing", func() { 394 BeforeEach(func() { 395 up.SignatureHeader.Nonce = nil 396 }) 397 398 It("returns an error", func() { 399 err := up.Validate(fakeIdentityDeserializer) 400 Expect(err).To(MatchError("nonce is empty")) 401 }) 402 }) 403 404 Context("when the creator is missing", func() { 405 BeforeEach(func() { 406 up.SignatureHeader.Creator = nil 407 }) 408 409 It("returns an error", func() { 410 err := up.Validate(fakeIdentityDeserializer) 411 Expect(err).To(MatchError("creator is empty")) 412 }) 413 }) 414 415 Context("when the epoch is nonzero", func() { 416 BeforeEach(func() { 417 up.ChannelHeader.Epoch = 7 418 }) 419 420 It("returns an error", func() { 421 err := up.Validate(fakeIdentityDeserializer) 422 Expect(err).To(MatchError("epoch is non-zero")) 423 }) 424 }) 425 426 Context("when the txid is wrong", func() { 427 BeforeEach(func() { 428 up.ChannelHeader.TxId = "fake-txid" 429 }) 430 431 It("returns an error", func() { 432 err := up.Validate(fakeIdentityDeserializer) 433 Expect(err).To(MatchError("incorrectly computed txid 'fake-txid' -- expected '876a1777b78e5e3a6d1aabf8b5a11b893c3838285b2f5eedca7d23e25365fcfd'")) 434 }) 435 }) 436 437 Context("when the proposal bytes are missing", func() { 438 BeforeEach(func() { 439 up.SignedProposal.ProposalBytes = nil 440 }) 441 442 It("returns an error", func() { 443 err := up.Validate(fakeIdentityDeserializer) 444 Expect(err).To(MatchError("empty proposal bytes")) 445 }) 446 }) 447 448 Context("when the identity cannot be deserialized", func() { 449 BeforeEach(func() { 450 fakeIdentityDeserializer.DeserializeIdentityReturns(nil, fmt.Errorf("fake-deserializing-error")) 451 }) 452 453 It("returns a generic auth error", func() { 454 err := up.Validate(fakeIdentityDeserializer) 455 Expect(err).To(MatchError("access denied: channel [channel-id] creator org unknown, creator is malformed")) 456 }) 457 }) 458 459 Context("when the identity is not valid", func() { 460 BeforeEach(func() { 461 fakeIdentity.GetMSPIdentifierReturns("mspid") 462 fakeIdentity.ValidateReturns(fmt.Errorf("fake-validate-error")) 463 }) 464 465 It("returns a generic auth error", func() { 466 err := up.Validate(fakeIdentityDeserializer) 467 Expect(err).To(MatchError("access denied: channel [channel-id] creator org [mspid]")) 468 }) 469 }) 470 471 Context("when the identity signature is not valid", func() { 472 BeforeEach(func() { 473 fakeIdentity.GetMSPIdentifierReturns("mspid") 474 fakeIdentity.VerifyReturns(fmt.Errorf("fake-verify-error")) 475 }) 476 477 It("returns a generic auth error", func() { 478 err := up.Validate(fakeIdentityDeserializer) 479 Expect(err).To(MatchError("access denied: channel [channel-id] creator org [mspid]")) 480 }) 481 }) 482 })