refactor overseer into proc-macro based pattern (#2962)

This commit is contained in:
Bernhard Schuster
2021-07-08 21:09:26 +02:00
committed by GitHub
parent 2510bfc5d7
commit 3c9104daff
119 changed files with 5675 additions and 3864 deletions
@@ -29,6 +29,7 @@
//! We maintain a rolling window of session indices. This starts as empty
use polkadot_node_subsystem::{
overseer,
messages::{
RuntimeApiMessage, RuntimeApiRequest, ChainApiMessage, ApprovalDistributionMessage,
ChainSelectionMessage,
@@ -84,7 +85,7 @@ struct ImportedBlockInfoEnv<'a> {
// Computes information about the imported block. Returns `None` if the info couldn't be extracted -
// failure to communicate with overseer,
async fn imported_block_info(
ctx: &mut impl SubsystemContext,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext),
env: ImportedBlockInfoEnv<'_>,
block_hash: Hash,
block_header: &Header,
@@ -98,7 +99,7 @@ async fn imported_block_info(
ctx.send_message(RuntimeApiMessage::Request(
block_hash,
RuntimeApiRequest::CandidateEvents(c_tx),
).into()).await;
)).await;
let events: Vec<CandidateEvent> = match c_rx.await {
Ok(Ok(events)) => events,
@@ -120,7 +121,7 @@ async fn imported_block_info(
ctx.send_message(RuntimeApiMessage::Request(
block_header.parent_hash,
RuntimeApiRequest::SessionIndexForChild(s_tx),
).into()).await;
)).await;
let session_index = match s_rx.await {
Ok(Ok(s)) => s,
@@ -161,7 +162,7 @@ async fn imported_block_info(
ctx.send_message(RuntimeApiMessage::Request(
block_hash,
RuntimeApiRequest::CurrentBabeEpoch(s_tx),
).into()).await;
)).await;
match s_rx.await {
Ok(Ok(s)) => s,
@@ -284,20 +285,21 @@ pub struct BlockImportedCandidates {
/// * and return information about all candidates imported under each block.
///
/// It is the responsibility of the caller to schedule wakeups for each block.
pub(crate) async fn handle_new_head<'a>(
ctx: &mut impl SubsystemContext,
pub(crate) async fn handle_new_head(
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext),
state: &mut State,
db: &mut OverlayedBackend<'a, impl Backend>,
db: &mut OverlayedBackend<'_, impl Backend>,
head: Hash,
finalized_number: &Option<BlockNumber>,
) -> SubsystemResult<Vec<BlockImportedCandidates>> {
) -> SubsystemResult<Vec<BlockImportedCandidates>>
{
// Update session info based on most recent head.
let mut span = jaeger::Span::new(head, "approval-checking-import");
let header = {
let (h_tx, h_rx) = oneshot::channel();
ctx.send_message(ChainApiMessage::BlockHeader(head, h_tx).into()).await;
ctx.send_message(ChainApiMessage::BlockHeader(head, h_tx)).await;
match h_rx.await? {
Err(e) => {
@@ -375,7 +377,7 @@ pub(crate) async fn handle_new_head<'a>(
// It's possible that we've lost a race with finality.
let (tx, rx) = oneshot::channel();
ctx.send_message(
ChainApiMessage::FinalizedBlockHash(block_header.number.clone(), tx).into()
ChainApiMessage::FinalizedBlockHash(block_header.number.clone(), tx)
).await;
let lost_to_finality = match rx.await {
@@ -469,7 +471,7 @@ pub(crate) async fn handle_new_head<'a>(
// If all bits are already set, then send an approve message.
if approved_bitfield.count_ones() == approved_bitfield.len() {
ctx.send_message(ChainSelectionMessage::Approved(block_hash).into()).await;
ctx.send_message(ChainSelectionMessage::Approved(block_hash)).await;
}
let block_entry = v1::BlockEntry {
@@ -498,7 +500,7 @@ pub(crate) async fn handle_new_head<'a>(
// Notify chain-selection of all approved hashes.
for hash in approved_hashes {
ctx.send_message(ChainSelectionMessage::Approved(hash).into()).await;
ctx.send_message(ChainSelectionMessage::Approved(hash)).await;
}
}
@@ -551,7 +553,7 @@ pub(crate) async fn handle_new_head<'a>(
"Informing distribution of newly imported chain",
);
ctx.send_unbounded_message(ApprovalDistributionMessage::NewBlocks(approval_meta).into());
ctx.send_unbounded_message(ApprovalDistributionMessage::NewBlocks(approval_meta));
Ok(imported_candidates)
}
+23 -19
View File
@@ -29,7 +29,7 @@ use polkadot_node_subsystem::{
AvailabilityRecoveryMessage, ChainSelectionMessage,
},
errors::RecoveryError,
Subsystem, SubsystemContext, SubsystemError, SubsystemResult, SpawnedSubsystem,
overseer::{self, SubsystemSender as _}, SubsystemContext, SubsystemError, SubsystemResult, SpawnedSubsystem,
FromOverseer, OverseerSignal, SubsystemSender,
};
use polkadot_node_subsystem_util::{
@@ -333,12 +333,15 @@ impl ApprovalVotingSubsystem {
}
}
impl<C> Subsystem<C> for ApprovalVotingSubsystem
where C: SubsystemContext<Message = ApprovalVotingMessage>
impl<Context> overseer::Subsystem<Context, SubsystemError> for ApprovalVotingSubsystem
where
Context: SubsystemContext<Message = ApprovalVotingMessage>,
Context: overseer::SubsystemContext<Message = ApprovalVotingMessage>,
{
fn start(self, ctx: C) -> SpawnedSubsystem {
fn start(self, ctx: Context) -> SpawnedSubsystem {
let backend = DbBackend::new(self.db.clone(), self.db_config);
let future = run::<DbBackend, C>(
let future = run::<DbBackend, Context>(
ctx,
self,
Box::new(SystemClock),
@@ -663,15 +666,16 @@ enum Action {
Conclude,
}
async fn run<B, C>(
mut ctx: C,
async fn run<B, Context>(
mut ctx: Context,
mut subsystem: ApprovalVotingSubsystem,
clock: Box<dyn Clock + Send + Sync>,
assignment_criteria: Box<dyn AssignmentCriteria + Send + Sync>,
mut backend: B,
) -> SubsystemResult<()>
where
C: SubsystemContext<Message = ApprovalVotingMessage>,
Context: SubsystemContext<Message = ApprovalVotingMessage>,
Context: overseer::SubsystemContext<Message = ApprovalVotingMessage>,
B: Backend,
{
let mut state = State {
@@ -797,7 +801,7 @@ async fn run<B, C>(
//
// returns `true` if any of the actions was a `Conclude` command.
async fn handle_actions(
ctx: &mut impl SubsystemContext,
ctx: &mut (impl SubsystemContext<Message = ApprovalVotingMessage> + overseer::SubsystemContext<Message = ApprovalVotingMessage>),
state: &mut State,
overlayed_db: &mut OverlayedBackend<'_, impl Backend>,
metrics: &Metrics,
@@ -861,7 +865,7 @@ async fn handle_actions(
ctx.send_unbounded_message(ApprovalDistributionMessage::DistributeAssignment(
indirect_cert,
candidate_index,
).into());
));
match approvals_cache.get(&candidate_hash) {
Some(ApprovalOutcome::Approved) => {
@@ -902,14 +906,14 @@ async fn handle_actions(
}
}
Action::NoteApprovedInChainSelection(block_hash) => {
ctx.send_message(ChainSelectionMessage::Approved(block_hash).into()).await;
ctx.send_message(ChainSelectionMessage::Approved(block_hash)).await;
}
Action::BecomeActive => {
*mode = Mode::Active;
let messages = distribution_messages_for_activation(overlayed_db)?;
ctx.send_messages(messages.into_iter().map(Into::into)).await;
ctx.send_messages(messages.into_iter()).await;
}
Action::Conclude => { conclude = true; }
}
@@ -1017,7 +1021,7 @@ fn distribution_messages_for_activation(
// Handle an incoming signal from the overseer. Returns true if execution should conclude.
async fn handle_from_overseer(
ctx: &mut impl SubsystemContext,
ctx: &mut (impl SubsystemContext<Message = ApprovalVotingMessage> + overseer::SubsystemContext<Message = ApprovalVotingMessage>),
state: &mut State,
db: &mut OverlayedBackend<'_, impl Backend>,
metrics: &Metrics,
@@ -1130,7 +1134,7 @@ async fn handle_from_overseer(
}
async fn handle_approved_ancestor(
ctx: &mut impl SubsystemContext,
ctx: &mut (impl SubsystemContext + overseer::SubsystemContext),
db: &OverlayedBackend<'_, impl Backend>,
target: Hash,
lower_bound: BlockNumber,
@@ -1149,7 +1153,7 @@ async fn handle_approved_ancestor(
let target_number = {
let (tx, rx) = oneshot::channel();
ctx.send_message(ChainApiMessage::BlockNumber(target, tx).into()).await;
ctx.send_message(ChainApiMessage::BlockNumber(target, tx)).await;
match rx.await {
Ok(Ok(Some(n))) => n,
@@ -1173,7 +1177,7 @@ async fn handle_approved_ancestor(
hash: target,
k: (target_number - (lower_bound + 1)) as usize,
response_channel: tx,
}.into()).await;
}).await;
match rx.await {
Ok(Ok(a)) => a,
@@ -1994,7 +1998,7 @@ fn process_wakeup(
// spawned. When the background work is no longer needed, the `AbortHandle` should be dropped
// to cancel the background work and any requests it has spawned.
async fn launch_approval(
ctx: &mut impl SubsystemContext,
ctx: &mut (impl SubsystemContext<Message = ApprovalVotingMessage> + overseer::SubsystemContext<Message = ApprovalVotingMessage>),
metrics: Metrics,
session_index: SessionIndex,
candidate: CandidateReceipt,
@@ -2043,7 +2047,7 @@ async fn launch_approval(
session_index,
Some(backing_group),
a_tx,
).into()).await;
)).await;
ctx.send_message(
RuntimeApiMessage::Request(
@@ -2052,7 +2056,7 @@ async fn launch_approval(
candidate.descriptor.validation_code_hash,
code_tx,
),
).into()
)
).await;
let candidate = candidate.clone();
+34 -17
View File
@@ -37,7 +37,9 @@ use polkadot_node_primitives::{
ErasureChunk, AvailableData,
};
use polkadot_subsystem::{
FromOverseer, OverseerSignal, SubsystemError, Subsystem, SubsystemContext, SpawnedSubsystem,
FromOverseer, OverseerSignal, SubsystemError,
SubsystemContext, SpawnedSubsystem,
overseer,
ActiveLeavesUpdate,
errors::{ChainApiError, RuntimeApiError},
};
@@ -522,9 +524,10 @@ impl KnownUnfinalizedBlocks {
}
}
impl<Context> Subsystem<Context> for AvailabilityStoreSubsystem
impl<Context> overseer::Subsystem<Context, SubsystemError> for AvailabilityStoreSubsystem
where
Context: SubsystemContext<Message = AvailabilityStoreMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityStoreMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = run(self, ctx)
@@ -540,7 +543,8 @@ where
async fn run<Context>(mut subsystem: AvailabilityStoreSubsystem, mut ctx: Context)
where
Context: SubsystemContext<Message=AvailabilityStoreMessage>,
Context: SubsystemContext<Message = AvailabilityStoreMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityStoreMessage>,
{
let mut next_pruning = Delay::new(subsystem.pruning_config.pruning_interval).fuse();
@@ -570,7 +574,8 @@ async fn run_iteration<Context>(
)
-> Result<bool, Error>
where
Context: SubsystemContext<Message=AvailabilityStoreMessage>,
Context: SubsystemContext<Message = AvailabilityStoreMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityStoreMessage>,
{
select! {
incoming = ctx.recv().fuse() => {
@@ -615,18 +620,22 @@ where
Ok(false)
}
async fn process_block_activated(
ctx: &mut impl SubsystemContext,
async fn process_block_activated<Context>(
ctx: &mut Context,
subsystem: &mut AvailabilityStoreSubsystem,
activated: Hash,
) -> Result<(), Error> {
) -> Result<(), Error>
where
Context: SubsystemContext<Message = AvailabilityStoreMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityStoreMessage>,
{
let now = subsystem.clock.now()?;
let block_header = {
let (tx, rx) = oneshot::channel();
ctx.send_message(
ChainApiMessage::BlockHeader(activated, tx).into()
ChainApiMessage::BlockHeader(activated, tx)
).await;
match rx.await?? {
@@ -666,8 +675,8 @@ async fn process_block_activated(
Ok(())
}
async fn process_new_head(
ctx: &mut impl SubsystemContext,
async fn process_new_head<Context>(
ctx: &mut Context,
db: &Arc<dyn KeyValueDB>,
db_transaction: &mut DBTransaction,
config: &Config,
@@ -675,12 +684,16 @@ async fn process_new_head(
now: Duration,
hash: Hash,
header: Header,
) -> Result<(), Error> {
) -> Result<(), Error>
where
Context: SubsystemContext<Message = AvailabilityStoreMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityStoreMessage>,
{
let candidate_events = {
let (tx, rx) = oneshot::channel();
ctx.send_message(
RuntimeApiMessage::Request(hash, RuntimeApiRequest::CandidateEvents(tx)).into()
RuntimeApiMessage::Request(hash, RuntimeApiRequest::CandidateEvents(tx))
).await;
rx.await??
@@ -691,7 +704,7 @@ async fn process_new_head(
let n_validators = {
let (tx, rx) = oneshot::channel();
ctx.send_message(
RuntimeApiMessage::Request(header.parent_hash, RuntimeApiRequest::Validators(tx)).into()
RuntimeApiMessage::Request(header.parent_hash, RuntimeApiRequest::Validators(tx))
).await;
rx.await??.len()
@@ -835,12 +848,16 @@ macro_rules! peek_num {
}
}
async fn process_block_finalized(
ctx: &mut impl SubsystemContext,
async fn process_block_finalized<Context>(
ctx: &mut Context,
subsystem: &AvailabilityStoreSubsystem,
finalized_hash: Hash,
finalized_number: BlockNumber,
) -> Result<(), Error> {
) -> Result<(), Error>
where
Context: SubsystemContext<Message = AvailabilityStoreMessage>,
Context: overseer::SubsystemContext<Message = AvailabilityStoreMessage>,
{
let now = subsystem.clock.now()?;
let mut next_possible_batch = 0;
@@ -869,7 +886,7 @@ async fn process_block_finalized(
finalized_hash
} else {
let (tx, rx) = oneshot::channel();
ctx.send_message(ChainApiMessage::FinalizedBlockHash(batch_num, tx).into()).await;
ctx.send_message(ChainApiMessage::FinalizedBlockHash(batch_num, tx)).await;
match rx.await?? {
None => {
+16 -16
View File
@@ -37,6 +37,7 @@ use polkadot_node_primitives::{
use polkadot_subsystem::{
PerLeafSpan, Stage, SubsystemSender,
jaeger,
overseer,
messages::{
AllMessages, AvailabilityDistributionMessage, AvailabilityStoreMessage,
CandidateBackingMessage, CandidateValidationMessage, CollatorProtocolMessage,
@@ -308,7 +309,7 @@ async fn store_available_data(
n_validators,
available_data,
tx,
).into()).await;
)).await;
let _ = rx.await.map_err(Error::StoreAvailableData)?;
@@ -384,7 +385,7 @@ async fn request_pov(
candidate_hash,
pov_hash,
tx,
}.into()).await;
}).await;
let pov = rx.await.map_err(|_| Error::FetchPoV)?;
Ok(Arc::new(pov))
@@ -397,13 +398,12 @@ async fn request_candidate_validation(
) -> Result<ValidationResult, Error> {
let (tx, rx) = oneshot::channel();
sender.send_message(AllMessages::CandidateValidation(
CandidateValidationMessage::ValidateFromChainState(
candidate,
pov,
tx,
)
).into()
sender.send_message(
CandidateValidationMessage::ValidateFromChainState(
candidate,
pov,
tx,
)
).await;
match rx.await {
@@ -415,7 +415,7 @@ async fn request_candidate_validation(
type BackgroundValidationResult = Result<(CandidateReceipt, CandidateCommitments, Arc<PoV>), CandidateReceipt>;
struct BackgroundValidationParams<S, F> {
struct BackgroundValidationParams<S: overseer::SubsystemSender<AllMessages>, F> {
sender: JobSender<S>,
tx_command: mpsc::Sender<ValidatedCandidateCommand>,
candidate: CandidateReceipt,
@@ -600,14 +600,14 @@ impl CandidateBackingJob {
root_span,
).await? {
sender.send_message(
CollatorProtocolMessage::Seconded(self.parent, stmt).into()
CollatorProtocolMessage::Seconded(self.parent, stmt)
).await;
}
}
}
Err(candidate) => {
sender.send_message(
CollatorProtocolMessage::Invalid(self.parent, candidate).into()
CollatorProtocolMessage::Invalid(self.parent, candidate)
).await;
}
}
@@ -683,7 +683,7 @@ impl CandidateBackingJob {
.map_or(false, |c| c != &candidate.descriptor().collator)
{
sender.send_message(
CollatorProtocolMessage::Invalid(self.parent, candidate.clone()).into()
CollatorProtocolMessage::Invalid(self.parent, candidate.clone())
).await;
return Ok(());
}
@@ -732,7 +732,7 @@ impl CandidateBackingJob {
if let Some(signed_statement) = self.sign_statement(statement).await {
self.import_statement(sender, &signed_statement, root_span).await?;
let smsg = StatementDistributionMessage::Share(self.parent, signed_statement.clone());
sender.send_unbounded_message(smsg.into());
sender.send_unbounded_message(smsg);
Ok(Some(signed_statement))
} else {
@@ -749,7 +749,7 @@ impl CandidateBackingJob {
ProvisionerMessage::ProvisionableData(
self.parent,
ProvisionableData::MisbehaviorReport(self.parent, validator_id, report)
).into()
)
).await;
}
}
@@ -801,7 +801,7 @@ impl CandidateBackingJob {
self.parent,
ProvisionableData::BackedCandidate(backed.receipt()),
);
sender.send_message(message.into()).await;
sender.send_message(message).await;
span.as_ref().map(|s| s.child("backed"));
span
+5 -72
View File
@@ -38,10 +38,14 @@ use polkadot_primitives::v1::{AvailabilityBitfield, CoreState, Hash, ValidatorIn
use std::{pin::Pin, time::Duration, iter::FromIterator, sync::Arc};
use wasm_timer::{Delay, Instant};
#[cfg(test)]
mod tests;
/// Delay between starting a bitfield signing job and its attempting to create a bitfield.
const JOB_DELAY: Duration = Duration::from_millis(1500);
const LOG_TARGET: &str = "parachain::bitfield-signing";
/// Each `BitfieldSigningJob` prepares a signed bitfield for a single relay parent.
pub struct BitfieldSigningJob;
@@ -299,7 +303,7 @@ impl JobTrait for BitfieldSigningJob {
.send_message(BitfieldDistributionMessage::DistributeBitfield(
relay_parent,
signed_bitfield,
).into())
))
.await;
Ok(())
@@ -310,74 +314,3 @@ impl JobTrait for BitfieldSigningJob {
/// BitfieldSigningSubsystem manages a number of bitfield signing jobs.
pub type BitfieldSigningSubsystem<Spawner> = JobSubsystem<BitfieldSigningJob, Spawner>;
#[cfg(test)]
mod tests {
use super::*;
use futures::{pin_mut, executor::block_on};
use polkadot_primitives::v1::{CandidateHash, OccupiedCore};
use polkadot_node_subsystem::messages::AllMessages;
fn occupied_core(para_id: u32, candidate_hash: CandidateHash) -> CoreState {
CoreState::Occupied(OccupiedCore {
group_responsible: para_id.into(),
next_up_on_available: None,
occupied_since: 100_u32,
time_out_at: 200_u32,
next_up_on_time_out: None,
availability: Default::default(),
candidate_hash,
candidate_descriptor: Default::default(),
})
}
#[test]
fn construct_availability_bitfield_works() {
block_on(async move {
let relay_parent = Hash::default();
let validator_index = ValidatorIndex(1u32);
let (mut sender, mut receiver) = polkadot_node_subsystem_test_helpers::sender_receiver();
let future = construct_availability_bitfield(
relay_parent,
&jaeger::Span::Disabled,
validator_index,
&mut sender,
).fuse();
pin_mut!(future);
let hash_a = CandidateHash(Hash::repeat_byte(1));
let hash_b = CandidateHash(Hash::repeat_byte(2));
loop {
futures::select! {
m = receiver.next() => match m.unwrap() {
AllMessages::RuntimeApi(
RuntimeApiMessage::Request(rp, RuntimeApiRequest::AvailabilityCores(tx)),
) => {
assert_eq!(relay_parent, rp);
tx.send(Ok(vec![CoreState::Free, occupied_core(1, hash_a), occupied_core(2, hash_b)])).unwrap();
}
AllMessages::AvailabilityStore(
AvailabilityStoreMessage::QueryChunkAvailability(c_hash, vidx, tx),
) => {
assert_eq!(validator_index, vidx);
tx.send(c_hash == hash_a).unwrap();
},
o => panic!("Unknown message: {:?}", o),
},
r = future => match r {
Ok(r) => {
assert!(!r.0.get(0).unwrap());
assert!(r.0.get(1).unwrap());
assert!(!r.0.get(2).unwrap());
break
},
Err(e) => panic!("Failed: {:?}", e),
},
}
}
});
}
}
@@ -0,0 +1,83 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use super::*;
use futures::{pin_mut, executor::block_on};
use polkadot_primitives::v1::{CandidateHash, OccupiedCore};
use polkadot_node_subsystem::messages::AllMessages;
fn occupied_core(para_id: u32, candidate_hash: CandidateHash) -> CoreState {
CoreState::Occupied(OccupiedCore {
group_responsible: para_id.into(),
next_up_on_available: None,
occupied_since: 100_u32,
time_out_at: 200_u32,
next_up_on_time_out: None,
availability: Default::default(),
candidate_hash,
candidate_descriptor: Default::default(),
})
}
#[test]
fn construct_availability_bitfield_works() {
block_on(async move {
let relay_parent = Hash::default();
let validator_index = ValidatorIndex(1u32);
let (mut sender, mut receiver) = polkadot_node_subsystem_test_helpers::sender_receiver();
let future = construct_availability_bitfield(
relay_parent,
&jaeger::Span::Disabled,
validator_index,
&mut sender,
).fuse();
pin_mut!(future);
let hash_a = CandidateHash(Hash::repeat_byte(1));
let hash_b = CandidateHash(Hash::repeat_byte(2));
loop {
futures::select! {
m = receiver.next() => match m.unwrap() {
AllMessages::RuntimeApi(
RuntimeApiMessage::Request(rp, RuntimeApiRequest::AvailabilityCores(tx)),
) => {
assert_eq!(relay_parent, rp);
tx.send(Ok(vec![CoreState::Free, occupied_core(1, hash_a), occupied_core(2, hash_b)])).unwrap();
}
AllMessages::AvailabilityStore(
AvailabilityStoreMessage::QueryChunkAvailability(c_hash, vidx, tx),
) => {
assert_eq!(validator_index, vidx);
tx.send(c_hash == hash_a).unwrap();
},
o => panic!("Unknown message: {:?}", o),
},
r = future => match r {
Ok(r) => {
assert!(!r.0.get(0).unwrap());
assert!(r.0.get(1).unwrap());
assert!(!r.0.get(2).unwrap());
break
},
Err(e) => panic!("Failed: {:?}", e),
},
}
}
});
}
@@ -15,7 +15,7 @@ parity-scale-codec = { version = "2.0.0", default-features = false, features = [
polkadot-primitives = { path = "../../../primitives" }
polkadot-parachain = { path = "../../../parachain" }
polkadot-node-primitives = { path = "../../primitives" }
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
polkadot-node-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
[target.'cfg(not(any(target_os = "android", target_os = "unknown")))'.dependencies]
@@ -23,16 +23,17 @@
#![deny(unused_crate_dependencies, unused_results)]
#![warn(missing_docs)]
use polkadot_subsystem::{
Subsystem, SubsystemContext, SpawnedSubsystem, SubsystemResult, SubsystemError,
use polkadot_node_subsystem::{
overseer,
SubsystemContext, SpawnedSubsystem, SubsystemResult, SubsystemError,
FromOverseer, OverseerSignal,
messages::{
AllMessages, CandidateValidationMessage, RuntimeApiMessage,
CandidateValidationMessage, RuntimeApiMessage,
ValidationFailed, RuntimeApiRequest,
},
errors::RuntimeApiError,
};
use polkadot_node_subsystem_util::metrics::{self, prometheus};
use polkadot_subsystem::errors::RuntimeApiError;
use polkadot_node_primitives::{
VALIDATION_CODE_BOMB_LIMIT, POV_BOMB_LIMIT, ValidationResult, InvalidCandidate, PoV, BlockData,
};
@@ -84,10 +85,12 @@ impl CandidateValidationSubsystem {
}
}
impl<C> Subsystem<C> for CandidateValidationSubsystem where
C: SubsystemContext<Message = CandidateValidationMessage>,
impl<Context> overseer::Subsystem<Context, SubsystemError> for CandidateValidationSubsystem
where
Context: SubsystemContext<Message = CandidateValidationMessage>,
Context: overseer::SubsystemContext<Message = CandidateValidationMessage>,
{
fn start(self, ctx: C) -> SpawnedSubsystem {
fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = run(ctx, self.metrics, self.config.artifacts_cache_path, self.config.program_path)
.map_err(|e| SubsystemError::with_origin("candidate-validation", e))
.boxed();
@@ -98,12 +101,16 @@ impl<C> Subsystem<C> for CandidateValidationSubsystem where
}
}
async fn run(
mut ctx: impl SubsystemContext<Message = CandidateValidationMessage>,
async fn run<Context>(
mut ctx: Context,
metrics: Metrics,
cache_path: PathBuf,
program_path: PathBuf,
) -> SubsystemResult<()> {
) -> SubsystemResult<()>
where
Context: SubsystemContext<Message = CandidateValidationMessage>,
Context: overseer::SubsystemContext<Message = CandidateValidationMessage>,
{
let (mut validation_host, task) = polkadot_node_core_pvf::start(
polkadot_node_core_pvf::Config::new(cache_path, program_path),
);
@@ -174,17 +181,21 @@ async fn run(
}
}
async fn runtime_api_request<T>(
ctx: &mut impl SubsystemContext<Message = CandidateValidationMessage>,
async fn runtime_api_request<T, Context>(
ctx: &mut Context,
relay_parent: Hash,
request: RuntimeApiRequest,
receiver: oneshot::Receiver<Result<T, RuntimeApiError>>,
) -> SubsystemResult<Result<T, RuntimeApiError>> {
) -> SubsystemResult<Result<T, RuntimeApiError>>
where
Context: SubsystemContext<Message = CandidateValidationMessage>,
Context: overseer::SubsystemContext<Message = CandidateValidationMessage>,
{
ctx.send_message(
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
RuntimeApiMessage::Request(
relay_parent,
request,
))
)
).await;
receiver.await.map_err(Into::into)
@@ -197,11 +208,15 @@ enum AssumptionCheckOutcome {
BadRequest,
}
async fn check_assumption_validation_data(
ctx: &mut impl SubsystemContext<Message = CandidateValidationMessage>,
async fn check_assumption_validation_data<Context>(
ctx: &mut Context,
descriptor: &CandidateDescriptor,
assumption: OccupiedCoreAssumption,
) -> SubsystemResult<AssumptionCheckOutcome> {
) -> SubsystemResult<AssumptionCheckOutcome>
where
Context: SubsystemContext<Message = CandidateValidationMessage>,
Context: overseer::SubsystemContext<Message = CandidateValidationMessage>,
{
let validation_data = {
let (tx, rx) = oneshot::channel();
let d = runtime_api_request(
@@ -247,10 +262,14 @@ async fn check_assumption_validation_data(
})
}
async fn find_assumed_validation_data(
ctx: &mut impl SubsystemContext<Message = CandidateValidationMessage>,
async fn find_assumed_validation_data<Context>(
ctx: &mut Context,
descriptor: &CandidateDescriptor,
) -> SubsystemResult<AssumptionCheckOutcome> {
) -> SubsystemResult<AssumptionCheckOutcome>
where
Context: SubsystemContext<Message = CandidateValidationMessage>,
Context: overseer::SubsystemContext<Message = CandidateValidationMessage>,
{
// The candidate descriptor has a `persisted_validation_data_hash` which corresponds to
// one of up to two possible values that we can derive from the state of the
// relay-parent. We can fetch these values by getting the persisted validation data
@@ -278,13 +297,17 @@ async fn find_assumed_validation_data(
Ok(AssumptionCheckOutcome::DoesNotMatch)
}
async fn spawn_validate_from_chain_state(
ctx: &mut impl SubsystemContext<Message = CandidateValidationMessage>,
async fn spawn_validate_from_chain_state<Context>(
ctx: &mut Context,
validation_host: &mut ValidationHost,
descriptor: CandidateDescriptor,
pov: Arc<PoV>,
metrics: &Metrics,
) -> SubsystemResult<Result<ValidationResult, ValidationFailed>> {
) -> SubsystemResult<Result<ValidationResult, ValidationFailed>>
where
Context: SubsystemContext<Message = CandidateValidationMessage>,
Context: overseer::SubsystemContext<Message = CandidateValidationMessage>,
{
let (validation_data, validation_code) =
match find_assumed_validation_data(ctx, &descriptor).await? {
AssumptionCheckOutcome::Matches(validation_data, validation_code) => {
@@ -15,6 +15,7 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use super::*;
use polkadot_node_subsystem::messages::AllMessages;
use polkadot_node_subsystem_test_helpers as test_helpers;
use polkadot_primitives::v1::{HeadData, UpwardMessage};
use sp_core::testing::TaskExecutor;
+13 -313
View File
@@ -40,10 +40,15 @@ use sp_blockchain::HeaderBackend;
use polkadot_node_subsystem_util::metrics::{self, prometheus};
use polkadot_primitives::v1::{Block, BlockId};
use polkadot_subsystem::{
messages::ChainApiMessage, FromOverseer, OverseerSignal, SpawnedSubsystem, Subsystem,
overseer,
messages::ChainApiMessage,
FromOverseer, OverseerSignal, SpawnedSubsystem,
SubsystemContext, SubsystemError, SubsystemResult,
};
#[cfg(test)]
mod tests;
const LOG_TARGET: &str = "parachain::chain-api";
/// The Chain API Subsystem implementation.
@@ -62,13 +67,14 @@ impl<Client> ChainApiSubsystem<Client> {
}
}
impl<Client, Context> Subsystem<Context> for ChainApiSubsystem<Client>
impl<Client, Context> overseer::Subsystem<Context, SubsystemError> for ChainApiSubsystem<Client>
where
Client: HeaderBackend<Block> + AuxStore + 'static,
Context: SubsystemContext<Message = ChainApiMessage>,
Context: overseer::SubsystemContext<Message = ChainApiMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = run(ctx, self)
let future = run::<Client, Context>(ctx, self)
.map_err(|e| SubsystemError::with_origin("chain-api", e))
.boxed();
SpawnedSubsystem {
@@ -78,12 +84,14 @@ where
}
}
async fn run<Client>(
mut ctx: impl SubsystemContext<Message = ChainApiMessage>,
async fn run<Client, Context>(
mut ctx: Context,
subsystem: ChainApiSubsystem<Client>,
) -> SubsystemResult<()>
where
Client: HeaderBackend<Block> + AuxStore,
Context: SubsystemContext<Message = ChainApiMessage>,
Context: overseer::SubsystemContext<Message = ChainApiMessage>,
{
loop {
match ctx.recv().await? {
@@ -291,311 +299,3 @@ impl metrics::Metrics for Metrics {
Ok(Metrics(Some(metrics)))
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeMap;
use futures::{future::BoxFuture, channel::oneshot};
use parity_scale_codec::Encode;
use polkadot_primitives::v1::{Hash, BlockNumber, BlockId, Header};
use polkadot_node_primitives::BlockWeight;
use polkadot_node_subsystem_test_helpers::{make_subsystem_context, TestSubsystemContextHandle};
use sp_blockchain::Info as BlockInfo;
use sp_core::testing::TaskExecutor;
#[derive(Clone)]
struct TestClient {
blocks: BTreeMap<Hash, BlockNumber>,
block_weights: BTreeMap<Hash, BlockWeight>,
finalized_blocks: BTreeMap<BlockNumber, Hash>,
headers: BTreeMap<Hash, Header>,
}
const ONE: Hash = Hash::repeat_byte(0x01);
const TWO: Hash = Hash::repeat_byte(0x02);
const THREE: Hash = Hash::repeat_byte(0x03);
const FOUR: Hash = Hash::repeat_byte(0x04);
const ERROR_PATH: Hash = Hash::repeat_byte(0xFF);
fn default_header() -> Header {
Header {
parent_hash: Hash::zero(),
number: 100500,
state_root: Hash::zero(),
extrinsics_root: Hash::zero(),
digest: Default::default(),
}
}
impl Default for TestClient {
fn default() -> Self {
Self {
blocks: maplit::btreemap! {
ONE => 1,
TWO => 2,
THREE => 3,
FOUR => 4,
},
block_weights: maplit::btreemap! {
ONE => 0,
TWO => 1,
THREE => 1,
FOUR => 2,
},
finalized_blocks: maplit::btreemap! {
1 => ONE,
3 => THREE,
},
headers: maplit::btreemap! {
TWO => Header {
parent_hash: ONE,
number: 2,
..default_header()
},
THREE => Header {
parent_hash: TWO,
number: 3,
..default_header()
},
FOUR => Header {
parent_hash: THREE,
number: 4,
..default_header()
},
ERROR_PATH => Header {
..default_header()
}
},
}
}
}
fn last_key_value<K: Clone, V: Clone>(map: &BTreeMap<K, V>) -> (K, V) {
assert!(!map.is_empty());
map.iter()
.last()
.map(|(k, v)| (k.clone(), v.clone()))
.unwrap()
}
impl HeaderBackend<Block> for TestClient {
fn info(&self) -> BlockInfo<Block> {
let genesis_hash = self.blocks.iter().next().map(|(h, _)| *h).unwrap();
let (best_hash, best_number) = last_key_value(&self.blocks);
let (finalized_number, finalized_hash) = last_key_value(&self.finalized_blocks);
BlockInfo {
best_hash,
best_number,
genesis_hash,
finalized_hash,
finalized_number,
number_leaves: 0,
finalized_state: None,
}
}
fn number(&self, hash: Hash) -> sp_blockchain::Result<Option<BlockNumber>> {
Ok(self.blocks.get(&hash).copied())
}
fn hash(&self, number: BlockNumber) -> sp_blockchain::Result<Option<Hash>> {
Ok(self.finalized_blocks.get(&number).copied())
}
fn header(&self, id: BlockId) -> sp_blockchain::Result<Option<Header>> {
match id {
// for error path testing
BlockId::Hash(hash) if hash.is_zero() => {
Err(sp_blockchain::Error::Backend("Zero hashes are illegal!".into()))
}
BlockId::Hash(hash) => {
Ok(self.headers.get(&hash).cloned())
}
_ => unreachable!(),
}
}
fn status(&self, _id: BlockId) -> sp_blockchain::Result<sp_blockchain::BlockStatus> {
unimplemented!()
}
}
fn test_harness(
test: impl FnOnce(Arc<TestClient>, TestSubsystemContextHandle<ChainApiMessage>)
-> BoxFuture<'static, ()>,
) {
let (ctx, ctx_handle) = make_subsystem_context(TaskExecutor::new());
let client = Arc::new(TestClient::default());
let subsystem = ChainApiSubsystem::new(client.clone(), Metrics(None));
let chain_api_task = run(ctx, subsystem).map(|x| x.unwrap());
let test_task = test(client, ctx_handle);
futures::executor::block_on(future::join(chain_api_task, test_task));
}
impl AuxStore for TestClient {
fn insert_aux<
'a,
'b: 'a,
'c: 'a,
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
D: IntoIterator<Item = &'a &'b [u8]>,
>(
&self,
_insert: I,
_delete: D,
) -> sp_blockchain::Result<()> {
unimplemented!()
}
fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>> {
Ok(self
.block_weights
.iter()
.find(|(hash, _)| sc_consensus_babe::aux_schema::block_weight_key(hash) == key)
.map(|(_, weight)| weight.encode()))
}
}
#[test]
fn request_block_number() {
test_harness(|client, mut sender| {
async move {
let zero = Hash::zero();
let test_cases = [
(TWO, client.number(TWO).unwrap()),
(zero, client.number(zero).unwrap()), // not here
];
for (hash, expected) in &test_cases {
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::BlockNumber(*hash, tx),
}).await;
assert_eq!(rx.await.unwrap().unwrap(), *expected);
}
sender.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}.boxed()
})
}
#[test]
fn request_block_header() {
test_harness(|client, mut sender| {
async move {
const NOT_HERE: Hash = Hash::repeat_byte(0x5);
let test_cases = [
(TWO, client.header(BlockId::Hash(TWO)).unwrap()),
(NOT_HERE, client.header(BlockId::Hash(NOT_HERE)).unwrap()),
];
for (hash, expected) in &test_cases {
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::BlockHeader(*hash, tx),
}).await;
assert_eq!(rx.await.unwrap().unwrap(), *expected);
}
sender.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}.boxed()
})
}
#[test]
fn request_block_weight() {
test_harness(|client, mut sender| {
async move {
const NOT_HERE: Hash = Hash::repeat_byte(0x5);
let test_cases = [
(TWO, sc_consensus_babe::block_weight(&*client, TWO).unwrap()),
(FOUR, sc_consensus_babe::block_weight(&*client, FOUR).unwrap()),
(NOT_HERE, sc_consensus_babe::block_weight(&*client, NOT_HERE).unwrap()),
];
for (hash, expected) in &test_cases {
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::BlockWeight(*hash, tx),
}).await;
assert_eq!(rx.await.unwrap().unwrap(), *expected);
}
sender.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}.boxed()
})
}
#[test]
fn request_finalized_hash() {
test_harness(|client, mut sender| {
async move {
let test_cases = [
(1, client.hash(1).unwrap()), // not here
(2, client.hash(2).unwrap()),
];
for (number, expected) in &test_cases {
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::FinalizedBlockHash(*number, tx),
}).await;
assert_eq!(rx.await.unwrap().unwrap(), *expected);
}
sender.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}.boxed()
})
}
#[test]
fn request_last_finalized_number() {
test_harness(|client, mut sender| {
async move {
let (tx, rx) = oneshot::channel();
let expected = client.info().finalized_number;
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::FinalizedBlockNumber(tx),
}).await;
assert_eq!(rx.await.unwrap().unwrap(), expected);
sender.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}.boxed()
})
}
#[test]
fn request_ancestors() {
test_harness(|_client, mut sender| {
async move {
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::Ancestors { hash: THREE, k: 4, response_channel: tx },
}).await;
assert_eq!(rx.await.unwrap().unwrap(), vec![TWO, ONE]);
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::Ancestors { hash: TWO, k: 1, response_channel: tx },
}).await;
assert_eq!(rx.await.unwrap().unwrap(), vec![ONE]);
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::Ancestors { hash: ERROR_PATH, k: 2, response_channel: tx },
}).await;
assert!(rx.await.unwrap().is_err());
sender.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}.boxed()
})
}
}
+304
View File
@@ -0,0 +1,304 @@
use super::*;
use std::collections::BTreeMap;
use futures::{future::BoxFuture, channel::oneshot};
use parity_scale_codec::Encode;
use polkadot_primitives::v1::{Hash, BlockNumber, BlockId, Header};
use polkadot_node_primitives::BlockWeight;
use polkadot_node_subsystem_test_helpers::{make_subsystem_context, TestSubsystemContextHandle};
use sp_blockchain::Info as BlockInfo;
use sp_core::testing::TaskExecutor;
#[derive(Clone)]
struct TestClient {
blocks: BTreeMap<Hash, BlockNumber>,
block_weights: BTreeMap<Hash, BlockWeight>,
finalized_blocks: BTreeMap<BlockNumber, Hash>,
headers: BTreeMap<Hash, Header>,
}
const ONE: Hash = Hash::repeat_byte(0x01);
const TWO: Hash = Hash::repeat_byte(0x02);
const THREE: Hash = Hash::repeat_byte(0x03);
const FOUR: Hash = Hash::repeat_byte(0x04);
const ERROR_PATH: Hash = Hash::repeat_byte(0xFF);
fn default_header() -> Header {
Header {
parent_hash: Hash::zero(),
number: 100500,
state_root: Hash::zero(),
extrinsics_root: Hash::zero(),
digest: Default::default(),
}
}
impl Default for TestClient {
fn default() -> Self {
Self {
blocks: maplit::btreemap! {
ONE => 1,
TWO => 2,
THREE => 3,
FOUR => 4,
},
block_weights: maplit::btreemap! {
ONE => 0,
TWO => 1,
THREE => 1,
FOUR => 2,
},
finalized_blocks: maplit::btreemap! {
1 => ONE,
3 => THREE,
},
headers: maplit::btreemap! {
TWO => Header {
parent_hash: ONE,
number: 2,
..default_header()
},
THREE => Header {
parent_hash: TWO,
number: 3,
..default_header()
},
FOUR => Header {
parent_hash: THREE,
number: 4,
..default_header()
},
ERROR_PATH => Header {
..default_header()
}
},
}
}
}
fn last_key_value<K: Clone, V: Clone>(map: &BTreeMap<K, V>) -> (K, V) {
assert!(!map.is_empty());
map.iter()
.last()
.map(|(k, v)| (k.clone(), v.clone()))
.unwrap()
}
impl HeaderBackend<Block> for TestClient {
fn info(&self) -> BlockInfo<Block> {
let genesis_hash = self.blocks.iter().next().map(|(h, _)| *h).unwrap();
let (best_hash, best_number) = last_key_value(&self.blocks);
let (finalized_number, finalized_hash) = last_key_value(&self.finalized_blocks);
BlockInfo {
best_hash,
best_number,
genesis_hash,
finalized_hash,
finalized_number,
number_leaves: 0,
finalized_state: None,
}
}
fn number(&self, hash: Hash) -> sp_blockchain::Result<Option<BlockNumber>> {
Ok(self.blocks.get(&hash).copied())
}
fn hash(&self, number: BlockNumber) -> sp_blockchain::Result<Option<Hash>> {
Ok(self.finalized_blocks.get(&number).copied())
}
fn header(&self, id: BlockId) -> sp_blockchain::Result<Option<Header>> {
match id {
// for error path testing
BlockId::Hash(hash) if hash.is_zero() => {
Err(sp_blockchain::Error::Backend("Zero hashes are illegal!".into()))
}
BlockId::Hash(hash) => {
Ok(self.headers.get(&hash).cloned())
}
_ => unreachable!(),
}
}
fn status(&self, _id: BlockId) -> sp_blockchain::Result<sp_blockchain::BlockStatus> {
unimplemented!()
}
}
fn test_harness(
test: impl FnOnce(Arc<TestClient>, TestSubsystemContextHandle<ChainApiMessage>)
-> BoxFuture<'static, ()>,
) {
let (ctx, ctx_handle) = make_subsystem_context(TaskExecutor::new());
let client = Arc::new(TestClient::default());
let subsystem = ChainApiSubsystem::new(client.clone(), Metrics(None));
let chain_api_task = run(ctx, subsystem).map(|x| x.unwrap());
let test_task = test(client, ctx_handle);
futures::executor::block_on(future::join(chain_api_task, test_task));
}
impl AuxStore for TestClient {
fn insert_aux<
'a,
'b: 'a,
'c: 'a,
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
D: IntoIterator<Item = &'a &'b [u8]>,
>(
&self,
_insert: I,
_delete: D,
) -> sp_blockchain::Result<()> {
unimplemented!()
}
fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>> {
Ok(self
.block_weights
.iter()
.find(|(hash, _)| sc_consensus_babe::aux_schema::block_weight_key(hash) == key)
.map(|(_, weight)| weight.encode()))
}
}
#[test]
fn request_block_number() {
test_harness(|client, mut sender| {
async move {
let zero = Hash::zero();
let test_cases = [
(TWO, client.number(TWO).unwrap()),
(zero, client.number(zero).unwrap()), // not here
];
for (hash, expected) in &test_cases {
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::BlockNumber(*hash, tx),
}).await;
assert_eq!(rx.await.unwrap().unwrap(), *expected);
}
sender.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}.boxed()
})
}
#[test]
fn request_block_header() {
test_harness(|client, mut sender| {
async move {
const NOT_HERE: Hash = Hash::repeat_byte(0x5);
let test_cases = [
(TWO, client.header(BlockId::Hash(TWO)).unwrap()),
(NOT_HERE, client.header(BlockId::Hash(NOT_HERE)).unwrap()),
];
for (hash, expected) in &test_cases {
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::BlockHeader(*hash, tx),
}).await;
assert_eq!(rx.await.unwrap().unwrap(), *expected);
}
sender.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}.boxed()
})
}
#[test]
fn request_block_weight() {
test_harness(|client, mut sender| {
async move {
const NOT_HERE: Hash = Hash::repeat_byte(0x5);
let test_cases = [
(TWO, sc_consensus_babe::block_weight(&*client, TWO).unwrap()),
(FOUR, sc_consensus_babe::block_weight(&*client, FOUR).unwrap()),
(NOT_HERE, sc_consensus_babe::block_weight(&*client, NOT_HERE).unwrap()),
];
for (hash, expected) in &test_cases {
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::BlockWeight(*hash, tx),
}).await;
assert_eq!(rx.await.unwrap().unwrap(), *expected);
}
sender.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}.boxed()
})
}
#[test]
fn request_finalized_hash() {
test_harness(|client, mut sender| {
async move {
let test_cases = [
(1, client.hash(1).unwrap()), // not here
(2, client.hash(2).unwrap()),
];
for (number, expected) in &test_cases {
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::FinalizedBlockHash(*number, tx),
}).await;
assert_eq!(rx.await.unwrap().unwrap(), *expected);
}
sender.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}.boxed()
})
}
#[test]
fn request_last_finalized_number() {
test_harness(|client, mut sender| {
async move {
let (tx, rx) = oneshot::channel();
let expected = client.info().finalized_number;
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::FinalizedBlockNumber(tx),
}).await;
assert_eq!(rx.await.unwrap().unwrap(), expected);
sender.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}.boxed()
})
}
#[test]
fn request_ancestors() {
test_harness(|_client, mut sender| {
async move {
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::Ancestors { hash: THREE, k: 4, response_channel: tx },
}).await;
assert_eq!(rx.await.unwrap().unwrap(), vec![TWO, ONE]);
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::Ancestors { hash: TWO, k: 1, response_channel: tx },
}).await;
assert_eq!(rx.await.unwrap().unwrap(), vec![ONE]);
let (tx, rx) = oneshot::channel();
sender.send(FromOverseer::Communication {
msg: ChainApiMessage::Ancestors { hash: ERROR_PATH, k: 2, response_channel: tx },
}).await;
assert!(rx.await.unwrap().is_err());
sender.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}.boxed()
})
}
@@ -11,7 +11,7 @@ futures-timer = "3"
tracing = "0.1.26"
polkadot-primitives = { path = "../../../primitives" }
polkadot-node-primitives = { path = "../../primitives" }
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
polkadot-node-subsystem = { path = "../../subsystem" }
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
kvdb = "0.10.0"
thiserror = "1.0.23"
+12 -8
View File
@@ -18,8 +18,8 @@
use polkadot_primitives::v1::{BlockNumber, Hash, Header, ConsensusLog};
use polkadot_node_primitives::BlockWeight;
use polkadot_subsystem::{
Subsystem, SubsystemContext, SubsystemError, SpawnedSubsystem,
use polkadot_node_subsystem::{
overseer, SubsystemContext, SubsystemError, SpawnedSubsystem,
OverseerSignal, FromOverseer,
messages::{ChainSelectionMessage, ChainApiMessage},
errors::ChainApiError,
@@ -306,8 +306,10 @@ impl ChainSelectionSubsystem {
}
}
impl<Context> Subsystem<Context> for ChainSelectionSubsystem
where Context: SubsystemContext<Message = ChainSelectionMessage>
impl<Context> overseer::Subsystem<Context, SubsystemError> for ChainSelectionSubsystem
where
Context: SubsystemContext<Message = ChainSelectionMessage>,
Context: overseer::SubsystemContext<Message = ChainSelectionMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem {
let backend = crate::db_backend::v1::DbBackend::new(
@@ -337,6 +339,7 @@ async fn run<Context, B>(
)
where
Context: SubsystemContext<Message = ChainSelectionMessage>,
Context: overseer::SubsystemContext<Message = ChainSelectionMessage>,
B: Backend,
{
loop {
@@ -376,6 +379,7 @@ async fn run_iteration<Context, B>(
-> Result<(), Error>
where
Context: SubsystemContext<Message = ChainSelectionMessage>,
Context: overseer::SubsystemContext<Message = ChainSelectionMessage>,
B: Backend,
{
let mut stagnant_check_stream = stagnant_check_interval.timeout_stream();
@@ -439,11 +443,11 @@ async fn fetch_finalized(
let (number_tx, number_rx) = oneshot::channel();
let (hash_tx, hash_rx) = oneshot::channel();
ctx.send_message(ChainApiMessage::FinalizedBlockNumber(number_tx).into()).await;
ctx.send_message(ChainApiMessage::FinalizedBlockNumber(number_tx)).await;
let number = number_rx.await??;
ctx.send_message(ChainApiMessage::FinalizedBlockHash(number, hash_tx).into()).await;
ctx.send_message(ChainApiMessage::FinalizedBlockHash(number, hash_tx)).await;
match hash_rx.await?? {
None => {
@@ -464,7 +468,7 @@ async fn fetch_header(
hash: Hash,
) -> Result<Option<Header>, Error> {
let (h_tx, h_rx) = oneshot::channel();
ctx.send_message(ChainApiMessage::BlockHeader(hash, h_tx).into()).await;
ctx.send_message(ChainApiMessage::BlockHeader(hash, h_tx)).await;
h_rx.await?.map_err(Into::into)
}
@@ -474,7 +478,7 @@ async fn fetch_block_weight(
hash: Hash,
) -> Result<Option<BlockWeight>, Error> {
let (tx, rx) = oneshot::channel();
ctx.send_message(ChainApiMessage::BlockWeight(hash, tx).into()).await;
ctx.send_message(ChainApiMessage::BlockWeight(hash, tx)).await;
rx.await?.map_err(Into::into)
}
@@ -31,8 +31,11 @@ use sp_core::testing::TaskExecutor;
use assert_matches::assert_matches;
use polkadot_primitives::v1::{BlakeTwo256, HashT, ConsensusLog};
use polkadot_subsystem::{jaeger, ActiveLeavesUpdate, ActivatedLeaf, LeafStatus};
use polkadot_subsystem::messages::AllMessages;
use polkadot_node_subsystem::{
messages::AllMessages,
jaeger,
ActiveLeavesUpdate, ActivatedLeaf, LeafStatus,
};
use polkadot_node_subsystem_test_helpers as test_helpers;
#[derive(Default)]
@@ -30,10 +30,11 @@ use std::sync::Arc;
use polkadot_node_primitives::{CandidateVotes, SignedDisputeStatement};
use polkadot_node_subsystem::{
overseer,
messages::{
DisputeCoordinatorMessage, ChainApiMessage, DisputeParticipationMessage,
},
Subsystem, SubsystemContext, FromOverseer, OverseerSignal, SpawnedSubsystem,
SubsystemContext, FromOverseer, OverseerSignal, SpawnedSubsystem,
SubsystemError,
errors::{ChainApiError, RuntimeApiError},
};
@@ -101,8 +102,10 @@ impl DisputeCoordinatorSubsystem {
}
}
impl<Context> Subsystem<Context> for DisputeCoordinatorSubsystem
where Context: SubsystemContext<Message = DisputeCoordinatorMessage>
impl<Context> overseer::Subsystem<Context, SubsystemError> for DisputeCoordinatorSubsystem
where
Context: SubsystemContext<Message = DisputeCoordinatorMessage>,
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = run(self, ctx)
@@ -160,7 +163,9 @@ impl Error {
}
async fn run<Context>(subsystem: DisputeCoordinatorSubsystem, mut ctx: Context)
where Context: SubsystemContext<Message = DisputeCoordinatorMessage>
where
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>,
Context: SubsystemContext<Message = DisputeCoordinatorMessage>
{
loop {
let res = run_iteration(&mut ctx, &subsystem).await;
@@ -187,7 +192,9 @@ async fn run<Context>(subsystem: DisputeCoordinatorSubsystem, mut ctx: Context)
// lead to another call to this function.
async fn run_iteration<Context>(ctx: &mut Context, subsystem: &DisputeCoordinatorSubsystem)
-> Result<(), Error>
where Context: SubsystemContext<Message = DisputeCoordinatorMessage>
where
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>,
Context: SubsystemContext<Message = DisputeCoordinatorMessage>
{
let DisputeCoordinatorSubsystem { ref store, ref keystore, ref config } = *subsystem;
let mut state = State {
@@ -225,7 +232,7 @@ async fn run_iteration<Context>(ctx: &mut Context, subsystem: &DisputeCoordinato
}
async fn handle_new_activations(
ctx: &mut impl SubsystemContext,
ctx: &mut (impl SubsystemContext<Message = DisputeCoordinatorMessage> + overseer::SubsystemContext<Message = DisputeCoordinatorMessage>),
store: &dyn KeyValueDB,
state: &mut State,
config: &Config,
@@ -236,7 +243,7 @@ async fn handle_new_activations(
let (tx, rx) = oneshot::channel();
ctx.send_message(
ChainApiMessage::BlockHeader(new_leaf, tx).into()
ChainApiMessage::BlockHeader(new_leaf, tx)
).await;
match rx.await?? {
@@ -488,7 +495,7 @@ async fn handle_import_statements(
candidate_receipt,
session,
n_validators: n_validators as u32,
}.into()).await;
}).await;
}
if concluded_valid && already_disputed {
@@ -26,12 +26,13 @@ use futures::prelude::*;
use polkadot_node_primitives::ValidationResult;
use polkadot_node_subsystem::{
errors::{RecoveryError, RuntimeApiError},
overseer,
messages::{
AllMessages, AvailabilityRecoveryMessage, AvailabilityStoreMessage,
AvailabilityRecoveryMessage, AvailabilityStoreMessage,
CandidateValidationMessage, DisputeCoordinatorMessage, DisputeParticipationMessage,
RuntimeApiMessage, RuntimeApiRequest,
},
ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, Subsystem,
ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem,
SubsystemContext, SubsystemError,
};
use polkadot_primitives::v1::{BlockNumber, CandidateHash, CandidateReceipt, Hash, SessionIndex};
@@ -55,9 +56,10 @@ impl DisputeParticipationSubsystem {
}
}
impl<Context> Subsystem<Context> for DisputeParticipationSubsystem
impl<Context> overseer::Subsystem<Context, SubsystemError> for DisputeParticipationSubsystem
where
Context: SubsystemContext<Message = DisputeParticipationMessage>,
Context: overseer::SubsystemContext<Message = DisputeParticipationMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem {
let future = run(ctx).map(|_| Ok(())).boxed();
@@ -111,6 +113,7 @@ impl Error {
async fn run<Context>(mut ctx: Context)
where
Context: SubsystemContext<Message = DisputeParticipationMessage>,
Context: overseer::SubsystemContext<Message = DisputeParticipationMessage>,
{
let mut state = State { recent_block: None };
@@ -196,7 +199,6 @@ async fn participate(
None,
recover_available_data_tx,
)
.into(),
)
.await;
@@ -223,7 +225,6 @@ async fn participate(
code_tx,
),
)
.into(),
)
.await;
@@ -252,7 +253,6 @@ async fn participate(
available_data.clone(),
store_available_data_tx,
)
.into(),
)
.await;
@@ -277,7 +277,6 @@ async fn participate(
available_data.pov,
validation_tx,
)
.into(),
)
.await;
@@ -360,13 +359,13 @@ async fn issue_local_statement(
session: SessionIndex,
valid: bool,
) {
ctx.send_message(AllMessages::DisputeCoordinator(
ctx.send_message(
DisputeCoordinatorMessage::IssueLocalStatement(
session,
candidate_hash,
candidate_receipt,
valid,
),
))
)
.await
}
@@ -24,7 +24,8 @@ use super::*;
use parity_scale_codec::Encode;
use polkadot_node_primitives::{AvailableData, BlockData, InvalidCandidate, PoV};
use polkadot_node_subsystem::{
jaeger, messages::ValidationFailed, ActivatedLeaf, ActiveLeavesUpdate, LeafStatus,
overseer::Subsystem,
jaeger, messages::{AllMessages, ValidationFailed}, ActivatedLeaf, ActiveLeavesUpdate, LeafStatus,
};
use polkadot_node_subsystem_test_helpers::{make_subsystem_context, TestSubsystemContextHandle};
use polkadot_primitives::v1::{BlakeTwo256, CandidateCommitments, HashT, Header, ValidationCode};
@@ -11,7 +11,6 @@ tracing = "0.1.26"
thiserror = "1.0.23"
async-trait = "0.1.47"
polkadot-node-subsystem = { path = "../../subsystem" }
polkadot-overseer = { path = "../../overseer" }
polkadot-primitives = { path = "../../../primitives" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -26,9 +26,9 @@
use futures::{select, FutureExt};
use polkadot_node_subsystem::{
messages::{AllMessages, ProvisionerMessage}, SubsystemError,
overseer::Handle,
messages::ProvisionerMessage, errors::SubsystemError,
};
use polkadot_overseer::OverseerHandler;
use polkadot_primitives::v1::{
Block, Hash, InherentData as ParachainsInherentData,
};
@@ -48,19 +48,17 @@ impl ParachainsInherentDataProvider {
/// Create a new instance of the [`ParachainsInherentDataProvider`].
pub async fn create<C: HeaderBackend<Block>>(
client: &C,
mut overseer: OverseerHandler,
mut overseer: Handle,
parent: Hash,
) -> Result<Self, Error> {
let pid = async {
let (sender, receiver) = futures::channel::oneshot::channel();
overseer.wait_for_activation(parent, sender).await;
receiver.await.map_err(|_| Error::ClosedChannelAwaitingActivation)?.map_err(Error::Subsystem)?;
receiver.await.map_err(|_| Error::ClosedChannelAwaitingActivation)?.map_err(|e| Error::Subsystem(e))?;
let (sender, receiver) = futures::channel::oneshot::channel();
overseer.send_msg(
AllMessages::Provisioner(
ProvisionerMessage::RequestInherentData(parent, sender),
),
ProvisionerMessage::RequestInherentData(parent, sender),
std::any::type_name::<Self>(),
).await;
@@ -127,7 +125,7 @@ impl sp_inherents::InherentDataProvider for ParachainsInherentDataProvider {
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Blockchain error")]
Blockchain(sp_blockchain::Error),
Blockchain(#[from] sp_blockchain::Error),
#[error("Timeout: provisioner did not return inherent data after {:?}", PROVISIONER_TIMEOUT)]
Timeout,
#[error("Could not find the parent header in the blockchain: {:?}", _0)]
@@ -137,5 +135,5 @@ pub enum Error {
#[error("Closed channel from provisioner when awaiting inherent data")]
ClosedChannelAwaitingInherentData,
#[error("Subsystem failed")]
Subsystem(SubsystemError),
Subsystem(#[from] SubsystemError),
}
+12 -7
View File
@@ -23,12 +23,14 @@
#![warn(missing_docs)]
use polkadot_subsystem::{
Subsystem, SpawnedSubsystem, SubsystemResult, SubsystemContext,
FromOverseer, OverseerSignal,
SubsystemError, SubsystemResult,
FromOverseer, OverseerSignal, SpawnedSubsystem,
SubsystemContext,
errors::RuntimeApiError,
messages::{
RuntimeApiMessage, RuntimeApiRequest as Request,
},
errors::RuntimeApiError,
overseer,
};
use polkadot_node_subsystem_util::metrics::{self, prometheus};
use polkadot_primitives::v1::{Block, BlockId, Hash, ParachainHost};
@@ -85,10 +87,11 @@ impl<Client> RuntimeApiSubsystem<Client> {
}
}
impl<Client, Context> Subsystem<Context> for RuntimeApiSubsystem<Client> where
impl<Client, Context> overseer::Subsystem<Context, SubsystemError> for RuntimeApiSubsystem<Client> where
Client: ProvideRuntimeApi<Block> + Send + 'static + Sync,
Client::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
Context: SubsystemContext<Message = RuntimeApiMessage>
Context: SubsystemContext<Message = RuntimeApiMessage>,
Context: overseer::SubsystemContext<Message = RuntimeApiMessage>,
{
fn start(self, ctx: Context) -> SpawnedSubsystem {
SpawnedSubsystem {
@@ -265,12 +268,14 @@ impl<Client> RuntimeApiSubsystem<Client> where
}
}
async fn run<Client>(
mut ctx: impl SubsystemContext<Message = RuntimeApiMessage>,
async fn run<Client, Context>(
mut ctx: Context,
mut subsystem: RuntimeApiSubsystem<Client>,
) -> SubsystemResult<()> where
Client: ProvideRuntimeApi<Block> + Send + Sync + 'static,
Client::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
Context: SubsystemContext<Message = RuntimeApiMessage>,
Context: overseer::SubsystemContext<Message = RuntimeApiMessage>,
{
loop {
select! {