mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 19:51:05 +00:00
backing: Remove redundant erasure encoding (#7469)
* Remove redundant erasure encoding Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Review feedback Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fix comments Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> --------- Signed-off-by: Andrei Sandu <andrei-mihail@parity.io>
This commit is contained in:
@@ -20,6 +20,7 @@ polkadot-overseer = { path = "../../overseer" }
|
||||
polkadot-primitives = { path = "../../../primitives" }
|
||||
polkadot-node-primitives = { path = "../../primitives" }
|
||||
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
polkadot-node-jaeger = { path = "../../jaeger" }
|
||||
|
||||
[dev-dependencies]
|
||||
log = "0.4.17"
|
||||
|
||||
@@ -39,10 +39,11 @@ use polkadot_node_subsystem_util::database::{DBTransaction, Database};
|
||||
use sp_consensus::SyncOracle;
|
||||
|
||||
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
|
||||
use polkadot_node_jaeger as jaeger;
|
||||
use polkadot_node_primitives::{AvailableData, ErasureChunk};
|
||||
use polkadot_node_subsystem::{
|
||||
errors::{ChainApiError, RuntimeApiError},
|
||||
messages::{AvailabilityStoreMessage, ChainApiMessage},
|
||||
messages::{AvailabilityStoreMessage, ChainApiMessage, StoreAvailableDataError},
|
||||
overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError,
|
||||
};
|
||||
use polkadot_node_subsystem_util as util;
|
||||
@@ -372,6 +373,9 @@ pub enum Error {
|
||||
|
||||
#[error("Custom databases are not supported")]
|
||||
CustomDatabase,
|
||||
|
||||
#[error("Erasure root does not match expected one")]
|
||||
InvalidErasureRoot,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
@@ -1184,21 +1188,34 @@ fn process_message(
|
||||
candidate_hash,
|
||||
n_validators,
|
||||
available_data,
|
||||
expected_erasure_root,
|
||||
tx,
|
||||
} => {
|
||||
subsystem.metrics.on_chunks_received(n_validators as _);
|
||||
|
||||
let _timer = subsystem.metrics.time_store_available_data();
|
||||
|
||||
let res =
|
||||
store_available_data(&subsystem, candidate_hash, n_validators as _, available_data);
|
||||
let res = store_available_data(
|
||||
&subsystem,
|
||||
candidate_hash,
|
||||
n_validators as _,
|
||||
available_data,
|
||||
expected_erasure_root,
|
||||
);
|
||||
|
||||
match res {
|
||||
Ok(()) => {
|
||||
let _ = tx.send(Ok(()));
|
||||
},
|
||||
Err(Error::InvalidErasureRoot) => {
|
||||
let _ = tx.send(Err(StoreAvailableDataError::InvalidErasureRoot));
|
||||
return Err(Error::InvalidErasureRoot)
|
||||
},
|
||||
Err(e) => {
|
||||
let _ = tx.send(Err(()));
|
||||
// We do not bubble up internal errors to caller subsystems, instead the
|
||||
// tx channel is dropped and that error is caught by the caller subsystem.
|
||||
//
|
||||
// We bubble up the specific error here so `av-store` logs still tell what happend.
|
||||
return Err(e.into())
|
||||
},
|
||||
}
|
||||
@@ -1250,6 +1267,7 @@ fn store_available_data(
|
||||
candidate_hash: CandidateHash,
|
||||
n_validators: usize,
|
||||
available_data: AvailableData,
|
||||
expected_erasure_root: Hash,
|
||||
) -> Result<(), Error> {
|
||||
let mut tx = DBTransaction::new();
|
||||
|
||||
@@ -1276,9 +1294,21 @@ fn store_available_data(
|
||||
},
|
||||
};
|
||||
|
||||
let erasure_span = jaeger::Span::new(candidate_hash, "erasure-coding")
|
||||
.with_candidate(candidate_hash)
|
||||
.with_pov(&available_data.pov);
|
||||
|
||||
// Important note: This check below is critical for consensus and the `backing` subsystem relies on it to
|
||||
// ensure candidate validity.
|
||||
let chunks = erasure::obtain_chunks_v1(n_validators, &available_data)?;
|
||||
let branches = erasure::branches(chunks.as_ref());
|
||||
|
||||
if branches.root() != expected_erasure_root {
|
||||
return Err(Error::InvalidErasureRoot)
|
||||
}
|
||||
|
||||
drop(erasure_span);
|
||||
|
||||
let erasure_chunks = chunks.iter().zip(branches.map(|(proof, _)| proof)).enumerate().map(
|
||||
|(index, (chunk, proof))| ErasureChunk {
|
||||
chunk: chunk.clone(),
|
||||
|
||||
@@ -415,6 +415,45 @@ fn query_chunk_checks_meta() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn store_available_data_erasure_mismatch() {
|
||||
let store = test_store();
|
||||
let test_state = TestState::default();
|
||||
test_harness(test_state.clone(), store.clone(), |mut virtual_overseer| async move {
|
||||
let candidate_hash = CandidateHash(Hash::repeat_byte(1));
|
||||
let validator_index = ValidatorIndex(5);
|
||||
let n_validators = 10;
|
||||
|
||||
let pov = PoV { block_data: BlockData(vec![4, 5, 6]) };
|
||||
|
||||
let available_data = AvailableData {
|
||||
pov: Arc::new(pov),
|
||||
validation_data: test_state.persisted_validation_data.clone(),
|
||||
};
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
let block_msg = AvailabilityStoreMessage::StoreAvailableData {
|
||||
candidate_hash,
|
||||
n_validators,
|
||||
available_data: available_data.clone(),
|
||||
tx,
|
||||
// A dummy erasure root should lead to failure.
|
||||
expected_erasure_root: Hash::default(),
|
||||
};
|
||||
|
||||
virtual_overseer.send(FromOrchestra::Communication { msg: block_msg }).await;
|
||||
assert_eq!(rx.await.unwrap(), Err(StoreAvailableDataError::InvalidErasureRoot));
|
||||
|
||||
assert!(query_available_data(&mut virtual_overseer, candidate_hash).await.is_none());
|
||||
|
||||
assert!(query_chunk(&mut virtual_overseer, candidate_hash, validator_index)
|
||||
.await
|
||||
.is_none());
|
||||
|
||||
virtual_overseer
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn store_block_works() {
|
||||
let store = test_store();
|
||||
@@ -430,13 +469,17 @@ fn store_block_works() {
|
||||
pov: Arc::new(pov),
|
||||
validation_data: test_state.persisted_validation_data.clone(),
|
||||
};
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
let chunks = erasure::obtain_chunks_v1(10, &available_data).unwrap();
|
||||
let mut branches = erasure::branches(chunks.as_ref());
|
||||
|
||||
let block_msg = AvailabilityStoreMessage::StoreAvailableData {
|
||||
candidate_hash,
|
||||
n_validators,
|
||||
available_data: available_data.clone(),
|
||||
tx,
|
||||
expected_erasure_root: branches.root(),
|
||||
};
|
||||
|
||||
virtual_overseer.send(FromOrchestra::Communication { msg: block_msg }).await;
|
||||
@@ -449,10 +492,6 @@ fn store_block_works() {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let chunks = erasure::obtain_chunks_v1(10, &available_data).unwrap();
|
||||
|
||||
let mut branches = erasure::branches(chunks.as_ref());
|
||||
|
||||
let branch = branches.nth(5).unwrap();
|
||||
let expected_chunk = ErasureChunk {
|
||||
chunk: branch.1.to_vec(),
|
||||
@@ -483,6 +522,7 @@ fn store_pov_and_query_chunk_works() {
|
||||
|
||||
let chunks_expected =
|
||||
erasure::obtain_chunks_v1(n_validators as _, &available_data).unwrap();
|
||||
let branches = erasure::branches(chunks_expected.as_ref());
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let block_msg = AvailabilityStoreMessage::StoreAvailableData {
|
||||
@@ -490,6 +530,7 @@ fn store_pov_and_query_chunk_works() {
|
||||
n_validators,
|
||||
available_data,
|
||||
tx,
|
||||
expected_erasure_root: branches.root(),
|
||||
};
|
||||
|
||||
virtual_overseer.send(FromOrchestra::Communication { msg: block_msg }).await;
|
||||
@@ -530,12 +571,16 @@ fn query_all_chunks_works() {
|
||||
};
|
||||
|
||||
{
|
||||
let chunks_expected =
|
||||
erasure::obtain_chunks_v1(n_validators as _, &available_data).unwrap();
|
||||
let branches = erasure::branches(chunks_expected.as_ref());
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let block_msg = AvailabilityStoreMessage::StoreAvailableData {
|
||||
candidate_hash: candidate_hash_1,
|
||||
n_validators,
|
||||
available_data,
|
||||
tx,
|
||||
expected_erasure_root: branches.root(),
|
||||
};
|
||||
|
||||
virtual_overseer.send(FromOrchestra::Communication { msg: block_msg }).await;
|
||||
@@ -619,11 +664,15 @@ fn stored_but_not_included_data_is_pruned() {
|
||||
};
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let chunks = erasure::obtain_chunks_v1(n_validators as _, &available_data).unwrap();
|
||||
let branches = erasure::branches(chunks.as_ref());
|
||||
|
||||
let block_msg = AvailabilityStoreMessage::StoreAvailableData {
|
||||
candidate_hash,
|
||||
n_validators,
|
||||
available_data: available_data.clone(),
|
||||
tx,
|
||||
expected_erasure_root: branches.root(),
|
||||
};
|
||||
|
||||
virtual_overseer.send(FromOrchestra::Communication { msg: block_msg }).await;
|
||||
@@ -670,12 +719,16 @@ fn stored_data_kept_until_finalized() {
|
||||
let parent = Hash::repeat_byte(2);
|
||||
let block_number = 10;
|
||||
|
||||
let chunks = erasure::obtain_chunks_v1(n_validators as _, &available_data).unwrap();
|
||||
let branches = erasure::branches(chunks.as_ref());
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let block_msg = AvailabilityStoreMessage::StoreAvailableData {
|
||||
candidate_hash,
|
||||
n_validators,
|
||||
available_data: available_data.clone(),
|
||||
tx,
|
||||
expected_erasure_root: branches.root(),
|
||||
};
|
||||
|
||||
virtual_overseer.send(FromOrchestra::Communication { msg: block_msg }).await;
|
||||
@@ -946,24 +999,32 @@ fn forkfullness_works() {
|
||||
validation_data: test_state.persisted_validation_data.clone(),
|
||||
};
|
||||
|
||||
let chunks = erasure::obtain_chunks_v1(n_validators as _, &available_data_1).unwrap();
|
||||
let branches = erasure::branches(chunks.as_ref());
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let msg = AvailabilityStoreMessage::StoreAvailableData {
|
||||
candidate_hash: candidate_1_hash,
|
||||
n_validators,
|
||||
available_data: available_data_1.clone(),
|
||||
tx,
|
||||
expected_erasure_root: branches.root(),
|
||||
};
|
||||
|
||||
virtual_overseer.send(FromOrchestra::Communication { msg }).await;
|
||||
|
||||
rx.await.unwrap().unwrap();
|
||||
|
||||
let chunks = erasure::obtain_chunks_v1(n_validators as _, &available_data_2).unwrap();
|
||||
let branches = erasure::branches(chunks.as_ref());
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let msg = AvailabilityStoreMessage::StoreAvailableData {
|
||||
candidate_hash: candidate_2_hash,
|
||||
n_validators,
|
||||
available_data: available_data_2.clone(),
|
||||
tx,
|
||||
expected_erasure_root: branches.root(),
|
||||
};
|
||||
|
||||
virtual_overseer.send(FromOrchestra::Communication { msg }).await;
|
||||
|
||||
Reference in New Issue
Block a user