Skip to content

Commit

Permalink
A0-1820: implement substrate specific verifier for sync protocol (#864)
Browse files Browse the repository at this point in the history
* Small refactor to prepare for verifier

* move justification verification to sync folder

* implement SessionVerifier cache

* implement verifier for VerifierCache
  • Loading branch information
maciejnems authored Jan 19, 2023
1 parent f113623 commit 725fd98
Show file tree
Hide file tree
Showing 12 changed files with 627 additions and 100 deletions.
2 changes: 1 addition & 1 deletion finality-aleph/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ pub fn verify(authority: &AuthorityId, message: &[u8], signature: &Signature) ->

/// Holds the public authority keys for a session allowing for verification of messages from that
/// session.
#[derive(Clone)]
#[derive(PartialEq, Clone, Debug)]
pub struct AuthorityVerifier {
authorities: Vec<AuthorityId>,
}
Expand Down
67 changes: 7 additions & 60 deletions finality-aleph/src/nodes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,23 @@ mod validator_node;

use std::{future::Future, sync::Arc};

use aleph_primitives::{AuthorityId, SessionAuthorityData};
use codec::Encode;
use log::warn;
pub use nonvalidator_node::run_nonvalidator_node;
use sc_client_api::Backend;
use sc_network::NetworkService;
use sc_network_common::ExHashT;
use sp_runtime::{
traits::{Block, Header, NumberFor},
RuntimeAppPublic,
};
use sp_runtime::traits::{Block, Header, NumberFor};
pub use validator_node::run_validator_node;

use crate::{
crypto::AuthorityVerifier,
finalization::AlephFinalizer,
justification::{
AlephJustification, JustificationHandler, JustificationRequestSchedulerImpl, SessionInfo,
SessionInfoProvider, Verifier,
JustificationHandler, JustificationRequestSchedulerImpl, SessionInfo, SessionInfoProvider,
},
last_block_of_session, mpsc,
mpsc::UnboundedSender,
session_id_from_block_num,
session_map::ReadOnlySessionMap,
sync::SessionVerifier,
BlockchainBackend, JustificationNotification, Metrics, MillisecsPerBlock, SessionPeriod,
};

Expand All @@ -38,52 +31,6 @@ pub mod testing {
/// Max amount of tries we can not update a finalized block number before we will clear requests queue
const MAX_ATTEMPTS: u32 = 5;

struct JustificationVerifier {
authority_verifier: AuthorityVerifier,
emergency_signer: Option<AuthorityId>,
}

impl From<SessionAuthorityData> for JustificationVerifier {
fn from(authority_data: SessionAuthorityData) -> Self {
JustificationVerifier {
authority_verifier: AuthorityVerifier::new(authority_data.authorities().to_vec()),
emergency_signer: authority_data.emergency_finalizer().clone(),
}
}
}

impl<B: Block> Verifier<B> for JustificationVerifier {
fn verify(&self, justification: &AlephJustification, hash: B::Hash) -> bool {
use AlephJustification::*;
let encoded_hash = hash.encode();
match justification {
CommitteeMultisignature(multisignature) => match self
.authority_verifier
.is_complete(&encoded_hash, multisignature)
{
true => true,
false => {
warn!(target: "aleph-justification", "Bad multisignature for block hash #{:?} {:?}", hash, multisignature);
false
}
},
EmergencySignature(signature) => match &self.emergency_signer {
Some(emergency_signer) => match emergency_signer.verify(&encoded_hash, signature) {
true => true,
false => {
warn!(target: "aleph-justification", "Bad emergency signature for block hash #{:?} {:?}", hash, signature);
false
}
},
None => {
warn!(target: "aleph-justification", "Received emergency signature for block with hash #{:?}, which has no emergency signer defined.", hash);
false
}
},
}
}
}

struct JustificationParams<B: Block, H: ExHashT, C, BB> {
pub network: Arc<NetworkService<B, H>>,
pub client: Arc<C>,
Expand All @@ -110,10 +57,10 @@ impl SessionInfoProviderImpl {
}

#[async_trait::async_trait]
impl<B: Block> SessionInfoProvider<B, JustificationVerifier> for SessionInfoProviderImpl {
async fn for_block_num(&self, number: NumberFor<B>) -> SessionInfo<B, JustificationVerifier> {
let current_session = session_id_from_block_num::<B>(number, self.session_period);
let last_block_height = last_block_of_session::<B>(current_session, self.session_period);
impl<B: Block> SessionInfoProvider<B, SessionVerifier> for SessionInfoProviderImpl {
async fn for_block_num(&self, number: NumberFor<B>) -> SessionInfo<B, SessionVerifier> {
let current_session = session_id_from_block_num(number, self.session_period);
let last_block_height = last_block_of_session(current_session, self.session_period);
let verifier = self
.session_authorities
.get(current_session)
Expand Down
9 changes: 5 additions & 4 deletions finality-aleph/src/party/impls.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::{marker::PhantomData, sync::Arc};

use sc_client_api::Backend;
use sp_runtime::traits::{Block as BlockT, NumberFor, SaturatedConversion};
use sp_runtime::traits::{Block as BlockT, NumberFor};

use crate::{
party::traits::{Block, ChainState, SessionInfo},
session::{first_block_of_session, last_block_of_session, session_id_from_block_num},
ClientForAleph, SessionId, SessionPeriod,
};

Expand Down Expand Up @@ -44,14 +45,14 @@ impl SessionInfoImpl {

impl<B: BlockT> SessionInfo<B> for SessionInfoImpl {
fn session_id_from_block_num(&self, n: NumberFor<B>) -> SessionId {
SessionId(n.saturated_into::<u32>() / self.session_period.0)
session_id_from_block_num(n, self.session_period)
}

fn last_block_of_session(&self, session_id: SessionId) -> NumberFor<B> {
((session_id.0 + 1) * self.session_period.0 - 1).into()
last_block_of_session(session_id, self.session_period)
}

fn first_block_of_session(&self, session_id: SessionId) -> NumberFor<B> {
(session_id.0 * self.session_period.0).into()
first_block_of_session(session_id, self.session_period)
}
}
15 changes: 9 additions & 6 deletions finality-aleph/src/party/mocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use crate::{
manager::AuthorityTask,
traits::{Block, ChainState, NodeSessionManager, SessionInfo, SyncState},
},
AuthorityId, NodeIndex, SessionId,
session::{first_block_of_session, last_block_of_session, session_id_from_block_num},
AuthorityId, NodeIndex, SessionId, SessionPeriod,
};

type AMutex<T> = Arc<Mutex<T>>;
Expand Down Expand Up @@ -183,25 +184,27 @@ impl NodeSessionManager for Arc<MockNodeSessionManager> {
}

pub struct MockSessionInfo {
pub session_period: u32,
pub session_period: SessionPeriod,
}

impl MockSessionInfo {
pub fn new(session_period: u32) -> Self {
Self { session_period }
Self {
session_period: SessionPeriod(session_period),
}
}
}

impl SessionInfo<SimpleBlock> for MockSessionInfo {
fn session_id_from_block_num(&self, n: u32) -> SessionId {
SessionId(n / self.session_period)
session_id_from_block_num(n, self.session_period)
}

fn last_block_of_session(&self, session_id: SessionId) -> u32 {
(session_id.0 + 1) * self.session_period - 1
last_block_of_session(session_id, self.session_period)
}

fn first_block_of_session(&self, session_id: SessionId) -> u32 {
session_id.0 * self.session_period
first_block_of_session(session_id, self.session_period)
}
}
39 changes: 30 additions & 9 deletions finality-aleph/src/session.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use codec::{Decode, Encode};
use sp_runtime::{traits::Block, SaturatedConversion};
use sp_runtime::{
traits::{AtLeast32BitUnsigned, Block},
SaturatedConversion,
};

use crate::NumberFor;

Expand All @@ -12,8 +15,8 @@ pub struct SessionBoundaries<B: Block> {
impl<B: Block> SessionBoundaries<B> {
pub fn new(session_id: SessionId, period: SessionPeriod) -> Self {
SessionBoundaries {
first_block: first_block_of_session::<B>(session_id, period),
last_block: last_block_of_session::<B>(session_id, period),
first_block: first_block_of_session(session_id, period),
last_block: last_block_of_session(session_id, period),
}
}

Expand All @@ -26,22 +29,40 @@ impl<B: Block> SessionBoundaries<B> {
}
}

pub fn first_block_of_session<B: Block>(
pub fn first_block_of_session<N: AtLeast32BitUnsigned>(
session_id: SessionId,
period: SessionPeriod,
) -> NumberFor<B> {
) -> N {
(session_id.0 * period.0).into()
}

pub fn last_block_of_session<B: Block>(
pub fn last_block_of_session<N: AtLeast32BitUnsigned>(
session_id: SessionId,
period: SessionPeriod,
) -> NumberFor<B> {
) -> N {
((session_id.0 + 1) * period.0 - 1).into()
}

pub fn session_id_from_block_num<B: Block>(num: NumberFor<B>, period: SessionPeriod) -> SessionId {
SessionId(num.saturated_into::<u32>() / period.0)
pub fn session_id_from_block_num<N: AtLeast32BitUnsigned>(
num: N,
period: SessionPeriod,
) -> SessionId {
SessionId((num / period.0.into()).saturated_into())
}

#[cfg(test)]
pub mod testing {
use aleph_primitives::SessionAuthorityData;
use sp_runtime::testing::UintAuthorityId;

pub fn authority_data(from: u64, to: u64) -> SessionAuthorityData {
SessionAuthorityData::new(
(from..to)
.map(|id| UintAuthorityId(id).to_public_key())
.collect(),
None,
)
}
}

#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd, Encode, Decode)]
Expand Down
18 changes: 4 additions & 14 deletions finality-aleph/src/session_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,15 +313,15 @@ where
}

async fn update_session(&mut self, session_id: SessionId, period: SessionPeriod) {
let first_block = first_block_of_session::<B>(session_id, period);
let first_block = first_block_of_session(session_id, period);
self.handle_first_block_of_session(first_block, session_id)
.await;
}

fn catch_up_boundaries(&self, period: SessionPeriod) -> (SessionId, SessionId) {
let last_finalized = self.finality_notificator.last_finalized();

let current_session = session_id_from_block_num::<B>(last_finalized, period);
let current_session = session_id_from_block_num(last_finalized, period);
let starting_session = SessionId(current_session.0.saturating_sub(PRUNING_THRESHOLD));

(starting_session, current_session)
Expand All @@ -343,7 +343,7 @@ where
let last_finalized = header.number();
trace!(target: "aleph-session-updater", "got FinalityNotification about #{:?}", last_finalized);

let session_id = session_id_from_block_num::<B>(*last_finalized, period);
let session_id = session_id_from_block_num(*last_finalized, period);

if last_updated >= session_id {
continue;
Expand All @@ -366,15 +366,14 @@ mod tests {
use sc_block_builder::BlockBuilderProvider;
use sc_utils::mpsc::tracing_unbounded;
use sp_consensus::BlockOrigin;
use sp_runtime::testing::UintAuthorityId;
use substrate_test_runtime_client::{
ClientBlockImportExt, DefaultTestClientBuilderExt, TestClient, TestClientBuilder,
TestClientBuilderExt,
};
use tokio::sync::oneshot::error::TryRecvError;

use super::*;
use crate::testing::mocks::TBlock;
use crate::{session::testing::authority_data, testing::mocks::TBlock};

struct MockProvider {
pub session_map: HashMap<NumberFor<TBlock>, SessionAuthorityData>,
Expand Down Expand Up @@ -432,15 +431,6 @@ mod tests {
}
}

fn authority_data(from: u64, to: u64) -> SessionAuthorityData {
SessionAuthorityData::new(
(from..to)
.map(|id| UintAuthorityId(id).to_public_key())
.collect(),
None,
)
}

fn n_new_blocks(client: &mut Arc<TestClient>, n: u64) -> Vec<TBlock> {
(0..n)
.map(|_| {
Expand Down
4 changes: 3 additions & 1 deletion finality-aleph/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ mod substrate;
mod task_queue;
mod ticker;

pub use substrate::SessionVerifier;

const LOG_TARGET: &str = "aleph-block-sync";

/// The identifier of a block, the least amount of knowledge we can have about a block.
Expand Down Expand Up @@ -50,7 +52,7 @@ pub trait Verifier<J: Justification> {

/// Verifies the raw justification and returns a full justification if successful, otherwise an
/// error.
fn verify(&self, justification: J::Unverified) -> Result<J, Self::Error>;
fn verify(&mut self, justification: J::Unverified) -> Result<J, Self::Error>;
}

/// A facility for finalizing blocks using justifications.
Expand Down
4 changes: 4 additions & 0 deletions finality-aleph/src/sync/substrate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@ use crate::{
mod chain_status;
mod finalizer;
mod status_notifier;
mod verification;

pub use verification::SessionVerifier;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BlockId<H: SubstrateHeader<Number = BlockNumber>> {
hash: H::Hash,
number: H::Number,
}

/// An identifier uniquely specifying a block and its height.
impl<SH: SubstrateHeader<Number = BlockNumber>> Hash for BlockId<SH> {
fn hash<H>(&self, state: &mut H)
where
Expand Down
Loading

0 comments on commit 725fd98

Please sign in to comment.