runtime-api: add validation_code_hash API (#4629)

This is the first step to close
https://github.com/paritytech/polkadot/issues/4524
This commit is contained in:
Sergei Shulepov
2021-12-28 21:16:03 +01:00
committed by GitHub
parent b49291dc76
commit 91aff5d341
13 changed files with 153 additions and 0 deletions
@@ -48,6 +48,7 @@ const INBOUND_HRMP_CHANNELS_CACHE_SIZE: usize = 64 * 1024;
const CURRENT_BABE_EPOCH_CACHE_SIZE: usize = 64 * 1024;
const ON_CHAIN_VOTES_CACHE_SIZE: usize = 3 * 1024;
const PVFS_REQUIRE_PRECHECK_SIZE: usize = 1024;
const VALIDATION_CODE_HASH_CACHE_SIZE: usize = 64 * 1024;
struct ResidentSizeOf<T>(T);
@@ -111,6 +112,10 @@ pub(crate) struct RequestResultCache {
current_babe_epoch: MemoryLruCache<Hash, DoesNotAllocate<Epoch>>,
on_chain_votes: MemoryLruCache<Hash, ResidentSizeOf<Option<ScrapedOnChainVotes>>>,
pvfs_require_precheck: MemoryLruCache<Hash, ResidentSizeOf<Vec<ValidationCodeHash>>>,
validation_code_hash: MemoryLruCache<
(Hash, ParaId, OccupiedCoreAssumption),
ResidentSizeOf<Option<ValidationCodeHash>>,
>,
}
impl Default for RequestResultCache {
@@ -136,6 +141,7 @@ impl Default for RequestResultCache {
current_babe_epoch: MemoryLruCache::new(CURRENT_BABE_EPOCH_CACHE_SIZE),
on_chain_votes: MemoryLruCache::new(ON_CHAIN_VOTES_CACHE_SIZE),
pvfs_require_precheck: MemoryLruCache::new(PVFS_REQUIRE_PRECHECK_SIZE),
validation_code_hash: MemoryLruCache::new(VALIDATION_CODE_HASH_CACHE_SIZE),
}
}
}
@@ -381,6 +387,21 @@ impl RequestResultCache {
) {
self.pvfs_require_precheck.insert(relay_parent, ResidentSizeOf(pvfs))
}
pub(crate) fn validation_code_hash(
&mut self,
key: (Hash, ParaId, OccupiedCoreAssumption),
) -> Option<&Option<ValidationCodeHash>> {
self.validation_code_hash.get(&key).map(|v| &v.0)
}
pub(crate) fn cache_validation_code_hash(
&mut self,
key: (Hash, ParaId, OccupiedCoreAssumption),
value: Option<ValidationCodeHash>,
) {
self.validation_code_hash.insert(key, ResidentSizeOf(value));
}
}
pub(crate) enum RequestResult {
@@ -414,4 +435,5 @@ pub(crate) enum RequestResult {
PvfsRequirePrecheck(Hash, Vec<ValidationCodeHash>),
// This is a request with side-effects and no result, hence ().
SubmitPvfCheckStatement(Hash, PvfCheckStatement, ValidatorSignature, ()),
ValidationCodeHash(Hash, ParaId, OccupiedCoreAssumption, Option<ValidationCodeHash>),
}
@@ -160,6 +160,9 @@ where
PvfsRequirePrecheck(relay_parent, pvfs) =>
self.requests_cache.cache_pvfs_require_precheck(relay_parent, pvfs),
SubmitPvfCheckStatement(_, _, _, ()) => {},
ValidationCodeHash(relay_parent, para_id, assumption, hash) => self
.requests_cache
.cache_validation_code_hash((relay_parent, para_id, assumption), hash),
}
}
@@ -249,6 +252,9 @@ where
// This request is side-effecting and thus cannot be cached.
Some(request)
},
Request::ValidationCodeHash(para, assumption, sender) =>
query!(validation_code_hash(para, assumption), sender)
.map(|sender| Request::ValidationCodeHash(para, assumption, sender)),
}
}
@@ -486,6 +492,8 @@ where
Request::PvfsRequirePrecheck(sender) => {
query!(PvfsRequirePrecheck, pvfs_require_precheck(), ver = 2, sender)
},
Request::ValidationCodeHash(para, assumption, sender) =>
query!(ValidationCodeHash, validation_code_hash(para, assumption), ver = 2, sender),
}
}
@@ -56,6 +56,7 @@ struct MockRuntimeApi {
on_chain_votes: Option<ScrapedOnChainVotes>,
submitted_pvf_check_statement: Arc<Mutex<Vec<(PvfCheckStatement, ValidatorSignature)>>>,
pvfs_require_precheck: Vec<ValidationCodeHash>,
validation_code_hash: HashMap<ParaId, ValidationCodeHash>,
}
impl ProvideRuntimeApi<Block> for MockRuntimeApi {
@@ -183,6 +184,14 @@ sp_api::mock_impl_runtime_apis! {
fn pvfs_require_precheck() -> Vec<ValidationCodeHash> {
self.pvfs_require_precheck.clone()
}
fn validation_code_hash(
&self,
para: ParaId,
_assumption: OccupiedCoreAssumption,
) -> Option<ValidationCodeHash> {
self.validation_code_hash.get(&para).map(|c| c.clone())
}
}
impl BabeApi<Block> for MockRuntimeApi {
@@ -987,3 +996,51 @@ fn requests_pvfs_require_precheck() {
futures::executor::block_on(future::join(subsystem_task, test_task));
}
#[test]
fn requests_validation_code_hash() {
let (ctx, mut ctx_handle) = 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_hash = dummy_validation_code().hash();
let mut runtime_api = MockRuntimeApi::default();
runtime_api.validation_code_hash.insert(para_a, validation_code_hash.clone());
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::ValidationCodeHash(para_a, OccupiedCoreAssumption::Included, tx),
),
})
.await;
assert_eq!(rx.await.unwrap().unwrap(), Some(validation_code_hash));
let (tx, rx) = oneshot::channel();
ctx_handle
.send(FromOverseer::Communication {
msg: RuntimeApiMessage::Request(
relay_parent,
Request::ValidationCodeHash(para_b, OccupiedCoreAssumption::Included, 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));
}