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.

262 lines
7.8 KiB

  1. package types
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/require"
  8. tmmath "github.com/tendermint/tendermint/libs/math"
  9. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  10. )
  11. // Check VerifyCommit, VerifyCommitLight and VerifyCommitLightTrusting basic
  12. // verification.
  13. func TestValidatorSet_VerifyCommit_All(t *testing.T) {
  14. var (
  15. round = int32(0)
  16. height = int64(100)
  17. blockID = makeBlockID([]byte("blockhash"), 1000, []byte("partshash"))
  18. chainID = "Lalande21185"
  19. trustLevel = tmmath.Fraction{Numerator: 2, Denominator: 3}
  20. )
  21. testCases := []struct {
  22. description string
  23. // vote chainID
  24. chainID string
  25. // vote blockID
  26. blockID BlockID
  27. valSize int
  28. // height of the commit
  29. height int64
  30. // votes
  31. blockVotes int
  32. nilVotes int
  33. absentVotes int
  34. expErr bool
  35. }{
  36. {"good (batch verification)", chainID, blockID, 3, height, 3, 0, 0, false},
  37. {"good (single verification)", chainID, blockID, 1, height, 1, 0, 0, false},
  38. {"wrong signature (#0)", "EpsilonEridani", blockID, 2, height, 2, 0, 0, true},
  39. {"wrong block ID", chainID, makeBlockIDRandom(), 2, height, 2, 0, 0, true},
  40. {"wrong height", chainID, blockID, 1, height - 1, 1, 0, 0, true},
  41. {"wrong set size: 4 vs 3", chainID, blockID, 4, height, 3, 0, 0, true},
  42. {"wrong set size: 1 vs 2", chainID, blockID, 1, height, 2, 0, 0, true},
  43. {"insufficient voting power: got 30, needed more than 66", chainID, blockID, 10, height, 3, 2, 5, true},
  44. {"insufficient voting power: got 0, needed more than 6", chainID, blockID, 1, height, 0, 0, 1, true},
  45. {"insufficient voting power: got 60, needed more than 60", chainID, blockID, 9, height, 6, 3, 0, true},
  46. }
  47. for _, tc := range testCases {
  48. tc := tc
  49. t.Run(tc.description, func(t *testing.T) {
  50. _, valSet, vals := randVoteSet(tc.height, round, tmproto.PrecommitType, tc.valSize, 10)
  51. totalVotes := tc.blockVotes + tc.absentVotes + tc.nilVotes
  52. sigs := make([]CommitSig, totalVotes)
  53. vi := 0
  54. // add absent sigs first
  55. for i := 0; i < tc.absentVotes; i++ {
  56. sigs[vi] = NewCommitSigAbsent()
  57. vi++
  58. }
  59. for i := 0; i < tc.blockVotes+tc.nilVotes; i++ {
  60. pubKey, err := vals[vi%len(vals)].GetPubKey(context.Background())
  61. require.NoError(t, err)
  62. vote := &Vote{
  63. ValidatorAddress: pubKey.Address(),
  64. ValidatorIndex: int32(vi),
  65. Height: tc.height,
  66. Round: round,
  67. Type: tmproto.PrecommitType,
  68. BlockID: tc.blockID,
  69. Timestamp: time.Now(),
  70. }
  71. if i >= tc.blockVotes {
  72. vote.BlockID = BlockID{}
  73. }
  74. v := vote.ToProto()
  75. require.NoError(t, vals[vi%len(vals)].SignVote(context.Background(), tc.chainID, v))
  76. vote.Signature = v.Signature
  77. sigs[vi] = vote.CommitSig()
  78. vi++
  79. }
  80. commit := NewCommit(tc.height, round, tc.blockID, sigs)
  81. err := valSet.VerifyCommit(chainID, blockID, height, commit)
  82. if tc.expErr {
  83. if assert.Error(t, err, "VerifyCommit") {
  84. assert.Contains(t, err.Error(), tc.description, "VerifyCommit")
  85. }
  86. } else {
  87. assert.NoError(t, err, "VerifyCommit")
  88. }
  89. err = valSet.VerifyCommitLight(chainID, blockID, height, commit)
  90. if tc.expErr {
  91. if assert.Error(t, err, "VerifyCommitLight") {
  92. assert.Contains(t, err.Error(), tc.description, "VerifyCommitLight")
  93. }
  94. } else {
  95. assert.NoError(t, err, "VerifyCommitLight")
  96. }
  97. // only a subsection of the tests apply to VerifyCommitLightTrusting
  98. if totalVotes != tc.valSize || !tc.blockID.Equals(blockID) || tc.height != height {
  99. tc.expErr = false
  100. }
  101. err = valSet.VerifyCommitLightTrusting(chainID, commit, trustLevel)
  102. if tc.expErr {
  103. if assert.Error(t, err, "VerifyCommitLightTrusting") {
  104. assert.Contains(t, err.Error(), tc.description, "VerifyCommitLightTrusting")
  105. }
  106. } else {
  107. assert.NoError(t, err, "VerifyCommitLightTrusting")
  108. }
  109. })
  110. }
  111. }
  112. func TestValidatorSet_VerifyCommit_CheckAllSignatures(t *testing.T) {
  113. var (
  114. chainID = "test_chain_id"
  115. h = int64(3)
  116. blockID = makeBlockIDRandom()
  117. )
  118. voteSet, valSet, vals := randVoteSet(h, 0, tmproto.PrecommitType, 4, 10)
  119. commit, err := makeCommit(blockID, h, 0, voteSet, vals, time.Now())
  120. require.NoError(t, err)
  121. require.NoError(t, valSet.VerifyCommit(chainID, blockID, h, commit))
  122. // malleate 4th signature
  123. vote := voteSet.GetByIndex(3)
  124. v := vote.ToProto()
  125. err = vals[3].SignVote(context.Background(), "CentaurusA", v)
  126. require.NoError(t, err)
  127. vote.Signature = v.Signature
  128. commit.Signatures[3] = vote.CommitSig()
  129. err = valSet.VerifyCommit(chainID, blockID, h, commit)
  130. if assert.Error(t, err) {
  131. assert.Contains(t, err.Error(), "wrong signature (#3)")
  132. }
  133. }
  134. func TestValidatorSet_VerifyCommitLight_ReturnsAsSoonAsMajorityOfVotingPowerSigned(t *testing.T) {
  135. var (
  136. chainID = "test_chain_id"
  137. h = int64(3)
  138. blockID = makeBlockIDRandom()
  139. )
  140. voteSet, valSet, vals := randVoteSet(h, 0, tmproto.PrecommitType, 4, 10)
  141. commit, err := makeCommit(blockID, h, 0, voteSet, vals, time.Now())
  142. require.NoError(t, err)
  143. require.NoError(t, valSet.VerifyCommit(chainID, blockID, h, commit))
  144. // malleate 4th signature (3 signatures are enough for 2/3+)
  145. vote := voteSet.GetByIndex(3)
  146. v := vote.ToProto()
  147. err = vals[3].SignVote(context.Background(), "CentaurusA", v)
  148. require.NoError(t, err)
  149. vote.Signature = v.Signature
  150. commit.Signatures[3] = vote.CommitSig()
  151. err = valSet.VerifyCommitLight(chainID, blockID, h, commit)
  152. assert.NoError(t, err)
  153. }
  154. func TestValidatorSet_VerifyCommitLightTrusting_ReturnsAsSoonAsTrustLevelOfVotingPowerSigned(t *testing.T) {
  155. var (
  156. chainID = "test_chain_id"
  157. h = int64(3)
  158. blockID = makeBlockIDRandom()
  159. )
  160. voteSet, valSet, vals := randVoteSet(h, 0, tmproto.PrecommitType, 4, 10)
  161. commit, err := makeCommit(blockID, h, 0, voteSet, vals, time.Now())
  162. require.NoError(t, err)
  163. require.NoError(t, valSet.VerifyCommit(chainID, blockID, h, commit))
  164. // malleate 3rd signature (2 signatures are enough for 1/3+ trust level)
  165. vote := voteSet.GetByIndex(2)
  166. v := vote.ToProto()
  167. err = vals[2].SignVote(context.Background(), "CentaurusA", v)
  168. require.NoError(t, err)
  169. vote.Signature = v.Signature
  170. commit.Signatures[2] = vote.CommitSig()
  171. err = valSet.VerifyCommitLightTrusting(chainID, commit, tmmath.Fraction{Numerator: 1, Denominator: 3})
  172. assert.NoError(t, err)
  173. }
  174. func TestValidatorSet_VerifyCommitLightTrusting(t *testing.T) {
  175. var (
  176. blockID = makeBlockIDRandom()
  177. voteSet, originalValset, vals = randVoteSet(1, 1, tmproto.PrecommitType, 6, 1)
  178. commit, err = makeCommit(blockID, 1, 1, voteSet, vals, time.Now())
  179. newValSet, _ = randValidatorPrivValSet(2, 1)
  180. )
  181. require.NoError(t, err)
  182. testCases := []struct {
  183. valSet *ValidatorSet
  184. err bool
  185. }{
  186. // good
  187. 0: {
  188. valSet: originalValset,
  189. err: false,
  190. },
  191. // bad - no overlap between validator sets
  192. 1: {
  193. valSet: newValSet,
  194. err: true,
  195. },
  196. // good - first two are different but the rest of the same -> >1/3
  197. 2: {
  198. valSet: NewValidatorSet(append(newValSet.Validators, originalValset.Validators...)),
  199. err: false,
  200. },
  201. }
  202. for _, tc := range testCases {
  203. err = tc.valSet.VerifyCommitLightTrusting("test_chain_id", commit,
  204. tmmath.Fraction{Numerator: 1, Denominator: 3})
  205. if tc.err {
  206. assert.Error(t, err)
  207. } else {
  208. assert.NoError(t, err)
  209. }
  210. }
  211. }
  212. func TestValidatorSet_VerifyCommitLightTrustingErrorsOnOverflow(t *testing.T) {
  213. var (
  214. blockID = makeBlockIDRandom()
  215. voteSet, valSet, vals = randVoteSet(1, 1, tmproto.PrecommitType, 1, MaxTotalVotingPower)
  216. commit, err = makeCommit(blockID, 1, 1, voteSet, vals, time.Now())
  217. )
  218. require.NoError(t, err)
  219. err = valSet.VerifyCommitLightTrusting("test_chain_id", commit,
  220. tmmath.Fraction{Numerator: 25, Denominator: 55})
  221. if assert.Error(t, err) {
  222. assert.Contains(t, err.Error(), "int64 overflow")
  223. }
  224. }