Lattice Blockchain Core SDK
The consensus layer of the Lattice SDK. Hierarchical proof-of-work with merged mining — child chains inherit parent security without splitting hashrate. Cross-chain transfers verified by Merkle proof. No bridges, no multisigs, no trust assumptions.
Blocks
A Lattice block is a Cashew Merkle structure containing transactions, state roots, child blocks, and proof-of-work metadata.
struct Block: Node {
var previousBlock: HeaderImpl<Block>?
var transactions: MerkleDictionaryImpl<Transaction>
var difficulty: UInt256
var nextDifficulty: UInt256
var spec: HeaderImpl<ChainSpec>
var homestead: HeaderImpl<LatticeState> // state before execution
var frontier: HeaderImpl<LatticeState> // state after execution
var childBlocks: MerkleDictionaryImpl<Block> // merged-mined children
var parentHomestead: HeaderImpl<LatticeState>?
var index: UInt64
var timestamp: Int64
var nonce: UInt256
}
Because blocks are Cashew Nodes, they are content-addressed (every block has a unique CID), lazily loadable (you can reference a block by CID without having its full data), and recursively storable in the Acorn CAS chain.
Block Types
| Type | Description | Constraints |
|---|---|---|
| Genesis | First block of any chain. No previous block, index 0. | No withdrawals. Can contain deposits and genesis actions. |
| Nexus | Block on the root chain (the nexus). | No deposits or withdrawals. Standalone proof of work. |
| Child | Block on a child chain, embedded in a parent block's childBlocks. |
Timestamp must match parent. Inherits parent's filter rules. |
Validation Pipeline
Every block passes through a multi-stage validation:
- Structural: Index sequential, timestamp not in future, spec matches
- Difficulty:
difficulty ≥ getDifficultyHash()— the block's hash meets the work requirement - Transactions: All signatures valid, all nonces correct, count within spec limits
- State: Execute all actions against homestead; computed frontier must match declared frontier
- Spec limits: State growth within
maxStateGrowth, block size withinmaxBlockSize - Balances: Total balance changes = block reward + deposits - withdrawals (conservation of value)
ChainSpec
The economic and consensus parameters for a chain. Immutable once the chain launches.
struct ChainSpec: Node {
var premine: Int // blocks by founders before public mining
var initialRewardExponent: Int // block reward = 2^exponent
var halvingInterval: Int // blocks between reward halvings
var targetBlockTime: Int // milliseconds between blocks
var difficultyAdjustmentWindow: Int // blocks averaged for difficulty
var maxDifficultyChange: Int // max 2x increase or decrease
var maxNumberOfTransactionsPerBlock: Int
var maxStateGrowth: Int // max bytes of state changes per block
var maxBlockSize: Int // max serialized block bytes
var filter: String? // JavaScript validator for transactions
var actionFilter: String? // JavaScript validator for actions
}
Block Reward
Rewards follow a halving schedule similar to Bitcoin:
baseReward = 2^initialRewardExponent
halvings = (blockIndex - premine) / halvingInterval
reward = baseReward >> halvings
When halvings ≥ 64, the reward is zero. The geometric series is designed so total supply asymptotically approaches UInt64.max.
Difficulty Adjustment
Difficulty adjusts to maintain the target block time using a windowed average of recent block timestamps:
- Compute actual time for the last
difficultyAdjustmentWindowblocks - Compare to expected time (
window × targetBlockTime) - Scale difficulty proportionally, clamped to
maxDifficultyChange(max 2x up or down)
Predefined Specs
| Spec | Block Time | Reward | Adjustment Window |
|---|---|---|---|
.bitcoin | 10 min | 210 = 1024 | 2016 blocks |
.ethereum | 12 sec | 218 = 262144 | 256 blocks |
.development | 1 sec | 210 = 1024 | 20 blocks |
Transactions
Transactions are signed bundles of actions that modify world state.
struct Transaction: Node {
var signatures: [String: String] // publicKeyHex → signatureHex
var body: HeaderImpl<TransactionBody>
}
struct TransactionBody: Node {
var accountActions: [AccountAction]
var actions: [Action]
var depositActions: [DepositAction]
var withdrawalActions: [WithdrawalAction]
var genesisActions: [GenesisAction]
var peerActions: [PeerAction]
var receiptActions: [ReceiptAction]
var signers: [String] // public keys that signed
var fee: UInt64
var nonce: UInt64 // replay protection
}
Signature Verification
Transactions use P256 ECDSA signatures. Each signer's public key maps to their signature over the transaction body's CID. Multi-signature transactions are natively supported — multiple signers can authorize the same transaction.
World State
LatticeState is an 8-component Merkle tree representing all state on a chain. Each component is a MerkleDictionary.
State transitions are deterministic: given a homestead (state before) and a set of transactions, the frontier (state after) is uniquely determined. This is how nodes independently verify blocks without trusting anyone.
State Proofs
Because every state component is a Cashew Merkle structure, you can generate sparse Merkle proofs for any state claim. For example: "Alice's balance at block 50,000 was 1,000 tokens" can be proven with a proof containing only the path from the state root to Alice's account entry — a few hundred bytes regardless of how many accounts exist.
Actions
Actions are the atomic operations within transactions. Each action type modifies a specific component of world state.
| Action | State Component | Description |
|---|---|---|
AccountAction |
AccountState | Balance transfers. Specifies owner, old balance, new balance. Creates or deletes accounts. |
Action |
GeneralState | Generic key-value state changes. Application-level storage. |
DepositAction |
DepositState | Records a cross-chain deposit request. Only valid in genesis blocks. |
WithdrawalAction |
WithdrawalState | Initiates a cross-chain withdrawal. Only valid on child chains. |
ReceiptAction |
ReceiptState | Records proof of a withdrawal on the parent chain. |
GenesisAction |
GenesisState | Creates a new child chain by embedding its genesis block. |
PeerAction |
PeerState | Registers, updates, or removes a P2P peer endpoint on-chain. |
State Delta Tracking
Every action declares its state delta (bytes added or removed). The total delta across all actions in a block must be within maxStateGrowth. This prevents state bloat attacks.
Merged Mining
Lattice's defining feature. Parent blocks structurally contain child blocks — no auxiliary proof needed.
How It Works
- A miner builds a nexus block template with transactions
- The miner also builds child block templates for each child chain they want to mine
- Child blocks are inserted into the nexus block's
childBlocksMerkle dictionary - The miner finds a nonce that satisfies the nexus difficulty
- One proof of work secures all blocks simultaneously
Isolation Property
An invalid child block does not invalidate its parent. Child blocks are validated independently. If a child block fails validation, it's simply ignored — the parent block remains valid. This means a bug or attack on one child chain cannot compromise the nexus or any other child chain.
Child Chain Creation
New child chains are created via GenesisAction. The genesis block of the child chain is embedded in a nexus transaction, and the child chain's ChainSpec is locked at creation. The child chain inherits the parent's filter rules in addition to its own.
Cross-Chain Transfers
Lattice supports trustless cross-chain transfers via a deposit/withdrawal/receipt cycle. No bridges, no multisigs, no oracles.
The Flow
- Deposit: A
DepositActionin the child chain's genesis block records the deposit demand (who wants tokens and how many) - Withdrawal: A
WithdrawalActionon the child chain claims tokens, providing proof that the deposit exists in the parent state - Receipt: A
ReceiptActionon the parent chain records proof that the withdrawal was processed on the child chain
Each step is verified by Merkle proof against the respective state root. The parent block contains the child block, so the parent node can verify the child's state root directly. No external validator or bridge contract is needed.
Consensus: Fork Choice
ChainState manages the consensus logic for each chain, tracking all known blocks and determining the canonical chain.
Fork Choice Rule
Lattice uses a two-tier fork choice rule:
- Parent chain anchoring (primary): A child block anchored by an earlier parent block wins. If block A's parent is at nexus height 1000 and block B's parent is at nexus height 1001, block A wins — regardless of child chain length.
- Longest chain (tiebreaker): If parent anchoring is tied, the longer chain wins (more cumulative work).
Reorganization
When a fork accumulates more work than the current main chain:
- Find the common ancestor between the current tip and the fork
- Remove blocks from the current tip back to the ancestor
- Add blocks from the fork on top of the ancestor
- Recursively propagate the reorg to all affected child chains
Reorgs cascade: if a nexus reorg removes a block that contained child blocks, those child blocks are also removed from their respective chains.
Pruning
Consensus state keeps only the most recent 1000 blocks (configurable). Older blocks are pruned from the working set but remain available in the Acorn CAS chain for historical queries.
Mining
MinerLoop is the async mining engine that builds blocks and searches for valid nonces.
// Simplified mining loop
while running {
let tip = await chain.tip()
let txs = mempool.selectTransactions(limit: spec.maxNumberOfTransactionsPerBlock)
let template = try BlockBuilder.extend(previous: tip, transactions: txs)
// Batch nonce iteration (10,000 per yield)
for batch in 0..<batchCount {
if let block = template.mine(batchSize: 10_000) {
await network.broadcastBlock(block)
break
}
await Task.yield() // stay responsive
}
}
Block Building
BlockBuilder constructs block templates:
- Carry forward the previous block's frontier as the new homestead
- Pack transactions selected from the mempool (sorted by fee)
- Execute all actions to compute the frontier state root
- Include child block templates in the
childBlocksdictionary - Set difficulty from the previous block's
nextDifficulty
Network Layer
LatticeNode is the full node implementation that ties everything together.
public actor LatticeNode {
// One ChainNetwork per chain (nexus + all children)
var networks: [String: ChainNetwork]
var lattice: Lattice
}
ChainNetwork
Each chain (nexus and every child) gets its own ChainNetwork wrapping an Ivy node:
- Block propagation: Store locally in Acorn disk cache, gossip CID to peers
- Block fetching: Lazily resolve block data from peers via Acorn's
CompositeCASWorker - Mempool: Per-chain transaction pool with fee-based eviction (10,000 tx capacity)
- Discovery: Bootstrap peers + on-chain
PeerStatefor peer endpoints
Mempool
struct Mempool {
func add(_ tx: Transaction) -> Bool
func selectTransactions(limit: Int) -> [Transaction] // sorted by fee
func removeConfirmed(_ txIDs: Set<String>)
var totalFees: UInt64
}
When full (10,000 transactions), the lowest-fee transaction is evicted to make room. Transactions expire after a configurable duration.
Persistence
Chain state is persisted to disk for crash recovery:
- Block data: Stored in Acorn's
DiskCASWorker(content-addressed, sharded, Bloom-filtered) - Consensus state: Serialized as JSON every 100 blocks via
ChainStatePersister - State snapshots: Periodic checkpoints of world state for fast sync
On restart, the node loads persisted consensus state and resumes from the last checkpoint. Block data is lazily loaded from disk as needed.
Cryptography
| Operation | Algorithm |
|---|---|
| Key generation | P256 ECDSA |
| Transaction signing | P256 ECDSA |
| Content addressing | SHA-256 (via swift-crypto) |
| Address derivation | "1" + first32chars(SHA256(SHA256(publicKey))) |
| Difficulty hashing | SHA-256 of serialized block |
Package Integration
Lattice is the top-level package that brings the entire ecosystem together:
- Cashew: All state (blocks, transactions, world state) is Cashew Merkle structures
- Acorn + DiskWorker: Content-addressed storage for blocks and state nodes
- Ivy: Per-chain P2P networking for block/transaction gossip and peer discovery
- Tally: Peer reputation for routing and rate limiting at the network layer