Skip to content

Commit

Permalink
Add shwap data types
Browse files Browse the repository at this point in the history
  • Loading branch information
fl0rek committed Dec 21, 2023
1 parent 129272e commit 35cf252
Show file tree
Hide file tree
Showing 11 changed files with 490 additions and 10 deletions.
4 changes: 4 additions & 0 deletions proto/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ pub static CUSTOM_TYPE_ATTRIBUTES: &[(&str, &str)] = &[
(".share.eds.byzantine.pb.Share", SERIALIZED),
(".proof.pb.Proof", SERIALIZED),
(".share.p2p.shrex.nd.NamespaceRowResponse", SERIALIZED),
(".share.p2p.shwap.Axis", SERIALIZED),
(".share.p2p.shwap.Sample", SERIALIZED),
(".share.p2p.shwap.Data", SERIALIZED),
];

#[rustfmt::skip]
Expand Down Expand Up @@ -81,6 +84,7 @@ fn main() -> Result<()> {
"vendor/celestia/blob/v1/tx.proto",
"vendor/header/pb/extended_header.proto",
"vendor/share/p2p/shrexnd/pb/share.proto",
"vendor/share/p2p/shwap/pb/shwap.proto",
"vendor/share/eds/byzantine/pb/share.proto",
"vendor/cosmos/base/v1beta1/coin.proto",
"vendor/cosmos/base/abci/v1beta1/abci.proto",
Expand Down
32 changes: 32 additions & 0 deletions proto/vendor/share/p2p/shwap/pb/shwap.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
syntax = "proto3";

package share.p2p.shwap;
import "pb/proof.proto"; // celestiaorg/nmt/pb/proof.proto

enum AxisType {
Row = 0;
Col = 1;
}

message Axis {
bytes axis_id = 1;
repeated bytes axis_half = 2;
}

enum SampleType {
DataSample = 0;
ParitySample = 1;
}

message Sample {
bytes sample_id = 1;
SampleType sample_type = 2;
bytes sample_share = 3;
proof.pb.Proof sample_proof = 4;
}

message Data {
bytes data_id = 1;
repeated bytes data_shares = 2;
proof.pb.Proof data_proof = 3;
}
133 changes: 129 additions & 4 deletions types/src/axis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ use std::result::Result as StdResult;

use blockstore::block::CidError;
use bytes::{Buf, BufMut, BytesMut};
use celestia_proto::share::p2p::shwap::Axis as RawAxis;
use cid::CidGeneric;
use multihash::Multihash;
use nmt_rs::NamespaceMerkleHasher;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use tendermint_proto::Protobuf;

use crate::nmt::{NamespacedHashExt, HASH_SIZE};
use crate::DataAvailabilityHeader;
use crate::{Error, Result};
use crate::nmt::{NamespacedHashExt, NamespacedSha2Hasher, Nmt, HASH_SIZE};
use crate::{DataAvailabilityHeader, ExtendedDataSquare};
use crate::{Error, Result, Share};

const AXIS_ID_SIZE: usize = AxisId::size();
pub const AXIS_ID_MULTIHASH_CODE: u64 = 0x7811;
Expand Down Expand Up @@ -45,6 +49,86 @@ pub struct AxisId {
pub block_height: u64,
}

#[derive(Serialize, Deserialize, Clone)]
#[serde(try_from = "RawAxis", into = "RawAxis")]
pub struct Axis {
pub axis_id: AxisId,

pub shares: Vec<Share>,
}

impl Axis {
pub fn new(
axis_type: AxisType,
index: usize,
dah: &DataAvailabilityHeader,
eds: &ExtendedDataSquare,
block_height: u64,
) -> Result<Self> {
let square_len = dah.square_len();

let axis_id = AxisId::new(axis_type, index, dah, block_height)?;
let mut shares = eds.axis(axis_type, index, square_len);
shares.truncate(square_len / 2);

Ok(Axis { axis_id, shares })
}

pub fn validate(&self) -> Result<()> {
let mut tree = Nmt::with_hasher(NamespacedSha2Hasher::with_ignore_max_ns(true));

for s in &self.shares {
tree.push_leaf(s.data(), *s.namespace())
.map_err(Error::Nmt)?;
}

//TODO: only original data shares are sent over the wire, we need leopard codec to
//re-compute parity shares
/*
let parity_shares : Vec<Share> = unimplemented!();
for s in parity_shares {
tree.push_leaf(s.data(), *s.namespace())
.map_err(Error::Nmt)?;
}
*/

if self.axis_id.hash != tree.root().hash() {
return Err(Error::RootMismatch);
}

unimplemented!("unable to compute parity shares")
}
}

impl Protobuf<RawAxis> for Axis {}

impl TryFrom<RawAxis> for Axis {
type Error = Error;

fn try_from(axis: RawAxis) -> Result<Axis, Self::Error> {
let axis_id = AxisId::decode(&axis.axis_id)?;
let shares = axis
.axis_half
.into_iter()
.map(|s| Share::from_raw(&s))
.collect::<Result<Vec<_>>>()?;

Ok(Axis { axis_id, shares })
}
}

impl From<Axis> for RawAxis {
fn from(axis: Axis) -> RawAxis {
let mut axis_id_bytes = BytesMut::new();
axis.axis_id.encode(&mut axis_id_bytes);

RawAxis {
axis_id: axis_id_bytes.to_vec(),
axis_half: axis.shares.into_iter().map(|s| s.data.to_vec()).collect(),
}
}
}

impl AxisId {
/// Create new axis for the particular data square
pub fn new(
Expand Down Expand Up @@ -156,7 +240,8 @@ impl TryFrom<AxisId> for CidGeneric<AXIS_ID_SIZE> {
#[cfg(test)]
mod tests {
use super::*;
use crate::nmt::NamespacedHash;
use crate::consts::appconsts::SHARE_SIZE;
use crate::nmt::{Namespace, NamespacedHash, NS_SIZE};

#[test]
fn axis_type_serialization() {
Expand Down Expand Up @@ -307,4 +392,44 @@ mod tests {
let axis_err = AxisId::try_from(cid).unwrap_err();
assert_eq!(axis_err, CidError::InvalidCidCodec(1234));
}

#[test]
fn decode_axis_bytes() {
let bytes = include_bytes!("../test_data/shwap_samples/axis.data");
let axis = Axis::decode(&bytes[..]).unwrap();

/*
msg.axis_id.axis_type = AxisType::Col;
msg.axis_id.index = 64;
msg.axis_id.hash = [0xEF; HASH_SIZE];
msg.axis_id.block_height = 255;
let mut i = 0;
for share in &mut msg.shares {
let ns = Namespace::new_v0(&[i]).unwrap();
let data = [0; crate::consts::appconsts::SHARE_SIZE];
share.data[..].copy_from_slice(&data);
share.data[..NS_SIZE].copy_from_slice(ns.as_bytes());
println!("{i} {:?}", share.namespace());
i += 1;
}
let mut file = std::fs::File::create("axis.data2").unwrap();
let bytes = msg.encode_vec().unwrap();
file.write_all(&bytes).unwrap();
*/
assert_eq!(axis.axis_id.axis_type, AxisType::Col);
assert_eq!(axis.axis_id.index, 64);
assert_eq!(axis.axis_id.hash, [0xEF; HASH_SIZE]);
assert_eq!(axis.axis_id.block_height, 255);

for (idx, share) in axis.shares.iter().enumerate() {
let ns = Namespace::new_v0(&[idx as u8]).unwrap();
assert_eq!(share.namespace(), ns);
let data = [0; SHARE_SIZE - NS_SIZE];
assert_eq!(share.data(), data);
}
}
}
9 changes: 9 additions & 0 deletions types/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ pub enum Error {
#[error(transparent)]
Multihash(#[from] cid::multihash::Error),

#[error(transparent)]
CidError(#[from] blockstore::block::CidError),

#[error("Missing header")]
MissingHeader,

Expand Down Expand Up @@ -73,6 +76,12 @@ pub enum Error {
#[error("Range proof verification failed: {0:?}")]
RangeProofError(nmt_rs::simple_merkle::error::RangeProofError),

#[error("Index {0} is out of range for NMT Range Proof")]
RangeProofIndexOutOfRange(i64),

#[error("Computed root doesn't match received one")]
RootMismatch,

#[error("Unexpected absent commit signature")]
UnexpectedAbsentSignature,

Expand Down
73 changes: 71 additions & 2 deletions types/src/namespaced_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ use std::io::Cursor;

use blockstore::block::CidError;
use bytes::{Buf, BufMut, BytesMut};
use celestia_proto::share::p2p::shwap::Data as RawNamespacedData;
use cid::CidGeneric;
use multihash::Multihash;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use tendermint_proto::Protobuf;

use crate::axis::AxisType;
use crate::nmt::{Namespace, NamespacedHashExt, HASH_SIZE, NS_SIZE};
use crate::{DataAvailabilityHeader, Error, Result};
use crate::nmt::{Namespace, NamespaceProof, NamespacedHashExt, HASH_SIZE, NS_SIZE};
use crate::{DataAvailabilityHeader, Error, Result, Share};

const NAMESPACED_DATA_ID_SIZE: usize = NamespacedDataId::size();
pub const NAMESPACED_DATA_ID_MULTIHASH_CODE: u64 = 0x7821;
Expand All @@ -23,6 +26,57 @@ pub struct NamespacedDataId {
pub block_height: u64,
}

#[derive(Serialize, Deserialize, Clone)]
#[serde(try_from = "RawNamespacedData", into = "RawNamespacedData")]
pub struct NamespacedData {
pub namespaced_data_id: NamespacedDataId,

pub proof: NamespaceProof,
pub shares: Vec<Share>,
}

impl NamespacedData {}

impl Protobuf<RawNamespacedData> for NamespacedData {}

impl TryFrom<RawNamespacedData> for NamespacedData {
type Error = Error;

fn try_from(namespaced_data: RawNamespacedData) -> Result<NamespacedData, Self::Error> {
let Some(proof) = namespaced_data.data_proof else {
return Err(Error::MissingProof);
};

let namespaced_data_id = NamespacedDataId::decode(&namespaced_data.data_id)?;
let shares = namespaced_data
.data_shares
.iter()
.map(|s| Share::from_raw(s))
.collect::<Result<_, _>>()?;

Ok(NamespacedData {
namespaced_data_id,
shares,
proof: proof.try_into()?,
})
}
}

impl From<NamespacedData> for RawNamespacedData {
fn from(namespaced_data: NamespacedData) -> RawNamespacedData {
let mut data_id_bytes = BytesMut::new();
namespaced_data
.namespaced_data_id
.encode(&mut data_id_bytes);

RawNamespacedData {
data_id: data_id_bytes.to_vec(),
data_shares: namespaced_data.shares.iter().map(|s| s.to_vec()).collect(),
data_proof: Some(namespaced_data.proof.into()),
}
}
}

impl NamespacedDataId {
/// Creates new NamespacedDataId for row and namespace, computes appropriate root hash
/// from provided DataAvailabilityHeader
Expand Down Expand Up @@ -208,4 +262,19 @@ mod tests {
let axis_err = NamespacedDataId::try_from(cid).unwrap_err();
assert_eq!(axis_err, CidError::InvalidCidCodec(4321));
}

#[test]
fn decode_data_bytes() {
let bytes = include_bytes!("../test_data/shwap_samples/namespaced_data.data");
let msg = NamespacedData::decode(&bytes[..]).unwrap();

let ns = Namespace::new_v0(&[93, 2, 248, 47, 108, 59, 195, 216, 222, 33]).unwrap();
assert_eq!(msg.namespaced_data_id.namespace, ns);
assert_eq!(msg.namespaced_data_id.row_index, 0);
assert_eq!(msg.namespaced_data_id.block_height, 1);

for s in msg.shares {
assert_eq!(s.namespace(), ns);
}
}
}
1 change: 1 addition & 0 deletions types/src/nmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub const NMT_ID_SIZE: usize = 2 * NS_SIZE + SHA256_HASH_SIZE;
pub type NamespacedSha2Hasher = nmt_rs::NamespacedSha2Hasher<NS_SIZE>;
pub type NamespacedHash = nmt_rs::NamespacedHash<NS_SIZE>;
pub type Nmt = nmt_rs::NamespaceMerkleTree<MemDb<NamespacedHash>, NamespacedSha2Hasher, NS_SIZE>;
pub type Proof = nmt_rs::simple_merkle::proof::Proof<crate::nmt::NamespacedSha2Hasher>;

pub struct NodePair(NamespacedHash, NamespacedHash);

Expand Down
Loading

0 comments on commit 35cf252

Please sign in to comment.