Skip to content

Commit

Permalink
feat: borsh serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
distractedm1nd committed Jul 25, 2024
1 parent 15b661a commit 8514da8
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 133 deletions.
48 changes: 45 additions & 3 deletions Cargo.lock

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

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ key_transparency = []

[dependencies]
axum = "0.6"
borsh = { version = "1.5.1", features = ["derive"] }
tower-http = { version = "0.4", features = ["cors"] }
utoipa = { version = "3.3", features = ["axum_extras"] }
utoipa-swagger-ui = { version = "3.1", features = ["axum"] }
Expand Down Expand Up @@ -55,7 +56,7 @@ clap = { version = "4.3.2", features = ["derive"] }
config = "0.14.0"
fs2 = "0.4.3"
thiserror = "1.0.62"
indexed-merkle-tree = "0.5.2"
indexed-merkle-tree = { path = "../indexed-merkle-tree" }
dotenvy = "0.15.7"
ahash = "0.8.7"
celestia-rpc = "0.2.0"
Expand All @@ -68,4 +69,4 @@ toml = "0.8.14"
dirs = "5.0.1"

[dev-dependencies]
serial_test = "3.1.1"
serial_test = "3.1.1"
26 changes: 11 additions & 15 deletions src/da/celestia.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::{
consts::CHANNEL_BUFFER_SIZE,
da::{DataAvailabilityLayer, EpochJson},
da::{DataAvailabilityLayer, FinalizedEpoch},
error::{DAResult, DataAvailabilityError, GeneralError},
};
use async_trait::async_trait;
use borsh::from_slice;
use celestia_rpc::{BlobClient, Client, HeaderClient};
use celestia_types::{blob::GasPrice, nmt::Namespace, Blob};
use std::{self, sync::Arc};
Expand All @@ -15,17 +16,12 @@ use tokio::{
task::spawn,
};

impl TryFrom<&Blob> for EpochJson {
impl TryFrom<&Blob> for FinalizedEpoch {
type Error = GeneralError;

fn try_from(value: &Blob) -> Result<Self, GeneralError> {
// convert blob data to utf8 string
let data_str = String::from_utf8(value.data.clone()).map_err(|e| {
GeneralError::EncodingError(format!("encoding blob data to utf8 string: {}", e))
})?;

serde_json::from_str(&data_str)
.map_err(|e| GeneralError::DecodingError(format!("epoch json: {}", e)))
from_slice::<Self>(&value.data)
.map_err(|e| GeneralError::DecodingError(format!("decoding blob: {}", e)))
}
}

Expand Down Expand Up @@ -102,13 +98,13 @@ impl DataAvailabilityLayer for CelestiaConnection {
}
}

