mainnet formatrent-exempt ROMsha-256 root

/boot/solana/pda-rom

A whole game, held inside a chain.

Arvex stores engine code, maps, sprites, and save-proof metadata inside Solana accounts. PDA chunks stay rent-exempt, while SHA-256 Merkle roots prove the bytes before the canvas ever boots.

PDA chunks

18

Merkle root

locked

RPC read

parallel

Pull it off the chain

Nothing here is cached and nothing is served from this page. Every byte below arrives from an RPC node and is checked before it is run.

Ready

DEPTH // PDA MAZE

1st-person raycaster stored as sealed account chunks.

Collect 3 ROM shards and reach the amber exit. WASD move/strafe · arrows turn · click for mouse-look

rpc stream01 lines

> terminal ready: select ROM and pull account chunks

canvas id="canvas"

Canvas accepts keyboard, mouse, click-to-boot, and fullscreen input.

Chunks

18 PDA chunks

Bytes on chain

184,320

Accounts read

0

Merkle root

7vMkK9...9VrP

The chain checks its own copy

Proof before pixels.

A Solana program can verify account state with SHA-256 syscalls and zero-copy Merkle paths. The browser gets speed, while the program keeps a strict checksum trail for the ROM it agreed to store.

Unsealed chunk accounts are rejected before bytes enter memory.

Tampered chunk payloads fail SHA-256 leaf comparison.

Invalid Merkle paths never reach the committed root.

Wrong-owner PDAs are refused even if their bytes match.

Stale roots are ignored once a newer sealed commit exists.

simulated on-chain log

Spot-check 6 chunks

anchor verify01 lines

> proof console idle: waiting for spot-check request

How a game fits in Solana

Small accounts. One committed ROM.

01

Bundle

Engine code, maps, sprites, and metadata compile into one deterministic ROM image.

02

Chunk

The bundle is split across PDA accounts sized for predictable reads and upgrades.

03

Commit

Each chunk hashes into a SHA-256 Merkle root committed by the program.

04

Deploy

Rent-exempt accounts hold the bytes and can return lamports when closed.

05

Read

The browser pulls account slices with getMultipleAccounts and rebuilds the ROM.

Storage cost comparison

Approximate framing for a ROM-sized payload; live market prices vary.

MethodWrite modelRead pathReality checkStatus
Solana Account Rent~0.001–0.002 SOL per 10 KBParallel RPC account readsRent-exempt balance is refundable when accounts close.Best fit
EVM CalldataPaid per byte, not refundableCheap to reference, costly to publishGood for proofs, expensive for full game payloads.Proofs only
EVM Contract StorageHighest persistent write costState reads are available, writes dominatePermanent state is powerful but punishing for ROM bundles.Cost wall

Honest status

Replica shell, real constraints.

proof

Merkle and account checks are simulated for the demo.

canvas

Three upgraded playable modes run locally after boot.

docs

Architecture copy mirrors Solana PDA storage patterns.

rent

Rent-exempt balances are modeled as refundable storage.

// SPECIFICATION & PROTOCOL DOCS

The Arvex Solana Standard

How to bundle, chunk, verify, and run immutable games and binaries from Solana account storage.

module 01

PDA Storage & Account Layout

PDA

ROM bytes are segmented into deterministic Program Derived Address chunks. Each account stores a small sealed header, chunk index, payload length, payload bytes, and the root commitment it belongs to.

  • PDAs are derived from the fixed Arvex seed, a human-readable ROM id, and the little-endian chunk index.
  • Publishers deposit lamports until each account is rent-exempt; that deposit is 100% refundable if the publisher burns or reclaims the ROM accounts.
  • Fixed chunk sizing keeps parallel account reads predictable while preserving a verifiable byte order for reconstruction.
01.spec
seeds = [b"arvex", rom_id.as_bytes(), &chunk_index.to_le_bytes()]

module 02

On-Chain Verification & Syscalls

PDA

The program verifies chunk leaves and Merkle paths inside Solana BPF/SBF with the native sol_sha256 syscall, then rejects any account that cannot prove membership against the sealed root.

  • initialize_rom creates the manifest, write_chunk fills each PDA payload, and seal_rom performs the one-way immutability freeze.
  • verify_chunk spot-checks a chunk leaf, its Merkle branch, owner, sealed bit, and current root.
  • Zero-copy AccountInfo slice inspection avoids deserializing the whole payload and keeps a chunk proof near ~1,500 compute units.
02.spec
initialize_rom(ctx, rom_id, chunk_count)
write_chunk(ctx, rom_id, chunk_index, bytes)
seal_rom(ctx, rom_id, merkle_root)
verify_chunk(ctx, rom_id, chunk_index, proof)

module 03

Client RPC Loader & Decompression Pipeline

PDA

The browser treats RPC data as untrusted until every chunk is hashed, ordered, and reconstructed against the on-chain root commitment.

  • Parallel RPC fetch via getMultipleAccounts pulls PDA slices in one batch.
  • Leaf hashing rebuilds the in-memory Merkle tree before any game byte executes.
  • After root match, Gzip or LZ4 inflation feeds WASM or Canvas memory instantiation.
03.spec
getMultipleAccounts(pdas) -> hash leaves -> rebuild Merkle root -> inflate bundle -> instantiate memory

module 04

Developer CLI & Publishing Guide

PDA

A publisher packs a deterministic build folder, deploys chunk accounts to the target network, then seals the ROM id so clients can boot from an immutable root.

  • pack creates a canonical bundle and manifest.
  • deploy funds rent-exempt PDA accounts and writes chunk payloads.
  • seal commits the final Merkle root and closes the mutable publishing window.
04.spec
npx arvex-solana pack ./dist --id depth
npx arvex-solana deploy --network mainnet --keypair id.json
npx arvex-solana seal --rom-id depth

interactive examples

Boot protocol snippets

Rust
#[program]
pub mod arvex_solana {
    pub fn initialize_rom(ctx: Context<InitializeRom>, rom_id: String, chunk_count: u32) -> Result<()> {
        ctx.accounts.manifest.set_inner(RomManifest::new(rom_id, chunk_count));
        Ok(())
    }

    pub fn write_chunk(ctx: Context<WriteChunk>, chunk_index: u32, bytes: Vec<u8>) -> Result<()> {
        require!(!ctx.accounts.manifest.sealed, ArvexError::AlreadySealed);
        ctx.accounts.chunk.write_payload(chunk_index, &bytes)?;
        Ok(())
    }

    pub fn seal_rom(ctx: Context<SealRom>, merkle_root: [u8; 32]) -> Result<()> {
        ctx.accounts.manifest.root = merkle_root;
        ctx.accounts.manifest.sealed = true;
        Ok(())
    }

    pub fn verify_chunk(ctx: Context<VerifyChunk>, proof: Vec<[u8; 32]>) -> Result<()> {
        let bytes = ctx.accounts.chunk.data.borrow();
        let leaf = solana_program::hash::hashv(&[&bytes[HEADER_LEN..]]);
        verify_merkle_branch(leaf.to_bytes(), proof, ctx.accounts.manifest.root)
    }
}