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.

140 lines
4.2 KiB

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