mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-23 09:41:07 +00:00
ICMP message-routing gossip (#304)
* core logic for ICMP gossip * refactor gossip to make more extension friendly * move files aroun * extract attestation-gossip logic to its own module * message validation and broadcast logic * fix upstream crates' compilation * add a test * another test for overlapping * Some grammar and phrasing tweaks Co-Authored-By: Luke Schoen <ltfschoen@users.noreply.github.com> * add since parameter to ingress runtime API * broadcast out known unrouted message queues * fix compilation of service and collator * remove useless index_mapping * some tests for icmp propagation * fix decoding bug and test icmp queue validation * simplify engine-id definition Co-Authored-By: Sergei Pepyakin <sergei@parity.io> * address some grumbles * some cleanup of old circulation code * give network a handle to extrinsic store on startup * an honest collator ensures data available as well * address some grumbles * add docs; rename the attestation session to "leaf work" * module docs * move gossip back to gossip.rs * clean up and document attestation-gossip a bit * some more docs on the availability store * store all outgoing message queues in the availability store * filter `Extrinsic` out of validation crate * expunge Extrinsic from network * expunge Extrinsic from erasure-coding * expunge Extrinsic from collator * expunge from adder-collator * rename ExtrinsicStore to AvailabilityStore everywhere * annotate and clean up message-routing tests
This commit is contained in:
committed by
GitHub
parent
bd8ebbfee5
commit
55c4c830fe
@@ -14,29 +14,24 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! The "validation session" networking code built on top of the base network service.
|
||||
//! The "validation leaf work" networking code built on top of the base network service.
|
||||
//!
|
||||
//! This fulfills the `polkadot_validation::Network` trait, providing a hook to be called
|
||||
//! each time a validation session begins on a new chain head.
|
||||
//! each time validation leaf work begins on a new chain head.
|
||||
|
||||
use crate::gossip::GossipMessage;
|
||||
use sr_primitives::traits::ProvideRuntimeApi;
|
||||
use substrate_network::{PeerId, Context as NetContext};
|
||||
use substrate_network::consensus_gossip::{
|
||||
self, TopicNotification, MessageRecipient as GossipMessageRecipient, ConsensusMessage,
|
||||
};
|
||||
use substrate_network::PeerId;
|
||||
use polkadot_validation::{
|
||||
Network as ParachainNetwork, SharedTable, Collators, Statement, GenericStatement, SignedStatement,
|
||||
};
|
||||
use polkadot_primitives::{Block, BlockId, Hash};
|
||||
use polkadot_primitives::parachain::{
|
||||
Id as ParaId, Collation, Extrinsic, ParachainHost, CandidateReceipt, CollatorId,
|
||||
ValidatorId, PoVBlock, ValidatorIndex
|
||||
Id as ParaId, Collation, OutgoingMessages, ParachainHost, CandidateReceipt, CollatorId,
|
||||
ValidatorId, PoVBlock
|
||||
};
|
||||
|
||||
use futures::prelude::*;
|
||||
use futures::future::{self, Executor as FutureExecutor};
|
||||
use futures::sync::mpsc;
|
||||
use futures::sync::oneshot::{self, Receiver};
|
||||
|
||||
use std::collections::hash_map::{HashMap, Entry};
|
||||
@@ -45,17 +40,15 @@ use std::sync::Arc;
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use parking_lot::Mutex;
|
||||
use log::{debug, warn};
|
||||
use log::warn;
|
||||
|
||||
use crate::router::Router;
|
||||
use crate::gossip::{POLKADOT_ENGINE_ID, RegisteredMessageValidator, MessageValidationData};
|
||||
use crate::gossip::{RegisteredMessageValidator, MessageValidationData};
|
||||
|
||||
use super::PolkadotProtocol;
|
||||
use super::NetworkService;
|
||||
|
||||
pub use polkadot_validation::Incoming;
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
|
||||
/// An executor suitable for dispatching async consensus tasks.
|
||||
pub trait Executor {
|
||||
fn spawn<F: Future<Item=(),Error=()> + Send + 'static>(&self, f: F);
|
||||
@@ -83,108 +76,8 @@ impl Executor for Arc<
|
||||
}
|
||||
}
|
||||
|
||||
/// A gossip network subservice.
|
||||
pub trait GossipService {
|
||||
fn send_message(&mut self, ctx: &mut dyn NetContext<Block>, who: &PeerId, message: ConsensusMessage);
|
||||
}
|
||||
|
||||
impl GossipService for consensus_gossip::ConsensusGossip<Block> {
|
||||
fn send_message(&mut self, ctx: &mut dyn NetContext<Block>, who: &PeerId, message: ConsensusMessage) {
|
||||
consensus_gossip::ConsensusGossip::send_message(self, ctx, who, message)
|
||||
}
|
||||
}
|
||||
|
||||
/// A stream of gossip messages and an optional sender for a topic.
|
||||
pub struct GossipMessageStream {
|
||||
topic_stream: mpsc::UnboundedReceiver<TopicNotification>,
|
||||
}
|
||||
|
||||
impl GossipMessageStream {
|
||||
/// Create a new instance with the given topic stream.
|
||||
pub fn new(topic_stream: mpsc::UnboundedReceiver<TopicNotification>) -> Self {
|
||||
Self {
|
||||
topic_stream
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for GossipMessageStream {
|
||||
type Item = (GossipMessage, Option<PeerId>);
|
||||
type Error = ();
|
||||
|
||||
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||
loop {
|
||||
let msg = match futures::try_ready!(self.topic_stream.poll()) {
|
||||
Some(msg) => msg,
|
||||
None => return Ok(Async::Ready(None)),
|
||||
};
|
||||
|
||||
debug!(target: "validation", "Processing statement for live validation session");
|
||||
if let Ok(gmsg) = GossipMessage::decode(&mut &msg.message[..]) {
|
||||
return Ok(Async::Ready(Some((gmsg, msg.sender))))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Basic functionality that a network has to fulfill.
|
||||
pub trait NetworkService: Send + Sync + 'static {
|
||||
/// Get a stream of gossip messages for a given hash.
|
||||
fn gossip_messages_for(&self, topic: Hash) -> GossipMessageStream;
|
||||
|
||||
/// Gossip a message on given topic.
|
||||
fn gossip_message(&self, topic: Hash, message: GossipMessage);
|
||||
|
||||
/// Execute a closure with the gossip service.
|
||||
fn with_gossip<F: Send + 'static>(&self, with: F)
|
||||
where F: FnOnce(&mut dyn GossipService, &mut dyn NetContext<Block>);
|
||||
|
||||
/// Execute a closure with the polkadot protocol.
|
||||
fn with_spec<F: Send + 'static>(&self, with: F)
|
||||
where F: FnOnce(&mut PolkadotProtocol, &mut dyn NetContext<Block>);
|
||||
}
|
||||
|
||||
impl NetworkService for super::NetworkService {
|
||||
fn gossip_messages_for(&self, topic: Hash) -> GossipMessageStream {
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
|
||||
super::NetworkService::with_gossip(self, move |gossip, _| {
|
||||
let inner_rx = gossip.messages_for(POLKADOT_ENGINE_ID, topic);
|
||||
let _ = tx.send(inner_rx);
|
||||
});
|
||||
|
||||
let topic_stream = match rx.recv() {
|
||||
Ok(rx) => rx,
|
||||
Err(_) => mpsc::unbounded().1, // return empty channel.
|
||||
};
|
||||
|
||||
GossipMessageStream::new(topic_stream)
|
||||
}
|
||||
|
||||
fn gossip_message(&self, topic: Hash, message: GossipMessage) {
|
||||
self.gossip_consensus_message(
|
||||
topic,
|
||||
POLKADOT_ENGINE_ID,
|
||||
message.encode(),
|
||||
GossipMessageRecipient::BroadcastToAll,
|
||||
);
|
||||
}
|
||||
|
||||
fn with_gossip<F: Send + 'static>(&self, with: F)
|
||||
where F: FnOnce(&mut dyn GossipService, &mut dyn NetContext<Block>)
|
||||
{
|
||||
super::NetworkService::with_gossip(self, move |gossip, ctx| with(gossip, ctx))
|
||||
}
|
||||
|
||||
fn with_spec<F: Send + 'static>(&self, with: F)
|
||||
where F: FnOnce(&mut PolkadotProtocol, &mut dyn NetContext<Block>)
|
||||
{
|
||||
super::NetworkService::with_spec(self, with)
|
||||
}
|
||||
}
|
||||
|
||||
/// Params to a current validation session.
|
||||
pub struct SessionParams {
|
||||
/// Params to instantiate validation work on a block-DAG leaf.
|
||||
pub struct LeafWorkParams {
|
||||
/// The local session key.
|
||||
pub local_session_key: Option<ValidatorId>,
|
||||
/// The parent hash.
|
||||
@@ -234,20 +127,22 @@ impl<P, E, N, T> ValidationNetwork<P, E, N, T> where
|
||||
N: NetworkService,
|
||||
T: Clone + Executor + Send + Sync + 'static,
|
||||
{
|
||||
/// Instantiate session data fetcher at a parent hash.
|
||||
/// Instantiate block-DAG leaf work
|
||||
/// (i.e. the work we want to be done by validators at some chain-head)
|
||||
/// at a parent hash.
|
||||
///
|
||||
/// If the used session key is new, it will be broadcast to peers.
|
||||
/// If a validation session was already instantiated at this parent hash,
|
||||
/// If any validation leaf-work was already instantiated at this parent hash,
|
||||
/// the underlying instance will be shared.
|
||||
///
|
||||
/// If there was already a validation session instantiated and a different
|
||||
/// If there was already validation leaf-work instantiated and a different
|
||||
/// session key was set, then the new key will be ignored.
|
||||
///
|
||||
/// This implies that there can be multiple services intantiating validation
|
||||
/// session instances safely, but they should all be coordinated on which session keys
|
||||
/// leaf-work instances safely, but they should all be coordinated on which session keys
|
||||
/// are being used.
|
||||
pub fn instantiate_session(&self, params: SessionParams)
|
||||
-> oneshot::Receiver<SessionDataFetcher<P, E, N, T>>
|
||||
pub fn instantiate_leaf_work(&self, params: LeafWorkParams)
|
||||
-> oneshot::Receiver<LeafWorkDataFetcher<P, E, N, T>>
|
||||
{
|
||||
let parent_hash = params.parent_hash;
|
||||
let network = self.network.clone();
|
||||
@@ -255,34 +150,27 @@ impl<P, E, N, T> ValidationNetwork<P, E, N, T> where
|
||||
let task_executor = self.executor.clone();
|
||||
let exit = self.exit.clone();
|
||||
let message_validator = self.message_validator.clone();
|
||||
let index_mapping = params.authorities
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, k)| (i as ValidatorIndex, k.clone()))
|
||||
.collect();
|
||||
let authorities = params.authorities.clone();
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
{
|
||||
let message_validator = self.message_validator.clone();
|
||||
let authorities = params.authorities.clone();
|
||||
self.network.with_gossip(move |gossip, ctx| {
|
||||
message_validator.note_session(
|
||||
parent_hash,
|
||||
MessageValidationData { authorities, index_mapping },
|
||||
|peer_id, message| gossip.send_message(ctx, peer_id, message),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
self.network.with_spec(move |spec, ctx| {
|
||||
let session = spec.new_validation_session(ctx, params);
|
||||
let _ = tx.send(SessionDataFetcher {
|
||||
let actions = message_validator.new_local_leaf(
|
||||
parent_hash,
|
||||
MessageValidationData { authorities },
|
||||
|queue_root| spec.availability_store.as_ref()
|
||||
.and_then(|store| store.queue_by_root(queue_root))
|
||||
);
|
||||
|
||||
network.with_gossip(move |gossip, ctx| actions.perform(gossip, ctx));
|
||||
|
||||
let work = spec.new_validation_leaf_work(ctx, params);
|
||||
let _ = tx.send(LeafWorkDataFetcher {
|
||||
network,
|
||||
api,
|
||||
task_executor,
|
||||
parent_hash,
|
||||
knowledge: session.knowledge().clone(),
|
||||
knowledge: work.knowledge().clone(),
|
||||
exit,
|
||||
message_validator,
|
||||
});
|
||||
@@ -335,7 +223,7 @@ impl<P, E, N, T> ParachainNetwork for ValidationNetwork<P, E, N, T> where
|
||||
let parent_hash = *table.consensus_parent_hash();
|
||||
let local_session_key = table.session_key();
|
||||
|
||||
let build_fetcher = self.instantiate_session(SessionParams {
|
||||
let build_fetcher = self.instantiate_leaf_work(LeafWorkParams {
|
||||
local_session_key,
|
||||
parent_hash,
|
||||
authorities: authorities.to_vec(),
|
||||
@@ -421,9 +309,9 @@ impl<P, E: Clone, N, T: Clone> Collators for ValidationNetwork<P, E, N, T> where
|
||||
#[derive(Default)]
|
||||
struct KnowledgeEntry {
|
||||
knows_block_data: Vec<ValidatorId>,
|
||||
knows_extrinsic: Vec<ValidatorId>,
|
||||
knows_outgoing: Vec<ValidatorId>,
|
||||
pov: Option<PoVBlock>,
|
||||
extrinsic: Option<Extrinsic>,
|
||||
outgoing_messages: Option<OutgoingMessages>,
|
||||
}
|
||||
|
||||
/// Tracks knowledge of peers.
|
||||
@@ -442,18 +330,18 @@ impl Knowledge {
|
||||
/// Note a statement seen from another validator.
|
||||
pub(crate) fn note_statement(&mut self, from: ValidatorId, statement: &Statement) {
|
||||
// those proposing the candidate or declaring it valid know everything.
|
||||
// those claiming it invalid do not have the extrinsic data as it is
|
||||
// those claiming it invalid do not have the outgoing messages data as it is
|
||||
// generated by valid execution.
|
||||
match *statement {
|
||||
GenericStatement::Candidate(ref c) => {
|
||||
let entry = self.candidates.entry(c.hash()).or_insert_with(Default::default);
|
||||
entry.knows_block_data.push(from.clone());
|
||||
entry.knows_extrinsic.push(from);
|
||||
entry.knows_outgoing.push(from);
|
||||
}
|
||||
GenericStatement::Valid(ref hash) => {
|
||||
let entry = self.candidates.entry(*hash).or_insert_with(Default::default);
|
||||
entry.knows_block_data.push(from.clone());
|
||||
entry.knows_extrinsic.push(from);
|
||||
entry.knows_outgoing.push(from);
|
||||
}
|
||||
GenericStatement::Invalid(ref hash) => self.candidates.entry(*hash)
|
||||
.or_insert_with(Default::default)
|
||||
@@ -463,10 +351,15 @@ impl Knowledge {
|
||||
}
|
||||
|
||||
/// Note a candidate collated or seen locally.
|
||||
pub(crate) fn note_candidate(&mut self, hash: Hash, pov: Option<PoVBlock>, extrinsic: Option<Extrinsic>) {
|
||||
pub(crate) fn note_candidate(
|
||||
&mut self,
|
||||
hash: Hash,
|
||||
pov: Option<PoVBlock>,
|
||||
outgoing_messages: Option<OutgoingMessages>,
|
||||
) {
|
||||
let entry = self.candidates.entry(hash).or_insert_with(Default::default);
|
||||
entry.pov = entry.pov.take().or(pov);
|
||||
entry.extrinsic = entry.extrinsic.take().or(extrinsic);
|
||||
entry.outgoing_messages = entry.outgoing_messages.take().or(outgoing_messages);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,19 +385,19 @@ impl Future for IncomingReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
/// A current validation session instance.
|
||||
/// A current validation leaf-work instance
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct ValidationSession {
|
||||
pub(crate) struct LiveValidationLeaf {
|
||||
parent_hash: Hash,
|
||||
knowledge: Arc<Mutex<Knowledge>>,
|
||||
local_session_key: Option<ValidatorId>,
|
||||
}
|
||||
|
||||
impl ValidationSession {
|
||||
/// Create a new validation session instance. Needs to be attached to the
|
||||
impl LiveValidationLeaf {
|
||||
/// Create a new validation leaf-work instance. Needs to be attached to the
|
||||
/// network.
|
||||
pub(crate) fn new(params: SessionParams) -> Self {
|
||||
ValidationSession {
|
||||
pub(crate) fn new(params: LeafWorkParams) -> Self {
|
||||
LiveValidationLeaf {
|
||||
parent_hash: params.parent_hash,
|
||||
knowledge: Arc::new(Mutex::new(Knowledge::new())),
|
||||
local_session_key: params.local_session_key,
|
||||
@@ -577,32 +470,32 @@ impl RecentValidatorIds {
|
||||
}
|
||||
}
|
||||
|
||||
/// Manages requests and keys for live validation session instances.
|
||||
pub(crate) struct LiveValidationSessions {
|
||||
/// Manages requests and keys for live validation leaf-work instances.
|
||||
pub(crate) struct LiveValidationLeaves {
|
||||
// recent local session keys.
|
||||
recent: RecentValidatorIds,
|
||||
// live validation session instances, on `parent_hash`. refcount retained alongside.
|
||||
live_instances: HashMap<Hash, (usize, ValidationSession)>,
|
||||
// live validation leaf-work instances, on `parent_hash`. refcount retained alongside.
|
||||
live_instances: HashMap<Hash, (usize, LiveValidationLeaf)>,
|
||||
}
|
||||
|
||||
impl LiveValidationSessions {
|
||||
/// Create a new `LiveValidationSessions`
|
||||
impl LiveValidationLeaves {
|
||||
/// Create a new `LiveValidationLeaves`
|
||||
pub(crate) fn new() -> Self {
|
||||
LiveValidationSessions {
|
||||
LiveValidationLeaves {
|
||||
recent: Default::default(),
|
||||
live_instances: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Note new validation session. If the used session key is new,
|
||||
/// Note new leaf for validation work. If the used session key is new,
|
||||
/// it returns it to be broadcasted to peers.
|
||||
///
|
||||
/// If there was already a validation session instantiated and a different
|
||||
/// If there was already work instantiated at this leaf and a different
|
||||
/// session key was set, then the new key will be ignored.
|
||||
pub(crate) fn new_validation_session(
|
||||
pub(crate) fn new_validation_leaf(
|
||||
&mut self,
|
||||
params: SessionParams,
|
||||
) -> (ValidationSession, Option<ValidatorId>) {
|
||||
params: LeafWorkParams,
|
||||
) -> (LiveValidationLeaf, Option<ValidatorId>) {
|
||||
let parent_hash = params.parent_hash;
|
||||
|
||||
let key = params.local_session_key.clone();
|
||||
@@ -629,19 +522,19 @@ impl LiveValidationSessions {
|
||||
return (prev.clone(), maybe_new)
|
||||
}
|
||||
|
||||
let session = ValidationSession::new(params);
|
||||
self.live_instances.insert(parent_hash, (1, session.clone()));
|
||||
let leaf_work = LiveValidationLeaf::new(params);
|
||||
self.live_instances.insert(parent_hash, (1, leaf_work.clone()));
|
||||
|
||||
(session, check_new_key())
|
||||
(leaf_work, check_new_key())
|
||||
}
|
||||
|
||||
/// Remove validation session. true indicates that it was actually removed.
|
||||
/// Remove validation leaf-work. true indicates that it was actually removed.
|
||||
pub(crate) fn remove(&mut self, parent_hash: Hash) -> bool {
|
||||
let maybe_removed = if let Entry::Occupied(mut entry) = self.live_instances.entry(parent_hash) {
|
||||
entry.get_mut().0 -= 1;
|
||||
if entry.get().0 == 0 {
|
||||
let (_, session) = entry.remove();
|
||||
Some(session)
|
||||
let (_, leaf_work) = entry.remove();
|
||||
Some(leaf_work)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -649,12 +542,12 @@ impl LiveValidationSessions {
|
||||
None
|
||||
};
|
||||
|
||||
let session = match maybe_removed {
|
||||
let leaf_work = match maybe_removed {
|
||||
None => return false,
|
||||
Some(s) => s,
|
||||
};
|
||||
|
||||
if let Some(ref key) = session.local_session_key {
|
||||
if let Some(ref key) = leaf_work.local_session_key {
|
||||
let key_still_used = self.live_instances.values()
|
||||
.any(|c| c.1.local_session_key.as_ref() == Some(key));
|
||||
|
||||
@@ -671,12 +564,12 @@ impl LiveValidationSessions {
|
||||
self.recent.as_slice()
|
||||
}
|
||||
|
||||
/// Call a closure with pov-data from validation session at parent hash for a given
|
||||
/// Call a closure with pov-data from validation leaf-work at parent hash for a given
|
||||
/// candidate-receipt hash.
|
||||
///
|
||||
/// This calls the closure with `Some(data)` where the session and data are live,
|
||||
/// `Err(Some(keys))` when the session is live but the data unknown, with a list of keys
|
||||
/// who have the data, and `Err(None)` where the session is unknown.
|
||||
/// This calls the closure with `Some(data)` where the leaf-work and data are live,
|
||||
/// `Err(Some(keys))` when the leaf-work is live but the data unknown, with a list of keys
|
||||
/// who have the data, and `Err(None)` where the leaf-work is unknown.
|
||||
pub(crate) fn with_pov_block<F, U>(&self, parent_hash: &Hash, c_hash: &Hash, f: F) -> U
|
||||
where F: FnOnce(Result<&PoVBlock, Option<&[ValidatorId]>>) -> U
|
||||
{
|
||||
@@ -716,8 +609,8 @@ impl Future for PoVReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
/// Can fetch data for a given validation session
|
||||
pub struct SessionDataFetcher<P, E, N: NetworkService, T> {
|
||||
/// Can fetch data for a given validation leaf-work instance.
|
||||
pub struct LeafWorkDataFetcher<P, E, N: NetworkService, T> {
|
||||
network: Arc<N>,
|
||||
api: Arc<P>,
|
||||
exit: E,
|
||||
@@ -727,7 +620,7 @@ pub struct SessionDataFetcher<P, E, N: NetworkService, T> {
|
||||
message_validator: RegisteredMessageValidator,
|
||||
}
|
||||
|
||||
impl<P, E, N: NetworkService, T> SessionDataFetcher<P, E, N, T> {
|
||||
impl<P, E, N: NetworkService, T> LeafWorkDataFetcher<P, E, N, T> {
|
||||
/// Get the parent hash.
|
||||
pub(crate) fn parent_hash(&self) -> Hash {
|
||||
self.parent_hash
|
||||
@@ -759,9 +652,9 @@ impl<P, E, N: NetworkService, T> SessionDataFetcher<P, E, N, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P, E: Clone, N: NetworkService, T: Clone> Clone for SessionDataFetcher<P, E, N, T> {
|
||||
impl<P, E: Clone, N: NetworkService, T: Clone> Clone for LeafWorkDataFetcher<P, E, N, T> {
|
||||
fn clone(&self) -> Self {
|
||||
SessionDataFetcher {
|
||||
LeafWorkDataFetcher {
|
||||
network: self.network.clone(),
|
||||
api: self.api.clone(),
|
||||
task_executor: self.task_executor.clone(),
|
||||
@@ -773,7 +666,7 @@ impl<P, E: Clone, N: NetworkService, T: Clone> Clone for SessionDataFetcher<P, E
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: ProvideRuntimeApi + Send, E, N, T> SessionDataFetcher<P, E, N, T> where
|
||||
impl<P: ProvideRuntimeApi + Send, E, N, T> LeafWorkDataFetcher<P, E, N, T> where
|
||||
P::Api: ParachainHost<Block>,
|
||||
N: NetworkService,
|
||||
T: Clone + Executor + Send + 'static,
|
||||
@@ -784,7 +677,11 @@ impl<P: ProvideRuntimeApi + Send, E, N, T> SessionDataFetcher<P, E, N, T> where
|
||||
let parachain = candidate.parachain_index;
|
||||
let parent_hash = self.parent_hash;
|
||||
|
||||
let canon_roots = self.api.runtime_api().ingress(&BlockId::hash(parent_hash), parachain)
|
||||
let canon_roots = self.api.runtime_api().ingress(
|
||||
&BlockId::hash(parent_hash),
|
||||
parachain,
|
||||
None,
|
||||
)
|
||||
.map_err(|e|
|
||||
format!(
|
||||
"Cannot fetch ingress for parachain {:?} at {:?}: {:?}",
|
||||
@@ -862,39 +759,39 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_new_sessions_works() {
|
||||
let mut live_sessions = LiveValidationSessions::new();
|
||||
fn add_new_leaf_work_works() {
|
||||
let mut live_leaves = LiveValidationLeaves::new();
|
||||
let key_a: ValidatorId = [0; 32].unchecked_into();
|
||||
let key_b: ValidatorId = [1; 32].unchecked_into();
|
||||
let parent_hash = [0xff; 32].into();
|
||||
|
||||
let (session, new_key) = live_sessions.new_validation_session(SessionParams {
|
||||
let (leaf_work, new_key) = live_leaves.new_validation_leaf(LeafWorkParams {
|
||||
parent_hash,
|
||||
local_session_key: None,
|
||||
authorities: Vec::new(),
|
||||
});
|
||||
|
||||
let knowledge = session.knowledge().clone();
|
||||
let knowledge = leaf_work.knowledge().clone();
|
||||
|
||||
assert!(new_key.is_none());
|
||||
|
||||
let (session, new_key) = live_sessions.new_validation_session(SessionParams {
|
||||
let (leaf_work, new_key) = live_leaves.new_validation_leaf(LeafWorkParams {
|
||||
parent_hash,
|
||||
local_session_key: Some(key_a.clone()),
|
||||
authorities: Vec::new(),
|
||||
});
|
||||
|
||||
// check that knowledge points to the same place.
|
||||
assert_eq!(&**session.knowledge() as *const _, &*knowledge as *const _);
|
||||
assert_eq!(&**leaf_work.knowledge() as *const _, &*knowledge as *const _);
|
||||
assert_eq!(new_key, Some(key_a.clone()));
|
||||
|
||||
let (session, new_key) = live_sessions.new_validation_session(SessionParams {
|
||||
let (leaf_work, new_key) = live_leaves.new_validation_leaf(LeafWorkParams {
|
||||
parent_hash,
|
||||
local_session_key: Some(key_b.clone()),
|
||||
authorities: Vec::new(),
|
||||
});
|
||||
|
||||
assert_eq!(&**session.knowledge() as *const _, &*knowledge as *const _);
|
||||
assert_eq!(&**leaf_work.knowledge() as *const _, &*knowledge as *const _);
|
||||
assert!(new_key.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user