#![deny(missing_docs)]
#![feature(test)]
mod codec;
pub mod error;
pub mod overlord;
mod smr;
mod state;
mod timer;
pub mod types;
mod utils;
mod wal;
pub use self::overlord::Overlord;
pub use self::overlord::OverlordHandler;
pub use creep::Context;
use std::error::Error;
use std::fmt::Debug;
use async_trait::async_trait;
use bytes::Bytes;
use serde::{Deserialize, Serialize};
use crate::error::ConsensusError;
use crate::types::{Address, Commit, Hash, Node, OverlordMsg, Signature, Status};
pub type ConsensusResult<T> = ::std::result::Result<T, ConsensusError>;
const INIT_EPOCH_ID: u64 = 0;
const INIT_ROUND: u64 = 0;
#[async_trait]
pub trait Consensus<T: Codec>: Send + Sync {
async fn get_epoch(
&self,
ctx: Context,
epoch_id: u64,
) -> Result<(T, Hash), Box<dyn Error + Send>>;
async fn check_epoch(
&self,
ctx: Context,
epoch_id: u64,
hash: Hash,
epoch: T,
) -> Result<(), Box<dyn Error + Send>>;
async fn commit(
&self,
ctx: Context,
epoch_id: u64,
commit: Commit<T>,
) -> Result<Status, Box<dyn Error + Send>>;
async fn get_authority_list(
&self,
ctx: Context,
epoch_id: u64,
) -> Result<Vec<Node>, Box<dyn Error + Send>>;
async fn broadcast_to_other(
&self,
ctx: Context,
msg: OverlordMsg<T>,
) -> Result<(), Box<dyn Error + Send>>;
async fn transmit_to_relayer(
&self,
ctx: Context,
addr: Address,
msg: OverlordMsg<T>,
) -> Result<(), Box<dyn Error + Send>>;
}
pub trait Codec: Clone + Debug + Send + PartialEq + Eq {
fn encode(&self) -> Result<Bytes, Box<dyn Error + Send>>;
fn decode(data: Bytes) -> Result<Self, Box<dyn Error + Send>>;
}
#[async_trait]
pub trait Wal {
async fn save(&self, info: Bytes) -> Result<(), Box<dyn Error + Send>>;
async fn load(&self) -> Result<Option<Bytes>, Box<dyn Error + Send>>;
}
pub trait Crypto: Send {
fn hash(&self, msg: Bytes) -> Hash;
fn sign(&self, hash: Hash) -> Result<Signature, Box<dyn Error + Send>>;
fn aggregate_signatures(
&self,
signatures: Vec<Signature>,
voters: Vec<Address>,
) -> Result<Signature, Box<dyn Error + Send>>;
fn verify_signature(
&self,
signature: Signature,
hash: Hash,
voter: Address,
) -> Result<(), Box<dyn Error + Send>>;
fn verify_aggregated_signature(
&self,
aggregate_signature: Signature,
msg_hash: Hash,
voters: Vec<Address>,
) -> Result<(), Box<dyn Error + Send>>;
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct DurationConfig {
pub propose_ratio: u64,
pub prevote_ratio: u64,
pub precommit_ratio: u64,
}
impl DurationConfig {
pub fn new(propose_ratio: u64, prevote_ratio: u64, precommit_ratio: u64) -> Self {
DurationConfig {
propose_ratio,
prevote_ratio,
precommit_ratio,
}
}
pub(crate) fn get_propose_config(&self) -> (u64, u64) {
(self.propose_ratio, 10u64)
}
pub(crate) fn get_prevote_config(&self) -> (u64, u64) {
(self.prevote_ratio, 10u64)
}
pub(crate) fn get_precommit_config(&self) -> (u64, u64) {
(self.precommit_ratio, 10u64)
}
}
#[cfg(test)]
mod test {
use super::DurationConfig;
#[test]
fn test_duration_config() {
let config = DurationConfig::new(1, 2, 3);
assert_eq!(config.get_propose_config(), (1, 10));
assert_eq!(config.get_prevote_config(), (2, 10));
assert_eq!(config.get_precommit_config(), (3, 10));
}
}