66//! 2. There is an incoming downward message from the relay chain.
77//! 3. There is a go-ahead signal for a parachain code upgrade.
88//! 4. The block is the first block of the parachain. Useful for testing.
9+ //! 5. The chain is not producing blocks for more than the maximum allowed number of skipped blocks
910//!
1011//! If any of these conditions are met, then the block is authored.
1112
1213use anyhow:: anyhow;
14+ use parity_scale_codec:: Decode ;
1315
16+ use sc_client_api:: backend:: StorageProvider ;
1417use sc_transaction_pool_api:: TransactionPool ;
1518use sp_api:: StorageProof ;
1619use sp_consensus:: Proposal ;
@@ -30,29 +33,36 @@ use std::time::Duration;
3033use crate :: service:: ParachainClient ;
3134
3235/// Proposes blocks, but only under certain conditions. See module docs.
33- pub struct BlockLimitingProposer < P > {
36+ pub struct BlockLimitingProposer < P , C > {
3437 inner : P ,
38+ client : Arc < C > ,
3539 para_id : ParaId ,
3640 transaction_pool : Arc < sc_transaction_pool:: FullPool < Block , ParachainClient > > ,
3741}
3842
39- impl < P > BlockLimitingProposer < P > {
43+ impl < P , C > BlockLimitingProposer < P , C > {
4044 /// Create a new block-limiting proposer.
4145 pub fn new (
4246 inner : P ,
47+ client : Arc < C > ,
4348 para_id : ParaId ,
4449 transaction_pool : Arc < sc_transaction_pool:: FullPool < Block , ParachainClient > > ,
4550 ) -> Self {
4651 BlockLimitingProposer {
4752 inner,
53+ client,
4854 para_id,
4955 transaction_pool,
5056 }
5157 }
5258}
5359
5460#[ async_trait:: async_trait]
55- impl < P : ProposerInterface < Block > + Send > ProposerInterface < Block > for BlockLimitingProposer < P > {
61+ impl < P , C > ProposerInterface < Block > for BlockLimitingProposer < P , C >
62+ where
63+ P : ProposerInterface < Block > + Send ,
64+ C : StorageProvider < Block , sc_client_db:: Backend < Block > > + Send + Sync ,
65+ {
5666 async fn propose (
5767 & mut self ,
5868 parent_header : & Header ,
@@ -89,8 +99,44 @@ impl<P: ProposerInterface<Block> + Send> ProposerInterface<Block> for BlockLimit
8999 // testing for detection of healthiness.
90100 parent_header. number == 0
91101 } ;
102+ let exceeded_max_skipped_blocks = ' max_skipped: {
103+ let maybe_last_relay_block_number = self . client . storage (
104+ parent_header. parent_hash ,
105+ & sp_storage:: StorageKey ( sugondat_primitives:: last_relay_block_number_key ( ) ) ,
106+ ) ;
92107
93- if has_downward_message || has_go_ahead || has_transactions || first_block {
108+ // If the state of the previous block or the last relay block number
109+ // is not available, to be sure of not exceeding the max amount of
110+ // skippable blocks, the block will be produced.
111+ let last_relay_block_number = match maybe_last_relay_block_number {
112+ Ok ( Some ( raw_data) ) => match Decode :: decode ( & mut & raw_data. 0 [ ..] ) {
113+ Ok ( last_relay_block_number) => last_relay_block_number,
114+ Err ( _) => break ' max_skipped true ,
115+ } ,
116+ _ => break ' max_skipped true ,
117+ } ;
118+ let relay_block_number = paras_inherent_data. validation_data . relay_parent_number ;
119+
120+ // TODO: Change 3600 to 7200 (half a day)
121+ // and `n_skipped_blocks = relay_parent_distance.saturating_sub(1)`
122+ // when updating to asynchronous backing
123+ // https://github.com/thrumdev/blobs/issues/166
124+
125+ // The accepted error is less than 10^(-2) for an expected
126+ // maximum of 3600 skipped blocks (half a day)
127+ const MAX_SKIPPED_BLOCKS : u32 = 3600 ;
128+
129+ let relay_parent_distance = relay_block_number. saturating_sub ( last_relay_block_number) ;
130+ let n_skipped_blocks = relay_parent_distance. saturating_sub ( 2 ) / 2 ;
131+ n_skipped_blocks >= MAX_SKIPPED_BLOCKS
132+ } ;
133+
134+ if has_downward_message
135+ || has_go_ahead
136+ || has_transactions
137+ || first_block
138+ || exceeded_max_skipped_blocks
139+ {
94140 self . inner
95141 . propose (
96142 parent_header,
0 commit comments