From b9c091c5d007a58bc93653b476be3185e145c7d9 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Mon, 24 Oct 2022 04:48:17 -0400 Subject: [PATCH] When resetting, use the end time of the round which was committed to The machine reset to the end time of the current round. For a delayed network connection, a machine may move ahead in rounds and only later realize a prior round succeeded. Despite acknowledging that round's success, it would maintain its delay when moving to the next block, bricking it. Done by tracking the end time for each round as they occur. --- substrate/tendermint/src/lib.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/substrate/tendermint/src/lib.rs b/substrate/tendermint/src/lib.rs index 56dea0c3..f9b9de56 100644 --- a/substrate/tendermint/src/lib.rs +++ b/substrate/tendermint/src/lib.rs @@ -105,6 +105,7 @@ pub struct TendermintMachine { log: MessageLog, round: Round, + end_time: HashMap, step: Step, locked: Option<(Round, ::Id)>, @@ -169,8 +170,10 @@ impl TendermintMachine { fn round(&mut self, round: Round) -> bool { // Correct the start time - for _ in self.round.0 .. round.0 { - self.start_time = self.timeout(Step::Precommit); + for r in self.round.0 .. round.0 { + let end = self.timeout(Step::Precommit); + self.end_time.insert(Round(r), end); + self.start_time = end; } // 11-13 @@ -178,15 +181,16 @@ impl TendermintMachine { self.timeouts = HashMap::new(); self.round = round; + self.end_time.insert(round, self.timeout(Step::Precommit)); self.step = Step::Propose; self.round_propose() } // 53-54 - async fn reset(&mut self, proposal: N::Block) { + async fn reset(&mut self, end_round: Round, proposal: N::Block) { // Wait for the next block interval - let round_end = self.timeout(Step::Precommit); - sleep(round_end - Instant::now()).await; + let round_end = self.end_time[&end_round]; + sleep(round_end.saturating_duration_since(Instant::now())).await; self.number.0 += 1; self.start_time = round_end; @@ -195,6 +199,7 @@ impl TendermintMachine { self.queue = self.queue.drain(..).filter(|msg| msg.1.number == self.number).collect(); self.log = MessageLog::new(self.network.read().await.weights()); + self.end_time = HashMap::new(); self.locked = None; self.valid = None; @@ -241,6 +246,7 @@ impl TendermintMachine { log: MessageLog::new(weights), round: Round(0), + end_time: HashMap::new(), step: Step::Propose, locked: None, @@ -319,7 +325,7 @@ impl TendermintMachine { debug_assert!(machine.network.read().await.verify_commit(block.id(), &commit)); let proposal = machine.network.write().await.add_block(block, commit).await; - machine.reset(proposal).await; + machine.reset(msg.round, proposal).await; } Err(TendermintError::Malicious(validator)) => { machine.network.write().await.slash(validator).await;