# EPF - Update 12 & 13
## tl;dr
* Removed the build script, now input data is set through the [Zisk backend](https://github.com/0xprivateChaos/grandine-zk/blob/331d9f0499503dbde8e0b7621d6e2569a4852d73/zkvm/host/src/backend/zisk.rs#L50C6-L52C1) only.
* Integrated the build and Zisk execute commands directly into the [execute method](https://github.com/0xprivateChaos/grandine-zk/blob/331d9f0499503dbde8e0b7621d6e2569a4852d73/zkvm/host/src/backend/zisk.rs#L40) of the backend VM for a cleaner workflow.
* Execution now runs smoothly using only the `execute` subcommand, without requiring additional steps.
* Upgraded [Zisk](https://x.com/ziskvm/status/1963503563293823187) from version `0.10.0` to `0.11.0`, encountered some errors during the update process.
## Details
### Removal of Build Script
Previously, we relied on a build script to prepare the input for zisk programs. In general, zisk uses this mechanism to place data into the `build/input.bin` file, which can later be accessed inside the guest program through the `ziskos::read_input()` method.
In our case, the build script was responsible for:
* Fetching the **block and state data** from the data directory (where test case data is stored).
* Serializing this data and writing it into `input.bin`.
* Allowing the guest program to then read and deserialize it at runtime.
However, our host program already had the [setup](https://github.com/0xprivateChaos/grandine-zk/blob/331d9f0499503dbde8e0b7621d6e2569a4852d73/zkvm/host/src/main.rs#L158) in place to fetch block and state SSZ data. Since we support multiple zkVM backends, the host handles serialization according to the target VM’s requirements. For zisk specifically, this meant serializing the data in a format compatible with zisk’s VM.
### Embedding Build & Execute Commands in Backend
In my previous update, I mentioned that the guest program for zisk was being built and executed manually inside the guest directory using their respective commands. This required running `cargo-zisk build` followed by invoking `ziskemu` with the generated ELF.
Now, I’ve refactored this flow by embedding those commands directly inside the `execute` method of our zisk backend. This means that whenever we call `execute`, it automatically:
1. Builds the guest program ELF using `cargo-zisk build --release`.
2. Locates the generated ELF file in the `target/riscv64ima-zisk-zkvm-elf/release` directory.
3. Runs the ELF through ziskemu with the provided input file and a high max-step count (`100000000000000`).
```rust
// First, build the guest program ELF file.
let build_output = Command::new("cargo-zisk")
.arg("build")
.arg("--release")
.current_dir(&zisk_guest_dir)
.output()?;
// Second, execute the ELF file using ziskemu with a high step count.
let elf_path = zisk_guest_dir
.join("../../../target/riscv64ima-zisk-zkvm-elf/release/zkvm_guest_zisk");
let output = Command::new("ziskemu")
.arg("-e")
.arg(elf_path)
.arg("-i")
.arg(input_path)
.arg("--max-steps")
.arg("100000000000000")
.current_dir(&zisk_guest_dir)
.output()?;
```
### Execution Command for Test Cases
With the new integration, running the consensus spec tests (Electra, empty block transition) now works directly through a single command:
```zsh
cargo run -p zkvm_host --features zisk --release -- --test "consensus spec tests mainnet electra empty block transition" execute
```
This command handles building and executing under the hood via the zisk backend’s `execute` method.