mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 17:31:05 +00:00
BABE slot and epoch event notifications (#6563)
* BabeWorker -> BabeSlotWorker * SlotWorker::notify_slot: similar to claim_slot, but called no matter authoring * Wrap the future with a new struct BabeWorker * Add type definition slot_notification_sinks * Function slot_notification_streams for the receiver side * Get a handle of slot_notification_sinks in BabeSlotWorker * Implement notify_slot * Switch to use bounded mpsc * Do not drop the sink when channel is full Only skip sending the message and emit a warning, because it is recoverable. * Fix future type bounds * Add must_use and sink type alias
This commit is contained in:
Generated
+2
@@ -6389,6 +6389,7 @@ dependencies = [
|
|||||||
"pdqselect",
|
"pdqselect",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"rand_chacha 0.2.2",
|
"rand_chacha 0.2.2",
|
||||||
|
"retain_mut",
|
||||||
"sc-block-builder",
|
"sc-block-builder",
|
||||||
"sc-client-api",
|
"sc-client-api",
|
||||||
"sc-consensus-epochs",
|
"sc-consensus-epochs",
|
||||||
@@ -6415,6 +6416,7 @@ dependencies = [
|
|||||||
"sp-keyring",
|
"sp-keyring",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
"sp-timestamp",
|
"sp-timestamp",
|
||||||
|
"sp-utils",
|
||||||
"sp-version",
|
"sp-version",
|
||||||
"substrate-prometheus-endpoint",
|
"substrate-prometheus-endpoint",
|
||||||
"substrate-test-runtime-client",
|
"substrate-test-runtime-client",
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ sp-consensus-vrf = { version = "0.8.0-rc5", path = "../../../primitives/consensu
|
|||||||
sc-consensus-uncles = { version = "0.8.0-rc5", path = "../uncles" }
|
sc-consensus-uncles = { version = "0.8.0-rc5", path = "../uncles" }
|
||||||
sc-consensus-slots = { version = "0.8.0-rc5", path = "../slots" }
|
sc-consensus-slots = { version = "0.8.0-rc5", path = "../slots" }
|
||||||
sp-runtime = { version = "2.0.0-rc5", path = "../../../primitives/runtime" }
|
sp-runtime = { version = "2.0.0-rc5", path = "../../../primitives/runtime" }
|
||||||
|
sp-utils = { version = "2.0.0-rc5", path = "../../../primitives/utils" }
|
||||||
fork-tree = { version = "2.0.0-rc5", path = "../../../utils/fork-tree" }
|
fork-tree = { version = "2.0.0-rc5", path = "../../../utils/fork-tree" }
|
||||||
prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.8.0-rc5"}
|
prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.8.0-rc5"}
|
||||||
futures = "0.3.4"
|
futures = "0.3.4"
|
||||||
@@ -48,6 +49,7 @@ rand = "0.7.2"
|
|||||||
merlin = "2.0"
|
merlin = "2.0"
|
||||||
pdqselect = "0.1.0"
|
pdqselect = "0.1.0"
|
||||||
derive_more = "0.99.2"
|
derive_more = "0.99.2"
|
||||||
|
retain_mut = "0.1.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
sp-keyring = { version = "2.0.0-rc5", path = "../../../primitives/keyring" }
|
sp-keyring = { version = "2.0.0-rc5", path = "../../../primitives/keyring" }
|
||||||
|
|||||||
@@ -106,6 +106,8 @@ use sc_client_api::{
|
|||||||
BlockchainEvents, ProvideUncles,
|
BlockchainEvents, ProvideUncles,
|
||||||
};
|
};
|
||||||
use sp_block_builder::BlockBuilder as BlockBuilderApi;
|
use sp_block_builder::BlockBuilder as BlockBuilderApi;
|
||||||
|
use futures::channel::mpsc::{channel, Sender, Receiver};
|
||||||
|
use retain_mut::RetainMut;
|
||||||
|
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use log::{debug, info, log, trace, warn};
|
use log::{debug, info, log, trace, warn};
|
||||||
@@ -370,7 +372,7 @@ pub fn start_babe<B, C, SC, E, I, SO, CAW, Error>(BabeParams {
|
|||||||
babe_link,
|
babe_link,
|
||||||
can_author_with,
|
can_author_with,
|
||||||
}: BabeParams<B, C, E, I, SO, SC, CAW>) -> Result<
|
}: BabeParams<B, C, E, I, SO, SC, CAW>) -> Result<
|
||||||
impl futures::Future<Output=()>,
|
BabeWorker<B>,
|
||||||
sp_consensus::Error,
|
sp_consensus::Error,
|
||||||
> where
|
> where
|
||||||
B: BlockT,
|
B: BlockT,
|
||||||
@@ -378,16 +380,18 @@ pub fn start_babe<B, C, SC, E, I, SO, CAW, Error>(BabeParams {
|
|||||||
+ HeaderBackend<B> + HeaderMetadata<B, Error = ClientError> + Send + Sync + 'static,
|
+ HeaderBackend<B> + HeaderMetadata<B, Error = ClientError> + Send + Sync + 'static,
|
||||||
C::Api: BabeApi<B>,
|
C::Api: BabeApi<B>,
|
||||||
SC: SelectChain<B> + 'static,
|
SC: SelectChain<B> + 'static,
|
||||||
E: Environment<B, Error = Error> + Send + Sync,
|
E: Environment<B, Error = Error> + Send + Sync + 'static,
|
||||||
E::Proposer: Proposer<B, Error = Error, Transaction = sp_api::TransactionFor<C, B>>,
|
E::Proposer: Proposer<B, Error = Error, Transaction = sp_api::TransactionFor<C, B>>,
|
||||||
I: BlockImport<B, Error = ConsensusError, Transaction = sp_api::TransactionFor<C, B>> + Send
|
I: BlockImport<B, Error = ConsensusError, Transaction = sp_api::TransactionFor<C, B>> + Send
|
||||||
+ Sync + 'static,
|
+ Sync + 'static,
|
||||||
Error: std::error::Error + Send + From<ConsensusError> + From<I::Error> + 'static,
|
Error: std::error::Error + Send + From<ConsensusError> + From<I::Error> + 'static,
|
||||||
SO: SyncOracle + Send + Sync + Clone,
|
SO: SyncOracle + Send + Sync + Clone + 'static,
|
||||||
CAW: CanAuthorWith<B> + Send,
|
CAW: CanAuthorWith<B> + Send + 'static,
|
||||||
{
|
{
|
||||||
let config = babe_link.config;
|
let config = babe_link.config;
|
||||||
let worker = BabeWorker {
|
let slot_notification_sinks = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
|
||||||
|
let worker = BabeSlotWorker {
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
block_import: Arc::new(Mutex::new(block_import)),
|
block_import: Arc::new(Mutex::new(block_import)),
|
||||||
env,
|
env,
|
||||||
@@ -395,6 +399,7 @@ pub fn start_babe<B, C, SC, E, I, SO, CAW, Error>(BabeParams {
|
|||||||
force_authoring,
|
force_authoring,
|
||||||
keystore,
|
keystore,
|
||||||
epoch_changes: babe_link.epoch_changes.clone(),
|
epoch_changes: babe_link.epoch_changes.clone(),
|
||||||
|
slot_notification_sinks: slot_notification_sinks.clone(),
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -406,7 +411,7 @@ pub fn start_babe<B, C, SC, E, I, SO, CAW, Error>(BabeParams {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
info!(target: "babe", "👶 Starting BABE Authorship worker");
|
info!(target: "babe", "👶 Starting BABE Authorship worker");
|
||||||
Ok(sc_consensus_slots::start_slot_worker(
|
let inner = sc_consensus_slots::start_slot_worker(
|
||||||
config.0,
|
config.0,
|
||||||
select_chain,
|
select_chain,
|
||||||
worker,
|
worker,
|
||||||
@@ -414,10 +419,49 @@ pub fn start_babe<B, C, SC, E, I, SO, CAW, Error>(BabeParams {
|
|||||||
inherent_data_providers,
|
inherent_data_providers,
|
||||||
babe_link.time_source,
|
babe_link.time_source,
|
||||||
can_author_with,
|
can_author_with,
|
||||||
))
|
);
|
||||||
|
Ok(BabeWorker {
|
||||||
|
inner: Box::pin(inner),
|
||||||
|
slot_notification_sinks,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BabeWorker<B: BlockT, C, E, I, SO> {
|
/// Worker for Babe which implements `Future<Output=()>`. This must be polled.
|
||||||
|
#[must_use]
|
||||||
|
pub struct BabeWorker<B: BlockT> {
|
||||||
|
inner: Pin<Box<dyn futures::Future<Output=()> + Send + 'static>>,
|
||||||
|
slot_notification_sinks: Arc<Mutex<Vec<Sender<(u64, ViableEpochDescriptor<B::Hash, NumberFor<B>, Epoch>)>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: BlockT> BabeWorker<B> {
|
||||||
|
/// Return an event stream of notifications for when new slot happens, and the corresponding
|
||||||
|
/// epoch descriptor.
|
||||||
|
pub fn slot_notification_stream(
|
||||||
|
&self
|
||||||
|
) -> Receiver<(u64, ViableEpochDescriptor<B::Hash, NumberFor<B>, Epoch>)> {
|
||||||
|
const CHANNEL_BUFFER_SIZE: usize = 1024;
|
||||||
|
|
||||||
|
let (sink, stream) = channel(CHANNEL_BUFFER_SIZE);
|
||||||
|
self.slot_notification_sinks.lock().push(sink);
|
||||||
|
stream
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: BlockT> futures::Future for BabeWorker<B> {
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
fn poll(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut futures::task::Context
|
||||||
|
) -> futures::task::Poll<Self::Output> {
|
||||||
|
self.inner.as_mut().poll(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Slot notification sinks.
|
||||||
|
type SlotNotificationSinks<B> = Arc<Mutex<Vec<Sender<(u64, ViableEpochDescriptor<<B as BlockT>::Hash, NumberFor<B>, Epoch>)>>>>;
|
||||||
|
|
||||||
|
struct BabeSlotWorker<B: BlockT, C, E, I, SO> {
|
||||||
client: Arc<C>,
|
client: Arc<C>,
|
||||||
block_import: Arc<Mutex<I>>,
|
block_import: Arc<Mutex<I>>,
|
||||||
env: E,
|
env: E,
|
||||||
@@ -425,10 +469,11 @@ struct BabeWorker<B: BlockT, C, E, I, SO> {
|
|||||||
force_authoring: bool,
|
force_authoring: bool,
|
||||||
keystore: KeyStorePtr,
|
keystore: KeyStorePtr,
|
||||||
epoch_changes: SharedEpochChanges<B, Epoch>,
|
epoch_changes: SharedEpochChanges<B, Epoch>,
|
||||||
|
slot_notification_sinks: SlotNotificationSinks<B>,
|
||||||
config: Config,
|
config: Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, C, E, I, Error, SO> sc_consensus_slots::SimpleSlotWorker<B> for BabeWorker<B, C, E, I, SO> where
|
impl<B, C, E, I, Error, SO> sc_consensus_slots::SimpleSlotWorker<B> for BabeSlotWorker<B, C, E, I, SO> where
|
||||||
B: BlockT,
|
B: BlockT,
|
||||||
C: ProvideRuntimeApi<B> +
|
C: ProvideRuntimeApi<B> +
|
||||||
ProvideCache<B> +
|
ProvideCache<B> +
|
||||||
@@ -502,6 +547,28 @@ impl<B, C, E, I, Error, SO> sc_consensus_slots::SimpleSlotWorker<B> for BabeWork
|
|||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn notify_slot(
|
||||||
|
&self,
|
||||||
|
_parent_header: &B::Header,
|
||||||
|
slot_number: SlotNumber,
|
||||||
|
epoch_descriptor: &ViableEpochDescriptor<B::Hash, NumberFor<B>, Epoch>,
|
||||||
|
) {
|
||||||
|
self.slot_notification_sinks.lock()
|
||||||
|
.retain_mut(|sink| {
|
||||||
|
match sink.try_send((slot_number, epoch_descriptor.clone())) {
|
||||||
|
Ok(()) => true,
|
||||||
|
Err(e) => {
|
||||||
|
if e.is_full() {
|
||||||
|
warn!(target: "babe", "Trying to notify a slot but the channel is full");
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn pre_digest_data(
|
fn pre_digest_data(
|
||||||
&self,
|
&self,
|
||||||
_slot_number: u64,
|
_slot_number: u64,
|
||||||
@@ -599,7 +666,7 @@ impl<B, C, E, I, Error, SO> sc_consensus_slots::SimpleSlotWorker<B> for BabeWork
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<B, C, E, I, SO> where
|
impl<B, C, E, I, Error, SO> SlotWorker<B> for BabeSlotWorker<B, C, E, I, SO> where
|
||||||
B: BlockT,
|
B: BlockT,
|
||||||
C: ProvideRuntimeApi<B> +
|
C: ProvideRuntimeApi<B> +
|
||||||
ProvideCache<B> +
|
ProvideCache<B> +
|
||||||
|
|||||||
@@ -104,6 +104,15 @@ pub trait SimpleSlotWorker<B: BlockT> {
|
|||||||
epoch_data: &Self::EpochData,
|
epoch_data: &Self::EpochData,
|
||||||
) -> Option<Self::Claim>;
|
) -> Option<Self::Claim>;
|
||||||
|
|
||||||
|
/// Notifies the given slot. Similar to `claim_slot`, but will be called no matter whether we
|
||||||
|
/// need to author blocks or not.
|
||||||
|
fn notify_slot(
|
||||||
|
&self,
|
||||||
|
_header: &B::Header,
|
||||||
|
_slot_number: u64,
|
||||||
|
_epoch_data: &Self::EpochData,
|
||||||
|
) { }
|
||||||
|
|
||||||
/// Return the pre digest data to include in a block authored with the given claim.
|
/// Return the pre digest data to include in a block authored with the given claim.
|
||||||
fn pre_digest_data(
|
fn pre_digest_data(
|
||||||
&self,
|
&self,
|
||||||
@@ -191,6 +200,8 @@ pub trait SimpleSlotWorker<B: BlockT> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.notify_slot(&chain_head, slot_number, &epoch_data);
|
||||||
|
|
||||||
let authorities_len = self.authorities_len(&epoch_data);
|
let authorities_len = self.authorities_len(&epoch_data);
|
||||||
|
|
||||||
if !self.force_authoring() &&
|
if !self.force_authoring() &&
|
||||||
|
|||||||
Reference in New Issue
Block a user