Skip to Content
ConceptsArchitecture

Architecture

Solidus is a novel, purpose-built Layer 1 blockchain for decentralized identity, written from scratch in Rust. It is not a fork of Avalanche, avalanchego, or any existing chain — it shares no codebase with them. Its design draws inspiration from HotStuff and Tendermint-family BFT consensus, and the roadmap borrows the Avalanche subnet pattern (the architectural idea, not the implementation). Unlike general-purpose chains, every design decision — consensus, state model, transaction types — is optimized for identity operations: creating DIDs, issuing credentials, and verifying proofs.

What’s Live Today

The shipped, testnet-live protocol is a single Layer 1 chain:

  • HotStuff-inspired BFT consensus with VRF leader election, BLS signature aggregation, and 3-chain finality
  • Sparse Merkle Tree state over RocksDB, committed to in every block header
  • Typed native transactions — DID lifecycle, BBS+ credentials, transfers, and staking — with no smart-contract VM
  • libp2p networking for block, vote, and transaction propagation

Everything below under “What’s Live Today” describes running code. The subnet model in the next section is roadmap, clearly labelled as such.

The Live Layer 1

The base layer handles:

  • Validator set management — which nodes participate in consensus (stake-weighted, identity-anchored)
  • Block production — ordering and committing transactions
  • DID registry — storing DID Documents and their lifecycle state
  • Credential anchoring — recording credential hashes, BBS+ commitments, and revocations
  • Token transfers — SLDS token movements for fees and staking

All DIDs and credential anchors live on this chain, which is the layer currently live on testnet at rpc.solidus.network.

Roadmap — Identity Subnets

Identity Subnets are a planned future capability, not currently shipped. The design borrows the Avalanche-style subnet pattern — opt-in chains that share the L1 validator set — but is an independent implementation, not a fork. Each subnet would carry its own validator opt-in, consensus parameters, and credential types while anchoring to the L1.

Example use cases under consideration:

  • A financial institution running a private subnet for KYC credentials with permissioned validators
  • A healthcare subnet with specialized credential types for medical records
  • A government subnet for national ID credentials with sovereignty-compliant data residency

These are forward-looking; the current testnet operates as a single L1 only. See the scaling roadmap below for the staged plan.

Consensus: HotStuff-inspired BFT

Solidus uses a HotStuff-inspired Byzantine Fault Tolerant (BFT) consensus engine — a leader-based protocol that achieves deterministic finality with low latency. It is the implemented mechanism, written from scratch in Rust. (An early design called this “Proof of Identity / PoI”; that name described the intent of identity-anchored validators, but the shipped consensus is HotStuff BFT. Identity-anchoring is a property of validator selection, not a separate consensus algorithm.)

How It Works

Each round, a single leader proposes a block and the committee votes; votes are aggregated into a quorum certificate, and the 3-chain commit rule finalizes blocks:

┌────────────┐ ┌────────────┐ ┌────────────┐ │ PROPOSE │ → │ VOTE │ → │ COMMIT │ │ │ │ │ │ │ │ VRF-elected│ │ Committee │ │ 3-chain │ │ leader │ │ signs (BLS)│ │ rule │ │ proposes │ │ → quorum │ │ finalizes │ │ a block │ │ certificate│ │ the block │ └────────────┘ └────────────┘ └────────────┘
  1. Propose — the VRF-elected leader for the round collects pending transactions, speculatively executes them, and proposes a block committing to the post-execution state root
  2. Vote — validators re-execute the block, verify the state root, and sign with BLS; once a quorum (2/3+) of votes is collected, the signatures aggregate into a quorum certificate (QC)
  3. Commit — the 3-chain commit rule (round + 2 ≤ highest QC round) finalizes the block; finality is deterministic and irreversible

Key Properties

VRF leader election. The proposer for each round is chosen by a Verifiable Random Function (Ed25519-based VRF) seeded from the previous round’s VRF output. This is verifiably random and unpredictable — no validator can guarantee or game its own selection. (A round-robin dev mode exists for local testing but is not used in production.)

BLS12-381 signature aggregation. Validator votes are individually BLS-signed and aggregated into a single compact signature per QC (via blst), keeping certificates small as the committee grows.

3-chain finality. A block achieves finality once two further QCs are formed on top of it (the 3-chain commit rule). With ~2.5-second block times on the current testnet, finality lands at roughly 7.5 seconds best-case.

Pacemaker and view changes. A pacemaker drives round timeouts (2-second minimum, exponential backoff up to 16 seconds). If a leader is silent, validators broadcast timeout votes that aggregate into a timeout certificate (TC), advancing the round without the stalled leader.

