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.

161 lines
4.6 KiB

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