mirror of
https://github.com/fluencelabs/tendermint
synced 2025-07-03 22:51:37 +00:00
consensus cleanup, privValidator config
This commit is contained in:
@ -9,12 +9,12 @@ import (
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
type PrivValidator struct {
|
type PrivValidator struct {
|
||||||
state.PrivAccount
|
|
||||||
db db_.DB
|
db db_.DB
|
||||||
|
state.PrivAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPrivValidator(priv *state.PrivAccount, db db_.DB) *PrivValidator {
|
func NewPrivValidator(db db_.DB, priv *state.PrivAccount) *PrivValidator {
|
||||||
return &PrivValidator{*priv, db}
|
return &PrivValidator{db, *priv}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Double signing results in a panic.
|
// Double signing results in a panic.
|
||||||
|
@ -58,14 +58,14 @@ func calcRound(startTime time.Time) uint16 {
|
|||||||
if now.Before(startTime) {
|
if now.Before(startTime) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
// Start + D_0 * R + D_delta * (R^2 - R)/2 <= Now; find largest integer R.
|
// Start + D_0 * R + D_delta * (R^2 - R)/2 <= Now; find largest integer R.
|
||||||
// D_delta * R^2 + (2D_0 - D_delta) * R + 2(Start - Now) <= 0.
|
// D_delta * R^2 + (2D_0 - D_delta) * R + 2(Start - Now) <= 0.
|
||||||
// AR^2 + BR + C <= 0; A = D_delta, B = (2_D0 - D_delta), C = 2(Start - Now).
|
// AR^2 + BR + C <= 0; A = D_delta, B = (2_D0 - D_delta), C = 2(Start - Now).
|
||||||
// R = Floor((-B + Sqrt(B^2 - 4AC))/2A)
|
// R = Floor((-B + Sqrt(B^2 - 4AC))/2A)
|
||||||
A := float64(roundDurationDelta)
|
A := float64(roundDurationDelta)
|
||||||
B := 2.0*float64(roundDuration0) - float64(roundDurationDelta)
|
B := 2.0*float64(roundDuration0) - float64(roundDurationDelta)
|
||||||
C := 2.0 * float64(startTime.Sub(now))
|
C := 2.0 * float64(startTime.Sub(now))
|
||||||
R := math.Floor((-B + math.Sqrt(B*B-4.0*A*C)/(2*A)))
|
R := math.Floor((-B + math.Sqrt(B*B-4.0*A*C)) / (2 * A))
|
||||||
if math.IsNaN(R) {
|
if math.IsNaN(R) {
|
||||||
panic("Could not calc round, should not happen")
|
panic("Could not calc round, should not happen")
|
||||||
}
|
}
|
||||||
@ -300,20 +300,20 @@ func (conR *ConsensusReactor) stepTransitionRoutine() {
|
|||||||
// It's a new RoundState.
|
// It's a new RoundState.
|
||||||
if elapsedRatio < 0 {
|
if elapsedRatio < 0 {
|
||||||
// startTime is in the future.
|
// startTime is in the future.
|
||||||
time.Sleep(time.Duration(-1.0*elapsedRatio) * roundDuration)
|
time.Sleep(time.Duration((-1.0 * elapsedRatio) * float64(roundDuration)))
|
||||||
}
|
}
|
||||||
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPropose}
|
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPropose}
|
||||||
case RoundStepPropose:
|
case RoundStepPropose:
|
||||||
// Wake up when it's time to vote.
|
// Wake up when it's time to vote.
|
||||||
time.Sleep(time.Duration(roundDeadlinePrevote-elapsedRatio) * roundDuration)
|
time.Sleep(time.Duration((roundDeadlinePrevote - elapsedRatio) * float64(roundDuration)))
|
||||||
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPrevote}
|
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPrevote}
|
||||||
case RoundStepPrevote:
|
case RoundStepPrevote:
|
||||||
// Wake up when it's time to precommit.
|
// Wake up when it's time to precommit.
|
||||||
time.Sleep(time.Duration(roundDeadlinePrecommit-elapsedRatio) * roundDuration)
|
time.Sleep(time.Duration((roundDeadlinePrecommit - elapsedRatio) * float64(roundDuration)))
|
||||||
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPrecommit}
|
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPrecommit}
|
||||||
case RoundStepPrecommit:
|
case RoundStepPrecommit:
|
||||||
// Wake up when the round is over.
|
// Wake up when the round is over.
|
||||||
time.Sleep(time.Duration(1.0-elapsedRatio) * roundDuration)
|
time.Sleep(time.Duration((1.0 - elapsedRatio) * float64(roundDuration)))
|
||||||
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionNextRound}
|
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionNextRound}
|
||||||
case RoundStepCommit:
|
case RoundStepCommit:
|
||||||
panic("Should not happen: RoundStepCommit waits until +2/3 commits.")
|
panic("Should not happen: RoundStepCommit waits until +2/3 commits.")
|
||||||
@ -344,6 +344,8 @@ ACTION_LOOP:
|
|||||||
round := roundAction.Round
|
round := roundAction.Round
|
||||||
action := roundAction.Action
|
action := roundAction.Action
|
||||||
rs := conR.conS.GetRoundState()
|
rs := conR.conS.GetRoundState()
|
||||||
|
log.Info("Running round action A:%X %v", action, rs.Description())
|
||||||
|
|
||||||
broadcastNewRoundStep := func(step RoundStep) {
|
broadcastNewRoundStep := func(step RoundStep) {
|
||||||
// Broadcast NewRoundStepMessage
|
// Broadcast NewRoundStepMessage
|
||||||
msg := &NewRoundStepMessage{
|
msg := &NewRoundStepMessage{
|
||||||
@ -379,14 +381,11 @@ ACTION_LOOP:
|
|||||||
if rs.Step >= RoundStepPrevote {
|
if rs.Step >= RoundStepPrevote {
|
||||||
continue ACTION_LOOP
|
continue ACTION_LOOP
|
||||||
}
|
}
|
||||||
hash := conR.conS.RunActionPrevote(rs.Height, rs.Round)
|
vote := conR.conS.RunActionPrevote(rs.Height, rs.Round)
|
||||||
broadcastNewRoundStep(RoundStepPrevote)
|
broadcastNewRoundStep(RoundStepPrevote)
|
||||||
conR.signAndBroadcastVote(rs, &Vote{
|
if vote != nil {
|
||||||
Height: rs.Height,
|
conR.broadcastVote(vote)
|
||||||
Round: rs.Round,
|
}
|
||||||
Type: VoteTypePrevote,
|
|
||||||
BlockHash: hash,
|
|
||||||
})
|
|
||||||
scheduleNextAction()
|
scheduleNextAction()
|
||||||
continue ACTION_LOOP
|
continue ACTION_LOOP
|
||||||
|
|
||||||
@ -394,15 +393,10 @@ ACTION_LOOP:
|
|||||||
if rs.Step >= RoundStepPrecommit {
|
if rs.Step >= RoundStepPrecommit {
|
||||||
continue ACTION_LOOP
|
continue ACTION_LOOP
|
||||||
}
|
}
|
||||||
hash := conR.conS.RunActionPrecommit(rs.Height, rs.Round)
|
vote := conR.conS.RunActionPrecommit(rs.Height, rs.Round)
|
||||||
broadcastNewRoundStep(RoundStepPrecommit)
|
broadcastNewRoundStep(RoundStepPrecommit)
|
||||||
if len(hash) > 0 {
|
if vote != nil {
|
||||||
conR.signAndBroadcastVote(rs, &Vote{
|
conR.broadcastVote(vote)
|
||||||
Height: rs.Height,
|
|
||||||
Round: rs.Round,
|
|
||||||
Type: VoteTypePrecommit,
|
|
||||||
BlockHash: hash,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
scheduleNextAction()
|
scheduleNextAction()
|
||||||
continue ACTION_LOOP
|
continue ACTION_LOOP
|
||||||
@ -420,17 +414,10 @@ ACTION_LOOP:
|
|||||||
continue ACTION_LOOP
|
continue ACTION_LOOP
|
||||||
}
|
}
|
||||||
// NOTE: Duplicated in RoundActionCommitWait.
|
// NOTE: Duplicated in RoundActionCommitWait.
|
||||||
hash := conR.conS.RunActionCommit(rs.Height)
|
vote := conR.conS.RunActionCommit(rs.Height, rs.Round)
|
||||||
if len(hash) > 0 {
|
broadcastNewRoundStep(RoundStepCommit)
|
||||||
broadcastNewRoundStep(RoundStepCommit)
|
if vote != nil {
|
||||||
conR.signAndBroadcastVote(rs, &Vote{
|
conR.broadcastVote(vote)
|
||||||
Height: rs.Height,
|
|
||||||
Round: rs.Round,
|
|
||||||
Type: VoteTypeCommit,
|
|
||||||
BlockHash: hash,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
panic("This shouldn't happen")
|
|
||||||
}
|
}
|
||||||
// do not schedule next action.
|
// do not schedule next action.
|
||||||
continue ACTION_LOOP
|
continue ACTION_LOOP
|
||||||
@ -442,21 +429,14 @@ ACTION_LOOP:
|
|||||||
// Commit first we haven't already.
|
// Commit first we haven't already.
|
||||||
if rs.Step < RoundStepCommit {
|
if rs.Step < RoundStepCommit {
|
||||||
// NOTE: Duplicated in RoundActionCommit.
|
// NOTE: Duplicated in RoundActionCommit.
|
||||||
hash := conR.conS.RunActionCommit(rs.Height)
|
vote := conR.conS.RunActionCommit(rs.Height, rs.Round)
|
||||||
if len(hash) > 0 {
|
broadcastNewRoundStep(RoundStepCommit)
|
||||||
broadcastNewRoundStep(RoundStepCommit)
|
if vote != nil {
|
||||||
conR.signAndBroadcastVote(rs, &Vote{
|
conR.broadcastVote(vote)
|
||||||
Height: rs.Height,
|
|
||||||
Round: rs.Round,
|
|
||||||
Type: VoteTypeCommit,
|
|
||||||
BlockHash: hash,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
panic("This shouldn't happen")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Wait for more commit votes.
|
// Wait for more commit votes.
|
||||||
conR.conS.RunActionCommitWait(rs.Height)
|
conR.conS.RunActionCommitWait(rs.Height, rs.Round)
|
||||||
scheduleNextAction()
|
scheduleNextAction()
|
||||||
continue ACTION_LOOP
|
continue ACTION_LOOP
|
||||||
|
|
||||||
@ -464,7 +444,7 @@ ACTION_LOOP:
|
|||||||
if rs.Step != RoundStepCommitWait {
|
if rs.Step != RoundStepCommitWait {
|
||||||
panic("This shouldn't happen")
|
panic("This shouldn't happen")
|
||||||
}
|
}
|
||||||
conR.conS.RunActionFinalize(rs.Height)
|
conR.conS.RunActionFinalize(rs.Height, rs.Round)
|
||||||
// Height has been incremented, step is now RoundStepStart.
|
// Height has been incremented, step is now RoundStepStart.
|
||||||
scheduleNextAction()
|
scheduleNextAction()
|
||||||
continue ACTION_LOOP
|
continue ACTION_LOOP
|
||||||
@ -478,13 +458,9 @@ ACTION_LOOP:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conR *ConsensusReactor) signAndBroadcastVote(rs *RoundState, vote *Vote) {
|
func (conR *ConsensusReactor) broadcastVote(vote *Vote) {
|
||||||
if rs.PrivValidator != nil {
|
msg := p2p.TypedMessage{msgTypeVote, vote}
|
||||||
rs.PrivValidator.Sign(vote)
|
conR.sw.Broadcast(VoteCh, msg)
|
||||||
conR.conS.AddVote(vote)
|
|
||||||
msg := p2p.TypedMessage{msgTypeVote, vote}
|
|
||||||
conR.sw.Broadcast(VoteCh, msg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
@ -826,7 +802,7 @@ func (m *NewRoundStepMessage) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *NewRoundStepMessage) String() string {
|
func (m *NewRoundStepMessage) String() string {
|
||||||
return fmt.Sprintf("[NewRoundStepMessage H:%v R:%v]", m.Height, m.Round)
|
return fmt.Sprintf("[NewRoundStep %v/%v/%X]", m.Height, m.Round, m.Step)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
@ -22,8 +22,8 @@ const (
|
|||||||
RoundStepPropose = RoundStep(0x01) // Did propose, gossip proposal.
|
RoundStepPropose = RoundStep(0x01) // Did propose, gossip proposal.
|
||||||
RoundStepPrevote = RoundStep(0x02) // Did prevote, gossip prevotes.
|
RoundStepPrevote = RoundStep(0x02) // Did prevote, gossip prevotes.
|
||||||
RoundStepPrecommit = RoundStep(0x03) // Did precommit, gossip precommits.
|
RoundStepPrecommit = RoundStep(0x03) // Did precommit, gossip precommits.
|
||||||
RoundStepCommit = RoundStep(0x04) // Did commit, gossip commits.
|
RoundStepCommit = RoundStep(0x10) // Did commit, gossip commits.
|
||||||
RoundStepCommitWait = RoundStep(0x05) // Found +2/3 commits, wait more.
|
RoundStepCommitWait = RoundStep(0x11) // Found +2/3 commits, wait more.
|
||||||
|
|
||||||
// If a block could not be committed at a given round,
|
// If a block could not be committed at a given round,
|
||||||
// we progress to the next round, skipping RoundStepCommit.
|
// we progress to the next round, skipping RoundStepCommit.
|
||||||
@ -37,9 +37,9 @@ const (
|
|||||||
RoundActionPrevote = RoundActionType(0x01) // Goto RoundStepPrevote
|
RoundActionPrevote = RoundActionType(0x01) // Goto RoundStepPrevote
|
||||||
RoundActionPrecommit = RoundActionType(0x02) // Goto RoundStepPrecommit
|
RoundActionPrecommit = RoundActionType(0x02) // Goto RoundStepPrecommit
|
||||||
RoundActionNextRound = RoundActionType(0x04) // Goto next round RoundStepStart
|
RoundActionNextRound = RoundActionType(0x04) // Goto next round RoundStepStart
|
||||||
RoundActionCommit = RoundActionType(0x05) // Goto RoundStepCommit or RoundStepStart next round
|
RoundActionCommit = RoundActionType(0x10) // Goto RoundStepCommit or RoundStepStart next round
|
||||||
RoundActionCommitWait = RoundActionType(0x06) // Goto RoundStepCommitWait
|
RoundActionCommitWait = RoundActionType(0x11) // Goto RoundStepCommitWait
|
||||||
RoundActionFinalize = RoundActionType(0x07) // Goto RoundStepStart next height
|
RoundActionFinalize = RoundActionType(0x12) // Goto RoundStepStart next height
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -107,10 +107,15 @@ func (rs *RoundState) StringWithIndent(indent string) string {
|
|||||||
indent, rs.Prevotes.StringWithIndent(indent+" "),
|
indent, rs.Prevotes.StringWithIndent(indent+" "),
|
||||||
indent, rs.Precommits.StringWithIndent(indent+" "),
|
indent, rs.Precommits.StringWithIndent(indent+" "),
|
||||||
indent, rs.Commits.StringWithIndent(indent+" "),
|
indent, rs.Commits.StringWithIndent(indent+" "),
|
||||||
indent, rs.LastCommits.StringWithIndent(indent+" "),
|
indent, rs.LastCommits.Description(),
|
||||||
indent)
|
indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rs *RoundState) Description() string {
|
||||||
|
return fmt.Sprintf(`RS{%v/%v/%X %v}`,
|
||||||
|
rs.Height, rs.Round, rs.Step, rs.StartTime)
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
// Tracks consensus state across block heights and rounds.
|
// Tracks consensus state across block heights and rounds.
|
||||||
@ -298,17 +303,21 @@ func (cs *ConsensusState) RunActionPropose(height uint32, round uint16) {
|
|||||||
cs.ProposalPOLPartSet = polPartSet
|
cs.ProposalPOLPartSet = polPartSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ConsensusState) RunActionPrevote(height uint32, round uint16) []byte {
|
func (cs *ConsensusState) RunActionPrevote(height uint32, round uint16) *Vote {
|
||||||
cs.mtx.Lock()
|
cs.mtx.Lock()
|
||||||
defer cs.mtx.Unlock()
|
defer cs.mtx.Unlock()
|
||||||
if cs.Height != height || cs.Round != round {
|
if cs.Height != height || cs.Round != round {
|
||||||
return nil
|
Panicf("RunActionPrevote(%v/%v), expected %v/%v", height, round, cs.Height, cs.Round)
|
||||||
}
|
}
|
||||||
cs.Step = RoundStepPrevote
|
cs.Step = RoundStepPrevote
|
||||||
|
|
||||||
// If a block is locked, prevote that.
|
// If a block is locked, prevote that.
|
||||||
if cs.LockedBlock != nil {
|
if cs.LockedBlock != nil {
|
||||||
return cs.LockedBlock.Hash()
|
return cs.signAddVote(VoteTypePrevote, cs.LockedBlock.Hash())
|
||||||
|
}
|
||||||
|
// If ProposalBlock is nil, prevote nil.
|
||||||
|
if cs.ProposalBlock == nil {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
// Try staging proposed block.
|
// Try staging proposed block.
|
||||||
err := cs.stageBlock(cs.ProposalBlock)
|
err := cs.stageBlock(cs.ProposalBlock)
|
||||||
@ -317,18 +326,18 @@ func (cs *ConsensusState) RunActionPrevote(height uint32, round uint16) []byte {
|
|||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
// Prevote block.
|
// Prevote block.
|
||||||
return cs.ProposalBlock.Hash()
|
return cs.signAddVote(VoteTypePrevote, cs.ProposalBlock.Hash())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock the ProposalBlock if we have enough prevotes for it,
|
// Lock the ProposalBlock if we have enough prevotes for it,
|
||||||
// or unlock an existing lock if +2/3 of prevotes were nil.
|
// or unlock an existing lock if +2/3 of prevotes were nil.
|
||||||
// Returns a blockhash if a block was locked.
|
// Returns a blockhash if a block was locked.
|
||||||
func (cs *ConsensusState) RunActionPrecommit(height uint32, round uint16) []byte {
|
func (cs *ConsensusState) RunActionPrecommit(height uint32, round uint16) *Vote {
|
||||||
cs.mtx.Lock()
|
cs.mtx.Lock()
|
||||||
defer cs.mtx.Unlock()
|
defer cs.mtx.Unlock()
|
||||||
if cs.Height != height || cs.Round != round {
|
if cs.Height != height || cs.Round != round {
|
||||||
return nil
|
Panicf("RunActionPrecommit(%v/%v), expected %v/%v", height, round, cs.Height, cs.Round)
|
||||||
}
|
}
|
||||||
cs.Step = RoundStepPrecommit
|
cs.Step = RoundStepPrecommit
|
||||||
|
|
||||||
@ -352,10 +361,10 @@ func (cs *ConsensusState) RunActionPrecommit(height uint32, round uint16) []byte
|
|||||||
}
|
}
|
||||||
cs.LockedBlock = cs.ProposalBlock
|
cs.LockedBlock = cs.ProposalBlock
|
||||||
cs.LockedBlockPartSet = cs.ProposalBlockPartSet
|
cs.LockedBlockPartSet = cs.ProposalBlockPartSet
|
||||||
return hash
|
return cs.signAddVote(VoteTypePrecommit, hash)
|
||||||
} else if cs.LockedBlock.HashesTo(hash) {
|
} else if cs.LockedBlock.HashesTo(hash) {
|
||||||
// +2/3 prevoted for already locked block
|
// +2/3 prevoted for already locked block
|
||||||
return hash
|
return cs.signAddVote(VoteTypePrecommit, hash)
|
||||||
} else {
|
} else {
|
||||||
// We don't have the block that hashes to hash.
|
// We don't have the block that hashes to hash.
|
||||||
// Unlock if we're locked.
|
// Unlock if we're locked.
|
||||||
@ -373,11 +382,11 @@ func (cs *ConsensusState) RunActionPrecommit(height uint32, round uint16) []byte
|
|||||||
// and returns the committed block.
|
// and returns the committed block.
|
||||||
// Commit is not finalized until FinalizeCommit() is called.
|
// Commit is not finalized until FinalizeCommit() is called.
|
||||||
// This allows us to stay at this height and gather more commits.
|
// This allows us to stay at this height and gather more commits.
|
||||||
func (cs *ConsensusState) RunActionCommit(height uint32) []byte {
|
func (cs *ConsensusState) RunActionCommit(height uint32, round uint16) *Vote {
|
||||||
cs.mtx.Lock()
|
cs.mtx.Lock()
|
||||||
defer cs.mtx.Unlock()
|
defer cs.mtx.Unlock()
|
||||||
if cs.Height != height {
|
if cs.Height != height || cs.Round != round {
|
||||||
return nil
|
Panicf("RunActionCommit(%v/%v), expected %v/%v", height, round, cs.Height, cs.Round)
|
||||||
}
|
}
|
||||||
cs.Step = RoundStepCommit
|
cs.Step = RoundStepCommit
|
||||||
|
|
||||||
@ -424,17 +433,17 @@ func (cs *ConsensusState) RunActionCommit(height uint32) []byte {
|
|||||||
// Update mempool.
|
// Update mempool.
|
||||||
cs.mempool.ResetForBlockAndState(block, cs.stagedState)
|
cs.mempool.ResetForBlockAndState(block, cs.stagedState)
|
||||||
|
|
||||||
return block.Hash()
|
return cs.signAddVote(VoteTypeCommit, block.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ConsensusState) RunActionCommitWait(height uint32) {
|
func (cs *ConsensusState) RunActionCommitWait(height uint32, round uint16) {
|
||||||
cs.mtx.Lock()
|
cs.mtx.Lock()
|
||||||
defer cs.mtx.Unlock()
|
defer cs.mtx.Unlock()
|
||||||
if cs.Height != height {
|
if cs.Height != height || cs.Round != round {
|
||||||
return
|
Panicf("RunActionCommitWait(%v/%v), expected %v/%v", height, round, cs.Height, cs.Round)
|
||||||
}
|
}
|
||||||
cs.Step = RoundStepCommitWait
|
cs.Step = RoundStepCommitWait
|
||||||
|
|
||||||
@ -445,11 +454,11 @@ func (cs *ConsensusState) RunActionCommitWait(height uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ConsensusState) RunActionFinalize(height uint32) {
|
func (cs *ConsensusState) RunActionFinalize(height uint32, round uint16) {
|
||||||
cs.mtx.Lock()
|
cs.mtx.Lock()
|
||||||
defer cs.mtx.Unlock()
|
defer cs.mtx.Unlock()
|
||||||
if cs.Height != height {
|
if cs.Height != height || cs.Round != round {
|
||||||
return
|
Panicf("RunActionFinalize(%v/%v), expected %v/%v", height, round, cs.Height, cs.Round)
|
||||||
}
|
}
|
||||||
|
|
||||||
// What was staged becomes committed.
|
// What was staged becomes committed.
|
||||||
@ -557,6 +566,9 @@ func (cs *ConsensusState) AddVote(vote *Vote) (added bool, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ConsensusState) stageBlock(block *Block) error {
|
func (cs *ConsensusState) stageBlock(block *Block) error {
|
||||||
|
if block == nil {
|
||||||
|
panic("Cannot stage nil block")
|
||||||
|
}
|
||||||
|
|
||||||
// Already staged?
|
// Already staged?
|
||||||
if cs.stagedBlock == block {
|
if cs.stagedBlock == block {
|
||||||
@ -577,3 +589,18 @@ func (cs *ConsensusState) stageBlock(block *Block) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cs *ConsensusState) signAddVote(type_ byte, hash []byte) *Vote {
|
||||||
|
if cs.PrivValidator == nil || !cs.Validators.HasId(cs.PrivValidator.Id) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
vote := &Vote{
|
||||||
|
Height: cs.Height,
|
||||||
|
Round: cs.Round,
|
||||||
|
Type: type_,
|
||||||
|
BlockHash: hash,
|
||||||
|
}
|
||||||
|
cs.PrivValidator.Sign(vote)
|
||||||
|
cs.AddVote(vote)
|
||||||
|
return vote
|
||||||
|
}
|
||||||
|
@ -50,6 +50,15 @@ func makeConsensusState() (*ConsensusState, []*state.PrivAccount) {
|
|||||||
return cs, privAccounts
|
return cs, privAccounts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertPanics(t *testing.T, msg string, f func()) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err == nil {
|
||||||
|
t.Error("Should have panic'd, but didn't. %v", msg)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
func TestSetupRound(t *testing.T) {
|
func TestSetupRound(t *testing.T) {
|
||||||
@ -91,14 +100,9 @@ func TestSetupRound(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup round 1 (should fail)
|
// Setup round 1 (should fail)
|
||||||
{
|
assertPanics(t, "Round did not increment", func() {
|
||||||
defer func() {
|
|
||||||
if e := recover(); e == nil {
|
|
||||||
t.Errorf("Expected to panic, round did not increment")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
cs.SetupRound(1)
|
cs.SetupRound(1)
|
||||||
}
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +117,7 @@ func TestRunActionProposeNoPrivValidator(t *testing.T) {
|
|||||||
|
|
||||||
func TestRunActionPropose(t *testing.T) {
|
func TestRunActionPropose(t *testing.T) {
|
||||||
cs, privAccounts := makeConsensusState()
|
cs, privAccounts := makeConsensusState()
|
||||||
priv := NewPrivValidator(privAccounts[0], db_.NewMemDB())
|
priv := NewPrivValidator(db_.NewMemDB(), privAccounts[0])
|
||||||
cs.SetPrivValidator(priv)
|
cs.SetPrivValidator(priv)
|
||||||
|
|
||||||
cs.RunActionPropose(1, 0)
|
cs.RunActionPropose(1, 0)
|
||||||
@ -147,28 +151,22 @@ func checkRoundState(t *testing.T, cs *ConsensusState,
|
|||||||
|
|
||||||
func TestRunActionPrecommitCommitFinalize(t *testing.T) {
|
func TestRunActionPrecommitCommitFinalize(t *testing.T) {
|
||||||
cs, privAccounts := makeConsensusState()
|
cs, privAccounts := makeConsensusState()
|
||||||
priv := NewPrivValidator(privAccounts[0], db_.NewMemDB())
|
priv := NewPrivValidator(db_.NewMemDB(), privAccounts[0])
|
||||||
cs.SetPrivValidator(priv)
|
cs.SetPrivValidator(priv)
|
||||||
|
|
||||||
blockHash := cs.RunActionPrecommit(1, 0)
|
vote := cs.RunActionPrecommit(1, 0)
|
||||||
if blockHash != nil {
|
if vote != nil {
|
||||||
t.Errorf("RunActionPrecommit should fail without a proposal")
|
t.Errorf("RunActionPrecommit should return nil without a proposal")
|
||||||
}
|
}
|
||||||
|
|
||||||
cs.RunActionPropose(1, 0)
|
cs.RunActionPropose(1, 0)
|
||||||
|
|
||||||
// Test RunActionPrecommit failures:
|
// Test RunActionPrecommit failures:
|
||||||
blockHash = cs.RunActionPrecommit(1, 1)
|
assertPanics(t, "Wrong height ", func() { cs.RunActionPrecommit(2, 0) })
|
||||||
if blockHash != nil {
|
assertPanics(t, "Wrong round", func() { cs.RunActionPrecommit(1, 1) })
|
||||||
t.Errorf("RunActionPrecommit should fail for wrong round")
|
vote = cs.RunActionPrecommit(1, 0)
|
||||||
}
|
if vote != nil {
|
||||||
blockHash = cs.RunActionPrecommit(2, 0)
|
t.Errorf("RunActionPrecommit should return nil, not enough prevotes")
|
||||||
if blockHash != nil {
|
|
||||||
t.Errorf("RunActionPrecommit should fail for wrong height")
|
|
||||||
}
|
|
||||||
blockHash = cs.RunActionPrecommit(1, 0)
|
|
||||||
if blockHash != nil {
|
|
||||||
t.Errorf("RunActionPrecommit should fail, not enough prevotes")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add at least +2/3 prevotes.
|
// Add at least +2/3 prevotes.
|
||||||
@ -184,21 +182,15 @@ func TestRunActionPrecommitCommitFinalize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test RunActionPrecommit success:
|
// Test RunActionPrecommit success:
|
||||||
blockHash = cs.RunActionPrecommit(1, 0)
|
vote = cs.RunActionPrecommit(1, 0)
|
||||||
if len(blockHash) == 0 {
|
if vote == nil {
|
||||||
t.Errorf("RunActionPrecommit should have succeeded")
|
t.Errorf("RunActionPrecommit should have succeeded")
|
||||||
}
|
}
|
||||||
checkRoundState(t, cs, 1, 0, RoundStepPrecommit)
|
checkRoundState(t, cs, 1, 0, RoundStepPrecommit)
|
||||||
|
|
||||||
// Test RunActionCommit failures:
|
// Test RunActionCommit failures:
|
||||||
blockHash = cs.RunActionCommit(2)
|
assertPanics(t, "Wrong height ", func() { cs.RunActionCommit(2, 0) })
|
||||||
if blockHash != nil {
|
assertPanics(t, "Wrong round", func() { cs.RunActionCommit(1, 1) })
|
||||||
t.Errorf("RunActionCommit should fail for wrong height")
|
|
||||||
}
|
|
||||||
blockHash = cs.RunActionCommit(1)
|
|
||||||
if blockHash != nil {
|
|
||||||
t.Errorf("RunActionCommit should fail, not enough commits")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add at least +2/3 precommits.
|
// Add at least +2/3 precommits.
|
||||||
for i := 0; i < 7; i++ {
|
for i := 0; i < 7; i++ {
|
||||||
@ -213,8 +205,8 @@ func TestRunActionPrecommitCommitFinalize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test RunActionCommit success:
|
// Test RunActionCommit success:
|
||||||
blockHash = cs.RunActionCommit(1)
|
vote = cs.RunActionCommit(1, 0)
|
||||||
if len(blockHash) == 0 {
|
if vote == nil {
|
||||||
t.Errorf("RunActionCommit should have succeeded")
|
t.Errorf("RunActionCommit should have succeeded")
|
||||||
}
|
}
|
||||||
checkRoundState(t, cs, 1, 0, RoundStepCommit)
|
checkRoundState(t, cs, 1, 0, RoundStepCommit)
|
||||||
@ -237,13 +229,13 @@ func TestRunActionPrecommitCommitFinalize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test RunActionCommitWait:
|
// Test RunActionCommitWait:
|
||||||
cs.RunActionCommitWait(1)
|
cs.RunActionCommitWait(1, 0)
|
||||||
if cs.CommitTime.IsZero() {
|
if cs.CommitTime.IsZero() {
|
||||||
t.Errorf("Expected CommitTime to have been set")
|
t.Errorf("Expected CommitTime to have been set")
|
||||||
}
|
}
|
||||||
checkRoundState(t, cs, 1, 0, RoundStepCommitWait)
|
checkRoundState(t, cs, 1, 0, RoundStepCommitWait)
|
||||||
|
|
||||||
// Test RunActionFinalize:
|
// Test RunActionFinalize:
|
||||||
cs.RunActionFinalize(1)
|
cs.RunActionFinalize(1, 0)
|
||||||
checkRoundState(t, cs, 2, 0, RoundStepStart)
|
checkRoundState(t, cs, 2, 0, RoundStepStart)
|
||||||
}
|
}
|
||||||
|
@ -238,3 +238,13 @@ func (vs *VoteSet) StringWithIndent(indent string) string {
|
|||||||
indent, vs.votesBitArray,
|
indent, vs.votesBitArray,
|
||||||
indent)
|
indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vs *VoteSet) Description() string {
|
||||||
|
if vs == nil {
|
||||||
|
return "nil-VoteSet"
|
||||||
|
}
|
||||||
|
vs.mtx.Lock()
|
||||||
|
defer vs.mtx.Unlock()
|
||||||
|
return fmt.Sprintf(`VoteSet{H:%v R:%v T:%v %v}`,
|
||||||
|
vs.height, vs.round, vs.type_, vs.votesBitArray)
|
||||||
|
}
|
||||||
|
31
gen_account.go
Normal file
31
gen_account.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// +build gen_account
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/tendermint/tendermint/config"
|
||||||
|
"github.com/tendermint/tendermint/state"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
// Parse config flags
|
||||||
|
config.ParseFlags()
|
||||||
|
|
||||||
|
// Generate private account
|
||||||
|
privAccount := state.GenPrivAccount()
|
||||||
|
|
||||||
|
fmt.Printf(`Generated account:
|
||||||
|
Account Public Key: %X
|
||||||
|
(base64) %v
|
||||||
|
Account Private Key: %X
|
||||||
|
(base64) %v
|
||||||
|
`,
|
||||||
|
privAccount.PubKey,
|
||||||
|
base64.StdEncoding.EncodeToString(privAccount.PubKey),
|
||||||
|
privAccount.PrivKey,
|
||||||
|
base64.StdEncoding.EncodeToString(privAccount.PrivKey))
|
||||||
|
}
|
@ -170,7 +170,7 @@ func (sw *Switch) Broadcast(chId byte, msg Binary) (numSuccess, numFailure int)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("Broadcast on [%X]", chId, msg)
|
log.Debug("[%X] Broadcast: %v", chId, msg)
|
||||||
for _, peer := range sw.peers.List() {
|
for _, peer := range sw.peers.List() {
|
||||||
success := peer.TrySend(chId, msg)
|
success := peer.TrySend(chId, msg)
|
||||||
log.Debug("Broadcast for peer %v success: %v", peer, success)
|
log.Debug("Broadcast for peer %v success: %v", peer, success)
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
. "github.com/tendermint/tendermint/binary"
|
. "github.com/tendermint/tendermint/binary"
|
||||||
. "github.com/tendermint/tendermint/blocks"
|
. "github.com/tendermint/tendermint/blocks"
|
||||||
@ -138,6 +140,24 @@ func GenPrivAccount() *PrivAccount {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The Account.Id is empty since it isn't in the blockchain.
|
||||||
|
func PrivAccountFromJSON(jsonBlob []byte) (privAccount *PrivAccount) {
|
||||||
|
err := json.Unmarshal(jsonBlob, &privAccount)
|
||||||
|
if err != nil {
|
||||||
|
Panicf("Couldn't read PrivAccount: %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Account.Id is empty since it isn't in the blockchain.
|
||||||
|
func PrivAccountFromFile(file string) *PrivAccount {
|
||||||
|
jsonBlob, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
Panicf("Couldn't read PrivAccount from file: %v", err)
|
||||||
|
}
|
||||||
|
return PrivAccountFromJSON(jsonBlob)
|
||||||
|
}
|
||||||
|
|
||||||
func (pa *PrivAccount) SignBytes(msg []byte) Signature {
|
func (pa *PrivAccount) SignBytes(msg []byte) Signature {
|
||||||
signature := crypto.SignMessage(msg, pa.PrivKey, pa.PubKey)
|
signature := crypto.SignMessage(msg, pa.PrivKey, pa.PubKey)
|
||||||
sig := Signature{
|
sig := Signature{
|
||||||
|
@ -16,7 +16,7 @@ type GenesisDoc struct {
|
|||||||
AccountDetails []*AccountDetail
|
AccountDetails []*AccountDetail
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadGenesisDocJSON(jsonBlob []byte) (genState *GenesisDoc) {
|
func GenesisDocFromJSON(jsonBlob []byte) (genState *GenesisDoc) {
|
||||||
err := json.Unmarshal(jsonBlob, &genState)
|
err := json.Unmarshal(jsonBlob, &genState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Panicf("Couldn't read GenesisDoc: %v", err)
|
Panicf("Couldn't read GenesisDoc: %v", err)
|
||||||
@ -29,7 +29,7 @@ func GenesisStateFromFile(db db_.DB, genDocFile string) *State {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
Panicf("Couldn't read GenesisDoc file: %v", err)
|
Panicf("Couldn't read GenesisDoc file: %v", err)
|
||||||
}
|
}
|
||||||
genDoc := ReadGenesisDocJSON(jsonBlob)
|
genDoc := GenesisDocFromJSON(jsonBlob)
|
||||||
return GenesisStateFromDoc(db, genDoc)
|
return GenesisStateFromDoc(db, genDoc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +81,11 @@ func (vset *ValidatorSet) GetById(id uint64) (index uint32, val *Validator) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vset *ValidatorSet) HasId(id uint64) bool {
|
||||||
|
_, val_ := vset.validators.Get(id)
|
||||||
|
return val_ != nil
|
||||||
|
}
|
||||||
|
|
||||||
func (vset *ValidatorSet) GetByIndex(index uint32) (id uint64, val *Validator) {
|
func (vset *ValidatorSet) GetByIndex(index uint32) (id uint64, val *Validator) {
|
||||||
id_, val_ := vset.validators.GetByIndex(uint64(index))
|
id_, val_ := vset.validators.GetByIndex(uint64(index))
|
||||||
id, val = id_.(uint64), val_.(*Validator)
|
id, val = id_.(uint64), val_.(*Validator)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// +build tendermintd
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -20,6 +22,7 @@ type Node struct {
|
|||||||
pexReactor *p2p.PEXReactor
|
pexReactor *p2p.PEXReactor
|
||||||
mempoolReactor *mempool_.MempoolReactor
|
mempoolReactor *mempool_.MempoolReactor
|
||||||
consensusReactor *consensus.ConsensusReactor
|
consensusReactor *consensus.ConsensusReactor
|
||||||
|
privValidator *consensus.PrivValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNode() *Node {
|
func NewNode() *Node {
|
||||||
@ -34,6 +37,14 @@ func NewNode() *Node {
|
|||||||
state = state_.GenesisStateFromFile(stateDB, config.RootDir+"/genesis.json")
|
state = state_.GenesisStateFromFile(stateDB, config.RootDir+"/genesis.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get PrivAccount
|
||||||
|
var privValidator *consensus.PrivValidator
|
||||||
|
if _, err := os.Stat(config.RootDir + "/private.json"); os.IsExist(err) {
|
||||||
|
privAccount := state_.PrivAccountFromFile(config.RootDir + "/private.json")
|
||||||
|
privValidatorDB := db_.NewMemDB() // TODO configurable db.
|
||||||
|
privValidator = consensus.NewPrivValidator(privValidatorDB, privAccount)
|
||||||
|
}
|
||||||
|
|
||||||
// Get PEXReactor
|
// Get PEXReactor
|
||||||
book := p2p.NewAddrBook(config.RootDir + "/addrbook.json")
|
book := p2p.NewAddrBook(config.RootDir + "/addrbook.json")
|
||||||
pexReactor := p2p.NewPEXReactor(book)
|
pexReactor := p2p.NewPEXReactor(book)
|
||||||
@ -44,6 +55,9 @@ func NewNode() *Node {
|
|||||||
|
|
||||||
// Get ConsensusReactor
|
// Get ConsensusReactor
|
||||||
consensusReactor := consensus.NewConsensusReactor(blockStore, mempool, state)
|
consensusReactor := consensus.NewConsensusReactor(blockStore, mempool, state)
|
||||||
|
if privValidator != nil {
|
||||||
|
consensusReactor.SetPrivValidator(privValidator)
|
||||||
|
}
|
||||||
|
|
||||||
sw := p2p.NewSwitch([]p2p.Reactor{pexReactor, mempoolReactor, consensusReactor})
|
sw := p2p.NewSwitch([]p2p.Reactor{pexReactor, mempoolReactor, consensusReactor})
|
||||||
|
|
||||||
@ -53,6 +67,7 @@ func NewNode() *Node {
|
|||||||
pexReactor: pexReactor,
|
pexReactor: pexReactor,
|
||||||
mempoolReactor: mempoolReactor,
|
mempoolReactor: mempoolReactor,
|
||||||
consensusReactor: consensusReactor,
|
consensusReactor: consensusReactor,
|
||||||
|
privValidator: privValidator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue
Block a user