Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Delayed BEEFY worker initialization (#121)
Browse files Browse the repository at this point in the history
* lifecycle state

* add Client convenience trait

* rework trait identifiers

* WIP

* rework BeefyWorker::new() signature

* Delayed BEEFY gadget initialization

* address review
  • Loading branch information
adoerr authored Mar 22, 2021
1 parent 7120b62 commit c010f95
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 109 deletions.
18 changes: 14 additions & 4 deletions client/beefy/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,29 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! BEEFY gadget specific errors
//!
//! Used for BEEFY gadget interal error handling only

use std::fmt::Debug;

use sp_core::crypto::Public;

/// BEEFY gadget specific errors
/// Note that this type is currently used for BEEFY gadget internal
/// error handling only.
/// Crypto related errors
#[derive(Debug, thiserror::Error)]
pub(crate) enum Error<Id: Public + Debug> {
pub(crate) enum Crypto<Id: Public + Debug> {
/// Check signature error
#[error("Message signature {0} by {1:?} is invalid.")]
InvalidSignature(String, Id),
/// Sign commitment error
#[error("Failed to sign comitment using key: {0:?}. Reason: {1}")]
CannotSign(Id, String),
}

/// Lifecycle related errors
#[derive(Debug, thiserror::Error)]
pub(crate) enum Lifecycle {
/// Can't fetch validator set from BEEFY pallet
#[error("Failed to fetch validator set: {0}")]
MissingValidatorSet(String),
}
106 changes: 62 additions & 44 deletions client/beefy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,23 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use std::{convert::TryFrom, fmt::Debug, sync::Arc};

use beefy_primitives::BeefyApi;
use codec::Codec;
use sc_client_api::{Backend as BackendT, BlockchainEvents, Finalizer};

use sc_client_api::{Backend, BlockchainEvents, Finalizer};
use sc_network_gossip::{
GossipEngine, Network as GossipNetwork, ValidationResult as GossipValidationResult, Validator as GossipValidator,
ValidatorContext as GossipValidatorContext,
};
use sp_api::{BlockId, ProvideRuntimeApi};

use sp_api::ProvideRuntimeApi;
use sp_application_crypto::AppPublic;
use sp_blockchain::HeaderBackend;
use sp_consensus::SyncOracle as SyncOracleT;
use sp_keystore::SyncCryptoStorePtr;
use sp_runtime::traits::{Block as BlockT, Zero};
use std::{convert::TryFrom, fmt::Debug, sync::Arc};
use sp_runtime::traits::Block;

mod error;
mod round;
Expand All @@ -52,74 +55,89 @@ pub fn beefy_peers_set_config() -> sc_network::config::NonDefaultSetConfig {
}
}

/// A convenience BEEFY client trait that defines all the type bounds a BEEFY client
/// has to satisfy. Ideally that should actually be a trait alias. Unfortunately as
/// of today, Rust does not allow a type alias to be used as a trait bound. Tracking
/// issue is <https://github.com/rust-lang/rust/issues/41517>.
pub(crate) trait Client<B, BE, P>:
BlockchainEvents<B> + HeaderBackend<B> + Finalizer<B, BE> + ProvideRuntimeApi<B> + Send + Sync
where
B: Block,
BE: Backend<B>,
P: sp_core::Pair,
P::Public: AppPublic + Codec,
P::Signature: Clone + Codec + Debug + PartialEq + TryFrom<Vec<u8>>,
{
// empty
}

impl<B, BE, P, T> Client<B, BE, P> for T
where
B: Block,
BE: Backend<B>,
P: sp_core::Pair,
P::Public: AppPublic + Codec,
P::Signature: Clone + Codec + Debug + PartialEq + TryFrom<Vec<u8>>,
T: BlockchainEvents<B> + HeaderBackend<B> + Finalizer<B, BE> + ProvideRuntimeApi<B> + Send + Sync,
{
// empty
}

/// Allows all gossip messages to get through.
struct AllowAll<Hash> {
topic: Hash,
}

impl<Block> GossipValidator<Block> for AllowAll<Block::Hash>
impl<B> GossipValidator<B> for AllowAll<B::Hash>
where
Block: BlockT,
B: Block,
{
fn validate(
&self,
_context: &mut dyn GossipValidatorContext<Block>,
_context: &mut dyn GossipValidatorContext<B>,
_sender: &sc_network::PeerId,
_data: &[u8],
) -> GossipValidationResult<Block::Hash> {
) -> GossipValidationResult<B::Hash> {
GossipValidationResult::ProcessAndKeep(self.topic)
}
}

pub async fn start_beefy_gadget<Block, Pair, Backend, Client, Network, SyncOracle>(
client: Arc<Client>,
/// Start the BEEFY gadget.
///
/// This is a thin shim around running and awaiting a BEEFY worker. The [`Client`]
/// convenience trait is not used here on purpose. We don't want to leak it into the
/// public interface of the BEEFY gadget.
pub async fn start_beefy_gadget<B, P, BE, C, N, SO>(
client: Arc<C>,
key_store: SyncCryptoStorePtr,
network: Network,
signed_commitment_sender: notification::BeefySignedCommitmentSender<Block, Pair::Signature>,
_sync_oracle: SyncOracle,
network: N,
signed_commitment_sender: notification::BeefySignedCommitmentSender<B, P::Signature>,
_sync_oracle: SO,
) where
Block: BlockT,
Pair: sp_core::Pair,
Pair::Public: AppPublic + Codec,
Pair::Signature: Clone + Codec + Debug + PartialEq + TryFrom<Vec<u8>>,
Backend: BackendT<Block>,
Client: BlockchainEvents<Block>
+ HeaderBackend<Block>
+ Finalizer<Block, Backend>
+ ProvideRuntimeApi<Block>
+ Send
+ Sync,
Client::Api: BeefyApi<Block, Pair::Public>,
Network: GossipNetwork<Block> + Clone + Send + 'static,
SyncOracle: SyncOracleT + Send + 'static,
B: Block,
P: sp_core::Pair,
P::Public: AppPublic + Codec,
P::Signature: Clone + Codec + Debug + PartialEq + TryFrom<Vec<u8>>,
BE: Backend<B>,
C: BlockchainEvents<B> + HeaderBackend<B> + Finalizer<B, BE> + ProvideRuntimeApi<B> + Send + Sync,
C::Api: BeefyApi<B, P::Public>,
N: GossipNetwork<B> + Clone + Send + 'static,
SO: SyncOracleT + Send + 'static,
{
let gossip_engine = GossipEngine::new(
network,
BEEFY_PROTOCOL_NAME,
Arc::new(AllowAll {
topic: worker::topic::<Block>(),
topic: worker::topic::<B>(),
}),
None,
);

let at = BlockId::hash(client.info().best_hash);

let validator_set = client
.runtime_api()
.validator_set(&at)
.expect("Failed to get BEEFY validator set");

let best_finalized_block = client.info().finalized_number;
let best_block_voted_on = Zero::zero();

let worker = worker::BeefyWorker::<_, Pair::Public, Pair::Signature, _>::new(
validator_set,
let worker = worker::BeefyWorker::<_, P::Signature, _, BE, P>::new(
client.clone(),
key_store,
client.finality_notification_stream(),
gossip_engine,
signed_commitment_sender,
best_finalized_block,
best_block_voted_on,
gossip_engine,
);

worker.run().await
Expand Down
Loading

0 comments on commit c010f95

Please sign in to comment.