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

[saya] Publish proof to Celestia #2053

Merged
merged 3 commits into from
Jun 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions Cargo.lock

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

5 changes: 5 additions & 0 deletions bin/saya/src/args/data_availability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
#[arg(help = "The namespace used to submit blobs.")]
#[arg(requires = "celestia_node_url")]
pub celestia_namespace: Option<String>,

#[arg(long)]
#[arg(help = "Whether to include a proof to the publish DA.")]
#[arg(default_value_t = false)]
pub skip_publishing_proof: bool,

Check warning on line 50 in bin/saya/src/args/data_availability.rs

View check run for this annotation

Codecov / codecov/patch

bin/saya/src/args/data_availability.rs#L49-L50

Added lines #L49 - L50 were not covered by tests
}

// -- Clap enums impls --
Expand Down
5 changes: 5 additions & 0 deletions bin/saya/src/args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@
type Error = Box<dyn std::error::Error>;

fn try_from(args: SayaArgs) -> Result<Self, Self::Error> {
let skip_publishing_proof = args.data_availability.celestia.skip_publishing_proof;

if let Some(config_file) = args.config_file {
let file = File::open(config_file).map_err(|_| "Failed to open config file")?;
let reader = BufReader::new(file);
Expand Down Expand Up @@ -147,6 +149,7 @@
data_availability: da_config,
world_address: args.proof.world_address,
fact_registry_address: args.proof.fact_registry_address,
skip_publishing_proof,

Check warning on line 152 in bin/saya/src/args/mod.rs

View check run for this annotation

Codecov / codecov/patch

bin/saya/src/args/mod.rs#L152

Added line #L152 was not covered by tests
})
}
}
Expand Down Expand Up @@ -181,6 +184,7 @@
celestia_node_url: None,
celestia_node_auth_token: None,
celestia_namespace: None,
skip_publishing_proof: true,
},
},
proof: ProofOptions {
Expand All @@ -199,6 +203,7 @@
"0xd0fa91f4949e9a777ebec071ca3ca6acc1f5cd6c6827f123b798f94e73425027"
);
assert!(!config.store_proofs);
assert!(config.skip_publishing_proof);
assert_eq!(config.start_block, 0);
if let Some(DataAvailabilityConfig::Celestia(celestia_config)) = config.data_availability {
assert_eq!(celestia_config.node_url.as_str(), "http://localhost:26657/");
Expand Down
1 change: 1 addition & 0 deletions bin/saya/src/args/test_saya_config_file.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"world_address": "0x332b8ff41b1b026991fa9b7f0ec352909f8bc33416b65a80527edc988a9b082",
"fact_registry_address": "0x217746a5f74c2e5b6fa92c97e902d8cd78b1fabf1e8081c4aa0d2fe159bc0eb",
"start_block": 0,
"skip_publishing_proof": true,
"data_availability": {
"Celestia": {
"node_url": "http://localhost:26657",
Expand Down
4 changes: 2 additions & 2 deletions crates/saya/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ tracing.workspace = true
url.workspace = true

# TODO: use features for each possible DA.
celestia-rpc = "0.1.1"
celestia-types = "0.1.1"
celestia-rpc = "0.2.0"
celestia-types = "0.2.0"

cairo-felt = "0.9.1"
num-bigint = "0.4.4"
Expand Down
22 changes: 20 additions & 2 deletions crates/saya/core/src/data_availability/celestia/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use async_trait::async_trait;
use celestia_rpc::{BlobClient, Client};
use celestia_types::blob::SubmitOptions;
use celestia_types::blob::GasPrice;
use celestia_types::nmt::Namespace;
use celestia_types::Blob;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -65,7 +65,25 @@
// TODO: we may want to use `blob_get` to ensure the state diff has been published
// correctly.
self.client
.blob_submit(&[blob], SubmitOptions::default())
.blob_submit(&[blob], GasPrice::default())
.await
.map_err(|e| Error::Client(format!("Celestia RPC error: {e}")))
}

Check warning on line 71 in crates/saya/core/src/data_availability/celestia/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/saya/core/src/data_availability/celestia/mod.rs#L68-L71

Added lines #L68 - L71 were not covered by tests

async fn publish_state_diff_and_proof_felts(
&self,
state_diff: &[FieldElement],
state_diff_proof: &[FieldElement],
) -> DataAvailabilityResult<u64> {
let bytes: Vec<u8> = state_diff.iter().flat_map(|fe| fe.to_bytes_be().to_vec()).collect();
let blob = Blob::new(self.namespace, bytes)?;

Check warning on line 79 in crates/saya/core/src/data_availability/celestia/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/saya/core/src/data_availability/celestia/mod.rs#L77-L79

Added lines #L77 - L79 were not covered by tests

let proof_bytes: Vec<u8> =
state_diff_proof.iter().flat_map(|fe| fe.to_bytes_be().to_vec()).collect();
let proof_blob = Blob::new(self.namespace, proof_bytes)?;

Check warning on line 83 in crates/saya/core/src/data_availability/celestia/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/saya/core/src/data_availability/celestia/mod.rs#L81-L83

Added lines #L81 - L83 were not covered by tests

self.client
.blob_submit(&[blob, proof_blob], GasPrice::default())

Check warning on line 86 in crates/saya/core/src/data_availability/celestia/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/saya/core/src/data_availability/celestia/mod.rs#L85-L86

Added lines #L85 - L86 were not covered by tests
.await
.map_err(|e| Error::Client(format!("Celestia RPC error: {e}")))
}
Expand Down
15 changes: 15 additions & 0 deletions crates/saya/core/src/data_availability/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,21 @@ pub trait DataAvailabilityClient {
&self,
state_diff: &[FieldElement],
) -> DataAvailabilityResult<u64>;

/// Publishes both data and transition proof on the DA layer atomically.
/// Returns the block height in which the state diff was included.
///
/// # Arguments
///
/// * `state_diff` - An array of felt representing the data to be published on the DA layer. We
/// use felt as all fields inside the state diff can be expressed as a felt. Nonce and updates
/// count are limited to 64 bits anyway.
/// * `state_diff_proof` - The serialized transition proof corresponding to the `state_diff`.
async fn publish_state_diff_and_proof_felts(
&self,
state_diff: &[FieldElement],
state_diff_proof: &[FieldElement],
) -> DataAvailabilityResult<u64>;
}

/// Initializes a [`DataAvailabilityClient`] from a [`DataAvailabilityConfig`].
Expand Down
29 changes: 21 additions & 8 deletions crates/saya/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
pub data_availability: Option<DataAvailabilityConfig>,
pub world_address: FieldElement,
pub fact_registry_address: FieldElement,
pub skip_publishing_proof: bool,
}

