---
title: Transaction Execution
description: Documentation for the Thru blockchain.
source_url:
  html: https://thru.org/docs/spec/runtime/transaction-execution/
  md: https://thru.org/docs/spec/runtime/transaction-execution.md
---

# Transaction Execution

Transaction execution in Thru follows a structured four-phase pipeline that ensures consistency, security, and resource management. Each phase has specific responsibilities and failure conditions.

1. **Transaction Validation**

   This phase occurs **before** a transaction can be included in a block. Validation failures result in invalid blocks and consensus rejection.

   **Signature Verification**

   - Transaction signature must be valid for the fee payer’s public key
   - Ed25519 signature verification on transaction payload

   **Account Structure Validation**

   - Account addresses must be properly sorted (read-write accounts in ascending order, then read-only accounts in ascending order - see [transaction format](https://thru.org/docs/spec/core/transactions.md#account-list-verification))
   - No duplicate account addresses across any account lists
   - Total account count must not exceed `TN_TXN_MAX_ACCOUNTS` limit
   - Fee payer and program accounts must be distinct

   **Transaction Format Validation**

   - Transaction version must be supported
   - Transaction flags must be valid
   - Transaction size must not exceed MTU limits

   > **Note:**
   >
   > **Critical**: These validation checks determine block validity. A block containing transactions that fail validation will be rejected by consensus.

2. **Pre-Execution**

   Pre-execution prepares the transaction context and performs economic checks. **If any pre-execution check fails, the transaction is rejected and VM execution does not occur.** Even so, some state changes (nonce advancement, fee collection) may occur during this phase that do persist.

   **Temporal Validation**

   - Current block slot must be ≥ transaction’s `start_slot`
   - Current block slot must be < transaction’s `expiry_slot`

   **Fee Payer Account Setup**

   - Fee payer account must exist or be created with a valid state proof

   - State proof validation (if present):

     - Cryptographic proof verification against current state root
     - Proof type must be `CREATION` or `EXISTING`
     - Proof path must represent valid Merkle tree path

   **Nonce Processing**

   - Transaction nonce must exactly match fee payer’s current nonce
   - **Nonce is advanced immediately** upon validation

   **Fee Processing**

   - Fee payer balance must be sufficient for transaction fee
   - Transaction fee is collected after nonce advancement

   > **Caution:**
   >
   > **Critical**: Nonce advancement occurs **before** fee collection. If fee collection fails due to insufficient balance, the nonce remains advanced but no fee is charged. This prevents replay attacks while allowing transactions to fail gracefully.

3. **VM Execution**

   The virtual machine executes the transaction’s program with strict resource limits and safety constraints.

   **Program Validation**

   - Program account must exist and be marked as executable
   - Program data must be valid bytecode

   **Resource Constraints**

   - **Compute Units**: Execution must not exceed `requested_compute_units` (see [compute units](https://thru.org/docs/spec/runtime/resources.md#compute-units))
   - **Memory**: VM memory access must stay within allocated segments

   **VM Execution Environment**

   - Program runs in isolated VM with segmented memory (`tn_vm_base.h:TN_VM_SEG_*`)

   - System calls provide controlled access to accounts and blockchain state

   - Execution can terminate with success or various fault conditions:

     - `TN_VM_SUCCESS`: Normal completion
     - `TN_VM_FAULT_REVERT`: Program-initiated revert
     - `TN_VM_FAULT_SIGCU`: Compute units exhausted
     - `TN_VM_FAULT_SIGSU`: State units exhausted

   **State Unit Calculation** State units are computed based on account data size changes:

   ```plaintext
   state_bytes_net = max(0, bytes_added - bytes_removed)
   state_units_consumed = ceil(state_bytes_net / TN_RUNTIME_PAGE_SZ)
   ```

4. **Post-Execution**

   Post-execution finalizes state changes and handles compressed account proofs.

   **State Unit Validation**

   - **State Units**: After VM execution, state size changes are calculated and must not exceed `requested_state_units` (see [state units](https://thru.org/docs/spec/runtime/resources.md#state-units))
   - Transactions that exceed state unit limits are failed with `TN_VM_FAULT_SIGSU`

   **State Finalization**

   - Account state changes are committed to storage if execution succeeded
   - Failed executions preserve nonce advancement and fee collection only

   **Account Compression Processing**

   - Accounts that are compressed during execution are removed from the active state set

### Execution Results

The execution result includes:

- `execution_result`: VM exit code
- `compute_units_consumed`: Actual compute units used
- `state_units_consumed`: State units consumed by account changes
- `user_error_code`: Program-specific error information
- `error_program_acc_idx`: Account index of the program that caused the error, useful for identifying the faulting program in cross-program invocation (CPI) scenarios
- Memory fault details (if applicable)

> **Note:**
>
> **Resource Tracking**: All phases track resource consumption to ensure transactions stay within their declared limits and prevent denial-of-service attacks.

## Errors

For detailed error codes and their descriptions, see [Runtime Errors](https://thru.org/docs/spec/runtime/errors.md).
