Architecture

How the XE Layer 1 protocol fits together

The XE node is structured as a set of Go packages with clear dependency boundaries. The node package ties everything together; all other packages are independently testable.

Package map

The repository is github.com/xeprotocol/core.

core/
├── cmd/xe/         Single binary — node daemon, wallet, send/receive, leases, ssh
├── core/           Domain logic — ledger, crypto, encoding, PoW, voting, finalization
├── store/          Pluggable storage — MemStore (testing), BadgerStore (production)
├── net/            libp2p networking — gossip, sync, DHT, marketplace, messaging
├── node/           Orchestration — ties all packages together into a running node
├── api/            HTTP REST API — handler, routes, CORS
├── client/         Go HTTP client for talking to a node's API
├── statechain/     Deterministic state machine — DAO governance, KV store, sync
├── vm/             VM abstraction — manager interface, mock, credentials
├── perf/           Provider benchmarks and performance certificates
├── directory/      P2P account directory — registration, verification, gossip
├── chat/           P2P messaging — envelope format, chat store
├── web/            Embedded web UI (explorer, wallet) served by the node
└── scripts/        Test and utility scripts — e2e, stress, genesis generation

Package details

core/ -- Domain logic

The heart of the system. Contains no I/O, no networking, no persistence implementation -- only pure domain logic and interfaces.

File

Purpose

types.go

Block, Vote, Conflict, Lease, PendingSend, Keyset structs; the twelve BlockType constants; the valid-asset allowlist

ledger.go

Ledger struct — validates and adds blocks, manages per-account locking, delegation tracking, asset balances, lease economics

crypto.go

KeyPair, GenerateKeyPair, KeyPairFromSeed, HashBlock, SignBlock, VerifyBlock (ed25519), network ID

encoding.go

MarshalBlockCanonical (binary encoding for hashing), MarshalBlockAux (certificate/attestation binding), MarshalBlock (with PoW nonce), UnmarshalBlock; vote encoding

amount.go

Per-asset decimal config and micro-unit parsing/formatting (XE and XUSD both use 6 decimals)

genesis.go

Embedded ledger genesis block, its validation, and genesis-pinned lease timing

pow.go

blake2b proof-of-work — ComputePoW, ComputePoWConcurrent, ComputePoWWithContext, ValidatePoW

vote.go

VoteManager — casts and validates converge and final votes

finalization.go

Two-phase finalization — converge votes, the write-once commit-lock, and the dependency gate

quorum.go

QuorumManager — tallies votes, finalizes/rejects blocks at the 67% weight threshold

conflict.go

Conflict detection — equivocation checks when two blocks share the same Previous hash

rollback.go

Cascade rollback — unwinds the side effects of a losing block and everything that depended on it

mint.go

Authorized XUSD minting against the state chain's sys.minter config

multisig.go

Keyset validation, hash-derived multisig addresses, threshold signature verification

attestation.go

Timekeeper attestation validation for lease blocks

store.go

Store interface and optional interfaces (VoteStore, ConflictStore, QuorumStore, LeaseStore, etc.)

store/ -- Pluggable storage

Two implementations of the core.Store interface:

  • MemStore -- in-memory maps, used in tests. Implements all optional interfaces (VoteStore, ConflictStore, QuorumStore, LeaseStore, DelegationStore, AtomicBlockStore).
  • BadgerStore -- production storage using BadgerDB. Atomic block commits via BadgerDB transactions. Implements all optional interfaces.

Both stores are interchangeable. The node selects BadgerStore by default; tests inject MemStore via Config.Store.

net/ -- Networking

Built on libp2p. Each concern has its own gossip topic or protocol.

File

Purpose

host.go

Creates and configures the libp2p host (TCP transport, noise security, yamux muxer)

gossip.go

All pubsub topics — blocks (xe/blocks), votes (xe/votes), marketplace (xe/marketplace), state chain (xe/statechain), directory (xe/directory), certificates (xe/certificates); incoming blocks are deduplicated, validated, and added to the ledger

msg.go

Messenger — the /xe/msg/1.0.0 direct-stream protocol used for request/response between peers

sync.go

Frontier sync protocol — on peer connect, exchange frontier hashes and fetch missing blocks

dht.go

Kademlia DHT setup for peer discovery and routing

messages.go

The wire message types carried over gossip and the sync/direct protocols (BlockMsg, VoteMsg, SyncRequest, …)

