pub struct ConsensusService<Scope, Storage, Event, Signer>where
Scope: ConsensusScope,
Storage: ConsensusStorage<Scope>,
Event: ConsensusEventBus<Scope>,
Signer: ConsensusSignatureScheme,{ /* private fields */ }Expand description
The main service that handles proposals, votes, and consensus.
This is the main entry point for using the consensus service. It handles creating proposals, processing votes, and managing timeouts.
Generic parameters:
Scope: scope key type (seeConsensusScope).Storage: storage backend (seeConsensusStorage).Event: event bus backend (seeConsensusEventBus).Signer: signature scheme (seeConsensusSignatureScheme). Carried only as a type; the service callsSigner::verifystatically when validating incoming votes. All peers on a network must agree on this type.
Implementations§
Source§impl ConsensusService<String, InMemoryConsensusStorage<String>, BroadcastEventBus<String>, EthereumConsensusSigner>
impl ConsensusService<String, InMemoryConsensusStorage<String>, BroadcastEventBus<String>, EthereumConsensusSigner>
Sourcepub fn new_with_max_sessions(max_sessions_per_scope: usize) -> Self
pub fn new_with_max_sessions(max_sessions_per_scope: usize) -> Self
Create a service with a custom limit on how many sessions can exist per scope.
When the limit is reached, older sessions are automatically removed to make room. Eviction is silent — no event is emitted. Archive results you need before they are evicted.
Source§impl<Scope, Storage, Event, Signer> ConsensusService<Scope, Storage, Event, Signer>where
Scope: ConsensusScope,
Storage: ConsensusStorage<Scope>,
Event: ConsensusEventBus<Scope>,
Signer: ConsensusSignatureScheme,
impl<Scope, Storage, Event, Signer> ConsensusService<Scope, Storage, Event, Signer>where
Scope: ConsensusScope,
Storage: ConsensusStorage<Scope>,
Event: ConsensusEventBus<Scope>,
Signer: ConsensusSignatureScheme,
Sourcepub fn new_with_components(
storage: Storage,
event_bus: Event,
max_sessions_per_scope: usize,
) -> Self
pub fn new_with_components( storage: Storage, event_bus: Event, max_sessions_per_scope: usize, ) -> Self
Build a service with your own storage and event bus implementations.
The signature scheme Signer is selected via turbofish or type inference at
the call site (or by using a type alias like
DefaultConsensusService). Use this when you need custom persistence
(like a database) or event handling. The max_sessions_per_scope
parameter controls how many sessions can exist per scope. When the
limit is reached, older sessions are automatically removed.
Sourcepub fn storage(&self) -> &Storage
pub fn storage(&self) -> &Storage
Access the underlying storage backend.
Use this for reading state (sessions, proposals, scope config) and for
lifecycle operations like delete_scope.
Sourcepub fn event_bus(&self) -> &Event
pub fn event_bus(&self) -> &Event
Access the underlying event bus.
Use this to subscribe to consensus events.
Sourcepub async fn create_proposal(
&self,
scope: &Scope,
request: CreateProposalRequest,
) -> Result<Proposal, ConsensusError>
pub async fn create_proposal( &self, scope: &Scope, request: CreateProposalRequest, ) -> Result<Proposal, ConsensusError>
Create a new proposal and start the voting process.
This creates the proposal and sets up a session to track votes. The proposal will expire after the time specified in the request.
Important: The library does not schedule timeouts automatically.
Your application MUST call handle_consensus_timeout
when the proposal’s timeout elapses (e.g. via tokio::time::sleep).
Without this call, proposals with offline voters will remain stuck in the
Active state indefinitely, and the liveness criteria for silent peers
will never take effect.
Configuration is resolved from: proposal config > scope config > global default. If no config is provided, the scope’s default configuration is used.
Sourcepub async fn create_proposal_with_config(
&self,
scope: &Scope,
request: CreateProposalRequest,
config: Option<ConsensusConfig>,
) -> Result<Proposal, ConsensusError>
pub async fn create_proposal_with_config( &self, scope: &Scope, request: CreateProposalRequest, config: Option<ConsensusConfig>, ) -> Result<Proposal, ConsensusError>
Create a new proposal with an explicit ConsensusConfig override.
Pass None to fall back to scope defaults (same as create_proposal).
Sourcepub async fn cast_vote(
&self,
scope: &Scope,
proposal_id: u32,
choice: bool,
signer: Signer,
) -> Result<Vote, ConsensusError>
pub async fn cast_vote( &self, scope: &Scope, proposal_id: u32, choice: bool, signer: Signer, ) -> Result<Vote, ConsensusError>
Cast a vote on an active proposal.
The vote is cryptographically signed with signer and linked into the
hashgraph chain. Returns the signed Vote for network propagation.
Each voter can only vote once per proposal.
The signer is of the same scheme Signer that the service uses for
verification, so signatures it produces are guaranteed to round-trip
through process_incoming_vote.
Sourcepub async fn cast_vote_and_get_proposal(
&self,
scope: &Scope,
proposal_id: u32,
choice: bool,
signer: Signer,
) -> Result<Proposal, ConsensusError>
pub async fn cast_vote_and_get_proposal( &self, scope: &Scope, proposal_id: u32, choice: bool, signer: Signer, ) -> Result<Proposal, ConsensusError>
Cast a vote and return the updated Proposal (with the new vote included).
Convenience method useful for the proposal creator who wants to immediately gossip the updated proposal to peers.
Sourcepub async fn process_incoming_proposal(
&self,
scope: &Scope,
proposal: Proposal,
) -> Result<(), ConsensusError>
pub async fn process_incoming_proposal( &self, scope: &Scope, proposal: Proposal, ) -> Result<(), ConsensusError>
Process a proposal received from the network.
Call this when your networking layer delivers a proposal from another peer. The library performs no I/O — your application must handle gossip/transport and call this method on receipt.
Validates the proposal and all embedded votes, then stores it locally. If enough votes are already present, consensus is reached immediately.
Sourcepub async fn process_incoming_vote(
&self,
scope: &Scope,
vote: Vote,
) -> Result<(), ConsensusError>
pub async fn process_incoming_vote( &self, scope: &Scope, vote: Vote, ) -> Result<(), ConsensusError>
Process a single vote received from the network.
Call this when your networking layer delivers a vote from another peer. Validates the vote (signature, timestamp, chain) and adds it to the corresponding proposal session. May trigger consensus.
Sourcepub async fn handle_consensus_timeout(
&self,
scope: &Scope,
proposal_id: u32,
) -> Result<bool, ConsensusError>
pub async fn handle_consensus_timeout( &self, scope: &Scope, proposal_id: u32, ) -> Result<bool, ConsensusError>
Handle the timeout for a proposal.
The library does not call this automatically. Your application MUST
schedule a timer (e.g. tokio::time::sleep(config.consensus_timeout()))
and invoke this method when it fires. Without this call, proposals with
offline voters will stay in the Active state forever and silent-peer
liveness logic will never run.
At timeout, silent peers are counted toward quorum using the proposal’s
liveness_criteria_yes flag (RFC Section 4, Silent Node Management):
liveness_criteria_yes = true— silent peers count as YESliveness_criteria_yes = false— silent peers count as NO
Returns the consensus result if determinable, or
InsufficientVotesAtTimeout
if the result is a tie after counting silent peers.
Sourcepub async fn scope(
&self,
scope: &Scope,
) -> Result<ScopeConfigBuilderWrapper<Scope, Storage, Event, Signer>, ConsensusError>
pub async fn scope( &self, scope: &Scope, ) -> Result<ScopeConfigBuilderWrapper<Scope, Storage, Event, Signer>, ConsensusError>
Get a builder for a scope configuration.
§Example
use hashgraph_like_consensus::{scope_config::NetworkType, scope::ScopeID, service::DefaultConsensusService};
use std::time::Duration;
async fn example() -> Result<(), Box<dyn std::error::Error>> {
let service = DefaultConsensusService::default();
let scope = ScopeID::from("my_scope");
// Initialize new scope
service
.scope(&scope)
.await?
.with_network_type(NetworkType::P2P)
.with_threshold(0.75)
.with_timeout(Duration::from_secs(120))
.initialize()
.await?;
// Update existing scope (single field)
service
.scope(&scope)
.await?
.with_threshold(0.8)
.update()
.await?;
Ok(())
}Source§impl<Scope, Storage, Event, Signer> ConsensusService<Scope, Storage, Event, Signer>where
Scope: ConsensusScope,
Storage: ConsensusStorage<Scope>,
Event: ConsensusEventBus<Scope>,
Signer: ConsensusSignatureScheme,
impl<Scope, Storage, Event, Signer> ConsensusService<Scope, Storage, Event, Signer>where
Scope: ConsensusScope,
Storage: ConsensusStorage<Scope>,
Event: ConsensusEventBus<Scope>,
Signer: ConsensusSignatureScheme,
Sourcepub async fn get_scope_stats(&self, scope: &Scope) -> ConsensusStats
pub async fn get_scope_stats(&self, scope: &Scope) -> ConsensusStats
Get statistics about proposals in a scope.
Returns counts of total, active, failed, and finalized proposals. Useful for monitoring and dashboards.
Trait Implementations§
Source§impl<Scope, Storage, Event, Signer> Clone for ConsensusService<Scope, Storage, Event, Signer>where
Scope: ConsensusScope,
Storage: ConsensusStorage<Scope>,
Event: ConsensusEventBus<Scope>,
Signer: ConsensusSignatureScheme,
impl<Scope, Storage, Event, Signer> Clone for ConsensusService<Scope, Storage, Event, Signer>where
Scope: ConsensusScope,
Storage: ConsensusStorage<Scope>,
Event: ConsensusEventBus<Scope>,
Signer: ConsensusSignatureScheme,
Auto Trait Implementations§
impl<Scope, Storage, Event, Signer> Freeze for ConsensusService<Scope, Storage, Event, Signer>
impl<Scope, Storage, Event, Signer> RefUnwindSafe for ConsensusService<Scope, Storage, Event, Signer>
impl<Scope, Storage, Event, Signer> Send for ConsensusService<Scope, Storage, Event, Signer>
impl<Scope, Storage, Event, Signer> Sync for ConsensusService<Scope, Storage, Event, Signer>
impl<Scope, Storage, Event, Signer> Unpin for ConsensusService<Scope, Storage, Event, Signer>
impl<Scope, Storage, Event, Signer> UnsafeUnpin for ConsensusService<Scope, Storage, Event, Signer>where
Storage: UnsafeUnpin,
Event: UnsafeUnpin,
impl<Scope, Storage, Event, Signer> UnwindSafe for ConsensusService<Scope, Storage, Event, Signer>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more