fn url_deserializer<'de, D>(deserializer: D) -> Result<Url, D::Error>
Expand Down Expand Up @@ -190,7 +191,9 @@

let mut state_updates_and_exec_info = vec![];

let (state_updates, da_state_updates): (Vec<_>, Vec<_>) = future::try_join_all(
// The serialized DA is not used here as we only need the state updates to generate the
// proof and the DA data are generated by the `dojo-os`.
let (state_updates, _): (Vec<_>, Vec<_>) = future::try_join_all(

Check warning on line 196 in crates/saya/core/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/saya/core/src/lib.rs#L196

Added line #L196 was not covered by tests
block_numbers
.clone()
.map(|block_number| self.provider.fetch_state_updates(block_number)),
Expand All @@ -205,13 +208,6 @@
)
.await?;

for da_state_update in da_state_updates {
if let Some(da) = &self.da_client {
// Publish state difference if DA client is available
da.publish_state_diff_felts(&da_state_update).await?;
}
}

state_updates.into_iter().zip(transactions_executions.into_iter()).for_each(
|(state_updates, exec_info)| {
state_updates_and_exec_info.push((state_updates, exec_info));
Expand Down Expand Up @@ -326,6 +322,8 @@
let (proof, state_diff, (_, last_block)) =
prove_scheduler.proved().await.context("Failed to prove.")?;

trace!(target: LOG_TARGET, last_block, "Processing proven blocks.");

Check warning on line 325 in crates/saya/core/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/saya/core/src/lib.rs#L325

Added line #L325 was not covered by tests

if self.config.store_proofs {
let filename = format!("proof_{}.json", last_block);
let mut file = File::create(filename).await.context("Failed to create proof file.")?;
Expand All @@ -335,6 +333,17 @@
let serialized_proof: Vec<FieldElement> = parse(&proof)?.into();
let world_da = state_diff.world_da.unwrap();

// Publish state difference if DA client is available
if let Some(da) = &self.da_client {
trace!(target: LOG_TARGET, last_block, "Publishing DA.");

Check warning on line 338 in crates/saya/core/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/saya/core/src/lib.rs#L337-L338

Added lines #L337 - L338 were not covered by tests

if self.config.skip_publishing_proof {
da.publish_state_diff_felts(&world_da).await?;

Check warning on line 341 in crates/saya/core/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/saya/core/src/lib.rs#L340-L341

Added lines #L340 - L341 were not covered by tests
} else {
da.publish_state_diff_and_proof_felts(&world_da, &serialized_proof).await?;

Check warning on line 343 in crates/saya/core/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/saya/core/src/lib.rs#L343

Added line #L343 was not covered by tests
}
}

Check warning on line 345 in crates/saya/core/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/saya/core/src/lib.rs#L345

Added line #L345 was not covered by tests

trace!(target: LOG_TARGET, last_block, "Verifying block.");
let (transaction_hash, nonce_after) = verifier::verify(
VerifierIdentifier::HerodotusStarknetSepolia(self.config.fact_registry_address),
Expand All @@ -348,6 +357,10 @@
let expected_fact = poseidon_hash_many(&[program_hash, program_output_hash]).to_string();
info!(target: LOG_TARGET, expected_fact, "Expected fact.");

// When not waiting for couple of second `apply_diffs` will sometimes fail due to reliance
// on registered fact
tokio::time::sleep(std::time::Duration::from_secs(2)).await;

Check warning on line 362 in crates/saya/core/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/saya/core/src/lib.rs#L362

Added line #L362 was not covered by tests
glihm marked this conversation as resolved.
Show resolved Hide resolved

trace!(target: LOG_TARGET, last_block, "Applying diffs.");
let transaction_hash = dojo_os::starknet_apply_diffs(
self.config.world_address,
Expand Down
Loading