blocksync.go

Targeted block-by-hash pull, so a node can fetch a conflicting sibling's body that gossip missed

votesync.go

Targeted vote-by-position pull, so a node can recover the votes at a chain position it is behind on

certsync.go

Provider performance certificate exchange on connect, instead of waiting for the next gossip rebroadcast

netcheck.go

Peer admission — enforces matching network ID and protocol version at the connection gate

tunnel.go

TCP-over-libp2p tunnels (/xe/tunnel/2.0.0) used for SSH access to leased VMs

node/ -- Orchestration

The Node struct holds references to every subsystem and coordinates startup, background goroutines, and shutdown.

type Node struct {
    Ledger           *core.Ledger
    Host             host.Host
    Gossip           *xenet.Gossip
    VoteGossip       *xenet.VoteGossip
    MarketGossip     *xenet.MarketplaceGossip
    StateChain       *statechain.Chain
    StateChainGossip *xenet.StateChainGossip
    DirGossip        *xenet.DirectoryGossip
    Msg              *xenet.Messenger
    Directory        *directory.Directory
    DHT              *dht.IpfsDHT
    ChatStore        *chat.ChatStore
    KeyPair          *core.KeyPair
    VoteMgr          *core.VoteManager
    QuorumMgr        *core.QuorumManager
    VMManager        vm.Manager
    CertGossip       *xenet.CertificateGossip
    // ...
}

api/ -- HTTP REST API

A standard net/http handler with routes for:

  • Account balances, chains, keysets and reputation
  • Block submission and lookup
  • Pending sends
  • Conflicts and delegation
  • Lease management, providers and performance certificates
  • VM info and tunnels
  • State chain queries
  • Directory lookups
  • Chat messages
  • Node info

routes() in api/handler.go is the single source of truth for the endpoint list, and the API serves an auto-discovery manifest at GET / rendered from it.

See API Reference for endpoint documentation.

statechain/ -- DAO governance

A linear chain of signed blocks that form a deterministic state machine. Each block contains an operation (set/delete key, update config) signed by authorized keys. The state chain has its own gossip topic and sync protocol, separate from the block lattice.

vm/ -- Compute abstraction

Defines the vm.Manager interface for creating, inspecting, and destroying virtual machines. A mock implementation is used in testing; production providers plug in real hypervisor backends.

directory/ -- Account directory

A decentralized name-to-address registry. Accounts register signed entries that are propagated via gossip. Entries have a TTL and must be periodically refreshed.

chat/ -- P2P messaging

Envelope-based messaging between accounts. Messages are delivered via libp2p direct streams and stored in a bounded in-memory ring buffer per account (1000 envelopes), with replay dedup by envelope ID so one solved PoW nonce cannot be amortised over unlimited copies.

Startup sequence

When node.New(ctx, cfg) is called:

  1. Resolve the state chain genesis and set the network ID -- the ID lives in the genesis ops and is bound into every block hash, so it must be set before the host exists. Peers that handshake during the rest of startup would otherwise see an empty network ID and ban the node.
  2. Create libp2p host -- TCP transport on the configured port, noise encryption, yamux multiplexing, plus the netcheck handler so incoming connections find a handler immediately.
  3. Setup pubsub -- GossipSub protocol for topic-based message propagation.
  4. Create gossip layers -- block gossip, vote gossip, marketplace gossip, directory gossip, certificate gossip.
  5. Setup mDNS -- local peer discovery (unless disabled).
  6. Open or create key pair -- loads node.key from the data directory, or generates a new seed.
  7. Open store -- creates a BadgerStore at {dataDir}/ledger (or uses the injected store).
  8. Create ledger -- wraps the store with validation logic, rebuilds delegation and balance maps from existing data.
  9. Wire voting -- VoteManager and QuorumManager for finalization and conflict resolution; the conflict callback triggers automatic voting, and a periodic frontier sweep re-drives stalled positions.
  10. Setup frontier sync -- registers the sync protocol handler so peers exchange frontiers on connect.
  11. Setup DHT -- Kademlia distributed hash table for peer routing.
  12. Create messenger and chat store -- direct P2P streams for request/response patterns.
  13. Initialize state chain -- create the chain from the genesis, replay the stored chain, register gossip and sync, and re-assert the network ID from sys.network_id.
  14. Wire state-chain-backed config -- sys.timekeepers for attestation validation, sys.minter for mint authorization, and the epoch lookups that supply emission parameters.
  15. Register handlers -- incoming blocks, votes, marketplace, state chain, directory and certificate messages; plus certificate pull, block-body pull, and tunnel handlers.
  16. Dial bootstrap peers -- connects with retry to the addresses specified in --dial.
  17. Start background goroutines -- directory self-registration once peers connect and, for providers, resource advertisement and the lease watch loop.

