@@ -42,7 +42,7 @@ use sp_inherents::InherentData;
4242use sp_runtime:: {
4343 generic:: BlockId ,
4444 traits:: { BlakeTwo256 , Block as BlockT , Hash as HashT , Header as HeaderT } ,
45- Digest ,
45+ Digest , Percent , SaturatedConversion ,
4646} ;
4747use std:: { marker:: PhantomData , pin:: Pin , sync:: Arc , time} ;
4848
@@ -58,6 +58,8 @@ use sc_proposer_metrics::MetricsLink as PrometheusMetrics;
5858/// transferred to other nodes.
5959pub const DEFAULT_BLOCK_SIZE_LIMIT : usize = 4 * 1024 * 1024 + 512 ;
6060
61+ const DEFAULT_SOFT_DEADLINE_PERCENT : Percent = Percent :: from_percent ( 50 ) ;
62+
6163/// [`Proposer`] factory.
6264pub struct ProposerFactory < A , B , C , PR > {
6365 spawn_handle : Box < dyn SpawnNamed > ,
@@ -72,6 +74,14 @@ pub struct ProposerFactory<A, B, C, PR> {
7274 /// If no `block_size_limit` is passed to [`sp_consensus::Proposer::propose`], this block size
7375 /// limit will be used.
7476 default_block_size_limit : usize ,
77+ /// Soft deadline percentage of hard deadline.
78+ ///
79+ /// The value is used to compute soft deadline during block production.
80+ /// The soft deadline indicates where we should stop attempting to add transactions
81+ /// to the block, which exhaust resources. After soft deadline is reached,
82+ /// we switch to a fixed-amount mode, in which after we see `MAX_SKIPPED_TRANSACTIONS`
83+ /// transactions which exhaust resrouces, we will conclude that the block is full.
84+ soft_deadline_percent : Percent ,
7585 telemetry : Option < TelemetryHandle > ,
7686 /// When estimating the block size, should the proof be included?
7787 include_proof_in_block_size_estimation : bool ,
@@ -96,6 +106,7 @@ impl<A, B, C> ProposerFactory<A, B, C, DisableProofRecording> {
96106 transaction_pool,
97107 metrics : PrometheusMetrics :: new ( prometheus) ,
98108 default_block_size_limit : DEFAULT_BLOCK_SIZE_LIMIT ,
109+ soft_deadline_percent : DEFAULT_SOFT_DEADLINE_PERCENT ,
99110 telemetry,
100111 client,
101112 include_proof_in_block_size_estimation : false ,
@@ -124,6 +135,7 @@ impl<A, B, C> ProposerFactory<A, B, C, EnableProofRecording> {
124135 transaction_pool,
125136 metrics : PrometheusMetrics :: new ( prometheus) ,
126137 default_block_size_limit : DEFAULT_BLOCK_SIZE_LIMIT ,
138+ soft_deadline_percent : DEFAULT_SOFT_DEADLINE_PERCENT ,
127139 telemetry,
128140 include_proof_in_block_size_estimation : true ,
129141 _phantom : PhantomData ,
@@ -147,6 +159,22 @@ impl<A, B, C, PR> ProposerFactory<A, B, C, PR> {
147159 pub fn set_default_block_size_limit ( & mut self , limit : usize ) {
148160 self . default_block_size_limit = limit;
149161 }
162+
163+ /// Set soft deadline percentage.
164+ ///
165+ /// The value is used to compute soft deadline during block production.
166+ /// The soft deadline indicates where we should stop attempting to add transactions
167+ /// to the block, which exhaust resources. After soft deadline is reached,
168+ /// we switch to a fixed-amount mode, in which after we see `MAX_SKIPPED_TRANSACTIONS`
169+ /// transactions which exhaust resrouces, we will conclude that the block is full.
170+ ///
171+ /// Setting the value too low will significantly limit the amount of transactions
172+ /// we try in case they exhaust resources. Setting the value too high can
173+ /// potentially open a DoS vector, where many "exhaust resources" transactions
174+ /// are being tried with no success, hence block producer ends up creating an empty block.
175+ pub fn set_soft_deadline ( & mut self , percent : Percent ) {
176+ self . soft_deadline_percent = percent;
177+ }
150178}
151179
152180impl < B , Block , C , A , PR > ProposerFactory < A , B , C , PR >
@@ -184,6 +212,7 @@ where
184212 now,
185213 metrics : self . metrics . clone ( ) ,
186214 default_block_size_limit : self . default_block_size_limit ,
215+ soft_deadline_percent : self . soft_deadline_percent ,
187216 telemetry : self . telemetry . clone ( ) ,
188217 _phantom : PhantomData ,
189218 include_proof_in_block_size_estimation : self . include_proof_in_block_size_estimation ,
@@ -229,6 +258,7 @@ pub struct Proposer<B, Block: BlockT, C, A: TransactionPool, PR> {
229258 metrics : PrometheusMetrics ,
230259 default_block_size_limit : usize ,
231260 include_proof_in_block_size_estimation : bool ,
261+ soft_deadline_percent : Percent ,
232262 telemetry : Option < TelemetryHandle > ,
233263 _phantom : PhantomData < ( B , PR ) > ,
234264}
@@ -340,7 +370,10 @@ where
340370 // proceed with transactions
341371 // We calculate soft deadline used only in case we start skipping transactions.
342372 let now = ( self . now ) ( ) ;
343- let soft_deadline = now + deadline. saturating_duration_since ( now) / 2 ;
373+ let left = deadline. saturating_duration_since ( now) ;
374+ let left_micros: u64 = left. as_micros ( ) . saturated_into ( ) ;
375+ let soft_deadline =
376+ now + time:: Duration :: from_micros ( self . soft_deadline_percent . mul_floor ( left_micros) ) ;
344377 let block_timer = time:: Instant :: now ( ) ;
345378 let mut skipped = 0 ;
346379 let mut unqueue_invalid = Vec :: new ( ) ;
0 commit comments