pub struct ConsensusService<Scope, S, E>{ /* 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.
Implementations§
Source§impl ConsensusService<String, InMemoryConsensusStorage<String>, BroadcastEventBus<String>>
impl ConsensusService<String, InMemoryConsensusStorage<String>, BroadcastEventBus<String>>
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.
Source§impl<Scope, S, E> ConsensusService<Scope, S, E>
impl<Scope, S, E> ConsensusService<Scope, S, E>
Sourcepub fn new_with_components(
storage: S,
event_bus: E,
max_sessions_per_scope: usize,
) -> Self
pub fn new_with_components( storage: S, event_bus: E, max_sessions_per_scope: usize, ) -> Self
Build a service with your own storage and event bus implementations.
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 subscribe_to_events(&self) -> E::Receiver
pub fn subscribe_to_events(&self) -> E::Receiver
Subscribe to events like consensus reached or consensus failed.
Returns a receiver that you can use to listen for events across all scopes. Events are broadcast to all subscribers, so multiple parts of your application can react to consensus outcomes.
Sourcepub async fn get_consensus_result(
&self,
scope: &Scope,
proposal_id: u32,
) -> Result<bool, ConsensusError>
pub async fn get_consensus_result( &self, scope: &Scope, proposal_id: u32, ) -> Result<bool, ConsensusError>
Get the final consensus result for a proposal, if it’s been reached.
Returns Ok(true) if consensus was YES, Ok(false) if NO, or Err if
consensus hasn’t been reached yet (or the proposal doesn’t exist or is still active).
Sourcepub async fn get_active_proposals(
&self,
scope: &Scope,
) -> Result<Option<Vec<Proposal>>, ConsensusError>
pub async fn get_active_proposals( &self, scope: &Scope, ) -> Result<Option<Vec<Proposal>>, ConsensusError>
Get all proposals that are still accepting votes.
Sourcepub async fn get_reached_proposals(
&self,
scope: &Scope,
) -> Result<Option<HashMap<u32, bool>>, ConsensusError>
pub async fn get_reached_proposals( &self, scope: &Scope, ) -> Result<Option<HashMap<u32, bool>>, ConsensusError>
Get all proposals that have reached consensus, along with their results.
Returns a map from proposal ID to result (true for YES, false for NO).
Only includes proposals that have finalized - active proposals are not included.
Returns None if no proposals have reached consensus.
Sourcepub async fn has_sufficient_votes_for_proposal(
&self,
scope: &Scope,
proposal_id: u32,
) -> Result<bool, ConsensusError>
pub async fn has_sufficient_votes_for_proposal( &self, scope: &Scope, proposal_id: u32, ) -> Result<bool, ConsensusError>
Check if a proposal has collected enough votes to reach consensus.
Sourcepub async fn scope(
&self,
scope: &Scope,
) -> Result<ScopeConfigBuilderWrapper<Scope, S, E>, ConsensusError>
pub async fn scope( &self, scope: &Scope, ) -> Result<ScopeConfigBuilderWrapper<Scope, S, E>, 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(())
}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.
First checks if consensus has already been reached and returns the result if so. Otherwise, calculates consensus from current votes. If consensus is reached, marks the session as ConsensusReached and returns the result. If no consensus, marks the session as Failed and returns an error.
Source§impl<Scope, S, E> ConsensusService<Scope, S, E>
impl<Scope, S, E> ConsensusService<Scope, S, E>
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, sets up a session to track votes, and schedules automatic timeout handling. The proposal will expire after the time specified in the request.
Configuration is resolved from: proposal config > scope config > global default. If no config is provided, the scope’s default configuration is used.
§Examples
use hashgraph_like_consensus::{scope::ScopeID, scope_config::NetworkType,
service::DefaultConsensusService, types::CreateProposalRequest};
async fn example() -> Result<(), Box<dyn std::error::Error>> {
let service = DefaultConsensusService::default();
let scope = ScopeID::from("my_scope");
service
.scope(&scope)
.await?
.with_network_type(NetworkType::P2P)
.with_threshold(0.75)
.initialize()
.await?;
let request = CreateProposalRequest::new(
"Test Proposal".to_string(),
"payload".to_string(),
vec![0u8; 20],
3,
100,
true,
)?;
let proposal = service.create_proposal(&scope, request).await?;
Ok(())
}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 explicit configuration override.
This allows you to override the scope’s default configuration for a specific proposal. The override takes precedence over scope config.
§Examples
use hashgraph_like_consensus::{scope::ScopeID,
service::DefaultConsensusService, session::ConsensusConfig, types::CreateProposalRequest};
async fn example() -> Result<(), Box<dyn std::error::Error>> {
let service = DefaultConsensusService::default();
let scope = ScopeID::from("my_scope");
let request = CreateProposalRequest::new(
"Test Proposal".to_string(),
"payload".to_string(),
vec![0u8; 20],
3,
100,
true,
)?;
let proposal = service.create_proposal_with_config(
&scope,
request,
Some(ConsensusConfig::p2p())
).await?;
let request2 = CreateProposalRequest::new(
"Another Proposal".to_string(),
"payload2".to_string(),
vec![0u8; 20],
3,
100,
true,
)?;
let proposal2 = service.create_proposal_with_config(
&scope,
request2,
None
).await?;
Ok(())
}Sourcepub async fn cast_vote<SN: Signer + Sync>(
&self,
scope: &Scope,
proposal_id: u32,
choice: bool,
signer: SN,
) -> Result<Vote, ConsensusError>
pub async fn cast_vote<SN: Signer + Sync>( &self, scope: &Scope, proposal_id: u32, choice: bool, signer: SN, ) -> Result<Vote, ConsensusError>
Cast your vote on a proposal (yes or no).
Vote is cryptographically signed and linked to previous votes in the hashgraph. Returns the signed vote, which you can then send to other peers in the network. Each voter can only vote once per proposal.
Sourcepub async fn cast_vote_and_get_proposal<SN: Signer + Sync>(
&self,
scope: &Scope,
proposal_id: u32,
choice: bool,
signer: SN,
) -> Result<Proposal, ConsensusError>
pub async fn cast_vote_and_get_proposal<SN: Signer + Sync>( &self, scope: &Scope, proposal_id: u32, choice: bool, signer: SN, ) -> Result<Proposal, ConsensusError>
Cast a vote and immediately get back the updated proposal.
This is a convenience method that combines cast_vote and fetching the proposal.
Useful for proposal creator as they can immediately see the proposal with their vote
and share it with other 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 you received from another peer in the network.
This validates the proposal and all its votes (signatures, vote chains, timestamps), then stores it locally. If it necessary the consensus configuration is resolved from the proposal. If the proposal already has enough votes, consensus is reached immediately and an event is emitted.
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 vote you received from another peer.
The vote is validated (signature, timestamp, vote chain) and added to the proposal. If this vote brings the total to the consensus threshold, consensus is reached and an event is emitted.
Source§impl<Scope, S, E> ConsensusService<Scope, S, E>
impl<Scope, S, E> ConsensusService<Scope, S, E>
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, S, E> Clone for ConsensusService<Scope, S, E>
impl<Scope, S, E> Clone for ConsensusService<Scope, S, E>
Auto Trait Implementations§
impl<Scope, S, E> Freeze for ConsensusService<Scope, S, E>
impl<Scope, S, E> RefUnwindSafe for ConsensusService<Scope, S, E>
impl<Scope, S, E> Send for ConsensusService<Scope, S, E>
impl<Scope, S, E> Sync for ConsensusService<Scope, S, E>
impl<Scope, S, E> Unpin for ConsensusService<Scope, S, E>
impl<Scope, S, E> UnwindSafe for ConsensusService<Scope, S, E>
Blanket Implementations§
§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§unsafe fn clone_to_uninit(&self, dest: *mut u8)
unsafe fn clone_to_uninit(&self, dest: *mut u8)
clone_to_uninit)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