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.

295 lines
9.3 KiB

  1. package types
  2. import (
  3. "testing"
  4. "time"
  5. "github.com/gogo/protobuf/proto"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/require"
  8. "github.com/tendermint/tendermint/crypto"
  9. "github.com/tendermint/tendermint/crypto/ed25519"
  10. "github.com/tendermint/tendermint/crypto/tmhash"
  11. "github.com/tendermint/tendermint/libs/protoio"
  12. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  13. )
  14. func examplePrevote() *Vote {
  15. return exampleVote(byte(tmproto.PrevoteType))
  16. }
  17. func examplePrecommit() *Vote {
  18. return exampleVote(byte(tmproto.PrecommitType))
  19. }
  20. func exampleVote(t byte) *Vote {
  21. var stamp, err = time.Parse(TimeFormat, "2017-12-25T03:00:01.234Z")
  22. if err != nil {
  23. panic(err)
  24. }
  25. return &Vote{
  26. Type: tmproto.SignedMsgType(t),
  27. Height: 12345,
  28. Round: 2,
  29. Timestamp: stamp,
  30. BlockID: BlockID{
  31. Hash: tmhash.Sum([]byte("blockID_hash")),
  32. PartSetHeader: PartSetHeader{
  33. Total: 1000000,
  34. Hash: tmhash.Sum([]byte("blockID_part_set_header_hash")),
  35. },
  36. },
  37. ValidatorAddress: crypto.AddressHash([]byte("validator_address")),
  38. ValidatorIndex: 56789,
  39. }
  40. }
  41. func TestVoteSignable(t *testing.T) {
  42. vote := examplePrecommit()
  43. v := vote.ToProto()
  44. signBytes := VoteSignBytes("test_chain_id", v)
  45. pb := CanonicalizeVote("test_chain_id", v)
  46. expected, err := protoio.MarshalDelimited(&pb)
  47. require.NoError(t, err)
  48. require.Equal(t, expected, signBytes, "Got unexpected sign bytes for Vote.")
  49. }
  50. func TestVoteSignBytesTestVectors(t *testing.T) {
  51. tests := []struct {
  52. chainID string
  53. vote *Vote
  54. want []byte
  55. }{
  56. 0: {
  57. "", &Vote{},
  58. // NOTE: Height and Round are skipped here. This case needs to be considered while parsing.
  59. []byte{0xd, 0x2a, 0xb, 0x8, 0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1},
  60. },
  61. // with proper (fixed size) height and round (PreCommit):
  62. 1: {
  63. "", &Vote{Height: 1, Round: 1, Type: tmproto.PrecommitType},
  64. []byte{
  65. 0x21, // length
  66. 0x8, // (field_number << 3) | wire_type
  67. 0x2, // PrecommitType
  68. 0x11, // (field_number << 3) | wire_type
  69. 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
  70. 0x19, // (field_number << 3) | wire_type
  71. 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round
  72. 0x2a, // (field_number << 3) | wire_type
  73. // remaining fields (timestamp):
  74. 0xb, 0x8, 0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1},
  75. },
  76. // with proper (fixed size) height and round (PreVote):
  77. 2: {
  78. "", &Vote{Height: 1, Round: 1, Type: tmproto.PrevoteType},
  79. []byte{
  80. 0x21, // length
  81. 0x8, // (field_number << 3) | wire_type
  82. 0x1, // PrevoteType
  83. 0x11, // (field_number << 3) | wire_type
  84. 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
  85. 0x19, // (field_number << 3) | wire_type
  86. 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round
  87. 0x2a, // (field_number << 3) | wire_type
  88. // remaining fields (timestamp):
  89. 0xb, 0x8, 0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1},
  90. },
  91. 3: {
  92. "", &Vote{Height: 1, Round: 1},
  93. []byte{
  94. 0x1f, // length
  95. 0x11, // (field_number << 3) | wire_type
  96. 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
  97. 0x19, // (field_number << 3) | wire_type
  98. 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round
  99. // remaining fields (timestamp):
  100. 0x2a,
  101. 0xb, 0x8, 0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1},
  102. },
  103. // containing non-empty chain_id:
  104. 4: {
  105. "test_chain_id", &Vote{Height: 1, Round: 1},
  106. []byte{
  107. 0x2e, // length
  108. 0x11, // (field_number << 3) | wire_type
  109. 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
  110. 0x19, // (field_number << 3) | wire_type
  111. 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round
  112. // remaining fields:
  113. 0x2a, // (field_number << 3) | wire_type
  114. 0xb, 0x8, 0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1, // timestamp
  115. // (field_number << 3) | wire_type
  116. 0x32,
  117. 0xd, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64}, // chainID
  118. },
  119. }
  120. for i, tc := range tests {
  121. v := tc.vote.ToProto()
  122. got := VoteSignBytes(tc.chainID, v)
  123. assert.Equal(t, len(tc.want), len(got), "test case #%v: got unexpected sign bytes length for Vote.", i)
  124. assert.Equal(t, tc.want, got, "test case #%v: got unexpected sign bytes for Vote.", i)
  125. }
  126. }
  127. func TestVoteProposalNotEq(t *testing.T) {
  128. cv := CanonicalizeVote("", &tmproto.Vote{Height: 1, Round: 1})
  129. p := CanonicalizeProposal("", &tmproto.Proposal{Height: 1, Round: 1})
  130. vb, err := proto.Marshal(&cv)
  131. require.NoError(t, err)
  132. pb, err := proto.Marshal(&p)
  133. require.NoError(t, err)
  134. require.NotEqual(t, vb, pb)
  135. }
  136. func TestVoteVerifySignature(t *testing.T) {
  137. privVal := NewMockPV()
  138. pubkey, err := privVal.GetPubKey()
  139. require.NoError(t, err)
  140. vote := examplePrecommit()
  141. v := vote.ToProto()
  142. signBytes := VoteSignBytes("test_chain_id", v)
  143. // sign it
  144. err = privVal.SignVote("test_chain_id", v)
  145. require.NoError(t, err)
  146. // verify the same vote
  147. valid := pubkey.VerifySignature(VoteSignBytes("test_chain_id", v), v.Signature)
  148. require.True(t, valid)
  149. // serialize, deserialize and verify again....
  150. precommit := new(tmproto.Vote)
  151. bs, err := proto.Marshal(v)
  152. require.NoError(t, err)
  153. err = proto.Unmarshal(bs, precommit)
  154. require.NoError(t, err)
  155. // verify the transmitted vote
  156. newSignBytes := VoteSignBytes("test_chain_id", precommit)
  157. require.Equal(t, string(signBytes), string(newSignBytes))
  158. valid = pubkey.VerifySignature(newSignBytes, precommit.Signature)
  159. require.True(t, valid)
  160. }
  161. func TestIsVoteTypeValid(t *testing.T) {
  162. tc := []struct {
  163. name string
  164. in tmproto.SignedMsgType
  165. out bool
  166. }{
  167. {"Prevote", tmproto.PrevoteType, true},
  168. {"Precommit", tmproto.PrecommitType, true},
  169. {"InvalidType", tmproto.SignedMsgType(0x3), false},
  170. }
  171. for _, tt := range tc {
  172. tt := tt
  173. t.Run(tt.name, func(st *testing.T) {
  174. if rs := IsVoteTypeValid(tt.in); rs != tt.out {
  175. t.Errorf("got unexpected Vote type. Expected:\n%v\nGot:\n%v", rs, tt.out)
  176. }
  177. })
  178. }
  179. }
  180. func TestVoteVerify(t *testing.T) {
  181. privVal := NewMockPV()
  182. pubkey, err := privVal.GetPubKey()
  183. require.NoError(t, err)
  184. vote := examplePrevote()
  185. vote.ValidatorAddress = pubkey.Address()
  186. err = vote.Verify("test_chain_id", ed25519.GenPrivKey().PubKey())
  187. if assert.Error(t, err) {
  188. assert.Equal(t, ErrVoteInvalidValidatorAddress, err)
  189. }
  190. err = vote.Verify("test_chain_id", pubkey)
  191. if assert.Error(t, err) {
  192. assert.Equal(t, ErrVoteInvalidSignature, err)
  193. }
  194. }
  195. func TestVoteString(t *testing.T) {
  196. str := examplePrecommit().String()
  197. expected := `Vote{56789:6AF1F4111082 12345/02/SIGNED_MSG_TYPE_PRECOMMIT(Precommit) 8B01023386C3 000000000000 @ 2017-12-25T03:00:01.234Z}` //nolint:lll //ignore line length for tests
  198. if str != expected {
  199. t.Errorf("got unexpected string for Vote. Expected:\n%v\nGot:\n%v", expected, str)
  200. }
  201. str2 := examplePrevote().String()
  202. expected = `Vote{56789:6AF1F4111082 12345/02/SIGNED_MSG_TYPE_PREVOTE(Prevote) 8B01023386C3 000000000000 @ 2017-12-25T03:00:01.234Z}` //nolint:lll //ignore line length for tests
  203. if str2 != expected {
  204. t.Errorf("got unexpected string for Vote. Expected:\n%v\nGot:\n%v", expected, str2)
  205. }
  206. }
  207. func TestVoteValidateBasic(t *testing.T) {
  208. privVal := NewMockPV()
  209. testCases := []struct {
  210. testName string
  211. malleateVote func(*Vote)
  212. expectErr bool
  213. }{
  214. {"Good Vote", func(v *Vote) {}, false},
  215. {"Negative Height", func(v *Vote) { v.Height = -1 }, true},
  216. {"Negative Round", func(v *Vote) { v.Round = -1 }, true},
  217. {"Invalid BlockID", func(v *Vote) {
  218. v.BlockID = BlockID{[]byte{1, 2, 3}, PartSetHeader{111, []byte("blockparts")}}
  219. }, true},
  220. {"Invalid Address", func(v *Vote) { v.ValidatorAddress = make([]byte, 1) }, true},
  221. {"Invalid ValidatorIndex", func(v *Vote) { v.ValidatorIndex = -1 }, true},
  222. {"Invalid Signature", func(v *Vote) { v.Signature = nil }, true},
  223. {"Too big Signature", func(v *Vote) { v.Signature = make([]byte, MaxSignatureSize+1) }, true},
  224. }
  225. for _, tc := range testCases {
  226. tc := tc
  227. t.Run(tc.testName, func(t *testing.T) {
  228. vote := examplePrecommit()
  229. v := vote.ToProto()
  230. err := privVal.SignVote("test_chain_id", v)
  231. vote.Signature = v.Signature
  232. require.NoError(t, err)
  233. tc.malleateVote(vote)
  234. assert.Equal(t, tc.expectErr, vote.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  235. })
  236. }
  237. }
  238. func TestVoteProtobuf(t *testing.T) {
  239. privVal := NewMockPV()
  240. vote := examplePrecommit()
  241. v := vote.ToProto()
  242. err := privVal.SignVote("test_chain_id", v)
  243. vote.Signature = v.Signature
  244. require.NoError(t, err)
  245. testCases := []struct {
  246. msg string
  247. v1 *Vote
  248. expPass bool
  249. }{
  250. {"success", vote, true},
  251. {"fail vote validate basic", &Vote{}, false},
  252. {"failure nil", nil, false},
  253. }
  254. for _, tc := range testCases {
  255. protoProposal := tc.v1.ToProto()
  256. v, err := VoteFromProto(protoProposal)
  257. if tc.expPass {
  258. require.NoError(t, err)
  259. require.Equal(t, tc.v1, v, tc.msg)
  260. } else {
  261. require.Error(t, err)
  262. }
  263. }
  264. }