Skip to content
Draft
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
12 changes: 12 additions & 0 deletions .github/workflows/run-benchmark-natively.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Run benchmark natively

on:
workflow_dispatch:

jobs:
benchmark:
name: Benchmark RISCV kernel natively
uses: ./.github/workflows/run-benchmark-job.yml
with:
run-natively: true
job-name: "Benchmark RISCV kernel natively"
17 changes: 17 additions & 0 deletions .github/workflows/run-benchmark.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Run benchmark

on:
workflow_dispatch:

jobs:
build_riscv_kernel:
name: Build RISCV kernel
uses: ./.github/workflows/build-riscv-kernel.yml

benchmark:
name: Benchmark RISCV kernel
needs: [build_riscv_kernel]
uses: ./.github/workflows/run-benchmark-job.yml
with:
run-natively: false
job-name: "Benchmark RISCV kernel"
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions crates/jstzd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ clap.workspace = true
console.workspace = true
futures.workspace = true
futures-util.workspace = true
hex.workspace = true
http.workspace = true
indicatif.workspace = true
jstz_crypto = { path = "../jstz_crypto" }
Expand All @@ -38,6 +39,7 @@ anyhow.workspace = true
bincode.workspace = true
hex.workspace = true
serde_json.workspace = true
sha2 = "0.10"
tempfile.workspace = true
tezos_crypto_rs.workspace = true
tezos-smart-rollup.workspace = true
Expand Down
74 changes: 63 additions & 11 deletions crates/jstzd/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ include!("build_config.rs");
/// The jstz kernel path used to generate the rollup installer / preimages.
/// generated by running `make build build-jstzd-kernel`
const JSTZ_KERNEL_PATH: &str = "./resources/jstz_rollup/jstz_kernel.wasm";
/// The RISC-V kernel executable path for origination
const JSTZ_RISCV_KERNEL_PATH: &str =
"./resources/jstz_rollup/lightweight-kernel-executable";
const JSTZ_PARAMETERS_TY_PATH: &str = "./resources/jstz_rollup/parameters_ty.json";
/// Generated file that contains path getter functions
const JSTZ_ROLLUP_PATH: &str = "jstz_rollup_path.rs";
Expand All @@ -38,16 +41,19 @@ const ROLLUP_OPERATOR_BOOTSTRAP_ACCOUNT_ALIAS: &str = "rollup_operator";
/// - parameters_ty.json: JSON file containing parameter types
///
/// Files generated:
/// - kernel_installer.hex: Hex-encoded kernel installer binary
/// - preimages/: Directory containing kernel preimages
/// - kernel_installer.hex: Hex-encoded kernel installer binary (for WASM bootstrap - legacy)
/// - preimages/: Directory containing kernel preimages (for WASM bootstrap - legacy)
/// - jstz_rollup_path.rs: Generated Rust code with path getters
///
/// The generated jstz_rollup_path.rs provides the following functions:
/// - kernel_installer_path(): Path to the kernel installer hex file
/// - kernel_installer_path(): Path to the kernel installer hex file (legacy)
/// - parameters_ty_path(): Path to the parameters type JSON file
/// - preimages_path(): Path to the preimages directory
/// - preimages_path(): Path to the preimages directory (legacy)
/// - riscv_kernel_path(): Path to the RISC-V kernel executable
/// - riscv_kernel_checksum(): SHA256 checksum of the RISC-V kernel
fn main() {
println!("cargo:rerun-if-changed={JSTZ_KERNEL_PATH}");
println!("cargo:rerun-if-changed={JSTZ_RISCV_KERNEL_PATH}");
println!("cargo:rerun-if-changed={JSTZ_PARAMETERS_TY_PATH}");
println!("cargo:rerun-if-changed={BOOTSTRAP_ACCOUNT_PATH}");

Expand All @@ -60,7 +66,7 @@ fn main() {
// 2. Validate built-in bootstrap accounts stored in the resource file
let bootstrap_accounts = validate_builtin_bootstrap_accounts();

// 3. Create preimages directory and the kernel installer in OUT_DIR
// 3. Create preimages directory and the kernel installer in OUT_DIR (legacy WASM support)
let preimages_dir = out_dir.join("preimages");
fs::create_dir_all(&preimages_dir).expect("Failed to create preimages directory");
let injector_pk = bootstrap_accounts
Expand All @@ -74,12 +80,16 @@ fn main() {
)
.expect("Failed to make kernel installer");

// 4. Save hex-encoded kernel installer to OUT_DIR
// 4. Save hex-encoded kernel installer to OUT_DIR (legacy WASM support)
fs::write(out_dir.join("kernel_installer.hex"), kernel_installer)
.expect("Failed to write kernel_installer.hex");

// 5. Generate path getter code in OUT_DIR
generate_code(&out_dir);
// 5. Compute RISC-V kernel checksum
let riscv_kernel_checksum = compute_sha256(Path::new(JSTZ_RISCV_KERNEL_PATH))
.expect("Failed to compute RISC-V kernel checksum");

// 6. Generate path getter code in OUT_DIR
generate_code(&out_dir, &riscv_kernel_checksum);

println!(
"cargo:warning=Build script output directory: {}",
Expand Down Expand Up @@ -168,10 +178,12 @@ fn make_kernel_installer(
/// Generates Rust code for path getters to access files in OUT_DIR
///
/// Generates the following functions:
/// - kernel_installer_path(): Path to the kernel installer hex file
/// - kernel_installer_path(): Path to the kernel installer hex file (legacy)
/// - parameters_ty_path(): Path to the parameters type JSON file
/// - preimages_path(): Path to the preimages directory
fn generate_code(out_dir: &Path) {
/// - preimages_path(): Path to the preimages directory (legacy)
/// - riscv_kernel_path(): Path to the RISC-V kernel executable
/// - riscv_kernel_checksum(): SHA256 checksum of the RISC-V kernel
fn generate_code(out_dir: &Path, riscv_kernel_checksum: &str) {
let mut code = String::new();
code.push_str(&generate_path_getter_code(
out_dir,
Expand All @@ -189,6 +201,29 @@ fn generate_code(out_dir: &Path) {
"preimages",
));

// Generate RISC-V kernel path getter
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let riscv_kernel_absolute_path = PathBuf::from(&manifest_dir)
.join(JSTZ_RISCV_KERNEL_PATH)
.canonicalize()
.expect("Failed to canonicalize RISC-V kernel path");

code.push_str(&format!(
r#"
const RISCV_KERNEL_PATH: &str = "{}";
pub fn riscv_kernel_path() -> std::path::PathBuf {{
std::path::PathBuf::from(RISCV_KERNEL_PATH)
}}

const RISCV_KERNEL_CHECKSUM: &str = "{}";
pub fn riscv_kernel_checksum() -> &'static str {{
RISCV_KERNEL_CHECKSUM
}}
"#,
riscv_kernel_absolute_path.display(),
riscv_kernel_checksum
));

fs::write(out_dir.join(JSTZ_ROLLUP_PATH), code).expect("Failed to write paths.rs");
}

Expand Down Expand Up @@ -228,6 +263,23 @@ fn generate_path_getter_code(out_dir: &Path, fn_name: &str, path_suffix: &str) -
)
}

/// Computes SHA256 checksum of a file
fn compute_sha256(path: &Path) -> Result<String> {
use sha2::{Digest, Sha256};

if !path.exists() {
return Err(anyhow::anyhow!(
"RISC-V kernel file not found: {}",
path.display()
));
}

let content = fs::read(path)?;
let mut hasher = Sha256::new();
hasher.update(&content);
Ok(format!("{:x}", hasher.finalize()))
}

fn validate_builtin_bootstrap_accounts() -> HashMap<String, PublicKey> {
let bytes =
fs::read(BOOTSTRAP_ACCOUNT_PATH).expect("failed to read bootstrap account file");
Expand Down
Binary file not shown.
Binary file not shown.
21 changes: 17 additions & 4 deletions crates/jstzd/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,14 @@ pub async fn build_config(mut config: Config) -> Result<(u16, JstzdConfig)> {
rollup_builder.set_operator(ROLLUP_OPERATOR_ACCOUNT_ALIAS.to_string());
}
if !rollup_builder.has_boot_sector_file() {
rollup_builder = rollup_builder
.set_boot_sector_file(jstz_rollup_path::kernel_installer_path());
// Set a dummy path to satisfy the builder - won't be used for RISC-V rollups
// since we pass None when spawning (kernel comes from origination)
rollup_builder =
rollup_builder.set_boot_sector_file(jstz_rollup_path::riscv_kernel_path());
}

let octez_rollup_config = rollup_builder
.set_pvm_kind(SmartRollupPvmKind::Riscv)
.set_data_dir(RollupDataDir::TempWithPreImages {
preimages_dir: jstz_rollup_path::preimages_path(),
})
Expand Down Expand Up @@ -396,11 +399,21 @@ async fn build_protocol_params(
accounts.push(account);
}

let kernel_path = jstz_rollup_path::riscv_kernel_path();
let kernel_checksum = jstz_rollup_path::riscv_kernel_checksum();

// Format: kernel:<absolute_path>:<sha256_checksum>
let kernel = format!("kernel:{}:{}", kernel_path.display(), kernel_checksum);
println!("kernel: {}", kernel);

// No longer bootstrap the rollup - it will be originated instead
builder
.set_bootstrap_smart_rollups([BootstrapSmartRollup::new(
JSTZ_ROLLUP_ADDRESS,
SmartRollupPvmKind::Wasm,
&tokio::fs::read_to_string(jstz_rollup_path::kernel_installer_path()).await?,
SmartRollupPvmKind::Riscv,
&hex::encode(&kernel),
//hex::encode(&tokio::fs::read(jstz_rollup_path::riscv_kernel_path()).await?)
// .as_str(),
serde_json::from_slice(
&BootstrapRollupFile::get("parameters_ty.json")
.ok_or(anyhow::anyhow!("file not found"))?
Expand Down
92 changes: 83 additions & 9 deletions crates/jstzd/src/task/jstzd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ impl JstzdConfig {
impl Task for Jstzd {
type Config = JstzdConfig;

async fn spawn(config: Self::Config) -> Result<Self> {
async fn spawn(mut config: Self::Config) -> Result<Self> {
let octez_node = OctezNode::spawn(config.octez_node_config.clone()).await?;
let octez_client = OctezClient::new(config.octez_client_config.clone());
Self::wait_for_node(&octez_node).await?;
Expand All @@ -162,9 +162,30 @@ impl Task for Jstzd {
.await?;
Self::activate_protocol(&octez_client, &config.protocol_params).await?;
let baker = OctezBaker::spawn(config.baker_config.clone()).await?;
Self::wait_for_block_level(&config.octez_node_config.rpc_endpoint, 3).await?;
//Self::wait_for_block_level(&config.octez_node_config.rpc_endpoint, 3).await?;

// Originate the RISC-V rollup and update the config with the new address
/*let rollup_address = Self::originate_rollup(&octez_client).await?;
config.octez_rollup_config =
config.octez_rollup_config.with_address(rollup_address);*/

// Wait a couple blocks for the origination to be included
println!("\n⏳ Waiting for rollup origination to be included...");
Self::wait_for_block_level(&config.octez_node_config.rpc_endpoint, 5).await?;
println!(" ✅ Rollup origination included!");

println!(
"\n🔧 Starting rollup node (connecting to {})...",
config.octez_node_config.rpc_endpoint
);
let rollup = OctezRollup::spawn(config.octez_rollup_config.clone()).await?;

Self::wait_for_rollup(&rollup).await?;
// Give the rollup node a moment to start, but don't wait for full health check
// It will catch up and sync in the background
println!(" ⏳ Waiting for rollup node to start...");
sleep(Duration::from_secs(5)).await;
println!(" ✅ Rollup node started (will sync in background)!");
let jstz_node = match config.jstz_node_config {
Some(config) => Some(JstzNode::spawn(config.clone()).await?.into_shared()),
None => None,
Expand Down Expand Up @@ -291,22 +312,64 @@ impl Jstzd {
.await
}

/// Originate the RISC-V smart rollup
///
/// This function originates a RISC-V kernel using the octez client.
/// The kernel path format is: kernel:<path>:<checksum>
///
/// The kernel path and checksum are computed at build time from the
/// lightweight-kernel-executable in resources/jstz_rollup/
async fn originate_rollup(
octez_client: &OctezClient,
) -> Result<tezos_crypto_rs::hash::SmartRollupHash> {
use crate::jstz_rollup_path;

let kernel_path = jstz_rollup_path::riscv_kernel_path();
let kernel_checksum = jstz_rollup_path::riscv_kernel_checksum();

// Format: kernel:<absolute_path>:<sha256_checksum>
let kernel = format!("kernel:{}:{}", kernel_path.display(), kernel_checksum);

println!("Originating RISC-V smart rollup...");
println!(" Kernel path: {}", kernel_path.display());
println!(" Kernel checksum: {}", kernel_checksum);

let rollup_address = octez_client
.originate_smart_rollup(
"jstz_rollup",
ROLLUP_OPERATOR_ACCOUNT_ALIAS,
"riscv",
"string",
&kernel,
Some(999999.0),
)
.await?;

println!("Smart rollup originated with address: {}", rollup_address);
Ok(rollup_address)
}

async fn wait_for_node(octez_node: &OctezNode) -> Result<()> {
let ready = retry(10, 1000, || async {
Ok(octez_node.health_check().await.unwrap_or(false))
let ready = retry(30, 1000, || async {
let health = octez_node.health_check().await.unwrap_or(false);
if !health {
print!(".");
stdout().flush().ok();
}
Ok(health)
})
.await;
if !ready {
return Err(anyhow::anyhow!(
"octez node is still not ready after retries"
"octez node is still not ready after 30 retries"
));
}
Ok(())
}

/// Wait for the baker to bake at least `level` blocks.
async fn wait_for_block_level(node_endpoint: &Endpoint, level: i64) -> Result<()> {
let ready = retry(10, 1000, || async {
let ready = retry(100, 1000, || async {
get_block_level(&node_endpoint.to_string())
.await
.map(|l| l >= level)
Expand All @@ -319,13 +382,22 @@ impl Jstzd {
}

async fn wait_for_rollup(rollup: &OctezRollup) -> Result<()> {
let ready = retry(20, 1000, || async {
Ok(rollup.health_check().await.unwrap_or(false))
println!(
" Waiting for rollup node to become ready (this may take a minute)..."
);
let ready = retry(60, 2000, || async {
let health = rollup.health_check().await.unwrap_or(false);
if !health {
print!(".");
stdout().flush().ok();
}
Ok(health)
})
.await;
println!(); // newline after dots
if !ready {
return Err(anyhow::anyhow!(
"rollup node is still not ready after retries"
"rollup node is still not ready after 60 retries (2 minutes). Check the rollup log file for details."
));
}
Ok(())
Expand Down Expand Up @@ -469,6 +541,8 @@ impl JstzdServer {
// 60 seconds
for _ in 0..120 {
let (overall_result, individual_results) = jstzd.health_check_inner().await;
println!("overall_result: {:?}", overall_result);
println!("individual_results: {:?}", individual_results);
jstzd_healthy = overall_result.unwrap_or_default();
let latest_progress = collect_progress(individual_results);
update_progress_bar(progress_bar.as_ref(), latest_progress);
Expand Down
6 changes: 4 additions & 2 deletions crates/jstzd/tests/sandbox-params.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@
"consensus_rights_delay": 2,
"blocks_preservation_cycles": 1,
"delegate_parameters_activation_delay": 2,
"tolerated_inactivity_period": 2,
"tolerated_inactivity_period_high": 12,
"tolerated_inactivity_period_low": 1,
"tolerated_inactivity_period_threshold": 10,
"blocks_per_cycle": 8,
"blocks_per_commitment": 4,
"nonce_revelation_threshold": 4,
Expand Down Expand Up @@ -163,7 +165,7 @@
"dal_attested_slots_validity_lag": 241920
},
"smart_rollup_private_enable": true,
"smart_rollup_riscv_pvm_enable": false,
"smart_rollup_riscv_pvm_enable": true,
"zk_rollup_enable": false,
"zk_rollup_origination_size": 4000,
"zk_rollup_min_pending_to_process": 10,
Expand Down
Loading
Loading