deviant/scripts/asm-sequencer/deploy/asm-sequencer.service
Local Dev 07fd344299 feat(asm-sequencer): systemd + user-funded /tip+/submit + wallet client
Three-part completion of the tier-2 arc from 0278:

1. systemd — scripts/asm-sequencer/deploy/{asm-sequencer.service,README.md}
   Sandboxed unit (NoNewPrivileges, ProtectSystem=strict, PrivateTmp,
   MemoryDenyWriteExecute), EnvironmentFile at /etc/asm-sequencer/env,
   SIGINT graceful shutdown, auto-restart, nginx reverse-proxy snippet.

2. User-funded endpoints — server.mjs adds:
   GET  /tip      current reservoir + token metadata for local tx build
   POST /submit   body {signedTxHex, tipTxid, tipVout, amountUnits}
                  under mutex: verify tip, provider.sendRawTransaction,
                  advance local chain. 409 stale with currentTip on race.

   Chipnet proof via scripts/chipnet-asm-sequencer-userfunded-test.mjs:
     5/5 accepted, 15 total /submit attempts (mean 3.0), 6.6 s wall time,
     daemon chain depth 0 → 5. Users signed their own BCH inputs locally;
     daemon received signed hex only, never saw a user key.
     Txids: 32ba4055… → 10945cf9… → 71ef9a7e… → ed8fedaa… → 05e7f66d…

   Funded A/C/E/F/G from H via new scripts/chipnet-fund-from-h.mjs
   (one tx dc725fa5f3252b40…, 5×150k sats outputs, 32.6M-sat change
   back to H).

3. Wallet-side client — sequencerRelay.ts in both:
   - shells/app/src/asm-core/
   - design/potidaea/src/

   Same API: getSequencerEndpoint/setSequencerEndpoint (localStorage
   key asm-sequencer.endpoint), sequencerReachable, sequencerClaim,
   claimViaRelayOrFallback. Probe-first-then-commit dispatch — the
   relay and local path both advance the SAME reservoir UTXO so parallel
   execution would create a self-double-spend risk; the probe cost is
   worth paying for correctness. Default disabled; opts in via LS key.

Snapshot 0279 + wiki/asm/zero-contention-protocol.md updated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-10-02 00:21:51 +02:00

60 lines
1.7 KiB
Desktop File

[Unit]
Description=ASM sequencer (tier-2 relay for same-target reservoir races)
Documentation=file:///opt/deviant/wiki/asm/zero-contention-protocol.md
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=asm-seq
Group=asm-seq
WorkingDirectory=/opt/deviant
# EnvironmentFile holds the coordinator WIF, listen port, token selection.
# Must be mode 600, owned by asm-seq:asm-seq. Never commit this file.
# PORT=8710
# COORD=h (chipnet) or <your-prod-handle>
# TOKEN=asm2
# MAX_CHAIN_DEPTH=200
EnvironmentFile=/etc/asm-sequencer/env
ExecStart=/usr/bin/node /opt/deviant/scripts/asm-sequencer/server.mjs
# Graceful SIGINT shutdown (the server prints its totalServed stats on signal)
KillSignal=SIGINT
TimeoutStopSec=15
# Automatic restart with backoff — the sequencer is stateless (first /claim
# after restart re-fetches tip from the node), so restarts are safe.
Restart=on-failure
RestartSec=5
# Sandboxing — the only writes the service does are chipnet broadcasts via
# the configured electrum. No local filesystem writes required.
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
RestrictNamespaces=yes
SystemCallArchitectures=native
# Resource caps — a sequencer serving one category has a small footprint.
MemoryHigh=256M
MemoryMax=512M
TasksMax=64
# Network — only outbound to the chipnet electrum pool + inbound on PORT.
# Bind-mount or firewall rules handle the inbound; the service doesn't need
# raw-socket or multicast access.
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
[Install]
WantedBy=multi-user.target