Deploy previously stored a program's entire ELF in one segment account,
requiring DATA_MAX_LENGTH to be temporarily raised to 700 KiB. Splits
user_elf across as many 96 KiB segment PDAs as its size requires
(loader_core::plan_deploy, shared by execute_deploy and
V03State::insert_program so genesis and live Deploy can't diverge on
chunk boundaries or PDA derivation), and restores DATA_MAX_LENGTH to
100 KiB. ProgramData's segment_number field is renamed segment_count
(same layout, now a count instead of a fixed index) so a reader knows
how many segments to fetch without probing.
V03State::get_program reconstructs a program's bytecode by fetching and
concatenating segment_count segments, then recomputes the real image_id
from the reconstructed bytes and compares it to the header's claim,
returning LeeError::InvalidProgramBytecode on mismatch rather than
silently returning corrupted bytecode.
Companion fix: SeenShard::MAX_DELIVERIES recomputed for the restored
100 KiB cap (was sized for 700 KiB).
Base PR scope only: segments exist, written in a single transaction,
reassembly verified. Batched multi-transaction writing and the Data
type's underlying word-encoding overhead are deferred follow-ups.
Verified: RISC0_DEV_MODE=1 cargo test -p loader_core (8 passed) and
-p lee --lib (218 passed); -p sequencer_core --features mock (109
passed, 1 known-unrelated ignore). Both CI clippy invocations and
cargo fmt --check clean. Test fixture regenerated for the new header
schema and multi-segment genesis shape.
NOT yet verified: the full integration_tests suite. tps_test hangs
past a 25-minute timeout with no progress logged even before its
first phase completes (context setup / vault-claim submission) -
root cause not yet identified. A ~13ms-per-dispatch cost from the new
image-id integrity check in get_program was measured and ruled out as
insufficient to explain a hang of this magnitude on its own. Needs
follow-up before this branch is considered done.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
instruction_data is word-serialized (risc0_zkvm::serde) for guest consumption,
which encodes Vec<u8> at 4 bytes/word since it doesn't route through
serialize_bytes — a Deploy transaction's wire size ran ~4x its raw bytecode.
Add Message/ChainedCall::raw_payload, a plain borsh-encoded Vec<u8> alongside
instruction_data, and move Deploy's bytecode there instead; Instruction::Deploy
now only carries update_auth.
Also stop transmitting and storing the ~32KB RISC0 platform kernel on every
single deployment: it's byte-identical across every guest artifact in this
repo, so Deploy now carries only the program-specific user_elf and
execute_deploy reconstructs the full two-ELF binary from an embedded kernel
constant to compute image_id. Segment accounts store user_elf only, roughly
halving their footprint for a typical program.
Measured on real Deploy dispatch (claimer, ~366KB): encoded transaction size
dropped from 1,464,777 bytes to 334,094 bytes.
- RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID: restore the SHA256 derivation
docstring that explains the constant instead of leaving it as an opaque
byte array, and switch the array itself to a hex literal (hex-literal,
already a workspace dependency) for readability.
- Rename the loader/loader_core crate to program_loader/program_loader_core
to disambiguate it, across the directory, package name, workspace
members/dependency alias, both dependent crates, and every call site.