github.com/vipernet-xyz/tm@v0.34.24/light/helpers_test.go (about)

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