mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-29 02:07:56 +00:00
Code, PoV compression and remove CompressedPoV struct (#2852)
* use compressed blob in candidate-validation * add some tests for compressed code blobs * remove CompressedPoV and apply compression in collation-generation * decompress BlockData before executing * don't produce oversized collations * add test for PoV decompression failure * fix tests and clean up * fix test * address review and fix CI * take this )
This commit is contained in:
committed by
GitHub
parent
bb48c47fbf
commit
896ec8dbc3
@@ -33,7 +33,9 @@ use polkadot_subsystem::{
|
||||
};
|
||||
use polkadot_node_subsystem_util::metrics::{self, prometheus};
|
||||
use polkadot_subsystem::errors::RuntimeApiError;
|
||||
use polkadot_node_primitives::{ValidationResult, InvalidCandidate, PoV};
|
||||
use polkadot_node_primitives::{
|
||||
VALIDATION_CODE_BOMB_LIMIT, POV_BOMB_LIMIT, ValidationResult, InvalidCandidate, PoV, BlockData,
|
||||
};
|
||||
use polkadot_primitives::v1::{
|
||||
ValidationCode, CandidateDescriptor, PersistedValidationData,
|
||||
OccupiedCoreAssumption, Hash, CandidateCommitments,
|
||||
@@ -368,12 +370,12 @@ fn perform_basic_checks(
|
||||
pov: &PoV,
|
||||
validation_code: &ValidationCode,
|
||||
) -> Result<(), InvalidCandidate> {
|
||||
let encoded_pov = pov.encode();
|
||||
let pov_hash = pov.hash();
|
||||
let validation_code_hash = validation_code.hash();
|
||||
|
||||
if encoded_pov.len() > max_pov_size as usize {
|
||||
return Err(InvalidCandidate::ParamsTooLarge(encoded_pov.len() as u64));
|
||||
let encoded_pov_size = pov.encoded_size();
|
||||
if encoded_pov_size > max_pov_size as usize {
|
||||
return Err(InvalidCandidate::ParamsTooLarge(encoded_pov_size as u64));
|
||||
}
|
||||
|
||||
if pov_hash != candidate.pov_hash {
|
||||
@@ -396,7 +398,7 @@ trait ValidationBackend {
|
||||
|
||||
fn validate<S: SpawnNamed + 'static>(
|
||||
arg: Self::Arg,
|
||||
validation_code: &ValidationCode,
|
||||
raw_validation_code: &[u8],
|
||||
params: ValidationParams,
|
||||
spawn: S,
|
||||
) -> Result<WasmValidationResult, ValidationError>;
|
||||
@@ -409,12 +411,12 @@ impl ValidationBackend for RealValidationBackend {
|
||||
|
||||
fn validate<S: SpawnNamed + 'static>(
|
||||
isolation_strategy: IsolationStrategy,
|
||||
validation_code: &ValidationCode,
|
||||
raw_validation_code: &[u8],
|
||||
params: ValidationParams,
|
||||
spawn: S,
|
||||
) -> Result<WasmValidationResult, ValidationError> {
|
||||
wasm_executor::validate_candidate(
|
||||
&validation_code.0,
|
||||
&raw_validation_code,
|
||||
params,
|
||||
&isolation_strategy,
|
||||
spawn,
|
||||
@@ -446,14 +448,40 @@ fn validate_candidate_exhaustive<B: ValidationBackend, S: SpawnNamed + 'static>(
|
||||
return Ok(ValidationResult::Invalid(e))
|
||||
}
|
||||
|
||||
let raw_validation_code = match sp_maybe_compressed_blob::decompress(
|
||||
&validation_code.0,
|
||||
VALIDATION_CODE_BOMB_LIMIT,
|
||||
) {
|
||||
Ok(code) => code,
|
||||
Err(e) => {
|
||||
tracing::debug!(target: LOG_TARGET, err=?e, "Invalid validation code");
|
||||
|
||||
// If the validation code is invalid, the candidate certainly is.
|
||||
return Ok(ValidationResult::Invalid(InvalidCandidate::CodeDecompressionFailure));
|
||||
}
|
||||
};
|
||||
|
||||
let raw_block_data = match sp_maybe_compressed_blob::decompress(
|
||||
&pov.block_data.0,
|
||||
POV_BOMB_LIMIT,
|
||||
) {
|
||||
Ok(block_data) => BlockData(block_data.to_vec()),
|
||||
Err(e) => {
|
||||
tracing::debug!(target: LOG_TARGET, err=?e, "Invalid PoV code");
|
||||
|
||||
// If the PoV is invalid, the candidate certainly is.
|
||||
return Ok(ValidationResult::Invalid(InvalidCandidate::PoVDecompressionFailure));
|
||||
}
|
||||
};
|
||||
|
||||
let params = ValidationParams {
|
||||
parent_head: persisted_validation_data.parent_head.clone(),
|
||||
block_data: pov.block_data.clone(),
|
||||
block_data: raw_block_data,
|
||||
relay_parent_number: persisted_validation_data.relay_parent_number,
|
||||
relay_parent_storage_root: persisted_validation_data.relay_parent_storage_root,
|
||||
};
|
||||
|
||||
match B::validate(backend_arg, &validation_code, params, spawn) {
|
||||
match B::validate(backend_arg, &raw_validation_code, params, spawn) {
|
||||
Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::Timeout)) =>
|
||||
Ok(ValidationResult::Invalid(InvalidCandidate::Timeout)),
|
||||
Err(ValidationError::InvalidCandidate(WasmInvalidCandidate::ParamsTooLarge(l, _))) =>
|
||||
@@ -580,7 +608,6 @@ mod tests {
|
||||
use super::*;
|
||||
use polkadot_node_subsystem_test_helpers as test_helpers;
|
||||
use polkadot_primitives::v1::{HeadData, UpwardMessage};
|
||||
use polkadot_node_primitives::BlockData;
|
||||
use sp_core::testing::TaskExecutor;
|
||||
use futures::executor;
|
||||
use assert_matches::assert_matches;
|
||||
@@ -597,7 +624,7 @@ mod tests {
|
||||
|
||||
fn validate<S: SpawnNamed + 'static>(
|
||||
arg: Self::Arg,
|
||||
_validation_code: &ValidationCode,
|
||||
_raw_validation_code: &[u8],
|
||||
_params: ValidationParams,
|
||||
_spawn: S,
|
||||
) -> Result<WasmValidationResult, ValidationError> {
|
||||
@@ -1059,4 +1086,139 @@ mod tests {
|
||||
assert_matches!(v, ValidationResult::Invalid(InvalidCandidate::CodeHashMismatch));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compressed_code_works() {
|
||||
let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() };
|
||||
let pov = PoV { block_data: BlockData(vec![1; 32]) };
|
||||
let head_data = HeadData(vec![1, 1, 1]);
|
||||
|
||||
let raw_code = vec![2u8; 16];
|
||||
let validation_code = sp_maybe_compressed_blob::compress(
|
||||
&raw_code,
|
||||
VALIDATION_CODE_BOMB_LIMIT,
|
||||
)
|
||||
.map(ValidationCode)
|
||||
.unwrap();
|
||||
|
||||
let mut descriptor = CandidateDescriptor::default();
|
||||
descriptor.pov_hash = pov.hash();
|
||||
descriptor.para_head = head_data.hash();
|
||||
descriptor.validation_code_hash = validation_code.hash();
|
||||
collator_sign(&mut descriptor, Sr25519Keyring::Alice);
|
||||
|
||||
let validation_result = WasmValidationResult {
|
||||
head_data,
|
||||
new_validation_code: None,
|
||||
upward_messages: Vec::new(),
|
||||
horizontal_messages: Vec::new(),
|
||||
processed_downward_messages: 0,
|
||||
hrmp_watermark: 0,
|
||||
};
|
||||
|
||||
let v = validate_candidate_exhaustive::<MockValidationBackend, _>(
|
||||
MockValidationArg { result: Ok(validation_result) },
|
||||
validation_data,
|
||||
validation_code,
|
||||
descriptor,
|
||||
Arc::new(pov),
|
||||
TaskExecutor::new(),
|
||||
&Default::default(),
|
||||
);
|
||||
|
||||
assert_matches!(v, Ok(ValidationResult::Valid(_, _)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn code_decompression_failure_is_invalid() {
|
||||
let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() };
|
||||
let pov = PoV { block_data: BlockData(vec![1; 32]) };
|
||||
let head_data = HeadData(vec![1, 1, 1]);
|
||||
|
||||
let raw_code = vec![2u8; VALIDATION_CODE_BOMB_LIMIT + 1];
|
||||
let validation_code = sp_maybe_compressed_blob::compress(
|
||||
&raw_code,
|
||||
VALIDATION_CODE_BOMB_LIMIT + 1,
|
||||
)
|
||||
.map(ValidationCode)
|
||||
.unwrap();
|
||||
|
||||
let mut descriptor = CandidateDescriptor::default();
|
||||
descriptor.pov_hash = pov.hash();
|
||||
descriptor.para_head = head_data.hash();
|
||||
descriptor.validation_code_hash = validation_code.hash();
|
||||
collator_sign(&mut descriptor, Sr25519Keyring::Alice);
|
||||
|
||||
let validation_result = WasmValidationResult {
|
||||
head_data,
|
||||
new_validation_code: None,
|
||||
upward_messages: Vec::new(),
|
||||
horizontal_messages: Vec::new(),
|
||||
processed_downward_messages: 0,
|
||||
hrmp_watermark: 0,
|
||||
};
|
||||
|
||||
let v = validate_candidate_exhaustive::<MockValidationBackend, _>(
|
||||
MockValidationArg { result: Ok(validation_result) },
|
||||
validation_data,
|
||||
validation_code,
|
||||
descriptor,
|
||||
Arc::new(pov),
|
||||
TaskExecutor::new(),
|
||||
&Default::default(),
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
v,
|
||||
Ok(ValidationResult::Invalid(InvalidCandidate::CodeDecompressionFailure))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pov_decompression_failure_is_invalid() {
|
||||
let validation_data = PersistedValidationData {
|
||||
max_pov_size: POV_BOMB_LIMIT as u32,
|
||||
..Default::default()
|
||||
};
|
||||
let head_data = HeadData(vec![1, 1, 1]);
|
||||
|
||||
let raw_block_data = vec![2u8; POV_BOMB_LIMIT + 1];
|
||||
let pov = sp_maybe_compressed_blob::compress(
|
||||
&raw_block_data,
|
||||
POV_BOMB_LIMIT + 1,
|
||||
)
|
||||
.map(|raw| PoV { block_data: BlockData(raw) })
|
||||
.unwrap();
|
||||
|
||||
let validation_code = ValidationCode(vec![2; 16]);
|
||||
|
||||
let mut descriptor = CandidateDescriptor::default();
|
||||
descriptor.pov_hash = pov.hash();
|
||||
descriptor.para_head = head_data.hash();
|
||||
descriptor.validation_code_hash = validation_code.hash();
|
||||
collator_sign(&mut descriptor, Sr25519Keyring::Alice);
|
||||
|
||||
let validation_result = WasmValidationResult {
|
||||
head_data,
|
||||
new_validation_code: None,
|
||||
upward_messages: Vec::new(),
|
||||
horizontal_messages: Vec::new(),
|
||||
processed_downward_messages: 0,
|
||||
hrmp_watermark: 0,
|
||||
};
|
||||
|
||||
let v = validate_candidate_exhaustive::<MockValidationBackend, _>(
|
||||
MockValidationArg { result: Ok(validation_result) },
|
||||
validation_data,
|
||||
validation_code,
|
||||
descriptor,
|
||||
Arc::new(pov),
|
||||
TaskExecutor::new(),
|
||||
&Default::default(),
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
v,
|
||||
Ok(ValidationResult::Invalid(InvalidCandidate::PoVDecompressionFailure))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user