mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-08-26 03:41:13 +00:00
refactor(lee): drop the loader guest binary, native-only Deploy
Deploy is not intended to ever run privately, and public dispatch already always takes the native fast-path for it, so the guest ELF had no real execution path left. Removes lez/programs/loader's guest binary crate, its [[bin]] wiring, programs::loader(), and the now-pointless guest-vs-native equivalence test along with the test-only Program::execute_for_test it depended on. loader_core (Instruction, ProgramData, execute_deploy) stays — native dispatch still calls it directly. Deploy is now honestly just native dispatch logic with a program-shaped interface, not a program with a guest binary nobody executes.
This commit is contained in:
Generated
-9
@@ -6378,14 +6378,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "loader_program"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lee_core",
|
||||
"loader_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.14"
|
||||
@@ -9442,7 +9434,6 @@ dependencies = [
|
||||
"faucet_core",
|
||||
"lee",
|
||||
"lee_core",
|
||||
"loader_core",
|
||||
"ping_core",
|
||||
"risc0-zkvm",
|
||||
"sequencer_stake_core",
|
||||
|
||||
@@ -57,7 +57,6 @@ members = [
|
||||
"lez/programs/ping_sender",
|
||||
"lez/programs/ping_receiver",
|
||||
"lez/programs/sequencer_stake",
|
||||
"lez/programs/loader",
|
||||
"lez/programs/loader/core",
|
||||
"lez/cross_zone",
|
||||
|
||||
@@ -127,7 +126,6 @@ wrapped_token_core = { path = "lez/programs/wrapped_token/core" }
|
||||
ping_core = { path = "lez/programs/ping_core" }
|
||||
sequencer_stake_core = { path = "lez/programs/sequencer_stake/core" }
|
||||
loader_core = { path = "lez/programs/loader/core" }
|
||||
loader_program = { path = "lez/programs/loader" }
|
||||
cross_zone = { path = "lez/cross_zone" }
|
||||
build_utils = { path = "build_utils" }
|
||||
test_programs = { path = "test_programs" }
|
||||
|
||||
Binary file not shown.
@@ -57,25 +57,10 @@ impl Program {
|
||||
caller_account_id: Option<AccountId>,
|
||||
pre_states: &[AccountWithMetadata],
|
||||
instruction_data: &InstructionData,
|
||||
) -> Result<ProgramOutput, LeeError> {
|
||||
self.execute_with_session_limit(
|
||||
caller_program_id,
|
||||
pre_states,
|
||||
instruction_data,
|
||||
MAX_NUM_CYCLES_PUBLIC_EXECUTION,
|
||||
)
|
||||
}
|
||||
|
||||
fn execute_with_session_limit(
|
||||
&self,
|
||||
caller_program_id: Option<ProgramId>,
|
||||
pre_states: &[AccountWithMetadata],
|
||||
instruction_data: &InstructionData,
|
||||
session_limit: u64,
|
||||
) -> Result<ProgramOutput, LeeError> {
|
||||
// Write inputs to the program
|
||||
let mut env_builder = ExecutorEnv::builder();
|
||||
env_builder.session_limit(Some(session_limit));
|
||||
env_builder.session_limit(Some(MAX_NUM_CYCLES_PUBLIC_EXECUTION));
|
||||
Self::write_inputs(
|
||||
AccountId::from(self.id),
|
||||
caller_account_id,
|
||||
@@ -125,29 +110,5 @@ impl Program {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-utils")]
|
||||
impl Program {
|
||||
/// Test-only: like `execute`, but with a session limit far above the production
|
||||
/// `MAX_NUM_CYCLES_PUBLIC_EXECUTION` cap.
|
||||
///
|
||||
/// Exists so tests can run a real, possibly large guest program to completion — e.g.
|
||||
/// comparing the loader guest's actual execution against its native dispatch fast-path
|
||||
/// (see `RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID`) — without hitting the budget that exists
|
||||
/// specifically to bound production dispatch cost, which this is deliberately not testing.
|
||||
pub fn execute_for_test(
|
||||
&self,
|
||||
caller_program_id: Option<ProgramId>,
|
||||
pre_states: &[AccountWithMetadata],
|
||||
instruction_data: &InstructionData,
|
||||
) -> Result<ProgramOutput, LeeError> {
|
||||
self.execute_with_session_limit(
|
||||
caller_program_id,
|
||||
pre_states,
|
||||
instruction_data,
|
||||
MAX_NUM_CYCLES_PUBLIC_EXECUTION * 64,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@@ -89,11 +89,6 @@ name = "sequencer_stake"
|
||||
path = "sequencer_stake/src/main.rs"
|
||||
required-features = ["programs"]
|
||||
|
||||
[[bin]]
|
||||
name = "loader"
|
||||
path = "loader/src/main.rs"
|
||||
required-features = ["programs"]
|
||||
|
||||
[features]
|
||||
# TODO: Uncomment once https://github.com/risc0/risc0/issues/3772 is resolved.
|
||||
# default = ["artifacts"]
|
||||
@@ -125,7 +120,6 @@ programs = [
|
||||
"dep:wrapped_token_core",
|
||||
"dep:ping_core",
|
||||
"dep:sequencer_stake_core",
|
||||
"dep:loader_core",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
@@ -147,7 +141,6 @@ bridge_lock_core = { workspace = true, optional = true }
|
||||
wrapped_token_core = { workspace = true, optional = true }
|
||||
ping_core = { workspace = true, optional = true }
|
||||
sequencer_stake_core = { workspace = true, optional = true }
|
||||
loader_core = { workspace = true, optional = true }
|
||||
|
||||
amm_program = { path = "amm", optional = true }
|
||||
associated_token_account_program = { path = "associated_token_account", optional = true }
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
[package]
|
||||
name = "loader_program"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
lee_core.workspace = true
|
||||
loader_core.workspace = true
|
||||
@@ -1,31 +0,0 @@
|
||||
use lee_core::program::{ProgramInput, ProgramOutput, read_lee_inputs};
|
||||
use loader_core::Instruction;
|
||||
|
||||
fn main() {
|
||||
let (
|
||||
ProgramInput {
|
||||
self_program_id,
|
||||
caller_program_id,
|
||||
pre_states,
|
||||
instruction,
|
||||
},
|
||||
instruction_words,
|
||||
) = read_lee_inputs::<Instruction>();
|
||||
|
||||
let pre_states_clone = pre_states.clone();
|
||||
|
||||
let post_states = match instruction {
|
||||
Instruction::Deploy { bytecode } => {
|
||||
loader_core::execute_deploy(self_program_id, pre_states, bytecode)
|
||||
}
|
||||
};
|
||||
|
||||
ProgramOutput::new(
|
||||
self_program_id,
|
||||
caller_program_id,
|
||||
instruction_words,
|
||||
pre_states_clone,
|
||||
post_states,
|
||||
)
|
||||
.write();
|
||||
}
|
||||
@@ -13,8 +13,8 @@ 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,
|
||||
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,
|
||||
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,
|
||||
};
|
||||
@@ -133,12 +133,6 @@ 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::*;
|
||||
@@ -189,7 +183,6 @@ 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();
|
||||
|
||||
@@ -3731,44 +3731,3 @@ fn loader_rejects_redeploying_an_already_deployed_program() {
|
||||
"Redeploying to an already-claimed program account should fail, but got: {result:?}"
|
||||
);
|
||||
}
|
||||
|
||||
/// Runs the real `loader_program` guest ELF end-to-end (via `Program::execute_for_test`, which
|
||||
/// uses a session limit well above production's `MAX_NUM_CYCLES_PUBLIC_EXECUTION` since running
|
||||
/// a real guest to completion for this comparison is the whole point) and checks its output
|
||||
/// against calling `execute_deploy` natively with the same inputs.
|
||||
///
|
||||
/// This doesn't re-verify `execute_deploy`'s own logic — the guest and the native dispatch path
|
||||
/// both call that exact function, so it can't diverge between them. What this catches is drift
|
||||
/// in the thin wrapper code on each side: the guest's `read_lee_inputs`/`ProgramOutput::write`
|
||||
/// glue in `loader_program::main`, versus dispatch's manual `risc0_zkvm::serde::from_slice` and
|
||||
/// `ProgramOutput::new(..)` construction in `from_public_transaction`.
|
||||
#[test]
|
||||
fn loader_native_execution_matches_real_guest_execution() {
|
||||
let loader = programs::loader();
|
||||
let bytecode = test_programs::claimer().elf().to_vec();
|
||||
|
||||
let image_id: ProgramId = risc0_binfmt::compute_image_id(&bytecode).unwrap().into();
|
||||
let target = loader_core::deploy_account_id(loader.id(), image_id, 0, AccountId::default());
|
||||
|
||||
let pre_states = vec![lee_core::account::AccountWithMetadata::new(
|
||||
Account::default(),
|
||||
false,
|
||||
target,
|
||||
)];
|
||||
let instruction_data =
|
||||
lee::program::Program::serialize_instruction(loader_core::Instruction::Deploy {
|
||||
bytecode: bytecode.clone(),
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let guest_output = loader
|
||||
.execute_for_test(None, &pre_states, &instruction_data)
|
||||
.expect("real guest execution should succeed");
|
||||
|
||||
let native_post_states = loader_core::execute_deploy(loader.id(), pre_states.clone(), bytecode);
|
||||
|
||||
assert_eq!(guest_output.self_program_id, loader.id());
|
||||
assert_eq!(guest_output.caller_program_id, None);
|
||||
assert_eq!(guest_output.pre_states, pre_states);
|
||||
assert_eq!(guest_output.post_states, native_post_states);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user