Asq Documentation
Asq is a permissioned blockchain whose state machine is a SQLite database. Every validator runs the same binary, applies the same transactions in the same order, and arrives at the same state. The state is directly queryable with standard SQL tools.
Key Concepts
- Accounts are
asq1...Bech32m addresses derived from Ed25519 public keys. - Transactions are signed with Ed25519 and carry a sequential nonce.
- Blocks finalize via BLS-aggregate quorum certificates. No reorgs.
- State is a SQLite database. Every mutation emits a leaf into a Jellyfish Merkle Tree.
- Extensions are compiled Rust crates that own their schema and apply logic.
- Fees are fixed per tx type, paid in the native ASQ token.
- Subaccounts:
(master, subaccount: u32). One key, many isolated accounts.
Consensus: HotStuff-2
Asq uses HotStuff-2, a two-phase responsive BFT protocol. Validators identify with Ed25519 keys (chain identity) and BLS12-381 keys (consensus voting). The validator set is permissioned and known at genesis.
Block lifecycle
- The current leader pulls transactions from the mempool.
- The leader builds a block, applies it locally, computes the state root.
- The leader broadcasts the proposed block to all validators.
- Each validator verifies, applies, compares the state root, and votes.
- At 2f+1 votes the leader forms a quorum certificate (QC).
- QC is broadcast. All nodes finalize. No further reorgs.
Pacemaker
If the leader fails to propose within the timeout, validators send timeout votes. At supermajority the view advances to a new leader. Base timeout: 200ms (production).
State Machine: SQLite
The entire chain state lives in a single SQLite database per node. All tables use STRICT typing and CHECK constraints. SQLite runs in WAL mode: many concurrent readers alongside one writer. HTTP reads never block block-application.
Each block commits as one SQLite transaction. A block either lands in full or rolls back cleanly.
State Commitment: JMT
Every state mutation emits a state_changes row. At block end, all changes drain into a Jellyfish Merkle Tree. The root hash is the block's state root.
Leaf keys are namespaced: bal:{token}:{owner}, tok:{id}, obk:{market_id}, oracle:{feed_id}, cep:{cep_id}. Two nodes that disagree on any leaf produce different roots; the block is rejected.
Extensions
Each extension implements ChainExtension and owns its schema + tx variants. Registration order is fixed:
// dependency-aware order tokens // balances, supply, lock/unlock bridge // Solana bridge (depends on tokens) oracle // fair-value feeds (no deps) orderbook // Bid exchange (depends on tokens, reads oracle) cep // automation (depends on tokens, reads oracle)
New extensions land via UpgradeBinary. No arbitrary smart-contract deployment.
Transaction Lifecycle
1. Signing
Client constructs a Transaction, pairs with Ed25519 key + nonce, signs the canonical BCS encoding (includes chain_id).
{
"transaction": { "type": "Transfer", "token_id": "ASQ", "to": "asq1...", "amount": 1000 },
"signer": "a1b2...hex-pubkey",
"nonce": 42,
"signature": "d4e5...hex-sig"
}
2. Submission and Ingress
Client sends POST /tx to any node. The node:
- Validates the Ed25519 signature.
- Canonicalizes addresses (hex pubkey to
asq1...). - If validator: admits to local mempool.
- Forwards to all peers.
Response is immediate: "accepted" (queued) or "rejected" (with reason). Acceptance means queued, not confirmed.
3. Mempool and Admission
- Stale nonce (< expected): rejected.
- Current nonce (== expected): full validation (simulated apply, rolled back). Failures surface at submit time.
- Future nonce (within 1024-tx window): accepted without full validation. The leader validates at packing time. This is the MM burst path.
- Out-of-window: rejected.
4. Block Packing
The leader's select_executable_candidates:
- Priority-sorts by tx type (stable, preserves per-signer nonce order):
- Class 0:
OracleUpdate - Class 1:
Cancel/Modify - Class 2:
PlaceLimit { PostOnly } - Class 3: everything else
- Class 0:
- Each candidate wrapped in a SAVEPOINT. Success: release + include. Failure: rollback + reject/defer.
- Stops at 128 accepted transactions.
5. Block Application
Both leader (at propose) and followers (at verify) use the same path:
If a follower's state root differs from the leader's, the block is rejected.
6. Voting and Finality
- Leader signs the block (state root in the hash).
- Broadcasts proposal to all validators.
- Each validator applies independently, verifies root, sends BLS vote.
- At 2f+1 votes: quorum certificate (QC) formed.
- QC broadcast. Every node finalizes.
Finality is instant. Once a block has a QC it is permanent. No probabilistic finality, no confirmation count, no reorgs.
Tokens and NFTs
First-class chain objects. CreateToken registers with supply, decimals, optional mint authority, max supply, collection. Transfer, Mint, Burn operate on balances. Every balance has (liquid, locked): liquid is free, locked is reserved by orders/stops/CEPs.
Bid Exchange
On-chain CLOB. CreateMarket sets base/quote tokens, tick/lot size, fees.
Order types
- PlaceLimit: GTC, IOC, FOK, PostOnly.
- Cancel / CancelAll / CancelByCloid / Modify
- PlaceStop: conditional limit triggered by oracle feed.
Native market making
ConstantProduct (x*y=k) or OracleSpread (tracks feed with staleness-aware widening). Both post PostOnly and take inventory risk. Refresh at end_block.
Caps: 200 resting orders per account per market. 200 stops per account.
Oracle Feeds
RegisterOracleFeed binds a feed to a publisher. OracleUpdate publishes nonce-ordered values. Fee: 0 ASQ. Consumed by orderbook PropAMM, stops, CEPs, and future perp/prediction-market resolution.
CEPs (Conditional Execution Programs)
Register a predicate + action. Chain evaluates every block, fires when true.
Predicates: OracleValue, BlockHeight, BlockTimestamp, AccountBalance, And/Or/Not (max 8 leaves, depth 4).
Actions: Transfer (v1). PlaceLimit / Cancel (v2).
Caps: 100/account, 10k chain-wide. Lock budget per max_fires.
Stop Orders
Conditional limit orders triggered at end_block when oracle value crosses threshold. Comparators: >= and <=. Inventory locked at placement. Fires through the same apply_place_limit path users use.
Session Signing
SessionOpen delegates a session key for scoped orderbook ops (place, cancel, modify). One verify per session, not per order. Expires at a block height; revocable with SessionRevoke.
Solana Bridge
Validator-majority registration (RegisterBridgedToken), deposit attestation (MintBridged), user withdrawal (BurnBridged). Replay protection via solana_signature. Per-token deposit caps.
API: Chain Status
Height, validators, mempool, health, consensus view.
"ok" if producing/following blocks.
Hex JMT root at tip.
Active validator set.
API: Transactions
Submit signed tx. Returns accepted/rejected.
Submit multiple. Per-tx status.
Lookup by hash.
Next expected nonce.
Block with full tx list.
API: Accounts
Liquid balance.
All balances.
All tokens.
API: Orderbook
All markets.
Top N levels per side.
LP shares.
API: Oracle
Feed snapshot: value, nonce, freshness, publisher.
API: Bridge
All bridged tokens.
Pending/completed withdrawals.