Identity-anchored, stake-weighted validators. Validators are stake-weighted (minimum 1000 SLDS stake) and identity-anchored. Slashing covers equivocation / double-signing and downtime. This is a property of validator selection layered on top of HotStuff — not a replacement consensus algorithm.

Byzantine fault tolerance. The network tolerates up to f faulty or malicious validators where f < n/3 (n = total validators). With the current 4 validators, the network tolerates 1 faulty validator.

Linear message complexity. Unlike PBFT, which requires O(n²) messages per round, the QC-based design keeps per-round message complexity at O(n), scaling more efficiently as the validator set grows.

Current Testnet Parameters

ParameterValue
Validators4
Block time~2.5 seconds
Finality3-chain (~7.5 seconds)
Pacemaker timeout2s min, exponential backoff to 16s
Fault tolerance1 validator
Max transactions per block1000
Minimum validator stake1000 SLDS

State Model: Sparse Merkle Tree

The chain state is stored in a Jellyfish-style Sparse Merkle Tree (SMT) — a 256-bit tree with BLAKE3 hashing — persisted on RocksDB. The root hash of this tree is included in every block header, providing a cryptographic commitment to the entire state at each block height.

What Is Stored

State is namespaced into four logical sub-trees (accounts, DIDs, credentials, validators), all committed under one global root:

  • DID registry — mapping from DID to DID Document (verification methods, authentication keys, deactivation status)
  • Credential anchors — mapping from credential hash to issuance metadata (issuer DID, subject DID, BBS+ public-key commitment, timestamp, revocation status)
  • Account balances — mapping from address to SLDS token balance and nonce
  • Validator set — current validator public keys, stakes, and reputation

Speculative vs. Committed Views

The RocksDB store (14 column families) keeps two account views. When a block is proposed and validated, its effects are written to the speculative view (CF_ACCOUNTS); only when the 3-chain commit rule finalizes the block are the touched accounts mirrored into the committed view (CF_COMMITTED_ACCOUNTS). RPC reads such as getBalance / getNonce target the committed view, so callers never observe the effects of validated-but-not-yet-finalized blocks.

Why Sparse Merkle Tree

A Sparse Merkle Tree is a Merkle tree where most leaves are empty (default value). This structure has two important properties for identity:

Efficient existence and non-existence proofs. You can prove that a DID exists in the state (existence proof) or that a credential has not been revoked (non-existence proof in the revocation set). Both proofs are O(log n) in size.

Deterministic state roots. The same set of state entries always produces the same root hash, regardless of insertion order. This means all validators will arrive at the same state root after processing the same transactions, which is critical for consensus.

BLAKE3 Hashing

Solidus uses BLAKE3 as the hash function for the Merkle tree (not SHA-256 or Keccak). BLAKE3 was chosen for:

  • Speed — BLAKE3 is several times faster than SHA-256 on modern hardware
  • Parallelism — BLAKE3 can leverage SIMD and multi-threading for large hash computations
  • Security — 256-bit output with no known practical attacks

The state_root in each block header is the BLAKE3 root hash of the entire Sparse Merkle Tree.

Block Structure

Each block contains:

Block ├── Header │ ├── height: u64 │ ├── timestamp: u64 │ ├── previous_hash: [u8; 32] │ ├── state_root: [u8; 32] ← Sparse Merkle Tree root │ ├── transactions_root: [u8; 32] │ ├── proposer: PublicKey │ └── signature: Signature └── Body └── transactions: Vec<Transaction>

The state_root is what makes light client verification possible — a light node can verify any state query by checking a Merkle proof against the state_root in a finalized block header.

Transaction Types

There is no smart-contract VM. State changes happen only through a fixed set of nine typed transaction payloads (TxPayload), each handled by native Rust logic. This keeps the hot path fast and the audit surface small.

DidCreate

Registers a new DID on the chain. The transaction contains the DID Document with the initial verification method and service endpoints.

DidCreate ├── public_key: [u8; 32] ├── service_endpoints: Vec<Service> ├── nonce: u64 └── signature: Signature

DidUpdate

Applies an ordered set of patches to an existing DID Document atomically (rotating keys, adding or removing service endpoints).

DidUpdate ├── did: String ├── patches: Vec<DidPatch> ├── nonce: u64 └── signature: Signature

DidDeactivate

Marks a DID as permanently deactivated. After this transaction is finalized, the DID’s verification methods are cleared.

DidDeactivate ├── did: String ├── nonce: u64 └── signature: Signature

CredentialIssue

Anchors a credential hash on-chain. The credential itself is not stored — only its BLAKE3 hash along with metadata.

CredentialIssue ├── credential_hash: [u8; 32] ├── issuer: String ├── subject: String ├── credential_type: String ├── nonce: u64 └── signature: Signature

CredentialIssueBbs

