Skip to Content
How it works

How it works

You run one command.

A PTB that touches real mainnet pools just works, locally. No manual object dumping.

This page shows how. We follow one transaction from start to finish.

The big idea: copy-on-read

Galene is built on one trick. A copy-on-read fork.

Mainnet is the source of truth. It is read-only. Every write you make stays local.

Three things follow.

It starts instantly. No chain download. The fork boots empty. It stays empty until something asks for an object.

It fetches on demand. Touch an object that is not local yet. Galene pulls it from a mainnet fullnode and caches it. The next read is local.

Your writes stay home. Galene never writes to mainnet. Your mutations, mints, and overwrites land in the local store. Break whatever you want. The real chain is safe.

Mainnet is the default fork source, not the only one. Point Galene at any Sui network, mainnet, testnet, devnet, localnet, or a private fullnode, by setting rpc in the [fork] config. Everywhere this page says “mainnet,” read “your fork source.”

The four parts

PartJobSource
OceanusFetches a missing object from a mainnet fullnode. Decodes its contents, owner, and type.fetch.rs
PoseidonWraps Sui’s in-memory chain. Injects forked objects. Runs transactions.lib.rs
PloutoFabricates a Coin<T> directly. Any type, any balance, any owner.coin.rs
ProteusTurns a transaction into a per-command object graph.graph.rs

One transaction, end to end

This is the loop that makes mainnet DeFi work locally.

It lives in the galene_executeTransactionBlock handler in server.rs.

You submit a transaction

You send serialized TransactionData. These are the exact bytes the TS SDK builds before signing.

No signature needed. Galene runs it as an impersonated sender.

Poseidon finds what is missing

Galene reads the transaction’s input objects and gas payment. It asks the local store which ones are not present yet. That list is the work to do.

Oceanus fetches each one

For each missing object, Galene calls sui_getObject on a mainnet fullnode. It decodes the contents, owner, and type.

The objects enter the VM

Galene rebuilds each object and writes it into the local chain. It uses the same path genesis uses. The VM cannot tell it apart from a native object.

Poseidon runs it

Every object is now local. The real Move VM executes the transaction. No ownership or signature checks get in your way.

You get the results

You get the digest, the result, the gas used, and the created and mutated counts. You also get the list of objects Galene forked to make the run work.

Version-aware by design

Sui gives every object an id and a version. Galene keeps both.

The store keys each object by id and version. Not by id alone.

A fetched object arrives at its real mainnet version. A local change writes a new version. It does not overwrite the old one. Reads return the latest.

Every fetch pulls the object’s current upstream version, so a fork tracks the source’s latest state.

Galene also tags each object by origin. Mainnet, or local. It always knows which is which.

store.rs (paraphrased)
// keyed by id AND version ObjectKey { id, version } // a local change supersedes, never clobbers fn next_version(store, id) -> u64 { store.get_latest(id).map(|o| o.version + 1).unwrap_or(1) } // every object carries its origin: Mainnet | Local

This versioning is what powers the object-graph debugger.

Real execution, not simulation

Poseidon wraps Sui’s own engine. It is the real Move VM, running its own protocol version.

So gas, type checks, and effects are all real. If a transaction passes here, it passes on mainnet. The only difference is that you choose the starting state.

Decoupled protocol version. sui_getProtocolConfig reports the engine’s own protocol version, not mainnet’s. So the fork does not break when mainnet bumps its protocol, and clients never choke on a version mismatch.

Genesis-path injection. A forked object is rebuilt from its mainnet bytes. It is written through the exact path genesis uses. No special cases.

Direct coin fabrication. Plouto mints a Coin<T> by building the object directly. No TreasuryCap needed in a local fork.

Replay and the object graph

Galene also works backward. Give it any past mainnet digest.

Replay collects the artifacts. galene replay <digest> runs Sui’s own replay with tracing. It writes the results into .galene/replays/<digest>/. Galene parses them: the objects touched, the full effects, the gas report, and a compressed Move trace.

Proteus builds the graph. It reads the PTB and the effects. Then it builds a per-command graph: the input objects, what each command reads, and what the transaction created, mutated, or deleted. Studio renders it as a graph you can scrub.

The server

Galene serves JSON-RPC on 127.0.0.1:9123.

Standard Sui methods keep the SDK and CLI happy. The galene_* cheatcodes do the rest.

The same fork is also reachable over the modern Sui gRPC interface (sui.rpc.v2), served from 127.0.0.1:9000. Both servers share one fork state. See gRPC.

Every call changes one shared fork state behind a lock. Every call is also broadcast on a live channel. That is how the terminal dashboard and Galene Studio stay in sync as you work.

ForkState
ForkState { store, // version-aware objects engine, // the Move VM (Poseidon) epoch, clock_ms, // time travel active_sender, // impersonation package_overrides, // hot-swapped Move snapshots, // snapshot / revert }

Keep reading

Last updated on