Blitz is a dual-consensus payments L1: a colocated committee that soft-confirms simple transfers in single-digit milliseconds, anchored to a broad settlement layer that hosts smart contracts and hard finality.
Grab the terminal wallet — a live app with balances, an activity log, and a latency panel — point it at the network, and move value in about a minute.
A single small binary — no install, no account.
↓ Download for macOS (Apple Silicon)git clone <repo> blitz && cd blitz
cargo build --release -p blitz-wallet-tui
# binary at: target/release/blitz-wallet-tui
macOS quarantines downloaded binaries — clear it once:
chmod +x blitz-wallet-tui-macos-arm64
xattr -d com.apple.quarantine blitz-wallet-tui-macos-arm64
mv blitz-wallet-tui-macos-arm64 blitz-wallet-tui
Point it at a live node (the East leader) and run it. On first launch it creates your local keypair automatically — no separate setup.
BLITZ_RPC=44.218.58.19:8645 ./blitz-wallet-tui
Pull a starting balance from the faucet: press f, type an amount, and press Enter.
Press s, enter a recipient account id and amount, then Enter. It confirms in single-digit milliseconds — the latency panel shows the full breakdown as it lands.
The wallet's activity log confirms it instantly. Paste your account id or the tx hash into BlitzScan search to see the same transaction from the chain's side.
There's also a non-interactive CLI wallet with the same keystore and signing, for automation:
cargo build --release -p blitz-wallet
export BLITZ_RPC=44.218.58.19:8645
./blitz-wallet new
./blitz-wallet faucet 100000
./blitz-wallet send <recipient_account_id> 2500
Blitz runs two cooperating consensus mechanisms instead of one. A fast committee gives payments card-swipe latency; a broad settlement layer gives everything the finality and generality of a real L1.
A small, colocated committee (a rotating subset of the full validator set) orders and executes simple transfers in a single BFT round. Intra-datacenter round-trips are fractions of a millisecond, so a transfer soft-confirms in ≤5 ms. The committee can only touch transparent payment balances — that narrow scope is what keeps it fast.
Incoming payments append a credit to the receiver, an order-independent operation with zero write contention — a merchant taking 10k payments/sec creates 10k credits that never serialize. Only spends serialize, and only on the spender's own account, because a spend must check funds and prevent double-spends. Credits fold into the settled balance lazily. Reorder any account's credits and its final balance is identical — that invariant is the whole basis of payment throughput.
The full validator set runs a total-order BFT chain: the single canonical, hard-final ledger. It hosts smart contracts, the privacy pool, global ordering, and hard finality. The fast committee is a low-latency view of this same validator set — one security budget, no separate token.
Every interval the committee bundles its recent payment batches into an anchor: a Merkle root over the applied transfers and balance deltas plus a committee quorum certificate. The settlement layer verifies the certificate, checks the deltas conserve value, and roots the anchor into the canonical chain. Once rooted, those payments inherit full-set hard finality and are irreversible.
Between anchors a payment is soft-final — reversible only by a committee equivocation, which is cryptographically detectable and slashable. It's exactly the card-network split: authorization is instant, settlement follows. Wallets show both, and a merchant picks the threshold that fits the amount.
Commitments and Merkle trees use BLAKE3; every transaction and validator vote is ed25519-signed and verified on every node. Consensus is BFT / proof-of-stake with a stake-weighted validator set and slashing — the hash function is just a commitment primitive, never mined.
Contracts run on a WebAssembly virtual machine
on the settlement layer — the DeFi lane. WASM is already a universal, language-
neutral bytecode, so a contract can be written in Rust, Go, C, or AssemblyScript
and compiled to wasm32.
The VM is wasmtime with a locked-down configuration: fuel
metering on, and SIMD, threads, reference types, and every source of time or
entropy off. Contracts are integer-only. The result is that every validator
executing the same call computes a byte-identical result —
the property consensus depends on.
Each contract is an object on-chain with its own key/value
storage, versioned like every other object (MVCC). A call runs
a method with a gas budget — gas is measured as execution fuel, so an
infinite loop simply runs out. Every call is all-or-nothing:
on success the new storage commits as a fresh version; on a trap, out-of-gas,
or an explicit abort, nothing is written and the gas is still
charged.
A contract talks to the chain through a small set of host functions it
imports from the blitz namespace. Everything is bytes in, bytes
out, addressed through the guest's exported linear memory.
| Function | Signature | Purpose |
|---|---|---|
| storage_read | (key_ptr, key_len, out_ptr, out_cap) → len | Read a value by key; -1 if absent |
| storage_write | (key_ptr, key_len, val_ptr, val_len) | Write or overwrite a value |
| get_input | (out_ptr, out_cap) → len | Read the call's argument bytes |
| set_output | (ptr, len) | Return bytes to the caller |
| get_caller | (out_ptr) | Write the 16-byte caller address |
| emit_log | (ptr, len) | Append a log line to the receipt |
| abort | (ptr, len) | Revert the call with a message |
Here's a complete counter in Rust — it imports the host functions, keeps a
u64 under the key count, and exports two methods.
Each exported method is a contract entry point returning i32.
#![no_std]
#![no_main]
// Host functions the Blitz runtime provides.
#[link(wasm_import_module = "blitz")]
extern "C" {
fn storage_read(k: *const u8, klen: i32, out: *mut u8, cap: i32) -> i32;
fn storage_write(k: *const u8, klen: i32, v: *const u8, vlen: i32);
fn emit_log(ptr: *const u8, len: i32);
fn set_output(ptr: *const u8, len: i32);
}
const KEY: &[u8] = b"count";
fn load() -> u64 {
let mut buf = [0u8; 8];
let n = unsafe { storage_read(KEY.as_ptr(), 5, buf.as_mut_ptr(), 8) };
if n < 0 { 0 } else { u64::from_le_bytes(buf) }
}
// count += 1, persisted across calls
#[no_mangle]
pub extern "C" fn increment() -> i32 {
let bytes = (load() + 1).to_le_bytes();
unsafe {
storage_write(KEY.as_ptr(), 5, bytes.as_ptr(), 8);
emit_log("incremented".as_ptr(), 11);
}
0
}
// return the current count to the caller
#[no_mangle]
pub extern "C" fn get() -> i32 {
let bytes = load().to_le_bytes();
unsafe { set_output(bytes.as_ptr(), 8) };
0
}
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
With a Cargo.toml that builds a cdylib:
[package]
name = "counter"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[profile.release]
lto = true
opt-level = "z" # small wasm
Compile to WebAssembly, then deploy with your wallet — the deploy is signed by your key, and the chain returns the contract's on-chain address (derived deterministically from your account and a nonce).
rustup target add wasm32-unknown-unknown
cargo build --release --target wasm32-unknown-unknown
blitz-wallet deploy target/wasm32-unknown-unknown/release/counter.wasm
# → deployed · contract 7f3a91c4e2d0 · height 20514
Call a method by name. State-changing calls are included in a block and
confirm on the settlement layer; read-style methods return their bytes in the
receipt. Pass arguments with --args (hex) and a budget with
--gas.
blitz-wallet call 7f3a91c4e2d0 increment
# → ok · gas 142 · logs ["incremented"] · height 20515
blitz-wallet call 7f3a91c4e2d0 get
# → ok · output 0100000000000000 (count = 1, u64 LE)
Look the contract up on BlitzScan by its address to see its deploy, every call, and its current state version.
The DeFi lane runs on a multi-version (MVCC) object store, so contract calls execute optimistically and in parallel — Block-STM style — serializing only on a true read/write conflict, which is detected and re-executed automatically. Contracts settle in sub-second time on the settlement layer; the fast lane stays transparent-only.
The actual finality work for a transfer is about 1 millisecond. What you wait for beyond that is mostly the block interval — a tunable dial, not a cost of consensus.
Every confirmation the wallet reports is the sum of four coherent stages:
The block interval is the confirmation-latency dial: the default is
25 ms, a node run with 5 ms confirms in
single-digit milliseconds, and a larger interval batches more transactions per
block for higher throughput.
The fast-lane execution ceiling — commutative credits, no per-transaction signature check — runs to tens of millions of transfers per second. With every transaction ed25519-verified on the full pipeline, a node sustains tens of thousands of transfers per second, and because signature verification is the bottleneck, throughput scales linearly with the validator set. Add nodes, add capacity.
Three execution tiers mapped onto the two consensus mechanisms, partitioned by state ownership.
| Tier | Workload | Consensus | Latency |
|---|---|---|---|
| Fast lane | Simple transparent transfers | Payment committee | ≤5 ms soft |
| DeFi lane | Contracts, swaps, shielded transfers | Settlement layer | sub-second |
| Heavy lane | Unbounded / batch compute | Settlement (queued) | seconds |
Every account or contract is an object with an id, a version, typed contents, and exactly one owning lane. Transactions statically declare the objects they read and write, which lets the runtime classify each into a lane before execution and schedule non-conflicting ones in parallel. A lane only writes objects it owns, and reads another lane's object only at its last anchored (final) version — never reversible soft state. That single rule is what keeps two consensuses safe together.
Transactions are transparent by default. A user can opt one into a Zcash-style shielded pool that hides sender, receiver, and amount — encrypted notes, an incremental commitment tree, a nullifier set for double-spend prevention, user-held viewing keys, and single-transaction selective disclosure. It lives on the settlement layer because those structures need global total order.