Skip to content

Commit a1ed5a4

Browse files
committed
extract warn side-effect from ProposalMonitor
1 parent a85368c commit a1ed5a4

3 files changed

Lines changed: 49 additions & 21 deletions

File tree

crates/malachite-app/src/handlers/get_value.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use malachitebft_app_channel::app::types::LocallyProposedValue;
2626
use malachitebft_app_channel::{NetworkMsg, Reply};
2727
use malachitebft_core_types::Validity;
2828

29-
use arc_consensus_types::{Address, ArcContext, Height};
29+
use arc_consensus_types::{Address, ArcContext, Height, ValueId};
3030
use arc_eth_engine::engine::Engine;
3131
use arc_eth_engine::json_structures::ExecutionBlock;
3232
use arc_signer::ArcSigningProvider;
@@ -90,12 +90,7 @@ pub async fn handle(
9090

9191
if let Some(proposed_value) = proposed_value {
9292
if round.as_i64() == 0 {
93-
if let Some(monitor) = &mut state.proposal_monitor {
94-
debug_assert_eq!(monitor.height, height, "proposal monitor height mismatch");
95-
monitor.record_proposal(proposed_value.value.id());
96-
} else {
97-
warn!(%height, %round, "No proposal monitor present");
98-
}
93+
record_self_proposal_in_monitor(state, height, proposed_value.value.id());
9994
}
10095

10196
if let Err(e) = reply.send(proposed_value) {
@@ -308,3 +303,20 @@ async fn get_previously_built_block(
308303
let block = blocks.into_iter().find(|p| p.proposer == proposer);
309304
Ok(block)
310305
}
306+
307+
/// Records the proposed value in the proposal monitor for the given height, if the monitor exists.
308+
fn record_self_proposal_in_monitor(state: &mut State, height: Height, value_id: ValueId) {
309+
let Some(monitor) = &mut state.proposal_monitor else {
310+
warn!(%height, round = 0, "No proposal monitor present");
311+
return;
312+
};
313+
debug_assert_eq!(monitor.height, height, "proposal monitor height mismatch");
314+
if !monitor.record_proposal(value_id) {
315+
warn!(
316+
height = %monitor.height,
317+
first_value = %monitor.value_id.unwrap(),
318+
new_value = %value_id,
319+
"Equivocating proposal at round 0"
320+
);
321+
}
322+
}

crates/malachite-app/src/handlers/received_proposal_part.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,14 @@ fn record_proposal_in_monitor(state: &mut State, proposed_value: &ProposedValue<
128128
return;
129129
}
130130

131-
monitor.record_proposal(proposed_value.value.id());
131+
if !monitor.record_proposal(proposed_value.value.id()) {
132+
warn!(
133+
height = %monitor.height,
134+
first_value = %monitor.value_id.unwrap(),
135+
new_value = %proposed_value.value.id(),
136+
"Equivocating proposal at round 0"
137+
);
138+
}
132139
}
133140

134141
struct HandlerContext<'a, 'b> {

crates/types/src/proposal_monitor.rs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
//! By design, monitoring data is only stored for round-0 proposals.
2828
2929
use std::time::SystemTime;
30-
use tracing::warn;
3130

3231
use crate::{Address, Height, ValueId};
3332

@@ -117,22 +116,16 @@ impl ProposalMonitor {
117116

118117
/// Record that proposal was received.
119118
/// Takes precedence over synced value.
120-
pub fn record_proposal(&mut self, value_id: ValueId) {
121-
// FIXME: this log message should not be produced here.
122-
if let Some(first_value) = self.value_id
123-
&& !self.synced
124-
{
125-
warn!(
126-
height = %self.height,
127-
%first_value,
128-
new_value = %value_id,
129-
"Equivocating proposal at round 0"
130-
);
131-
return;
119+
/// Returns `true` if this is the first proposal recorded,
120+
/// `false` if a previous proposal exist (equivocation).
121+
pub fn record_proposal(&mut self, value_id: ValueId) -> bool {
122+
if self.value_id.is_some() && !self.synced {
123+
return false;
132124
}
133125
self.proposal_receive_time = Some(SystemTime::now());
134126
self.value_id = Some(value_id);
135127
self.synced = false;
128+
true
136129
}
137130

138131
/// Check if the decided value matches the recorded proposal.
@@ -236,6 +229,22 @@ mod tests {
236229
assert_eq!(monitor.value_id, Some(value_id1));
237230
}
238231

232+
#[test]
233+
fn test_record_proposal_duplicate_returns_false() {
234+
let mut monitor = ProposalMonitor::new(Height::new(1), test_address(), SystemTime::now());
235+
236+
let value_id1 = test_value_id(0x11);
237+
assert!(monitor.record_proposal(value_id1));
238+
let time1 = monitor.proposal_receive_time.unwrap();
239+
240+
// Second proposal returns false (equivocation), first value preserved
241+
let value_id2 = test_value_id(0x22);
242+
assert!(!monitor.record_proposal(value_id2));
243+
244+
assert_eq!(monitor.proposal_receive_time, Some(time1));
245+
assert_eq!(monitor.value_id, Some(value_id1));
246+
}
247+
239248
#[test]
240249
fn test_mark_decided_successful() {
241250
let mut monitor = ProposalMonitor::new(Height::new(1), test_address(), SystemTime::now());

0 commit comments

Comments
 (0)