diff --git a/polkadot/network/src/tests/validation.rs b/polkadot/network/src/tests/validation.rs index 428d86e019..a8903edd51 100644 --- a/polkadot/network/src/tests/validation.rs +++ b/polkadot/network/src/tests/validation.rs @@ -413,5 +413,6 @@ fn make_table(data: &ApiData, local_key: &AuthorityKeyring, parent_hash: Hash) - Arc::new(local_key.pair()), parent_hash, store, + None, )) } diff --git a/polkadot/service/src/lib.rs b/polkadot/service/src/lib.rs index d568b908bc..343b2a291a 100644 --- a/polkadot/service/src/lib.rs +++ b/polkadot/service/src/lib.rs @@ -85,6 +85,9 @@ pub struct CustomConfiguration { grandpa::LinkHalfForService )>, + /// Maximal `block_data` size. + pub max_block_data_size: Option, + inherent_data_providers: InherentDataProviders, } @@ -94,6 +97,7 @@ impl Default for CustomConfiguration { collating_for: None, grandpa_import_setup: None, inherent_data_providers: InherentDataProviders::new(), + max_block_data_size: None, } } } @@ -311,6 +315,7 @@ construct_service_factory! { key.clone(), extrinsic_store, SlotDuration::get_or_compute(&*client)?, + service.config.custom.max_block_data_size, ); info!("Using authority key {}", key.public()); diff --git a/polkadot/validation/src/attestation_service.rs b/polkadot/validation/src/attestation_service.rs index 76a0fce1cb..4b9f53af08 100644 --- a/polkadot/validation/src/attestation_service.rs +++ b/polkadot/validation/src/attestation_service.rs @@ -110,6 +110,7 @@ pub(crate) fn start( thread_pool: TaskExecutor, key: Arc, extrinsic_store: ExtrinsicStore, + max_block_data_size: Option, ) -> ServiceHandle where C: Collators + Send + Sync + 'static, @@ -147,6 +148,7 @@ pub(crate) fn start( notification.header.parent_hash().clone(), &authorities, key.clone(), + max_block_data_size, ) }); diff --git a/polkadot/validation/src/collation.rs b/polkadot/validation/src/collation.rs index 0ec3510671..d0c8632b84 100644 --- a/polkadot/validation/src/collation.rs +++ b/polkadot/validation/src/collation.rs @@ -64,6 +64,7 @@ pub struct CollationFetch { collators: C, live_fetch: Option<::Future>, client: Arc

