linera-io/linera-protocol · error · EvmExecutionError

It is illegal to call function summarize_events from an oper

Error message

It is illegal to call function summarize_events from an operation

What it means

Third guard in forbid_execute_operation_origin (used by execute_operation and init_transact): the operation calldata's 4-byte selector must not equal SUMMARIZE_EVENTS_SELECTOR, the function the system calls on a checkpoint and never from a submitted operation. Operations carrying that selector are rejected before execution, keeping checkpoint summarization system-only.

Source

Thrown at linera-execution/src/evm/inputs.rs:177

/// This is the selector of `summarize_events`, which is called by the system on a
/// checkpoint and never from a submitted operation.
pub(crate) const SUMMARIZE_EVENTS_SELECTOR: &[u8] =
    &<summarize_eventsCall as alloy_sol_types::SolCall>::SELECTOR;

/// This is the selector of `instantiate` that should be called
/// only when creating a new instance of a shared contract
pub(crate) const INSTANTIATE_SELECTOR: &[u8] = &[156, 163, 60, 158];

pub(crate) fn forbid_execute_operation_origin(vec: &[u8]) -> Result<(), EvmExecutionError> {
    ensure!(
        vec != EXECUTE_MESSAGE_SELECTOR,
        EvmExecutionError::IllegalOperationCall("function execute_message".to_string(),)
    );
    ensure!(
        vec != PROCESS_STREAMS_SELECTOR,
        EvmExecutionError::IllegalOperationCall("function process_streams".to_string(),)
    );
    ensure!(
        vec != SUMMARIZE_EVENTS_SELECTOR,
        EvmExecutionError::IllegalOperationCall("function summarize_events".to_string(),)
    );
    ensure!(
        vec != INSTANTIATE_SELECTOR,
        EvmExecutionError::IllegalOperationCall("function instantiate".to_string(),)
    );
    Ok(())
}

pub(crate) fn ensure_message_length(
    actual_length: usize,
    min_length: usize,
) -> Result<(), EvmExecutionError> {
    ensure!(
        actual_length >= min_length,
        EvmExecutionError::OperationIsTooShort
    );

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Rename the function or change its signature so the selector differs
  2. Do not expose system checkpoint entry points as user-callable; mark them internal/only-system
  3. Validate the selector prefix of every operation payload before submission

Example fix

// Solidity: hide the system entry point from user calls
// before
function summarize_events() external returns (bytes32) { ... }
// after
function summarize_events() internal view returns (bytes32) { ... }
Defensive patterns

Strategy: validation

Validate before calling

fn targets_summarize_events(calldata: &[u8], summarize_events_selector: [u8; 4]) -> bool {
    calldata.get(..4) == Some(&summarize_events_selector[..])
}

// compute the selector from your contract ABI, e.g. keccak("summarize_events(...)")[..4]
assert!(!targets_summarize_events(&operation_calldata, selector));

Type guard

fn is_illegal_summarize_events_call(err: &ExecutionError) -> bool {
    matches!(
        err,
        ExecutionError::EvmError(evm_error!::IllegalOperationCall(ref f)) if f.contains("summarize_events")
    )
}

Try / catch

match client.execute_operations(ops, vec![]).await {
    Err(e) if is_illegal_summarize_events_call(&e) => {
        Err(anyhow::anyhow!("operation targets reserved summarize_events selector: {e}"))
    }
    other => other,
}

Prevention

When it happens

Trigger: An EVM operation or transact request whose calldata starts with the summarize_events selector — a contract exposing a same-named function that a user tries to invoke via an operation, or an unrelated function whose ABI selector collides.

Common situations: Checkpoint-aware contracts re-exporting the summarize_events ABI as callable; generated bindings that expose system entry points as ordinary functions; 4-byte collisions in contracts with many external functions.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/a7e426acf6dcca27. Report an issue: GitHub.