github.com/okex/exchain@v1.8.0/libs/tendermint/lite/helpers.go (about)

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