Skip to content

Commit

Permalink
fix: row verification logic (#235)
Browse files Browse the repository at this point in the history
  • Loading branch information
zvolin authored Mar 1, 2024
1 parent 67fe9ec commit e57fe64
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 60 deletions.
95 changes: 35 additions & 60 deletions types/src/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ use multihash::Multihash;
use nmt_rs::NamespaceMerkleHasher;
use serde::{Deserialize, Serialize};

use crate::consts::appconsts::SHARE_SIZE;
use crate::nmt::NS_SIZE;
use crate::nmt::{Namespace, NamespacedSha2Hasher, Nmt};
use crate::rsmt2d::ExtendedDataSquare;
use crate::rsmt2d::{is_ods_square, ExtendedDataSquare};
use crate::{DataAvailabilityHeader, Error, Result};

/// The size of the [`RowId`] hash in `multihash`.
Expand Down Expand Up @@ -62,22 +63,20 @@ impl Row {
/// verify the row against roots from DAH
pub fn verify(&self, dah: &DataAvailabilityHeader) -> Result<()> {
let square_len = self.shares.len();

let (data_shares, parity_shares) = self.shares.split_at(square_len / 2);
let row = self.row_id.index as usize;

let mut tree = Nmt::with_hasher(NamespacedSha2Hasher::with_ignore_max_ns(true));
for s in data_shares {
let ns = Namespace::from_raw(&s[..NS_SIZE])?;
for (col, s) in self.shares.iter().enumerate() {
let ns = if is_ods_square(row, col, square_len) {
Namespace::from_raw(&s[..NS_SIZE])?
} else {
Namespace::PARITY_SHARE
};
tree.push_leaf(s, *ns).map_err(Error::Nmt)?;
}
for s in parity_shares {
tree.push_leaf(s, *Namespace::PARITY_SHARE)
.map_err(Error::Nmt)?;
}

let index = self.row_id.index.into();
let Some(root) = dah.row_root(index) else {
return Err(Error::EdsIndexOutOfRange(index));
let Some(root) = dah.row_root(row) else {
return Err(Error::EdsIndexOutOfRange(row));
};

if tree.root().hash() != root.hash() {
Expand All @@ -95,16 +94,14 @@ impl TryFrom<RawRow> for Row {

fn try_from(row: RawRow) -> Result<Row, Self::Error> {
let row_id = RowId::decode(&row.row_id)?;
let shares = row.row_half;
let mut shares = row.row_half;
let data_shares = shares.len();

// TODO: only original data shares are sent over the wire, we need leopard codec to
// re-compute parity shares
//
// somehow_generate_parity_shares(&mut shares);
shares.resize(shares.len() * 2, vec![0; SHARE_SIZE]);

let _ = Row { row_id, shares };
leopard_codec::encode(&mut shares, data_shares)?;

unimplemented!()
Ok(Row { row_id, shares })
}
}

Expand Down Expand Up @@ -215,6 +212,7 @@ impl From<RowId> for CidGeneric<ROW_ID_SIZE> {
mod tests {
use super::*;
use crate::consts::appconsts::SHARE_SIZE;
use crate::test_utils::generate_eds;

#[test]
fn round_trip_test() {
Expand Down Expand Up @@ -317,49 +315,26 @@ mod tests {
assert_eq!(row_err, CidError::InvalidCidCodec(1234));
}

#[test]
// TODO:
// fully testing protobuf deserialisation requires leopard codec, to generate parity shares.
// By asserting that we've reached `unimplemented!`, we rely on implementation detail to
// check whether protobuf, RowId and Share deserialisations were successful (but can't check
// the actual data)
// Once we have leopard codec, remove `should_panic` to enable full test functionality
#[should_panic(expected = "not implemented")]
fn decode_row_bytes() {
let bytes = include_bytes!("../test_data/shwap_samples/row.data");
let mut row = Row::decode(&bytes[..]).unwrap();

row.row_id.index = 64;
row.row_id.block_height = 255;

assert_eq!(row.row_id.index, 64);
assert_eq!(row.row_id.block_height, 255);

for (idx, share) in row.shares.iter().enumerate() {
let expected_ns = Namespace::new_v0(&[idx as u8]).unwrap();
let ns = Namespace::from_raw(&share[..NS_SIZE]).unwrap();
assert_eq!(ns, expected_ns);
let data = [0; SHARE_SIZE - NS_SIZE];
assert_eq!(share[NS_SIZE..], data);
}
}

#[test]
fn test_validate() {
let eds_json = include_str!("../test_data/shwap_samples/eds.json");
let eds: ExtendedDataSquare = serde_json::from_str(eds_json).unwrap();
let dah_json = include_str!("../test_data/shwap_samples/dah.json");
let dah: DataAvailabilityHeader = serde_json::from_str(dah_json).unwrap();

let index = 1;
let row = Row {
row_id: RowId {
block_height: 1,
index,
},
shares: eds.row(index.into()).unwrap(),
};
for _ in 0..10 {
let eds = generate_eds(2 << (rand::random::<usize>() % 8));
let dah = DataAvailabilityHeader::from_eds(&eds);

let index = rand::random::<u16>() % eds.square_len() as u16;

row.verify(&dah).unwrap();
let row = Row {
row_id: RowId {
block_height: 1,
index,
},
shares: eds.row(index.into()).unwrap(),
};

let encoded = row.encode_vec().unwrap();
let decoded = Row::decode(encoded.as_ref()).unwrap();

decoded.verify(&dah).unwrap();
}
}
}
Binary file removed types/test_data/shwap_samples/row.data
Binary file not shown.

0 comments on commit e57fe64

Please sign in to comment.