Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion consensus/src/aggregation/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,7 @@ impl<
let mut automaton = self.automaton.clone();
let timer = self.metrics.digest_duration.timer(self.context.as_ref());
self.digest_requests.push(async move {
let receiver = automaton.propose(height).await;
let receiver = automaton.propose(height, Arc::from([])).await;
let result = receiver.await.map_err(Error::AppProposeCanceled);
DigestRequest {
height,
Expand Down
8 changes: 7 additions & 1 deletion consensus/src/aggregation/mocks/application.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{Automaton as A, types::Height};
use commonware_cryptography::{Hasher, Sha256};
use commonware_utils::channel::oneshot;
use std::sync::Arc;
use tracing::trace;

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -30,7 +31,11 @@ impl A for Application {
type Context = Height;
type Digest = <Sha256 as Hasher>::Digest;

async fn propose(&mut self, context: Self::Context) -> oneshot::Receiver<Self::Digest> {
async fn propose(
&mut self,
context: Self::Context,
_ancestry: Arc<[Self::Digest]>,
) -> oneshot::Receiver<Self::Digest> {
let (sender, receiver) = oneshot::channel();

let digest = match &self.strategy {
Expand All @@ -56,6 +61,7 @@ impl A for Application {
&mut self,
context: Self::Context,
payload: Self::Digest,
_ancestry: Arc<[Self::Digest]>,
) -> oneshot::Receiver<bool> {
trace!(%context, ?payload, "verify");
let (sender, receiver) = oneshot::channel();
Expand Down
18 changes: 17 additions & 1 deletion consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,19 @@ stability_scope!(BETA, cfg(not(target_arch = "wasm32")) {
/// rather than rebuilding them from current local state. If consensus
/// later abandons a dependency, it also abandons the proposal.
///
/// `ancestry` contains commitments on the selected parent branch in
/// forward order, ending at the parent and excluding the new payload.
/// For parent-linked consensus it begins at a finalized or genesis
/// anchor; applications may resolve older canonical history as needed.
/// Consecutive re-proposals of one payload contribute one commitment.
///
/// Closing the response declines this request, which consensus may
/// treat as final for the context. Keep the response pending when
/// temporary unavailability should not abandon the context.
fn propose(
&mut self,
context: Self::Context,
ancestry: Arc<[Self::Digest]>,
) -> impl Future<Output = oneshot::Receiver<Self::Digest>> + Send;

/// Verify the payload is valid.
Expand All @@ -167,10 +174,13 @@ stability_scope!(BETA, cfg(not(target_arch = "wasm32")) {
///
/// The future-context requirement on [`Self::propose`] applies here
/// too: the context's dependencies may not be resolvable locally yet.
/// `ancestry` has the same ordering and availability contract as
/// [`Self::propose`] and excludes `payload`.
fn verify(
&mut self,
context: Self::Context,
payload: Self::Digest,
ancestry: Arc<[Self::Digest]>,
) -> impl Future<Output = oneshot::Receiver<bool>> + Send;
}

Expand All @@ -180,13 +190,18 @@ stability_scope!(BETA, cfg(not(target_arch = "wasm32")) {
/// phase between notarization and finalization. Applications that do not need custom certification
/// logic can use the default implementation which always certifies.
pub trait CertifiableAutomaton: Automaton {
/// Determine whether a verified payload is safe to commit.
/// Determine whether a payload is safe to commit.
///
/// The round parameter identifies which consensus round is being certified, allowing
/// applications to associate certification with the correct verification context. The
/// same payload may appear in multiple rounds, so implementations must key any state
/// on `(round, payload)` rather than `payload` alone.
///
/// Certification may be requested without prior local verification.
/// `ancestry` supplies the selected parent branch independently of
/// verification, with the same ordering and availability contract as
/// [`Automaton::propose`], and excludes `payload`.
///
/// Like [`Automaton::verify`], payloads produced by [`Automaton::propose`] are certifiable-by-construction.
/// Also like [`Automaton::verify`], certification is single-shot for the given
/// `(round, payload)`. Once the returned channel resolves or closes, consensus treats
Expand All @@ -211,6 +226,7 @@ stability_scope!(BETA, cfg(not(target_arch = "wasm32")) {
&mut self,
_round: Round,
_payload: Self::Digest,
_ancestry: Arc<[Self::Digest]>,
) -> impl Future<Output = oneshot::Receiver<bool>> + Send {
#[allow(clippy::async_yields_async)]
async move {
Expand Down
9 changes: 8 additions & 1 deletion consensus/src/marshal/coding/marshaled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ where
async fn propose(
&mut self,
consensus_context: Context<Commitment<B, C, H>, <Z::Scheme as Verifier>::PublicKey>,
_ancestry: Arc<[Self::Digest]>,
) -> oneshot::Receiver<Self::Digest> {
let marshal = self.marshal.clone();
let mut application = self.application.clone();
Expand Down Expand Up @@ -884,6 +885,7 @@ where
&mut self,
consensus_context: Context<Self::Digest, <Z::Scheme as Verifier>::PublicKey>,
payload: Self::Digest,
_ancestry: Arc<[Self::Digest]>,
) -> oneshot::Receiver<bool> {
// If there's no scheme for the current epoch, we cannot vote on the proposal.
// Send back a receiver with a dropped sender.
Expand Down Expand Up @@ -1110,7 +1112,12 @@ where
{
#[allow(clippy::async_yields_async)]
#[tracing::instrument(name = "marshal.coding.certify", level = "info", skip_all, fields(round = %round, commitment = %payload))]
async fn certify(&mut self, round: Round, payload: Self::Digest) -> oneshot::Receiver<bool> {
async fn certify(
&mut self,
round: Round,
payload: Self::Digest,
_ancestry: Arc<[Self::Digest]>,
) -> oneshot::Receiver<bool> {
self.gates.flush_unrelayed(&self.marshal, round, payload);

// First, check for an in-progress certification gate task.
Expand Down
Loading
Loading