---
title: invoke
description: Invokes another program with instruction data
source_url:
  html: https://thru.org/docs/spec/vm/syscalls/invoke/
  md: https://thru.org/docs/spec/vm/syscalls/invoke.md
---

# invoke

## Overview

The `invoke` syscall calls another program, creating a new execution frame. This enables cross-program invocation and modularity in the ThruVM runtime.

## Syscall Code

**Code:** `0x0A` (`TN_SYSCALL_CODE_INVOKE`)

## C SDK Function

```c
ulong tsys_invoke(void const* instr_data,
                  ulong instr_data_sz,
                  ushort program_account_idx,
                  tsdk_invoke_auth_t const* auth,
                  ulong* invoke_err_code);
```

## Arguments

**`instr_data` · *void const** · **required***\*

Pointer to the instruction data to pass to the invoked program.

**`instr_data_sz` · *ulong* · **required****

Length of the instruction data in bytes.

**`program_account_idx` · *ushort* · **required****

Index of the program account to invoke. Must be a valid program account.

**`auth` · *tsdk\_invoke\_auth\_t const** · **required***\*

Optional invoke authorization descriptor. Pass `NULL` to use default authorization behavior. When provided, the descriptor is validated by the SDK before the syscall is issued.

**`invoke_err_code` · *ulong** · **required***\*

Pointer to store the error code returned by the invoked program. This will be set to the exit code of the invoked program.

## Return Value

Returns a syscall result code:

**`Success` · *ulong***

- `TN_VM_SYSCALL_SUCCESS` (0) - Program invocation initiated successfully

**`Error Codes` · *ulong***

- `TN_VM_ERR_SYSCALL_INVALID_ACCOUNT_INDEX` (-8) - Program account index out of bounds
- `TN_VM_ERR_SYSCALL_ACCOUNT_DOES_NOT_EXIST` (-9) - Program account does not exist
- `TN_VM_ERR_SYSCALL_ACCOUNT_IS_NOT_PROGRAM` (-17) - Account is not a valid program
- `TN_VM_ERR_SYSCALL_CALL_DEPTH_TOO_DEEP` (-24) - Maximum call depth exceeded

## Resource Consumption

### Compute Units

- **Base cost**: `TN_VM_SYSCALL_BASE_COST` (512 units)

  - Represents the overhead of saving and restoring VM register state

  - **Implementation details**:

    - **Save operation**: All 32 registers (256 bytes) are saved to the public shadow stack
    - **Restore operation**: When returning from the invoked program (via exit syscall), the registers (256 bytes) are restored from the public shadow stack back to the VM
    - **Total memory operations per invoke/exit cycle**: 512 bytes (256 saved + 256 restored)

  - **Cost calculation**: 32 registers × 8 bytes × 2 operations (save + restore) = 512 CUs

- **Additional cost**: None for the invoke syscall itself

- **Note**: The invoked program will consume additional compute units during its execution

### Memory Pages

- **Page usage**: No direct page allocation
- **Shadow stack**: Uses existing shadow stack pages to save execution state
- **Call overhead**: Minimal memory overhead for call frame management

## Side Effects

- **Execution context**: Creates new execution frame and updates call stack

- **Register setup**: Sets a0 to instruction data address, a1 to data length

- **Program counter**: Resets PC to 0 for the new program

- **Call tracking**: Increments frame and call indices

- **Shadow stack**: Saves current execution state on shadow stack

  - Stores all 32 registers (256 bytes) in the public shadow stack
  - Public shadow stack is read-only memory accessible to programs via memory segment 0x0002
  - Preserves program context including stack/heap page counts
  - Creates accessible snapshot for cross-program inspection and state restoration

## Call Stack Management

The syscall manages a call stack with the following updates:

- **Frame index**: Incremented to create new frame
- **Call depth**: Updated to reflect nesting level
- **Shadow stack**: Current state saved for restoration on return
- **Program context**: Switches to the invoked program’s bytecode

## Program Validation

- The target account must have the PROGRAM flag set
- Program bytecode is validated before invocation
- Account must exist and be accessible in the transaction

## Depth Limiting

- Maximum call depth is enforced (`TN_VM_CALL_DEPTH_MAX`)
- Prevents infinite recursion and stack overflow
- Call depth is tracked per execution frame

## Register State

Upon successful invocation:

- **a0**: Set to instruction data virtual address
- **a1**: Set to instruction data length
- **PC**: Reset to 0 (start of invoked program)
- Other registers: Preserved from calling context

## Usage Notes

- Instruction data can be any format understood by the target program

- The invoked program executes with the same transaction context

- Account permissions and writability are preserved

- Return values are passed through program exit mechanisms

- If `auth` is non-`NULL`, SDK-side validation runs before the syscall:

  - bad auth magic: `0xBAD0A170`
  - auth account not owned by current program: `0xBAD0A171`
  - invalid account index in auth/deauth lists: `0xBAD0A173`

## Example

```c
#include <thru-sdk/c/tn_sdk_syscall.h>
#include <stdint.h>

// Invoke a calculator program with operation data
ushort calculator_program_idx = 5;

// Prepare instruction data
struct calc_instruction {
    uint32_t operation;  // 1 = add, 2 = multiply
    uint64_t operand_a;
    uint64_t operand_b;
} instruction = {
    .operation = 1,      // Addition
    .operand_a = 100,
    .operand_b = 200
};

ulong invoke_err = (ulong)-1;
ulong result = tsys_invoke( &instruction,
                            sizeof(instruction),
                            calculator_program_idx,
                            NULL,
                            &invoke_err );

if (result == TN_VM_SYSCALL_SUCCESS && invoke_err == TN_VM_SYSCALL_SUCCESS) {
    // Calculator program is now executing
    // It will receive instruction data in a0, a1
    // Current program state saved on shadow stack
    // Execution will continue in calculator program
}
```
