Skip to content

[execute] Mint-precompile balance changes silently lost on epoch-change early return #296

@keanji-x

Description

@keanji-x

Summary

When a system transaction (metadata or DKG) triggers an epoch change, the early-return path at lib.rs:709-717 / lib.rs:787-795 builds the epoch-change block from inner_state.take_bundle() only. The mint precompile operates on a separate ParallelState (state_for_precompile) that is never drained on these early-return paths.

If any system transaction in the block called the mint precompile (via a contract callback), those minted tokens are permanently lost — the balance increment is silently dropped.

Root cause

Two parallel state databases exist during system transaction execution:

  1. inner_state — used by the EVM for system transactions
  2. state_for_precompile — used by the mint precompile (ParallelState)

On the normal (non-epoch-change) path, precompile state is extracted at L812-842 and merged into accumulated_state_changes. On the epoch-change early-return path, this extraction block is skippedstate_for_precompile_ref is dropped without being read.

Trigger conditions

  1. A system transaction calls a contract that, in turn, calls the mint precompile at NATIVE_MINT_PRECOMPILE_ADDR.
  2. In the same block, metadata or a DKG transaction emits NewEpochEvent.
  3. The early-return path executes before the precompile-state extraction block at L812-842.

Impact

  • Severity: Critical
  • Permanent token loss with no error indication.
  • The on-chain contract logic believes the mint succeeded (EVM returned success), but the receiving account never gets the balance.

Files

  • crates/pipe-exec-layer-ext-v2/execute/src/lib.rs (L659-717, L774-796, L812-842)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions