-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
In crates/consensus/src/host.rs, the HostMsg::Decided handler does NOT call self.decision_handler.on_decided(). This means decided Cuts are never persisted, forwarded, or processed.
Location
crates/consensus/src/host.rs:268-316
Code Analysis
HostMsg::Decided {
certificate,
extensions: _,
reply_to,
} => {
let height = certificate.height;
let round = certificate.round;
info!(parent: &self.span, "Consensus decided on value");
// Check for epoch transition
let _epoch_transition = match self.on_block_committed(height) {
// ...
};
// Reply with next height to start
let next_height = height.next();
// ... sends Next::Start ...
// BUG: decision_handler.on_decided() is NEVER CALLED!
}The DecisionHandler trait expects:
async fn on_decided(
&self,
height: ConsensusHeight,
round: ConsensusRound,
value: ConsensusValue, // <-- This is needed
certificate: CommitCertificate<CipherBftContext>,
) -> Result<(), ConsensusError>Root Cause
Two issues compound this bug:
-
Handler never called: The
HostMsg::Decidedhandler simply logs and replies withNext::Startwithout invokingdecision_handler.on_decided() -
Missing value lookup: Even if the handler tried to call
on_decided(), it only hascertificate.value_id- not the actualConsensusValue. The value needs to be looked up fromChannelValueBuilder.cuts_by_value_id.
Impact
- Decided Cuts are lost: The backward-compatible
spawn_host()sends Cuts todecided_tx, but that channel never receives anything - Node loop stalls: In
node.rs:run(), thedecided_rx.recv()branch never triggers - No Cut execution: The execution layer never receives decided Cuts
- State never advances: Block state root is never updated
Suggested Fix
HostMsg::Decided {
certificate,
extensions: _,
reply_to,
} => {
let height = certificate.height;
let round = certificate.round;
let value_id = certificate.value_id.clone();
info!(parent: &self.span, height = height.0, "Consensus decided on value");
// Look up the actual value from value_id
// This requires the value_builder to expose a method to get value by id
// or we need to store proposed values by value_id in the Host
// Call decision handler
if let Err(e) = self.decision_handler.on_decided(
height,
round,
value, // Need to obtain this from value_id lookup
certificate.clone(),
).await {
error!(parent: &self.span, error = %e, "Failed to process decided value");
}
// Check for epoch transition
// ...
}The ChannelValueBuilder already stores cuts by value_id in cuts_by_value_id. A getter method should be added to retrieve the value for the Decided handler.
Severity
Critical - This breaks the entire consensus finalization flow.