Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Introduce new Runtime API endpoint for fetching the validation data #3728

Merged
merged 9 commits into from
Oct 22, 2021
29 changes: 29 additions & 0 deletions node/core/runtime-api/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const VALIDATORS_CACHE_SIZE: usize = 64 * 1024;
const VALIDATOR_GROUPS_CACHE_SIZE: usize = 64 * 1024;
const AVAILABILITY_CORES_CACHE_SIZE: usize = 64 * 1024;
const PERSISTED_VALIDATION_DATA_CACHE_SIZE: usize = 64 * 1024;
const PERSISTED_VALIDATION_DATA_WITH_CODE_HASH_CACHE_SIZE: usize = 64 * 1024;
const CHECK_VALIDATION_OUTPUTS_CACHE_SIZE: usize = 64 * 1024;
const SESSION_INDEX_FOR_CHILD_CACHE_SIZE: usize = 64 * 1024;
const VALIDATION_CODE_CACHE_SIZE: usize = 10 * 1024 * 1024;
Expand Down Expand Up @@ -78,6 +79,10 @@ pub(crate) struct RequestResultCache {
(Hash, ParaId, OccupiedCoreAssumption),
ResidentSizeOf<Option<PersistedValidationData>>,
>,
persisted_validation_data_with_code_hash: MemoryLruCache<
(ParaId, Hash),
ResidentSizeOf<Option<(PersistedValidationData, ValidationCodeHash)>>,
>,
check_validation_outputs:
MemoryLruCache<(Hash, ParaId, CandidateCommitments), ResidentSizeOf<bool>>,
session_index_for_child: MemoryLruCache<Hash, ResidentSizeOf<SessionIndex>>,
Expand Down Expand Up @@ -108,6 +113,9 @@ impl Default for RequestResultCache {
validator_groups: MemoryLruCache::new(VALIDATOR_GROUPS_CACHE_SIZE),
availability_cores: MemoryLruCache::new(AVAILABILITY_CORES_CACHE_SIZE),
persisted_validation_data: MemoryLruCache::new(PERSISTED_VALIDATION_DATA_CACHE_SIZE),
persisted_validation_data_with_code_hash: MemoryLruCache::new(
PERSISTED_VALIDATION_DATA_WITH_CODE_HASH_CACHE_SIZE,
),
check_validation_outputs: MemoryLruCache::new(CHECK_VALIDATION_OUTPUTS_CACHE_SIZE),
session_index_for_child: MemoryLruCache::new(SESSION_INDEX_FOR_CHILD_CACHE_SIZE),
validation_code: MemoryLruCache::new(VALIDATION_CODE_CACHE_SIZE),
Expand Down Expand Up @@ -186,6 +194,21 @@ impl RequestResultCache {
self.persisted_validation_data.insert(key, ResidentSizeOf(data));
}

pub(crate) fn persisted_validation_data_with_code_hash(
&mut self,
key: (Hash, ParaId, Hash),
) -> Option<&Option<(PersistedValidationData, ValidationCodeHash)>> {
self.persisted_validation_data_with_code_hash.get(&(key.1, key.2)).map(|v| &v.0)
}

pub(crate) fn cache_persisted_validation_data_with_code_hash(
&mut self,
key: (ParaId, Hash),
data: Option<(PersistedValidationData, ValidationCodeHash)>,
) {
self.persisted_validation_data_with_code_hash.insert(key, ResidentSizeOf(data));
}

pub(crate) fn check_validation_outputs(
&mut self,
key: (Hash, ParaId, CandidateCommitments),
Expand Down Expand Up @@ -328,6 +351,12 @@ pub(crate) enum RequestResult {
ValidatorGroups(Hash, (Vec<Vec<ValidatorIndex>>, GroupRotationInfo)),
AvailabilityCores(Hash, Vec<CoreState>),
PersistedValidationData(Hash, ParaId, OccupiedCoreAssumption, Option<PersistedValidationData>),
PersistedValidationDataWithCodeHash(
Hash,
ParaId,
Hash,
Option<(PersistedValidationData, ValidationCodeHash)>,
),
CheckValidationOutputs(Hash, ParaId, CandidateCommitments, bool),
SessionIndexForChild(Hash, SessionIndex),
ValidationCode(Hash, ParaId, OccupiedCoreAssumption, Option<ValidationCode>),
Expand Down
36 changes: 36 additions & 0 deletions node/core/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,15 @@ where
PersistedValidationData(relay_parent, para_id, assumption, data) => self
.requests_cache
.cache_persisted_validation_data((relay_parent, para_id, assumption), data),
PersistedValidationDataWithCodeHash(
_relay_parent,
para_id,
expected_persisted_validation_data_hash,
data,
) => self.requests_cache.cache_persisted_validation_data_with_code_hash(
(para_id, expected_persisted_validation_data_hash),
data,
),
CheckValidationOutputs(relay_parent, para_id, commitments, b) => self
.requests_cache
.cache_check_validation_outputs((relay_parent, para_id, commitments), b),
Expand Down Expand Up @@ -184,6 +193,24 @@ where
Request::PersistedValidationData(para, assumption, sender) =>
query!(persisted_validation_data(para, assumption), sender)
.map(|sender| Request::PersistedValidationData(para, assumption, sender)),
Request::PersistedValidationDataWithCodeHash(
para,
expected_persisted_validation_data_hash,
sender,
) => query!(
persisted_validation_data_with_code_hash(
para,
expected_persisted_validation_data_hash
),
sender
)
.map(|sender| {
Request::PersistedValidationDataWithCodeHash(
para,
expected_persisted_validation_data_hash,
sender,
)
}),
Request::CheckValidationOutputs(para, commitments, sender) =>
query!(check_validation_outputs(para, commitments), sender)
.map(|sender| Request::CheckValidationOutputs(para, commitments, sender)),
Expand Down Expand Up @@ -326,6 +353,15 @@ where
query!(AvailabilityCores, availability_cores(), sender),
Request::PersistedValidationData(para, assumption, sender) =>
query!(PersistedValidationData, persisted_validation_data(para, assumption), sender),
Request::PersistedValidationDataWithCodeHash(
para,
expected_persisted_validation_data_hash,
sender,
) => query!(
PersistedValidationDataWithCodeHash,
persisted_validation_data_with_code_hash(para, expected_persisted_validation_data_hash),
sender
),
Request::CheckValidationOutputs(para, commitments, sender) =>
query!(CheckValidationOutputs, check_validation_outputs(para, commitments), sender),
Request::SessionIndexForChild(sender) =>
Expand Down
63 changes: 63 additions & 0 deletions node/core/runtime-api/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ sp_api::mock_impl_runtime_apis! {
self.validation_data.get(&para).cloned()
}

fn persisted_validation_data_with_code_hash(
para_id: ParaId,
expected_persisted_validation_data_hash: Hash,
) -> Option<(PersistedValidationData, ValidationCodeHash)> {
self.validation_data
.get(&para_id)
.cloned()
.filter(|data| data.hash() == expected_persisted_validation_data_hash)
.zip(self.validation_code.get(&para_id).map(|code| code.hash()))
}

fn check_validation_outputs(
&self,
para_id: ParaId,
Expand Down Expand Up @@ -340,6 +351,58 @@ fn requests_persisted_validation_data() {
futures::executor::block_on(future::join(subsystem_task, test_task));
}

#[test]
fn requests_persisted_validation_data_with_code_hash() {
let (ctx, mut ctx_handle) = test_helpers::make_subsystem_context(TaskExecutor::new());
let relay_parent = [1; 32].into();
let para_a = 5.into();
let para_b = 6.into();
let spawner = sp_core::testing::TaskExecutor::new();

let validation_code = ValidationCode(vec![1, 2, 3]);
let expected_data_hash = <PersistedValidationData as Default>::default().hash();
let expected_code_hash = validation_code.hash();

let mut runtime_api = MockRuntimeApi::default();
runtime_api.validation_data.insert(para_a, Default::default());
runtime_api.validation_code.insert(para_a, validation_code);
runtime_api.validation_data.insert(para_b, Default::default());
let runtime_api = Arc::new(runtime_api);

let subsystem = RuntimeApiSubsystem::new(runtime_api.clone(), Metrics(None), spawner);
let subsystem_task = run(ctx, subsystem).map(|x| x.unwrap());
let test_task = async move {
let (tx, rx) = oneshot::channel();

ctx_handle
.send(FromOverseer::Communication {
msg: RuntimeApiMessage::Request(
relay_parent,
Request::PersistedValidationDataWithCodeHash(para_a, expected_data_hash, tx),
),
})
.await;

assert_eq!(rx.await.unwrap().unwrap(), Some((Default::default(), expected_code_hash)));

let (tx, rx) = oneshot::channel();
ctx_handle
.send(FromOverseer::Communication {
msg: RuntimeApiMessage::Request(
relay_parent,
Request::PersistedValidationDataWithCodeHash(para_a, Hash::zero(), tx),
),
})
.await;

assert_eq!(rx.await.unwrap().unwrap(), None);

ctx_handle.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
};

futures::executor::block_on(future::join(subsystem_task, test_task));
}

#[test]
fn requests_check_validation_outputs() {
let (ctx, mut ctx_handle) = test_helpers::make_subsystem_context(TaskExecutor::new());
Expand Down
7 changes: 7 additions & 0 deletions node/subsystem-types/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,13 @@ pub enum RuntimeApiRequest {
OccupiedCoreAssumption,
RuntimeApiSender<Option<PersistedValidationData>>,
),
/// Get the persisted validation data for a particular para along with the current validation code
/// hash, matching the data hash against an expected one without any assumptions.
PersistedValidationDataWithCodeHash(
ParaId,
Hash,
RuntimeApiSender<Option<(PersistedValidationData, ValidationCodeHash)>>,
),
/// Sends back `true` if the validation outputs pass all acceptance criteria checks.
CheckValidationOutputs(
ParaId,
Expand Down
8 changes: 8 additions & 0 deletions primitives/src/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,14 @@ sp_api::decl_runtime_apis! {
fn persisted_validation_data(para_id: Id, assumption: OccupiedCoreAssumption)
-> Option<PersistedValidationData<H, N>>;

/// Returns the persisted validation data for the given `ParaId` along with the corresponding
/// validation code hash. Instead of accepting assumption about the para, matches the validation
/// data hash against an expected one and yields `None` if they're not equal.
fn persisted_validation_data_with_code_hash(
slumber marked this conversation as resolved.
Show resolved Hide resolved
para_id: Id,
expected_persisted_validation_data_hash: Hash,
) -> Option<(PersistedValidationData<H, N>, ValidationCodeHash)>;

/// Checks if the given validation outputs pass the acceptance criteria.
fn check_validation_outputs(para_id: Id, outputs: CandidateCommitments) -> bool;

Expand Down
10 changes: 10 additions & 0 deletions runtime/kusama/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1579,6 +1579,16 @@ sp_api::impl_runtime_apis! {
parachains_runtime_api_impl::persisted_validation_data::<Runtime>(para_id, assumption)
}

fn persisted_validation_data_with_code_hash(
para_id: ParaId,
expected_persisted_validation_data_hash: Hash,
) -> Option<(PersistedValidationData<Hash, BlockNumber>, ValidationCodeHash)> {
parachains_runtime_api_impl::persisted_validation_data_with_code_hash::<Runtime>(
para_id,
expected_persisted_validation_data_hash
)
}

fn check_validation_outputs(
para_id: ParaId,
outputs: primitives::v1::CandidateCommitments,
Expand Down
7 changes: 6 additions & 1 deletion runtime/parachains/src/paras.rs
Original file line number Diff line number Diff line change
Expand Up @@ -587,9 +587,14 @@ impl<T: Config> Pallet<T> {
outgoing_paras
}

/// The validation code hash of live para.
pub(crate) fn current_code_hash(para_id: &ParaId) -> Option<ValidationCodeHash> {
slumber marked this conversation as resolved.
Show resolved Hide resolved
CurrentCodeHash::<T>::get(para_id)
}

/// The validation code of live para.
pub(crate) fn current_code(para_id: &ParaId) -> Option<ValidationCode> {
CurrentCodeHash::<T>::get(para_id).and_then(|code_hash| {
Self::current_code_hash(para_id).and_then(|code_hash| {
let code = CodeByHash::<T>::get(&code_hash);
if code.is_none() {
log::error!(
Expand Down
40 changes: 35 additions & 5 deletions runtime/parachains/src/runtime_api_impl/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{
};
use primitives::v1::{
AuthorityDiscoveryId, CandidateEvent, CommittedCandidateReceipt, CoreIndex, CoreOccupied,
CoreState, GroupIndex, GroupRotationInfo, Id as ParaId, InboundDownwardMessage,
CoreState, GroupIndex, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage,
InboundHrmpMessage, OccupiedCore, OccupiedCoreAssumption, PersistedValidationData,
ScheduledCore, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId,
ValidatorIndex,
Expand Down Expand Up @@ -172,6 +172,16 @@ pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, T:
core_states
}

/// Returns current block number being processed and the corresponding root hash.
fn current_relay_parent<T: frame_system::Config>(
) -> (<T as frame_system::Config>::BlockNumber, <T as frame_system::Config>::Hash) {
use parity_scale_codec::Decode as _;
let relay_parent_number = <frame_system::Pallet<T>>::block_number();
let relay_parent_storage_root = T::Hash::decode(&mut &sp_io::storage::root()[..])
.expect("storage root must decode to the Hash type; qed");
(relay_parent_number, relay_parent_storage_root)
}

fn with_assumption<Config, T, F>(
para_id: ParaId,
assumption: OccupiedCoreAssumption,
Expand Down Expand Up @@ -202,10 +212,7 @@ pub fn persisted_validation_data<T: initializer::Config>(
para_id: ParaId,
assumption: OccupiedCoreAssumption,
) -> Option<PersistedValidationData<T::Hash, T::BlockNumber>> {
use parity_scale_codec::Decode as _;
let relay_parent_number = <frame_system::Pallet<T>>::block_number();
let relay_parent_storage_root = T::Hash::decode(&mut &sp_io::storage::root()[..])
.expect("storage root must decode to the Hash type; qed");
let (relay_parent_number, relay_parent_storage_root) = current_relay_parent::<T>();
with_assumption::<T, _, _>(para_id, assumption, || {
crate::util::make_persisted_validation_data::<T>(
para_id,
Expand All @@ -215,6 +222,29 @@ pub fn persisted_validation_data<T: initializer::Config>(
})
}

/// Implementation for the `persisted_validation_data_with_code_hash` function of the runtime API.
pub fn persisted_validation_data_with_code_hash<T: initializer::Config>(
para_id: ParaId,
expected_persisted_validation_data_hash: Hash,
) -> Option<(PersistedValidationData<T::Hash, T::BlockNumber>, ValidationCodeHash)> {
let (relay_parent_number, relay_parent_storage_root) = current_relay_parent::<T>();
let make_validation_data = || {
crate::util::make_persisted_validation_data::<T>(
para_id,
relay_parent_number,
relay_parent_storage_root,
)
.filter(|validation_data| validation_data.hash() == expected_persisted_validation_data_hash)
};
let persisted_validation_data = make_validation_data().or_else(|| {
<inclusion::Pallet<T>>::pending_availability(para_id).and_then(|_| {
<inclusion::Pallet<T>>::force_enact(para_id);
make_validation_data()
})
});
persisted_validation_data.zip(<paras::Pallet<T>>::current_code_hash(&para_id))
slumber marked this conversation as resolved.
Show resolved Hide resolved
}

/// Implementation for the `check_validation_outputs` function of the runtime API.
pub fn check_validation_outputs<T: initializer::Config>(
para_id: ParaId,
Expand Down
7 changes: 7 additions & 0 deletions runtime/polkadot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1219,6 +1219,13 @@ sp_api::impl_runtime_apis! {
None
}

fn persisted_validation_data_with_code_hash(
_: Id,
_: Hash,
) -> Option<(PersistedValidationData<Hash, BlockNumber>, ValidationCodeHash)> {
None
}

fn check_validation_outputs(_: Id, _: primitives::v1::CandidateCommitments) -> bool {
false
}
Expand Down
10 changes: 10 additions & 0 deletions runtime/rococo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,16 @@ sp_api::impl_runtime_apis! {
runtime_api_impl::persisted_validation_data::<Runtime>(para_id, assumption)
}

fn persisted_validation_data_with_code_hash(
para_id: ParaId,
expected_persisted_validation_data_hash: Hash,
) -> Option<(PersistedValidationData<Hash, BlockNumber>, ValidationCodeHash)> {
runtime_api_impl::persisted_validation_data_with_code_hash::<Runtime>(
para_id,
expected_persisted_validation_data_hash
)
}

fn check_validation_outputs(
para_id: Id,
outputs: primitives::v1::CandidateCommitments,
Expand Down
10 changes: 10 additions & 0 deletions runtime/test-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,16 @@ sp_api::impl_runtime_apis! {
runtime_impl::persisted_validation_data::<Runtime>(para_id, assumption)
}

fn persisted_validation_data_with_code_hash(
para_id: ParaId,
expected_persisted_validation_data_hash: Hash,
) -> Option<(PersistedValidationData<Hash, BlockNumber>, ValidationCodeHash)> {
runtime_impl::persisted_validation_data_with_code_hash::<Runtime>(
para_id,
expected_persisted_validation_data_hash
)
}

fn check_validation_outputs(
para_id: ParaId,
outputs: primitives::v1::CandidateCommitments,
Expand Down
10 changes: 10 additions & 0 deletions runtime/westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,16 @@ sp_api::impl_runtime_apis! {
parachains_runtime_api_impl::persisted_validation_data::<Runtime>(para_id, assumption)
}

fn persisted_validation_data_with_code_hash(
para_id: ParaId,
expected_persisted_validation_data_hash: Hash,
) -> Option<(PersistedValidationData<Hash, BlockNumber>, ValidationCodeHash)> {
parachains_runtime_api_impl::persisted_validation_data_with_code_hash::<Runtime>(
para_id,
expected_persisted_validation_data_hash
)
}

fn check_validation_outputs(
para_id: ParaId,
outputs: primitives::v1::CandidateCommitments,
Expand Down