76 lines
2.4 KiB
Nim
76 lines
2.4 KiB
Nim
# SPDX-License-Identifier: LUL-1.0
|
|
# Copyright (c) 2026 Markus Maiwald
|
|
# Stewardship: Self Sovereign Society Foundation
|
|
#
|
|
# This file is part of the Nexus Sovereign Core.
|
|
# See legal/LICENSE_SOVEREIGN.md for license terms.
|
|
|
|
## Nexus Membrane: Configuration Ledger (SPEC-140)
|
|
## Implements Event Sourcing for System State.
|
|
|
|
import strutils, times, options
|
|
import kdl # Local NPK/NipBox KDL
|
|
|
|
type
|
|
OpType* = enum
|
|
OpAdd, OpSet, OpDel, OpMerge, OpRollback
|
|
|
|
ConfigTx* = object
|
|
id*: uint64
|
|
timestamp*: uint64
|
|
author*: string
|
|
op*: OpType
|
|
path*: string
|
|
value*: Node # KDL Node for complex values
|
|
|
|
ConfigLedger* = object
|
|
head_tx*: uint64
|
|
ledger_path*: string
|
|
|
|
# --- Internal: Serialization ---
|
|
|
|
proc serialize_tx*(tx: ConfigTx): string =
|
|
## Converts a transaction to a KDL block for the log file.
|
|
result = "tx id=" & $tx.id & " ts=" & $tx.timestamp & " author=\"" & tx.author & "\" {\n"
|
|
result.add " op \"" & ($tx.op).replace("Op", "").toUpperAscii() & "\"\n"
|
|
result.add " path \"" & tx.path & "\"\n"
|
|
if tx.value != nil:
|
|
result.add tx.value.render(indent = 2)
|
|
result.add "}\n"
|
|
|
|
# --- Primary API ---
|
|
|
|
proc ledger_append*(ledger: var ConfigLedger, op: OpType, path: string, value: Node, author: string = "root") =
|
|
## Appends a new transaction to the ledger.
|
|
ledger.head_tx += 1
|
|
let tx = ConfigTx(
|
|
id: ledger.head_tx,
|
|
timestamp: uint64(epochTime()),
|
|
author: author,
|
|
op: op,
|
|
path: path,
|
|
value: value
|
|
)
|
|
|
|
# TODO: SFS-backed atomic write to /Data/ledger.sfs
|
|
let entry = serialize_tx(tx)
|
|
echo "[LEDGER] TX Commit: ", tx.id, " (", tx.path, ")"
|
|
# writeToFile(ledger.ledger_path, entry, append=true)
|
|
|
|
proc ledger_replay*(ledger: ConfigLedger): Node =
|
|
## Replays the entire log to project the current state tree.
|
|
## Returns the root KDL Node of the current world state.
|
|
result = newNode("root")
|
|
echo "[LEDGER] Replaying from 1 to ", ledger.head_tx
|
|
# 1. Read ledger.sfs
|
|
# 2. Parse into seq[ConfigTx]
|
|
# 3. Apply operations sequentially to result tree
|
|
# TODO: Implement state projection logic
|
|
|
|
proc ledger_rollback*(ledger: var ConfigLedger, target_tx: uint64) =
|
|
## Rolls back the system state.
|
|
## Note: This appends a ROLLBACK tx rather than truncating (SPEC-140 Doctrine).
|
|
let rb_node = newNode("rollback_target")
|
|
rb_node.addArg(newVal(int(target_tx)))
|
|
ledger.ledger_append(OpRollback, "system.rollback", rb_node)
|