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

* Introduce new Runtime API endpoint

`persisted_validation_data_with_code_hash` that will be used
by the candidate validation subsystem in order to decrease amount
of runtime API requests.

* Node-side part of new runtime API request

* Define code hash getter via macro

* Rename new endpoint to `assumed_validation_data`

* Docs for runtime API impl of new endpoint

* AssumedValidationData specialized request function

* fmt
This commit is contained in:
Chris Sosnin
2021-10-22 15:49:26 +03:00
committed by GitHub
parent 228977fd52
commit ad33b8749b
13 changed files with 230 additions and 7 deletions
@@ -33,6 +33,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 ASSUMED_VALIDATION_DATA_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;
@@ -80,6 +81,10 @@ pub(crate) struct RequestResultCache {
(Hash, ParaId, OccupiedCoreAssumption),
ResidentSizeOf<Option<PersistedValidationData>>,
>,
assumed_validation_data: MemoryLruCache<
(ParaId, Hash),
ResidentSizeOf<Option<(PersistedValidationData, ValidationCodeHash)>>,
>,
check_validation_outputs:
MemoryLruCache<(Hash, ParaId, CandidateCommitments), ResidentSizeOf<bool>>,
session_index_for_child: MemoryLruCache<Hash, ResidentSizeOf<SessionIndex>>,
@@ -111,6 +116,7 @@ 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),
assumed_validation_data: MemoryLruCache::new(ASSUMED_VALIDATION_DATA_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),
@@ -190,6 +196,21 @@ impl RequestResultCache {
self.persisted_validation_data.insert(key, ResidentSizeOf(data));
}
pub(crate) fn assumed_validation_data(
&mut self,
key: (Hash, ParaId, Hash),
) -> Option<&Option<(PersistedValidationData, ValidationCodeHash)>> {
self.assumed_validation_data.get(&(key.1, key.2)).map(|v| &v.0)
}
pub(crate) fn cache_assumed_validation_data(
&mut self,
key: (ParaId, Hash),
data: Option<(PersistedValidationData, ValidationCodeHash)>,
) {
self.assumed_validation_data.insert(key, ResidentSizeOf(data));
}
pub(crate) fn check_validation_outputs(
&mut self,
key: (Hash, ParaId, CandidateCommitments),
@@ -347,6 +368,12 @@ pub(crate) enum RequestResult {
ValidatorGroups(Hash, (Vec<Vec<ValidatorIndex>>, GroupRotationInfo)),
AvailabilityCores(Hash, Vec<CoreState>),
PersistedValidationData(Hash, ParaId, OccupiedCoreAssumption, Option<PersistedValidationData>),
AssumedValidationData(
Hash,
ParaId,
Hash,
Option<(PersistedValidationData, ValidationCodeHash)>,
),
CheckValidationOutputs(Hash, ParaId, CandidateCommitments, bool),
SessionIndexForChild(Hash, SessionIndex),
ValidationCode(Hash, ParaId, OccupiedCoreAssumption, Option<ValidationCode>),
+30
View File
@@ -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),
AssumedValidationData(
_relay_parent,
para_id,
expected_persisted_validation_data_hash,
data,
) => self.requests_cache.cache_assumed_validation_data(
(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),
@@ -186,6 +195,21 @@ where
Request::PersistedValidationData(para, assumption, sender) =>
query!(persisted_validation_data(para, assumption), sender)
.map(|sender| Request::PersistedValidationData(para, assumption, sender)),
Request::AssumedValidationData(
para,
expected_persisted_validation_data_hash,
sender,
) => query!(
assumed_validation_data(para, expected_persisted_validation_data_hash),
sender
)
.map(|sender| {
Request::AssumedValidationData(
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)),
@@ -330,6 +354,12 @@ where
query!(AvailabilityCores, availability_cores(), sender),
Request::PersistedValidationData(para, assumption, sender) =>
query!(PersistedValidationData, persisted_validation_data(para, assumption), sender),
Request::AssumedValidationData(para, expected_persisted_validation_data_hash, sender) =>
query!(
AssumedValidationData,
assumed_validation_data(para, expected_persisted_validation_data_hash),
sender
),
Request::CheckValidationOutputs(para, commitments, sender) =>
query!(CheckValidationOutputs, check_validation_outputs(para, commitments), sender),
Request::SessionIndexForChild(sender) =>
@@ -90,6 +90,17 @@ sp_api::mock_impl_runtime_apis! {
self.validation_data.get(&para).cloned()
}
fn assumed_validation_data(
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,
@@ -345,6 +356,58 @@ fn requests_persisted_validation_data() {
futures::executor::block_on(future::join(subsystem_task, test_task));
}
#[test]
fn requests_assumed_validation_data() {
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::AssumedValidationData(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::AssumedValidationData(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());