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.

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