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.

159 lines
4.9 KiB

  1. package lite
  2. import (
  3. "github.com/tendermint/tendermint/crypto"
  4. "github.com/tendermint/tendermint/crypto/ed25519"
  5. "github.com/tendermint/tendermint/crypto/secp256k1"
  6. "github.com/tendermint/tendermint/types"
  7. tmtime "github.com/tendermint/tendermint/types/time"
  8. )
  9. // privKeys is a helper type for testing.
  10. //
  11. // It lets us simulate signing with many keys. The main use case is to create
  12. // a set, and call GenSignedHeader to get properly signed header for testing.
  13. //
  14. // You can set different weights of validators each time you call ToValidators,
  15. // and can optionally extend the validator set later with Extend.
  16. type privKeys []crypto.PrivKey
  17. // genPrivKeys produces an array of private keys to generate commits.
  18. func genPrivKeys(n int) privKeys {
  19. res := make(privKeys, n)
  20. for i := range res {
  21. res[i] = ed25519.GenPrivKey()
  22. }
  23. return res
  24. }
  25. // Change replaces the key at index i.
  26. func (pkz privKeys) Change(i int) privKeys {
  27. res := make(privKeys, len(pkz))
  28. copy(res, pkz)
  29. res[i] = ed25519.GenPrivKey()
  30. return res
  31. }
  32. // Extend adds n more keys (to remove, just take a slice).
  33. func (pkz privKeys) Extend(n int) privKeys {
  34. extra := genPrivKeys(n)
  35. return append(pkz, extra...)
  36. }
  37. // GenSecpPrivKeys produces an array of secp256k1 private keys to generate commits.
  38. func GenSecpPrivKeys(n int) privKeys {
  39. res := make(privKeys, n)
  40. for i := range res {
  41. res[i] = secp256k1.GenPrivKey()
  42. }
  43. return res
  44. }
  45. // ExtendSecp adds n more secp256k1 keys (to remove, just take a slice).
  46. func (pkz privKeys) ExtendSecp(n int) privKeys {
  47. extra := GenSecpPrivKeys(n)
  48. return append(pkz, extra...)
  49. }
  50. // ToValidators produces a valset 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 (pkz privKeys) ToValidators(init, inc int64) *types.ValidatorSet {
  55. res := make([]*types.Validator, len(pkz))
  56. for i, k := range pkz {
  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 (pkz privKeys) signHeader(header *types.Header, first, last int) *types.Commit {
  63. commitSigs := make([]types.CommitSig, len(pkz))
  64. for i := 0; i < len(pkz); i++ {
  65. commitSigs[i] = types.NewCommitSigAbsent()
  66. }
  67. // We need this list to keep the ordering.
  68. vset := pkz.ToValidators(1, 0)
  69. blockID := types.BlockID{
  70. Hash: header.Hash(),
  71. PartsHeader: types.PartSetHeader{Total: 1, Hash: crypto.CRandBytes(32)},
  72. }
  73. // Fill in the votes we want.
  74. for i := first; i < last && i < len(pkz); i++ {
  75. vote := makeVote(header, vset, pkz[i], blockID)
  76. commitSigs[vote.ValidatorIndex] = vote.CommitSig()
  77. }
  78. return types.NewCommit(header.Height, 1, blockID, commitSigs)
  79. }
  80. func makeVote(header *types.Header, valset *types.ValidatorSet, key crypto.PrivKey, blockID types.BlockID) *types.Vote {
  81. addr := key.PubKey().Address()
  82. idx, _ := valset.GetByAddress(addr)
  83. vote := &types.Vote{
  84. ValidatorAddress: addr,
  85. ValidatorIndex: idx,
  86. Height: header.Height,
  87. Round: 1,
  88. Timestamp: tmtime.Now(),
  89. Type: types.PrecommitType,
  90. BlockID: blockID,
  91. }
  92. // Sign it
  93. signBytes := vote.SignBytes(header.ChainID)
  94. // TODO Consider reworking makeVote API to return an error
  95. sig, err := key.Sign(signBytes)
  96. if err != nil {
  97. panic(err)
  98. }
  99. vote.Signature = sig
  100. return vote
  101. }
  102. func genHeader(chainID string, height int64, txs types.Txs,
  103. valset, nextValset *types.ValidatorSet, appHash, consHash, resHash []byte) *types.Header {
  104. return &types.Header{
  105. ChainID: chainID,
  106. Height: height,
  107. Time: tmtime.Now(),
  108. // LastBlockID
  109. // LastCommitHash
  110. ValidatorsHash: valset.Hash(),
  111. NextValidatorsHash: nextValset.Hash(),
  112. DataHash: txs.Hash(),
  113. AppHash: appHash,
  114. ConsensusHash: consHash,
  115. LastResultsHash: resHash,
  116. }
  117. }
  118. // GenSignedHeader calls genHeader and signHeader and combines them into a SignedHeader.
  119. func (pkz privKeys) GenSignedHeader(chainID string, height int64, txs types.Txs,
  120. valset, nextValset *types.ValidatorSet, appHash, consHash, resHash []byte, first, last int) types.SignedHeader {
  121. header := genHeader(chainID, height, txs, valset, nextValset, appHash, consHash, resHash)
  122. check := types.SignedHeader{
  123. Header: header,
  124. Commit: pkz.signHeader(header, first, last),
  125. }
  126. return check
  127. }
  128. // GenFullCommit calls genHeader and signHeader and combines them into a FullCommit.
  129. func (pkz privKeys) GenFullCommit(chainID string, height int64, txs types.Txs,
  130. valset, nextValset *types.ValidatorSet, appHash, consHash, resHash []byte, first, last int) FullCommit {
  131. header := genHeader(chainID, height, txs, valset, nextValset, appHash, consHash, resHash)
  132. commit := types.SignedHeader{
  133. Header: header,
  134. Commit: pkz.signHeader(header, first, last),
  135. }
  136. return NewFullCommit(commit, valset, nextValset)
  137. }