mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-18 04:51:01 +00:00
define context trait and initialize statement table
This commit is contained in:
@@ -30,7 +30,168 @@
|
||||
//! Groups themselves may be compromised by malicious validators.
|
||||
|
||||
extern crate futures;
|
||||
extern crate polkadot_primitives as primitives;
|
||||
extern crate parking_lot;
|
||||
extern crate tokio_timer;
|
||||
|
||||
pub mod bft;
|
||||
pub mod table;
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
||||
use futures::prelude::*;
|
||||
use tokio_timer::Timer;
|
||||
|
||||
use table::Table;
|
||||
|
||||
/// Context necessary for agreement.
|
||||
pub trait Context: Send + Clone {
|
||||
/// A validator ID
|
||||
type ValidatorId: Debug + Hash + Eq + Clone;
|
||||
/// The digest (hash or other unique attribute) of a candidate.
|
||||
type Digest: Debug + Hash + Eq + Clone;
|
||||
/// The group ID type
|
||||
type GroupId: Debug + Hash + Ord + Eq + Clone;
|
||||
/// A signature type.
|
||||
type Signature: Debug + Eq + Clone;
|
||||
/// Candidate type. In practice this will be a candidate receipt.
|
||||
type ParachainCandidate: Debug + Ord + Eq + Clone;
|
||||
/// The actual block proposal type. This is what is agreed upon, and
|
||||
/// is composed of multiple candidates.
|
||||
type Proposal: Debug + Eq + Clone;
|
||||
|
||||
/// A future that resolves when a candidate is checked for validity.
|
||||
///
|
||||
/// In Polkadot, this will involve fetching the corresponding block data,
|
||||
/// producing the necessary ingress, and running the parachain validity function.
|
||||
type CheckCandidate: IntoFuture<Item=bool>;
|
||||
|
||||
/// A future that resolves when availability of a candidate's external
|
||||
/// data is checked.
|
||||
type CheckAvailability: IntoFuture<Item=bool>;
|
||||
|
||||
/// Get the digest of a candidate.
|
||||
fn candidate_digest(candidate: &Self::ParachainCandidate) -> Self::Digest;
|
||||
|
||||
/// Get the group of a candidate.
|
||||
fn candidate_group(candidate: &Self::ParachainCandidate) -> Self::GroupId;
|
||||
|
||||
/// Get the primary for a given round.
|
||||
fn round_proposer(&self, round: usize) -> Self::ValidatorId;
|
||||
|
||||
/// Check a candidate for validity.
|
||||
fn check_validity(&self, candidate: &Self::ParachainCandidate) -> Self::CheckCandidate;
|
||||
|
||||
/// Check availability of candidate data.
|
||||
fn check_availability(&self, candidate: &Self::ParachainCandidate) -> Self::CheckAvailability;
|
||||
|
||||
/// Attempt to combine a set of parachain candidates into a proposal.
|
||||
///
|
||||
/// This may arbitrarily return `None`, but the intent is for `Some`
|
||||
/// to only be returned when candidates from enough groups are known.
|
||||
///
|
||||
/// "enough" may be subjective as well.
|
||||
fn create_proposal(&self, candidates: Vec<&Self::ParachainCandidate>)
|
||||
-> Option<Self::Proposal>;
|
||||
|
||||
/// Check validity of a proposal. This may also be somewhat subjective
|
||||
/// based on a monotonic-decreasing curve.
|
||||
fn proposal_valid(&self, proposal: &Self::Proposal) -> bool;
|
||||
|
||||
/// Get the local validator ID.
|
||||
fn local_id(&self) -> Self::ValidatorId;
|
||||
|
||||
/// Sign a table validity statement with the local key.
|
||||
fn sign_table_statement(
|
||||
&self,
|
||||
statement: &table::Statement<Self::ParachainCandidate, Self::Digest>
|
||||
) -> Self::Signature;
|
||||
|
||||
/// Sign a BFT agreement message.
|
||||
fn sign_bft_message(&self, &bft::Message<Self::Proposal, Self::Digest>) -> Self::Signature;
|
||||
}
|
||||
|
||||
/// Information about a specific group.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GroupInfo<V: Hash + Eq> {
|
||||
/// Validators meant to check validity of candidates.
|
||||
pub validity_guarantors: HashSet<V>,
|
||||
/// Validators meant to check availability of candidate data.
|
||||
pub availability_guarantors: HashSet<V>,
|
||||
/// Number of votes needed for validity.
|
||||
pub needed_validity: usize,
|
||||
/// Number of votes needed for availability.
|
||||
pub needed_availability: usize,
|
||||
}
|
||||
|
||||
struct TableContext<C: Context> {
|
||||
context: C,
|
||||
groups: HashMap<C::GroupId, GroupInfo<C::ValidatorId>>,
|
||||
}
|
||||
|
||||
impl<C: Context> table::Context for TableContext<C> {
|
||||
type ValidatorId = C::ValidatorId;
|
||||
type Digest = C::Digest;
|
||||
type GroupId = C::GroupId;
|
||||
type Signature = C::Signature;
|
||||
type Candidate = C::ParachainCandidate;
|
||||
|
||||
fn candidate_digest(candidate: &Self::Candidate) -> Self::Digest {
|
||||
C::candidate_digest(candidate)
|
||||
}
|
||||
|
||||
fn candidate_group(candidate: &Self::Candidate) -> Self::GroupId {
|
||||
C::candidate_group(candidate)
|
||||
}
|
||||
|
||||
fn is_member_of(&self, validator: &Self::ValidatorId, group: &Self::GroupId) -> bool {
|
||||
self.groups.get(group).map_or(false, |g| g.validity_guarantors.contains(validator))
|
||||
}
|
||||
|
||||
fn is_availability_guarantor_of(&self, validator: &Self::ValidatorId, group: &Self::GroupId) -> bool {
|
||||
self.groups.get(group).map_or(false, |g| g.availability_guarantors.contains(validator))
|
||||
}
|
||||
|
||||
fn requisite_votes(&self, group: &Self::GroupId) -> (usize, usize) {
|
||||
self.groups.get(group).map_or(
|
||||
(usize::max_value(), usize::max_value()),
|
||||
|g| (g.needed_validity, g.needed_availability),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters necessary for agreement.
|
||||
pub struct AgreementParams<C: Context> {
|
||||
/// The context itself.
|
||||
pub context: C,
|
||||
/// For scheduling timeouts.
|
||||
pub timer: Timer,
|
||||
/// Group assignments.
|
||||
pub groups: HashMap<C::GroupId, GroupInfo<C::ValidatorId>>,
|
||||
/// The local candidate proposal.
|
||||
// TODO: replace with future.
|
||||
pub local_proposal: Option<C::ParachainCandidate>,
|
||||
}
|
||||
|
||||
pub fn agree<C: Context + Clone>(params: AgreementParams<C>) {
|
||||
let context = params.context;
|
||||
let local_id = context.local_id();
|
||||
let mut table = Table::<TableContext<C>>::default();
|
||||
|
||||
let table_context = TableContext {
|
||||
context: context.clone(),
|
||||
groups: params.groups,
|
||||
};
|
||||
|
||||
if let Some(candidate) = params.local_proposal {
|
||||
let statement = table::Statement::Candidate(candidate);
|
||||
let signed_statement = table::SignedStatement {
|
||||
signature: context.sign_table_statement(&statement),
|
||||
sender: local_id.clone(),
|
||||
statement: statement,
|
||||
};
|
||||
|
||||
table.import_statement(&table_context, signed_statement, None);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user