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:
Sergei Shulepov
2021-12-21 15:15:30 +01:00
committed by GitHub
parent 5a3ee43cda
commit 3cb138d236
12 changed files with 220 additions and 9 deletions
+1
View File
@@ -6378,6 +6378,7 @@ dependencies = [
"sp-authority-discovery",
"sp-consensus-babe",
"sp-core",
"sp-keyring",
"tracing",
]
@@ -21,6 +21,7 @@ polkadot-node-subsystem-util = { path = "../../subsystem-util" }
[dev-dependencies]
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
futures = { version = "0.3.19", features = ["thread-pool"] }
polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" }
polkadot-node-primitives = { path = "../../primitives" }
+24 -2
View File
@@ -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, ()),
}
+20
View File
@@ -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)
},
}
}
+106 -2
View File
@@ -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));
}
@@ -43,9 +43,9 @@ use polkadot_primitives::v1::{
CandidateHash, CandidateIndex, CandidateReceipt, CollatorId, CommittedCandidateReceipt,
CoreState, GroupIndex, GroupRotationInfo, Hash, Header as BlockHeader, Id as ParaId,
InboundDownwardMessage, InboundHrmpMessage, MultiDisputeStatementSet, OccupiedCoreAssumption,
PersistedValidationData, SessionIndex, SessionInfo, SignedAvailabilityBitfield,
SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex,
ValidatorSignature,
PersistedValidationData, PvfCheckStatement, SessionIndex, SessionInfo,
SignedAvailabilityBitfield, SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash,
ValidatorId, ValidatorIndex, ValidatorSignature,
};
use polkadot_statement_table::v1::Misbehavior;
use std::{
@@ -666,6 +666,10 @@ pub enum RuntimeApiRequest {
CurrentBabeEpoch(RuntimeApiSender<BabeEpoch>),
/// Get all disputes in relation to a relay parent.
FetchOnChainVotes(RuntimeApiSender<Option<polkadot_primitives::v1::ScrapedOnChainVotes>>),
/// Submits a PVF pre-checking statement into the transaction pool.
SubmitPvfCheckStatement(PvfCheckStatement, ValidatorSignature, RuntimeApiSender<()>),
/// Returns code hashes of PVFs that require pre-checking by validators in the active set.
PvfsRequirePrecheck(RuntimeApiSender<Vec<ValidationCodeHash>>),
}
/// A message to the Runtime API subsystem.
+7
View File
@@ -986,6 +986,7 @@ impl ApprovalVote {
sp_api::decl_runtime_apis! {
/// The API for querying the state of parachains on-chain.
#[api_version(2)]
pub trait ParachainHost<H: Encode + Decode = Hash, N: Encode + Decode = BlockNumber> {
/// Get the current validators.
fn validators() -> Vec<ValidatorId>;
@@ -1054,6 +1055,12 @@ sp_api::decl_runtime_apis! {
/// Scrape dispute relevant from on-chain, backing votes and resolved disputes.
fn on_chain_votes() -> Option<ScrapedOnChainVotes<H>>;
/// Submits a PVF pre-checking statement into the transaction pool.
fn submit_pvf_check_statement(stmt: PvfCheckStatement, signature: ValidatorSignature);
/// Returns code hashes of PVFs that require pre-checking by validators in the active set.
fn pvfs_require_precheck() -> Vec<ValidationCodeHash>;
}
}
+11
View File
@@ -1814,6 +1814,17 @@ sp_api::impl_runtime_apis! {
fn on_chain_votes() -> Option<ScrapedOnChainVotes<Hash>> {
parachains_runtime_api_impl::on_chain_votes::<Runtime>()
}
fn submit_pvf_check_statement(
stmt: primitives::v1::PvfCheckStatement,
signature: primitives::v1::ValidatorSignature,
) {
parachains_runtime_api_impl::submit_pvf_check_statement::<Runtime>(stmt, signature)
}
fn pvfs_require_precheck() -> Vec<ValidationCodeHash> {
parachains_runtime_api_impl::pvfs_require_precheck::<Runtime>()
}
}
impl beefy_primitives::BeefyApi<Block> for Runtime {
+11
View File
@@ -1781,6 +1781,17 @@ sp_api::impl_runtime_apis! {
fn on_chain_votes() -> Option<ScrapedOnChainVotes<Hash>> {
parachains_runtime_api_impl::on_chain_votes::<Runtime>()
}
fn submit_pvf_check_statement(
stmt: primitives::v1::PvfCheckStatement,
signature: primitives::v1::ValidatorSignature,
) {
parachains_runtime_api_impl::submit_pvf_check_statement::<Runtime>(stmt, signature)
}
fn pvfs_require_precheck() -> Vec<ValidationCodeHash> {
parachains_runtime_api_impl::pvfs_require_precheck::<Runtime>()
}
}
impl beefy_primitives::BeefyApi<Block> for Runtime {
+10 -2
View File
@@ -38,9 +38,9 @@ use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use primitives::v1::{
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
CoreState, GroupRotationInfo, Hash, Id, InboundDownwardMessage, InboundHrmpMessage, Moment,
Nonce, OccupiedCoreAssumption, PersistedValidationData, ScrapedOnChainVotes,
Nonce, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes,
SessionInfo as SessionInfoData, Signature, ValidationCode, ValidationCodeHash, ValidatorId,
ValidatorIndex,
ValidatorIndex, ValidatorSignature,
};
use runtime_common::{
assigned_slots, auctions, crowdloan, impls::ToAuthor, paras_registrar, paras_sudo_wrapper,
@@ -1372,6 +1372,14 @@ sp_api::impl_runtime_apis! {
fn on_chain_votes() -> Option<ScrapedOnChainVotes<Hash>> {
runtime_api_impl::on_chain_votes::<Runtime>()
}
fn submit_pvf_check_statement(stmt: PvfCheckStatement, signature: ValidatorSignature) {
runtime_api_impl::submit_pvf_check_statement::<Runtime>(stmt, signature)
}
fn pvfs_require_precheck() -> Vec<ValidationCodeHash> {
runtime_api_impl::pvfs_require_precheck::<Runtime>()
}
}
impl fg_primitives::GrandpaApi<Block> for Runtime {
+11
View File
@@ -873,6 +873,17 @@ sp_api::impl_runtime_apis! {
fn on_chain_votes() -> Option<ScrapedOnChainVotes<Hash>> {
runtime_impl::on_chain_votes::<Runtime>()
}
fn submit_pvf_check_statement(
stmt: primitives::v1::PvfCheckStatement,
signature: primitives::v1::ValidatorSignature,
) {
runtime_impl::submit_pvf_check_statement::<Runtime>(stmt, signature)
}
fn pvfs_require_precheck() -> Vec<ValidationCodeHash> {
runtime_impl::pvfs_require_precheck::<Runtime>()
}
}
impl beefy_primitives::BeefyApi<Block> for Runtime {
+11
View File
@@ -1385,6 +1385,17 @@ sp_api::impl_runtime_apis! {
fn on_chain_votes() -> Option<ScrapedOnChainVotes<Hash>> {
parachains_runtime_api_impl::on_chain_votes::<Runtime>()
}
fn submit_pvf_check_statement(
stmt: primitives::v1::PvfCheckStatement,
signature: primitives::v1::ValidatorSignature,
) {
parachains_runtime_api_impl::submit_pvf_check_statement::<Runtime>(stmt, signature)
}
fn pvfs_require_precheck() -> Vec<ValidationCodeHash> {
parachains_runtime_api_impl::pvfs_require_precheck::<Runtime>()
}
}
impl beefy_primitives::BeefyApi<Block> for Runtime {