Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

$$ \newcommand \EC {\mathrm{EC}} $$

Transition Function

The Evaluation Cycle is the fundamental process by which a program \( \EC_P \) is executed in the Algorand Virtual Machine (AVM).

Starting from an initial Evaluation Context \( \EC \), it applies the step() function repeatedly to progress through the program’s instructions.

Based on the program’s logic and runtime behavior, this cycle ultimately determines whether a transaction is:

  • REJECTED: Discarded and ignored, or

  • APPROVED: Accepted, either pushed into the Transaction Pool or validated during block assembly or verification.

Step Function Flow

The step() function powers AVM state transitions between successive \( \EC \) states. It encapsulates the execution logic for a single opcode and performs multiple validations at each step.

Below is a diagram that visualizes the logic flow of a single step() invocation:

flowchart TD
  Start(["Start **step()**"]):::cend

  %% Decision Nodes
  CheckNextOpcode{{"Does **nextOpcode()** exist, is allowed, and validated?"}}:::decision
  CheckBudget{{"Is **EC.Budget** > **MaxBudget**?"}}:::decision
  ValidateStack{{"Validate stack size and element constraints"}}:::decision

  %% Action Nodes
  DispatchNextOpcode["Dispatch **nextOpcode** (observe changes)"]:::action
  UpdateTxnCost["Update transaction cost with **txnCostUpdate()**"]:::action
  UpdatePC["Update program counter **EC.PC()** to next instruction"]:::action

  %% Reject Node
  RejectFromValidation["**REJECT()**"]:::reject

  %% End Node
  End(["**End Step()**"]):::cend

  %% Connections
  Start --> CheckNextOpcode
  CheckNextOpcode -->|Yes| DispatchNextOpcode
  CheckNextOpcode -->|No| RejectFromValidation
  DispatchNextOpcode --> UpdateTxnCost
  UpdateTxnCost --> CheckBudget
  CheckBudget -->|Yes| RejectFromValidation
  CheckBudget -->|No| ValidateStack
  ValidateStack -->|Valid| UpdatePC
  ValidateStack -->|Invalid| RejectFromValidation
  UpdatePC --> End

  %% Styling
  classDef decision stroke:#FFFF,stroke-width:2px
  classDef action stroke:#FFFFFF,stroke-width:2px
  classDef cend stroke:#FFFF,stroke-width:2px
  classDef reject fill:#FF6347,stroke:#FFF,stroke-width:2px

⚙️ IMPLEMENTATION

Step function reference implementation.

Step-by-Step Execution

  1. Opcode Fetch and Validation
    The function begins by checking whether the next opcode (determined by PC()) exists, is permitted under the current AVM version, and passes static validation. If any of these checks fail, the transaction is immediately REJECTED.

  2. Opcode Dispatch
    If the opcode is valid, the AVM dispatches the corresponding handler (see AVM operation definitions). Handlers may perform additional runtime validations and update the execution state. Errors encountered here also cause the transaction to be immediately REJECTED.

  3. Cost Update
    After executing the opcode, the transaction’s cost is updated. If the accumulated cost exceeds the allowed execution budget, the transaction is REJECTED.

  4. Stack Validation
    The stack is then validated to ensure:

    • It does not exceed the maximum allowed size.

    • All pushed values are valid StackValue types (either uint64 or []byte with length less than \( 4096 \) bytes).

    An invalid stack state causes the transaction to be REJECTED.

  5. Program Counter Update
    Finally, if all validations pass, the program counter PC() is incremented to point to the next instruction, and the current step concludes.

Final State Evaluation

After each step(), the Evaluation Cycle checks if the program has reached a terminal state. This happens if:

  • Error Occurs:
    Any failure during step() leads to immediate REJECTION of the transaction.

  • End of Program:
    If PC() points beyond the end of the program bytecode \( \EC_P \), the cycle evaluates the final stack:

    • If the stack contains exactly one non-zero value, the transaction is APPROVED.

    • Otherwise, the transaction is REJECTED.

Opcodes like return internally sanitize the stack (e.g., popping all elements except the top result) to comply with these final stack requirements before ending execution.