diff --git a/polkadot/Cargo.lock b/polkadot/Cargo.lock index 7c998fc0a54d51d6432ffa3a3c29d30335dda889..287b58f8af77cbbaebcf7d167bcb34d328dfec92 100644 --- a/polkadot/Cargo.lock +++ b/polkadot/Cargo.lock @@ -8694,19 +8694,6 @@ dependencies = [ "test-parachain-adder", ] -[[package]] -name = "test-parachain-code-upgrader" -version = "0.7.22" -dependencies = [ - "dlmalloc", - "parity-scale-codec", - "polkadot-parachain", - "sp-io", - "sp-std", - "substrate-wasm-builder-runner 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.5.0", -] - [[package]] name = "test-parachain-halt" version = "0.8.22" @@ -8722,7 +8709,6 @@ dependencies = [ "polkadot-parachain", "sp-core", "test-parachain-adder", - "test-parachain-code-upgrader", "test-parachain-halt", "tiny-keccak 1.5.0", ] diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index 1c98ca8d0b85715ce85444b180ef8e4f63e9aedd..817851211fbdf7f16288ec8344e589ad2dd31fe9 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -70,7 +70,6 @@ members = [ "parachain/test-parachains", "parachain/test-parachains/adder", "parachain/test-parachains/adder/collator", - "parachain/test-parachains/code-upgrader", ] [badges] diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index 793616d907187074c7a1eafda2ede842186caeb7..c2f6f9bc2ceb74ce21de9648be0ebf2768f63992 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -34,13 +34,13 @@ use polkadot_node_subsystem::{ metrics::{self, prometheus}, }; use polkadot_node_subsystem_util::{ - self as util, request_availability_cores_ctx, request_global_validation_data_ctx, - request_local_validation_data_ctx, request_validators_ctx, + self as util, request_availability_cores_ctx, request_full_validation_data_ctx, + request_validators_ctx, }; use polkadot_primitives::v1::{ - collator_signature_payload, validation_data_hash, AvailableData, CandidateCommitments, - CandidateDescriptor, CandidateReceipt, CoreState, GlobalValidationData, Hash, - LocalValidationData, OccupiedCoreAssumption, PoV, + collator_signature_payload, AvailableData, CandidateCommitments, + CandidateDescriptor, CandidateReceipt, CoreState, Hash, OccupiedCoreAssumption, + PersistedValidationData, PoV, }; use sp_core::crypto::Pair; use std::sync::Arc; @@ -198,13 +198,11 @@ async fn handle_new_activations<Context: SubsystemContext>( for relay_parent in activated.iter().copied() { // double-future magic happens here: the first layer of requests takes a mutable borrow of the context, and // returns a receiver. The second layer of requests actually polls those receivers to completion. - let (global_validation_data, availability_cores, validators) = join!( - request_global_validation_data_ctx(relay_parent, ctx).await?, + let (availability_cores, validators) = join!( request_availability_cores_ctx(relay_parent, ctx).await?, request_validators_ctx(relay_parent, ctx).await?, ); - let global_validation_data = global_validation_data??; let availability_cores = availability_cores??; let n_validators = validators??.len(); @@ -224,9 +222,10 @@ async fn handle_new_activations<Context: SubsystemContext>( continue; } - // we get local validation data synchronously for each core instead of within the subtask loop, - // because we have only a single mutable handle to the context, so the work can't really be distributed - let local_validation_data = match request_local_validation_data_ctx( + // we get validation data synchronously for each core instead of + // within the subtask loop, because we have only a single mutable handle to the + // context, so the work can't really be distributed + let validation_data = match request_full_validation_data_ctx( relay_parent, scheduled_core.para_id, assumption, @@ -235,30 +234,32 @@ async fn handle_new_activations<Context: SubsystemContext>( .await? .await?? { - Some(local_validation_data) => local_validation_data, + Some(v) => v, None => continue, }; - let task_global_validation_data = global_validation_data.clone(); let task_config = config.clone(); let mut task_sender = sender.clone(); let metrics = metrics.clone(); ctx.spawn("collation generation collation builder", Box::pin(async move { - let validation_data_hash = - validation_data_hash(&task_global_validation_data, &local_validation_data); + let persisted_validation_data_hash = validation_data.persisted.hash(); - let collation = (task_config.collator)(&task_global_validation_data, &local_validation_data).await; + let collation = (task_config.collator)(&validation_data).await; let pov_hash = collation.proof_of_validity.hash(); let signature_payload = collator_signature_payload( &relay_parent, &scheduled_core.para_id, - &validation_data_hash, + &persisted_validation_data_hash, &pov_hash, ); - let erasure_root = match erasure_root(n_validators, local_validation_data, task_global_validation_data, collation.proof_of_validity.clone()) { + let erasure_root = match erasure_root( + n_validators, + validation_data.persisted, + collation.proof_of_validity.clone(), + ) { Ok(erasure_root) => erasure_root, Err(err) => { log::error!(target: "collation_generation", "failed to calculate erasure root for para_id {}: {:?}", scheduled_core.para_id, err); @@ -281,7 +282,7 @@ async fn handle_new_activations<Context: SubsystemContext>( para_id: scheduled_core.para_id, relay_parent, collator: task_config.key.public(), - validation_data_hash, + persisted_validation_data_hash, pov_hash, }, }; @@ -302,17 +303,11 @@ async fn handle_new_activations<Context: SubsystemContext>( fn erasure_root( n_validators: usize, - local_validation_data: LocalValidationData, - global_validation_data: GlobalValidationData, + persisted_validation: PersistedValidationData, pov: PoV, ) -> Result<Hash> { - let omitted_validation = polkadot_primitives::v1::OmittedValidationData { - global_validation: global_validation_data, - local_validation: local_validation_data, - }; - let available_data = AvailableData { - omitted_validation, + validation_data: persisted_validation, pov, }; @@ -369,8 +364,8 @@ mod tests { subsystem_test_harness, TestSubsystemContextHandle, }; use polkadot_primitives::v1::{ - BlockData, BlockNumber, CollatorPair, GlobalValidationData, Id as ParaId, - LocalValidationData, PoV, ScheduledCore, + BlockData, BlockNumber, CollatorPair, Id as ParaId, + PersistedValidationData, PoV, ScheduledCore, ValidationData, }; use std::pin::Pin; @@ -402,7 +397,7 @@ mod tests { fn test_config<Id: Into<ParaId>>(para_id: Id) -> Arc<CollationGenerationConfig> { Arc::new(CollationGenerationConfig { key: CollatorPair::generate().0, - collator: Box::new(|_gvd: &GlobalValidationData, _lvd: &LocalValidationData| { + collator: Box::new(|_vd: &ValidationData| { Box::new(TestCollator) }), para_id: para_id.into(), @@ -417,7 +412,7 @@ mod tests { } #[test] - fn requests_validation_and_availability_per_relay_parent() { + fn requests_availability_per_relay_parent() { let activated_hashes: Vec<Hash> = vec![ [1; 32].into(), [4; 32].into(), @@ -425,19 +420,13 @@ mod tests { [16; 32].into(), ]; - let requested_validation_data = Arc::new(Mutex::new(Vec::new())); let requested_availability_cores = Arc::new(Mutex::new(Vec::new())); - let overseer_requested_validation_data = requested_validation_data.clone(); let overseer_requested_availability_cores = requested_availability_cores.clone(); let overseer = |mut handle: TestSubsystemContextHandle<CollationGenerationMessage>| async move { loop { match handle.try_recv().await { None => break, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::GlobalValidationData(tx)))) => { - overseer_requested_validation_data.lock().await.push(hash); - tx.send(Ok(Default::default())).unwrap(); - } Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::AvailabilityCores(tx)))) => { overseer_requested_availability_cores.lock().await.push(hash); tx.send(Ok(vec![])).unwrap(); @@ -455,7 +444,7 @@ mod tests { let subsystem_activated_hashes = activated_hashes.clone(); subsystem_test_harness(overseer, |mut ctx| async move { handle_new_activations( - test_config(123), + test_config(123u32), &subsystem_activated_hashes, &mut ctx, Metrics(None), @@ -465,21 +454,16 @@ mod tests { .unwrap(); }); - let mut requested_validation_data = Arc::try_unwrap(requested_validation_data) - .expect("overseer should have shut down by now") - .into_inner(); - requested_validation_data.sort(); let mut requested_availability_cores = Arc::try_unwrap(requested_availability_cores) .expect("overseer should have shut down by now") .into_inner(); requested_availability_cores.sort(); - assert_eq!(requested_validation_data, activated_hashes); assert_eq!(requested_availability_cores, activated_hashes); } #[test] - fn requests_local_validation_for_scheduled_matches() { + fn requests_validation_data_for_scheduled_matches() { let activated_hashes: Vec<Hash> = vec![ Hash::repeat_byte(1), Hash::repeat_byte(4), @@ -487,19 +471,13 @@ mod tests { Hash::repeat_byte(16), ]; - let requested_local_validation_data = Arc::new(Mutex::new(Vec::new())); + let requested_full_validation_data = Arc::new(Mutex::new(Vec::new())); - let overseer_requested_local_validation_data = requested_local_validation_data.clone(); + let overseer_requested_full_validation_data = requested_full_validation_data.clone(); let overseer = |mut handle: TestSubsystemContextHandle<CollationGenerationMessage>| async move { loop { match handle.try_recv().await { None => break, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::GlobalValidationData(tx), - ))) => { - tx.send(Ok(Default::default())).unwrap(); - } Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( hash, RuntimeApiRequest::AvailabilityCores(tx), @@ -518,13 +496,13 @@ mod tests { } Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( hash, - RuntimeApiRequest::LocalValidationData( + RuntimeApiRequest::FullValidationData( _para_id, _occupied_core_assumption, tx, ), ))) => { - overseer_requested_local_validation_data + overseer_requested_full_validation_data .lock() .await .push(hash); @@ -551,7 +529,7 @@ mod tests { .unwrap(); }); - let requested_local_validation_data = Arc::try_unwrap(requested_local_validation_data) + let requested_full_validation_data = Arc::try_unwrap(requested_full_validation_data) .expect("overseer should have shut down by now") .into_inner(); @@ -559,7 +537,7 @@ mod tests { // each activated hash generates two scheduled cores: one with its value * 4, one with its value * 5 // given that the test configuration has a para_id of 16, there's only one way to get that value: with the 4 // hash. - assert_eq!(requested_local_validation_data, vec![[4; 32].into()]); + assert_eq!(requested_full_validation_data, vec![[4; 32].into()]); } #[test] @@ -575,12 +553,6 @@ mod tests { loop { match handle.try_recv().await { None => break, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::GlobalValidationData(tx), - ))) => { - tx.send(Ok(Default::default())).unwrap(); - } Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( hash, RuntimeApiRequest::AvailabilityCores(tx), @@ -599,7 +571,7 @@ mod tests { } Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( _hash, - RuntimeApiRequest::LocalValidationData( + RuntimeApiRequest::FullValidationData( _para_id, _occupied_core_assumption, tx, @@ -647,8 +619,8 @@ mod tests { // we don't care too much about the commitments_hash right now, but let's ensure that we've calculated the // correct descriptor let expect_pov_hash = test_collation().proof_of_validity.hash(); - let expect_validation_data_hash = - validation_data_hash::<BlockNumber>(&Default::default(), &Default::default()); + let expect_validation_data_hash + = PersistedValidationData::<BlockNumber>::default().hash(); let expect_relay_parent = Hash::repeat_byte(4); let expect_payload = collator_signature_payload( &expect_relay_parent, @@ -661,7 +633,7 @@ mod tests { para_id: config.para_id, relay_parent: expect_relay_parent, collator: config.key.public(), - validation_data_hash: expect_validation_data_hash, + persisted_validation_data_hash: expect_validation_data_hash, pov_hash: expect_pov_hash, }; @@ -680,7 +652,7 @@ mod tests { &collator_signature_payload( &descriptor.relay_parent, &descriptor.para_id, - &descriptor.validation_data_hash, + &descriptor.persisted_validation_data_hash, &descriptor.pov_hash, ) .as_ref(), diff --git a/polkadot/node/core/av-store/src/lib.rs b/polkadot/node/core/av-store/src/lib.rs index 84381e438e608b40830d110f34b1212d1654e494..5837377dd5f975bb8e6e75fec1115fe78c1dbd68 100644 --- a/polkadot/node/core/av-store/src/lib.rs +++ b/polkadot/node/core/av-store/src/lib.rs @@ -356,8 +356,7 @@ mod tests { }; use std::cell::RefCell; use polkadot_primitives::v1::{ - AvailableData, BlockData, HeadData, GlobalValidationData, LocalValidationData, PoV, - OmittedValidationData, + AvailableData, BlockData, HeadData, PersistedValidationData, PoV, }; use polkadot_node_subsystem_test_helpers as test_helpers; @@ -370,29 +369,19 @@ mod tests { } struct TestState { - global_validation_schedule: GlobalValidationData, - local_validation_data: LocalValidationData, + persisted_validation_data: PersistedValidationData, } impl Default for TestState { fn default() -> Self { - let local_validation_data = LocalValidationData { + let persisted_validation_data = PersistedValidationData { parent_head: HeadData(vec![7, 8, 9]), - balance: Default::default(), - code_upgrade_allowed: None, - validation_code_hash: Default::default(), - }; - - let global_validation_schedule = GlobalValidationData { - max_code_size: 1000, - max_head_data_size: 1000, block_number: Default::default(), + hrmp_mqc_heads: Vec::new(), }; - Self { - local_validation_data, - global_validation_schedule, + persisted_validation_data, } } } @@ -470,17 +459,9 @@ mod tests { block_data: BlockData(vec![4, 5, 6]), }; - let global_validation = test_state.global_validation_schedule; - let local_validation = test_state.local_validation_data; - - let omitted_validation = OmittedValidationData { - global_validation, - local_validation, - }; - let available_data = AvailableData { pov, - omitted_validation, + validation_data: test_state.persisted_validation_data, }; @@ -531,17 +512,9 @@ mod tests { block_data: BlockData(vec![4, 5, 6]), }; - let global_validation = test_state.global_validation_schedule; - let local_validation = test_state.local_validation_data; - - let omitted_validation = OmittedValidationData { - global_validation, - local_validation, - }; - let available_data = AvailableData { pov, - omitted_validation, + validation_data: test_state.persisted_validation_data, }; let no_metrics = Metrics(None); diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index 30a95965eb21cd066f89ef230d841bf552acbf62..6ca3b43d14fd229840f8ffe615827d7aa0bfb209 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -30,7 +30,7 @@ use futures::{ use keystore::KeyStorePtr; use polkadot_primitives::v1::{ CommittedCandidateReceipt, BackedCandidate, Id as ParaId, ValidatorId, - ValidatorIndex, SigningContext, PoV, OmittedValidationData, + ValidatorIndex, SigningContext, PoV, CandidateDescriptor, AvailableData, ValidatorSignature, Hash, CandidateReceipt, CandidateCommitments, CoreState, CoreIndex, }; @@ -623,14 +623,9 @@ impl CandidateBackingJob { outputs: ValidationOutputs, with_commitments: impl FnOnce(CandidateCommitments) -> Result<T, E>, ) -> Result<Result<T, E>, Error> { - let omitted_validation = OmittedValidationData { - global_validation: outputs.global_validation_data, - local_validation: outputs.local_validation_data, - }; - let available_data = AvailableData { pov, - omitted_validation, + validation_data: outputs.validation_data, }; let chunks = erasure_coding::obtain_chunks_v1( @@ -835,7 +830,7 @@ mod tests { use futures::{executor, future, Future}; use polkadot_primitives::v1::{ ScheduledCore, BlockData, CandidateCommitments, CollatorId, - LocalValidationData, GlobalValidationData, HeadData, + PersistedValidationData, ValidationData, TransientValidationData, HeadData, ValidatorPair, ValidityAttestation, GroupRotationInfo, }; use polkadot_subsystem::{ @@ -855,8 +850,7 @@ mod tests { keystore: KeyStorePtr, validators: Vec<Sr25519Keyring>, validator_public: Vec<ValidatorId>, - global_validation_data: GlobalValidationData, - local_validation_data: LocalValidationData, + validation_data: ValidationData, validator_groups: (Vec<Vec<ValidatorIndex>>, GroupRotationInfo), availability_cores: Vec<CoreState>, head_data: HashMap<ParaId, HeadData>, @@ -920,17 +914,18 @@ mod tests { parent_hash: relay_parent, }; - let local_validation_data = LocalValidationData { - parent_head: HeadData(vec![7, 8, 9]), - balance: Default::default(), - code_upgrade_allowed: None, - validation_code_hash: Default::default(), - }; - - let global_validation_data = GlobalValidationData { - max_code_size: 1000, - max_head_data_size: 1000, - block_number: Default::default(), + let validation_data = ValidationData { + persisted: PersistedValidationData { + parent_head: HeadData(vec![7, 8, 9]), + block_number: Default::default(), + hrmp_mqc_heads: Vec::new(), + }, + transient: TransientValidationData { + max_code_size: 1000, + max_head_data_size: 1000, + balance: Default::default(), + code_upgrade_allowed: None, + }, }; Self { @@ -941,8 +936,7 @@ mod tests { validator_groups: (validator_groups, group_rotation_info), availability_cores, head_data, - local_validation_data, - global_validation_data, + validation_data, signing_context, relay_parent, } @@ -971,13 +965,8 @@ mod tests { } fn make_erasure_root(test: &TestState, pov: PoV) -> Hash { - let omitted_validation = OmittedValidationData { - global_validation: test.global_validation_data.clone(), - local_validation: test.local_validation_data.clone(), - }; - let available_data = AvailableData { - omitted_validation, + validation_data: test.validation_data.persisted.clone(), pov, }; @@ -1109,8 +1098,7 @@ mod tests { ) if pov == pov && &c == candidate.descriptor() => { tx.send(Ok( ValidationResult::Valid(ValidationOutputs { - global_validation_data: test_state.global_validation_data, - local_validation_data: test_state.local_validation_data, + validation_data: test_state.validation_data.persisted, head_data: expected_head_data.clone(), upward_messages: Vec::new(), fees: Default::default(), @@ -1221,8 +1209,7 @@ mod tests { ) if pov == pov && &c == candidate_a.descriptor() => { tx.send(Ok( ValidationResult::Valid(ValidationOutputs { - global_validation_data: test_state.global_validation_data, - local_validation_data: test_state.local_validation_data, + validation_data: test_state.validation_data.persisted, head_data: expected_head_data.clone(), upward_messages: Vec::new(), fees: Default::default(), @@ -1351,8 +1338,7 @@ mod tests { ) if pov == pov && &c == candidate_a.descriptor() => { tx.send(Ok( ValidationResult::Valid(ValidationOutputs { - global_validation_data: test_state.global_validation_data, - local_validation_data: test_state.local_validation_data, + validation_data: test_state.validation_data.persisted, head_data: expected_head_data.clone(), upward_messages: Vec::new(), fees: Default::default(), @@ -1508,8 +1494,7 @@ mod tests { ) if pov == pov && &c == candidate_b.descriptor() => { tx.send(Ok( ValidationResult::Valid(ValidationOutputs { - global_validation_data: test_state.global_validation_data, - local_validation_data: test_state.local_validation_data, + validation_data: test_state.validation_data.persisted, head_data: expected_head_data.clone(), upward_messages: Vec::new(), fees: Default::default(), diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index bb832ee19554cd4e2bca134de67d7fdc6e13db14..600dde2c4e72a14bf06dd7243e28f79e88d34f8d 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -32,8 +32,8 @@ use polkadot_subsystem::{ use polkadot_subsystem::errors::RuntimeApiError; use polkadot_node_primitives::{ValidationResult, ValidationOutputs, InvalidCandidate}; use polkadot_primitives::v1::{ - ValidationCode, OmittedValidationData, PoV, CandidateDescriptor, LocalValidationData, - GlobalValidationData, OccupiedCoreAssumption, Hash, validation_data_hash, + ValidationCode, PoV, CandidateDescriptor, ValidationData, PersistedValidationData, + TransientValidationData, OccupiedCoreAssumption, Hash, }; use polkadot_parachain::wasm_executor::{self, ValidationPool, ExecutionMode, ValidationError, InvalidCandidate as WasmInvalidCandidate}; @@ -158,7 +158,8 @@ async fn run( } } CandidateValidationMessage::ValidateFromExhaustive( - omitted_validation, + persisted_validation_data, + transient_validation_data, validation_code, descriptor, pov, @@ -167,7 +168,8 @@ async fn run( let res = spawn_validate_exhaustive( &mut ctx, Some(pool.clone()), - omitted_validation, + persisted_validation_data, + transient_validation_data, validation_code, descriptor, pov, @@ -210,7 +212,7 @@ async fn runtime_api_request<T>( #[derive(Debug)] enum AssumptionCheckOutcome { - Matches(OmittedValidationData, ValidationCode), + Matches(ValidationData, ValidationCode), DoesNotMatch, BadRequest, } @@ -218,15 +220,14 @@ enum AssumptionCheckOutcome { async fn check_assumption_validation_data( ctx: &mut impl SubsystemContext<Message = CandidateValidationMessage>, descriptor: &CandidateDescriptor, - global_validation_data: &GlobalValidationData, assumption: OccupiedCoreAssumption, ) -> SubsystemResult<AssumptionCheckOutcome> { - let local_validation_data = { + let validation_data = { let (tx, rx) = oneshot::channel(); let d = runtime_api_request( ctx, descriptor.relay_parent, - RuntimeApiRequest::LocalValidationData( + RuntimeApiRequest::FullValidationData( descriptor.para_id, assumption, tx, @@ -242,17 +243,9 @@ async fn check_assumption_validation_data( } }; - let validation_data_hash = validation_data_hash( - &global_validation_data, - &local_validation_data, - ); - - SubsystemResult::Ok(if descriptor.validation_data_hash == validation_data_hash { - let omitted_validation = OmittedValidationData { - global_validation: global_validation_data.clone(), - local_validation: local_validation_data, - }; + let persisted_validation_data_hash = validation_data.persisted.hash(); + SubsystemResult::Ok(if descriptor.persisted_validation_data_hash == persisted_validation_data_hash { let (code_tx, code_rx) = oneshot::channel(); let validation_code = runtime_api_request( ctx, @@ -267,7 +260,7 @@ async fn check_assumption_validation_data( match validation_code { Ok(None) | Err(_) => AssumptionCheckOutcome::BadRequest, - Ok(Some(v)) => AssumptionCheckOutcome::Matches(omitted_validation, v), + Ok(Some(v)) => AssumptionCheckOutcome::Matches(validation_data, v), } } else { AssumptionCheckOutcome::DoesNotMatch @@ -281,44 +274,21 @@ async fn spawn_validate_from_chain_state( pov: Arc<PoV>, spawn: impl SpawnNamed + 'static, ) -> SubsystemResult<Result<ValidationResult, ValidationFailed>> { - // The candidate descriptor has a `validation_data_hash` which corresponds to + // The candidate descriptor has a `persisted_validation_data_hash` which corresponds to // one of up to two possible values that we can derive from the state of the - // relay-parent. We can fetch these values by getting the `global_validation_data`, - // and both `local_validation_data` based on the different `OccupiedCoreAssumption`s. - let global_validation_data = { - let (tx, rx) = oneshot::channel(); - let res = runtime_api_request( - ctx, - descriptor.relay_parent, - RuntimeApiRequest::GlobalValidationData(tx), - rx, - ).await?; - - match res { - Ok(g) => g, - Err(e) => { - log::warn!( - target: LOG_TARGET, - "Error making runtime API request: {:?}", - e, - ); - - return Ok(Err(ValidationFailed("Error making API request".into()))); - } - } - }; - + // relay-parent. We can fetch these values by getting the persisted validation data + // based on the different `OccupiedCoreAssumption`s. match check_assumption_validation_data( ctx, &descriptor, - &global_validation_data, OccupiedCoreAssumption::Included, ).await? { - AssumptionCheckOutcome::Matches(omitted_validation, validation_code) => { + AssumptionCheckOutcome::Matches(validation_data, validation_code) => { return spawn_validate_exhaustive( ctx, validation_pool, - omitted_validation, + validation_data.persisted, + Some(validation_data.transient), validation_code, descriptor, pov, @@ -332,14 +302,14 @@ async fn spawn_validate_from_chain_state( match check_assumption_validation_data( ctx, &descriptor, - &global_validation_data, OccupiedCoreAssumption::TimedOut, ).await? { - AssumptionCheckOutcome::Matches(omitted_validation, validation_code) => { + AssumptionCheckOutcome::Matches(validation_data, validation_code) => { return spawn_validate_exhaustive( ctx, validation_pool, - omitted_validation, + validation_data.persisted, + Some(validation_data.transient), validation_code, descriptor, pov, @@ -351,7 +321,7 @@ async fn spawn_validate_from_chain_state( } // If neither the assumption of the occupied core having the para included or the assumption - // of the occupied core timing out are valid, then the validation_data_hash in the descriptor + // of the occupied core timing out are valid, then the persisted_validation_data_hash in the descriptor // is not based on the relay parent and is thus invalid. Ok(Ok(ValidationResult::Invalid(InvalidCandidate::BadParent))) } @@ -359,7 +329,8 @@ async fn spawn_validate_from_chain_state( async fn spawn_validate_exhaustive( ctx: &mut impl SubsystemContext<Message = CandidateValidationMessage>, validation_pool: Option<ValidationPool>, - omitted_validation: OmittedValidationData, + persisted_validation_data: PersistedValidationData, + transient_validation_data: Option<TransientValidationData>, validation_code: ValidationCode, descriptor: CandidateDescriptor, pov: Arc<PoV>, @@ -369,7 +340,8 @@ async fn spawn_validate_exhaustive( let fut = async move { let res = validate_candidate_exhaustive::<RealValidationBackend, _>( validation_pool, - omitted_validation, + persisted_validation_data, + transient_validation_data, validation_code, descriptor, pov, @@ -414,16 +386,19 @@ fn perform_basic_checks( /// /// Returns `Ok(())` if checks pass, error otherwise. fn check_wasm_result_against_constraints( - global_validation_data: &GlobalValidationData, - _local_validation_data: &LocalValidationData, + transient_params: &TransientValidationData, result: &WasmValidationResult, ) -> Result<(), InvalidCandidate> { - if result.head_data.0.len() > global_validation_data.max_head_data_size as _ { + if result.head_data.0.len() > transient_params.max_head_data_size as _ { return Err(InvalidCandidate::HeadDataTooLarge(result.head_data.0.len() as u64)) } if let Some(ref code) = result.new_validation_code { - if code.0.len() > global_validation_data.max_code_size as _ { + if transient_params.code_upgrade_allowed.is_none() { + return Err(InvalidCandidate::CodeUpgradeNotAllowed) + } + + if code.0.len() > transient_params.max_code_size as _ { return Err(InvalidCandidate::NewCodeTooLarge(code.0.len() as u64)) } } @@ -471,7 +446,8 @@ impl ValidationBackend for RealValidationBackend { /// Sends the result of validation on the channel once complete. fn validate_candidate_exhaustive<B: ValidationBackend, S: SpawnNamed + 'static>( backend_arg: B::Arg, - omitted_validation: OmittedValidationData, + persisted_validation_data: PersistedValidationData, + transient_validation_data: Option<TransientValidationData>, validation_code: ValidationCode, descriptor: CandidateDescriptor, pov: Arc<PoV>, @@ -481,15 +457,11 @@ fn validate_candidate_exhaustive<B: ValidationBackend, S: SpawnNamed + 'static>( return Ok(ValidationResult::Invalid(e)) } - let OmittedValidationData { global_validation, local_validation } = omitted_validation; - let params = ValidationParams { - parent_head: local_validation.parent_head.clone(), + parent_head: persisted_validation_data.parent_head.clone(), block_data: pov.block_data.clone(), - max_code_size: global_validation.max_code_size, - max_head_data_size: global_validation.max_head_data_size, - relay_chain_height: global_validation.block_number, - code_upgrade_allowed: local_validation.code_upgrade_allowed, + relay_chain_height: persisted_validation_data.block_number, + hrmp_mqc_heads: persisted_validation_data.hrmp_mqc_heads.clone(), }; match B::validate(backend_arg, &validation_code, params, spawn) { @@ -507,17 +479,19 @@ fn validate_candidate_exhaustive<B: ValidationBackend, S: SpawnNamed + 'static>( Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(e.to_string()))), Err(ValidationError::Internal(e)) => Err(ValidationFailed(e.to_string())), Ok(res) => { - let post_check_result = check_wasm_result_against_constraints( - &global_validation, - &local_validation, - &res, - ); + let post_check_result = if let Some(transient) = transient_validation_data { + check_wasm_result_against_constraints( + &transient, + &res, + ) + } else { + Ok(()) + }; Ok(match post_check_result { Ok(()) => ValidationResult::Valid(ValidationOutputs { head_data: res.head_data, - global_validation_data: global_validation, - local_validation_data: local_validation, + validation_data: persisted_validation_data, upward_messages: res.upward_messages, fees: 0, new_validation_code: res.new_validation_code, @@ -562,7 +536,7 @@ mod tests { let payload = polkadot_primitives::v1::collator_signature_payload( &descriptor.relay_parent, &descriptor.para_id, - &descriptor.validation_data_hash, + &descriptor.persisted_validation_data_hash, &descriptor.pov_hash, ); @@ -572,17 +546,16 @@ mod tests { #[test] fn correctly_checks_included_assumption() { - let local_validation_data = LocalValidationData::default(); - let global_validation_data = GlobalValidationData::default(); + let validation_data: ValidationData = Default::default(); let validation_code: ValidationCode = vec![1, 2, 3].into(); - let validation_data_hash = validation_data_hash(&global_validation_data, &local_validation_data); + let persisted_validation_data_hash = validation_data.persisted.hash(); let relay_parent = [2; 32].into(); let para_id = 5.into(); let mut candidate = CandidateDescriptor::default(); candidate.relay_parent = relay_parent; - candidate.validation_data_hash = validation_data_hash; + candidate.persisted_validation_data_hash = persisted_validation_data_hash; candidate.para_id = para_id; let pool = TaskExecutor::new(); @@ -591,22 +564,20 @@ mod tests { let (check_fut, check_result) = check_assumption_validation_data( &mut ctx, &candidate, - &global_validation_data, OccupiedCoreAssumption::Included, ).remote_handle(); - let global_validation_data = global_validation_data.clone(); let test_fut = async move { assert_matches!( ctx_handle.recv().await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( rp, - RuntimeApiRequest::LocalValidationData(p, OccupiedCoreAssumption::Included, tx) + RuntimeApiRequest::FullValidationData(p, OccupiedCoreAssumption::Included, tx) )) => { assert_eq!(rp, relay_parent); assert_eq!(p, para_id); - let _ = tx.send(Ok(Some(local_validation_data.clone()))); + let _ = tx.send(Ok(Some(validation_data.clone()))); } ); @@ -624,11 +595,7 @@ mod tests { ); assert_matches!(check_result.await.unwrap(), AssumptionCheckOutcome::Matches(o, v) => { - assert_eq!(o, OmittedValidationData { - local_validation: local_validation_data, - global_validation: global_validation_data, - }); - + assert_eq!(o, validation_data); assert_eq!(v, validation_code); }); }; @@ -639,17 +606,16 @@ mod tests { #[test] fn correctly_checks_timed_out_assumption() { - let local_validation_data = LocalValidationData::default(); - let global_validation_data = GlobalValidationData::default(); + let validation_data: ValidationData = Default::default(); let validation_code: ValidationCode = vec![1, 2, 3].into(); - let validation_data_hash = validation_data_hash(&global_validation_data, &local_validation_data); + let persisted_validation_data_hash = validation_data.persisted.hash(); let relay_parent = [2; 32].into(); let para_id = 5.into(); let mut candidate = CandidateDescriptor::default(); candidate.relay_parent = relay_parent; - candidate.validation_data_hash = validation_data_hash; + candidate.persisted_validation_data_hash = persisted_validation_data_hash; candidate.para_id = para_id; let pool = TaskExecutor::new(); @@ -658,22 +624,20 @@ mod tests { let (check_fut, check_result) = check_assumption_validation_data( &mut ctx, &candidate, - &global_validation_data, OccupiedCoreAssumption::TimedOut, ).remote_handle(); - let global_validation_data = global_validation_data.clone(); let test_fut = async move { assert_matches!( ctx_handle.recv().await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( rp, - RuntimeApiRequest::LocalValidationData(p, OccupiedCoreAssumption::TimedOut, tx) + RuntimeApiRequest::FullValidationData(p, OccupiedCoreAssumption::TimedOut, tx) )) => { assert_eq!(rp, relay_parent); assert_eq!(p, para_id); - let _ = tx.send(Ok(Some(local_validation_data.clone()))); + let _ = tx.send(Ok(Some(validation_data.clone()))); } ); @@ -691,11 +655,7 @@ mod tests { ); assert_matches!(check_result.await.unwrap(), AssumptionCheckOutcome::Matches(o, v) => { - assert_eq!(o, OmittedValidationData { - local_validation: local_validation_data, - global_validation: global_validation_data, - }); - + assert_eq!(o, validation_data); assert_eq!(v, validation_code); }); }; @@ -706,16 +666,14 @@ mod tests { #[test] fn check_is_bad_request_if_no_validation_data() { - let local_validation_data = LocalValidationData::default(); - let global_validation_data = GlobalValidationData::default(); - - let validation_data_hash = validation_data_hash(&global_validation_data, &local_validation_data); + let validation_data: ValidationData = Default::default(); + let persisted_validation_data_hash = validation_data.persisted.hash(); let relay_parent = [2; 32].into(); let para_id = 5.into(); let mut candidate = CandidateDescriptor::default(); candidate.relay_parent = relay_parent; - candidate.validation_data_hash = validation_data_hash; + candidate.persisted_validation_data_hash = persisted_validation_data_hash; candidate.para_id = para_id; let pool = TaskExecutor::new(); @@ -724,7 +682,6 @@ mod tests { let (check_fut, check_result) = check_assumption_validation_data( &mut ctx, &candidate, - &global_validation_data, OccupiedCoreAssumption::Included, ).remote_handle(); @@ -733,7 +690,7 @@ mod tests { ctx_handle.recv().await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( rp, - RuntimeApiRequest::LocalValidationData(p, OccupiedCoreAssumption::Included, tx) + RuntimeApiRequest::FullValidationData(p, OccupiedCoreAssumption::Included, tx) )) => { assert_eq!(rp, relay_parent); assert_eq!(p, para_id); @@ -751,16 +708,14 @@ mod tests { #[test] fn check_is_bad_request_if_no_validation_code() { - let local_validation_data = LocalValidationData::default(); - let global_validation_data = GlobalValidationData::default(); - - let validation_data_hash = validation_data_hash(&global_validation_data, &local_validation_data); + let validation_data: ValidationData = Default::default(); + let persisted_validation_data_hash = validation_data.persisted.hash(); let relay_parent = [2; 32].into(); let para_id = 5.into(); let mut candidate = CandidateDescriptor::default(); candidate.relay_parent = relay_parent; - candidate.validation_data_hash = validation_data_hash; + candidate.persisted_validation_data_hash = persisted_validation_data_hash; candidate.para_id = para_id; let pool = TaskExecutor::new(); @@ -769,7 +724,6 @@ mod tests { let (check_fut, check_result) = check_assumption_validation_data( &mut ctx, &candidate, - &global_validation_data, OccupiedCoreAssumption::TimedOut, ).remote_handle(); @@ -778,12 +732,12 @@ mod tests { ctx_handle.recv().await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( rp, - RuntimeApiRequest::LocalValidationData(p, OccupiedCoreAssumption::TimedOut, tx) + RuntimeApiRequest::FullValidationData(p, OccupiedCoreAssumption::TimedOut, tx) )) => { assert_eq!(rp, relay_parent); assert_eq!(p, para_id); - let _ = tx.send(Ok(Some(local_validation_data.clone()))); + let _ = tx.send(Ok(Some(validation_data.clone()))); } ); @@ -809,15 +763,13 @@ mod tests { #[test] fn check_does_not_match() { - let local_validation_data = LocalValidationData::default(); - let global_validation_data = GlobalValidationData::default(); - + let validation_data: ValidationData = Default::default(); let relay_parent = [2; 32].into(); let para_id = 5.into(); let mut candidate = CandidateDescriptor::default(); candidate.relay_parent = relay_parent; - candidate.validation_data_hash = [3; 32].into(); + candidate.persisted_validation_data_hash = [3; 32].into(); candidate.para_id = para_id; let pool = TaskExecutor::new(); @@ -826,7 +778,6 @@ mod tests { let (check_fut, check_result) = check_assumption_validation_data( &mut ctx, &candidate, - &global_validation_data, OccupiedCoreAssumption::Included, ).remote_handle(); @@ -835,12 +786,12 @@ mod tests { ctx_handle.recv().await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( rp, - RuntimeApiRequest::LocalValidationData(p, OccupiedCoreAssumption::Included, tx) + RuntimeApiRequest::FullValidationData(p, OccupiedCoreAssumption::Included, tx) )) => { assert_eq!(rp, relay_parent); assert_eq!(p, para_id); - let _ = tx.send(Ok(Some(local_validation_data.clone()))); + let _ = tx.send(Ok(Some(validation_data.clone()))); } ); @@ -853,13 +804,10 @@ mod tests { #[test] fn candidate_validation_ok_is_ok() { - let mut omitted_validation = OmittedValidationData { - local_validation: Default::default(), - global_validation: Default::default(), - }; - - omitted_validation.global_validation.max_head_data_size = 1024; - omitted_validation.global_validation.max_code_size = 1024; + let mut validation_data: ValidationData = Default::default(); + validation_data.transient.max_head_data_size = 1024; + validation_data.transient.max_code_size = 1024; + validation_data.transient.code_upgrade_allowed = Some(20); let pov = PoV { block_data: BlockData(vec![1; 32]) }; @@ -877,14 +825,14 @@ mod tests { }; assert!(check_wasm_result_against_constraints( - &omitted_validation.global_validation, - &omitted_validation.local_validation, + &validation_data.transient, &validation_result, ).is_ok()); let v = validate_candidate_exhaustive::<MockValidationBackend, _>( MockValidationArg { result: Ok(validation_result) }, - omitted_validation.clone(), + validation_data.persisted.clone(), + Some(validation_data.transient), vec![1, 2, 3].into(), descriptor, Arc::new(pov), @@ -893,8 +841,7 @@ mod tests { assert_matches!(v, ValidationResult::Valid(outputs) => { assert_eq!(outputs.head_data, HeadData(vec![1, 1, 1])); - assert_eq!(outputs.global_validation_data, omitted_validation.global_validation); - assert_eq!(outputs.local_validation_data, omitted_validation.local_validation); + assert_eq!(outputs.validation_data, validation_data.persisted); assert_eq!(outputs.upward_messages, Vec::new()); assert_eq!(outputs.fees, 0); assert_eq!(outputs.new_validation_code, Some(vec![2, 2, 2].into())); @@ -903,13 +850,11 @@ mod tests { #[test] fn candidate_validation_bad_return_is_invalid() { - let mut omitted_validation = OmittedValidationData { - local_validation: Default::default(), - global_validation: Default::default(), - }; + let mut validation_data: ValidationData = Default::default(); - omitted_validation.global_validation.max_head_data_size = 1024; - omitted_validation.global_validation.max_code_size = 1024; + validation_data.transient.max_head_data_size = 1024; + validation_data.transient.max_code_size = 1024; + validation_data.transient.code_upgrade_allowed = Some(20); let pov = PoV { block_data: BlockData(vec![1; 32]) }; @@ -927,8 +872,7 @@ mod tests { }; assert!(check_wasm_result_against_constraints( - &omitted_validation.global_validation, - &omitted_validation.local_validation, + &validation_data.transient, &validation_result, ).is_ok()); @@ -938,7 +882,8 @@ mod tests { WasmInvalidCandidate::BadReturn )) }, - omitted_validation.clone(), + validation_data.persisted, + Some(validation_data.transient), vec![1, 2, 3].into(), descriptor, Arc::new(pov), @@ -951,13 +896,11 @@ mod tests { #[test] fn candidate_validation_timeout_is_internal_error() { - let mut omitted_validation = OmittedValidationData { - local_validation: Default::default(), - global_validation: Default::default(), - }; + let mut validation_data: ValidationData = Default::default(); - omitted_validation.global_validation.max_head_data_size = 1024; - omitted_validation.global_validation.max_code_size = 1024; + validation_data.transient.max_head_data_size = 1024; + validation_data.transient.max_code_size = 1024; + validation_data.transient.code_upgrade_allowed = Some(20); let pov = PoV { block_data: BlockData(vec![1; 32]) }; @@ -975,8 +918,7 @@ mod tests { }; assert!(check_wasm_result_against_constraints( - &omitted_validation.global_validation, - &omitted_validation.local_validation, + &validation_data.transient, &validation_result, ).is_ok()); @@ -986,7 +928,8 @@ mod tests { WasmInvalidCandidate::Timeout )) }, - omitted_validation.clone(), + validation_data.persisted, + Some(validation_data.transient), vec![1, 2, 3].into(), descriptor, Arc::new(pov), @@ -995,4 +938,49 @@ mod tests { assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))); } + + #[test] + fn candidate_validation_ok_does_not_validate_outputs_if_no_transient() { + let mut validation_data: ValidationData = Default::default(); + validation_data.transient.max_head_data_size = 1; + validation_data.transient.max_code_size = 1; + + let pov = PoV { block_data: BlockData(vec![1; 32]) }; + + let mut descriptor = CandidateDescriptor::default(); + descriptor.pov_hash = pov.hash(); + collator_sign(&mut descriptor, Sr25519Keyring::Alice); + + assert!(perform_basic_checks(&descriptor, Some(1024), &pov).is_ok()); + + let validation_result = WasmValidationResult { + head_data: HeadData(vec![1, 1, 1]), + new_validation_code: Some(vec![2, 2, 2].into()), + upward_messages: Vec::new(), + processed_downward_messages: 0, + }; + + assert!(check_wasm_result_against_constraints( + &validation_data.transient, + &validation_result, + ).is_err()); + + let v = validate_candidate_exhaustive::<MockValidationBackend, _>( + MockValidationArg { result: Ok(validation_result) }, + validation_data.persisted.clone(), + None, + vec![1, 2, 3].into(), + descriptor, + Arc::new(pov), + TaskExecutor::new(), + ).unwrap(); + + assert_matches!(v, ValidationResult::Valid(outputs) => { + assert_eq!(outputs.head_data, HeadData(vec![1, 1, 1])); + assert_eq!(outputs.validation_data, validation_data.persisted); + assert_eq!(outputs.upward_messages, Vec::new()); + assert_eq!(outputs.fees, 0); + assert_eq!(outputs.new_validation_code, Some(vec![2, 2, 2].into())); + }); + } } diff --git a/polkadot/node/core/provisioner/src/lib.rs b/polkadot/node/core/provisioner/src/lib.rs index ef93d15ab8324550e3712d3b5c2c0b667b3119e2..24254734289bd9c6f00f6d44158bb56298f5d8c1 100644 --- a/polkadot/node/core/provisioner/src/lib.rs +++ b/polkadot/node/core/provisioner/src/lib.rs @@ -35,11 +35,10 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_util::{ self as util, delegated_subsystem, - request_availability_cores, request_global_validation_data, - request_local_validation_data, JobTrait, ToJobTrait, + request_availability_cores, request_persisted_validation_data, JobTrait, ToJobTrait, }; use polkadot_primitives::v1::{ - validation_data_hash, BackedCandidate, BlockNumber, CoreState, Hash, OccupiedCoreAssumption, + BackedCandidate, BlockNumber, CoreState, Hash, OccupiedCoreAssumption, SignedAvailabilityBitfield, }; use std::{collections::HashMap, convert::TryFrom, pin::Pin}; @@ -355,10 +354,6 @@ async fn select_candidates( ) -> Result<Vec<BackedCandidate>, Error> { let block_number = get_block_number_under_construction(relay_parent, sender).await?; - let global_validation_data = request_global_validation_data(relay_parent, sender) - .await? - .await??; - let mut selected_candidates = Vec::with_capacity(candidates.len().min(availability_cores.len())); @@ -387,7 +382,7 @@ async fn select_candidates( _ => continue, }; - let local_validation_data = match request_local_validation_data( + let validation_data = match request_persisted_validation_data( relay_parent, scheduled_core.para_id, assumption, @@ -396,18 +391,17 @@ async fn select_candidates( .await? .await?? { - Some(local_validation_data) => local_validation_data, + Some(v) => v, None => continue, }; - let computed_validation_data_hash = - validation_data_hash(&global_validation_data, &local_validation_data); + let computed_validation_data_hash = validation_data.hash(); // we arbitrarily pick the first of the backed candidates which match the appropriate selection criteria if let Some(candidate) = candidates.iter().find(|backed_candidate| { let descriptor = &backed_candidate.candidate.descriptor; descriptor.para_id == scheduled_core.para_id - && descriptor.validation_data_hash == computed_validation_data_hash + && descriptor.persisted_validation_data_hash == computed_validation_data_hash }) { selected_candidates.push(candidate.clone()); } @@ -657,10 +651,10 @@ mod tests { use super::super::*; use super::{build_occupied_core, default_bitvec, occupied_core, scheduled_core}; use polkadot_node_subsystem::messages::RuntimeApiRequest::{ - AvailabilityCores, GlobalValidationData, LocalValidationData, + AvailabilityCores, PersistedValidationData as PersistedValidationDataReq, }; use polkadot_primitives::v1::{ - BlockNumber, CandidateDescriptor, CommittedCandidateReceipt, + BlockNumber, CandidateDescriptor, CommittedCandidateReceipt, PersistedValidationData, }; use FromJob::{ChainApi, Runtime}; @@ -771,12 +765,9 @@ mod tests { ChainApi(BlockNumber(_relay_parent, tx)) => { tx.send(Ok(Some(BLOCK_UNDER_PRODUCTION - 1))).unwrap() } - Runtime(Request(_parent_hash, GlobalValidationData(tx))) => { - tx.send(Ok(Default::default())).unwrap() - } Runtime(Request( _parent_hash, - LocalValidationData(_para_id, _assumption, tx), + PersistedValidationDataReq(_para_id, _assumption, tx), )) => tx.send(Ok(Some(Default::default()))).unwrap(), Runtime(Request(_parent_hash, AvailabilityCores(tx))) => { tx.send(Ok(mock_availability_cores())).unwrap() @@ -823,14 +814,12 @@ mod tests { fn selects_correct_candidates() { let mock_cores = mock_availability_cores(); - let empty_hash = - validation_data_hash::<BlockNumber>(&Default::default(), &Default::default()); - dbg!(empty_hash); + let empty_hash = PersistedValidationData::<BlockNumber>::default().hash(); let candidate_template = BackedCandidate { candidate: CommittedCandidateReceipt { descriptor: CandidateDescriptor { - validation_data_hash: empty_hash, + persisted_validation_data_hash: empty_hash, ..Default::default() }, ..Default::default() @@ -855,7 +844,8 @@ mod tests { candidate } else if idx < mock_cores.len() * 2 { // for the second repetition of the candidates, give them the wrong hash - candidate.candidate.descriptor.validation_data_hash = Default::default(); + candidate.candidate.descriptor.persisted_validation_data_hash + = Default::default(); candidate } else { // third go-around: right hash, wrong para_id diff --git a/polkadot/node/core/runtime-api/src/lib.rs b/polkadot/node/core/runtime-api/src/lib.rs index dd5f247eb0dad6b9d4a26016829d95b227c8f8a3..3c05b71dd7000405b8e711c1879f90feed2f2bc3 100644 --- a/polkadot/node/core/runtime-api/src/lib.rs +++ b/polkadot/node/core/runtime-api/src/lib.rs @@ -110,9 +110,10 @@ fn make_runtime_api_request<Client>( Request::Validators(sender) => query!(validators(), sender), Request::ValidatorGroups(sender) => query!(validator_groups(), sender), Request::AvailabilityCores(sender) => query!(availability_cores(), sender), - Request::GlobalValidationData(sender) => query!(global_validation_data(), sender), - Request::LocalValidationData(para, assumption, sender) => - query!(local_validation_data(para, assumption), sender), + Request::PersistedValidationData(para, assumption, sender) => + query!(persisted_validation_data(para, assumption), sender), + Request::FullValidationData(para, assumption, sender) => + query!(full_validation_data(para, assumption), sender), Request::SessionIndexForChild(sender) => query!(session_index_for_child(), sender), Request::ValidationCode(para, assumption, sender) => query!(validation_code(para, assumption), sender), @@ -166,8 +167,8 @@ mod tests { use super::*; use polkadot_primitives::v1::{ - ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, GlobalValidationData, - Id as ParaId, OccupiedCoreAssumption, LocalValidationData, SessionIndex, ValidationCode, + ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, PersistedValidationData, + Id as ParaId, OccupiedCoreAssumption, ValidationData, SessionIndex, ValidationCode, CommittedCandidateReceipt, CandidateEvent, }; use polkadot_node_subsystem_test_helpers as test_helpers; @@ -181,8 +182,7 @@ mod tests { validators: Vec<ValidatorId>, validator_groups: Vec<Vec<ValidatorIndex>>, availability_cores: Vec<CoreState>, - global_validation_data: GlobalValidationData, - local_validation_data: HashMap<ParaId, LocalValidationData>, + validation_data: HashMap<ParaId, ValidationData>, session_index_for_child: SessionIndex, validation_code: HashMap<ParaId, ValidationCode>, candidate_pending_availability: HashMap<ParaId, CommittedCandidateReceipt>, @@ -220,16 +220,20 @@ mod tests { self.availability_cores.clone() } - fn global_validation_data(&self) -> GlobalValidationData { - self.global_validation_data.clone() + fn persisted_validation_data( + &self, + para: ParaId, + _assumption: OccupiedCoreAssumption, + ) -> Option<PersistedValidationData> { + self.validation_data.get(¶).map(|l| l.persisted.clone()) } - fn local_validation_data( + fn full_validation_data( &self, para: ParaId, _assumption: OccupiedCoreAssumption, - ) -> Option<LocalValidationData> { - self.local_validation_data.get(¶).map(|l| l.clone()) + ) -> Option<ValidationData> { + self.validation_data.get(¶).map(|l| l.clone()) } fn session_index_for_child(&self) -> SessionIndex { @@ -327,10 +331,14 @@ mod tests { } #[test] - fn requests_global_validation_data() { + fn requests_persisted_validation_data() { let (ctx, mut ctx_handle) = test_helpers::make_subsystem_context(TaskExecutor::new()); - let runtime_api = MockRuntimeApi::default(); + let mut runtime_api = MockRuntimeApi::default(); let relay_parent = [1; 32].into(); + let para_a = 5.into(); + let para_b = 6.into(); + + runtime_api.validation_data.insert(para_a, Default::default()); let subsystem = RuntimeApiSubsystem::new(runtime_api.clone(), Metrics(None)); let subsystem_task = run(ctx, subsystem).map(|x| x.unwrap()); @@ -338,10 +346,23 @@ mod tests { let (tx, rx) = oneshot::channel(); ctx_handle.send(FromOverseer::Communication { - msg: RuntimeApiMessage::Request(relay_parent, Request::GlobalValidationData(tx)) + msg: RuntimeApiMessage::Request( + relay_parent, + Request::PersistedValidationData(para_a, OccupiedCoreAssumption::Included, tx) + ), }).await; - assert_eq!(rx.await.unwrap().unwrap(), runtime_api.global_validation_data); + assert_eq!(rx.await.unwrap().unwrap(), Some(Default::default())); + + let (tx, rx) = oneshot::channel(); + ctx_handle.send(FromOverseer::Communication { + msg: RuntimeApiMessage::Request( + relay_parent, + Request::PersistedValidationData(para_b, OccupiedCoreAssumption::Included, tx) + ), + }).await; + + assert_eq!(rx.await.unwrap().unwrap(), None); ctx_handle.send(FromOverseer::Signal(OverseerSignal::Conclude)).await; }; @@ -350,14 +371,14 @@ mod tests { } #[test] - fn requests_local_validation_data() { + fn requests_full_validation_data() { let (ctx, mut ctx_handle) = test_helpers::make_subsystem_context(TaskExecutor::new()); let mut runtime_api = MockRuntimeApi::default(); let relay_parent = [1; 32].into(); let para_a = 5.into(); let para_b = 6.into(); - runtime_api.local_validation_data.insert(para_a, Default::default()); + runtime_api.validation_data.insert(para_a, Default::default()); let subsystem = RuntimeApiSubsystem::new(runtime_api.clone(), Metrics(None)); let subsystem_task = run(ctx, subsystem).map(|x| x.unwrap()); @@ -367,7 +388,7 @@ mod tests { ctx_handle.send(FromOverseer::Communication { msg: RuntimeApiMessage::Request( relay_parent, - Request::LocalValidationData(para_a, OccupiedCoreAssumption::Included, tx) + Request::FullValidationData(para_a, OccupiedCoreAssumption::Included, tx) ), }).await; @@ -377,7 +398,7 @@ mod tests { ctx_handle.send(FromOverseer::Communication { msg: RuntimeApiMessage::Request( relay_parent, - Request::LocalValidationData(para_b, OccupiedCoreAssumption::Included, tx) + Request::FullValidationData(para_b, OccupiedCoreAssumption::Included, tx) ), }).await; diff --git a/polkadot/node/network/availability-distribution/src/tests.rs b/polkadot/node/network/availability-distribution/src/tests.rs index f4988fd8b77ed91b00a1ea8f67784276749a4f44..143fd8b05b7bb842cbef4f8e4b907d63eef1c11b 100644 --- a/polkadot/node/network/availability-distribution/src/tests.rs +++ b/polkadot/node/network/availability-distribution/src/tests.rs @@ -18,9 +18,9 @@ use super::*; use assert_matches::assert_matches; use polkadot_erasure_coding::{branches, obtain_chunks_v1 as obtain_chunks}; use polkadot_primitives::v1::{ - AvailableData, BlockData, CandidateCommitments, CandidateDescriptor, GlobalValidationData, - GroupIndex, GroupRotationInfo, HeadData, LocalValidationData, OccupiedCore, - OmittedValidationData, PoV, ScheduledCore, ValidatorPair, + AvailableData, BlockData, CandidateCommitments, CandidateDescriptor, GroupIndex, + GroupRotationInfo, HeadData, PersistedValidationData, OccupiedCore, + PoV, ScheduledCore, ValidatorPair, }; use polkadot_subsystem_testhelpers as test_helpers; use polkadot_node_network_protocol::ObservedRole; @@ -148,8 +148,7 @@ struct TestState { relay_parent: Hash, ancestors: Vec<Hash>, availability_cores: Vec<CoreState>, - global_validation_data: GlobalValidationData, - local_validation_data: LocalValidationData, + persisted_validation_data: PersistedValidationData, } fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec<ValidatorId> { @@ -210,17 +209,10 @@ impl Default for TestState { ]; let relay_parent = Hash::repeat_byte(0x05); - let local_validation_data = LocalValidationData { + let persisted_validation_data = PersistedValidationData { parent_head: HeadData(vec![7, 8, 9]), - balance: Default::default(), - code_upgrade_allowed: None, - validation_code_hash: Default::default(), - }; - - let global_validation_data = GlobalValidationData { - max_code_size: 1000, - max_head_data_size: 1000, block_number: Default::default(), + hrmp_mqc_heads: Vec::new(), }; let validator_index = Some((validators.len() - 1) as ValidatorIndex); @@ -233,8 +225,7 @@ impl Default for TestState { validator_groups, availability_cores, head_data, - local_validation_data, - global_validation_data, + persisted_validation_data, relay_parent, ancestors, validator_index, @@ -243,13 +234,8 @@ impl Default for TestState { } fn make_available_data(test: &TestState, pov: PoV) -> AvailableData { - let omitted_validation = OmittedValidationData { - global_validation: test.global_validation_data.clone(), - local_validation: test.local_validation_data.clone(), - }; - AvailableData { - omitted_validation, + validation_data: test.persisted_validation_data.clone(), pov, } } @@ -434,8 +420,7 @@ fn reputation_verification() { validator_groups, availability_cores, head_data: _, - local_validation_data: _, - global_validation_data: _, + persisted_validation_data: _, relay_parent: current, ancestors, validator_index: _, diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index 321a20f568f5923a227bef90bd2937d07fb85b23..1d4c7bcaf493a95d61d6898500d65bed46750e49 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -1800,7 +1800,7 @@ mod tests { fn test_collator_generation_msg() -> CollationGenerationMessage { CollationGenerationMessage::Initialize(CollationGenerationConfig { key: CollatorPair::generate().0, - collator: Box::new(|_, _| Box::new(TestCollator)), + collator: Box::new(|_| Box::new(TestCollator)), para_id: Default::default(), }) } diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index 2ff704c2dd1628f0d372b338108267cd0554abbb..df8bc22551da479cd8a285b9e7c8c9db0a0fb7a5 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -25,7 +25,7 @@ use parity_scale_codec::{Decode, Encode}; use polkadot_primitives::v1::{ Hash, CommittedCandidateReceipt, CandidateReceipt, CompactStatement, EncodeAs, Signed, SigningContext, ValidatorIndex, ValidatorId, - UpwardMessage, Balance, ValidationCode, GlobalValidationData, LocalValidationData, + UpwardMessage, Balance, ValidationCode, PersistedValidationData, ValidationData, HeadData, PoV, CollatorPair, Id as ParaId, }; use polkadot_statement_table::{ @@ -118,10 +118,8 @@ pub struct FromTableMisbehavior { pub struct ValidationOutputs { /// The head-data produced by validation. pub head_data: HeadData, - /// The global validation schedule. - pub global_validation_data: GlobalValidationData, - /// The local validation data. - pub local_validation_data: LocalValidationData, + /// The persisted validation data. + pub validation_data: PersistedValidationData, /// Upward messages to the relay chain. pub upward_messages: Vec<UpwardMessage>, /// Fees paid to the validators of the relay-chain. @@ -153,6 +151,8 @@ pub enum InvalidCandidate { NewCodeTooLarge(u64), /// Head-data is over the limit. HeadDataTooLarge(u64), + /// Code upgrade triggered but not allowed. + CodeUpgradeNotAllowed, } /// Result of the validation of the candidate. @@ -285,7 +285,7 @@ pub struct CollationGenerationConfig { /// Collator's authentication key, so it can sign things. pub key: CollatorPair, /// Collation function. - pub collator: Box<dyn Fn(&GlobalValidationData, &LocalValidationData) -> Box<dyn Future<Output = Collation> + Unpin + Send> + Send + Sync>, + pub collator: Box<dyn Fn(&ValidationData) -> Box<dyn Future<Output = Collation> + Unpin + Send> + Send + Sync>, /// The parachain that this collator collates for pub para_id: ParaId, } diff --git a/polkadot/node/subsystem-util/src/lib.rs b/polkadot/node/subsystem-util/src/lib.rs index 57f1efed3bb05cae3789e3a633e324427129eecd..ab7742715333a27ccf920b2acab65508c7c09fdb 100644 --- a/polkadot/node/subsystem-util/src/lib.rs +++ b/polkadot/node/subsystem-util/src/lib.rs @@ -39,8 +39,8 @@ use keystore::KeyStorePtr; use parity_scale_codec::Encode; use pin_project::{pin_project, pinned_drop}; use polkadot_primitives::v1::{ - CandidateEvent, CommittedCandidateReceipt, CoreState, EncodeAs, GlobalValidationData, - GroupRotationInfo, Hash, Id as ParaId, LocalValidationData, OccupiedCoreAssumption, + CandidateEvent, CommittedCandidateReceipt, CoreState, EncodeAs, PersistedValidationData, + GroupRotationInfo, Hash, Id as ParaId, ValidationData, OccupiedCoreAssumption, SessionIndex, Signed, SigningContext, ValidationCode, ValidatorId, ValidatorIndex, ValidatorPair, }; @@ -184,8 +184,8 @@ specialize_requests! { fn request_validators() -> Vec<ValidatorId>; Validators; fn request_validator_groups() -> (Vec<Vec<ValidatorIndex>>, GroupRotationInfo); ValidatorGroups; fn request_availability_cores() -> Vec<CoreState>; AvailabilityCores; - fn request_global_validation_data() -> GlobalValidationData; GlobalValidationData; - fn request_local_validation_data(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option<LocalValidationData>; LocalValidationData; + fn request_full_validation_data(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option<ValidationData>; FullValidationData; + fn request_persisted_validation_data(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option<PersistedValidationData>; PersistedValidationData; fn request_session_index_for_child() -> SessionIndex; SessionIndexForChild; fn request_validation_code(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option<ValidationCode>; ValidationCode; fn request_candidate_pending_availability(para_id: ParaId) -> Option<CommittedCandidateReceipt>; CandidatePendingAvailability; @@ -267,8 +267,8 @@ specialize_requests_ctx! { fn request_validators_ctx() -> Vec<ValidatorId>; Validators; fn request_validator_groups_ctx() -> (Vec<Vec<ValidatorIndex>>, GroupRotationInfo); ValidatorGroups; fn request_availability_cores_ctx() -> Vec<CoreState>; AvailabilityCores; - fn request_global_validation_data_ctx() -> GlobalValidationData; GlobalValidationData; - fn request_local_validation_data_ctx(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option<LocalValidationData>; LocalValidationData; + fn request_full_validation_data_ctx(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option<ValidationData>; FullValidationData; + fn request_persisted_validation_data_ctx(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option<PersistedValidationData>; PersistedValidationData; fn request_session_index_for_child_ctx() -> SessionIndex; SessionIndexForChild; fn request_validation_code_ctx(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option<ValidationCode>; ValidationCode; fn request_candidate_pending_availability_ctx(para_id: ParaId) -> Option<CommittedCandidateReceipt>; CandidatePendingAvailability; diff --git a/polkadot/node/subsystem/src/messages.rs b/polkadot/node/subsystem/src/messages.rs index 9891692a062a4db30d5d65235fa7a3e154385af4..39f3dc923f777294f4529f98be8bb2081c24e1f0 100644 --- a/polkadot/node/subsystem/src/messages.rs +++ b/polkadot/node/subsystem/src/messages.rs @@ -33,9 +33,9 @@ use polkadot_node_primitives::{ use polkadot_primitives::v1::{ AvailableData, BackedCandidate, BlockNumber, CandidateDescriptor, CandidateEvent, CandidateReceipt, CollatorId, CommittedCandidateReceipt, - CoreState, ErasureChunk, GlobalValidationData, GroupRotationInfo, - Hash, Id as ParaId, LocalValidationData, OccupiedCoreAssumption, OmittedValidationData, PoV, - SessionIndex, SignedAvailabilityBitfield, ValidationCode, ValidatorId, ValidatorIndex, + CoreState, ErasureChunk, GroupRotationInfo, Hash, Id as ParaId, + OccupiedCoreAssumption, PersistedValidationData, PoV, SessionIndex, SignedAvailabilityBitfield, + TransientValidationData, ValidationCode, ValidatorId, ValidationData, ValidatorIndex, ValidatorSignature, }; use std::sync::Arc; @@ -107,7 +107,7 @@ pub struct ValidationFailed(pub String); pub enum CandidateValidationMessage { /// Validate a candidate with provided parameters using relay-chain state. /// - /// This will implicitly attempt to gather the `OmittedValidationData` and `ValidationCode` + /// This will implicitly attempt to gather the `PersistedValidationData` and `ValidationCode` /// from the runtime API of the chain, based on the `relay_parent` /// of the `CandidateDescriptor`. /// @@ -120,10 +120,12 @@ pub enum CandidateValidationMessage { ), /// Validate a candidate with provided, exhaustive parameters for validation. /// - /// Explicitly provide the `OmittedValidationData` and `ValidationCode` so this can do full - /// validation without needing to access the state of the relay-chain. + /// Explicitly provide the `PersistedValidationData` and `ValidationCode` so this can do full + /// validation without needing to access the state of the relay-chain. Optionally provide the + /// `TransientValidationData` for further checks on the outputs. ValidateFromExhaustive( - OmittedValidationData, + PersistedValidationData, + Option<TransientValidationData>, ValidationCode, CandidateDescriptor, Arc<PoV>, @@ -136,7 +138,7 @@ impl CandidateValidationMessage { pub fn relay_parent(&self) -> Option<Hash> { match self { Self::ValidateFromChainState(_, _, _) => None, - Self::ValidateFromExhaustive(_, _, _, _, _) => None, + Self::ValidateFromExhaustive(_, _, _, _, _, _) => None, } } } @@ -357,15 +359,21 @@ pub enum RuntimeApiRequest { ValidatorGroups(RuntimeApiSender<(Vec<Vec<ValidatorIndex>>, GroupRotationInfo)>), /// Get information on all availability cores. AvailabilityCores(RuntimeApiSender<Vec<CoreState>>), - /// Get the global validation data. - GlobalValidationData(RuntimeApiSender<GlobalValidationData>), - /// Get the local validation data for a particular para, taking the given + /// Get the persisted validation data for a particular para, taking the given /// `OccupiedCoreAssumption`, which will inform on how the validation data should be computed /// if the para currently occupies a core. - LocalValidationData( + PersistedValidationData( ParaId, OccupiedCoreAssumption, - RuntimeApiSender<Option<LocalValidationData>>, + RuntimeApiSender<Option<PersistedValidationData>>, + ), + /// Get the full validation data for a particular para, taking the given + /// `OccupiedCoreAssumption`, which will inform on how the validation data should be computed + /// if the para currently occupies a core. + FullValidationData( + ParaId, + OccupiedCoreAssumption, + RuntimeApiSender<Option<ValidationData>>, ), /// Get the session index that a child of the block will have. SessionIndexForChild(RuntimeApiSender<SessionIndex>), diff --git a/polkadot/parachain/src/primitives.rs b/polkadot/parachain/src/primitives.rs index 955842e30fb91c860f8b77b62f80f7a99a522414..3a1ee81bcdc31451b897d140b590d2994c91c15c 100644 --- a/polkadot/parachain/src/primitives.rs +++ b/polkadot/parachain/src/primitives.rs @@ -28,6 +28,8 @@ use serde::{Serialize, Deserialize}; #[cfg(feature = "std")] use sp_core::bytes; +use polkadot_core_primitives::Hash; + /// Block number type used by the relay chain. pub use polkadot_core_primitives::BlockNumber as RelayChainBlockNumber; @@ -228,22 +230,16 @@ pub struct UpwardMessage { #[derive(PartialEq, Eq, Decode)] #[cfg_attr(feature = "std", derive(Debug, Encode))] pub struct ValidationParams { - /// The collation body. - pub block_data: BlockData, /// Previous head-data. pub parent_head: HeadData, - /// The maximum code size permitted, in bytes. - pub max_code_size: u32, - /// The maximum head-data size permitted, in bytes. - pub max_head_data_size: u32, + /// The collation body. + pub block_data: BlockData, /// The current relay-chain block number. - pub relay_chain_height: polkadot_core_primitives::BlockNumber, - /// Whether a code upgrade is allowed or not, and at which height the upgrade - /// would be applied after, if so. The parachain logic should apply any upgrade - /// issued in this block after the first block - /// with `relay_chain_height` at least this value, if `Some`. if `None`, issue - /// no upgrade. - pub code_upgrade_allowed: Option<polkadot_core_primitives::BlockNumber>, + pub relay_chain_height: RelayChainBlockNumber, + /// The list of MQC heads for the inbound HRMP channels paired with the sender para ids. This + /// vector is sorted ascending by the para id and doesn't contain multiple entries with the same + /// sender. + pub hrmp_mqc_heads: Vec<(Id, Hash)>, } /// The result of parachain validation. diff --git a/polkadot/parachain/test-parachains/Cargo.toml b/polkadot/parachain/test-parachains/Cargo.toml index 044115119d97d745cfd0a8aafa30645965b5198d..d391c1b2314dc70e256b796ad127adb4235cf376 100644 --- a/polkadot/parachain/test-parachains/Cargo.toml +++ b/polkadot/parachain/test-parachains/Cargo.toml @@ -12,7 +12,6 @@ codec = { package = "parity-scale-codec", version = "1.3.4", default-features = parachain = { package = "polkadot-parachain", path = ".." } adder = { package = "test-parachain-adder", path = "adder" } halt = { package = "test-parachain-halt", path = "halt" } -code-upgrader = { package = "test-parachain-code-upgrader", path = "code-upgrader" } [dev-dependencies] sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } @@ -22,5 +21,4 @@ default = [ "std" ] std = [ "adder/std", "halt/std", - "code-upgrader/std", ] diff --git a/polkadot/parachain/test-parachains/code-upgrader/Cargo.toml b/polkadot/parachain/test-parachains/code-upgrader/Cargo.toml deleted file mode 100644 index 6f673adbf82a4d5f1ad6527a40a55326ebe36ad9..0000000000000000000000000000000000000000 --- a/polkadot/parachain/test-parachains/code-upgrader/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "test-parachain-code-upgrader" -version = "0.7.22" -authors = ["Parity Technologies <admin@parity.io>"] -description = "Test parachain which can upgrade code" -edition = "2018" -build = "build.rs" - -[dependencies] -parachain = { package = "polkadot-parachain", path = "../../", default-features = false, features = [ "wasm-api" ] } -codec = { package = "parity-scale-codec", version = "1.1.0", default-features = false, features = ["derive"] } -sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -tiny-keccak = "1.5.0" -dlmalloc = { version = "0.1.3", features = [ "global" ] } - -# We need to make sure the global allocator is disabled until we have support of full substrate externalities -runtime-io = { package = "sp-io", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, features = [ "disable_allocator" ] } - -[build-dependencies] -wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.6" } - -[features] -default = [ "std" ] -std = [ - "parachain/std", - "sp-std/std", -] diff --git a/polkadot/parachain/test-parachains/code-upgrader/build.rs b/polkadot/parachain/test-parachains/code-upgrader/build.rs deleted file mode 100644 index 2e407bbef3876e3ff3cc1183533545fb74952acf..0000000000000000000000000000000000000000 --- a/polkadot/parachain/test-parachains/code-upgrader/build.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019-2020 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see <http://www.gnu.org/licenses/>. - -use wasm_builder_runner::WasmBuilder; - -fn main() { - WasmBuilder::new() - .with_current_project() - .with_wasm_builder_from_crates("2.0.0") - .export_heap_base() - .build() -} diff --git a/polkadot/parachain/test-parachains/code-upgrader/src/lib.rs b/polkadot/parachain/test-parachains/code-upgrader/src/lib.rs deleted file mode 100644 index c0219e0229a8459acf813b6a2c9fd8bcf5c691fa..0000000000000000000000000000000000000000 --- a/polkadot/parachain/test-parachains/code-upgrader/src/lib.rs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. - -//! Test parachain WASM which implements code ugprades. - -#![no_std] - -#![cfg_attr(not(feature = "std"), feature(core_intrinsics, lang_items, core_panic_info, alloc_error_handler))] - -use codec::{Encode, Decode}; -use parachain::primitives::{RelayChainBlockNumber, ValidationCode}; - -#[cfg(not(feature = "std"))] -mod wasm_validation; - -#[cfg(not(feature = "std"))] -#[global_allocator] -static ALLOC: dlmalloc::GlobalDlmalloc = dlmalloc::GlobalDlmalloc; - -// Make the WASM binary available. -#[cfg(feature = "std")] -include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); - -#[cfg(feature = "std")] -/// Wasm binary unwrapped. If built with `BUILD_DUMMY_WASM_BINARY`, the function panics. -pub fn wasm_binary_unwrap() -> &'static [u8] { - WASM_BINARY.expect("Development wasm binary is not available. Testing is only \ - supported with the flag disabled.") -} - -#[derive(Encode, Decode, Clone, Default)] -pub struct State { - /// The current code that is "active" in this chain. - pub code: ValidationCode, - /// Code upgrade that is pending. - pub pending_code: Option<(ValidationCode, RelayChainBlockNumber)>, -} - -/// Head data for this parachain. -#[derive(Default, Clone, Hash, Eq, PartialEq, Encode, Decode)] -pub struct HeadData { - /// Block number - pub number: u64, - /// parent block keccak256 - pub parent_hash: [u8; 32], - /// hash of post-execution state. - pub post_state: [u8; 32], -} - -impl HeadData { - pub fn hash(&self) -> [u8; 32] { - tiny_keccak::keccak256(&self.encode()) - } -} - -/// Block data for this parachain. -#[derive(Default, Clone, Encode, Decode)] -pub struct BlockData { - /// State to begin from. - pub state: State, - /// Code to upgrade to. - pub new_validation_code: Option<ValidationCode>, -} - -pub fn hash_state(state: &State) -> [u8; 32] { - tiny_keccak::keccak256(state.encode().as_slice()) -} - -#[derive(Debug)] -pub enum Error { - /// Start state mismatched with parent header's state hash. - StateMismatch, - /// New validation code too large. - NewCodeTooLarge, - /// Code upgrades not allowed at this time. - CodeUpgradeDisallowed, -} - -pub struct ValidationResult { - /// The new head data. - pub head_data: HeadData, - /// The new validation code. - pub new_validation_code: Option<ValidationCode>, -} - -pub struct RelayChainParams { - /// Whether a code upgrade is allowed and at what relay-chain block number - /// to process it after. - pub code_upgrade_allowed: Option<RelayChainBlockNumber>, - /// The maximum code size allowed for an upgrade. - pub max_code_size: u32, - /// The relay-chain block number. - pub relay_chain_block_number: RelayChainBlockNumber, -} - -/// Execute a block body on top of given parent head, producing new parent head -/// if valid. -pub fn execute( - parent_hash: [u8; 32], - parent_head: HeadData, - block_data: BlockData, - relay_params: &RelayChainParams, -) -> Result<ValidationResult, Error> { - debug_assert_eq!(parent_hash, parent_head.hash()); - - if hash_state(&block_data.state) != parent_head.post_state { - return Err(Error::StateMismatch); - } - - let mut new_state = block_data.state; - - if let Some((pending_code, after)) = new_state.pending_code.take() { - if after <= relay_params.relay_chain_block_number { - // code applied. - new_state.code = pending_code; - } else { - // reinstate. - new_state.pending_code = Some((pending_code, after)); - } - } - - let new_validation_code = if let Some(ref new_validation_code) = block_data.new_validation_code { - if new_validation_code.0.len() as u32 > relay_params.max_code_size { - return Err(Error::NewCodeTooLarge); - } - - // replace the code if allowed and we don't have an upgrade pending. - match (new_state.pending_code.is_some(), relay_params.code_upgrade_allowed) { - (_, None) => return Err(Error::CodeUpgradeDisallowed), - (false, Some(after)) => { - new_state.pending_code = Some((new_validation_code.clone(), after)); - Some(new_validation_code.clone()) - } - (true, Some(_)) => None, - } - } else { - None - }; - - let head_data = HeadData { - number: parent_head.number + 1, - parent_hash, - post_state: hash_state(&new_state), - }; - - Ok(ValidationResult { - head_data, - new_validation_code: new_validation_code, - }) -} diff --git a/polkadot/parachain/test-parachains/code-upgrader/src/wasm_validation.rs b/polkadot/parachain/test-parachains/code-upgrader/src/wasm_validation.rs deleted file mode 100644 index 3f4d0c44f8f4cfd853182d6f4804ec6281e0749b..0000000000000000000000000000000000000000 --- a/polkadot/parachain/test-parachains/code-upgrader/src/wasm_validation.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2019-2020 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. - -//! WASM validation for adder parachain. - -use crate::{HeadData, BlockData, RelayChainParams}; -use core::{intrinsics, panic}; -use parachain::primitives::{ValidationResult, HeadData as GenericHeadData}; -use codec::{Encode, Decode}; - -#[no_mangle] -pub extern fn validate_block(params: *const u8, len: usize) -> u64 { - let params = unsafe { parachain::load_params(params, len) }; - let parent_head = HeadData::decode(&mut ¶ms.parent_head.0[..]) - .expect("invalid parent head format."); - - let block_data = BlockData::decode(&mut ¶ms.block_data.0[..]) - .expect("invalid block data format."); - - let parent_hash = tiny_keccak::keccak256(¶ms.parent_head.0[..]); - - let res = crate::execute( - parent_hash, - parent_head, - block_data, - &RelayChainParams { - code_upgrade_allowed: params.code_upgrade_allowed, - max_code_size: params.max_code_size, - relay_chain_block_number: params.relay_chain_height, - }, - ); - - match res { - Ok(output) => parachain::write_result( - &ValidationResult { - head_data: GenericHeadData(output.head_data.encode()), - new_validation_code: output.new_validation_code, - upward_messages: sp_std::vec::Vec::new(), - processed_downward_messages: 0, - } - ), - Err(_) => panic!("execution failure"), - } -} diff --git a/polkadot/parachain/test-parachains/code-upgrader/wasm/Cargo.toml b/polkadot/parachain/test-parachains/code-upgrader/wasm/Cargo.toml deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/polkadot/parachain/test-parachains/tests/adder/mod.rs b/polkadot/parachain/test-parachains/tests/adder/mod.rs index ecbac12ac5abee87cf22a8faf5e70a0e6d12fa4d..76924551ba9a33e35ad90516bd604bfee7c7b5d6 100644 --- a/polkadot/parachain/test-parachains/tests/adder/mod.rs +++ b/polkadot/parachain/test-parachains/tests/adder/mod.rs @@ -72,10 +72,8 @@ pub fn execute_good_on_parent() { ValidationParams { parent_head: GenericHeadData(parent_head.encode()), block_data: GenericBlockData(block_data.encode()), - max_code_size: 1024, - max_head_data_size: 1024, relay_chain_height: 1, - code_upgrade_allowed: None, + hrmp_mqc_heads: Vec::new(), }, parachain::wasm_executor::ExecutionMode::RemoteTest(&pool), sp_core::testing::TaskExecutor::new(), @@ -112,10 +110,8 @@ fn execute_good_chain_on_parent() { ValidationParams { parent_head: GenericHeadData(parent_head.encode()), block_data: GenericBlockData(block_data.encode()), - max_code_size: 1024, - max_head_data_size: 1024, relay_chain_height: number as RelayChainBlockNumber + 1, - code_upgrade_allowed: None, + hrmp_mqc_heads: Vec::new(), }, parachain::wasm_executor::ExecutionMode::RemoteTest(&pool), sp_core::testing::TaskExecutor::new(), @@ -153,10 +149,8 @@ fn execute_bad_on_parent() { ValidationParams { parent_head: GenericHeadData(parent_head.encode()), block_data: GenericBlockData(block_data.encode()), - max_code_size: 1024, - max_head_data_size: 1024, relay_chain_height: 1, - code_upgrade_allowed: None, + hrmp_mqc_heads: Vec::new(), }, parachain::wasm_executor::ExecutionMode::RemoteTest(&pool), sp_core::testing::TaskExecutor::new(), diff --git a/polkadot/parachain/test-parachains/tests/code_upgrader/mod.rs b/polkadot/parachain/test-parachains/tests/code_upgrader/mod.rs deleted file mode 100644 index b99a6e9dbf45b9d721e9dbde5d6f9e48f75c3fcd..0000000000000000000000000000000000000000 --- a/polkadot/parachain/test-parachains/tests/code_upgrader/mod.rs +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2017-2020 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. - -//! Basic parachain that adds a number as part of its state. - -use parachain::primitives::{ - BlockData as GenericBlockData, - HeadData as GenericHeadData, - ValidationParams, ValidationCode, -}; -use codec::{Decode, Encode}; -use code_upgrader::{hash_state, HeadData, BlockData, State}; - -#[test] -pub fn execute_good_no_upgrade() { - let pool = parachain::wasm_executor::ValidationPool::new(); - - let parent_head = HeadData { - number: 0, - parent_hash: [0; 32], - post_state: hash_state(&State::default()), - }; - - let block_data = BlockData { - state: State::default(), - new_validation_code: None, - }; - - let ret = parachain::wasm_executor::validate_candidate( - code_upgrader::wasm_binary_unwrap(), - ValidationParams { - parent_head: GenericHeadData(parent_head.encode()), - block_data: GenericBlockData(block_data.encode()), - max_code_size: 1024, - max_head_data_size: 1024, - relay_chain_height: 1, - code_upgrade_allowed: None, - }, - parachain::wasm_executor::ExecutionMode::RemoteTest(&pool), - sp_core::testing::TaskExecutor::new(), - ).unwrap(); - - let new_head = HeadData::decode(&mut &ret.head_data.0[..]).unwrap(); - - assert!(ret.new_validation_code.is_none()); - assert_eq!(new_head.number, 1); - assert_eq!(new_head.parent_hash, parent_head.hash()); - assert_eq!(new_head.post_state, hash_state(&State::default())); -} - -#[test] -pub fn execute_good_with_upgrade() { - let pool = parachain::wasm_executor::ValidationPool::new(); - - let parent_head = HeadData { - number: 0, - parent_hash: [0; 32], - post_state: hash_state(&State::default()), - }; - - let block_data = BlockData { - state: State::default(), - new_validation_code: Some(ValidationCode(vec![1, 2, 3])), - }; - - let ret = parachain::wasm_executor::validate_candidate( - code_upgrader::wasm_binary_unwrap(), - ValidationParams { - parent_head: GenericHeadData(parent_head.encode()), - block_data: GenericBlockData(block_data.encode()), - max_code_size: 1024, - max_head_data_size: 1024, - relay_chain_height: 1, - code_upgrade_allowed: Some(20), - }, - parachain::wasm_executor::ExecutionMode::RemoteTest(&pool), - sp_core::testing::TaskExecutor::new(), - ).unwrap(); - - let new_head = HeadData::decode(&mut &ret.head_data.0[..]).unwrap(); - - assert_eq!(ret.new_validation_code.unwrap(), ValidationCode(vec![1, 2, 3])); - assert_eq!(new_head.number, 1); - assert_eq!(new_head.parent_hash, parent_head.hash()); - assert_eq!( - new_head.post_state, - hash_state(&State { - code: ValidationCode::default(), - pending_code: Some((ValidationCode(vec![1, 2, 3]), 20)), - }), - ); -} - -#[test] -#[should_panic] -pub fn code_upgrade_not_allowed() { - let pool = parachain::wasm_executor::ValidationPool::new(); - - let parent_head = HeadData { - number: 0, - parent_hash: [0; 32], - post_state: hash_state(&State::default()), - }; - - let block_data = BlockData { - state: State::default(), - new_validation_code: Some(ValidationCode(vec![1, 2, 3])), - }; - - parachain::wasm_executor::validate_candidate( - code_upgrader::wasm_binary_unwrap(), - ValidationParams { - parent_head: GenericHeadData(parent_head.encode()), - block_data: GenericBlockData(block_data.encode()), - max_code_size: 1024, - max_head_data_size: 1024, - relay_chain_height: 1, - code_upgrade_allowed: None, - }, - parachain::wasm_executor::ExecutionMode::RemoteTest(&pool), - sp_core::testing::TaskExecutor::new(), - ).unwrap(); -} - -#[test] -pub fn applies_code_upgrade_after_delay() { - let pool = parachain::wasm_executor::ValidationPool::new(); - - let (new_head, state) = { - let parent_head = HeadData { - number: 0, - parent_hash: [0; 32], - post_state: hash_state(&State::default()), - }; - - let block_data = BlockData { - state: State::default(), - new_validation_code: Some(ValidationCode(vec![1, 2, 3])), - }; - - let ret = parachain::wasm_executor::validate_candidate( - code_upgrader::wasm_binary_unwrap(), - ValidationParams { - parent_head: GenericHeadData(parent_head.encode()), - block_data: GenericBlockData(block_data.encode()), - max_code_size: 1024, - max_head_data_size: 1024, - relay_chain_height: 1, - code_upgrade_allowed: Some(2), - }, - parachain::wasm_executor::ExecutionMode::RemoteTest(&pool), - sp_core::testing::TaskExecutor::new(), - ).unwrap(); - - let new_head = HeadData::decode(&mut &ret.head_data.0[..]).unwrap(); - - let parent_hash = parent_head.hash(); - let state = State { - code: ValidationCode::default(), - pending_code: Some((ValidationCode(vec![1, 2, 3]), 2)), - }; - assert_eq!(ret.new_validation_code.unwrap(), ValidationCode(vec![1, 2, 3])); - assert_eq!(new_head.number, 1); - assert_eq!(new_head.parent_hash, parent_hash); - assert_eq!(new_head.post_state, hash_state(&state)); - - (new_head, state) - }; - - { - let parent_head = new_head; - let block_data = BlockData { - state, - new_validation_code: None, - }; - - let ret = parachain::wasm_executor::validate_candidate( - code_upgrader::wasm_binary_unwrap(), - ValidationParams { - parent_head: GenericHeadData(parent_head.encode()), - block_data: GenericBlockData(block_data.encode()), - max_code_size: 1024, - max_head_data_size: 1024, - relay_chain_height: 2, - code_upgrade_allowed: None, - }, - parachain::wasm_executor::ExecutionMode::RemoteTest(&pool), - sp_core::testing::TaskExecutor::new(), - ).unwrap(); - - let new_head = HeadData::decode(&mut &ret.head_data.0[..]).unwrap(); - - assert!(ret.new_validation_code.is_none()); - assert_eq!(new_head.number, 2); - assert_eq!(new_head.parent_hash, parent_head.hash()); - assert_eq!( - new_head.post_state, - hash_state(&State { - code: ValidationCode(vec![1, 2, 3]), - pending_code: None, - }), - ); - } -} diff --git a/polkadot/parachain/test-parachains/tests/lib.rs b/polkadot/parachain/test-parachains/tests/lib.rs index 692c04c10ca5fd66eba3de5229c1302d1d9252ff..3ad021a16e7035b16702af59cfbd40ed44329be7 100644 --- a/polkadot/parachain/test-parachains/tests/lib.rs +++ b/polkadot/parachain/test-parachains/tests/lib.rs @@ -15,7 +15,6 @@ // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. mod adder; -mod code_upgrader; mod wasm_executor; use parachain::wasm_executor::run_worker; diff --git a/polkadot/parachain/test-parachains/tests/wasm_executor/mod.rs b/polkadot/parachain/test-parachains/tests/wasm_executor/mod.rs index 769ad737ce9f4c34574ffe0a33ea2aae24339599..b4f2211baa56d8175b4840beb63b4d8dd4b56c78 100644 --- a/polkadot/parachain/test-parachains/tests/wasm_executor/mod.rs +++ b/polkadot/parachain/test-parachains/tests/wasm_executor/mod.rs @@ -31,10 +31,8 @@ fn terminates_on_timeout() { ValidationParams { block_data: BlockData(Vec::new()), parent_head: Default::default(), - max_code_size: 1024, - max_head_data_size: 1024, relay_chain_height: 1, - code_upgrade_allowed: None, + hrmp_mqc_heads: Vec::new(), }, parachain::wasm_executor::ExecutionMode::RemoteTest(&pool), sp_core::testing::TaskExecutor::new(), @@ -61,10 +59,8 @@ fn parallel_execution() { ValidationParams { block_data: BlockData(Vec::new()), parent_head: Default::default(), - max_code_size: 1024, - max_head_data_size: 1024, relay_chain_height: 1, - code_upgrade_allowed: None, + hrmp_mqc_heads: Vec::new(), }, parachain::wasm_executor::ExecutionMode::RemoteTest(&pool2), sp_core::testing::TaskExecutor::new(), @@ -74,10 +70,8 @@ fn parallel_execution() { ValidationParams { block_data: BlockData(Vec::new()), parent_head: Default::default(), - max_code_size: 1024, - max_head_data_size: 1024, relay_chain_height: 1, - code_upgrade_allowed: None, + hrmp_mqc_heads: Vec::new(), }, parachain::wasm_executor::ExecutionMode::RemoteTest(&pool), sp_core::testing::TaskExecutor::new(), diff --git a/polkadot/primitives/src/v1.rs b/polkadot/primitives/src/v1.rs index 086eface31672d1886cce5947396ff626aa68f56..c2a8ec43d5a7131950248e377cb26efc882c0d31 100644 --- a/polkadot/primitives/src/v1.rs +++ b/polkadot/primitives/src/v1.rs @@ -60,7 +60,7 @@ pub const INCLUSION_INHERENT_IDENTIFIER: InherentIdentifier = *b"inclusn0"; pub fn collator_signature_payload<H: AsRef<[u8]>>( relay_parent: &H, para_id: &Id, - validation_data_hash: &Hash, + persisted_validation_data_hash: &Hash, pov_hash: &Hash, ) -> [u8; 100] { // 32-byte hash length is protected in a test below. @@ -68,7 +68,7 @@ pub fn collator_signature_payload<H: AsRef<[u8]>>( payload[0..32].copy_from_slice(relay_parent.as_ref()); u32::from(*para_id).using_encoded(|s| payload[32..32 + s.len()].copy_from_slice(s)); - payload[36..68].copy_from_slice(validation_data_hash.as_ref()); + payload[36..68].copy_from_slice(persisted_validation_data_hash.as_ref()); payload[68..100].copy_from_slice(pov_hash.as_ref()); payload @@ -77,7 +77,7 @@ pub fn collator_signature_payload<H: AsRef<[u8]>>( fn check_collator_signature<H: AsRef<[u8]>>( relay_parent: &H, para_id: &Id, - validation_data_hash: &Hash, + persisted_validation_data_hash: &Hash, pov_hash: &Hash, collator: &CollatorId, signature: &CollatorSignature, @@ -85,7 +85,7 @@ fn check_collator_signature<H: AsRef<[u8]>>( let payload = collator_signature_payload( relay_parent, para_id, - validation_data_hash, + persisted_validation_data_hash, pov_hash, ); @@ -96,14 +96,6 @@ fn check_collator_signature<H: AsRef<[u8]>>( } } -/// Compute the `validation_data_hash` from global & local validation data. -pub fn validation_data_hash<N: Encode>( - global: &GlobalValidationData<N>, - local: &LocalValidationData<N>, -) -> Hash { - BlakeTwo256::hash_of(&(global, local)) -} - /// A unique descriptor of the candidate receipt. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Default, Hash))] @@ -114,16 +106,15 @@ pub struct CandidateDescriptor<H = Hash> { pub relay_parent: H, /// The collator's sr25519 public key. pub collator: CollatorId, - /// The blake2-256 hash of the validation data. This is extra data derived from + /// The blake2-256 hash of the persisted validation data. This is extra data derived from /// relay-chain state which may vary based on bitfields included before the candidate. /// Thus it cannot be derived entirely from the relay-parent. - pub validation_data_hash: Hash, + pub persisted_validation_data_hash: Hash, /// The blake2-256 hash of the pov. pub pov_hash: Hash, /// Signature on blake2-256 of components of this receipt: /// The parachain index, the relay parent, the validation data hash, and the pov_hash. pub signature: CollatorSignature, - } impl<H: AsRef<[u8]>> CandidateDescriptor<H> { @@ -132,7 +123,7 @@ impl<H: AsRef<[u8]>> CandidateDescriptor<H> { check_collator_signature( &self.relay_parent, &self.para_id, - &self.validation_data_hash, + &self.persisted_validation_data_hash, &self.pov_hash, &self.collator, &self.signature, @@ -168,10 +159,11 @@ impl<H> CandidateReceipt<H> { pub struct FullCandidateReceipt<H = Hash, N = BlockNumber> { /// The inner candidate receipt. pub inner: CandidateReceipt<H>, - /// The global validation schedule. - pub global_validation: GlobalValidationData<N>, - /// The local validation data. - pub local_validation: LocalValidationData<N>, + /// The validation data derived from the relay-chain state at that + /// point. The hash of the persisted validation data should + /// match the `persisted_validation_data_hash` in the descriptor + /// of the receipt. + pub validation_data: ValidationData<N>, } /// A candidate-receipt with commitments directly included. @@ -224,17 +216,78 @@ impl Ord for CommittedCandidateReceipt { } } -/// Extra data that is needed along with the other fields in a `CandidateReceipt` -/// to fully validate the candidate. These fields are parachain-specific. +/// The validation data provide information about how to validate both the inputs and +/// outputs of a candidate. +/// +/// There are two types of validation data: persisted and transient. +/// Their respective sections of the guide elaborate on their functionality in more detail. +/// +/// This information is derived from the chain state and will vary from para to para, +/// although some of the fields may be the same for every para. +/// +/// Persisted validation data are generally derived from some relay-chain state to form inputs +/// to the validation function, and as such need to be persisted by the availability system to +/// avoid dependence on availability of the relay-chain state. The backing phase of the +/// inclusion pipeline ensures that everything that is included in a valid fork of the +/// relay-chain already adheres to the transient constraints. +/// +/// The validation data also serve the purpose of giving collators a means of ensuring that +/// their produced candidate and the commitments submitted to the relay-chain alongside it +/// will pass the checks done by the relay-chain when backing, and give validators +/// the same understanding when determining whether to second or attest to a candidate. +/// +/// Since the commitments of the validation function are checked by the +/// relay-chain, secondary checkers can rely on the invariant that the relay-chain +/// only includes para-blocks for which these checks have already been done. As such, +/// there is no need for the validation data used to inform validators and collators about +/// the checks the relay-chain will perform to be persisted by the availability system. +/// Nevertheless, we expose it so the backing validators can validate the outputs of a +/// candidate before voting to submit it to the relay-chain and so collators can +/// collate candidates that satisfy the criteria implied these transient validation data. +#[derive(PartialEq, Eq, Clone, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug, Default))] +pub struct ValidationData<N = BlockNumber> { + /// The persisted validation data. + pub persisted: PersistedValidationData<N>, + /// The transient validation data. + pub transient: TransientValidationData<N>, +} + +/// Validation data that needs to be persisted for secondary checkers. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Default))] -pub struct LocalValidationData<N = BlockNumber> { +pub struct PersistedValidationData<N = BlockNumber> { /// The parent head-data. pub parent_head: HeadData, + /// The relay-chain block number this is in the context of. + pub block_number: N, + /// The list of MQC heads for the inbound channels paired with the sender para ids. This + /// vector is sorted ascending by the para id and doesn't contain multiple entries with the same + /// sender. + pub hrmp_mqc_heads: Vec<(Id, Hash)>, +} + +impl<N: Encode> PersistedValidationData<N> { + /// Compute the blake2-256 hash of the persisted validation data. + pub fn hash(&self) -> Hash { + BlakeTwo256::hash_of(self) + } +} + +/// Validation data for checking outputs of the validation-function. +/// As such, they also inform the collator about how to construct the candidate. +/// +/// These are transient because they are not necessary beyond the point where the +/// candidate is backed. +#[derive(PartialEq, Eq, Clone, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug, Default))] +pub struct TransientValidationData<N = BlockNumber> { + /// The maximum code size permitted, in bytes. + pub max_code_size: u32, + /// The maximum head-data size permitted, in bytes. + pub max_head_data_size: u32, /// The balance of the parachain at the moment of validation. pub balance: Balance, - /// The blake2-256 hash of the validation code used to execute the candidate. - pub validation_code_hash: Hash, /// Whether the parachain is allowed to upgrade its validation code. /// /// This is `Some` if so, and contains the number of the minimum relay-chain @@ -249,21 +302,6 @@ pub struct LocalValidationData<N = BlockNumber> { pub code_upgrade_allowed: Option<N>, } -/// Extra data that is needed along with the other fields in a `CandidateReceipt` -/// to fully validate the candidate. -/// -/// These are global parameters that apply to all candidates in a block. -#[derive(PartialEq, Eq, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug, Default))] -pub struct GlobalValidationData<N = BlockNumber> { - /// The maximum code size permitted, in bytes. - pub max_code_size: u32, - /// The maximum head-data size permitted, in bytes. - pub max_head_data_size: u32, - /// The relay-chain block number this is in the context of. - pub block_number: N, -} - /// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Default, Hash))] @@ -434,25 +472,14 @@ pub enum CoreOccupied { Parachain, } -/// Validation data omitted from most candidate descriptor structs, as it can be derived from the -/// relay-parent. -#[derive(Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(PartialEq, Debug, Default))] -pub struct OmittedValidationData { - /// The global validation schedule. - pub global_validation: GlobalValidationData, - /// The local validation data. - pub local_validation: LocalValidationData, -} - /// This is the data we keep available for each candidate included in the relay chain. #[derive(Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(PartialEq, Debug))] pub struct AvailableData { /// The Proof-of-Validation of the candidate. pub pov: PoV, - /// The omitted validation data. - pub omitted_validation: OmittedValidationData, + /// The persisted validation data needed for secondary checks. + pub validation_data: PersistedValidationData, } /// A helper data-type for tracking validator-group rotations. @@ -622,17 +649,21 @@ sp_api::decl_runtime_apis! { /// cores can have paras assigned to them. fn availability_cores() -> Vec<CoreState<N>>; - /// Yields the GlobalValidationData. This applies to all para candidates with the - /// relay-parent equal to the block in which context this is invoked in. - fn global_validation_data() -> GlobalValidationData<N>; + /// Yields the full validation data for the given ParaId along with an assumption that + /// should be used if the para currently occupieds a core. + /// + /// Returns `None` if either the para is not registered or the assumption is `Freed` + /// and the para already occupies a core. + fn full_validation_data(para_id: Id, assumption: OccupiedCoreAssumption) + -> Option<ValidationData<N>>; - /// Yields the LocalValidationData for the given ParaId along with an assumption that + /// Yields the persisted validation data for the given ParaId along with an assumption that /// should be used if the para currently occupies a core. /// /// Returns `None` if either the para is not registered or the assumption is `Freed` /// and the para already occupies a core. - fn local_validation_data(para_id: Id, assumption: OccupiedCoreAssumption) - -> Option<LocalValidationData<N>>; + fn persisted_validation_data(para_id: Id, assumption: OccupiedCoreAssumption) + -> Option<PersistedValidationData<N>>; /// Returns the session index expected at a child of the block. /// diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md b/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md index cd4a040fbfe7c1b3adf8bfcaa62ee688f5f1461a..19108bd78e811f48bb42d714595b1e06de4ec58b 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md @@ -24,7 +24,7 @@ Upon receiving a validation request, the first thing the candidate validation su ### Determining Parameters -For a [`CandidateValidationMessage`][CVM]`::ValidateFromExhaustive`, these parameters are exhaustively provided. The [`OmittedValidationData`](../../types/availability.md#omittedvalidationdata) can be deconstructed into the validation data. +For a [`CandidateValidationMessage`][CVM]`::ValidateFromExhaustive`, these parameters are exhaustively provided. The [`TransientValidationData`](../../types/candidate.md#transientvalidationdata) is optional, and is used to perform further checks on the outputs of validation. For a [`CandidateValidationMessage`][CVM]`::ValidateFromChainState`, some more work needs to be done. Due to the uncertainty of Availability Cores (implemented in the [`Scheduler`](../../runtime/scheduler.md) module of the runtime), a candidate at a particular relay-parent and for a particular para may have two different valid validation-data to be executed under depending on what is assumed to happen if the para is occupying a core at the onset of the new block. This is encoded as an `OccupiedCoreAssumption` in the runtime API. @@ -40,7 +40,7 @@ Once we have all parameters, we can spin up a background task to perform the val * The collator signature is valid * The PoV provided matches the `pov_hash` field of the descriptor -After that, we can invoke the validation function. Lastly, we do some final checks on the output: +After that, we can invoke the validation function. Lastly, if available, we do some final checks on the output using the `TransientValidationData`: * The produced head-data is no larger than the maximum allowed. * The produced code upgrade, if any, is no larger than the maximum allowed, and a code upgrade was allowed to be signaled. * The amount and size of produced upward messages is not too large. diff --git a/polkadot/roadmap/implementers-guide/src/types/candidate.md b/polkadot/roadmap/implementers-guide/src/types/candidate.md index 02ece10806ac0a4060fc502e5c65dbdb76d0ae9d..70191af973a8aa5b2eea043cea5099667ff323f7 100644 --- a/polkadot/roadmap/implementers-guide/src/types/candidate.md +++ b/polkadot/roadmap/implementers-guide/src/types/candidate.md @@ -77,7 +77,7 @@ struct CandidateDescriptor { /// The blake2-256 hash of the persisted validation data. These are extra parameters /// derived from relay-chain state that influence the validity of the block which /// must also be kept available for secondary checkers. - validation_data_hash: Hash, + persisted_validation_data_hash: Hash, /// The blake2-256 hash of the pov-block. pov_hash: Hash, /// Signature on blake2-256 of components of this receipt: @@ -119,23 +119,13 @@ Validation data that needs to be persisted for secondary checkers. See the secti struct PersistedValidationData { /// The parent head-data. parent_head: HeadData, - /// Whether the parachain is allowed to upgrade its validation code. - /// - /// This is `Some` if so, and contains the number of the minimum relay-chain - /// height at which the upgrade will be applied, if an upgrade is signaled - /// now. - /// - /// A parachain should enact its side of the upgrade at the end of the first - /// parablock executing in the context of a relay-chain block with at least this - /// height. This may be equal to the current perceived relay-chain block height, in - /// which case the code upgrade should be applied at the end of the signaling - /// block. - /// - /// This informs a relay-chain backing check and the parachain logic. - code_upgrade_allowed: Option<BlockNumber>, - /// The relay-chain block number this is in the context of. This informs the collator. block_number: BlockNumber, + /// The relay-chain + /// The list of MQC heads for the inbound channels paired with the sender para ids. This + /// vector is sorted ascending by the para id and doesn't contain multiple entries with the same + /// sender. + hrmp_mqc_heads: Vec<(ParaId, Hash)>, } ``` @@ -155,10 +145,20 @@ struct TransientValidationData { max_head_data_size: u32, /// The balance of the parachain at the moment of validation. balance: Balance, - /// The list of MQC heads for the inbound channels paired with the sender para ids. This - /// vector is sorted ascending by the para id and doesn't contain multiple entries with the same - /// sender. This informs the collator. - hrmp_mqc_heads: Vec<(ParaId, Hash)>, + /// Whether the parachain is allowed to upgrade its validation code. + /// + /// This is `Some` if so, and contains the number of the minimum relay-chain + /// height at which the upgrade will be applied, if an upgrade is signaled + /// now. + /// + /// A parachain should enact its side of the upgrade at the end of the first + /// parablock executing in the context of a relay-chain block with at least this + /// height. This may be equal to the current perceived relay-chain block height, in + /// which case the code upgrade should be applied at the end of the signaling + /// block. + /// + /// This informs a relay-chain backing check and the parachain logic. + code_upgrade_allowed: Option<BlockNumber>, } ``` @@ -219,8 +219,8 @@ This struct encapsulates the outputs of candidate validation. struct ValidationOutputs { /// The head-data produced by validation. head_data: HeadData, - /// The validation data, persisted and transient. - validation_data: ValidationData, + /// The validation data, persisted. + validation_data: PersistedValidationData, /// Messages directed to other paras routed via the relay chain. horizontal_messages: Vec<OutboundHrmpMessage>, /// Upwards messages to the relay chain. diff --git a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md index e054b82f078010ef473596176937a61f9445ab7b..0fdd871e274e8d7aea425214472f9370d5345388 100644 --- a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md @@ -393,11 +393,13 @@ enum CandidateValidationMessage { /// the para is not free at the relay-parent, an error is returned. ValidateFromChainState(CandidateDescriptor, PoV, ResponseChannel<Result<ValidationResult>>), - /// Validate a candidate with provided parameters. Explicitly provide the `OmittedValidationData` + /// Validate a candidate with provided parameters. Explicitly provide the `PersistedValidationData` /// and `ValidationCode` so this can do full validation without needing to access the state of - /// the relay-chain. + /// the relay-chain. Optionally provide the `TransientValidationData` which will lead to checks + /// on the output. ValidateFromExhaustive( - OmittedValidationData, + PersistedValidationData, + Option<TransientValidationData>, ValidationCode, CandidateDescriptor, PoV, diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index ae85e751bf531dc57e3e9417e7b078e363383f81..9b51404fc06bf69108f30c74dad1f79dce08d124 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -19,13 +19,12 @@ //! Configuration can change only at session boundaries and is buffered until then. use sp_std::prelude::*; -use primitives::v1::{ValidatorId, GlobalValidationData}; +use primitives::v1::ValidatorId; use frame_support::{ decl_storage, decl_module, decl_error, dispatch::DispatchResult, weights::{DispatchClass, Weight}, }; -use sp_runtime::traits::One; use codec::{Encode, Decode}; use frame_system::ensure_root; @@ -220,16 +219,6 @@ impl<T: Trait> Module<T> { <Self as Store>::PendingConfig::set(Some(prev)); } } - - /// Computes the global validation-data, assuming the context of the parent block. - pub(crate) fn global_validation_data() -> GlobalValidationData<T::BlockNumber> { - let config = Self::config(); - GlobalValidationData { - max_code_size: config.max_code_size, - max_head_data_size: config.max_head_data_size, - block_number: <frame_system::Module<T>>::block_number() - One::one(), - } - } } #[cfg(test)] diff --git a/polkadot/runtime/parachains/src/inclusion.rs b/polkadot/runtime/parachains/src/inclusion.rs index 0050e85724bb08c95609d6538e58f288a02b1847..1e04c2a407911b108a0afda8b43b039fb88fd784 100644 --- a/polkadot/runtime/parachains/src/inclusion.rs +++ b/polkadot/runtime/parachains/src/inclusion.rs @@ -22,7 +22,6 @@ use sp_std::prelude::*; use primitives::v1::{ - validation_data_hash, ValidatorId, CandidateCommitments, CandidateDescriptor, ValidatorIndex, Id as ParaId, AvailabilityBitfield as AvailabilityBitfield, SignedAvailabilityBitfields, SigningContext, BackedCandidate, CoreIndex, GroupIndex, CommittedCandidateReceipt, @@ -435,9 +434,8 @@ impl<T: Trait> Module<T> { { // this should never fail because the para is registered - let (global_validation_data, local_validation_data) = ( - <configuration::Module<T>>::global_validation_data(), - match <paras::Module<T>>::local_validation_data(para_id) { + let persisted_validation_data = + match crate::util::make_persisted_validation_data::<T>(para_id) { Some(l) => l, None => { // We don't want to error out here because it will @@ -445,16 +443,12 @@ impl<T: Trait> Module<T> { // doing anything. return Ok(Vec::new()); } - } - ); + }; - let expected = validation_data_hash( - &global_validation_data, - &local_validation_data, - ); + let expected = persisted_validation_data.hash(); ensure!( - expected == candidate.descriptor().validation_data_hash, + expected == candidate.descriptor().persisted_validation_data_hash, Error::<T>::ValidationDataHashMismatch, ); } @@ -722,7 +716,7 @@ mod tests { let payload = primitives::v1::collator_signature_payload( &candidate.descriptor.relay_parent, &candidate.descriptor.para_id, - &candidate.descriptor.validation_data_hash, + &candidate.descriptor.persisted_validation_data_hash, &candidate.descriptor.pov_hash, ); @@ -851,7 +845,7 @@ mod tests { head_data: HeadData, pov_hash: Hash, relay_parent: Hash, - validation_data_hash: Hash, + persisted_validation_data_hash: Hash, new_validation_code: Option<ValidationCode>, } @@ -862,7 +856,7 @@ mod tests { para_id: self.para_id, pov_hash: self.pov_hash, relay_parent: self.relay_parent, - validation_data_hash: self.validation_data_hash, + persisted_validation_data_hash: self.persisted_validation_data_hash, ..Default::default() }, commitments: CandidateCommitments { @@ -875,9 +869,9 @@ mod tests { } fn make_vdata_hash(para_id: ParaId) -> Option<Hash> { - let global_validation_data = Configuration::global_validation_data(); - let local_validation_data = Paras::local_validation_data(para_id)?; - Some(validation_data_hash(&global_validation_data, &local_validation_data)) + let persisted_validation_data + = crate::util::make_persisted_validation_data::<Test>(para_id)?; + Some(persisted_validation_data.hash()) } #[test] @@ -1306,7 +1300,7 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), - validation_data_hash: make_vdata_hash(chain_a).unwrap(), + persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); collator_sign_candidate( @@ -1338,14 +1332,14 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), - validation_data_hash: make_vdata_hash(chain_a).unwrap(), + persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); let mut candidate_b = TestCandidateBuilder { para_id: chain_b, relay_parent: System::parent_hash(), pov_hash: Hash::from([2; 32]), - validation_data_hash: make_vdata_hash(chain_b).unwrap(), + persisted_validation_data_hash: make_vdata_hash(chain_b).unwrap(), ..Default::default() }.build(); @@ -1392,7 +1386,7 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), - validation_data_hash: make_vdata_hash(chain_a).unwrap(), + persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); collator_sign_candidate( @@ -1427,7 +1421,7 @@ mod tests { para_id: chain_a, relay_parent: wrong_parent_hash, pov_hash: Hash::from([1; 32]), - validation_data_hash: make_vdata_hash(chain_a).unwrap(), + persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); collator_sign_candidate( @@ -1459,7 +1453,7 @@ mod tests { para_id: thread_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), - validation_data_hash: make_vdata_hash(thread_a).unwrap(), + persisted_validation_data_hash: make_vdata_hash(thread_a).unwrap(), ..Default::default() }.build(); @@ -1497,7 +1491,7 @@ mod tests { para_id: thread_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), - validation_data_hash: make_vdata_hash(thread_a).unwrap(), + persisted_validation_data_hash: make_vdata_hash(thread_a).unwrap(), ..Default::default() }.build(); @@ -1534,7 +1528,7 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), - validation_data_hash: make_vdata_hash(chain_a).unwrap(), + persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); @@ -1580,7 +1574,7 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), - validation_data_hash: make_vdata_hash(chain_a).unwrap(), + persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); @@ -1619,7 +1613,7 @@ mod tests { relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), new_validation_code: Some(vec![5, 6, 7, 8].into()), - validation_data_hash: make_vdata_hash(chain_a).unwrap(), + persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); @@ -1660,7 +1654,7 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), - validation_data_hash: [42u8; 32].into(), + persisted_validation_data_hash: [42u8; 32].into(), ..Default::default() }.build(); @@ -1750,7 +1744,7 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), - validation_data_hash: make_vdata_hash(chain_a).unwrap(), + persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); collator_sign_candidate( @@ -1762,7 +1756,7 @@ mod tests { para_id: chain_b, relay_parent: System::parent_hash(), pov_hash: Hash::from([2; 32]), - validation_data_hash: make_vdata_hash(chain_b).unwrap(), + persisted_validation_data_hash: make_vdata_hash(chain_b).unwrap(), ..Default::default() }.build(); collator_sign_candidate( @@ -1774,7 +1768,7 @@ mod tests { para_id: thread_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([3; 32]), - validation_data_hash: make_vdata_hash(thread_a).unwrap(), + persisted_validation_data_hash: make_vdata_hash(thread_a).unwrap(), ..Default::default() }.build(); collator_sign_candidate( @@ -1906,7 +1900,7 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), - validation_data_hash: make_vdata_hash(chain_a).unwrap(), + persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), new_validation_code: Some(vec![1, 2, 3].into()), ..Default::default() }.build(); diff --git a/polkadot/runtime/parachains/src/lib.rs b/polkadot/runtime/parachains/src/lib.rs index b41968b480f43293d19243a0f93507199818bffa..b707c3e39eaf4ff1b6b7b8a83dd86f8a3249f1c0 100644 --- a/polkadot/runtime/parachains/src/lib.rs +++ b/polkadot/runtime/parachains/src/lib.rs @@ -38,6 +38,8 @@ pub mod validity; pub mod runtime_api_impl; +mod util; + #[cfg(test)] mod mock; diff --git a/polkadot/runtime/parachains/src/paras.rs b/polkadot/runtime/parachains/src/paras.rs index abc69d0bceddc18150a7efe512f16f7cc7be909d..f2a64de6c3d0c877535d3f2dd36922859ebb5f57 100644 --- a/polkadot/runtime/parachains/src/paras.rs +++ b/polkadot/runtime/parachains/src/paras.rs @@ -26,10 +26,10 @@ use sp_std::prelude::*; #[cfg(feature = "std")] use sp_std::marker::PhantomData; -use sp_runtime::traits::{One, BlakeTwo256, Hash as HashT, Saturating}; use primitives::v1::{ - Id as ParaId, ValidationCode, HeadData, LocalValidationData, + Id as ParaId, ValidationCode, HeadData, }; +use sp_runtime::traits::One; use frame_support::{ decl_storage, decl_module, decl_error, traits::Get, @@ -550,37 +550,6 @@ impl<T: Trait> Module<T> { Self::past_code_meta(&id).most_recent_change() } - - /// Compute the local-validation data based on the head of the para. This assumes the - /// relay-parent is the parent of the current block. - pub(crate) fn local_validation_data(para_id: ParaId) -> Option<LocalValidationData<T::BlockNumber>> { - let relay_parent_number = <frame_system::Module<T>>::block_number() - One::one(); - - let config = <configuration::Module<T>>::config(); - let freq = config.validation_upgrade_frequency; - let delay = config.validation_upgrade_delay; - - let last_code_upgrade = Self::last_code_upgrade(para_id, true); - let can_upgrade_code = last_code_upgrade.map_or( - true, - |l| { l <= relay_parent_number && relay_parent_number.saturating_sub(l) >= freq }, - ); - - let code_upgrade_allowed = if can_upgrade_code { - Some(relay_parent_number + delay) - } else { - None - }; - - Some(LocalValidationData { - parent_head: Self::para_head(¶_id)?, - balance: 0, - validation_code_hash: BlakeTwo256::hash_of( - &Self::current_code(¶_id)? - ), - code_upgrade_allowed, - }) - } } #[cfg(test)] diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v1.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v1.rs index 0a19e798f1795bc64a476d23cddd8ae0b7076400..716d3eed9cb1d0036a9921c2c24bfc3d759ac4d9 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v1.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v1.rs @@ -19,10 +19,10 @@ use sp_std::prelude::*; use primitives::v1::{ - ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, GlobalValidationData, - Id as ParaId, OccupiedCoreAssumption, LocalValidationData, SessionIndex, ValidationCode, + ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, ValidationData, + Id as ParaId, OccupiedCoreAssumption, SessionIndex, ValidationCode, CommittedCandidateReceipt, ScheduledCore, OccupiedCore, CoreOccupied, CoreIndex, - GroupIndex, CandidateEvent, + GroupIndex, CandidateEvent, PersistedValidationData, }; use sp_runtime::traits::Zero; use frame_support::debug; @@ -161,36 +161,61 @@ pub fn availability_cores<T: initializer::Trait>() -> Vec<CoreState<T::BlockNumb core_states } -/// Implementation for the `global_validation_data` function of the runtime API. -pub fn global_validation_data<T: initializer::Trait>() - -> GlobalValidationData<T::BlockNumber> -{ - <configuration::Module<T>>::global_validation_data() -} - -/// Implementation for the `local_validation_data` function of the runtime API. -pub fn local_validation_data<T: initializer::Trait>( +fn with_assumption<Trait, T, F>( para_id: ParaId, assumption: OccupiedCoreAssumption, -) -> Option<LocalValidationData<T::BlockNumber>> { + build: F, +) -> Option<T> where + Trait: inclusion::Trait, + F: FnOnce() -> Option<T>, +{ match assumption { OccupiedCoreAssumption::Included => { - <inclusion::Module<T>>::force_enact(para_id); - <paras::Module<T>>::local_validation_data(para_id) + <inclusion::Module<Trait>>::force_enact(para_id); + build() } OccupiedCoreAssumption::TimedOut => { - <paras::Module<T>>::local_validation_data(para_id) + build() } OccupiedCoreAssumption::Free => { - if <inclusion::Module<T>>::pending_availability(para_id).is_some() { + if <inclusion::Module<Trait>>::pending_availability(para_id).is_some() { None } else { - <paras::Module<T>>::local_validation_data(para_id) + build() } } } } +/// Implementation for the `full_validation_data` function of the runtime API. +pub fn full_validation_data<T: initializer::Trait>( + para_id: ParaId, + assumption: OccupiedCoreAssumption, +) + -> Option<ValidationData<T::BlockNumber>> +{ + with_assumption::<T, _, _>( + para_id, + assumption, + || Some(ValidationData { + persisted: crate::util::make_persisted_validation_data::<T>(para_id)?, + transient: crate::util::make_transient_validation_data::<T>(para_id)?, + }), + ) +} + +/// Implementation for the `persisted_validation_data` function of the runtime API. +pub fn persisted_validation_data<T: initializer::Trait>( + para_id: ParaId, + assumption: OccupiedCoreAssumption, +) -> Option<PersistedValidationData<T::BlockNumber>> { + with_assumption::<T, _, _>( + para_id, + assumption, + || crate::util::make_persisted_validation_data::<T>(para_id), + ) +} + /// Implementation for the `session_index_for_child` function of the runtime API. pub fn session_index_for_child<T: initializer::Trait>() -> SessionIndex { // Just returns the session index from `inclusion`. Runtime APIs follow @@ -208,26 +233,11 @@ pub fn validation_code<T: initializer::Trait>( para_id: ParaId, assumption: OccupiedCoreAssumption, ) -> Option<ValidationCode> { - let fetch = || { - <paras::Module<T>>::current_code(¶_id) - }; - - match assumption { - OccupiedCoreAssumption::Included => { - <inclusion::Module<T>>::force_enact(para_id); - fetch() - } - OccupiedCoreAssumption::TimedOut => { - fetch() - } - OccupiedCoreAssumption::Free => { - if <inclusion::Module<T>>::pending_availability(para_id).is_some() { - None - } else { - fetch() - } - } - } + with_assumption::<T, _, _>( + para_id, + assumption, + || <paras::Module<T>>::current_code(¶_id), + ) } /// Implementation for the `candidate_pending_availability` function of the runtime API. diff --git a/polkadot/runtime/parachains/src/util.rs b/polkadot/runtime/parachains/src/util.rs new file mode 100644 index 0000000000000000000000000000000000000000..028d65c5d9579dd0332e35c6fec206048e100d5f --- /dev/null +++ b/polkadot/runtime/parachains/src/util.rs @@ -0,0 +1,71 @@ +// Copyright 2017-2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. + +//! Utilities that don't belong to any particular module but may draw +//! on all modules. + +use sp_runtime::traits::{One, Saturating}; +use primitives::v1::{Id as ParaId, PersistedValidationData, TransientValidationData}; +use sp_std::prelude::*; + +use crate::{configuration, paras}; + +/// Make the persisted validation data for a particular parachain. +/// +/// This ties together the storage of several modules. +pub fn make_persisted_validation_data<T: paras::Trait>( + para_id: ParaId, +) -> Option<PersistedValidationData<T::BlockNumber>> { + let relay_parent_number = <frame_system::Module<T>>::block_number() - One::one(); + + Some(PersistedValidationData { + parent_head: <paras::Module<T>>::para_head(¶_id)?, + block_number: relay_parent_number, + hrmp_mqc_heads: Vec::new(), + }) +} + +/// Make the transient validation data for a particular parachain. +/// +/// This ties together the storage of several modules. +pub fn make_transient_validation_data<T: paras::Trait>( + para_id: ParaId, +) -> Option<TransientValidationData<T::BlockNumber>> { + let config = <configuration::Module<T>>::config(); + let relay_parent_number = <frame_system::Module<T>>::block_number() - One::one(); + + let freq = config.validation_upgrade_frequency; + let delay = config.validation_upgrade_delay; + + let last_code_upgrade = <paras::Module<T>>::last_code_upgrade(para_id, true); + let can_upgrade_code = last_code_upgrade.map_or( + true, + |l| { l <= relay_parent_number && relay_parent_number.saturating_sub(l) >= freq }, + ); + + let code_upgrade_allowed = if can_upgrade_code { + Some(relay_parent_number + delay) + } else { + None + }; + + Some(TransientValidationData { + max_code_size: config.max_code_size, + max_head_data_size: config.max_head_data_size, + balance: 0, + code_upgrade_allowed, + }) +} diff --git a/polkadot/runtime/rococo-v1/src/lib.rs b/polkadot/runtime/rococo-v1/src/lib.rs index f1af47613ed1bc1621c98372d7d9d63013364cb5..fe812a1389c918865db4f855736622096d3516c3 100644 --- a/polkadot/runtime/rococo-v1/src/lib.rs +++ b/polkadot/runtime/rococo-v1/src/lib.rs @@ -24,9 +24,9 @@ use sp_std::prelude::*; use codec::Encode; use primitives::v1::{ AccountId, AccountIndex, Balance, BlockNumber, Hash, Nonce, Signature, Moment, - GroupRotationInfo, CoreState, Id, GlobalValidationData, ValidationCode, CandidateEvent, + GroupRotationInfo, CoreState, Id, ValidationData, ValidationCode, CandidateEvent, ValidatorId, ValidatorIndex, CommittedCandidateReceipt, OccupiedCoreAssumption, - LocalValidationData, + PersistedValidationData, }; use runtime_common::{ SlowAdjustingFeeUpdate, @@ -176,13 +176,14 @@ sp_api::impl_runtime_apis! { runtime_api_impl::availability_cores::<Runtime>() } - fn global_validation_data() -> GlobalValidationData<BlockNumber> { - runtime_api_impl::global_validation_data::<Runtime>() + fn full_validation_data(para_id: Id, assumption: OccupiedCoreAssumption) + -> Option<ValidationData<BlockNumber>> { + runtime_api_impl::full_validation_data::<Runtime>(para_id, assumption) } - fn local_validation_data(para_id: Id, assumption: OccupiedCoreAssumption) - -> Option<LocalValidationData<BlockNumber>> { - runtime_api_impl::local_validation_data::<Runtime>(para_id, assumption) + fn persisted_validation_data(para_id: Id, assumption: OccupiedCoreAssumption) + -> Option<PersistedValidationData<BlockNumber>> { + runtime_api_impl::persisted_validation_data::<Runtime>(para_id, assumption) } fn session_index_for_child() -> SessionIndex { diff --git a/polkadot/validation/src/pipeline.rs b/polkadot/validation/src/pipeline.rs index 1c826a7bb1324c41136c464fc567038b01c45134..7fe18212f081166f64f95cfc78923596cb6ddd51 100644 --- a/polkadot/validation/src/pipeline.rs +++ b/polkadot/validation/src/pipeline.rs @@ -204,10 +204,8 @@ pub fn validate<'a>( let params = ValidationParams { parent_head: local_validation.parent_head.clone(), block_data: pov_block.block_data.clone(), - max_code_size: global_validation.max_code_size, - max_head_data_size: global_validation.max_head_data_size, relay_chain_height: global_validation.block_number, - code_upgrade_allowed: local_validation.code_upgrade_allowed, + hrmp_mqc_heads: Vec::new(), }; // TODO: remove when ext does not do this.