2026-02-20 15:24:38 +00:00
---
2026-03-11 13:02:39 +00:00
title: Architecture
description: Package structure, dependency graph, CGo boundary, and core data structures.
---
# Architecture
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
## Dependency Graph
2026-02-20 15:24:38 +00:00
```
2026-03-11 13:02:39 +00:00
+------------+
| consensus |
+------+-----+
|
+------------+------------+
| |
+-----+-----+ +-----+-----+
| chain | | difficulty |
+-----+------+ +-----------+
|
+--------+---------+
| | |
+----+--+ +---+---+ +---+---+
| p2p | | rpc | | wallet|
+----+--+ +---+---+ +---+---+
| | |
+--------+---------+
|
+----+----+
| wire |
+----+----+
|
+-------+-------+
| |
+---+---+ +-----+-----+
| types | | config |
+---+---+ +-----------+
|
+---+---+
| crypto | < -- CGo boundary
+--------+
2026-02-20 15:24:38 +00:00
```
2026-03-11 13:02:39 +00:00
### Key Relationships
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
- **config** and **types** are leaf packages with no internal dependencies (stdlib only).
- **wire** depends on **types** for struct definitions and **config** for version-specific serialisation rules.
- **crypto** wraps the C++ library via CGo; it is used by **wire** (for hashing), **chain** (for signature verification), and **wallet** (for key derivation and tx signing).
- **p2p**, **rpc** , and **wallet** are higher-level packages that depend on wire-level serialisation.
- **chain** is the central coordinator: it validates blocks using **consensus** rules, adjusts **difficulty** , and stores state.
- **consensus** is standalone -- no dependency on **chain** or any storage layer. All functions are pure: they take types, config, and height, returning errors.
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
## Package Details
2026-02-21 02:21:36 +00:00
2026-03-11 13:02:39 +00:00
### config/
2026-02-21 02:21:36 +00:00
2026-03-11 13:02:39 +00:00
Every consensus-critical constant, derived from the C++ `currency_config.h.in` and `default.cmake` . The `ChainConfig` struct aggregates all parameters:
2026-02-21 02:21:36 +00:00
2026-03-11 13:02:39 +00:00
```go
// Pre-populated globals for each network.
var Mainnet = config.ChainConfig{
Name: "Lethean",
Abbreviation: "LTHN",
IsTestnet: false,
Coin: 1_000_000_000_000, // 10^12 atomic units
BlockReward: 1_000_000_000_000, // 1 LTHN per block
P2PPort: 36942,
RPCPort: 36941,
// ... all other parameters
}
```
2026-02-23 00:06:28 +00:00
2026-03-11 13:02:39 +00:00
The hardfork schedule is defined separately with lookup functions:
2026-02-23 00:06:28 +00:00
2026-03-11 13:02:39 +00:00
```go
version := config.VersionAtHeight(config.MainnetForks, height)
active := config.IsHardForkActive(config.MainnetForks, config.HF4Zarcanum, height)
```
2026-02-23 00:06:28 +00:00
2026-03-11 13:02:39 +00:00
### types/
2026-02-23 00:06:28 +00:00
2026-03-11 13:02:39 +00:00
Fixed-size byte arrays matching the CryptoNote specification:
2026-02-23 00:06:28 +00:00
2026-03-11 13:02:39 +00:00
```go
type Hash [32]byte // Keccak-256 hash
type PublicKey [32]byte // Ed25519 public key
type SecretKey [32]byte // Ed25519 secret key
type KeyImage [32]byte // Double-spend detection
type Signature [64]byte // Cryptographic signature
```
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
All types provide `String()` (hex encoding), `IsZero()` , and `FromHex()` methods.
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
### Block Structure
2026-02-20 15:24:38 +00:00
```go
2026-03-11 13:02:39 +00:00
type BlockHeader struct {
MajorVersion uint8 // Consensus rules version (0, 1, 2, 3)
Nonce uint64 // PoW nonce (8 bytes LE on wire)
PrevID Hash // Previous block hash (32 bytes)
MinorVersion uint64 // Soft-fork signalling (varint on wire)
Timestamp uint64 // Unix epoch seconds (varint on wire)
Flags uint8 // Bit 0: PoS flag (0=PoW, 1=PoS)
}
type Block struct {
BlockHeader
MinerTx Transaction // Coinbase transaction
TxHashes []Hash // Hashes of included transactions
2026-02-20 15:24:38 +00:00
}
```
2026-03-11 13:02:39 +00:00
The wire serialisation order differs from the struct field order. Canonical format: `major_version` , `nonce` , `prev_id` , `minor_version` , `timestamp` , `flags` .
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
### Transaction Structure
2026-02-20 15:24:38 +00:00
```go
2026-03-11 13:02:39 +00:00
type Transaction struct {
Version uint64 // 0=genesis, 1=pre-HF4, 2=post-HF4, 3=post-HF5
Vin []TxInput // Inputs (variant type)
Vout []TxOutput // Outputs (variant type)
Extra []byte // Raw wire bytes for bit-identical round-tripping
HardforkID uint8 // v3+ only
Signatures [][]Signature // v0/v1 ring signatures
SignaturesRaw []byte // v2+ raw signature bytes (CLSAG, etc.)
Attachment []byte // Service attachments
Proofs []byte // v2+ proofs (BP+, balance, surjection)
2026-02-20 15:24:38 +00:00
}
```
2026-03-11 13:02:39 +00:00
Wire format differs between versions:
- **v0/v1:** `version, vin, vout, extra, [signatures, attachment]`
- **v2+:** `version, vin, extra, vout, [hardfork_id], [attachment, signatures, proofs]`
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
### Input Types
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
| Type | Tag | Description |
|------|-----|-------------|
| `TxInputGenesis` | `0x00` | Coinbase input (block height only) |
| `TxInputToKey` | `0x01` | Standard spend with ring signature |
| `TxInputZC` | `0x25` | Zarcanum confidential input (no amount field) |
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
### Output Types
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
| Type | Tag | Description |
|------|-----|-------------|
| `TxOutputBare` | `0x24` | Transparent output (visible amount) |
| `TxOutputZarcanum` | `0x26` | Confidential output (Pedersen commitment) |
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
A `TxOutputZarcanum` contains:
2026-02-20 15:24:38 +00:00
```go
2026-03-11 13:02:39 +00:00
type TxOutputZarcanum struct {
StealthAddress PublicKey // One-time stealth address
ConcealingPoint PublicKey // Group element Q (premultiplied by 1/8)
AmountCommitment PublicKey // Pedersen commitment (premultiplied by 1/8)
BlindedAssetID PublicKey // Asset type blinding (premultiplied by 1/8)
EncryptedAmount uint64 // XOR-encrypted amount
MixAttr uint8 // Mixing attribute
2026-02-20 15:24:38 +00:00
}
2026-03-11 13:02:39 +00:00
```
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
### Address Encoding
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
Four address types via distinct base58 prefixes:
| Type | Prefix | Starts with | Auditable | Integrated |
|------|--------|-------------|-----------|------------|
| Standard | `0x1eaf7` | `iTHN` | No | No |
| Integrated | `0xdeaf7` | `iTHn` | No | Yes |
| Auditable | `0x3ceff7` | `iThN` | Yes | No |
| Auditable integrated | `0x8b077` | `iThn` | Yes | Yes |
Encoding format:
```
base58(varint(prefix) || spend_pubkey(32) || view_pubkey(32) || flags(1) || keccak256_checksum(4))
2026-02-20 15:24:38 +00:00
```
2026-03-11 13:02:39 +00:00
CryptoNote base58 splits input into 8-byte blocks, each encoded independently into 11 characters. Uses legacy Keccak-256 (pre-NIST), not SHA3-256.
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
## wire/
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
Consensus-critical binary serialisation. Key primitives:
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
- **Varint:** 7-bit LEB128 with MSB continuation (same as protobuf). Max 10 bytes per uint64.
- **Block hash:** `Keccak256(varint(len) || block_hashing_blob)` -- the length prefix comes from the C++ `binary_archive` serialisation of a `blobdata` type.
- **Tree hash:** CryptoNote Merkle tree over transaction hashes (direct port of `crypto/tree-hash.c` ).
2026-02-20 17:16:08 +00:00
2026-03-11 13:02:39 +00:00
Extra, attachment, and proof fields are stored as opaque raw wire bytes. This enables bit-identical round-tripping without implementing all 20+ extra variant types.
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
## consensus/
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
Three-layer validation, all hardfork-aware:
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
**Layer 1 -- Structural (no crypto):**
Transaction size, input/output counts, key image uniqueness, extra parsing, version checks.
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
**Layer 2 -- Economic:**
Block reward (fixed 1 LTHN with size penalty using 128-bit arithmetic), fee extraction, balance checks. Pre-HF4 fees go to miner; post-HF4 fees are burned.
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
```go
func BaseReward(height uint64) uint64 {
if height == 0 {
return config.Premine // Genesis block: 10M LTHN
}
return config.BlockReward // All other blocks: 1 LTHN
}
```
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
**Layer 3 -- Cryptographic (CGo):**
PoW hash verification (RandomX, key `"LetheanRandomXv1"` ), NLSAG ring signatures (pre-HF4), CLSAG signatures (post-HF4), Bulletproofs+ range proofs.
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
## chain/
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
Persistent blockchain storage using go-store (pure-Go SQLite). Five storage groups:
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
| Group | Key | Value |
|-------|-----|-------|
| `blocks` | Height (zero-padded) | JSON metadata + hex blob |
| `block_index` | Block hash | Height |
| `transactions` | Tx hash | JSON metadata + hex blob |
| `spent_keys` | Key image | Block height |
| `outputs:{amount}` | Index | Global output entry |
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
Supports two sync modes:
- **RPC sync:** Poll-based fetching from a JSON-RPC daemon.
- **P2P sync:** Levin protocol REQUEST_CHAIN / REQUEST_GET_OBJECTS loop.
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
Both share a common `processBlockBlobs()` validation path.
2026-02-20 17:16:08 +00:00
2026-03-11 13:02:39 +00:00
## wallet/
2026-02-20 17:16:08 +00:00
2026-03-11 13:02:39 +00:00
Interface-driven design with four core abstractions:
2026-02-20 17:16:08 +00:00
2026-03-11 13:02:39 +00:00
| Interface | Purpose | v1 Implementation |
|-----------|---------|-------------------|
| `Scanner` | Detect owned outputs via ECDH | `V1Scanner` |
| `Signer` | Produce ring signatures | `NLSAGSigner` |
| `Builder` | Construct signed transactions | `V1Builder` |
| `RingSelector` | Pick decoy outputs | `RPCRingSelector` |
2026-02-20 17:16:08 +00:00
2026-03-11 13:02:39 +00:00
Account key derivation: `viewSecret = sc_reduce32(Keccak256(spendSecret))` , matching the C++ `account_base::generate()` pattern. 25-word CryptoNote mnemonic encoding using the Electrum 1626-word dictionary.
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
## mining/
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
Solo PoW miner flow:
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
1. `GetBlockTemplate(walletAddr)` -- fetch template from daemon
2. `HeaderMiningHash(block)` -- Keccak-256 of `BlockHashingBlob` with nonce=0
3. Nonce loop: `RandomXHash("LetheanRandomXv1", headerHash || nonce_LE)`
4. `CheckDifficulty(powHash, difficulty)` -- solution found?
5. `SubmitBlock(hexBlob)` -- submit the solved block
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
## CGo Bridge Design
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
The crypto package follows **ADR-001: Go Shell + C++ Crypto Library** :
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
- `crypto/upstream/` -- 37 vendored C++ files from Zano commit `fa1608cf`
- `crypto/compat/` -- Compatibility stubs replacing epee/Boost dependencies
- `crypto/bridge.h` -- Stable C API (29 functions). Only `uint8_t*` pointers cross the boundary.
- `crypto/randomx/` -- Vendored RandomX source (26 files including x86_64 JIT)
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
Build: `cmake -S crypto -B crypto/build && cmake --build crypto/build --parallel`
2026-02-20 15:24:38 +00:00
2026-03-11 13:02:39 +00:00
All curve points on chain are stored premultiplied by the cofactor inverse (1/8). The `PointMul8` /`PointDiv8` helpers convert between representations. CLSAG generate takes full points; CLSAG verify takes premultiplied values.