Build Roadmap โ Sentinel service node in Syrius
Ordered, scoped work items distilled from the Specification and verified against the Investigation. Each task lists where the work lives, the code anchors to start from, acceptance criteria, and whether it needs a protocol change.
Legend: ๐ข off-chain (no consensus change) ยท ๐ด requires spork/governance ยท โ ๏ธ work outside Syrius-Dart (libznn/go-zenon).
Phase 0 โ Verify assumptions (no code)โ
| Task | Detail | Done when |
|---|---|---|
| 0.1 | Confirm go-zenon's embedded RPC config: does libznn already expose a public-capable RPC server, and on what interface? | The bind/port/TLS defaults are documented from go-zenon source. |
| 0.2 | Confirm the Sentinel reward logic in go-zenon (is "uptime = registration duration" true?). | Specification ยง2.1 is marked verified or corrected. |
Phase 0 needs the go-zenon source, which is not in this repo. Resolve before estimating Phase A.
Phase A โ Make Syrius serve as a Sentinel โ ๏ธ๐ขโ
The load-bearing, under-stated phase. The embedded node already runs and serves WS on
127.0.0.1:35998; the work is to let it serve publicly and stay up.
A.1 โ Configurable embedded node โ ๏ธโ
- Where:
libznn/go-zenon FFI andsyrius/lib/embedded_node/embedded_node.dart. - Anchors: FFI is arg-less
RunNode()/StopNode()(embedded_node.dart:15-21,96); start pathnode_utils.dart:243. - Do: extend the FFI to accept config (bind address, port, enable public RPC, TLS), or
have Syrius write a go-zenon
config.jsonthe node reads onRunNode(). - Acceptance: Syrius can start the embedded node bound to a chosen interface/port with
wss/TLS, controlled from Dart; default remains localhost-only.
A.2 โ "Run as Sentinel / serve publicly" mode ๐ขโ
- Where: Syrius app (settings + lifecycle).
- Anchors: wake-lock handling
node_utils.dart:238; node managementnode_management_screen.dart. - Do: add an explicit opt-in "serve publicly" toggle, a keep-alive/headless or tray-resident lifecycle, and a status surface (sync height, reachability, public endpoint).
- Acceptance: with the toggle on, the node keeps serving when the main window is closed; off by default; clear security warning shown.
A.3 โ Public-serving security hardening ๐ขโ
- Where: Syrius + node config.
- Do: read-scope the public RPC (no wallet/signing endpoints), add rate limiting/connection
caps, enforce
wssfor non-localhost. See Specification ยง9. - Acceptance: public endpoint exposes only read/subscribe RPC; abuse controls in place.
Phase B โ Discovery, health & failover ๐ขโ
Build the layer that finds Sentinel endpoints and routes clients to healthy ones. Reuses existing Syrius scaffolding.
B.1 โ Signed service recordsโ
- Where: Syrius + operator tooling (
znn-controller). - Spec: ยง5. Do: define + verify the signed
{owner, endpoint, capabilities, version, issuedAt, expiresAt, nonce, signature}record; verify signature, expiry, and thatowneris inembedded.sentinel.getAllActive()/getByOwner(). - Acceptance: an invalid/expired/non-active record is rejected before probing.
B.2 โ Populate the discovery slotโ
- Where:
syrius/lib/main.dart,assets/community-nodes.json. - Anchors: loader
_loadDefaultCommunityNodes(main.dart:180-192), validatorInputValidators.node, shuffle (node_management_screen.dart:43). - Do: add a "Sentinel Nodes" category sourced from signed records (curated list first,
feed later) instead of the empty
[]. - Acceptance: verified Sentinel endpoints appear as a selectable node tier.
B.3 โ Health probing + scoringโ
- Where: Syrius (
node_utils.dart). - Anchors:
establishConnectionToNode(node_utils.dart:20),getNodeChainIdentifier(:28); currently used only for the active node (:92,236), not as a pre-filter. - Spec: ยง7โยง8 (gating vs. scoring). Do: probe reachability + chain ID (gates) then score sync freshness, RPC correctness, latency, subscriptions, peers; rank; re-probe periodically.
- Acceptance: unhealthy/wrong-chain nodes are excluded; survivors are ranked and cached.
B.4 โ RPC failoverโ
- Where: Syrius (
NodeUtils). - Anchors: single
zenon!.wsClient(node_utils.dart:79-110). - Do: on active-node failure, fail over to the next-best ranked node.
- Acceptance: dropping the active node transparently reconnects to the next healthy one.
Phase C โ Trustless on-chain discovery ๐ดโ
Requires governance; out of MVP scope. Tracked so it isn't mistaken for buildable now.
| Task | Detail |
|---|---|
| C.1 | Add an endpoint (and optional capability/service-key) field to Sentinel Register + SentinelInfo + SDK. Blocker today: SentinelInfo has only owner/registrationTimestamp/isRevocable/revokeCooldown/active; register() encodes ('Register', []) (api/embedded/sentinel.dart:51). |
| C.2 | Move reward weighting from registration-duration to service quality: reward_weight = stake_valid ร reachability ร sync_freshness ร service_correctness ร uptime. |
Dependency orderโ
Phase 0 โโโบ A.1 โโโบ A.2 โโโบ A.3
โ
B.1 โโโบ B.2 โโโบ B.3 โโโบ B.4 (B.1โB.3 can start in parallel with A; B.2 needs B.1)
โ
โผ
Phase C (governance, later)
The smallest useful release = A.1 + A.2 + B.1 + B.2 + B.3 (operators serve publicly; Syrius discovers, verifies, and ranks them). No consensus change.