Skip to content

feat(code/engine): Store proposed values in WAL #896

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 48 commits into from
Apr 8, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
4da7504
feat(code/engine): Store locally proposed value in WAL and re-use it …
romac Mar 7, 2025
4065d06
Cleanup
romac Mar 7, 2025
6b70046
Merge all three WalAppend effects into one
romac Mar 7, 2025
b041f19
Cleanup
romac Mar 7, 2025
bf848d0
Merge branch 'main' into romac/wal-proposed-value
romac Mar 27, 2025
9dc0042
Add multi-round test with timeouts
romac Mar 27, 2025
4f201b2
Cleanup
romac Mar 27, 2025
580a450
Add a middleware to the test context to override vote building
romac Mar 27, 2025
d0eb574
Less noisy logs in test app
romac Mar 27, 2025
8e6dd5c
Merge remote-tracking branch 'origin/main' into romac/wal-proposed-value
romac Mar 28, 2025
23ab356
Add concept of middleware to change from the tests how votes and prop…
romac Mar 28, 2025
fb33d28
Merge remote-tracking branch 'origin/main' into romac/wal-proposed-value
romac Mar 28, 2025
1fe7b38
Deduplicate timeout elapsed code
romac Mar 28, 2025
a9f73f0
Replay proposed values before other entries
romac Mar 28, 2025
091c277
Split `StartHeight` into `PrepareHeight` and `StartHeight`
romac Mar 25, 2025
cf49f0e
Add check that we are in the right state before starting a height
romac Mar 25, 2025
fd34681
Actually replay the proposed values
romac Mar 28, 2025
2649113
Cleanup
romac Mar 28, 2025
f2462b0
Store proposed values for other rounds
romac Mar 28, 2025
254b9c5
Better naming
romac Mar 28, 2025
e0ccb97
Replay locally proposed value as an `ProposedValue` input instead of …
romac Mar 28, 2025
434cc37
Fix unused variable warning
romac Mar 31, 2025
0267c25
Merge branch 'main' into romac/wal-proposed-value
romac Apr 1, 2025
b142a49
Replay proposals
romac Apr 2, 2025
8416236
On GetValue output from the driver, re-use any full proposal proposed…
romac Apr 2, 2025
62019c9
Remove outdated check in Starknet tests
romac Apr 2, 2025
81d7709
Merge branch 'main' into romac/wal-proposed-value
romac Apr 2, 2025
9965158
Cleanup
romac Apr 2, 2025
2fce398
Merge branch 'main' into romac/wal-proposed-value
romac Apr 3, 2025
1debb22
Simplify WAL replay
romac Apr 3, 2025
7e1fda6
Re-enable checks in byzantine WAL tests
romac Apr 3, 2025
ed8554b
Cleanup
romac Apr 3, 2025
eb9c5dc
Cleanup protos
romac Apr 3, 2025
d426a5f
Replay ProposedValue exactly as stored in the WAL
ancazamfir Apr 3, 2025
cb696f6
Log proposed values to WAL only if not already seen and therefore
ancazamfir Apr 4, 2025
1868db0
Fix issue with last commit, store proposed values before getting the
ancazamfir Apr 4, 2025
66e7ca5
Fix comments
romac Apr 7, 2025
25c37a6
Ensure all timeouts can be decoded
romac Apr 7, 2025
130008a
Re-add check that was previously removed when we were replaying WAL b…
romac Apr 7, 2025
8f9679f
Merge `WalReplay` events into one
romac Apr 7, 2025
f3e06a9
Review comments
ancazamfir Apr 7, 2025
f92b07f
Apply suggestions from code review
ancazamfir Apr 7, 2025
adecaf7
Apply suggestions from code review
ancazamfir Apr 7, 2025
9d7ce77
Add comments to handler functions
ancazamfir Apr 7, 2025
6035541
Add comments to on_propose handler
ancazamfir Apr 7, 2025
a960ae4
Add encode and decode functions for all wal entries
ancazamfir Apr 7, 2025
31a926f
Merge branch 'main' into romac/wal-proposed-value
romac Apr 8, 2025
f631c01
Apply suggestion from code review
romac Apr 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions code/crates/core-consensus/src/full_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ impl<Ctx: Context> Entry<Ctx> {
fn full(value: Ctx::Value, validity: Validity, proposal: SignedProposal<Ctx>) -> Self {
Entry::Full(FullProposal::new(value, validity, proposal))
}

fn id(&self) -> Option<<Ctx::Value as Value>::Id> {
match self {
Entry::Full(p) => Some(p.builder_value.id()),
Entry::ProposalOnly(p) => Some(p.value().id()),
Entry::ValueOnly(v, _) => Some(v.id()),
Entry::Empty => None,
}
}
}

#[allow(clippy::derivable_impls)]
Expand Down Expand Up @@ -289,6 +298,15 @@ impl<Ctx: Context> FullProposalKeeper<Ctx> {
self.store_value_at_pol_round(new_value);
}

pub fn value_exists(&self, value: &ProposedValue<Ctx>) -> bool {
match self.keeper.get(&(value.height, value.round)) {
None => false,
Some(entries) => entries
.iter()
.any(|entry| entry.id() == Some(value.value.id())),
}
}

fn store_value_at_value_round(&mut self, new_value: &ProposedValue<Ctx>) {
let key = (new_value.height, new_value.round);
let entries = self.keeper.get_mut(&key);
Expand Down
18 changes: 12 additions & 6 deletions code/crates/core-consensus/src/handle/propose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,21 @@ where
validity: Validity::Valid,
};

state.store_value(&proposed_value);

#[cfg(feature = "metrics")]
metrics.consensus_start();

perform!(
co,
Effect::WalAppend(WalEntry::ProposedValue(proposed_value), Default::default())
);
// If this is the first time we see this value, append it to the WAL
if !state.value_exists(&proposed_value) {
perform!(
co,
Effect::WalAppend(
WalEntry::ProposedValue(proposed_value.clone()),
Default::default()
)
);
}

state.store_value(&proposed_value);

apply_driver_input(
co,
Expand Down
19 changes: 12 additions & 7 deletions code/crates/core-consensus/src/handle/proposed_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ where
return Ok(());
}

state.store_value(&proposed_value);

// There are two cases where we need to generate an internal Proposal message for consensus to process the full proposal:
// a) In parts-only mode, where we do not get a Proposal message but only the proposal parts
// b) In any mode if the proposed value was provided by Sync, where we do net get a Proposal message but only the full value and the certificate
Expand All @@ -57,11 +55,18 @@ where
let validity = proposed_value.validity;
let proposals = state.proposals_for_value(&proposed_value);

// Append the proposed value to the WAL, so it can be used for recovery.
perform!(
co,
Effect::WalAppend(WalEntry::ProposedValue(proposed_value), Default::default())
);
// If this is the first time we see this value, append it to the WAL, so it can be used for recovery.
if !state.value_exists(&proposed_value) {
perform!(
co,
Effect::WalAppend(
WalEntry::ProposedValue(proposed_value.clone()),
Default::default()
)
);
}

state.store_value(&proposed_value);

for signed_proposal in proposals {
debug!(
Expand Down
4 changes: 4 additions & 0 deletions code/crates/core-consensus/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ where
self.full_proposal_keeper.store_proposal(new_proposal)
}

pub fn value_exists(&mut self, new_value: &ProposedValue<Ctx>) -> bool {
self.full_proposal_keeper.value_exists(new_value)
}

pub fn store_value(&mut self, new_value: &ProposedValue<Ctx>) {
// Values for higher height should have been cached for future processing
assert_eq!(new_value.height, self.driver.height());
Expand Down
Loading