, + max_block_data_size: Option, } impl CollationFetch { @@ -73,6 +74,7 @@ impl CollationFetch { relay_parent_hash: Hash, collators: C, client: Arc

, + max_block_data_size: Option, ) -> Self { CollationFetch { relay_parent: BlockId::hash(relay_parent_hash), @@ -81,6 +83,7 @@ impl CollationFetch { client, parachain, live_fetch: None, + max_block_data_size, } } @@ -113,7 +116,7 @@ impl Future for CollationFetch try_ready!(poll) }; - let res = validate_collation(&*self.client, &self.relay_parent, &collation); + let res = validate_collation(&*self.client, &self.relay_parent, &collation, self.max_block_data_size); match res { Ok(e) => { @@ -179,7 +182,11 @@ error_chain! { } WrongHeadData(expected: Vec, got: Vec) { description("Parachain validation produced wrong head data."), - display("Parachain validation produced wrong head data (expected: {:?}, got {:?}", expected, got), + display("Parachain validation produced wrong head data (expected: {:?}, got {:?})", expected, got), + } + BlockDataTooBig(size: u64, max_size: u64) { + description("Block data is too big."), + display("Block data is too big (maximum allowed size: {}, actual size: {})", max_size, size), } } } @@ -331,12 +338,20 @@ pub fn validate_collation

( client: &P, relay_parent: &BlockId, collation: &Collation, + max_block_data_size: Option, ) -> Result where P: ProvideRuntimeApi, P::Api: ParachainHost, { use parachain::{IncomingMessage, ValidationParams}; + if let Some(max_size) = max_block_data_size { + let block_data_size = collation.pov.block_data.0.len() as u64; + if block_data_size > max_size { + return Err(ErrorKind::BlockDataTooBig(block_data_size, max_size).into()); + } + } + let api = client.runtime_api(); let para_id = collation.receipt.parachain_index; let validation_code = api.parachain_code(relay_parent, para_id)? diff --git a/polkadot/validation/src/lib.rs b/polkadot/validation/src/lib.rs index b7c5e93dcf..fbb98b9556 100644 --- a/polkadot/validation/src/lib.rs +++ b/polkadot/validation/src/lib.rs @@ -300,6 +300,7 @@ impl ParachainValidation where grandparent_hash: Hash, authorities: &[AuthorityId], sign_with: Arc, + max_block_data_size: Option, ) -> Result, Error> { @@ -351,7 +352,14 @@ impl ParachainValidation where debug!(target: "validation", "Active parachains: {:?}", active_parachains); - let table = Arc::new(SharedTable::new(authorities, group_info, sign_with.clone(), parent_hash, self.extrinsic_store.clone())); + let table = Arc::new(SharedTable::new( + authorities, + group_info, + sign_with.clone(), + parent_hash, + self.extrinsic_store.clone(), + max_block_data_size, + )); let router = self.network.communication_for( table.clone(), authorities, @@ -362,6 +370,7 @@ impl ParachainValidation where parent_hash, id, router, + max_block_data_size, )), Chain::Relay => None, }; @@ -387,7 +396,8 @@ impl ParachainValidation where &self, relay_parent: Hash, validation_para: ParaId, - build_router: N::BuildTableRouter + build_router: N::BuildTableRouter, + max_block_data_size: Option, ) -> exit_future::Signal { use extrinsic_store::Data; @@ -402,6 +412,7 @@ impl ParachainValidation where relay_parent, collators, client, + max_block_data_size, ); collation_work.then(move |result| match result { @@ -466,6 +477,7 @@ pub struct ProposerFactory { _service_handle: ServiceHandle, aura_slot_duration: SlotDuration, select_chain: SC, + max_block_data_size: Option, } impl ProposerFactory where @@ -491,6 +503,7 @@ impl ProposerFactory where key: Arc, extrinsic_store: ExtrinsicStore, aura_slot_duration: SlotDuration, + max_block_data_size: Option, ) -> Self { let parachain_validation = Arc::new(ParachainValidation { client: client.clone(), @@ -508,6 +521,7 @@ impl ProposerFactory where thread_pool, key.clone(), extrinsic_store, + max_block_data_size, ); ProposerFactory { @@ -516,7 +530,8 @@ impl ProposerFactory where key, _service_handle: service_handle, aura_slot_duration, - select_chain + select_chain, + max_block_data_size, } } } @@ -548,6 +563,7 @@ impl consensus::Environment for ProposerFactory, ) -> Option::Future, >> { @@ -191,7 +192,8 @@ impl SharedTableInner { work.map(|work| ParachainWork { extrinsic_store: self.extrinsic_store.clone(), relay_parent: context.parent_hash.clone(), - work + work, + max_block_data_size, }) } @@ -265,6 +267,7 @@ pub struct ParachainWork { work: Work, relay_parent: Hash, extrinsic_store: ExtrinsicStore, + max_block_data_size: Option, } impl ParachainWork { @@ -279,11 +282,13 @@ impl ParachainWork { P: Send + Sync + 'static, P::Api: ParachainHost, { + let max_block_data_size = self.max_block_data_size; let validate = move |id: &_, collation: &_| { let res = ::collation::validate_collation( &*api, id, collation, + max_block_data_size, ); match res { @@ -373,13 +378,15 @@ impl Future for PrimedParachainWork pub struct SharedTable { context: Arc, inner: Arc>, + max_block_data_size: Option, } impl Clone for SharedTable { fn clone(&self) -> Self { - SharedTable { + Self { context: self.context.clone(), inner: self.inner.clone(), + max_block_data_size: self.max_block_data_size, } } } @@ -395,10 +402,12 @@ impl SharedTable { key: Arc, parent_hash: Hash, extrinsic_store: ExtrinsicStore, + max_block_data_size: Option, ) -> Self { let index_mapping = authorities.iter().enumerate().map(|(i, k)| (i as ValidatorIndex, k.clone())).collect(); Self { context: Arc::new(TableContext { groups, key, parent_hash, index_mapping, }), + max_block_data_size, inner: Arc::new(Mutex::new(SharedTableInner { table: Table::default(), validated: HashMap::new(), @@ -447,7 +456,7 @@ impl SharedTable { ) -> Option::Future, >> { - self.inner.lock().import_remote_statement(&*self.context, router, statement) + self.inner.lock().import_remote_statement(&*self.context, router, statement, self.max_block_data_size) } /// Import many statements at once. @@ -467,7 +476,7 @@ impl SharedTable { let mut inner = self.inner.lock(); iterable.into_iter().map(move |statement| { - inner.import_remote_statement(&*self.context, router, statement) + inner.import_remote_statement(&*self.context, router, statement, self.max_block_data_size) }).collect() } @@ -612,6 +621,7 @@ mod tests { local_key.clone(), parent_hash, ExtrinsicStore::new_in_memory(), + None, ); let candidate = CandidateReceipt { @@ -665,6 +675,7 @@ mod tests { local_key.clone(), parent_hash, ExtrinsicStore::new_in_memory(), + None, ); let candidate = CandidateReceipt { @@ -720,6 +731,7 @@ mod tests { }, relay_parent, extrinsic_store: store.clone(), + max_block_data_size: None, }; let validated = producer.prime_with(|_, _| Ok(Extrinsic { outgoing_messages: Vec::new() })) @@ -760,6 +772,7 @@ mod tests { }, relay_parent, extrinsic_store: store.clone(), + max_block_data_size: None, }; let validated = producer.prime_with(|_, _| Ok(Extrinsic { outgoing_messages: Vec::new() })) @@ -797,6 +810,7 @@ mod tests { local_key.clone(), parent_hash, ExtrinsicStore::new_in_memory(), + None, ); let candidate = CandidateReceipt { @@ -861,6 +875,7 @@ mod tests { local_key.clone(), parent_hash, ExtrinsicStore::new_in_memory(), + None, ); let candidate = CandidateReceipt { @@ -909,6 +924,7 @@ mod tests { Arc::new(AuthorityKeyring::Alice.pair()), Default::default(), ExtrinsicStore::new_in_memory(), + None, ); let expected_mapping = authorities.iter().enumerate().map(|(i, k)| (i as ValidatorIndex, k.clone())).collect(); assert_eq!(shared_table.context.index_mapping, expected_mapping);