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.

149 lines
4.2 KiB

  1. package lite
  2. import (
  3. "time"
  4. crypto "github.com/tendermint/go-crypto"
  5. "github.com/tendermint/tendermint/types"
  6. )
  7. // ValKeys is a helper for testing.
  8. //
  9. // It lets us simulate signing with many keys, either ed25519 or secp256k1.
  10. // The main use case is to create a set, and call GenCommit
  11. // to get properly signed header for testing.
  12. //
  13. // You can set different weights of validators each time you call
  14. // ToValidators, and can optionally extend the validator set later
  15. // with Extend or ExtendSecp
  16. type ValKeys []crypto.PrivKey
  17. // GenValKeys produces an array of private keys to generate commits.
  18. func GenValKeys(n int) ValKeys {
  19. res := make(ValKeys, n)
  20. for i := range res {
  21. res[i] = crypto.GenPrivKeyEd25519().Wrap()
  22. }
  23. return res
  24. }
  25. // Change replaces the key at index i.
  26. func (v ValKeys) Change(i int) ValKeys {
  27. res := make(ValKeys, len(v))
  28. copy(res, v)
  29. res[i] = crypto.GenPrivKeyEd25519().Wrap()
  30. return res
  31. }
  32. // Extend adds n more keys (to remove, just take a slice).
  33. func (v ValKeys) Extend(n int) ValKeys {
  34. extra := GenValKeys(n)
  35. return append(v, extra...)
  36. }
  37. // GenSecpValKeys produces an array of secp256k1 private keys to generate commits.
  38. func GenSecpValKeys(n int) ValKeys {
  39. res := make(ValKeys, n)
  40. for i := range res {
  41. res[i] = crypto.GenPrivKeySecp256k1().Wrap()
  42. }
  43. return res
  44. }
  45. // ExtendSecp adds n more secp256k1 keys (to remove, just take a slice).
  46. func (v ValKeys) ExtendSecp(n int) ValKeys {
  47. extra := GenSecpValKeys(n)
  48. return append(v, extra...)
  49. }
  50. // ToValidators produces a list of validators from the set of keys
  51. // The first key has weight `init` and it increases by `inc` every step
  52. // so we can have all the same weight, or a simple linear distribution
  53. // (should be enough for testing).
  54. func (v ValKeys) ToValidators(init, inc int64) *types.ValidatorSet {
  55. res := make([]*types.Validator, len(v))
  56. for i, k := range v {
  57. res[i] = types.NewValidator(k.PubKey(), init+int64(i)*inc)
  58. }
  59. return types.NewValidatorSet(res)
  60. }
  61. // signHeader properly signs the header with all keys from first to last exclusive.
  62. func (v ValKeys) signHeader(header *types.Header, first, last int) *types.Commit {
  63. votes := make([]*types.Vote, len(v))
  64. // we need this list to keep the ordering...
  65. vset := v.ToValidators(1, 0)
  66. // fill in the votes we want
  67. for i := first; i < last; i++ {
  68. vote := makeVote(header, vset, v[i])
  69. votes[vote.ValidatorIndex] = vote
  70. }
  71. res := &types.Commit{
  72. BlockID: types.BlockID{Hash: header.Hash()},
  73. Precommits: votes,
  74. }
  75. return res
  76. }
  77. func makeVote(header *types.Header, vals *types.ValidatorSet, key crypto.PrivKey) *types.Vote {
  78. addr := key.PubKey().Address()
  79. idx, _ := vals.GetByAddress(addr)
  80. vote := &types.Vote{
  81. ValidatorAddress: addr,
  82. ValidatorIndex: idx,
  83. Height: header.Height,
  84. Round: 1,
  85. Type: types.VoteTypePrecommit,
  86. BlockID: types.BlockID{Hash: header.Hash()},
  87. }
  88. // Sign it
  89. signBytes := types.SignBytes(header.ChainID, vote)
  90. vote.Signature = key.Sign(signBytes)
  91. return vote
  92. }
  93. // Silences warning that vals can also be merkle.Hashable
  94. // nolint: interfacer
  95. func genHeader(chainID string, height int, txs types.Txs,
  96. vals *types.ValidatorSet, appHash []byte) *types.Header {
  97. return &types.Header{
  98. ChainID: chainID,
  99. Height: height,
  100. Time: time.Now(),
  101. NumTxs: len(txs),
  102. // LastBlockID
  103. // LastCommitHash
  104. ValidatorsHash: vals.Hash(),
  105. DataHash: txs.Hash(),
  106. AppHash: appHash,
  107. }
  108. }
  109. // GenCommit calls genHeader and signHeader and combines them into a Commit.
  110. func (v ValKeys) GenCommit(chainID string, height int, txs types.Txs,
  111. vals *types.ValidatorSet, appHash []byte, first, last int) Commit {
  112. header := genHeader(chainID, height, txs, vals, appHash)
  113. check := Commit{
  114. Header: header,
  115. Commit: v.signHeader(header, first, last),
  116. }
  117. return check
  118. }
  119. // GenFullCommit calls genHeader and signHeader and combines them into a Commit.
  120. func (v ValKeys) GenFullCommit(chainID string, height int, txs types.Txs,
  121. vals *types.ValidatorSet, appHash []byte, first, last int) FullCommit {
  122. header := genHeader(chainID, height, txs, vals, appHash)
  123. commit := Commit{
  124. Header: header,
  125. Commit: v.signHeader(header, first, last),
  126. }
  127. return NewFullCommit(commit, vals)
  128. }