---
title: Account Model
description: Complete specification of Thru's account structure, metadata,
  ownership model, and limitations
source_url:
  html: https://thru.org/docs/spec/accounts/account-model/
  md: https://thru.org/docs/spec/accounts/account-model.md
---

# Account Model

Accounts are the fundamental units of state in the Thru network. They serve as containers for data, code, and value, enabling programs to store persistent information and users to hold tokens. All network state is organized around accounts, from user wallets and program code to application data and system configuration.

Thru implements an account model that manages state, ownership, and data for all entities on the network. Each account is uniquely identified by a 32-byte public key and contains metadata and arbitrary data that programs can read and modify. See [Account Addresses](https://thru.org/docs/spec/accounts/addresses.md) for more information about how account addresses are determined.

## Account Structure

Each account consists of two main components: runtime metadata that defines the account’s properties and permissions, followed by variable-length data that can be up to 16MB in size. The metadata contains essential information like ownership, balance, and behavioral flags, while the data section stores arbitrary information that programs can read and modify.

### Account Metadata

On chain, the runtime stores a 64-byte internal metadata header. The public C SDK exposes a packed `tsdk_account_meta_t` view without the runtime-only `magic` field. This page uses the SDK-facing names unless otherwise noted.

**`version` · *uint8* · **required****

Account format version. Currently supports version 1 (`TN_ACCOUNT_V1 = 0x01`).

**`flags` · *uint8* · **required****

Bitfield controlling account behavior and permissions.

Account Flag Values

**`TSDK_ACCOUNT_FLAG_PROGRAM` · *0x01***

Marks the account as an executable program. Program accounts contain bytecode that can be executed by the Thru VM.

**`TSDK_ACCOUNT_FLAG_PRIVILEGED` · *0x02***

Indicates the account has special system privileges. Reserved for system contracts and core infrastructure.

**`TSDK_ACCOUNT_FLAG_UNCOMPRESSABLE` · *0x04***

Prevents the account from being compressed in state trees. Used for frequently accessed accounts.

**`TSDK_ACCOUNT_FLAG_EPHEMERAL` · *0x08***

Marks the account as temporary. Ephemeral accounts can be garbage collected when deleted.

**`TSDK_ACCOUNT_FLAG_DELETED` · *0x10***

Indicates the account has been deleted but may still exist in compressed form.

**`TSDK_ACCOUNT_FLAG_NEW` · *0x20***

Marks newly created accounts. Used during transaction processing to track state changes.

**`TSDK_ACCOUNT_FLAG_COMPRESSED` · *0x40***

Indicates the account is stored in compressed state trees rather than active state.

**`data_sz` · *uint32* · **required****

Size of the account’s data in bytes. Maximum value is 16MB (`TN_ACCOUNT_DATA_SZ_MAX = 16,777,216`).

**`seq` · *uint64* · **required****

Account sequence number that is incremented each time the account is modified during transaction execution. The sequence is updated at the end of the transaction for accounts that were modified.

**`owner` · *tn\_pubkey\_t* · **required****

32-byte public key of the program that owns this account. Only the owner program can modify account data.

**`balance` · *uint64* · **required****

Account balance in the network’s native token. Used for transaction fees and transfers.

**`nonce` · *uint64* · **required****

Transaction nonce for replay protection. Must match the transaction nonce exactly for fee payer accounts. See [Transaction Execution](https://thru.org/docs/spec/runtime/transaction-execution.md) for more details.

### Account Data

Following the 64-byte metadata header, accounts can store up to 16MB of arbitrary data that programs can read and modify through direct memory access in the VM.

> **Note:**
>
> For detailed information about how programs access account data in memory, see the [VM Memory Layout](https://thru.org/docs/spec/vm/memory-layout.md#account-data) documentation.

```c
struct __attribute__(( packed )) tsdk_account_meta {
  uchar       version;        /* Account format version */
  uchar       flags;          /* Behavior flags bitfield */
  uint        data_sz;        /* Data size in bytes */
  ulong       seq;            /* Account sequence number */
  tn_pubkey_t owner;          /* Owner program public key */
  ulong       balance;        /* Balance in native tokens */
  ulong       nonce;          /* Transaction nonce */
};
```

## Ownership Model

### Program Ownership

Every account is owned by exactly one program, identified by the `owner` field in the account metadata. Ownership is permanent and cannot be transferred. Only the owner program can:

- Modify account data during transaction execution
- Change account metadata (except balance and nonce)
- Delete the account by setting the `TSDK_ACCOUNT_FLAG_DELETED` flag

In almost all cases, the owner of an account is the program that created it. The exception is for accounts owned by the externally owned account (EOA) program, which may be created by any program.

### Externally Owned Accounts

Externally owned accounts (EOAs), also known as user accounts, are owned by the externally owned account program, which is located at the address `0` (all zeros). They can be accessed by using the private key corresponding to their address. EOAs are created using [`tsys_account_create_eoa()`](https://thru.org/docs/spec/vm/syscalls/account_create_eoa.md) with signature verification to prove ownership of the private key.

## Account Types

Thru supports two fundamental account types that determine their lifecycle and storage characteristics:

**Permanent Accounts:**

**Purpose**: Long-lived accounts that persist in the network state indefinitely.

**Characteristics**:

- Default account type (no special flags required)
- Require state proofs for creation to prevent conflicts
- Persist in state trees even when deleted
- Can be compressed to optimize storage
- Support all account flags and operations

**Lifecycle**:

- Created with [`tsys_account_create()`](https://thru.org/docs/spec/vm/syscalls/account_create.md) using state proofs
- When deleted, account is completely removed but can be recreated without another state proof for a time before compression
- Newly created accounts that have never existed before can be deleted like ephemeral accounts

**Common Use**:

- User wallets and token accounts
- Program accounts containing executable code
- Application data and state storage
- System contracts and infrastructure

**Ephemeral Accounts:**

**Purpose**: Temporary accounts designed for short-term operations and automatic cleanup.

**Characteristics**:

- Marked with `TSDK_ACCOUNT_FLAG_EPHEMERAL`
- No state proof required for creation
- Cannot hold funds
- Compressing an ephemeral account deletes it, and anyone can compress it

**Lifecycle**:

- Created with [`tsys_account_create_ephemeral()`](https://thru.org/docs/spec/vm/syscalls/account_create_ephemeral.md)
- Automatically cleaned up when both ephemeral and deleted flags are set

**Common Use**:

- Storing data temporarily to be used in a later transaction

### Account Purposes

While there are only two fundamental types, accounts serve various purposes based on their flags and ownership:

User Accounts (EOAs)

**Purpose**: Store user funds and serve as transaction fee payers.

**Also known as**: Externally Owned Accounts (EOAs)

**Characteristics**:

- Owned by the externally owned account program at address `0` (all zeros)
- Created with [`tsys_account_create_eoa()`](https://thru.org/docs/spec/vm/syscalls/account_create_eoa.md) using signature verification
- Controlled by the holder of the private key corresponding to the account’s public key address
- Typically have no custom data (data\_sz = 0)
- Used for balance transfers and fee payments

Program Accounts

**Purpose**: Store executable bytecode for smart contracts.

- Marked with `TSDK_ACCOUNT_FLAG_PROGRAM`
- Contain compiled program code in account data
- Upgradable by the configured program authority unless paused or finalized by policy

Data Accounts

**Purpose**: Store arbitrary application state and user data.

- Owned by specific programs that can modify them
- Most flexible storage option up to 16MB
- Used for application state, user profiles, game data

System Accounts

**Purpose**: Core network infrastructure and privileged operations.

- Marked with `TSDK_ACCOUNT_FLAG_PRIVILEGED`
- Special permissions for network-level operations
- Protected from normal program access

## Account Limitations

### Size Constraints

**`Maximum Data Size` · *16MB***

Each account can store at most 16,777,216 bytes of data (`TN_ACCOUNT_DATA_SZ_MAX`).

### Access Permissions

Read Access

Any program can read account metadata and data from accounts included in the transaction.

Write Access

Only the owner program can modify account data. System operations can modify balance and nonce fields.

Creation Rights

New accounts can only be created by their designated owner program during transaction execution.

## Account Lifecycle

### Creation

Programs create accounts using the system call interface:

1. **Create Account**

   Use `tsys_account_create()` or `tsys_account_create_ephemeral()` to create a new account:

   ```c
   // Create a new account with state proof
   ulong result = tsys_account_create(account_idx, seed, proof, proof_sz);

   // Create ephemeral account (no state proof required)
   ulong result = tsys_account_create_ephemeral(account_idx, seed);
   ```

   > **Note:**
   >
   > For detailed syscall documentation, see the [System Calls reference](https://thru.org/docs/spec/vm/syscalls/overview.md).

   > **Tip:**
   >
   > The account is immediately available for use within the same transaction.

2. **Set Initial Size**

   If the account needs data storage, resize it using `tsys_account_resize()`:

   ```c
   ulong result = tsys_account_resize(account_idx, new_size);
   ```

   > **Note:**
   >
   > See [`tsys_account_resize()`](https://thru.org/docs/spec/vm/syscalls/account_resize.md) for complete parameter details.

### Active State

Active accounts exist in the current state and can be:

- Read by any program in transactions that include them
- Modified by their owner program through direct memory access
- Transferred funds using [`tsys_account_transfer()`](https://thru.org/docs/spec/vm/syscalls/account_transfer.md)
- Resized using [`tsys_account_resize()`](https://thru.org/docs/spec/vm/syscalls/account_resize.md)
- Used as data storage for applications

> **Note:**
>
> An account is considered active if it’s not compressed and not both ephemeral and deleted.

### Compression

Programs can compress accounts to optimize state storage using the compression syscalls:

```c
// Compress an account with state proof
ulong result = tsys_account_compress(account_idx, proof, proof_sz);

// Decompress an account with metadata, data, and proof
ulong result = tsys_account_decompress(account_idx, meta, data, proof, proof_sz);
```

> **Note:**
>
> See [`tsys_account_compress()`](https://thru.org/docs/spec/vm/syscalls/account_compress.md) and [`tsys_account_decompress()`](https://thru.org/docs/spec/vm/syscalls/account_decompress.md) for detailed usage.

**Ephemeral Account Compression**

For ephemeral accounts, compression behaves differently:

- Calling `tsys_account_compress()` on an ephemeral account immediately deletes it instead of compressing
- **Relaxed permissions**: Any program can compress (delete) an ephemeral account if it’s writable in the transaction
- **No ownership check**: Unlike `tsys_account_delete()`, compression doesn’t require the current program to own the account
- No state proof required since the account is simply removed

> **Caution:**
>
> Compressed accounts are not accessible by programs and cannot be directly modified. They must be decompressed by providing the account data and a state proof to re-upload them to active state.

### Deletion

1. **Delete Account**

   Programs delete accounts using the deletion syscall:

   ```c
   ulong result = tsys_account_delete(account_idx);
   ```

   This sets the `TSDK_ACCOUNT_FLAG_DELETED` flag, making the account data inaccessible.

   > **Note:**
   >
   > See [`tsys_account_delete()`](https://thru.org/docs/spec/vm/syscalls/account_delete.md) for complete documentation.

2. **Ephemeral Cleanup**

   Accounts marked both `TSDK_ACCOUNT_FLAG_EPHEMERAL` and `TSDK_ACCOUNT_FLAG_DELETED` can be garbage collected by the runtime.

3. **Permanent Deletion**

   Non-ephemeral deleted accounts are marked with the `TSDK_ACCOUNT_FLAG_DELETED` flag as a tombstone in the state tree.

## Account Operations

### Balance Transfers

Programs can transfer funds between accounts using the transfer syscall:

```c
// Transfer amount from one account to another
ulong result = tsys_account_transfer(from_account_idx, to_account_idx, amount);
```

> **Note:**
>
> See [`tsys_account_transfer()`](https://thru.org/docs/spec/vm/syscalls/account_transfer.md) for usage details and requirements.

### Flag Management

Programs can modify account flags using the set flags syscall:

```c
// Set account flags (owner program only)
ulong result = tsys_account_set_flags(account_idx, flags);
```

> **Note:**
>
> See [`tsys_account_set_flags()`](https://thru.org/docs/spec/vm/syscalls/account_set_flags.md) for available flags and restrictions.

### Making Accounts Writable

Before modifying account data, programs must mark accounts as writable:

```c
// Mark account as writable for current transaction
ulong result = tsys_set_account_data_writable(account_idx);
```

> **Note:**
>
> See [`tsys_set_account_data_writable()`](https://thru.org/docs/spec/vm/syscalls/set_account_data_writable.md) for detailed requirements.
