Commit e014eeaa authored by caopingcp's avatar caopingcp Committed by vipwzw

fix qbft vote issue

parent 3d7831eb
...@@ -299,7 +299,15 @@ func (cs *ConsensusState) reconstructLastCommit(state State) { ...@@ -299,7 +299,15 @@ func (cs *ConsensusState) reconstructLastCommit(state State) {
seenCommit := cs.client.csStore.LoadSeenCommit(state.LastBlockHeight) seenCommit := cs.client.csStore.LoadSeenCommit(state.LastBlockHeight)
commit := ttypes.Commit{QbftCommit: seenCommit} commit := ttypes.Commit{QbftCommit: seenCommit}
voteType := byte(commit.VoteType) voteType := byte(commit.VoteType)
lastCommit := ttypes.NewVoteSet(state.ChainID, state.LastBlockHeight, commit.Round(), voteType, state.LastValidators) round := commit.Round()
validators := state.LastValidators
// Increment validators if necessary
if round > 0 {
validators.IncrementAccum(round)
qbftlog.Info("reconstructLastCommit validator change", "round", round,
"proposer", fmt.Sprintf("%X", ttypes.Fingerprint(validators.Proposer.Address)))
}
lastCommit := ttypes.NewVoteSet(state.ChainID, state.LastBlockHeight, round, voteType, validators, state.LastSequence)
if state.LastSequence == 0 { if state.LastSequence == 0 {
if voteType != ttypes.VoteTypePrecommit { if voteType != ttypes.VoteTypePrecommit {
panic("reconstructLastCommit: voteType not Precommit") panic("reconstructLastCommit: voteType not Precommit")
...@@ -391,7 +399,7 @@ func (cs *ConsensusState) updateToState(state State) { ...@@ -391,7 +399,7 @@ func (cs *ConsensusState) updateToState(state State) {
cs.LockedBlock = nil cs.LockedBlock = nil
cs.ValidRound = -1 cs.ValidRound = -1
cs.ValidBlock = nil cs.ValidBlock = nil
cs.Votes = ttypes.NewHeightVoteSet(state.ChainID, height, validators) cs.Votes = ttypes.NewHeightVoteSet(state.ChainID, height, validators, state.Sequence)
cs.CommitRound = -1 cs.CommitRound = -1
cs.LastCommit = lastCommit cs.LastCommit = lastCommit
cs.LastValidators = state.LastValidators cs.LastValidators = state.LastValidators
...@@ -635,6 +643,7 @@ func (cs *ConsensusState) enterNewRound(height int64, round int) { ...@@ -635,6 +643,7 @@ func (cs *ConsensusState) enterNewRound(height int64, round int) {
cs.ProposalBlock = nil cs.ProposalBlock = nil
cs.ProposalBlockHash = nil cs.ProposalBlockHash = nil
} }
cs.Votes.SetValSet(validators)
cs.Votes.SetRound(round + 1) // also track next round (round+1) to allow round-skipping cs.Votes.SetRound(round + 1) // also track next round (round+1) to allow round-skipping
//cs.eventBus.PublishEventNewRound(cs.RoundStateEvent()) //cs.eventBus.PublishEventNewRound(cs.RoundStateEvent())
......
...@@ -26,7 +26,7 @@ import ( ...@@ -26,7 +26,7 @@ import (
) )
const ( const (
qbftVersion = "0.2.0" qbftVersion = "0.2.1"
// DefaultQbftPort 默认端口 // DefaultQbftPort 默认端口
DefaultQbftPort = 33001 DefaultQbftPort = 33001
...@@ -114,7 +114,7 @@ type subConfig struct { ...@@ -114,7 +114,7 @@ type subConfig struct {
MessageInterval int32 `json:"messageInterval"` MessageInterval int32 `json:"messageInterval"`
} }
func applyConfig(sub []byte) { func applyConfig(cfg *types.Consensus, sub []byte) {
var subcfg subConfig var subcfg subConfig
if sub != nil { if sub != nil {
types.MustDecode(sub, &subcfg) types.MustDecode(sub, &subcfg)
...@@ -122,6 +122,9 @@ func applyConfig(sub []byte) { ...@@ -122,6 +122,9 @@ func applyConfig(sub []byte) {
genesis = subcfg.Genesis genesis = subcfg.Genesis
genesisAmount = subcfg.GenesisAmount genesisAmount = subcfg.GenesisAmount
genesisBlockTime = subcfg.GenesisBlockTime genesisBlockTime = subcfg.GenesisBlockTime
if !cfg.Minerstart {
return
}
timeoutTxAvail.Store(subcfg.TimeoutTxAvail) timeoutTxAvail.Store(subcfg.TimeoutTxAvail)
timeoutPropose.Store(subcfg.TimeoutPropose) timeoutPropose.Store(subcfg.TimeoutPropose)
...@@ -182,6 +185,7 @@ func New(cfg *types.Consensus, sub []byte) queue.Module { ...@@ -182,6 +185,7 @@ func New(cfg *types.Consensus, sub []byte) queue.Module {
qbftlog.Info("create qbft client") qbftlog.Info("create qbft client")
genesis = cfg.Genesis genesis = cfg.Genesis
genesisBlockTime = cfg.GenesisBlockTime genesisBlockTime = cfg.GenesisBlockTime
applyConfig(cfg, sub)
if !cfg.Minerstart { if !cfg.Minerstart {
qbftlog.Info("This node only sync block") qbftlog.Info("This node only sync block")
c := drivers.NewBaseClient(cfg) c := drivers.NewBaseClient(cfg)
...@@ -189,7 +193,6 @@ func New(cfg *types.Consensus, sub []byte) queue.Module { ...@@ -189,7 +193,6 @@ func New(cfg *types.Consensus, sub []byte) queue.Module {
c.SetChild(client) c.SetChild(client)
return client return client
} }
applyConfig(sub)
//init rand //init rand
ttypes.Init() ttypes.Init()
...@@ -226,8 +229,8 @@ func New(cfg *types.Consensus, sub []byte) queue.Module { ...@@ -226,8 +229,8 @@ func New(cfg *types.Consensus, sub []byte) queue.Module {
return nil return nil
} }
qbftlog.Info("show qbft info", "sign", ttypes.CryptoName, "useAggSig", UseAggSig(), "genesisFile", genesisFile, qbftlog.Info("show qbft info", "version", qbftVersion, "sign", ttypes.CryptoName, "useAggSig", UseAggSig(),
"privFile", privFile) "genesisFile", genesisFile, "privFile", privFile)
ttypes.InitMessageMap() ttypes.InitMessageMap()
......
...@@ -129,6 +129,7 @@ func (s State) StringIndented(indent string) string { ...@@ -129,6 +129,7 @@ func (s State) StringIndented(indent string) string {
%s LastBlockTotalTx: %v %s LastBlockTotalTx: %v
%s LastBlockID: %X %s LastBlockID: %X
%s Validators: %v %s Validators: %v
%s LastProposer: %v
%s Sequence: %v %s Sequence: %v
%s LastSequence: %v %s LastSequence: %v
%s LastCommitRound: %v %s LastCommitRound: %v
...@@ -138,6 +139,7 @@ func (s State) StringIndented(indent string) string { ...@@ -138,6 +139,7 @@ func (s State) StringIndented(indent string) string {
indent, s.LastBlockTotalTx, indent, s.LastBlockTotalTx,
indent, s.LastBlockID, indent, s.LastBlockID,
indent, s.Validators.StringIndented(indent), indent, s.Validators.StringIndented(indent),
indent, s.LastValidators.GetProposer().String(),
indent, s.Sequence, indent, s.Sequence,
indent, s.LastSequence, indent, s.LastSequence,
indent, s.LastCommitRound, indent, s.LastCommitRound,
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package types package types
import ( import (
"bytes"
"errors" "errors"
"strings" "strings"
"sync" "sync"
...@@ -37,6 +38,7 @@ One for their LastCommit round, and another for the official commit round. ...@@ -37,6 +38,7 @@ One for their LastCommit round, and another for the official commit round.
type HeightVoteSet struct { type HeightVoteSet struct {
chainID string chainID string
height int64 height int64
seq int64
valSet *ValidatorSet valSet *ValidatorSet
mtx sync.Mutex mtx sync.Mutex
...@@ -46,9 +48,10 @@ type HeightVoteSet struct { ...@@ -46,9 +48,10 @@ type HeightVoteSet struct {
} }
// NewHeightVoteSet ... // NewHeightVoteSet ...
func NewHeightVoteSet(chainID string, height int64, valSet *ValidatorSet) *HeightVoteSet { func NewHeightVoteSet(chainID string, height int64, valSet *ValidatorSet, seq int64) *HeightVoteSet {
hvs := &HeightVoteSet{ hvs := &HeightVoteSet{
chainID: chainID, chainID: chainID,
seq: seq,
} }
hvs.Reset(height, valSet) hvs.Reset(height, valSet)
return hvs return hvs
...@@ -82,15 +85,25 @@ func (hvs *HeightVoteSet) Round() int { ...@@ -82,15 +85,25 @@ func (hvs *HeightVoteSet) Round() int {
return hvs.round return hvs.round
} }
// SetValSet update ValidatorSet
func (hvs *HeightVoteSet) SetValSet(valSet *ValidatorSet) {
hvs.mtx.Lock()
defer hvs.mtx.Unlock()
hvs.valSet = valSet
}
// SetRound Create more RoundVoteSets up to round. // SetRound Create more RoundVoteSets up to round.
func (hvs *HeightVoteSet) SetRound(round int) { func (hvs *HeightVoteSet) SetRound(round int) {
hvs.mtx.Lock() hvs.mtx.Lock()
defer hvs.mtx.Unlock() defer hvs.mtx.Unlock()
if hvs.round != 0 && (round < hvs.round+1) { if hvs.round != 0 && (round < hvs.round-1) {
panic(Fmt("Panicked on a Sanity Check: %v", "SetRound() must increment hvs.round")) panic(Fmt("SetRound() must increment hvs.round %v, round %v", hvs.round, round))
}
for r := hvs.round - 1; r <= round; r++ {
if rvs, ok := hvs.roundVoteSets[r]; ok {
if r == round-1 {
hvs.updateValSet(rvs)
} }
for r := hvs.round + 1; r <= round; r++ {
if _, ok := hvs.roundVoteSets[r]; ok {
continue // Already exists because peerCatchupRounds. continue // Already exists because peerCatchupRounds.
} }
hvs.addRound(r) hvs.addRound(r)
...@@ -102,12 +115,24 @@ func (hvs *HeightVoteSet) addRound(round int) { ...@@ -102,12 +115,24 @@ func (hvs *HeightVoteSet) addRound(round int) {
if _, ok := hvs.roundVoteSets[round]; ok { if _, ok := hvs.roundVoteSets[round]; ok {
panic("addRound() for an existing round") panic("addRound() for an existing round")
} }
prevotes := NewVoteSet(hvs.chainID, hvs.height, round, VoteTypePrevote, hvs.valSet) prevotes := NewVoteSet(hvs.chainID, hvs.height, round, VoteTypePrevote, hvs.valSet, hvs.seq)
precommits := NewVoteSet(hvs.chainID, hvs.height, round, VoteTypePrecommit, hvs.valSet) precommits := NewVoteSet(hvs.chainID, hvs.height, round, VoteTypePrecommit, hvs.valSet, hvs.seq)
hvs.roundVoteSets[round] = RoundVoteSet{ hvs.roundVoteSets[round] = RoundVoteSet{
Prevotes: prevotes, Prevotes: prevotes,
Precommits: precommits, Precommits: precommits,
} }
ttlog.Debug("addRound", "round", round, "proposer", hvs.valSet.Proposer.String())
}
func (hvs *HeightVoteSet) updateValSet(rvs RoundVoteSet) {
hvsAddr := hvs.valSet.GetProposer().Address
rvsAddr := rvs.Prevotes.valSet.GetProposer().Address
if !bytes.Equal(hvsAddr, rvsAddr) {
ttlog.Info("update RoundVoteSet proposer", "round", rvs.Prevotes.Round(),
"old", Fmt("%X", Fingerprint(rvsAddr)), "new", Fmt("%X", Fingerprint(hvsAddr)))
rvs.Prevotes.valSet = hvs.valSet
rvs.Precommits.valSet = hvs.valSet
}
} }
// AddVote Duplicate votes return added=false, err=nil. // AddVote Duplicate votes return added=false, err=nil.
......
...@@ -66,7 +66,7 @@ func (v *Validator) String() string { ...@@ -66,7 +66,7 @@ func (v *Validator) String() string {
if v == nil { if v == nil {
return "nil-Validator" return "nil-Validator"
} }
return Fmt("Validator{ADDR:%X PUB:%X VP:%v A:%v}", return Fmt("{ADDR:%X PUB:%X VP:%v A:%v}",
v.Address, v.Address,
v.PubKey, v.PubKey,
v.VotingPower, v.VotingPower,
......
...@@ -56,6 +56,7 @@ type VoteSet struct { ...@@ -56,6 +56,7 @@ type VoteSet struct {
height int64 height int64
round int round int
voteType byte voteType byte
seq int64
mtx sync.Mutex mtx sync.Mutex
valSet *ValidatorSet valSet *ValidatorSet
...@@ -69,7 +70,7 @@ type VoteSet struct { ...@@ -69,7 +70,7 @@ type VoteSet struct {
} }
// NewVoteSet Constructs a new VoteSet struct used to accumulate votes for given height/round. // NewVoteSet Constructs a new VoteSet struct used to accumulate votes for given height/round.
func NewVoteSet(chainID string, height int64, round int, voteType byte, valSet *ValidatorSet) *VoteSet { func NewVoteSet(chainID string, height int64, round int, voteType byte, valSet *ValidatorSet, seq int64) *VoteSet {
if height == 0 { if height == 0 {
PanicSanity("Cannot make VoteSet for height == 0, doesn't make sense.") PanicSanity("Cannot make VoteSet for height == 0, doesn't make sense.")
} }
...@@ -78,6 +79,7 @@ func NewVoteSet(chainID string, height int64, round int, voteType byte, valSet * ...@@ -78,6 +79,7 @@ func NewVoteSet(chainID string, height int64, round int, voteType byte, valSet *
height: height, height: height,
round: round, round: round,
voteType: voteType, voteType: voteType,
seq: seq,
valSet: valSet, valSet: valSet,
votesBitArray: NewBitArray(valSet.Size()), votesBitArray: NewBitArray(valSet.Size()),
votes: make([]*Vote, valSet.Size()), votes: make([]*Vote, valSet.Size()),
...@@ -323,9 +325,8 @@ func (voteSet *VoteSet) AddAggVote(vote *AggVote) (bool, error) { ...@@ -323,9 +325,8 @@ func (voteSet *VoteSet) AddAggVote(vote *AggVote) (bool, error) {
// Ensure that signer is proposer // Ensure that signer is proposer
propAddr := valset.Proposer.Address propAddr := valset.Proposer.Address
if !bytes.Equal(valAddr, propAddr) { if !bytes.Equal(valAddr, propAddr) {
return false, errors.Wrapf(ErrVoteInvalidValidatorAddress, ttlog.Info("odd aggregate vote", "reason",
"aggVote.ValidatorAddress (%X) does not match proposer address (%X)", Fmt("ValidatorAddress: %X; Proposer: %X", Fingerprint(valAddr), Fingerprint(propAddr)))
valAddr, propAddr)
} }
// If we already know of this vote, return false // If we already know of this vote, return false
if voteSet.aggVote != nil { if voteSet.aggVote != nil {
...@@ -536,7 +537,7 @@ func (voteSet *VoteSet) IsCommit() bool { ...@@ -536,7 +537,7 @@ func (voteSet *VoteSet) IsCommit() bool {
if voteSet == nil { if voteSet == nil {
return false return false
} }
if voteSet.voteType != VoteTypePrecommit { if (voteSet.voteType != VoteTypePrevote || voteSet.seq == 0) && voteSet.voteType != VoteTypePrecommit {
return false return false
} }
voteSet.mtx.Lock() voteSet.mtx.Lock()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment