feat(lee): add loader program with native Deploy dispatch fast-path

Introduces a new loader_program/loader_core crate pair implementing a
Deploy instruction that claims a program's ProgramData PDA account
(image_id, segment_number, update_auth, elf_segment), unifying
deployment with ordinary PublicTransaction dispatch instead of the
separate ProgramDeploymentTransaction path.

Measured against every real program in this repo, computing a
program's image_id inside the zkVM costs ~1,400-1,500 cycles per byte
of deployed bytecode, pushing real deployments to 500M-900M cycles
against the 32M public-execution cap (vs. ~27ms natively, since
ProgramDeploymentTransaction's equivalent check runs as a plain host
function today). To keep the unified dispatch path viable, Deploy is
special-cased in from_public_transaction: calls targeting the reserved
RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID run loader_core::execute_deploy
natively instead of through the interpreted guest executor, wrapped in
catch_unwind since the shared execute_deploy logic validates via
assert!/expect() like every other guest program, relying on that
boundary instead of the zkVM's own panic-to-Result conversion.

The loader guest binary is kept buildable and covered by a test that
runs it for real and asserts its output matches the native path
exactly, so the two can't silently drift apart.
This commit is contained in:
Marvin Jones
2026-08-22 17:39:13 -04:00
parent 912c0982ce
commit dcc0c4b950
15 changed files with 458 additions and 17 deletions
+11 -3
View File
@@ -13,9 +13,10 @@ mod inner {
AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, BRIDGE_ELF, BRIDGE_ID,
BRIDGE_LOCK_ELF, BRIDGE_LOCK_ID, CLOCK_ELF, CLOCK_ID, CROSS_ZONE_INBOX_ELF,
CROSS_ZONE_INBOX_ID, CROSS_ZONE_OUTBOX_ELF, CROSS_ZONE_OUTBOX_ID, FAUCET_ELF, FAUCET_ID,
PINATA_ELF, PINATA_ID, PINATA_TOKEN_ELF, PINATA_TOKEN_ID, PING_RECEIVER_ELF,
PING_RECEIVER_ID, PING_SENDER_ELF, PING_SENDER_ID, SEQUENCER_STAKE_ELF, SEQUENCER_STAKE_ID,
TOKEN_ELF, TOKEN_ID, VAULT_ELF, VAULT_ID, WRAPPED_TOKEN_ELF, WRAPPED_TOKEN_ID,
LOADER_ELF, LOADER_ID, PINATA_ELF, PINATA_ID, PINATA_TOKEN_ELF, PINATA_TOKEN_ID,
PING_RECEIVER_ELF, PING_RECEIVER_ID, PING_SENDER_ELF, PING_SENDER_ID, SEQUENCER_STAKE_ELF,
SEQUENCER_STAKE_ID, TOKEN_ELF, TOKEN_ID, VAULT_ELF, VAULT_ID, WRAPPED_TOKEN_ELF,
WRAPPED_TOKEN_ID,
};
use lee::program::Program;
@@ -132,6 +133,12 @@ mod inner {
Program::new_unchecked(SEQUENCER_STAKE_ID, Cow::Borrowed(SEQUENCER_STAKE_ELF))
}
#[must_use]
#[inline]
pub const fn loader() -> Program {
Program::new_unchecked(LOADER_ID, Cow::Borrowed(LOADER_ELF))
}
#[cfg(test)]
mod tests {
use super::*;
@@ -182,6 +189,7 @@ mod inner {
(BRIDGE_LOCK_ELF, BRIDGE_LOCK_ID),
(WRAPPED_TOKEN_ELF, WRAPPED_TOKEN_ID),
(SEQUENCER_STAKE_ELF, SEQUENCER_STAKE_ID),
(LOADER_ELF, LOADER_ID),
];
for (elf, expected_id) in cases {
let program = Program::new((*elf).into()).unwrap();