diff --git a/bihs_live.go b/bihs_live.go index 8efed7a..47b967a 100644 --- a/bihs_live.go +++ b/bihs_live.go @@ -22,20 +22,20 @@ func (hs *HotStuff) loop() { case proposal := <-hs.proposeCh: if !hs.isLeader(hs.height, hs.view) { - hs.conf.Logger.Errorf("proposer(%s) not in turn, height(%d) view(%d)", hs.conf.ProposerID, hs.height, hs.view) + hs.conf.Logger.Errorf("proposer(%d) tried to propose when not in turn, height(%d) view(%d)", hs.idx, hs.height, hs.view) continue } - if hs.view != 0 { - hs.conf.Logger.Errorf("proposal(%s) Propose not in view 0", hs.conf.ProposerID) + if !hs.conf.Promiscuous && hs.view != 0 { + hs.conf.Logger.Errorf("proposer(%d) tried to propose when not in view 0 in bivalent mode", hs.idx) continue } switch { case proposal.Height() < hs.height: - hs.conf.Logger.Errorf("proposal(%s) Propose height decrease, proposal.height=%d, hs.height=%d", hs.conf.ProposerID, proposal.Height(), hs.height) + hs.conf.Logger.Errorf("proposer(%d) proposal height decrease, proposal.height=%d, hs.height=%d", hs.idx, proposal.Height(), hs.height) continue case proposal.Height() == hs.height: - if hs.candidateBlk != nil { - hs.conf.Logger.Errorf("proposal(%s) Propose twice in the same height, last:%v, current:%v", hs.conf.ProposerID, hs.candidateBlk.Hash(), proposal.Hash()) + if hs.hasVotedPrepare { + hs.conf.Logger.Errorf("proposer(%d) has voted prepare in the current height(%d) and view(%d), last:%v, current:%v", hs.idx, hs.height, hs.view, hs.candidateBlk.Hash(), proposal.Hash()) continue } case proposal.Height() > hs.height: @@ -208,7 +208,7 @@ func (hs *HotStuff) relayPropose() { return } - blk, err := hs.store.EmptyBlock(hs.height) + blk, err := hs.store.MakeBlock(hs.height, !hs.conf.Promiscuous && hs.view > 0) if err != nil { hs.conf.Logger.Errorf("proposer %d EmptyBlock failed:%v", hs.idx, err) return diff --git a/bihs_safe.go b/bihs_safe.go index 9fd463f..db6f4db 100644 --- a/bihs_safe.go +++ b/bihs_safe.go @@ -60,6 +60,11 @@ func (hs *HotStuff) onProposal(blk Block, qc *QC) { hs.p2p.Broadcast(prepareMsg) hs.onRecvPrepareVote(hs.conf.ProposerID, hs.idx, prepareMsg) + + if hs.relayTimer != nil { + hs.relayTimer.Stop() + hs.relayTimer = nil + } } func (hs *HotStuff) onRecvPrepare(sender ID, idx int, msg *Msg) { @@ -74,6 +79,11 @@ func (hs *HotStuff) onRecvPrepare(sender ID, idx int, msg *Msg) { return } + if !bytes.Equal(hs.store.SelectLeader(msg.Node.Blk.Height(), hs.view), sender) { + hs.conf.Logger.Errorf("proposer %s tried to propose when not in turn", sender) + return + } + if msg.Node.Blk.Height() != msg.Height { hs.conf.Logger.Errorf("prepare block height(%d) != msg height(%d)", msg.Node.Blk.Height(), msg.Height) return @@ -83,17 +93,14 @@ func (hs *HotStuff) onRecvPrepare(sender ID, idx int, msg *Msg) { return } - switch { - case msg.View == 0: - if !msg.Node.Blk.Empty() && !bytes.Equal(hs.store.SelectLeader(msg.Node.Blk.Height(), 0), sender) { - hs.conf.Logger.Errorf("proposer %s tried to propose when not in turn", sender) - return - } - case msg.View > 0: - if !msg.Node.Blk.Empty() && msg.Justify == nil { - hs.conf.Logger.Errorf("proposer %s tried to relay propose with no qc", sender) - return + if msg.View > 0 { + if !hs.conf.Promiscuous { + if !msg.Node.Blk.Empty() && msg.Justify == nil { + hs.conf.Logger.Errorf("proposer %s tried to relay propose with no qc when in bivalent mode", sender) + return + } } + if msg.Justify != nil { err := msg.Justify.validate(hs) if err != nil { diff --git a/bihs_test.go b/bihs_test.go index 6ae8aa3..cec10f3 100644 --- a/bihs_test.go +++ b/bihs_test.go @@ -132,7 +132,7 @@ func (db *HappyDB) ValidatorIndex(height uint64, peer ID) int { func (db *HappyDB) SelectLeader(height, view uint64) ID { return ID([]byte(fmt.Sprintf("%d", (height+view)%uint64(db.validators)))) } -func (db *HappyDB) EmptyBlock(height uint64) (Block, error) { +func (db *HappyDB) MakeBlock(height uint64, mustEmpty bool) (Block, error) { b := EmptyBlock(height) return &b, nil } diff --git a/type.go b/type.go index ebd1a1c..48d51f3 100644 --- a/type.go +++ b/type.go @@ -323,10 +323,9 @@ type StateDB interface { Height() uint64 SubscribeHeightChange(HeightChangeSub) UnSubscribeHeightChange(HeightChangeSub) - + MakeBlock(height uint64, mustEmpty bool) (Block, error) ValidatorIndex(height uint64, peer ID) int SelectLeader(height, view uint64) ID - EmptyBlock(height uint64) (Block, error) ValidatorCount(height uint64) int32 ValidatorIDs(height uint64) []ID @@ -361,6 +360,7 @@ type Config struct { BlockInterval time.Duration ProposerID ID DataDir string + Promiscuous bool EcSigner EcSigner BlsSigner BlsSigner