Interface-driven design

The core package defines a set of interfaces in store.go that storage backends may implement:

Interface

Purpose

Store

Required — block, chain, pending send, frontier CRUD

VoteStore

Optional — vote persistence

ConflictStore

Optional — conflict and staged block persistence

QuorumStore

Optional — block finalization status and heights

FinalVoteStore

Optional — the write-once commit-lock: one recorded final hash per chain position, never deleted

Syncer

Optional — flush pending writes to stable storage before an irrevocable side effect

LeaseStore

Optional — lease record persistence

DelegationStore

Optional — account-to-representative mapping persistence

DelegationIterator

Optional — enumerate all delegations for rebuild on startup

FrontierLister

Optional — enumerate all frontiers

CertificateStore

Optional — provider performance certificate persistence

ReputationStore

Optional — per-account reputation aggregate persistence

KeysetStore

Optional — multisig keyset persistence

AtomicBlockStore

Required — commit block + side effects in a single transaction

The ledger requires AtomicBlockStore at construction time and panics if the store does not implement it. The remaining optional interfaces are checked at runtime using type assertions. Both MemStore and BadgerStore implement all interfaces.

Block validation pipeline

The Ledger.AddBlock() method is the critical path — every block (whether from the local node, gossip, or sync) passes through this pipeline:

AddBlock(b *Block)

  ├── 1. Normalize hex fields (lowercase); strip attestations from non-lease types
  ├── 2. VerifyBlock — recompute hash + check ed25519 signature
  ├── 3. ValidatePoW — blake2b(nonce || hash) >= difficulty
  ├── 4. Timestamp check — within ±1 hour of local time (skipped for synced blocks)
  ├── 5. Acquire the per-account lock (plus a per-lease lock on lease transitions)
  ├── 6. Duplicate check — block hash not already in store (idempotent)
  ├── 7. Multisig signature check — threshold for spending ops, any-one otherwise
  ├── 8. Conflict detection — check if Previous hash is shared
  │     ├── No conflict → continue on main chain
  │     └── Conflict → stage block, fire callback, return

  ├── 9. Type-specific validation
  │     ├── send      → balance sufficient, frontier matches, amount > 0
  │     ├── receive   → pending send exists, destination matches, balance correct
  │     ├── mint      → XUSD only, account is an authorized sys.minter
  │     ├── burn      → XE only, balance sufficient
  │     ├── lease     → XUSD only, cost formula correct, certificate valid
  │     ├── lease_accept → lease created, stake = ⌈cost/5⌉, attestations valid
  │     └── lease_settle → lease expired, XE emission formula, attestations valid

  ├── 10. Update in-memory state (asset balances, delegation weights)
  └── 11. Write to store (atomic commit via AtomicBlockStore)

Each account has its own lock, so blocks for different accounts are validated concurrently. The per-account lock serialises operations within a single account to prevent race conditions.

Config struct

type Config struct {
    Port                 int            // libp2p TCP port
    DialAddrs            []string       // bootstrap peer multiaddrs
    DataDir              string         // persistent storage directory
    Difficulty           uint64         // block PoW threshold (0 = disabled)
    ChatDifficulty       uint64         // chat envelope PoW threshold (0 = derive)
    DisableMDNS          bool           // skip local discovery
    Store                core.Store     // injected store (nil = BadgerStore)
    Version              string         // node version string
    Provide              bool           // enable compute provider mode
    VCPUs                uint64         // provider: vCPUs to offer
    MemoryMB             uint64         // provider: memory in MB
    DiskGB               uint64         // provider: disk in GB
    PriceMultiplierMilli uint64         // provider: price multiplier ×1000
    AcceptPolicy         LeaseAcceptPolicy // provider: local auto-accept filter
    GenesisBlock         *statechain.Block // state chain genesis (nil = embedded)
    MsgTTL               time.Duration  // directory registration TTL
    LimactlPath          string         // path to limactl binary (empty = "limactl")
    MaxConnsPerIP        int            // per-IP inbound connection limit (0 = 8)
}