mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 14:37:57 +00:00
pvf-precheck: hook up runtime API (#4542)
This commit hooks up the API provided by #4457 to the runtime API subsystem. In a following PR this API will be consumed by the PVF pre-checking subsystem. Co-authored-by: Chris Sosnin <chris125_@live.com> Co-authored-by: Chris Sosnin <chris125_@live.com>
This commit is contained in:
@@ -24,8 +24,8 @@ use polkadot_primitives::v1::{
|
||||
AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent,
|
||||
CommittedCandidateReceipt, CoreState, GroupRotationInfo, Hash, Id as ParaId,
|
||||
InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData,
|
||||
ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash,
|
||||
ValidatorId, ValidatorIndex,
|
||||
PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode,
|
||||
ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature,
|
||||
};
|
||||
|
||||
const AUTHORITIES_CACHE_SIZE: usize = 128 * 1024;
|
||||
@@ -44,6 +44,7 @@ const DMQ_CONTENTS_CACHE_SIZE: usize = 64 * 1024;
|
||||
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;
|
||||
|
||||
struct ResidentSizeOf<T>(T);
|
||||
|
||||
@@ -106,6 +107,7 @@ 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>>>,
|
||||
}
|
||||
|
||||
impl Default for RequestResultCache {
|
||||
@@ -130,6 +132,7 @@ impl Default for RequestResultCache {
|
||||
inbound_hrmp_channels_contents: MemoryLruCache::new(INBOUND_HRMP_CHANNELS_CACHE_SIZE),
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,9 +363,25 @@ impl RequestResultCache {
|
||||
) {
|
||||
self.on_chain_votes.insert(relay_parent, ResidentSizeOf(scraped));
|
||||
}
|
||||
|
||||
pub(crate) fn pvfs_require_precheck(
|
||||
&mut self,
|
||||
relay_parent: &Hash,
|
||||
) -> Option<&Vec<ValidationCodeHash>> {
|
||||
self.pvfs_require_precheck.get(relay_parent).map(|v| &v.0)
|
||||
}
|
||||
|
||||
pub(crate) fn cache_pvfs_require_precheck(
|
||||
&mut self,
|
||||
relay_parent: Hash,
|
||||
pvfs: Vec<ValidationCodeHash>,
|
||||
) {
|
||||
self.pvfs_require_precheck.insert(relay_parent, ResidentSizeOf(pvfs))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum RequestResult {
|
||||
// The structure of each variant is (relay_parent, [params,]*, result)
|
||||
Authorities(Hash, Vec<AuthorityDiscoveryId>),
|
||||
Validators(Hash, Vec<ValidatorId>),
|
||||
ValidatorGroups(Hash, (Vec<Vec<ValidatorIndex>>, GroupRotationInfo)),
|
||||
@@ -389,4 +408,7 @@ pub(crate) enum RequestResult {
|
||||
),
|
||||
CurrentBabeEpoch(Hash, Epoch),
|
||||
FetchOnChainVotes(Hash, Option<ScrapedOnChainVotes>),
|
||||
PvfsRequirePrecheck(Hash, Vec<ValidationCodeHash>),
|
||||
// This is a request with side-effects and no result, hence ().
|
||||
SubmitPvfCheckStatement(Hash, PvfCheckStatement, ValidatorSignature, ()),
|
||||
}
|
||||
|
||||
@@ -154,6 +154,9 @@ where
|
||||
self.requests_cache.cache_current_babe_epoch(relay_parent, epoch),
|
||||
FetchOnChainVotes(relay_parent, scraped) =>
|
||||
self.requests_cache.cache_on_chain_votes(relay_parent, scraped),
|
||||
PvfsRequirePrecheck(relay_parent, pvfs) =>
|
||||
self.requests_cache.cache_pvfs_require_precheck(relay_parent, pvfs),
|
||||
SubmitPvfCheckStatement(_, _, _, ()) => {},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,6 +240,12 @@ where
|
||||
query!(current_babe_epoch(), sender).map(|sender| Request::CurrentBabeEpoch(sender)),
|
||||
Request::FetchOnChainVotes(sender) =>
|
||||
query!(on_chain_votes(), sender).map(|sender| Request::FetchOnChainVotes(sender)),
|
||||
Request::PvfsRequirePrecheck(sender) => query!(pvfs_require_precheck(), sender)
|
||||
.map(|sender| Request::PvfsRequirePrecheck(sender)),
|
||||
request @ Request::SubmitPvfCheckStatement(_, _, _) => {
|
||||
// This request is side-effecting and thus cannot be cached.
|
||||
Some(request)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,6 +450,17 @@ where
|
||||
query!(CurrentBabeEpoch, current_epoch(), ver = 1, sender),
|
||||
Request::FetchOnChainVotes(sender) =>
|
||||
query!(FetchOnChainVotes, on_chain_votes(), ver = 1, sender),
|
||||
Request::SubmitPvfCheckStatement(stmt, signature, sender) => {
|
||||
query!(
|
||||
SubmitPvfCheckStatement,
|
||||
submit_pvf_check_statement(stmt, signature),
|
||||
ver = 2,
|
||||
sender
|
||||
)
|
||||
},
|
||||
Request::PvfsRequirePrecheck(sender) => {
|
||||
query!(PvfsRequirePrecheck, pvfs_require_precheck(), ver = 2, sender)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ use polkadot_node_subsystem_test_helpers::make_subsystem_context;
|
||||
use polkadot_primitives::v1::{
|
||||
AuthorityDiscoveryId, CandidateEvent, CommittedCandidateReceipt, CoreState, GroupRotationInfo,
|
||||
Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption,
|
||||
PersistedValidationData, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode,
|
||||
ValidationCodeHash, ValidatorId, ValidatorIndex,
|
||||
PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo,
|
||||
ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature,
|
||||
};
|
||||
use sp_core::testing::TaskExecutor;
|
||||
use std::{
|
||||
@@ -51,6 +51,8 @@ struct MockRuntimeApi {
|
||||
hrmp_channels: HashMap<ParaId, BTreeMap<ParaId, Vec<InboundHrmpMessage>>>,
|
||||
babe_epoch: Option<BabeEpoch>,
|
||||
on_chain_votes: Option<ScrapedOnChainVotes>,
|
||||
submitted_pvf_check_statement: Arc<Mutex<Vec<(PvfCheckStatement, ValidatorSignature)>>>,
|
||||
pvfs_require_precheck: Vec<ValidationCodeHash>,
|
||||
}
|
||||
|
||||
impl ProvideRuntimeApi<Block> for MockRuntimeApi {
|
||||
@@ -166,6 +168,18 @@ sp_api::mock_impl_runtime_apis! {
|
||||
fn on_chain_votes(&self) -> Option<ScrapedOnChainVotes> {
|
||||
self.on_chain_votes.clone()
|
||||
}
|
||||
|
||||
fn submit_pvf_check_statement(stmt: PvfCheckStatement, signature: ValidatorSignature) {
|
||||
self
|
||||
.submitted_pvf_check_statement
|
||||
.lock()
|
||||
.expect("poisoned mutext")
|
||||
.push((stmt, signature));
|
||||
}
|
||||
|
||||
fn pvfs_require_precheck() -> Vec<ValidationCodeHash> {
|
||||
self.pvfs_require_precheck.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl BabeApi<Block> for MockRuntimeApi {
|
||||
@@ -877,3 +891,93 @@ fn request_babe_epoch() {
|
||||
|
||||
futures::executor::block_on(future::join(subsystem_task, test_task));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn requests_submit_pvf_check_statement() {
|
||||
let (ctx, mut ctx_handle) = make_subsystem_context(TaskExecutor::new());
|
||||
let spawner = sp_core::testing::TaskExecutor::new();
|
||||
|
||||
let runtime_api = Arc::new(MockRuntimeApi::default());
|
||||
let subsystem = RuntimeApiSubsystem::new(runtime_api.clone(), Metrics(None), spawner);
|
||||
let subsystem_task = run(ctx, subsystem).map(|x| x.unwrap());
|
||||
|
||||
let relay_parent = [1; 32].into();
|
||||
let test_task = async move {
|
||||
let (stmt, sig) = fake_statement();
|
||||
|
||||
// Send the same statement twice.
|
||||
//
|
||||
// Here we just want to ensure that those requests do not go through the cache.
|
||||
let (tx, rx) = oneshot::channel();
|
||||
ctx_handle
|
||||
.send(FromOverseer::Communication {
|
||||
msg: RuntimeApiMessage::Request(
|
||||
relay_parent,
|
||||
Request::SubmitPvfCheckStatement(stmt.clone(), sig.clone(), tx),
|
||||
),
|
||||
})
|
||||
.await;
|
||||
assert_eq!(rx.await.unwrap().unwrap(), ());
|
||||
let (tx, rx) = oneshot::channel();
|
||||
ctx_handle
|
||||
.send(FromOverseer::Communication {
|
||||
msg: RuntimeApiMessage::Request(
|
||||
relay_parent,
|
||||
Request::SubmitPvfCheckStatement(stmt.clone(), sig.clone(), tx),
|
||||
),
|
||||
})
|
||||
.await;
|
||||
assert_eq!(rx.await.unwrap().unwrap(), ());
|
||||
|
||||
assert_eq!(
|
||||
&*runtime_api.submitted_pvf_check_statement.lock().expect("poisened mutex"),
|
||||
&[(stmt.clone(), sig.clone()), (stmt.clone(), sig.clone())]
|
||||
);
|
||||
|
||||
ctx_handle.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
|
||||
};
|
||||
|
||||
futures::executor::block_on(future::join(subsystem_task, test_task));
|
||||
|
||||
fn fake_statement() -> (PvfCheckStatement, ValidatorSignature) {
|
||||
let stmt = PvfCheckStatement {
|
||||
accept: true,
|
||||
subject: [1; 32].into(),
|
||||
session_index: 1,
|
||||
validator_index: 1.into(),
|
||||
};
|
||||
let sig = sp_keyring::Sr25519Keyring::Alice.sign(&stmt.signing_payload()).into();
|
||||
(stmt, sig)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn requests_pvfs_require_precheck() {
|
||||
let (ctx, mut ctx_handle) = make_subsystem_context(TaskExecutor::new());
|
||||
let spawner = sp_core::testing::TaskExecutor::new();
|
||||
|
||||
let runtime_api = Arc::new({
|
||||
let mut runtime_api = MockRuntimeApi::default();
|
||||
runtime_api.pvfs_require_precheck = vec![[1; 32].into(), [2; 32].into()];
|
||||
runtime_api
|
||||
});
|
||||
|
||||
let subsystem = RuntimeApiSubsystem::new(runtime_api.clone(), Metrics(None), spawner);
|
||||
let subsystem_task = run(ctx, subsystem).map(|x| x.unwrap());
|
||||
|
||||
let relay_parent = [1; 32].into();
|
||||
let test_task = async move {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
ctx_handle
|
||||
.send(FromOverseer::Communication {
|
||||
msg: RuntimeApiMessage::Request(relay_parent, Request::PvfsRequirePrecheck(tx)),
|
||||
})
|
||||
.await;
|
||||
|
||||
assert_eq!(rx.await.unwrap().unwrap(), vec![[1; 32].into(), [2; 32].into()]);
|
||||
ctx_handle.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
|
||||
};
|
||||
|
||||
futures::executor::block_on(future::join(subsystem_task, test_task));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user