Add tests and modify as_vec implementation (#3715)

* Add tests and modify as_vec implementation

* Address feedback

* fix typo in test
This commit is contained in:
Lldenaurois
2021-09-06 13:24:04 +02:00
committed by GitHub
parent bbf09c96aa
commit 2bd84151ed
6 changed files with 39 additions and 25 deletions
+1
View File
@@ -6297,6 +6297,7 @@ dependencies = [
"bounded-vec", "bounded-vec",
"futures 0.3.17", "futures 0.3.17",
"parity-scale-codec", "parity-scale-codec",
"polkadot-erasure-coding",
"polkadot-parachain", "polkadot-parachain",
"polkadot-primitives", "polkadot-primitives",
"schnorrkel", "schnorrkel",
+26 -14
View File
@@ -298,10 +298,10 @@ where
/// Verify a merkle branch, yielding the chunk hash meant to be present at that /// Verify a merkle branch, yielding the chunk hash meant to be present at that
/// index. /// index.
pub fn branch_hash(root: &H256, branch_nodes: &[Vec<u8>], index: usize) -> Result<H256, Error> { pub fn branch_hash(root: &H256, branch_nodes: &Proof, index: usize) -> Result<H256, Error> {
let mut trie_storage: MemoryDB<Blake2Hasher> = MemoryDB::default(); let mut trie_storage: MemoryDB<Blake2Hasher> = MemoryDB::default();
for node in branch_nodes.iter() { for node in branch_nodes.iter() {
(&mut trie_storage as &mut trie::HashDB<_>).insert(EMPTY_PREFIX, node.as_slice()); (&mut trie_storage as &mut trie::HashDB<_>).insert(EMPTY_PREFIX, node);
} }
let trie = TrieDB::new(&trie_storage, &root).map_err(|_| Error::InvalidBranchProof)?; let trie = TrieDB::new(&trie_storage, &root).map_err(|_| Error::InvalidBranchProof)?;
@@ -372,6 +372,10 @@ mod tests {
use super::*; use super::*;
use polkadot_primitives::v0::{AvailableData, BlockData, PoVBlock}; use polkadot_primitives::v0::{AvailableData, BlockData, PoVBlock};
// In order to adequately compute the number of entries in the Merkle
// trie, we must account for the fixed 16-ary trie structure.
const KEY_INDEX_NIBBLE_SIZE: usize = 4;
#[test] #[test]
fn field_order_is_right_size() { fn field_order_is_right_size() {
assert_eq!(MAX_VALIDATORS, 65536); assert_eq!(MAX_VALIDATORS, 65536);
@@ -404,28 +408,36 @@ mod tests {
assert_eq!(reconstructed, Err(Error::NotEnoughValidators)); assert_eq!(reconstructed, Err(Error::NotEnoughValidators));
} }
#[test] fn generate_trie_and_generate_proofs(magnitude: u32) {
fn construct_valid_branches() { let n_validators = 2_u32.pow(magnitude) as usize;
let pov_block = PoVBlock { block_data: BlockData(vec![2; 256]) }; let pov_block =
PoVBlock { block_data: BlockData(vec![2; n_validators / KEY_INDEX_NIBBLE_SIZE]) };
let available_data = AvailableData { pov_block, omitted_validation: Default::default() }; let available_data = AvailableData { pov_block, omitted_validation: Default::default() };
let chunks = obtain_chunks(10, &available_data).unwrap(); let chunks = obtain_chunks(magnitude as usize, &available_data).unwrap();
assert_eq!(chunks.len(), 10); assert_eq!(chunks.len() as u32, magnitude);
let branches = branches(chunks.as_ref()); let branches = branches(chunks.as_ref());
let root = branches.root(); let root = branches.root();
let proofs: Vec<_> = branches.map(|(proof, _)| proof).collect(); let proofs: Vec<_> = branches.map(|(proof, _)| proof).collect();
assert_eq!(proofs.len() as u32, magnitude);
assert_eq!(proofs.len(), 10);
for (i, proof) in proofs.into_iter().enumerate() { for (i, proof) in proofs.into_iter().enumerate() {
assert_eq!( let encode = Encode::encode(&proof);
branch_hash(&root, &proof.as_vec(), i).unwrap(), let decode = Decode::decode(&mut &encode[..]).unwrap();
BlakeTwo256::hash(&chunks[i]) assert_eq!(proof, decode);
); assert_eq!(encode, Encode::encode(&decode));
assert_eq!(branch_hash(&root, &proof, i).unwrap(), BlakeTwo256::hash(&chunks[i]));
}
}
#[test]
fn roundtrip_proof_encoding() {
for i in 2..16 {
generate_trie_and_generate_proofs(i);
} }
} }
} }
@@ -363,7 +363,7 @@ impl RunningTask {
fn validate_chunk(&self, validator: &AuthorityDiscoveryId, chunk: &ErasureChunk) -> bool { fn validate_chunk(&self, validator: &AuthorityDiscoveryId, chunk: &ErasureChunk) -> bool {
let anticipated_hash = let anticipated_hash =
match branch_hash(&self.erasure_root, &chunk.proof_as_vec(), chunk.index.0 as usize) { match branch_hash(&self.erasure_root, chunk.proof(), chunk.index.0 as usize) {
Ok(hash) => hash, Ok(hash) => hash,
Err(e) => { Err(e) => {
tracing::warn!( tracing::warn!(
@@ -363,11 +363,9 @@ impl RequestChunksPhase {
let validator_index = chunk.index; let validator_index = chunk.index;
if let Ok(anticipated_hash) = branch_hash( if let Ok(anticipated_hash) =
&params.erasure_root, branch_hash(&params.erasure_root, chunk.proof(), chunk.index.0 as usize)
&chunk.proof_as_vec(), {
chunk.index.0 as usize,
) {
let erasure_chunk_hash = BlakeTwo256::hash(&chunk.chunk); let erasure_chunk_hash = BlakeTwo256::hash(&chunk.chunk);
if erasure_chunk_hash != anticipated_hash { if erasure_chunk_hash != anticipated_hash {
+3
View File
@@ -23,3 +23,6 @@ serde = { version = "1.0.130", features = ["derive"] }
[target.'cfg(not(target_os = "unknown"))'.dependencies] [target.'cfg(not(target_os = "unknown"))'.dependencies]
zstd = "0.6.0" zstd = "0.6.0"
[dev-dependencies]
polkadot-erasure-coding = { path = "../../erasure-coding" }
+5 -5
View File
@@ -301,8 +301,8 @@ pub struct Proof(BoundedVec<BoundedVec<u8, 1, MERKLE_NODE_MAX_SIZE>, 1, MERKLE_P
impl Proof { impl Proof {
/// This function allows to convert back to the standard nested Vec format /// This function allows to convert back to the standard nested Vec format
pub fn as_vec(&self) -> Vec<Vec<u8>> { pub fn iter(&self) -> impl Iterator<Item = &[u8]> {
self.0.as_vec().iter().map(|v| v.as_vec().clone()).collect() self.0.iter().map(|v| v.as_slice())
} }
/// Construct an invalid dummy proof /// Construct an invalid dummy proof
@@ -365,7 +365,7 @@ impl Encode for Proof {
} }
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R { fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
let temp = self.as_vec(); let temp = self.0.iter().map(|v| v.as_vec()).collect::<Vec<_>>();
temp.using_encoded(f) temp.using_encoded(f)
} }
} }
@@ -404,8 +404,8 @@ pub struct ErasureChunk {
impl ErasureChunk { impl ErasureChunk {
/// Convert bounded Vec Proof to regular Vec<Vec<u8>> /// Convert bounded Vec Proof to regular Vec<Vec<u8>>
pub fn proof_as_vec(&self) -> Vec<Vec<u8>> { pub fn proof(&self) -> &Proof {
self.proof.as_vec() &self.proof
} }
} }