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.

252 lines
7.7 KiB

  1. package privval
  2. import (
  3. "encoding/base64"
  4. "fmt"
  5. "os"
  6. "testing"
  7. "time"
  8. "github.com/stretchr/testify/assert"
  9. "github.com/stretchr/testify/require"
  10. "github.com/tendermint/tendermint/crypto"
  11. "github.com/tendermint/tendermint/crypto/ed25519"
  12. cmn "github.com/tendermint/tendermint/libs/common"
  13. "github.com/tendermint/tendermint/types"
  14. )
  15. func TestGenLoadValidator(t *testing.T) {
  16. assert := assert.New(t)
  17. _, tempFilePath := cmn.Tempfile("priv_validator_")
  18. privVal := GenFilePV(tempFilePath)
  19. height := int64(100)
  20. privVal.LastHeight = height
  21. privVal.Save()
  22. addr := privVal.GetAddress()
  23. privVal = LoadFilePV(tempFilePath)
  24. assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
  25. assert.Equal(height, privVal.LastHeight, "expected privval.LastHeight to have been saved")
  26. }
  27. func TestLoadOrGenValidator(t *testing.T) {
  28. assert := assert.New(t)
  29. _, tempFilePath := cmn.Tempfile("priv_validator_")
  30. if err := os.Remove(tempFilePath); err != nil {
  31. t.Error(err)
  32. }
  33. privVal := LoadOrGenFilePV(tempFilePath)
  34. addr := privVal.GetAddress()
  35. privVal = LoadOrGenFilePV(tempFilePath)
  36. assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
  37. }
  38. func TestUnmarshalValidator(t *testing.T) {
  39. assert, require := assert.New(t), require.New(t)
  40. // create some fixed values
  41. privKey := ed25519.GenPrivKey()
  42. pubKey := privKey.PubKey()
  43. addr := pubKey.Address()
  44. pubArray := [32]byte(pubKey.(ed25519.PubKeyEd25519))
  45. pubBytes := pubArray[:]
  46. privArray := [64]byte(privKey)
  47. privBytes := privArray[:]
  48. pubB64 := base64.StdEncoding.EncodeToString(pubBytes)
  49. privB64 := base64.StdEncoding.EncodeToString(privBytes)
  50. serialized := fmt.Sprintf(`{
  51. "address": "%s",
  52. "pub_key": {
  53. "type": "tendermint/PubKeyEd25519",
  54. "value": "%s"
  55. },
  56. "last_height": "0",
  57. "last_round": "0",
  58. "last_step": 0,
  59. "priv_key": {
  60. "type": "tendermint/PrivKeyEd25519",
  61. "value": "%s"
  62. }
  63. }`, addr, pubB64, privB64)
  64. val := FilePV{}
  65. err := cdc.UnmarshalJSON([]byte(serialized), &val)
  66. require.Nil(err, "%+v", err)
  67. // make sure the values match
  68. assert.EqualValues(addr, val.GetAddress())
  69. assert.EqualValues(pubKey, val.GetPubKey())
  70. assert.EqualValues(privKey, val.PrivKey)
  71. // export it and make sure it is the same
  72. out, err := cdc.MarshalJSON(val)
  73. require.Nil(err, "%+v", err)
  74. assert.JSONEq(serialized, string(out))
  75. }
  76. func TestSignVote(t *testing.T) {
  77. assert := assert.New(t)
  78. _, tempFilePath := cmn.Tempfile("priv_validator_")
  79. privVal := GenFilePV(tempFilePath)
  80. block1 := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{}}
  81. block2 := types.BlockID{[]byte{3, 2, 1}, types.PartSetHeader{}}
  82. height, round := int64(10), 1
  83. voteType := types.VoteTypePrevote
  84. // sign a vote for first time
  85. vote := newVote(privVal.Address, 0, height, round, voteType, block1)
  86. err := privVal.SignVote("mychainid", vote)
  87. assert.NoError(err, "expected no error signing vote")
  88. // try to sign the same vote again; should be fine
  89. err = privVal.SignVote("mychainid", vote)
  90. assert.NoError(err, "expected no error on signing same vote")
  91. // now try some bad votes
  92. cases := []*types.Vote{
  93. newVote(privVal.Address, 0, height, round-1, voteType, block1), // round regression
  94. newVote(privVal.Address, 0, height-1, round, voteType, block1), // height regression
  95. newVote(privVal.Address, 0, height-2, round+4, voteType, block1), // height regression and different round
  96. newVote(privVal.Address, 0, height, round, voteType, block2), // different block
  97. }
  98. for _, c := range cases {
  99. err = privVal.SignVote("mychainid", c)
  100. assert.Error(err, "expected error on signing conflicting vote")
  101. }
  102. // try signing a vote with a different time stamp
  103. sig := vote.Signature
  104. vote.Timestamp = vote.Timestamp.Add(time.Duration(1000))
  105. err = privVal.SignVote("mychainid", vote)
  106. assert.NoError(err)
  107. assert.Equal(sig, vote.Signature)
  108. }
  109. func TestSignProposal(t *testing.T) {
  110. assert := assert.New(t)
  111. _, tempFilePath := cmn.Tempfile("priv_validator_")
  112. privVal := GenFilePV(tempFilePath)
  113. block1 := types.PartSetHeader{5, []byte{1, 2, 3}}
  114. block2 := types.PartSetHeader{10, []byte{3, 2, 1}}
  115. height, round := int64(10), 1
  116. // sign a proposal for first time
  117. proposal := newProposal(height, round, block1)
  118. err := privVal.SignProposal("mychainid", proposal)
  119. assert.NoError(err, "expected no error signing proposal")
  120. // try to sign the same proposal again; should be fine
  121. err = privVal.SignProposal("mychainid", proposal)
  122. assert.NoError(err, "expected no error on signing same proposal")
  123. // now try some bad Proposals
  124. cases := []*types.Proposal{
  125. newProposal(height, round-1, block1), // round regression
  126. newProposal(height-1, round, block1), // height regression
  127. newProposal(height-2, round+4, block1), // height regression and different round
  128. newProposal(height, round, block2), // different block
  129. }
  130. for _, c := range cases {
  131. err = privVal.SignProposal("mychainid", c)
  132. assert.Error(err, "expected error on signing conflicting proposal")
  133. }
  134. // try signing a proposal with a different time stamp
  135. sig := proposal.Signature
  136. proposal.Timestamp = proposal.Timestamp.Add(time.Duration(1000))
  137. err = privVal.SignProposal("mychainid", proposal)
  138. assert.NoError(err)
  139. assert.Equal(sig, proposal.Signature)
  140. }
  141. func TestDifferByTimestamp(t *testing.T) {
  142. _, tempFilePath := cmn.Tempfile("priv_validator_")
  143. privVal := GenFilePV(tempFilePath)
  144. block1 := types.PartSetHeader{5, []byte{1, 2, 3}}
  145. height, round := int64(10), 1
  146. chainID := "mychainid"
  147. // test proposal
  148. {
  149. proposal := newProposal(height, round, block1)
  150. err := privVal.SignProposal(chainID, proposal)
  151. assert.NoError(t, err, "expected no error signing proposal")
  152. signBytes := proposal.SignBytes(chainID)
  153. sig := proposal.Signature
  154. timeStamp := clipToMS(proposal.Timestamp)
  155. // manipulate the timestamp. should get changed back
  156. proposal.Timestamp = proposal.Timestamp.Add(time.Millisecond)
  157. var emptySig crypto.Signature
  158. proposal.Signature = emptySig
  159. err = privVal.SignProposal("mychainid", proposal)
  160. assert.NoError(t, err, "expected no error on signing same proposal")
  161. assert.Equal(t, timeStamp, proposal.Timestamp)
  162. assert.Equal(t, signBytes, proposal.SignBytes(chainID))
  163. assert.Equal(t, sig, proposal.Signature)
  164. }
  165. // test vote
  166. {
  167. voteType := types.VoteTypePrevote
  168. blockID := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{}}
  169. vote := newVote(privVal.Address, 0, height, round, voteType, blockID)
  170. err := privVal.SignVote("mychainid", vote)
  171. assert.NoError(t, err, "expected no error signing vote")
  172. signBytes := vote.SignBytes(chainID)
  173. sig := vote.Signature
  174. timeStamp := clipToMS(vote.Timestamp)
  175. // manipulate the timestamp. should get changed back
  176. vote.Timestamp = vote.Timestamp.Add(time.Millisecond)
  177. var emptySig crypto.Signature
  178. vote.Signature = emptySig
  179. err = privVal.SignVote("mychainid", vote)
  180. assert.NoError(t, err, "expected no error on signing same vote")
  181. assert.Equal(t, timeStamp, vote.Timestamp)
  182. assert.Equal(t, signBytes, vote.SignBytes(chainID))
  183. assert.Equal(t, sig, vote.Signature)
  184. }
  185. }
  186. func newVote(addr types.Address, idx int, height int64, round int, typ byte, blockID types.BlockID) *types.Vote {
  187. return &types.Vote{
  188. ValidatorAddress: addr,
  189. ValidatorIndex: idx,
  190. Height: height,
  191. Round: round,
  192. Type: typ,
  193. Timestamp: time.Now().UTC(),
  194. BlockID: blockID,
  195. }
  196. }
  197. func newProposal(height int64, round int, partsHeader types.PartSetHeader) *types.Proposal {
  198. return &types.Proposal{
  199. Height: height,
  200. Round: round,
  201. BlockPartsHeader: partsHeader,
  202. Timestamp: time.Now().UTC(),
  203. }
  204. }
  205. func clipToMS(t time.Time) time.Time {
  206. nano := t.UnixNano()
  207. million := int64(1000000)
  208. nano = (nano / million) * million
  209. return time.Unix(0, nano).UTC()
  210. }