mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-08-25 03:11:21 +00:00
docs(lee,lez): trim doc comments on the program-upgrade branch
Cut "see X's doc comment for why"-style cross-references throughout — readers can navigate to referenced items themselves. Also tightened several overlong paragraphs, and fixed a stale get_program doc claim (it no longer returns Err(InvalidProgramBytecode) for a corrupted segment set; that re-verification was replaced by trusting a non-sentinel current_image_id directly) plus an orphaned comment fragment left over from an earlier conflict resolution.
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -47,52 +47,43 @@ pub const UNFINALIZED_IMAGE_ID: [u32; 8] = [0; 8];
|
||||
pub type ProgramId = [u32; 8];
|
||||
|
||||
/// The account-data layout of a program's header account, deployed via the `Deploy` native
|
||||
/// dispatch shortcut (see [`RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID`]).
|
||||
/// dispatch shortcut.
|
||||
///
|
||||
/// Deliberately holds only small, fixed-size fields — never the program's bytecode, which lives
|
||||
/// in a separate account (see `program_loader_core::deploy_segment_account_id`). Keeping the two
|
||||
/// apart means anything that needs to authenticate a program's *identity* (e.g. the
|
||||
/// privacy-preserving circuit confirming which `image_id` an `AccountId` currently maps to) only
|
||||
/// ever has to read this handful of bytes, not the full program — the only account-authentication
|
||||
/// primitive available today is whole-account equality, so what's bundled into one account sets
|
||||
/// the floor for how cheap that authentication can be.
|
||||
/// in separate segment accounts. Keeping the two apart means identity checks (e.g. the
|
||||
/// privacy-preserving circuit confirming which `image_id` an `AccountId` maps to) only need to
|
||||
/// read this handful of bytes, not the full program — the only account-authentication primitive
|
||||
/// today is whole-account equality, so what's bundled into one account sets the floor for how
|
||||
/// cheap that check can be.
|
||||
///
|
||||
/// Splits genesis (fixed forever) from current (mutable) state so a program can be upgraded —
|
||||
/// bytecode rewritten, authority rotated — without its address ever moving:
|
||||
/// - `genesis_image_id`/`genesis_update_auth` are the sole inputs to header/segment PDA address
|
||||
/// derivation (see `program_loader_core::deploy_header_account_id`/`deploy_segment_account_id`),
|
||||
/// chosen once at the program's first-ever `Deploy` and never touched again.
|
||||
/// - `current_image_id`/`update_auth`/`program_version` are live, mutable state: `current_image_id`
|
||||
/// is `[0; 8]` while unfinalized (initial multi-transaction deploy in progress, or an upgrade's
|
||||
/// segment writes have landed but `Finalize` hasn't run yet) — `V03State::get_program` trusts a
|
||||
/// non-sentinel `current_image_id` directly rather than re-deriving it from the segments on every
|
||||
/// read, so it is only ever written by `program_loader_core::execute_deploy`'s atomic single-tx
|
||||
/// fast path or by a signed `Finalize`. `update_auth` starts equal to `genesis_update_auth` and
|
||||
/// may diverge after a co-signed `RotateUpdateAuth`.
|
||||
/// bytecode rewritten, authority rotated — without its address ever moving. `genesis_image_id`/
|
||||
/// `genesis_update_auth` are the sole inputs to header/segment PDA address derivation, chosen
|
||||
/// once at the program's first-ever `Deploy` and never touched again. `current_image_id`/
|
||||
/// `update_auth`/`program_version` are live, mutable state.
|
||||
///
|
||||
/// Lives here rather than in `program_loader_core` so that `V03State::get_program` — a generic,
|
||||
/// Lives here rather than in `program_loader_core` so `V03State::get_program` — a generic,
|
||||
/// program-agnostic lookup — can decode it without depending on a specific program's crate.
|
||||
/// `program_loader_core` re-exports this type.
|
||||
#[derive(Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct ProgramData {
|
||||
pub genesis_image_id: ProgramId,
|
||||
/// `None` means immutable: the program was deployed with no upgrade authority at all, and
|
||||
/// `update_auth` below is (and forever stays) `None` too, since there's no genesis authority
|
||||
/// to ever assign a first `update_auth` from.
|
||||
/// `None` means immutable: deployed with no upgrade authority at all, and `update_auth`
|
||||
/// below stays `None` too — there's no genesis authority to ever assign one from.
|
||||
pub genesis_update_auth: Option<AccountId>,
|
||||
/// `[0; 8]` sentinel while unfinalized. See the struct doc for exactly when this is (and
|
||||
/// isn't) written.
|
||||
/// `[0; 8]` sentinel while unfinalized — an initial multi-transaction deploy in progress, or
|
||||
/// an upgrade whose segment writes landed but `Finalize` hasn't run yet.
|
||||
/// `V03State::get_program` trusts a non-sentinel value directly rather than re-deriving it
|
||||
/// from segments on every read, so it's only ever written by `execute_deploy`'s atomic
|
||||
/// single-tx fast path or a signed `Finalize`.
|
||||
pub current_image_id: ProgramId,
|
||||
/// How many bytecode segment accounts currently exist, so a reader knows exactly how many
|
||||
/// `program_loader_core::deploy_segment_account_id(genesis_image_id, 0..segment_count,
|
||||
/// genesis_update_auth)` accounts to fetch without probing. May change across an upgrade (a
|
||||
/// new version can have more or fewer segments than the one it replaces).
|
||||
/// How many bytecode segment accounts currently exist. May change across an upgrade (a new
|
||||
/// version can have more or fewer segments than the one it replaces).
|
||||
pub segment_count: u32,
|
||||
/// Current authority for writing segments, triggering `Finalize`, or co-signing a further
|
||||
/// `RotateUpdateAuth`. `None` means no one can ever authorize a future write — either the
|
||||
/// program was deployed immutably (`genesis_update_auth` is also `None`), or a prior
|
||||
/// `RotateUpdateAuth` deliberately renounced authority for good. Not an address-derivation
|
||||
/// input — see `genesis_update_auth`.
|
||||
/// `RotateUpdateAuth`. `None` means no one can ever authorize a future write — either
|
||||
/// deployed immutably, or a prior `RotateUpdateAuth` renounced authority for good. Not an
|
||||
/// address-derivation input.
|
||||
pub update_auth: Option<AccountId>,
|
||||
/// `0` until the first successful `Finalize` (or the atomic single-tx fast path), which sets
|
||||
/// it to `1`; every subsequent `Finalize` increments it by one. Never reset by anything,
|
||||
|
||||
@@ -207,9 +207,7 @@ impl V03State {
|
||||
|
||||
/// Seeds a program directly into state in the exact `1 + segment_count`-account shape a live
|
||||
/// `Deploy` dispatch (with no upgrade authority, i.e. immutable) would produce for the same
|
||||
/// `image_id` (see [`Self::get_program`] and
|
||||
/// [`program_loader_core::immutable_deploy_account_id`]), skipping only the dispatch/proving
|
||||
/// machinery genesis has no signer to drive.
|
||||
/// `image_id`, skipping only the dispatch/proving machinery genesis has no signer to drive.
|
||||
pub(crate) fn insert_program(&mut self, program: &Program) {
|
||||
let update_auth = None;
|
||||
let user_elf = program_loader_core::extract_user_elf(program.elf())
|
||||
@@ -344,10 +342,8 @@ impl V03State {
|
||||
/// - Owned by [`RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID`]: deployed via the native `Deploy`
|
||||
/// dispatch shortcut. `account.data` decodes as a [`ProgramData`] header holding the real
|
||||
/// `image_id` and `segment_count`; the program-specific `user_elf` is split across that many
|
||||
/// separately-addressed segment accounts (see
|
||||
/// `program_loader_core::deploy_segment_account_id`), which this fetches in order,
|
||||
/// concatenates, and reconstructs into the full two-ELF binary (see
|
||||
/// `program_loader_core::reconstruct_program_binary`) before returning it.
|
||||
/// separately-addressed segment accounts, which this fetches in order, concatenates, and
|
||||
/// reconstructs into the full two-ELF binary before returning it.
|
||||
///
|
||||
/// Returning the real `image_id` — rather than callers deriving one from the address, which
|
||||
/// is only valid for the legacy path — is what makes upgrading a `Deploy`-created program
|
||||
@@ -356,14 +352,10 @@ impl V03State {
|
||||
///
|
||||
/// An account that matches neither owner isn't a deployed program, whatever its contents —
|
||||
/// this is the single place that distinction is enforced, so callers never have to remember
|
||||
/// to re-check it themselves. `Ok(None)` means no such program exists — including, ordinarily,
|
||||
/// a multi-transaction `Deploy` sequence that hasn't (yet, or ever going to) land every one of
|
||||
/// its `segment_count` segments; a caller mid-sequence sees exactly the same result as a
|
||||
/// program that was never deployed at all, by construction, since a missing segment is
|
||||
/// detected the same way regardless of cause. `Err(LeeError::InvalidProgramBytecode(_))` means
|
||||
/// every segment exists but they don't reconstruct to the `image_id` the header declares — a
|
||||
/// defense-in-depth check against a corrupted or malformed segment set, distinguishable from
|
||||
/// plain absence.
|
||||
/// to re-check it themselves. `None` means no such program is currently dispatchable: no
|
||||
/// account at all, an unfinalized header (`current_image_id` still the sentinel), or a
|
||||
/// multi-transaction `Deploy` sequence missing one of its segments — all indistinguishable
|
||||
/// from a program that was never deployed.
|
||||
pub fn get_program(
|
||||
&self,
|
||||
program_account_id: AccountId,
|
||||
|
||||
@@ -122,7 +122,8 @@ impl ValidatedStateDiff {
|
||||
let mut program_output = if chained_call.program_account_id
|
||||
== RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID
|
||||
{
|
||||
// `RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID`'s doc comment for why.
|
||||
// Deploy runs as native Rust instead of interpreting a guest ELF — there's no
|
||||
// guest binary for it.
|
||||
let instruction: program_loader_core::Instruction =
|
||||
risc0_zkvm::serde::from_slice(&chained_call.instruction_data).map_err(|e| {
|
||||
LeeError::InvalidInput(format!("invalid loader instruction: {e}"))
|
||||
@@ -141,11 +142,11 @@ impl ValidatedStateDiff {
|
||||
} => {
|
||||
// The bytecode itself travels via the transaction's own
|
||||
// `raw_payload`, not `instruction_data` and not
|
||||
// `chained_call.raw_payload` (which no guest can ever set) — see
|
||||
// `Message::raw_payload`'s doc comment for why. Deploy only ever
|
||||
// runs natively, so a chained call into it (at any depth) can still
|
||||
// reach the top-level payload here, without any intermediary guest
|
||||
// ever having to carry the bytecode through its own execution.
|
||||
// `chained_call.raw_payload` (which no guest can ever set). Deploy
|
||||
// only ever runs natively, so a chained call into it (at any depth)
|
||||
// can still reach the top-level payload here, without any
|
||||
// intermediary guest ever having to carry the bytecode through its
|
||||
// own execution.
|
||||
let bytecode = message.raw_payload.clone().ok_or_else(|| {
|
||||
LeeError::InvalidInput("Deploy requires a raw_payload".into())
|
||||
})?;
|
||||
@@ -186,9 +187,8 @@ impl ValidatedStateDiff {
|
||||
)
|
||||
} else {
|
||||
// The real `image_id`, sourced from the program's own account rather than
|
||||
// guessed from its address — see `V03State::get_program`'s doc comment for
|
||||
// why that distinction matters once a program's address can outlive its
|
||||
// current bytecode (upgrades).
|
||||
// guessed from its address, since a program's address can outlive its current
|
||||
// bytecode (upgrades).
|
||||
let Some((program_id, elf)) = state.get_program(chained_call.program_account_id)?
|
||||
else {
|
||||
return Err(LeeError::InvalidInput("Unknown program".into()));
|
||||
|
||||
@@ -34,18 +34,17 @@ pub enum Instruction {
|
||||
/// transaction — its `ProgramData` header too. One or more `Deploy`s (each covering a
|
||||
/// contiguous range of segments) complete a deployment or an upgrade; a non-self-contained
|
||||
/// one always needs a following [`Instruction::Finalize`] before the program is
|
||||
/// dispatchable again — see [`execute_deploy`] for exactly what each transaction requires.
|
||||
/// dispatchable again.
|
||||
///
|
||||
/// The bytecode itself travels via the dispatching message's `raw_payload`, not this
|
||||
/// instruction — see `Message::raw_payload`'s doc comment for why.
|
||||
/// instruction.
|
||||
///
|
||||
/// Required accounts, in order:
|
||||
/// - The target `ProgramData` header PDA account (`Account::default()` for a program's very
|
||||
/// first `Deploy`, or its already-existing header for any later batch, continuation, or
|
||||
/// upgrade — see [`execute_deploy`])
|
||||
/// upgrade)
|
||||
/// - Unless this transaction is both self-contained *and* the program's very first `Deploy`: an
|
||||
/// account matching the authority that must sign this write (see [`execute_deploy`]),
|
||||
/// `is_authorized`
|
||||
/// account matching the authority that must sign this write, `is_authorized`
|
||||
/// - The target segment PDA accounts this transaction covers (`first_segment, first_segment+1,
|
||||
/// ...`), in order — each `Account::default()` for a program's first deploy, or (for an
|
||||
/// upgrade) either `Account::default()` or already-populated
|
||||
@@ -56,7 +55,7 @@ pub enum Instruction {
|
||||
/// trusts a caller's own claim about a program's genesis pair once its header already
|
||||
/// exists — it reads `ProgramData::genesis_image_id`/`genesis_update_auth` straight out
|
||||
/// of the header's own account data instead, so there's no way for a transaction to even
|
||||
/// declare a wrong or stale genesis pair for an existing program. See [`Genesis`].
|
||||
/// declare a wrong or stale genesis pair for an existing program.
|
||||
genesis: Option<Genesis>,
|
||||
/// `segment_number` of this transaction's first segment (0-indexed); its remaining
|
||||
/// segment accounts are `first_segment, first_segment+1, ...` in order.
|
||||
@@ -96,11 +95,11 @@ pub enum Instruction {
|
||||
}
|
||||
|
||||
/// A program's genesis identity — the address-derivation salt fixed forever at its first
|
||||
/// `Deploy`. See [`Instruction::Deploy::genesis`] and [`ProgramData`]'s doc comment.
|
||||
/// `Deploy`.
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
pub struct Genesis {
|
||||
pub image_id: ProgramId,
|
||||
/// `None` means immutable from birth — see `ProgramData::genesis_update_auth`.
|
||||
/// `None` means immutable from birth.
|
||||
pub update_auth: Option<AccountId>,
|
||||
}
|
||||
|
||||
@@ -152,13 +151,12 @@ pub fn compute_image_id(user_elf: &[u8]) -> anyhow::Result<ProgramId> {
|
||||
/// Derives the PDA seed for a deployed program's `ProgramData` header account.
|
||||
///
|
||||
/// Combines the program's genesis identity (`genesis_image_id`), `segment_number` (always `0`
|
||||
/// for a header — unrelated to how many bytecode segments the program's data spans, see
|
||||
/// [`plan_deploy`]; kept as a parameter only because it shares this shape with
|
||||
/// [`deploy_segment_pda_seed`]), and `genesis_update_auth` — included so multiple independent
|
||||
/// deployments of identical bytecode land at distinct accounts instead of colliding. Fixed
|
||||
/// forever once a program's header is created; never re-derived from its *current*
|
||||
/// `image_id`/`update_auth`, which may change across upgrades — see [`ProgramData`]'s doc
|
||||
/// comment.
|
||||
/// for a header — unrelated to how many bytecode segments the program's data spans; kept as a
|
||||
/// parameter only because it shares this shape with [`deploy_segment_pda_seed`]), and
|
||||
/// `genesis_update_auth` — included so multiple independent deployments of identical bytecode
|
||||
/// land at distinct accounts instead of colliding. Fixed forever once a program's header is
|
||||
/// created; never re-derived from its *current* `image_id`/`update_auth`, which may change
|
||||
/// across upgrades.
|
||||
///
|
||||
/// Domain-separated from other PDA-seed derivations in the codebase, including
|
||||
/// [`deploy_segment_pda_seed`], so a header seed can never collide with a segment seed (or
|
||||
@@ -258,9 +256,8 @@ pub fn deploy_segment_account_id(
|
||||
/// `segment_count`, so [`immutable_deploy_account_id`] stays stable regardless of how a deploy is
|
||||
/// batched) plus `batch_user_elf` chunked at [`MAX_SEGMENT_DATA_LEN`], numbered `first_segment,
|
||||
/// first_segment+1, ...`. `genesis_image_id`/`genesis_update_auth` are always the program's
|
||||
/// genesis pair (see [`ProgramData`]'s doc comment) — this function only computes *addresses*
|
||||
/// (and the segment byte chunks), never the header's current-state fields, since those depend on
|
||||
/// whether the header already exists; see [`execute_deploy`] for that.
|
||||
/// genesis pair — this function only computes *addresses* (and the segment byte chunks), never
|
||||
/// the header's current-state fields, since those depend on whether the header already exists.
|
||||
///
|
||||
/// `segment_count` is the *total* as of this write, not just this batch. [`plan_deploy`] is the
|
||||
/// single-batch (whole program, `first_segment` 0) special case of this — the single source of
|
||||
@@ -282,7 +279,7 @@ pub fn plan_deploy_range(
|
||||
// Only used by the fresh-header path in `execute_deploy` and by `V03State::insert_program`
|
||||
// — filled in with the real current-state fields there. Placeholder shape here just so
|
||||
// `PlannedAccount::data` always exists for the header like it does for a segment; not
|
||||
// meant to be written verbatim by an upgrade/continuation batch (see `execute_deploy`).
|
||||
// meant to be written verbatim by an upgrade/continuation batch.
|
||||
data: Vec::new(),
|
||||
};
|
||||
|
||||
@@ -318,8 +315,6 @@ pub fn plan_deploy_range(
|
||||
|
||||
/// Computes the account shape (header + N bytecode segments) for deploying the whole of `user_elf`
|
||||
/// at `genesis_image_id` under `genesis_update_auth` in a single, self-contained batch.
|
||||
///
|
||||
/// See [`plan_deploy_range`].
|
||||
#[must_use]
|
||||
pub fn plan_deploy(
|
||||
loader_account_id: AccountId,
|
||||
@@ -357,8 +352,7 @@ pub fn segment_count_for(user_elf: &[u8]) -> u32 {
|
||||
///
|
||||
/// `segment_number` 0, `update_auth` `None`. What every genesis-seeded builtin, and any immutable
|
||||
/// (non-upgradeable) `Deploy`, dispatches at. For an upgradeable program this is **not** the
|
||||
/// dispatch address — see [`deploy_header_account_id`] with the program's real genesis pair
|
||||
/// instead.
|
||||
/// dispatch address.
|
||||
#[must_use]
|
||||
pub fn immutable_deploy_account_id(image_id: ProgramId) -> AccountId {
|
||||
deploy_header_account_id(
|
||||
@@ -391,33 +385,26 @@ fn pass_through_signer(target: &AccountWithMetadata) -> AccountPostState {
|
||||
/// a multi-transaction one.
|
||||
///
|
||||
/// `genesis` must be `Some` if and only if the header doesn't exist yet (a program's very first
|
||||
/// `Deploy`) — see [`Instruction::Deploy::genesis`]. Once a header exists, its own stored
|
||||
/// `genesis_image_id`/`genesis_update_auth` are used for every address computation instead;
|
||||
/// nothing about a program's genesis identity is ever taken from a caller's declaration once
|
||||
/// there's a header to read it from.
|
||||
/// `Deploy`). Once a header exists, its own stored `genesis_image_id`/`genesis_update_auth` are
|
||||
/// used for every address computation instead — nothing about a program's genesis identity is
|
||||
/// ever taken from a caller's declaration once there's a header to read it from.
|
||||
///
|
||||
/// Whether this transaction needs a real, checked authorization depends on two independent
|
||||
/// things: whether it delivers the *whole* program in one shot (`first_segment == 0` and
|
||||
/// `user_elf_batch` covers all `segment_count` segments — i.e. "self-contained"), and whether the
|
||||
/// header already exists (i.e. this program has been written to before, whether finalized or
|
||||
/// not):
|
||||
/// Whether this transaction needs a real, checked authorization depends on two things: whether it
|
||||
/// delivers the *whole* program in one shot (`first_segment == 0` and `user_elf_batch` covers all
|
||||
/// `segment_count` segments — "self-contained"), and whether the header already exists:
|
||||
///
|
||||
/// - **Self-contained *and* the header doesn't exist yet (a brand-new program)**: no signature
|
||||
/// required. `user_elf_batch` is independently decoded and its real `image_id` recomputed
|
||||
/// (combined with the assumed [`KERNEL_ELF`]) and checked against the declared one right here.
|
||||
/// The header is written with `genesis_image_id`/`genesis_update_auth` equal to the declared
|
||||
/// values, `current_image_id` set directly to the verified real `image_id` (no separate
|
||||
/// [`finalize`] needed), and `program_version` `1`.
|
||||
/// values, `current_image_id` set directly to the verified real `image_id`, and `program_version`
|
||||
/// `1`.
|
||||
/// - **Everything else** (a partial batch of a brand-new deploy, or *any* write once the header
|
||||
/// already exists — a continuation of an unfinalized initial deploy, or a genuine upgrade of an
|
||||
/// already-finalized one): self-verification can't establish authorization to overwrite
|
||||
/// whatever's already there, so a real signer is always required, regardless of size. If the
|
||||
/// header doesn't exist yet, that authority is this instruction's own declared genesis
|
||||
/// `update_auth`, which must be `Some` — there is no key to sign a partial deploy of an
|
||||
/// otherwise-immutable program with. If the header already exists, that authority is whatever its
|
||||
/// *current* `ProgramData::update_auth` says (which may have diverged from the genesis value via
|
||||
/// [`Instruction::RotateUpdateAuth`], and must likewise be `Some` — a program with no authority
|
||||
/// at all, immutable from birth or by renouncement, can never be written to again). Either way,
|
||||
/// already exists): self-verification can't establish authorization to overwrite whatever's
|
||||
/// already there, so a real signer is always required. That authority is this instruction's own
|
||||
/// declared genesis `update_auth` if the header doesn't exist yet, or the header's *current*
|
||||
/// `ProgramData::update_auth` otherwise — either way it must be `Some`, since a program with no
|
||||
/// authority at all (immutable from birth or by renouncement) can never be written to again.
|
||||
/// `current_image_id` is left at (or reset to) [`UNFINALIZED_IMAGE_ID`]; a [`finalize`] is
|
||||
/// required afterward.
|
||||
///
|
||||
@@ -427,8 +414,8 @@ fn pass_through_signer(target: &AccountWithMetadata) -> AccountPostState {
|
||||
/// `Account::default()` (this upgrade grew the segment count) or already-populated (this upgrade
|
||||
/// is overwriting it) — both are fine, since authorization was already established above.
|
||||
///
|
||||
/// Called natively from dispatch's `RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID` shortcut (see that
|
||||
/// constant's doc comment in `lee_core::program`) — `Deploy` has no guest binary of its own.
|
||||
/// Called natively from dispatch's `RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID` shortcut — `Deploy`
|
||||
/// has no guest binary of its own.
|
||||
#[must_use]
|
||||
pub fn execute_deploy(
|
||||
self_account_id: AccountId,
|
||||
@@ -543,8 +530,8 @@ pub fn execute_deploy(
|
||||
);
|
||||
}
|
||||
|
||||
// pre_states/post_states are matched positionally (see validate_execution), so an
|
||||
// update_auth signer slot present in pre_states must get a matching entry here too.
|
||||
// pre_states/post_states are matched positionally, so an update_auth signer slot present in
|
||||
// pre_states must get a matching entry here too.
|
||||
let update_auth_post_state = update_auth_target.map(pass_through_signer);
|
||||
|
||||
let header_post_state = if header_is_fresh {
|
||||
@@ -1117,9 +1104,8 @@ mod tests {
|
||||
assert_eq!(header_data2.current_image_id, UNFINALIZED_IMAGE_ID);
|
||||
}
|
||||
|
||||
/// Deploys `program` across two batches (so it lands unfinalized, exactly like
|
||||
/// `execute_deploy_two_batch_sequence_leaves_it_unfinalized`), then returns everything needed
|
||||
/// to either finalize it or feed it back into another `execute_deploy`/`finalize`/
|
||||
/// Deploys `program` across two batches, so it lands unfinalized, then returns everything
|
||||
/// needed to either finalize it or feed it back into another `execute_deploy`/`finalize`/
|
||||
/// `rotate_update_auth` call: the plan, the header account as it exists on-chain, and every
|
||||
/// segment account as it exists on-chain (all real, populated bytes).
|
||||
fn deploy_unfinalized_across_two_batches(
|
||||
@@ -1280,10 +1266,8 @@ mod tests {
|
||||
}
|
||||
|
||||
/// Deploys `program` in one self-contained transaction with a real `update_auth` — no
|
||||
/// signature needed (per
|
||||
/// `execute_deploy_single_batch_finalizes_atomically_even_with_real_update_auth`),
|
||||
/// and already live (`current_image_id` real, `program_version` 1) with no separate
|
||||
/// `finalize` required. Returns the plan and the on-chain header/segment accounts.
|
||||
/// signature needed, and already live (`current_image_id` real, `program_version` 1) with no
|
||||
/// separate `finalize` required. Returns the plan and the on-chain header/segment accounts.
|
||||
fn deploy_and_finalize_in_one_shot(
|
||||
full_binary: &[u8],
|
||||
image_id: ProgramId,
|
||||
|
||||
@@ -4394,9 +4394,7 @@ fn loader_rejects_a_partial_deploy_batch_without_a_valid_signature() {
|
||||
|
||||
/// Once a header exists, the authorized `update_auth` can change the declared `segment_count`
|
||||
/// between batches (a new version may need more or fewer segments than the last) — this is the
|
||||
/// same mechanism upgrades use, not a distinct "racing" bug. Unauthorized third parties still
|
||||
/// can't touch an existing header at all — see
|
||||
/// `loader_rejects_an_unauthorized_party_touching_an_existing_header`.
|
||||
/// same mechanism upgrades use, not a distinct "racing" bug.
|
||||
#[test]
|
||||
fn loader_allows_the_authorized_party_to_change_segment_count_mid_sequence() {
|
||||
let mut state = V03State::new();
|
||||
@@ -4554,8 +4552,7 @@ fn loader_allows_the_authorized_party_to_rewrite_a_segment() {
|
||||
/// A program that wants to chain-call `Deploy` never has to carry the bytecode through its own
|
||||
/// execution: `Deploy` only ever runs natively, so the dispatcher resolves its `raw_payload`
|
||||
/// straight from the top-level transaction regardless of chain-call depth, and the forwarder here
|
||||
/// only ever handles a small `instruction_data` (see
|
||||
/// `lee::state_machine::validated_state_diff`'s `Deploy` dispatch branch).
|
||||
/// only ever handles a small `instruction_data`.
|
||||
#[test]
|
||||
fn loader_deploys_program_via_chained_call() {
|
||||
let forwarder = test_programs::chained_call_forwarder();
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user