val set changes

This commit is contained in:
Ethan Buchman
2016-11-19 19:32:35 -05:00
parent d7f6c0775a
commit 655b6300f5
7 changed files with 77 additions and 20 deletions

View File

@@ -236,6 +236,7 @@ FOR_LOOP:
} else {
bcR.pool.PopRequest()
// TODO: use ApplyBlock instead of Exec/Commit/SetAppHash/Save
// TODO: should we be firing events? need to fire NewBlock events manually ...
err := bcR.state.ExecBlock(bcR.evsw, bcR.proxyAppConn, first, firstPartsHeader)
if err != nil {
// TODO This is bad, are we zombie?

View File

@@ -163,6 +163,7 @@ func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, s
bs.db.Set(calcBlockCommitKey(height-1), blockCommitBytes)
// Save seen commit (seen +2/3 precommits for block)
// NOTE: we can delete this at a later height
seenCommitBytes := wire.BinaryBytes(seenCommit)
bs.db.Set(calcSeenCommitKey(height), seenCommitBytes)

View File

@@ -1263,6 +1263,8 @@ func (cs *ConsensusState) finalizeCommit(height int) {
// Save to blockStore.
if cs.blockStore.Height() < block.Height {
// NOTE: the seenCommit is local justification to commit this block,
// but may differ from the LastCommit included in the next block
precommits := cs.Votes.Precommits(cs.CommitRound)
seenCommit := precommits.MakeCommit()
cs.blockStore.SaveBlock(block, blockParts, seenCommit)

View File

@@ -8,6 +8,7 @@ import (
. "github.com/tendermint/go-common"
cfg "github.com/tendermint/go-config"
"github.com/tendermint/go-crypto"
"github.com/tendermint/tendermint/proxy"
"github.com/tendermint/tendermint/types"
tmsp "github.com/tendermint/tmsp/types"
@@ -21,28 +22,32 @@ import (
func (s *State) ExecBlock(eventCache types.Fireable, proxyAppConn proxy.AppConnConsensus, block *types.Block, blockPartsHeader types.PartSetHeader) error {
// Validate the block.
err := s.validateBlock(block)
if err != nil {
if err := s.validateBlock(block); err != nil {
return ErrInvalidBlock(err)
}
// Update the validator set
valSet := s.Validators.Copy()
// Update valSet with signatures from block.
// compute bitarray of validators that signed
signed := commitBitArrayFromBlock(block)
_ = signed // TODO
_ = signed // TODO send on begin block
// TODO: Update the validator set (e.g. block.Data.ValidatorUpdates?)
// copy the valset
valSet := s.Validators.Copy()
nextValSet := valSet.Copy()
// Execute the block txs
err = s.execBlockOnProxyApp(eventCache, proxyAppConn, block)
changedValidators, err := execBlockOnProxyApp(eventCache, proxyAppConn, block)
if err != nil {
// There was some error in proxyApp
// TODO Report error and wait for proxyApp to be available.
return ErrProxyAppConn(err)
}
// update the validator set
if err := updateValidators(nextValSet, changedValidators); err != nil {
log.Warn("Error changing validator set", "error", err)
// TODO: err or carry on?
}
// All good!
// Update validator accums and set state variables
nextValSet.IncrementAccum(1)
@@ -56,8 +61,9 @@ func (s *State) ExecBlock(eventCache types.Fireable, proxyAppConn proxy.AppConnC
}
// Executes block's transactions on proxyAppConn.
// Returns a list of updates to the validator set
// TODO: Generate a bitmap or otherwise store tx validity in state.
func (s *State) execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn proxy.AppConnConsensus, block *types.Block) error {
func execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn proxy.AppConnConsensus, block *types.Block) ([]*tmsp.Validator, error) {
var validTxs, invalidTxs = 0, 0
@@ -96,7 +102,7 @@ func (s *State) execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn prox
err := proxyAppConn.BeginBlockSync(block.Hash(), types.TM2PB.Header(block.Header))
if err != nil {
log.Warn("Error in proxyAppConn.BeginBlock", "error", err)
return err
return nil, err
}
fail.Fail() // XXX
@@ -106,7 +112,7 @@ func (s *State) execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn prox
fail.FailRand(len(block.Txs)) // XXX
proxyAppConn.AppendTxAsync(tx)
if err := proxyAppConn.Error(); err != nil {
return err
return nil, err
}
}
@@ -116,15 +122,53 @@ func (s *State) execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn prox
changedValidators, err := proxyAppConn.EndBlockSync(uint64(block.Height))
if err != nil {
log.Warn("Error in proxyAppConn.EndBlock", "error", err)
return err
return nil, err
}
fail.Fail() // XXX
// TODO: Do something with changedValidators
log.Debug("TODO: Do something with changedValidators", "changedValidators", changedValidators)
log.Info(Fmt("ExecBlock got %v valid txs and %v invalid txs", validTxs, invalidTxs))
return changedValidators, nil
}
func updateValidators(validators *types.ValidatorSet, changedValidators []*tmsp.Validator) error {
// TODO: prevent change of 1/3+ at once
for _, v := range changedValidators {
pubkey, err := crypto.PubKeyFromBytes(v.PubKey) // NOTE: expects go-wire encoded pubkey
if err != nil {
return err
}
address := pubkey.Address()
power := int64(v.Power)
// mind the overflow from uint64
if power < 0 {
return errors.New(Fmt("Power (%d) overflows int64", v.Power))
}
_, val := validators.GetByAddress(address)
if val == nil {
// add val
added := validators.Add(types.NewValidator(pubkey, power))
if !added {
return errors.New(Fmt("Failed to add new validator %X with voting power %d", address, power))
}
} else if v.Power == 0 {
// remove val
_, removed := validators.Remove(address)
if !removed {
return errors.New(Fmt("Failed to remove validator %X)"))
}
} else {
// update val
val.VotingPower = power
updated := validators.Update(val)
if !updated {
return errors.New(Fmt("Failed to update validator %X with voting power %d", address, power))
}
}
}
return nil
}

View File

@@ -34,7 +34,7 @@ type State struct {
LastBlockID types.BlockID
LastBlockTime time.Time
Validators *types.ValidatorSet
LastValidators *types.ValidatorSet
LastValidators *types.ValidatorSet // block.LastCommit validated against this
// AppHash is updated after Commit;
// it's stale after ExecBlock and before Commit

View File

@@ -154,10 +154,10 @@ type Header struct {
Time time.Time `json:"time"`
NumTxs int `json:"num_txs"`
LastBlockID BlockID `json:"last_block_id"`
LastCommitHash []byte `json:"last_commit_hash"`
DataHash []byte `json:"data_hash"`
ValidatorsHash []byte `json:"validators_hash"`
AppHash []byte `json:"app_hash"` // state merkle root of txs from the previous block
LastCommitHash []byte `json:"last_commit_hash"` // commit from validators from the last block
ValidatorsHash []byte `json:"validators_hash"` // validators for the current block
DataHash []byte `json:"data_hash"` // transactions
AppHash []byte `json:"app_hash"` // state after txs from the previous block
}
// NOTE: hash is nil if required fields are missing.

View File

@@ -20,6 +20,15 @@ type Validator struct {
Accum int64 `json:"accum"`
}
func NewValidator(pubKey crypto.PubKey, votingPower int64) *Validator {
return &Validator{
Address: pubKey.Address(),
PubKey: pubKey,
VotingPower: votingPower,
Accum: 0,
}
}
// Creates a new copy of the validator so we can mutate accum.
// Panics if the validator is nil.
func (v *Validator) Copy() *Validator {