mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-28 14:27:57 +00:00
Limit number of blocks per level (2nd attempt) (#1559)
Prevents the StateDbError::TooManySiblingBlocks error from being triggered by eagerly removing stale blocks from the backend on block import and before the error condition is met. Introduces a just in time block recovery mechanism for blocks that were wrongly removed via an explicit pov-recovery method Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
@@ -15,14 +15,23 @@
|
||||
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use polkadot_primitives::v2::{Hash as PHash, PersistedValidationData};
|
||||
use sc_consensus::BlockImport;
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
|
||||
use sc_client_api::Backend;
|
||||
use sc_consensus::{shared_data::SharedData, BlockImport, ImportResult};
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
mod level_monitor;
|
||||
mod parachain_consensus;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use parachain_consensus::run_parachain_consensus;
|
||||
|
||||
use level_monitor::LevelMonitor;
|
||||
pub use level_monitor::{LevelLimit, MAX_LEAVES_PER_LEVEL_SENSIBLE_DEFAULT};
|
||||
|
||||
/// The result of [`ParachainConsensus::produce_candidate`].
|
||||
pub struct ParachainCandidate<B> {
|
||||
/// The block that was built for this candidate.
|
||||
@@ -74,47 +83,93 @@ impl<B: BlockT> ParachainConsensus<B> for Box<dyn ParachainConsensus<B> + Send +
|
||||
/// This is used to set `block_import_params.fork_choice` to `false` as long as the block origin is
|
||||
/// not `NetworkInitialSync`. The best block for parachains is determined by the relay chain. Meaning
|
||||
/// we will update the best block, as it is included by the relay-chain.
|
||||
pub struct ParachainBlockImport<I>(I);
|
||||
pub struct ParachainBlockImport<Block: BlockT, BI, BE> {
|
||||
inner: BI,
|
||||
monitor: Option<SharedData<LevelMonitor<Block, BE>>>,
|
||||
}
|
||||
|
||||
impl<I> ParachainBlockImport<I> {
|
||||
impl<Block: BlockT, BI, BE: Backend<Block>> ParachainBlockImport<Block, BI, BE> {
|
||||
/// Create a new instance.
|
||||
pub fn new(inner: I) -> Self {
|
||||
Self(inner)
|
||||
///
|
||||
/// The number of leaves per level limit is set to `LevelLimit::Default`.
|
||||
pub fn new(inner: BI, backend: Arc<BE>) -> Self {
|
||||
Self::new_with_limit(inner, backend, LevelLimit::Default)
|
||||
}
|
||||
|
||||
/// Create a new instance with an explicit limit to the number of leaves per level.
|
||||
///
|
||||
/// This function alone doesn't enforce the limit on levels for old imported blocks,
|
||||
/// the limit is eventually enforced only when new blocks are imported.
|
||||
pub fn new_with_limit(inner: BI, backend: Arc<BE>, level_leaves_max: LevelLimit) -> Self {
|
||||
let level_limit = match level_leaves_max {
|
||||
LevelLimit::None => None,
|
||||
LevelLimit::Some(limit) => Some(limit),
|
||||
LevelLimit::Default => Some(MAX_LEAVES_PER_LEVEL_SENSIBLE_DEFAULT),
|
||||
};
|
||||
|
||||
let monitor =
|
||||
level_limit.map(|level_limit| SharedData::new(LevelMonitor::new(level_limit, backend)));
|
||||
|
||||
Self { inner, monitor }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Clone> Clone for ParachainBlockImport<I> {
|
||||
impl<Block: BlockT, I: Clone, BE> Clone for ParachainBlockImport<Block, I, BE> {
|
||||
fn clone(&self) -> Self {
|
||||
ParachainBlockImport(self.0.clone())
|
||||
ParachainBlockImport { inner: self.inner.clone(), monitor: self.monitor.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<Block, I> BlockImport<Block> for ParachainBlockImport<I>
|
||||
impl<Block, BI, BE> BlockImport<Block> for ParachainBlockImport<Block, BI, BE>
|
||||
where
|
||||
Block: BlockT,
|
||||
I: BlockImport<Block> + Send,
|
||||
BI: BlockImport<Block> + Send,
|
||||
BE: Backend<Block>,
|
||||
{
|
||||
type Error = I::Error;
|
||||
type Transaction = I::Transaction;
|
||||
type Error = BI::Error;
|
||||
type Transaction = BI::Transaction;
|
||||
|
||||
async fn check_block(
|
||||
&mut self,
|
||||
block: sc_consensus::BlockCheckParams<Block>,
|
||||
) -> Result<sc_consensus::ImportResult, Self::Error> {
|
||||
self.0.check_block(block).await
|
||||
self.inner.check_block(block).await
|
||||
}
|
||||
|
||||
async fn import_block(
|
||||
&mut self,
|
||||
mut block_import_params: sc_consensus::BlockImportParams<Block, Self::Transaction>,
|
||||
mut params: sc_consensus::BlockImportParams<Block, Self::Transaction>,
|
||||
cache: std::collections::HashMap<sp_consensus::CacheKeyId, Vec<u8>>,
|
||||
) -> Result<sc_consensus::ImportResult, Self::Error> {
|
||||
// Blocks are stored within the backend by using POST hash.
|
||||
let hash = params.post_hash();
|
||||
let number = *params.header.number();
|
||||
|
||||
// Best block is determined by the relay chain, or if we are doing the initial sync
|
||||
// we import all blocks as new best.
|
||||
block_import_params.fork_choice = Some(sc_consensus::ForkChoiceStrategy::Custom(
|
||||
block_import_params.origin == sp_consensus::BlockOrigin::NetworkInitialSync,
|
||||
params.fork_choice = Some(sc_consensus::ForkChoiceStrategy::Custom(
|
||||
params.origin == sp_consensus::BlockOrigin::NetworkInitialSync,
|
||||
));
|
||||
self.0.import_block(block_import_params, cache).await
|
||||
|
||||
let maybe_lock = self.monitor.as_ref().map(|monitor_lock| {
|
||||
let mut monitor = monitor_lock.shared_data_locked();
|
||||
monitor.enforce_limit(number);
|
||||
monitor.release_mutex()
|
||||
});
|
||||
|
||||
let res = self.inner.import_block(params, cache).await?;
|
||||
|
||||
if let (Some(mut monitor_lock), ImportResult::Imported(_)) = (maybe_lock, &res) {
|
||||
let mut monitor = monitor_lock.upgrade();
|
||||
monitor.block_imported(number, hash);
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// Marker trait denoting a block import type that fits the parachain requirements.
|
||||
pub trait ParachainBlockImportMarker {}
|
||||
|
||||
impl<B: BlockT, BI, BE> ParachainBlockImportMarker for ParachainBlockImport<B, BI, BE> {}
|
||||
|
||||
Reference in New Issue
Block a user