mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-30 03:35:34 +00:00
use correct source of evidence time
Conflicting votes are now sent to the evidence pool to form duplicate vote evidence only once the height of the evidence is finished and the time of the block finalised.
This commit is contained in:
@@ -154,6 +154,72 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// introducing a lazy proposer means that the time of the block committed is different to the
|
||||
// timestamp that the other nodes have. This tests to ensure that the evidence that finally gets
|
||||
// proposed will have a valid timestamp
|
||||
lazyProposer := css[1]
|
||||
|
||||
lazyProposer.decideProposal = func(height int64, round int32) {
|
||||
lazyProposer.Logger.Info("Lazy Proposer proposing condensed commit")
|
||||
if lazyProposer.privValidator == nil {
|
||||
panic("entered createProposalBlock with privValidator being nil")
|
||||
}
|
||||
|
||||
var commit *types.Commit
|
||||
switch {
|
||||
case lazyProposer.Height == lazyProposer.state.InitialHeight:
|
||||
// We're creating a proposal for the first block.
|
||||
// The commit is empty, but not nil.
|
||||
commit = types.NewCommit(0, 0, types.BlockID{}, nil)
|
||||
case lazyProposer.LastCommit.HasTwoThirdsMajority():
|
||||
// Make the commit from LastCommit
|
||||
commit = lazyProposer.LastCommit.MakeCommit()
|
||||
default: // This shouldn't happen.
|
||||
lazyProposer.Logger.Error("enterPropose: Cannot propose anything: No commit for the previous block")
|
||||
return
|
||||
}
|
||||
|
||||
// omit the last signature in the commit
|
||||
commit.Signatures[len(commit.Signatures)-1] = types.NewCommitSigAbsent()
|
||||
|
||||
if lazyProposer.privValidatorPubKey == nil {
|
||||
// If this node is a validator & proposer in the current round, it will
|
||||
// miss the opportunity to create a block.
|
||||
lazyProposer.Logger.Error(fmt.Sprintf("enterPropose: %v", errPubKeyIsNotSet))
|
||||
return
|
||||
}
|
||||
proposerAddr := lazyProposer.privValidatorPubKey.Address()
|
||||
|
||||
block, blockParts := lazyProposer.blockExec.CreateProposalBlock(
|
||||
lazyProposer.Height, lazyProposer.state, commit, proposerAddr,
|
||||
)
|
||||
|
||||
// Flush the WAL. Otherwise, we may not recompute the same proposal to sign,
|
||||
// and the privValidator will refuse to sign anything.
|
||||
if err := lazyProposer.wal.FlushAndSync(); err != nil {
|
||||
lazyProposer.Logger.Error("Error flushing to disk")
|
||||
}
|
||||
|
||||
// Make proposal
|
||||
propBlockID := types.BlockID{Hash: block.Hash(), PartSetHeader: blockParts.Header()}
|
||||
proposal := types.NewProposal(height, round, lazyProposer.ValidRound, propBlockID)
|
||||
p := proposal.ToProto()
|
||||
if err := lazyProposer.privValidator.SignProposal(lazyProposer.state.ChainID, p); err == nil {
|
||||
proposal.Signature = p.Signature
|
||||
|
||||
// send proposal and block parts on internal msg queue
|
||||
lazyProposer.sendInternalMessage(msgInfo{&ProposalMessage{proposal}, ""})
|
||||
for i := 0; i < int(blockParts.Total()); i++ {
|
||||
part := blockParts.GetPart(i)
|
||||
lazyProposer.sendInternalMessage(msgInfo{&BlockPartMessage{lazyProposer.Height, lazyProposer.Round, part}, ""})
|
||||
}
|
||||
lazyProposer.Logger.Info("Signed proposal", "height", height, "round", round, "proposal", proposal)
|
||||
lazyProposer.Logger.Debug(fmt.Sprintf("Signed proposal block: %v", block))
|
||||
} else if !lazyProposer.replayMode {
|
||||
lazyProposer.Logger.Error("enterPropose: Error signing proposal", "height", height, "round", round, "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// start the consensus reactors
|
||||
for i := 0; i < nValidators; i++ {
|
||||
s := reactors[i].conS.GetState()
|
||||
|
||||
+8
-18
@@ -73,9 +73,8 @@ type txNotifier interface {
|
||||
|
||||
// interface to the evidence pool
|
||||
type evidencePool interface {
|
||||
// Adds consensus based evidence to the evidence pool. This function differs to
|
||||
// AddEvidence by bypassing verification and adding it immediately to the pool
|
||||
AddEvidenceFromConsensus(types.Evidence) error
|
||||
// reports conflicting votes to the evidence pool to be processed into evidence
|
||||
ReportConflictingVotes(voteA, voteB *types.Vote)
|
||||
}
|
||||
|
||||
// State handles execution of the consensus algorithm.
|
||||
@@ -1865,21 +1864,12 @@ func (cs *State) tryAddVote(vote *types.Vote, peerID p2p.ID) (bool, error) {
|
||||
vote.Type)
|
||||
return added, err
|
||||
}
|
||||
var timestamp time.Time
|
||||
if voteErr.VoteA.Height == cs.state.InitialHeight {
|
||||
timestamp = cs.state.LastBlockTime // genesis time
|
||||
} else {
|
||||
timestamp = sm.MedianTime(cs.LastCommit.MakeCommit(), cs.LastValidators)
|
||||
}
|
||||
// form duplicate vote evidence from the conflicting votes and send it across to the
|
||||
// evidence pool
|
||||
ev := types.NewDuplicateVoteEvidence(voteErr.VoteA, voteErr.VoteB, timestamp, cs.Validators)
|
||||
evidenceErr := cs.evpool.AddEvidenceFromConsensus(ev)
|
||||
if evidenceErr != nil {
|
||||
cs.Logger.Error("Failed to add evidence to the evidence pool", "err", evidenceErr)
|
||||
} else {
|
||||
cs.Logger.Debug("Added evidence to the evidence pool", "ev", ev)
|
||||
}
|
||||
// report conflicting votes to the evidence pool
|
||||
cs.evpool.ReportConflictingVotes(voteErr.VoteA, voteErr.VoteB)
|
||||
cs.Logger.Info("Found and sent conflicting votes to the evidence pool",
|
||||
"VoteA", voteErr.VoteA,
|
||||
"VoteB", voteErr.VoteB,
|
||||
)
|
||||
return added, err
|
||||
} else if err == types.ErrVoteNonDeterministicSignature {
|
||||
cs.Logger.Debug("Vote has non-deterministic signature", "err", err)
|
||||
|
||||
Reference in New Issue
Block a user