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 generationPackage 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:
- 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.
- Create libp2p host -- TCP transport on the configured port, noise encryption, yamux multiplexing, plus the netcheck handler so incoming connections find a handler immediately.
- Setup pubsub -- GossipSub protocol for topic-based message propagation.
- Create gossip layers -- block gossip, vote gossip, marketplace gossip, directory gossip, certificate gossip.
- Setup mDNS -- local peer discovery (unless disabled).
- Open or create key pair -- loads
node.keyfrom the data directory, or generates a new seed. - Open store -- creates a BadgerStore at
{dataDir}/ledger(or uses the injected store). - Create ledger -- wraps the store with validation logic, rebuilds delegation and balance maps from existing data.
- 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.
- Setup frontier sync -- registers the sync protocol handler so peers exchange frontiers on connect.
- Setup DHT -- Kademlia distributed hash table for peer routing.
- Create messenger and chat store -- direct P2P streams for request/response patterns.
- 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. - Wire state-chain-backed config --
sys.timekeepersfor attestation validation,sys.minterfor mint authorization, and the epoch lookups that supply emission parameters. - Register handlers -- incoming blocks, votes, marketplace, state chain, directory and certificate messages; plus certificate pull, block-body pull, and tunnel handlers.
- Dial bootstrap peers -- connects with retry to the addresses specified in
--dial. - 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)
}