Anchors a BBS+ credential, enabling selective disclosure. The issuer commits on-chain to a BBS+ public key over a fixed-length message vector; the signature and messages live off-chain with the subject. Verifiers later check selective-disclosure proofs against the on-chain bbs_pubkey.

CredentialIssueBbs ├── subject_did: String ├── credential_type: CredentialType ├── bbs_pubkey: ... ├── nonce: u64 └── signature: Signature

CredentialRevoke

Marks a previously issued credential as revoked. Verifiers checking this credential will see the revocation.

CredentialRevoke ├── credential_hash: [u8; 32] ├── issuer: String ├── nonce: u64 └── signature: Signature

Transfer

Moves SLDS tokens between accounts. Used for transaction fees and staking.

Transfer ├── to: Address ├── amount: u64 ├── nonce: u64 └── signature: Signature

Stake / Unstake

Bonds or unbonds SLDS toward becoming (or remaining) a validator. A minimum 1000 SLDS stake is required to be active; unbonding is subject to a 21-day unbonding period.

Stake Unstake ├── amount: u64 ├── amount: u64 ├── nonce: u64 ├── nonce: u64 └── signature: Signature └── signature: Signature

Node Types

The network supports three types of nodes:

Full Node

Stores the complete current state and validates all blocks and transactions. Full nodes participate in consensus if they are in the validator set.

  • Stores: current state tree, recent blocks, transaction pool
  • Validates: all transactions and blocks
  • Serves: RPC queries for current state

Light Node

Stores only block headers and verifies state via Merkle proofs. Light nodes are suitable for mobile wallets and applications that need to verify state without storing the full chain.

  • Stores: block headers only
  • Validates: Merkle proofs against block header state roots
  • Serves: local verification of individual state queries

Archive Node

Stores the complete history of all blocks and state transitions. Archive nodes are used by the block explorer and for historical queries.

  • Stores: all blocks, all historical state trees
  • Validates: all transactions and blocks
  • Serves: historical queries, block explorer data

Networking

Peer-to-peer networking is built on libp2p, combining several behaviours:

  • gossipsub — block and transaction propagation across the network
  • request-response — direct exchange of votes and consensus messages between validators
  • identify — peer metadata exchange
  • Kademlia DHT — open peer discovery, so new nodes can join without a hardcoded peer list

Validators form a static committee mesh; Kademlia and Identify were added to support open discovery and a full-node read-replica mode for nodes that follow the chain without participating in consensus.

Cryptography

PurposePrimitive
Validator signatures (and VRF)Ed25519
Hashing (state tree, tx, blocks)BLAKE3
Signature aggregation (QCs / TCs)BLS12-381 (blst)
Leader electionVRF (Ed25519-based)
Selective disclosureBBS+

Protocol Implementation

The Solidus protocol is implemented from scratch in Rust, organized into 7 crates (with 189 tests, zero clippy warnings, and a live testnet):

CrateResponsibility
solidus-cryptoEd25519, BLAKE3, BLS12-381, VRF, BBS+
solidus-txnsTyped transaction payloads, fees, DID / credential / staking / token logic
solidus-stateSparse Merkle Tree, RocksDB store, block executor, state transitions
solidus-consensusHotStuff-inspired BFT engine, VRF leader election, pacemaker, mempool
solidus-rpcJSON-RPC server (solidus_* methods)
solidus-p2plibp2p networking — gossipsub, request-response, identify, Kademlia
solidus-nodeNode binary tying the crates together

DIDs resolve as did:solidus:<network>:<id>. The source is available at github.com/solidusnetwork/protocol.

Scaling Roadmap

The throughput and latency improvements below are roadmap, not current capability. Today’s testnet is a single-shard L1 with a serial executor and a 4-validator committee. The staged plan targets payment-class throughput (~50K TPS) over a multi-phase, audit-gated engineering effort:

  • Block-STM parallel execution — concurrent transaction execution while preserving the typed-payload handlers verbatim
  • HotStuff-2 (2-chain finality) plus a sub-second pacemaker — cutting a consensus round to lower finality latency
  • Narwhal-style DAG mempool — decoupling transaction dissemination from consensus ordering
  • Avalanche-style subnets — opt-in chains that share the L1 validator set (the pattern, independently implemented — not a fork of any chain)
  • EVM subnet — a REVM-based subnet exposing identity primitives as precompiles, so the L1 hot path stays untouched by EVM bytecode
  • 21-validator, multi-region topology for production mainnet

None of these is live today; each is framed in the engineering roadmap as a discrete, separately-benchmarked phase.

Next Steps

  • Network and Testnet — connect to the live testnet, RPC methods, explorer
  • DIDs — how DIDs use the state tree and key derivation
  • Credentials — how credential anchors and revocations work
  • Getting Started — build on top of the architecture with the SDK
Last updated on