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:
Callum
2021-01-19 16:00:02 +01:00
committed by Tess Rinearson
parent 7ea4dc52ed
commit a2a6852ab9
7 changed files with 205 additions and 96 deletions
+66
View File
@@ -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
View File
@@ -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)