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