-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Add block announce validator. #3346
Changes from 5 commits
88f0b53
877419c
dabb6d8
89f26a5
f05b2d1
ce11dd9
5d279bf
8becf1f
a5d2802
87d20bc
4a2fd48
acc2b11
4adb484
ca2aa07
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,7 +49,7 @@ use state_machine::{ | |
}; | ||
use executor::{RuntimeVersion, RuntimeInfo}; | ||
use consensus::{ | ||
Error as ConsensusError, BlockImportParams, | ||
Error as ConsensusError, BlockStatus, BlockImportParams, | ||
ImportResult, BlockOrigin, ForkChoiceStrategy, | ||
well_known_cache_keys::Id as CacheKeyId, | ||
SelectChain, self, | ||
|
@@ -173,21 +173,6 @@ pub struct ClientInfo<Block: BlockT> { | |
pub used_state_cache_size: Option<usize>, | ||
} | ||
|
||
/// Block status. | ||
#[derive(Debug, PartialEq, Eq)] | ||
pub enum BlockStatus { | ||
/// Added to the import queue. | ||
Queued, | ||
/// Already in the blockchain and the state is available. | ||
InChainWithState, | ||
/// In the blockchain, but the state is not available. | ||
InChainPruned, | ||
/// Block or parent is known to be bad. | ||
KnownBad, | ||
/// Not in the queue or the blockchain. | ||
Unknown, | ||
} | ||
|
||
/// Summary of an imported block | ||
#[derive(Clone, Debug)] | ||
pub struct BlockImportNotification<Block: BlockT> { | ||
|
@@ -201,6 +186,8 @@ pub struct BlockImportNotification<Block: BlockT> { | |
pub is_new_best: bool, | ||
/// List of retracted blocks ordered by block number. | ||
pub retracted: Vec<Block::Hash>, | ||
/// Any data associated with this block import. | ||
pub associated_data: Vec<u8>, | ||
} | ||
|
||
/// Summary of a finalized block. | ||
|
@@ -1015,6 +1002,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where | |
is_new_best, | ||
storage_changes, | ||
retracted, | ||
associated_data: Vec::new(), // TODO | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any TODOs or FIXMEs need to contain links to open issues. |
||
}) | ||
} | ||
|
||
|
@@ -1185,10 +1173,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where | |
Ok(()) | ||
} | ||
|
||
fn notify_imported( | ||
&self, | ||
notify_import: ImportSummary<Block>, | ||
) -> error::Result<()> { | ||
fn notify_imported(&self, notify_import: ImportSummary<Block>) -> error::Result<()> { | ||
if let Some(storage_changes) = notify_import.storage_changes { | ||
// TODO [ToDr] How to handle re-orgs? Should we re-emit all storage changes? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tomusdrw solved or needs an issue? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems that we are notifying about all blocks (not only the new best ones), so I think we don't really need any special handling here. CC @jacogr what would you expect in case of re-orgs and storage changes subscription? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there is a re-org, would expect the subscriptions to pass through the most-recent-actual-state values. Effectively the lasted values from the subscription and |
||
self.storage_notifications.lock() | ||
|
@@ -1205,6 +1190,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where | |
header: notify_import.header, | ||
is_new_best: notify_import.is_new_best, | ||
retracted: notify_import.retracted, | ||
associated_data: notify_import.associated_data, | ||
}; | ||
|
||
self.import_notification_sinks.lock() | ||
|
@@ -1939,6 +1925,16 @@ pub mod utils { | |
} | ||
} | ||
|
||
impl<BE, E, B, RA> consensus::block_validation::Chain<B> for Client<BE, E, B, RA> | ||
where BE: backend::Backend<B, Blake2Hasher>, | ||
E: CallExecutor<B, Blake2Hasher>, | ||
B: BlockT<Hash = H256> | ||
{ | ||
fn block_status(&self, id: &BlockId<B>) -> Result<BlockStatus, Box<dyn std::error::Error + Send>> { | ||
Client::block_status(self, id).map_err(|e| Box::new(e) as Box<_>) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
pub(crate) mod tests { | ||
use std::collections::HashMap; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright 2019 Parity Technologies (UK) Ltd. | ||
// This file is part of Substrate. | ||
// | ||
// Substrate 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. | ||
// | ||
// Substrate 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 Substrate. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
bkchr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
//! Block announcement validation. | ||
|
||
use crate::BlockStatus; | ||
use sr_primitives::{generic::BlockId, traits::Block}; | ||
use std::{error::Error, sync::Arc}; | ||
|
||
/// A type which provides access to chain information. | ||
pub trait Chain<B: Block> { | ||
/// Retrieve the status of the block denoted by the given [`BlockId`]. | ||
fn block_status(&self, id: &BlockId<B>) -> Result<BlockStatus, Box<dyn Error + Send>>; | ||
} | ||
|
||
impl<T: Chain<B>, B: Block> Chain<B> for Arc<T> { | ||
fn block_status(&self, id: &BlockId<B>) -> Result<BlockStatus, Box<dyn Error + Send>> { | ||
(&**self).block_status(id) | ||
} | ||
} | ||
|
||
/// Result of `BlockAnnounceValidator::validate`. | ||
#[derive(Debug, PartialEq, Eq)] | ||
pub enum Validation { | ||
/// Valid block announcement. | ||
Success, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not call them There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Typical Rust style would have this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think naming the type "Valid" can be misleading because "valid" is already biased towards "yes". Saying something valid is not valid feels a little inconsistent to me, so at a minimum I would like to see a neutral name. I agree that the "Result" suffix should better be avoided, especially since the type name will often be embedded in another |
||
/// Invalid block announcement. | ||
Failure, | ||
} | ||
|
||
/// Type which checks incoming block announcements. | ||
pub trait BlockAnnounceValidator<B: Block> { | ||
/// Validate the announced header and its associated data. | ||
fn validate(&mut self, header: &B::Header, data: &[u8]) -> Result<Validation, Box<dyn Error + Send>>; | ||
} | ||
|
||
/// Default implementation of `BlockAnnounceValidator`. | ||
#[derive(Debug)] | ||
pub struct DefaultBlockAnnounceValidator<C> { | ||
Demi-Marie marked this conversation as resolved.
Show resolved
Hide resolved
|
||
chain: C | ||
} | ||
|
||
impl<C> DefaultBlockAnnounceValidator<C> { | ||
pub fn new(chain: C) -> Self { | ||
Self { chain } | ||
} | ||
} | ||
|
||
impl<B: Block, C: Chain<B>> BlockAnnounceValidator<B> for DefaultBlockAnnounceValidator<C> { | ||
fn validate(&mut self, _h: &B::Header, _d: &[u8]) -> Result<Validation, Box<dyn Error + Send>> { | ||
Ok(Validation::Success) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need the data as part of the import notification?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, now I understand, but I don't think that this is required. In Cumulus we will have to delay sending the notification anyway and will fetch the associated data from a different source. So, yeah, just remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we remove this, how do we send block announcements with associated data to network peers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/paritytech/substrate/pull/3346/files#diff-16b4c34d50bdfcbf732c09c7be1fdcf9R684 here do we send the block announcement. The import notification is just used to know that we need to send a block announcement. But as I already said, we will send the block announcements differently in Cumulus.