| 762 | if p.env_hash != env_hash { |
| 763 | bail!("input {label}: leaf {i} env_hash mismatch with leaf 0"); |
| 764 | } |
| 765 | if p.range_start != expected_start { |
| 766 | bail!( |
| 767 | "input {label}: leaf {i} range_start = {} but expected {expected_start} \ |
| 768 | (non-tiling shards)", |
| 769 | p.range_start, |
| 770 | ); |
| 771 | } |
| 772 | expected_start = p.range_end; |
| 773 | failures = failures.saturating_add(p.failures); |
| 774 | } |
| 775 | if expected_start != total { |
| 776 | bail!( |
| 777 | "input {label}: leaves cover [0, {expected_start}) but env has {total} work items" |
| 778 | ); |
| 779 | } |
| 780 | Ok(failures) |
| 781 | } |
| 782 | |
| 783 | fn build_client(gpu: bool, asm: bool) -> Result<EmbeddedClient> { |
| 784 | // Executor choice. The default is the Assembly executor (`asm = true`, |
| 785 | // i.e. no `--emulator`): it is markedly faster at trace generation and is |
| 786 | // the prerequisite for the hints stream. It historically broke under our |
| 787 | // multi-program flow — calling `client.setup` for a second program |
| 788 | // re-initializes the ASM microservices and leaves the first program's ROM |
| 789 | // histogram empty, so a subsequent prove of the first program panics at |
| 790 | // `state-machines/rom/src/rom.rs:178` ("index out of bounds: len 0"). |
| 791 | // |
| 792 | // The fix is ordering-based: never set up the agg program *before* the |
| 793 | // leaves are proven. The `--shard-plan` path already does this |
| 794 | // (`run_shard_plan` sets up AGG only after the leaf loop), and the upfront |
| 795 | // agg setup in `main` is gated to the Emulator (`--emulator`), with Assembly |
| 796 | // deferring it to after the leaf loop. Validated: a 2-shard multi-program |
| 797 | // prove that previously panicked now completes and verifies. |
| 798 | // |
| 799 | // `minimal_memory()` deliberately NOT enabled — per upstream CLI |
| 800 | // docs ("Reduce memory footprint during proving at the cost of |
| 801 | // speed"). We have ~94 GB of free GPU memory, so the speed |
| 802 | // trade-off is the wrong direction for this hardware. |
| 803 | // Zisk's default embedded opts (witness cap 10). |
| 804 | let opts = EmbeddedOpts::default(); |