github.com/okex/exchain@v1.8.0/libs/tendermint/lite2/helpers_test.go (about)

     1  package lite_test
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/okex/exchain/libs/tendermint/crypto"
     7  	"github.com/okex/exchain/libs/tendermint/crypto/ed25519"
     8  	"github.com/okex/exchain/libs/tendermint/crypto/tmhash"
     9  
    10  	"github.com/okex/exchain/libs/tendermint/types"
    11  	tmtime "github.com/okex/exchain/libs/tendermint/types/time"
    12  )
    13  
    14  // privKeys is a helper type for testing.
    15  //
    16  // It lets us simulate signing with many keys.  The main use case is to create
    17  // a set, and call GenSignedHeader to get properly signed header for testing.
    18  //
    19  // You can set different weights of validators each time you call ToValidators,
    20  // and can optionally extend the validator set later with Extend.
    21  type privKeys []crypto.PrivKey
    22  
    23  // genPrivKeys produces an array of private keys to generate commits.
    24  func genPrivKeys(n int) privKeys {
    25  	res := make(privKeys, n)
    26  	for i := range res {
    27  		res[i] = ed25519.GenPrivKey()
    28  	}
    29  	return res
    30  }
    31  
    32  // // Change replaces the key at index i.
    33  // func (pkz privKeys) Change(i int) privKeys {
    34  // 	res := make(privKeys, len(pkz))
    35  // 	copy(res, pkz)
    36  // 	res[i] = ed25519.GenPrivKey()
    37  // 	return res
    38  // }
    39  
    40  // Extend adds n more keys (to remove, just take a slice).
    41  func (pkz privKeys) Extend(n int) privKeys {
    42  	extra := genPrivKeys(n)
    43  	return append(pkz, extra...)
    44  }
    45  
    46  // // GenSecpPrivKeys produces an array of secp256k1 private keys to generate commits.
    47  // func GenSecpPrivKeys(n int) privKeys {
    48  // 	res := make(privKeys, n)
    49  // 	for i := range res {
    50  // 		res[i] = secp256k1.GenPrivKey()
    51  // 	}
    52  // 	return res
    53  // }
    54  
    55  // // ExtendSecp adds n more secp256k1 keys (to remove, just take a slice).
    56  // func (pkz privKeys) ExtendSecp(n int) privKeys {
    57  // 	extra := GenSecpPrivKeys(n)
    58  // 	return append(pkz, extra...)
    59  // }
    60  
    61  // ToValidators produces a valset from the set of keys.
    62  // The first key has weight `init` and it increases by `inc` every step
    63  // so we can have all the same weight, or a simple linear distribution
    64  // (should be enough for testing).
    65  func (pkz privKeys) ToValidators(init, inc int64) *types.ValidatorSet {
    66  	res := make([]*types.Validator, len(pkz))
    67  	for i, k := range pkz {
    68  		res[i] = types.NewValidator(k.PubKey(), init+int64(i)*inc)
    69  	}
    70  	return types.NewValidatorSet(res)
    71  }
    72  
    73  // signHeader properly signs the header with all keys from first to last exclusive.
    74  func (pkz privKeys) signHeader(header *types.Header, first, last int) *types.Commit {
    75  	commitSigs := make([]types.CommitSig, len(pkz))
    76  	for i := 0; i < len(pkz); i++ {
    77  		commitSigs[i] = types.NewCommitSigAbsent()
    78  	}
    79  
    80  	// We need this list to keep the ordering.
    81  	vset := pkz.ToValidators(1, 0)
    82  
    83  	blockID := types.BlockID{
    84  		Hash:        header.Hash(),
    85  		PartsHeader: types.PartSetHeader{Total: 1, Hash: crypto.CRandBytes(32)},
    86  	}
    87  
    88  	// Fill in the votes we want.
    89  	for i := first; i < last && i < len(pkz); i++ {
    90  		vote := makeVote(header, vset, pkz[i], blockID)
    91  		commitSigs[vote.ValidatorIndex] = vote.CommitSig()
    92  	}
    93  
    94  	return types.NewCommit(header.Height, 1, blockID, commitSigs)
    95  }
    96  
    97  func makeVote(header *types.Header, valset *types.ValidatorSet,
    98  	key crypto.PrivKey, blockID types.BlockID) *types.Vote {
    99  
   100  	addr := key.PubKey().Address()
   101  	idx, _ := valset.GetByAddress(addr)
   102  	vote := &types.Vote{
   103  		ValidatorAddress: addr,
   104  		ValidatorIndex:   idx,
   105  		Height:           header.Height,
   106  		Round:            1,
   107  		Timestamp:        tmtime.Now(),
   108  		Type:             types.PrecommitType,
   109  		BlockID:          blockID,
   110  	}
   111  	// Sign it
   112  	signBytes := vote.SignBytes(header.ChainID)
   113  	// TODO Consider reworking makeVote API to return an error
   114  	sig, err := key.Sign(signBytes)
   115  	if err != nil {
   116  		panic(err)
   117  	}
   118  	vote.Signature = sig
   119  
   120  	return vote
   121  }
   122  
   123  func genHeader(chainID string, height int64, bTime time.Time, txs types.Txs,
   124  	valset, nextValset *types.ValidatorSet, appHash, consHash, resHash []byte) *types.Header {
   125  
   126  	return &types.Header{
   127  		ChainID: chainID,
   128  		Height:  height,
   129  		Time:    bTime,
   130  		// LastBlockID
   131  		// LastCommitHash
   132  		ValidatorsHash:     valset.Hash(height),
   133  		NextValidatorsHash: nextValset.Hash(height),
   134  		DataHash:           txs.Hash(height),
   135  		AppHash:            appHash,
   136  		ConsensusHash:      consHash,
   137  		LastResultsHash:    resHash,
   138  		ProposerAddress:    valset.Validators[0].Address,
   139  	}
   140  }
   141  
   142  // GenSignedHeader calls genHeader and signHeader and combines them into a SignedHeader.
   143  func (pkz privKeys) GenSignedHeader(chainID string, height int64, bTime time.Time, txs types.Txs,
   144  	valset, nextValset *types.ValidatorSet, appHash, consHash, resHash []byte, first, last int) *types.SignedHeader {
   145  
   146  	header := genHeader(chainID, height, bTime, txs, valset, nextValset, appHash, consHash, resHash)
   147  	return &types.SignedHeader{
   148  		Header: header,
   149  		Commit: pkz.signHeader(header, first, last),
   150  	}
   151  }
   152  
   153  // GenSignedHeaderLastBlockID calls genHeader and signHeader and combines them into a SignedHeader.
   154  func (pkz privKeys) GenSignedHeaderLastBlockID(chainID string, height int64, bTime time.Time, txs types.Txs,
   155  	valset, nextValset *types.ValidatorSet, appHash, consHash, resHash []byte, first, last int,
   156  	lastBlockID types.BlockID) *types.SignedHeader {
   157  
   158  	header := genHeader(chainID, height, bTime, txs, valset, nextValset, appHash, consHash, resHash)
   159  	header.LastBlockID = lastBlockID
   160  	return &types.SignedHeader{
   161  		Header: header,
   162  		Commit: pkz.signHeader(header, first, last),
   163  	}
   164  }
   165  
   166  func (pkz privKeys) ChangeKeys(delta int) privKeys {
   167  	newKeys := pkz[delta:]
   168  	return newKeys.Extend(delta)
   169  }
   170  
   171  // Generates the header and validator set to create a full entire mock node with blocks to height (
   172  // blockSize) and with variation in validator sets. BlockIntervals are in per minute.
   173  // NOTE: Expected to have a large validator set size ~ 100 validators.
   174  func GenMockNode(
   175  	chainID string,
   176  	blockSize int64,
   177  	valSize int,
   178  	valVariation float32,
   179  	bTime time.Time) (
   180  	string,
   181  	map[int64]*types.SignedHeader,
   182  	map[int64]*types.ValidatorSet) {
   183  
   184  	var (
   185  		headers         = make(map[int64]*types.SignedHeader, blockSize)
   186  		valset          = make(map[int64]*types.ValidatorSet, blockSize)
   187  		keys            = genPrivKeys(valSize)
   188  		totalVariation  = valVariation
   189  		valVariationInt int
   190  		newKeys         privKeys
   191  	)
   192  
   193  	valVariationInt = int(totalVariation)
   194  	totalVariation = -float32(valVariationInt)
   195  	newKeys = keys.ChangeKeys(valVariationInt)
   196  
   197  	// genesis header and vals
   198  	lastHeader := keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Minute), nil,
   199  		keys.ToValidators(2, 2), newKeys.ToValidators(2, 2), hash("app_hash"), hash("cons_hash"),
   200  		hash("results_hash"), 0, len(keys))
   201  	currentHeader := lastHeader
   202  	headers[1] = currentHeader
   203  	valset[1] = keys.ToValidators(2, 2)
   204  	keys = newKeys
   205  
   206  	for height := int64(2); height <= blockSize; height++ {
   207  		totalVariation += valVariation
   208  		valVariationInt = int(totalVariation)
   209  		totalVariation = -float32(valVariationInt)
   210  		newKeys = keys.ChangeKeys(valVariationInt)
   211  		currentHeader = keys.GenSignedHeaderLastBlockID(chainID, height, bTime.Add(time.Duration(height)*time.Minute),
   212  			nil,
   213  			keys.ToValidators(2, 2), newKeys.ToValidators(2, 2), hash("app_hash"), hash("cons_hash"),
   214  			hash("results_hash"), 0, len(keys), types.BlockID{Hash: lastHeader.Hash()})
   215  		headers[height] = currentHeader
   216  		valset[height] = keys.ToValidators(2, 2)
   217  		lastHeader = currentHeader
   218  		keys = newKeys
   219  	}
   220  
   221  	return chainID, headers, valset
   222  }
   223  
   224  func hash(s string) []byte {
   225  	return tmhash.Sum([]byte(s))
   226  }