Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!(types,rpc): Add share, row, merkle proofs and share.GetRange #375

Merged
merged 12 commits into from
Sep 19, 2024
Merged
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ celestia-rpc = { version = "0.4.0", path = "rpc", default-features = false }
celestia-types = { version = "0.4.0", path = "types", default-features = false }
libp2p = "0.54.0"
nmt-rs = "0.2.1"
celestia-tendermint = { version = "0.32.1", default-features = false }
celestia-tendermint-proto = "0.32.1"
celestia-tendermint = { version = "0.32.2", default-features = false }
celestia-tendermint-proto = "0.32.2"

[patch.crates-io]
# Uncomment to apply local changes
Expand Down
2 changes: 1 addition & 1 deletion rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ mod error;
mod header;
#[cfg(feature = "p2p")]
mod p2p;
mod share;
pub mod share;
mod state;

pub use crate::blob::BlobClient;
Expand Down
26 changes: 25 additions & 1 deletion rpc/src/share.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,37 @@
//! celestia-node rpc types and methods related to shares
//!
use celestia_types::nmt::Namespace;
use celestia_types::{ExtendedDataSquare, ExtendedHeader, NamespacedShares, Share};
use celestia_types::{
ExtendedDataSquare, ExtendedHeader, NamespacedShares, RawShare, Share, ShareProof,
};
use jsonrpsee::proc_macros::rpc;
use serde::{Deserialize, Serialize};

/// Response type for [`ShareClient::share_get_range`].
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct GetRangeResponse {
/// Shares contained in given range.
pub shares: Vec<RawShare>,
/// Proof of inclusion of the shares.
pub proof: ShareProof,
}

#[rpc(client)]
pub trait Share {
/// GetEDS gets the full EDS identified by the given root.
#[method(name = "share.GetEDS")]
async fn share_get_eds(&self, root: &ExtendedHeader) -> Result<ExtendedDataSquare, Error>;

/// GetRange gets a list of shares and their corresponding proof.
#[method(name = "share.GetRange")]
async fn share_get_range(
&self,
height: u64,
start: usize,
end: usize,
) -> Result<GetRangeResponse, Error>;

/// GetShare gets a Share by coordinates in EDS.
#[method(name = "share.GetShare")]
async fn share_get_share(
Expand Down
57 changes: 56 additions & 1 deletion rpc/tests/share.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use celestia_types::consts::appconsts::{
SHARE_INFO_BYTES,
};
use celestia_types::nmt::{Namespace, NamespacedSha2Hasher};
use celestia_types::Blob;
use celestia_types::{Blob, Share};

pub mod utils;

Expand Down Expand Up @@ -51,6 +51,61 @@ async fn get_shares_by_namespace() {
assert_eq!(&reconstructed_data[..seq_len as usize], &data[..]);
}

#[tokio::test]
async fn get_shares_range() {
let client = new_test_client(AuthLevel::Write).await.unwrap();
let namespace = random_ns();
let data = random_bytes(1024);
let blob = Blob::new(namespace, data.clone()).unwrap();
let commitment = blob.commitment;

let submitted_height = blob_submit(&client, &[blob]).await.unwrap();

let header = client.header_get_by_height(submitted_height).await.unwrap();
let blob_on_chain = client
.blob_get(submitted_height, namespace, commitment)
.await
.unwrap();
let index = blob_on_chain.index.unwrap();
let shares = blob_on_chain.to_shares().unwrap();

let shares_range = client
.share_get_range(
submitted_height,
index as usize,
index as usize + shares.len(),
)
.await
.unwrap();

shares_range.proof.verify(header.dah.hash()).unwrap();

for ((share, received), proven) in shares
.into_iter()
.zip(shares_range.shares.into_iter())
.zip(shares_range.proof.shares().iter())
{
assert_eq!(share, Share::try_from(received).unwrap());
assert_eq!(share.as_ref(), proven.as_ref());
}
}

#[tokio::test]
async fn get_shares_range_not_existing() {
let client = new_test_client(AuthLevel::Write).await.unwrap();
let header = client.header_network_head().await.unwrap();
let shares_in_block = header.dah.square_width().pow(2);

client
.share_get_range(
header.height().value(),
shares_in_block as usize - 2,
shares_in_block as usize + 2,
)
.await
.unwrap_err();
}

#[tokio::test]
async fn get_shares_by_namespace_wrong_ns() {
let client = new_test_client(AuthLevel::Write).await.unwrap();
Expand Down
Loading
Loading