Skip to content

Commit d4b9ec6

Browse files
authored
Fix: Deploy and Update ZKISM using Rust CLI (#264)
* properly deploy ISM using ev-prover cli * quickfix * quickfix
1 parent fbe8cbd commit d4b9ec6

File tree

12 files changed

+265
-63
lines changed

12 files changed

+265
-63
lines changed

.env.example

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,9 @@ CELESTIA_ISM_ID="0x726f757465725f69736d000000000000000000000000002a0000000000000
2121
CELESTIA_NAMESPACE="a8045f161bf468bf4d44"
2222

2323
# To submit messages to Celestia we must specify a funded private key.
24-
CELESTIA_PRIVATE_KEY="6e30efb1d3ebd30d1ba08c8d5fc9b190e08394009dc1dd787a69e60c33288a8c"
24+
CELESTIA_PRIVATE_KEY="6e30efb1d3ebd30d1ba08c8d5fc9b190e08394009dc1dd787a69e60c33288a8c"
25+
26+
RETH_RPC_URL="http://localhost:8545"
27+
RETH_WS_URL="ws://127.0.0.1:8546"
28+
CELESTIA_RPC_URL="http://localhost:26658"
29+
SEQUENCER_RPC_URL="http://localhost:7331"

crates/celestia-grpc-client/src/message.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
1-
use crate::{MsgProcessMessage, MsgRemoteTransfer, MsgSubmitMessages, MsgUpdateZkExecutionIsm};
1+
use crate::{
2+
proto::{celestia::zkism::v1::MsgCreateZkExecutionIsm, hyperlane::warp::v1::MsgSetToken},
3+
MsgProcessMessage, MsgRemoteTransfer, MsgSubmitMessages, MsgUpdateZkExecutionIsm,
4+
};
25
use prost::Name;
36

47
// Legacy aliases for backward compatibility
58
pub type StateTransitionProofMsg = MsgUpdateZkExecutionIsm;
69
pub type StateInclusionProofMsg = MsgSubmitMessages;
710
pub type HyperlaneMessage = MsgProcessMessage;
811

12+
impl Name for MsgSetToken {
13+
const NAME: &'static str = "MsgSetToken";
14+
const PACKAGE: &'static str = "hyperlane.warp.v1";
15+
}
16+
17+
impl Name for MsgCreateZkExecutionIsm {
18+
const NAME: &'static str = "MsgCreateZKExecutionISM";
19+
const PACKAGE: &'static str = "celestia.zkism.v1";
20+
}
21+
922
impl MsgUpdateZkExecutionIsm {
1023
/// Create a new ZK execution ISM update message
1124
pub fn new(id: String, proof: Vec<u8>, public_values: Vec<u8>, signer: String) -> Self {

crates/e2e/src/bin/block.rs

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1-
use std::sync::Arc;
1+
use std::{env, sync::Arc};
22

33
use alloy_primitives::{FixedBytes, hex::FromHex};
44
use e2e::{
55
config::debug::{TARGET_HEIGHT, TRUSTED_HEIGHT, TRUSTED_ROOT},
66
prover::block::prove_blocks,
77
};
8-
use ev_types::v1::{GetMetadataRequest, store_service_client::StoreServiceClient};
8+
use ev_prover::inclusion_height;
99
use sp1_sdk::ProverClient;
1010

1111
#[tokio::main]
1212
async fn main() {
13+
let sequencer_rpc_url = env::var("SEQUENCER_RPC_URL").unwrap();
1314
dotenvy::dotenv().ok();
14-
let trusted_inclusion_height = inclusion_height(TRUSTED_HEIGHT).await.unwrap() + 1;
15-
let target_inclusion_height = inclusion_height(TARGET_HEIGHT).await.unwrap();
15+
let trusted_inclusion_height = inclusion_height(TRUSTED_HEIGHT, sequencer_rpc_url.clone())
16+
.await
17+
.unwrap()
18+
+ 1;
19+
let target_inclusion_height = inclusion_height(TARGET_HEIGHT, sequencer_rpc_url).await.unwrap();
1620
let num_blocks = target_inclusion_height - trusted_inclusion_height + 1;
1721
let client = Arc::new(ProverClient::from_env());
1822
prove_blocks(
@@ -25,16 +29,3 @@ async fn main() {
2529
.await
2630
.expect("Failed to prove blocks");
2731
}
28-
29-
// todo: find a place for this function and remove it from the binaries
30-
async fn inclusion_height(block_number: u64) -> anyhow::Result<u64> {
31-
let mut client = StoreServiceClient::connect(e2e::config::debug::SEQUENCER_URL).await?;
32-
let req = GetMetadataRequest {
33-
key: format!("rhb/{block_number}/d"),
34-
};
35-
36-
let resp = client.get_metadata(req).await?;
37-
let height = u64::from_le_bytes(resp.into_inner().value[..8].try_into()?);
38-
39-
Ok(height)
40-
}

crates/e2e/src/bin/e2e.rs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ use celestia_grpc_client::types::ClientConfig;
55
use celestia_grpc_client::{
66
MsgProcessMessage, MsgSubmitMessages, MsgUpdateZkExecutionIsm, QueryIsmRequest, client::CelestiaIsmClient,
77
};
8-
use e2e::config::debug::EV_RPC;
98
use e2e::config::e2e::{CELESTIA_MAILBOX_ID, CELESTIA_TOKEN_ID, EV_RECIPIENT_ADDRESS, ISM_ID};
109
use e2e::prover::block::prove_blocks;
1110
use e2e::prover::helpers::transfer_back;
1211
use e2e::prover::message::prove_messages;
12+
use ev_prover::inclusion_height;
1313
use ev_state_queries::MockStateQueryProvider;
14-
use ev_types::v1::{GetMetadataRequest, store_service_client::StoreServiceClient};
1514
use ev_zkevm_types::hyperlane::encode_hyperlane_message;
1615
use sp1_sdk::{EnvProver, ProverClient};
16+
use std::env;
1717
use std::time::Duration;
1818
use std::{str::FromStr, sync::Arc};
1919
use storage::hyperlane::snapshot::HyperlaneSnapshotStore;
@@ -40,6 +40,9 @@ async fn main() {
4040
}
4141
tracing_subscriber::fmt().with_env_filter(filter).init();
4242

43+
let reth_rpc_url = env::var("RETH_RPC_URL").unwrap();
44+
let sequencer_rpc_url = env::var("SEQUENCER_RPC_URL").unwrap();
45+
4346
// instantiate ISM client for submitting payloads and querying state
4447
let config = ClientConfig::from_env().expect("failed to create celestia client config");
4548
let ism_client = CelestiaIsmClient::new(config).await.unwrap();
@@ -75,7 +78,11 @@ async fn main() {
7578
let target_height = retry_async(transfer_back, "transfer_back").await;
7679
info!("Target height: {}", target_height);
7780
let client: Arc<EnvProver> = Arc::new(ProverClient::from_env());
78-
let target_inclusion_height = retry_async(|| inclusion_height(target_height), "inclusion_height").await;
81+
let target_inclusion_height = retry_async(
82+
|| inclusion_height(target_height, sequencer_rpc_url.clone()),
83+
"inclusion_height",
84+
)
85+
.await;
7986
let num_blocks = target_inclusion_height - celestia_start_height;
8087

8188
info!("Proving Evolve blocks...");
@@ -102,7 +109,7 @@ async fn main() {
102109
assert!(response.success);
103110
info!("[Done] ZKISM was updated successfully");
104111

105-
let evm_provider = ProviderBuilder::new().connect_http(Url::from_str(EV_RPC).unwrap());
112+
let evm_provider = ProviderBuilder::new().connect_http(Url::from_str(&reth_rpc_url).unwrap());
106113
info!("Proving Evolve Hyperlane deposit events...");
107114

108115
let snapshot_storage_path = dirs::home_dir()
@@ -152,18 +159,6 @@ async fn main() {
152159
info!("[Done] Tia was bridged back to Celestia");
153160
}
154161

155-
// todo: find a place for this function and remove it from the binaries
156-
async fn inclusion_height(block_number: u64) -> anyhow::Result<u64> {
157-
let mut client = StoreServiceClient::connect(e2e::config::e2e::SEQUENCER_URL).await?;
158-
let req = GetMetadataRequest {
159-
key: format!("rhb/{block_number}/d"),
160-
};
161-
162-
let resp = client.get_metadata(req).await?;
163-
let height = u64::from_le_bytes(resp.into_inner().value[..8].try_into()?);
164-
Ok(height)
165-
}
166-
167162
async fn retry_async<F, Fut, T, E>(mut f: F, label: &str) -> T
168163
where
169164
F: FnMut() -> Fut,

crates/e2e/src/bin/message.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
use alloy_provider::ProviderBuilder;
2-
use e2e::{
3-
config::debug::{EV_RPC, TARGET_HEIGHT},
4-
prover::message::prove_messages,
5-
};
2+
use e2e::{config::debug::TARGET_HEIGHT, prover::message::prove_messages};
63
use ev_state_queries::MockStateQueryProvider;
74
use sp1_sdk::{EnvProver, ProverClient};
8-
use std::{str::FromStr, sync::Arc};
5+
use std::{env, str::FromStr, sync::Arc};
96
use url::Url;
107

118
#[tokio::main]
129
async fn main() {
1310
dotenvy::dotenv().ok();
11+
let reth_rpc_url = env::var("RETH_RPC_URL").unwrap();
1412
let client: Arc<EnvProver> = Arc::new(ProverClient::from_env());
15-
let evm_provider = ProviderBuilder::new().connect_http(Url::from_str(EV_RPC).unwrap());
13+
let evm_provider = ProviderBuilder::new().connect_http(Url::from_str(&reth_rpc_url).unwrap());
1614
let _proof = prove_messages(
1715
TARGET_HEIGHT,
1816
&evm_provider.clone(),

crates/e2e/src/config.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ pub mod e2e {
88
pub const EV_RECIPIENT_ADDRESS: &str = "0x000000000000000000000000aF9053bB6c4346381C77C2FeD279B17ABAfCDf4d";
99
// mailbox id on Celestia
1010
pub const CELESTIA_MAILBOX_ID: &str = "0x68797065726c616e650000000000000000000000000000000000000000000000";
11-
// target height for message prover
12-
pub const SEQUENCER_URL: &str = "http://127.0.0.1:7331";
1311
}
1412

1513
/// Other configs (block, message binaries), only useful for debugging
@@ -22,7 +20,4 @@ pub mod debug {
2220
pub const TARGET_HEIGHT: u64 = 198;
2321
// trusted evm root for block prover
2422
pub const TRUSTED_ROOT: &str = "0x0e106db5b2dd79354e2ae0116439ee1fa4fcf88bdec03803c9c79bf0e1101f08";
25-
pub const EV_RPC: &str = "http://127.0.0.1:8545";
26-
pub const SEQUENCER_URL: &str = "http://127.0.0.1:7331";
27-
pub const EV_WS: &str = "ws://127.0.0.1:8546";
2823
}

crates/ev-prover/src/commands/cli.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ pub enum Commands {
1717
/// Start the gRPC server
1818
Start {},
1919

20+
/// Create ZKISM
21+
Create {},
22+
23+
/// Update
24+
Update { ism_id: String, token_id: String },
25+
2026
/// Show the service version
2127
Version {},
2228
}

crates/ev-prover/src/commands/command.rs

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1-
use std::fs;
1+
use std::{env, fs};
22

3+
use crate::get_sequencer_pubkey;
4+
use alloy_provider::{Provider, ProviderBuilder};
35
use anyhow::{bail, Result};
6+
use celestia_grpc_client::proto::celestia::zkism::v1::MsgCreateZkExecutionIsm;
7+
use celestia_grpc_client::proto::hyperlane::warp::v1::MsgSetToken;
8+
use celestia_grpc_client::types::ClientConfig;
9+
use celestia_grpc_client::CelestiaIsmClient;
10+
use celestia_rpc::{BlobClient, Client, HeaderClient};
11+
use celestia_types::nmt::Namespace;
12+
use celestia_types::{Blob, ExtendedHeader};
13+
use ev_types::v1::SignedData;
14+
use prost::Message;
415
use tracing::info;
516

617
use crate::commands::cli::VERSION;
@@ -60,6 +71,117 @@ pub async fn start() -> Result<()> {
6071
Ok(())
6172
}
6273

74+
pub async fn create_zkism() -> Result<()> {
75+
let celestia_rpc_url = env::var("CELESTIA_RPC_URL")?;
76+
let reth_rpc_url = env::var("RETH_RPC_URL")?;
77+
let sequencer_rpc_url = env::var("SEQUENCER_RPC_URL")?;
78+
let namespace_hex = env::var("CELESTIA_NAMESPACE")?;
79+
let config = ClientConfig::from_env()?;
80+
let ism_client = CelestiaIsmClient::new(config).await?;
81+
let celestia_client = Client::new(&celestia_rpc_url, None).await?;
82+
let namespace: Namespace = Namespace::new_v0(&hex::decode(namespace_hex)?).unwrap();
83+
84+
// Find a Celestia height with at least one blob (brute force backwards starting from head)
85+
let (celestia_state, blobs) = brute_force_head(&celestia_client, namespace).await?;
86+
// DA HEIGHT
87+
let height: u64 = celestia_state.height().value();
88+
// DA BLOCK HASH
89+
let block_hash = celestia_state.hash().as_bytes().to_vec();
90+
let last_blob = blobs.last().expect("User Error: Can't use a 0-blob checkpoint");
91+
let data = SignedData::decode(last_blob.data.as_slice())?;
92+
93+
// EV BLOCK HEIGHT
94+
let last_blob_height = data.data.unwrap().metadata.unwrap().height;
95+
96+
let provider = ProviderBuilder::new().connect_http(reth_rpc_url.parse()?);
97+
98+
let block = provider
99+
.get_block(alloy_rpc_types::BlockId::Number(
100+
alloy_rpc_types::BlockNumberOrTag::Number(last_blob_height),
101+
))
102+
.await?
103+
.ok_or_else(|| anyhow::anyhow!("Block not found"))?;
104+
105+
// EV STATE ROOT
106+
let last_blob_state_root = block.header.state_root;
107+
// todo: deploy the ISM and Update
108+
let pub_key = get_sequencer_pubkey(sequencer_rpc_url).await?;
109+
110+
let ev_hyperlane_vkey = fs::read("testdata/vkeys/ev-hyperlane-vkey-hash")?;
111+
let ev_combined_vkey = fs::read("testdata/vkeys/ev-range-exec-vkey-hash")?;
112+
let groth16_vkey = fs::read("testdata/vkeys/groth16_vk.bin")?;
113+
114+
let create_message = MsgCreateZkExecutionIsm {
115+
creator: ism_client.signer_address().to_string(),
116+
state_root: last_blob_state_root.to_vec(),
117+
height: last_blob_height,
118+
celestia_header_hash: block_hash,
119+
celestia_height: height,
120+
namespace: namespace.as_bytes().to_vec(),
121+
sequencer_public_key: pub_key,
122+
groth16_vkey,
123+
state_transition_vkey: hex::decode(&ev_combined_vkey[2..]).unwrap(),
124+
state_membership_vkey: hex::decode(&ev_hyperlane_vkey[2..]).unwrap(),
125+
};
126+
127+
let response = ism_client.send_tx(create_message).await?;
128+
assert!(response.success);
129+
info!("ISM created successfully");
130+
Ok(())
131+
}
132+
133+
pub async fn update_ism(ism_id: String, token_id: String) -> Result<()> {
134+
let config = ClientConfig::from_env()?;
135+
let ism_client = CelestiaIsmClient::new(config).await?;
136+
137+
//todo update
138+
let message = MsgSetToken {
139+
owner: ism_client.signer_address().to_string(),
140+
token_id,
141+
new_owner: ism_client.signer_address().to_string(),
142+
ism_id,
143+
renounce_ownership: false,
144+
};
145+
146+
ism_client.send_tx(message).await?;
147+
info!("ISM updated successfully");
148+
149+
Ok(())
150+
}
151+
63152
pub fn version() {
64153
println!("version: {VERSION}");
65154
}
155+
156+
async fn brute_force_head(celestia_client: &Client, namespace: Namespace) -> Result<(ExtendedHeader, Vec<Blob>)> {
157+
// Find a Celestia height with at least one blob (brute force backwards starting from head)
158+
let mut search_height: u64 = celestia_client.header_local_head().await.unwrap().height().value();
159+
let (celestia_state, blobs) = loop {
160+
match celestia_client.header_get_by_height(search_height).await {
161+
Ok(state) => {
162+
let current_height = state.height().value();
163+
match celestia_client.blob_get_all(current_height, &[namespace]).await {
164+
Ok(Some(blobs)) if !blobs.is_empty() => {
165+
info!("Found {} blob(s) at Celestia height {}", blobs.len(), current_height);
166+
break (state, blobs);
167+
}
168+
Ok(_) => {
169+
info!("No blobs at height {}, trying nexst height", current_height);
170+
search_height -= 1;
171+
}
172+
Err(e) => {
173+
info!(
174+
"Error fetching blobs at height {}: {}, trying next height",
175+
current_height, e
176+
);
177+
search_height -= 1;
178+
}
179+
}
180+
}
181+
Err(e) => {
182+
return Err(anyhow::anyhow!("Failed to get header at height {search_height}: {e}"));
183+
}
184+
}
185+
};
186+
Ok((celestia_state, blobs))
187+
}

0 commit comments

Comments
 (0)