Refactor "lite" to handle delayed validator set changes.

Also, fix consensus liveness issue.
This commit is contained in:
Jae Kwon
2018-06-09 04:25:48 -07:00
parent a5b7ea93c4
commit bf0ff212b9
55 changed files with 1542 additions and 2449 deletions

View File

@ -4,24 +4,21 @@ import (
"time"
crypto "github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/types"
)
// ValKeys is a helper for testing.
// privKeys is a helper type for testing.
//
// It lets us simulate signing with many keys, either ed25519 or secp256k1.
// The main use case is to create a set, and call GenCommit
// to get properly signed header for testing.
// It lets us simulate signing with many keys. The main use case is to create
// a set, and call GenSignedHeader to get properly signed header for testing.
//
// You can set different weights of validators each time you call
// ToValidators, and can optionally extend the validator set later
// with Extend or ExtendSecp
type ValKeys []crypto.PrivKey
// You can set different weights of validators each time you call ToValidators,
// and can optionally extend the validator set later with Extend.
type privKeys []crypto.PrivKey
// GenValKeys produces an array of private keys to generate commits.
func GenValKeys(n int) ValKeys {
res := make(ValKeys, n)
// genPrivKeys produces an array of private keys to generate commits.
func genPrivKeys(n int) privKeys {
res := make(privKeys, n)
for i := range res {
res[i] = crypto.GenPrivKeyEd25519()
}
@ -29,56 +26,41 @@ func GenValKeys(n int) ValKeys {
}
// Change replaces the key at index i.
func (v ValKeys) Change(i int) ValKeys {
res := make(ValKeys, len(v))
copy(res, v)
func (pkz privKeys) Change(i int) privKeys {
res := make(privKeys, len(pkz))
copy(res, pkz)
res[i] = crypto.GenPrivKeyEd25519()
return res
}
// Extend adds n more keys (to remove, just take a slice).
func (v ValKeys) Extend(n int) ValKeys {
extra := GenValKeys(n)
return append(v, extra...)
func (pkz privKeys) Extend(n int) privKeys {
extra := genPrivKeys(n)
return append(pkz, extra...)
}
// GenSecpValKeys produces an array of secp256k1 private keys to generate commits.
func GenSecpValKeys(n int) ValKeys {
res := make(ValKeys, n)
for i := range res {
res[i] = crypto.GenPrivKeySecp256k1()
}
return res
}
// ExtendSecp adds n more secp256k1 keys (to remove, just take a slice).
func (v ValKeys) ExtendSecp(n int) ValKeys {
extra := GenSecpValKeys(n)
return append(v, extra...)
}
// ToValidators produces a list of validators from the set of keys
// ToValidators produces a valset from the set of keys.
// The first key has weight `init` and it increases by `inc` every step
// so we can have all the same weight, or a simple linear distribution
// (should be enough for testing).
func (v ValKeys) ToValidators(init, inc int64) *types.ValidatorSet {
res := make([]*types.Validator, len(v))
for i, k := range v {
func (pkz privKeys) ToValidators(init, inc int64) *types.ValidatorSet {
res := make([]*types.Validator, len(pkz))
for i, k := range pkz {
res[i] = types.NewValidator(k.PubKey(), init+int64(i)*inc)
}
return types.NewValidatorSet(res)
}
// signHeader properly signs the header with all keys from first to last exclusive.
func (v ValKeys) signHeader(header *types.Header, first, last int) *types.Commit {
votes := make([]*types.Vote, len(v))
func (pkz privKeys) signHeader(header *types.Header, first, last int) *types.Commit {
votes := make([]*types.Vote, len(pkz))
// we need this list to keep the ordering...
vset := v.ToValidators(1, 0)
// We need this list to keep the ordering.
vset := pkz.ToValidators(1, 0)
// fill in the votes we want
for i := first; i < last && i < len(v); i++ {
vote := makeVote(header, vset, v[i])
// Fill in the votes we want.
for i := first; i < last && i < len(pkz); i++ {
vote := makeVote(header, vset, pkz[i])
votes[vote.ValidatorIndex] = vote
}
@ -89,15 +71,15 @@ func (v ValKeys) signHeader(header *types.Header, first, last int) *types.Commit
return res
}
func makeVote(header *types.Header, vals *types.ValidatorSet, key crypto.PrivKey) *types.Vote {
func makeVote(header *types.Header, valset *types.ValidatorSet, key crypto.PrivKey) *types.Vote {
addr := key.PubKey().Address()
idx, _ := vals.GetByAddress(addr)
idx, _ := valset.GetByAddress(addr)
vote := &types.Vote{
ValidatorAddress: addr,
ValidatorIndex: idx,
Height: header.Height,
Round: 1,
Timestamp: time.Now().UTC(),
Timestamp: time.Now().Round(0).UTC(),
Type: types.VoteTypePrecommit,
BlockID: types.BlockID{Hash: header.Hash()},
}
@ -113,47 +95,46 @@ func makeVote(header *types.Header, vals *types.ValidatorSet, key crypto.PrivKey
return vote
}
// Silences warning that vals can also be merkle.Hashable
// nolint: interfacer
func genHeader(chainID string, height int64, txs types.Txs,
vals *types.ValidatorSet, appHash, consHash, resHash []byte) *types.Header {
valset, nvalset *types.ValidatorSet, appHash, consHash, resHash []byte) *types.Header {
return &types.Header{
ChainID: chainID,
Height: height,
Time: time.Now(),
Time: time.Now().Round(0).UTC(),
NumTxs: int64(len(txs)),
TotalTxs: int64(len(txs)),
// LastBlockID
// LastCommitHash
ValidatorsHash: vals.Hash(),
DataHash: txs.Hash(),
AppHash: appHash,
ConsensusHash: consHash,
LastResultsHash: resHash,
ValidatorsHash: valset.Hash(),
NextValidatorsHash: nvalset.Hash(),
DataHash: txs.Hash(),
AppHash: appHash,
ConsensusHash: consHash,
LastResultsHash: resHash,
}
}
// GenCommit calls genHeader and signHeader and combines them into a Commit.
func (v ValKeys) GenCommit(chainID string, height int64, txs types.Txs,
vals *types.ValidatorSet, appHash, consHash, resHash []byte, first, last int) Commit {
// GenSignedHeader calls genHeader and signHeader and combines them into a SignedHeader.
func (pkz privKeys) GenSignedHeader(chainID string, height int64, txs types.Txs,
valset, nvalset *types.ValidatorSet, appHash, consHash, resHash []byte, first, last int) types.SignedHeader {
header := genHeader(chainID, height, txs, vals, appHash, consHash, resHash)
check := Commit{
header := genHeader(chainID, height, txs, valset, nvalset, appHash, consHash, resHash)
check := types.SignedHeader{
Header: header,
Commit: v.signHeader(header, first, last),
Commit: pkz.signHeader(header, first, last),
}
return check
}
// GenFullCommit calls genHeader and signHeader and combines them into a Commit.
func (v ValKeys) GenFullCommit(chainID string, height int64, txs types.Txs,
vals *types.ValidatorSet, appHash, consHash, resHash []byte, first, last int) FullCommit {
// GenFullCommit calls genHeader and signHeader and combines them into a FullCommit.
func (pkz privKeys) GenFullCommit(chainID string, height int64, txs types.Txs,
valset, nvalset *types.ValidatorSet, appHash, consHash, resHash []byte, first, last int) FullCommit {
header := genHeader(chainID, height, txs, vals, appHash, consHash, resHash)
commit := Commit{
header := genHeader(chainID, height, txs, valset, nvalset, appHash, consHash, resHash)
commit := types.SignedHeader{
Header: header,
Commit: v.signHeader(header, first, last),
Commit: pkz.signHeader(header, first, last),
}
return NewFullCommit(commit, vals)
return NewFullCommit(commit, valset, nvalset)
}