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.

168 lines
4.6 KiB

  1. package e2e_test
  2. import (
  3. "bytes"
  4. "testing"
  5. "github.com/stretchr/testify/require"
  6. e2e "github.com/tendermint/tendermint/test/e2e/pkg"
  7. "github.com/tendermint/tendermint/types"
  8. )
  9. // Tests that validator sets are available and correct according to
  10. // scheduled validator updates.
  11. func TestValidator_Sets(t *testing.T) {
  12. testNode(t, func(t *testing.T, node e2e.Node) {
  13. if node.Mode == e2e.ModeSeed {
  14. return
  15. }
  16. client, err := node.Client()
  17. require.NoError(t, err)
  18. status, err := client.Status(ctx)
  19. require.NoError(t, err)
  20. first := status.SyncInfo.EarliestBlockHeight
  21. last := status.SyncInfo.LatestBlockHeight
  22. // skip first block if node is pruning blocks, to avoid race conditions
  23. if node.RetainBlocks > 0 {
  24. first++
  25. }
  26. valSchedule := newValidatorSchedule(*node.Testnet)
  27. valSchedule.Increment(first - node.Testnet.InitialHeight)
  28. for h := first; h <= last; h++ {
  29. validators := []*types.Validator{}
  30. perPage := 100
  31. for page := 1; ; page++ {
  32. resp, err := client.Validators(ctx, &(h), &(page), &perPage)
  33. require.NoError(t, err)
  34. validators = append(validators, resp.Validators...)
  35. if len(validators) == resp.Total {
  36. break
  37. }
  38. }
  39. require.Equal(t, valSchedule.Set.Validators, validators,
  40. "incorrect validator set at height %v", h)
  41. valSchedule.Increment(1)
  42. }
  43. })
  44. }
  45. // Tests that a validator proposes blocks when it's supposed to. It tolerates some
  46. // missed blocks, e.g. due to testnet perturbations.
  47. func TestValidator_Propose(t *testing.T) {
  48. blocks := fetchBlockChain(t)
  49. testNode(t, func(t *testing.T, node e2e.Node) {
  50. if node.Mode != e2e.ModeValidator {
  51. return
  52. }
  53. address := node.PrivvalKey.PubKey().Address()
  54. valSchedule := newValidatorSchedule(*node.Testnet)
  55. expectCount := 0
  56. proposeCount := 0
  57. for _, block := range blocks {
  58. if bytes.Equal(valSchedule.Set.Proposer.Address, address) {
  59. expectCount++
  60. if bytes.Equal(block.ProposerAddress, address) {
  61. proposeCount++
  62. }
  63. }
  64. valSchedule.Increment(1)
  65. }
  66. require.False(t, proposeCount == 0 && expectCount > 0,
  67. "node did not propose any blocks (expected %v)", expectCount)
  68. if expectCount > 5 {
  69. require.GreaterOrEqual(t, proposeCount, 3, "validator didn't propose even 3 blocks")
  70. }
  71. })
  72. }
  73. // Tests that a validator signs blocks when it's supposed to. It tolerates some
  74. // missed blocks, e.g. due to testnet perturbations.
  75. func TestValidator_Sign(t *testing.T) {
  76. blocks := fetchBlockChain(t)
  77. testNode(t, func(t *testing.T, node e2e.Node) {
  78. if node.Mode != e2e.ModeValidator {
  79. return
  80. }
  81. address := node.PrivvalKey.PubKey().Address()
  82. valSchedule := newValidatorSchedule(*node.Testnet)
  83. expectCount := 0
  84. signCount := 0
  85. for _, block := range blocks[1:] { // Skip first block, since it has no signatures
  86. signed := false
  87. for _, sig := range block.LastCommit.Signatures {
  88. if bytes.Equal(sig.ValidatorAddress, address) {
  89. signed = true
  90. break
  91. }
  92. }
  93. if valSchedule.Set.HasAddress(address) {
  94. expectCount++
  95. if signed {
  96. signCount++
  97. }
  98. } else {
  99. require.False(t, signed, "unexpected signature for block %v", block.LastCommit.Height)
  100. }
  101. valSchedule.Increment(1)
  102. }
  103. require.False(t, signCount == 0 && expectCount > 0,
  104. "validator did not sign any blocks (expected %v)", expectCount)
  105. if expectCount > 7 {
  106. require.GreaterOrEqual(t, signCount, 3, "validator didn't sign even 3 blocks (expected %v)", expectCount)
  107. }
  108. })
  109. }
  110. // validatorSchedule is a validator set iterator, which takes into account
  111. // validator set updates.
  112. type validatorSchedule struct {
  113. Set *types.ValidatorSet
  114. height int64
  115. updates map[int64]map[*e2e.Node]int64
  116. }
  117. func newValidatorSchedule(testnet e2e.Testnet) *validatorSchedule {
  118. valMap := testnet.Validators // genesis validators
  119. if v, ok := testnet.ValidatorUpdates[0]; ok { // InitChain validators
  120. valMap = v
  121. }
  122. return &validatorSchedule{
  123. height: testnet.InitialHeight,
  124. Set: types.NewValidatorSet(makeVals(valMap)),
  125. updates: testnet.ValidatorUpdates,
  126. }
  127. }
  128. func (s *validatorSchedule) Increment(heights int64) {
  129. for i := int64(0); i < heights; i++ {
  130. s.height++
  131. if s.height > 2 {
  132. // validator set updates are offset by 2, since they only take effect
  133. // two blocks after they're returned.
  134. if update, ok := s.updates[s.height-2]; ok {
  135. if err := s.Set.UpdateWithChangeSet(makeVals(update)); err != nil {
  136. panic(err)
  137. }
  138. }
  139. }
  140. s.Set.IncrementProposerPriority(1)
  141. }
  142. }
  143. func makeVals(valMap map[*e2e.Node]int64) []*types.Validator {
  144. vals := make([]*types.Validator, 0, len(valMap))
  145. for node, power := range valMap {
  146. vals = append(vals, types.NewValidator(node.PrivvalKey.PubKey(), power))
  147. }
  148. return vals
  149. }