You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
4.7 KiB

  1. package types
  2. import (
  3. "math"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/require"
  8. "github.com/tendermint/tendermint/crypto/tmhash"
  9. )
  10. var testProposal *Proposal
  11. func init() {
  12. var stamp, err = time.Parse(TimeFormat, "2018-02-11T07:09:22.765Z")
  13. if err != nil {
  14. panic(err)
  15. }
  16. testProposal = &Proposal{
  17. Height: 12345,
  18. Round: 23456,
  19. BlockID: BlockID{[]byte{1, 2, 3}, PartSetHeader{111, []byte("blockparts")}},
  20. POLRound: -1,
  21. Timestamp: stamp,
  22. }
  23. }
  24. func TestProposalSignable(t *testing.T) {
  25. chainID := "test_chain_id"
  26. signBytes := testProposal.SignBytes(chainID)
  27. expected, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeProposal(chainID, testProposal))
  28. require.NoError(t, err)
  29. require.Equal(t, expected, signBytes, "Got unexpected sign bytes for Proposal")
  30. }
  31. func TestProposalString(t *testing.T) {
  32. str := testProposal.String()
  33. expected := `Proposal{12345/23456 (010203:111:626C6F636B70, -1) 000000000000 @ 2018-02-11T07:09:22.765Z}`
  34. if str != expected {
  35. t.Errorf("got unexpected string for Proposal. Expected:\n%v\nGot:\n%v", expected, str)
  36. }
  37. }
  38. func TestProposalVerifySignature(t *testing.T) {
  39. privVal := NewMockPV()
  40. pubKey, err := privVal.GetPubKey()
  41. require.NoError(t, err)
  42. prop := NewProposal(
  43. 4, 2, 2,
  44. BlockID{[]byte{1, 2, 3}, PartSetHeader{777, []byte("proper")}})
  45. signBytes := prop.SignBytes("test_chain_id")
  46. // sign it
  47. err = privVal.SignProposal("test_chain_id", prop)
  48. require.NoError(t, err)
  49. // verify the same proposal
  50. valid := pubKey.VerifyBytes(signBytes, prop.Signature)
  51. require.True(t, valid)
  52. // serialize, deserialize and verify again....
  53. newProp := new(Proposal)
  54. bs, err := cdc.MarshalBinaryLengthPrefixed(prop)
  55. require.NoError(t, err)
  56. err = cdc.UnmarshalBinaryLengthPrefixed(bs, &newProp)
  57. require.NoError(t, err)
  58. // verify the transmitted proposal
  59. newSignBytes := newProp.SignBytes("test_chain_id")
  60. require.Equal(t, string(signBytes), string(newSignBytes))
  61. valid = pubKey.VerifyBytes(newSignBytes, newProp.Signature)
  62. require.True(t, valid)
  63. }
  64. func BenchmarkProposalWriteSignBytes(b *testing.B) {
  65. for i := 0; i < b.N; i++ {
  66. testProposal.SignBytes("test_chain_id")
  67. }
  68. }
  69. func BenchmarkProposalSign(b *testing.B) {
  70. privVal := NewMockPV()
  71. for i := 0; i < b.N; i++ {
  72. err := privVal.SignProposal("test_chain_id", testProposal)
  73. if err != nil {
  74. b.Error(err)
  75. }
  76. }
  77. }
  78. func BenchmarkProposalVerifySignature(b *testing.B) {
  79. privVal := NewMockPV()
  80. err := privVal.SignProposal("test_chain_id", testProposal)
  81. require.NoError(b, err)
  82. pubKey, err := privVal.GetPubKey()
  83. require.NoError(b, err)
  84. for i := 0; i < b.N; i++ {
  85. pubKey.VerifyBytes(testProposal.SignBytes("test_chain_id"), testProposal.Signature)
  86. }
  87. }
  88. func TestProposalValidateBasic(t *testing.T) {
  89. privVal := NewMockPV()
  90. testCases := []struct {
  91. testName string
  92. malleateProposal func(*Proposal)
  93. expectErr bool
  94. }{
  95. {"Good Proposal", func(p *Proposal) {}, false},
  96. {"Invalid Type", func(p *Proposal) { p.Type = PrecommitType }, true},
  97. {"Invalid Height", func(p *Proposal) { p.Height = -1 }, true},
  98. {"Invalid Round", func(p *Proposal) { p.Round = -1 }, true},
  99. {"Invalid POLRound", func(p *Proposal) { p.POLRound = -2 }, true},
  100. {"Invalid BlockId", func(p *Proposal) {
  101. p.BlockID = BlockID{[]byte{1, 2, 3}, PartSetHeader{111, []byte("blockparts")}}
  102. }, true},
  103. {"Invalid Signature", func(p *Proposal) {
  104. p.Signature = make([]byte, 0)
  105. }, true},
  106. {"Too big Signature", func(p *Proposal) {
  107. p.Signature = make([]byte, MaxSignatureSize+1)
  108. }, true},
  109. }
  110. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt64, tmhash.Sum([]byte("partshash")))
  111. for _, tc := range testCases {
  112. tc := tc
  113. t.Run(tc.testName, func(t *testing.T) {
  114. prop := NewProposal(
  115. 4, 2, 2,
  116. blockID)
  117. err := privVal.SignProposal("test_chain_id", prop)
  118. require.NoError(t, err)
  119. tc.malleateProposal(prop)
  120. assert.Equal(t, tc.expectErr, prop.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  121. })
  122. }
  123. }
  124. func TestProposalProtoBuf(t *testing.T) {
  125. proposal := NewProposal(1, 2, 3, makeBlockID([]byte("hash"), 2, []byte("part_set_hash")))
  126. proposal.Signature = []byte("sig")
  127. proposal2 := NewProposal(1, 2, 3, BlockID{})
  128. testCases := []struct {
  129. msg string
  130. p1 *Proposal
  131. expPass bool
  132. }{
  133. {"success", proposal, true},
  134. {"success", proposal2, false}, // blcokID cannot be empty
  135. {"empty proposal failure validatebasic", &Proposal{}, false},
  136. {"nil proposal", nil, false},
  137. }
  138. for _, tc := range testCases {
  139. protoProposal := tc.p1.ToProto()
  140. p, err := ProposalFromProto(protoProposal)
  141. if tc.expPass {
  142. require.NoError(t, err)
  143. require.Equal(t, tc.p1, p, tc.msg)
  144. } else {
  145. require.Error(t, err)
  146. }
  147. }
  148. }