6
6
//! 2. There is an incoming downward message from the relay chain.
7
7
//! 3. There is a go-ahead signal for a parachain code upgrade.
8
8
//! 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
9
10
//!
10
11
//! If any of these conditions are met, then the block is authored.
11
12
12
13
use anyhow:: anyhow;
14
+ use parity_scale_codec:: Decode ;
13
15
16
+ use sc_client_api:: backend:: StorageProvider ;
14
17
use sc_transaction_pool_api:: TransactionPool ;
15
18
use sp_api:: StorageProof ;
16
19
use sp_consensus:: Proposal ;
@@ -30,29 +33,36 @@ use std::time::Duration;
30
33
use crate :: service:: ParachainClient ;
31
34
32
35
/// Proposes blocks, but only under certain conditions. See module docs.
33
- pub struct BlockLimitingProposer < P > {
36
+ pub struct BlockLimitingProposer < P , C > {
34
37
inner : P ,
38
+ client : Arc < C > ,
35
39
para_id : ParaId ,
36
40
transaction_pool : Arc < sc_transaction_pool:: FullPool < Block , ParachainClient > > ,
37
41
}
38
42
39
- impl < P > BlockLimitingProposer < P > {
43
+ impl < P , C > BlockLimitingProposer < P , C > {
40
44
/// Create a new block-limiting proposer.
41
45
pub fn new (
42
46
inner : P ,
47
+ client : Arc < C > ,
43
48
para_id : ParaId ,
44
49
transaction_pool : Arc < sc_transaction_pool:: FullPool < Block , ParachainClient > > ,
45
50
) -> Self {
46
51
BlockLimitingProposer {
47
52
inner,
53
+ client,
48
54
para_id,
49
55
transaction_pool,
50
56
}
51
57
}
52
58
}
53
59
54
60
#[ 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
+ {
56
66
async fn propose (
57
67
& mut self ,
58
68
parent_header : & Header ,
@@ -89,8 +99,44 @@ impl<P: ProposerInterface<Block> + Send> ProposerInterface<Block> for BlockLimit
89
99
// testing for detection of healthiness.
90
100
parent_header. number == 0
91
101
} ;
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
+ ) ;
92
107
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
+ {
94
140
self . inner
95
141
. propose (
96
142
parent_header,
0 commit comments