linera-io/linera-protocol · error · WorkerError

Fast blocks cannot query oracles

Error message

Fast blocks cannot query oracles

What it means

Fast rounds let super owners finalize blocks without a full quorum, so validators must be able to verify the block purely from its content. After executing the proposal, try_handle_block_proposal checks that a fast-round block produced no oracle responses (block.has_oracle_responses()); any oracle query in the outcome makes fast-path validation impossible and the proposal is rejected with FastBlockUsingOracles.

Source

Thrown at linera-core/src/chain_worker/state.rs:2648

        self.chain
            .remove_bundles_from_inboxes(block.timestamp, true, block.incoming_bundles())
            .await?;
        let block = if let Some(outcome) = outcome {
            outcome.clone().with(proposal.content.block.clone())
        } else {
            let (executed_block, _resource_tracker, _) = Box::pin(self.execute_block(
                block.clone(),
                local_time,
                round.multi_leader(),
                &published_blobs,
                BlockExecution::HandleProposal,
            ))
            .await?;
            executed_block
        };

        ensure!(
            !round.is_fast() || !block.has_oracle_responses(),
            WorkerError::FastBlockUsingOracles
        );
        let chain = &mut self.chain;
        // Don't save the changes since the block is not confirmed yet.
        chain.rollback();

        // Create the vote and store it in the chain state.
        let blobs = self
            .get_required_blobs(proposal.expected_blob_ids(), block.created_blobs())
            .await?;
        let key_pair = self.config.key_pair();
        let manager = &mut self.chain.manager;
        match manager.create_vote(&proposal, block, key_pair, local_time, blobs)? {
            // Cache the value we voted on, so the client doesn't have to send it again.
            Some(Either::Left(vote)) => {
                self.block_values
                    .insert_hashed(Cow::Borrowed(vote.value.inner()));

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Propose oracle-using blocks in a multi-leader or single-leader round instead of Round::Fast.
  2. Split the block: oracle-free operations may go fast, oracle queries go through a regular round.
  3. After trial execution, check has_oracle_responses() on the outcome and downgrade the round before submitting.

Example fix

// before: fast round for a block that queries oracles
let round = Round::Fast;

// after: choose the round based on the trial outcome
let executed = trial_execute(&block).await?;
let round = if executed.has_oracle_responses() {
    Round::MultiLeader(0)
} else {
    Round::Fast
};
Defensive patterns

Strategy: validation

Validate before calling

// After trial execution, before settling on the fast round.
if round.is_fast() && executed_block.has_oracle_responses() {
    // Downgrade to a regular round; validators will reject a fast submission.
    round = Round::MultiLeader(0);
}

Type guard

// Fast-round eligibility check on an executed block.
fn is_fast_round_safe(block: &Block) -> bool {
    !block.has_oracle_responses()
}

Try / catch

match node.handle_block_proposal(proposal).await {
    Err(NodeError::WorkerError(err)) if matches!(*err, WorkerError::FastBlockUsingOracles) => {
        // Re-propose the same block in a non-fast round (e.g. MultiLeader(0)).
    }
    result => result,
}

Prevention

When it happens

Trigger: Proposing in Round::Fast a block whose execution queries oracles (time or benchmark queries, application service oracles); oracle-dependent operations left inside a block that a super owner submits as fast.

Common situations: Applications that routinely query oracles (timers, price feeds, application oracles) and default to fast proposals on super-owner chains; tests reusing fast blocks that gained oracle-reading operations after an app upgrade.

Related errors


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