async fn get(&self, height: u64) -> DAResult<Vec<EpochJson>> {
async fn get(&self, height: u64) -> DAResult<Vec<FinalizedEpoch>> {
trace!("searching for epoch on da layer at height {}", height);
match BlobClient::blob_get_all(&self.client, height, &[self.namespace_id]).await {
Ok(blobs) => {
let mut epochs = Vec::new();
for blob in blobs.iter() {
match EpochJson::try_from(blob) {
match FinalizedEpoch::try_from(blob) {
Ok(epoch_json) => epochs.push(epoch_json),
Err(_) => {
GeneralError::ParsingError(format!(
Expand All @@ -134,16 +130,16 @@ impl DataAvailabilityLayer for CelestiaConnection {
}
}

async fn submit(&self, epoch: &EpochJson) -> DAResult<u64> {
async fn submit(&self, epoch: &FinalizedEpoch) -> DAResult<u64> {
debug!("posting epoch {} to da layer", epoch.height);

let data = serde_json::to_string(&epoch).map_err(|e| {
let data = borsh::to_vec(&epoch).map_err(|e| {
DataAvailabilityError::GeneralError(GeneralError::ParsingError(format!(
"serializing epoch json: {}",
"serializing epoch: {}",
e
)))
})?;
let blob = Blob::new(self.namespace_id, data.into_bytes()).map_err(|e| {
let blob = Blob::new(self.namespace_id, data).map_err(|e| {
DataAvailabilityError::GeneralError(GeneralError::BlobCreationError(e.to_string()))
})?;
trace!("blob: {:?}", &blob);
Expand Down
31 changes: 19 additions & 12 deletions src/da/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{
io::{Read, Seek, Write},
};

use crate::da::{DataAvailabilityLayer, EpochJson};
use crate::da::{DataAvailabilityLayer, FinalizedEpoch};

/// The `NoopDataAvailabilityLayer` is a mock implementation of the `DataAvailabilityLayer` trait.
pub struct NoopDataAvailabilityLayer {}
Expand All @@ -23,11 +23,11 @@ impl DataAvailabilityLayer for NoopDataAvailabilityLayer {
Ok(0)
}

async fn get(&self, _: u64) -> DAResult<Vec<EpochJson>> {
async fn get(&self, _: u64) -> DAResult<Vec<FinalizedEpoch>> {
Ok(vec![])
}

async fn submit(&self, _: &EpochJson) -> DAResult<u64> {
async fn submit(&self, _: &FinalizedEpoch) -> DAResult<u64> {
Ok(0)
}

Expand Down Expand Up @@ -65,7 +65,7 @@ impl DataAvailabilityLayer for LocalDataAvailabilityLayer {
Ok(0) // header starts always at zero in test cases
}

async fn get(&self, height: u64) -> DAResult<Vec<EpochJson>> {
async fn get(&self, height: u64) -> DAResult<Vec<FinalizedEpoch>> {
let mut file = File::open("data.json").expect("Unable to open file");
let mut contents = String::new();
file.lock_exclusive().expect("Unable to lock file");
Expand All @@ -75,8 +75,11 @@ impl DataAvailabilityLayer for LocalDataAvailabilityLayer {
let data: Value = serde_json::from_str(&contents).expect("Invalid JSON format");

if let Some(epoch) = data.get(height.to_string()) {
// convert arbit. json value to EpochJson
let result_epoch: Result<EpochJson, _> = serde_json::from_value(epoch.clone());
let epoch_hex = epoch.as_str().expect("Epoch value is not a string");
let epoch_bytes = hex::decode(epoch_hex).expect("Invalid hex string");

let result_epoch: Result<FinalizedEpoch, _> = borsh::from_slice(&epoch_bytes);

file.unlock().expect("Unable to unlock file");
Ok(vec![result_epoch.expect("WRON FORMT")])
} else {
Expand All @@ -88,7 +91,7 @@ impl DataAvailabilityLayer for LocalDataAvailabilityLayer {
}
}

async fn submit(&self, epoch: &EpochJson) -> DAResult<u64> {
async fn submit(&self, epoch: &FinalizedEpoch) -> DAResult<u64> {
let mut file = OpenOptions::new()
.read(true)
.write(true)
Expand All @@ -112,7 +115,8 @@ impl DataAvailabilityLayer for LocalDataAvailabilityLayer {
};

// add new epoch to existing json-file data
data[epoch.height.to_string()] = json!(epoch);
data[epoch.height.to_string()] =
hex::encode(borsh::to_vec(&epoch).expect("Unable to serialize epoch")).into();

// Reset the file pointer to the beginning of the file
file.seek(std::io::SeekFrom::Start(0))
Expand Down Expand Up @@ -208,7 +212,7 @@ mod tests {
(proof.into(), params.vk.into())
}

fn verify_epoch_json(epoch: Vec<EpochJson>) {
fn verify_epoch_json(epoch: Vec<FinalizedEpoch>) {
for epoch_json in epoch {
let prev_commitment = epoch_json.prev_commitment;
let current_commitment = epoch_json.current_commitment;
Expand All @@ -218,7 +222,10 @@ mod tests {

match validate_epoch(&prev_commitment, &current_commitment, proof, verifying_key) {
Ok(_) => {
info!("\n\nvalidating epochs with commitments: [{}, {}]\n\n proof\n a: {},\n b: {},\n c: {}\n\n verifying key \n alpha_g1: {},\n beta_1: {},\n beta_2: {},\n delta_1: {},\n delta_2: {},\n gamma_2: {}\n", prev_commitment, current_commitment, &epoch_json.proof.a, &epoch_json.proof.b, &epoch_json.proof.c, &epoch_json.verifying_key.alpha_g1, &epoch_json.verifying_key.beta_g1, &epoch_json.verifying_key.beta_g2, &epoch_json.verifying_key.delta_g1, &epoch_json.verifying_key.delta_g2, &epoch_json.verifying_key.gamma_g2);
info!(
"epoch {}->{} validation successful",
prev_commitment, current_commitment
)
}
Err(err) => panic!("failed to validate epoch: {:?}", err),
}
Expand Down Expand Up @@ -254,7 +261,7 @@ mod tests {
);

sequencer_layer
.submit(&EpochJson {
.submit(&FinalizedEpoch {
height: 1,
prev_commitment,
current_commitment: tree.get_commitment().unwrap(),
Expand Down Expand Up @@ -286,7 +293,7 @@ mod tests {
vec![second_insert_zk_snark, third_insert_zk_snark],
);
sequencer_layer
.submit(&EpochJson {
.submit(&FinalizedEpoch {
height: 2,
prev_commitment,
current_commitment: tree.get_commitment().unwrap(),
Expand Down
19 changes: 10 additions & 9 deletions src/da/mod.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
use crate::{
error::{DAResult, PrismResult, GeneralError},
error::{DAResult, GeneralError, PrismResult},
utils::SignedContent,
zk_snark::{Bls12Proof, VerifyingKey},
};
use async_trait::async_trait;
use borsh::{BorshDeserialize, BorshSerialize};
use ed25519::Signature;
use indexed_merkle_tree::Hash;
use serde::{Deserialize, Serialize};
use std::{self, str::FromStr};

pub mod celestia;
pub mod mock;

#[derive(Serialize, Deserialize, Clone)]
pub struct EpochJson {
// FinalizedEpoch is the data structure that represents the finalized epoch data, and is posted to the DA layer.
#[derive(BorshSerialize, BorshDeserialize, Clone)]
pub struct FinalizedEpoch {
pub height: u64,
pub prev_commitment: Hash,
pub current_commitment: Hash,
Expand All @@ -22,7 +23,7 @@ pub struct EpochJson {
pub signature: Option<String>,
}

impl SignedContent for EpochJson {
impl SignedContent for FinalizedEpoch {
fn get_signature(&self) -> PrismResult<Signature> {
match &self.signature {
Some(signature) => Signature::from_str(signature)
Expand All @@ -31,10 +32,10 @@ impl SignedContent for EpochJson {
}
}

fn get_plaintext(&self) -> PrismResult<String> {
fn get_plaintext(&self) -> PrismResult<Vec<u8>> {
let mut copy = self.clone();
copy.signature = None;
serde_json::to_string(&copy).map_err(|e| GeneralError::EncodingError(e.to_string()).into())
borsh::to_vec(&copy).map_err(|e| GeneralError::EncodingError(e.to_string()).into())
}

fn get_public_key(&self) -> PrismResult<String> {
Expand All @@ -50,7 +51,7 @@ impl SignedContent for EpochJson {
pub trait DataAvailabilityLayer: Send + Sync {
async fn get_latest_height(&self) -> DAResult<u64>;
async fn initialize_sync_target(&self) -> DAResult<u64>;
async fn get(&self, height: u64) -> DAResult<Vec<EpochJson>>;
async fn submit(&self, epoch: &EpochJson) -> DAResult<u64>;
async fn get(&self, height: u64) -> DAResult<Vec<FinalizedEpoch>>;
async fn submit(&self, epoch: &FinalizedEpoch) -> DAResult<u64>;
async fn start(&self) -> DAResult<()>;
}
4 changes: 2 additions & 2 deletions src/node_types/lightclient.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
cfg::CelestiaConfig,
error::{DataAvailabilityError, PrismResult, GeneralError},
error::{DataAvailabilityError, GeneralError, PrismResult},
};
use async_trait::async_trait;
use std::{self, sync::Arc, time::Duration};
Expand Down Expand Up @@ -102,7 +102,7 @@ impl LightClient {
&epoch_json.clone(),
self.verifying_key.clone(),
) {
Ok(i) => trace!("valid signature for epoch {}", i),
Ok(_) => trace!("valid signature for epoch {}", epoch_json.height),
Err(e) => {
panic!("invalid signature in epoch {}: {:?}", i, e)
}
Expand Down
Loading

0 comments on commit 8514da8

Please sign in to comment.