---
title: emit_event
description: Records an event in the transaction's event log
source_url:
  html: https://thru.org/docs/spec/vm/syscalls/emit_event/
  md: https://thru.org/docs/spec/vm/syscalls/emit_event.md
---

# emit_event

## Overview

The `emit_event` syscall records an event in the transaction’s event log. Events are stored in anonymous memory and become part of the transaction’s output for external consumption.

## Syscall Code

**Code:** `0x0D` (`TN_SYSCALL_CODE_EMIT_EVENT`)

## C SDK Function

```c
ulong tsys_emit_event(void const* data, ulong data_sz);
```

## Arguments

**`data` · *void const** · **required***\*

Pointer to the event data to be recorded.

**`data_sz` · *ulong* · **required****

Size of the event data in bytes. Must not exceed the maximum event size.

## Return Value

Returns a syscall result code:

**`Success` · *ulong***

- `TN_VM_SYSCALL_SUCCESS` (0) - Event recorded successfully

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

- `TN_VM_ERR_SYSCALL_EVENT_IS_ZERO_SIZE` (-46) - Event size must be greater than zero
- `TN_VM_ERR_SYSCALL_EVENT_TOO_LARGE` (-31) - Event size exceeds maximum allowed
- `TN_VM_ERR_SYSCALL_INVALID_ADDRESS` (-22) - Invalid virtual address for event data
- `TN_VM_ERR_SYSCALL_INSUFFICIENT_PAGES` (-26) - Not enough pages to expand event storage

## Resource Consumption

### Compute Units

- **Base cost**: `TN_VM_SYSCALL_BASE_COST` (512 units)
- **Event cost**: Additional units equal to event data size in bytes
- **Total formula**: `base_cost + data_sz`

### Memory Pages

- **Event storage**: Pages allocated for event storage in anonymous memory segment
- **Automatic expansion**: Event storage segment grows as needed (page-aligned)
- **Metadata overhead**: Additional space for event metadata per event

## Side Effects

- **Event storage**: Copies event data to transaction’s event log
- **Memory allocation**: May expand event storage segment if needed
- **Event counter**: Increments the transaction’s event count

## Event Metadata

The runtime automatically adds internal metadata to each emitted event before exposing it in transaction output. That metadata is not part of the public C SDK surface, so programs should treat the event payload they pass to `tsys_emit_event()` as the only SDK-facing input.

The metadata attached by the runtime includes:

- **Event size**: Size of the event data
- **Call index**: Unique identifier for the program invocation
- **Program account index**: Index of the program that emitted the event

## Storage Management

- Events are stored in a grow-up anonymous memory segment
- Storage automatically expands as needed (page-aligned)
- Events are stored sequentially in the order emitted
- Multiple events can be emitted by the same program

## Size Limitations

- Maximum event size: `UINT_MAX` bytes (4GB)
- Practical limits imposed by available memory pages
- Event storage competes with other memory allocations

## Usage Notes

- Events are included in transaction output for external consumption
- Event order is preserved within the transaction
- Events from different programs are distinguished by metadata
- Event data format is application-defined

## Example

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

// Emit a simple text event
char event_msg[] = "Account created successfully";
ulong result = tsys_emit_event(event_msg, strlen(event_msg));

// Emit structured event data
struct account_created_event {
    uint64_t account_id;
    uint64_t initial_balance;
    char account_type[16];
} event = {
    .account_id = 12345,
    .initial_balance = 1000000,
    .account_type = "savings"
};

result = tsys_emit_event(&event, sizeof(event));

// Emit multiple related events
for (int i = 0; i < transfer_count; i++) {
    struct transfer_event {
        uint64_t from_account;
        uint64_t to_account;
        uint64_t amount;
    } transfer = {
        .from_account = transfers[i].from,
        .to_account = transfers[i].to,
        .amount = transfers[i].amount
    };

    result = tsys_emit_event(&transfer, sizeof(transfer));
    if (result != TN_VM_SYSCALL_SUCCESS) break;
}
```
