Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

sysnode-backend

Express API behind sysnode.info. Aggregates Syscoin Core RPC + Blockbook + masternode telemetry + a small authenticated subsystem for governance proposal drafts, vote reminders, and "Pay-with-Pali" collateral flows.

The public dashboard is served by sysnode-info; this repo is the backend half of that stack.

Runtime surface

Public, unauthenticated routes (read-only). Canonical URL casing is lowercase, matching the historical https://syscoin.dev/mnstats convention and the existing /govlist. Express's default routing is case-insensitive, so legacy camelCase callers (/mnStats, /mnList, …) continue to work at the route layer; the bundled nginx config (deploy/nginx/sysnode.conf.example) uses a case-insensitive regex match for the same reason, so external bookmarks/clients with mixed casing keep working through the same-origin proxy. New integrations should use lowercase.

  • GET /mnstats — chain + market + masternode summary, refreshed by services/sysMain.js
  • GET /mncount — historical masternode count series
  • GET /mnlist — fresh masternode_list RPC passthrough
  • POST /mnsearch — paginated/searched view over the in-memory tracker snapshot
  • POST /govlist — active + historical governance proposals (Syscoin Core gobject list)
  • GET /api/privacy/v1/pools/:poolId/snapshot — opt-in anonymous Classic ETH pool snapshots for local wallet verification; see configuration and protocol.
  • GET /api/privacy/v1/relayers — separately opt-in anonymous Classic ETH relayer discovery; see source checks and endpoint boundaries.

Authenticated routes (cookie + CSRF, same-site):

  • /auth/* — registration, verification, login, session, delete account
  • /vault — encrypted per-user blob (notification prefs, proposal drafts; one row per user, conditional GET/PUT with ETag)
  • /gov/* — masternode lookup, vote relay, vote receipts (/gov/mns/lookup, /gov/vote, /gov/receipts, …)
  • /gov/proposals/* — governance proposal wizard, submissions, collateral PSBT

Requirements

  • Node.js 26.12.1 (pinned in .nvmrc and CI; engines allow patched Node 26 releases from 26.12.1, below 27)
  • A reachable syscoind on mainnet or testnet, with RPC enabled
  • SMTP server for verification emails and vote reminders (or MAIL_TRANSPORT=log for dry-run)
  • SQLite 3 (via better-sqlite3, no separate install; native module compiles at npm install)

Optional, used only for the Pali PSBT collateral path:

  • A Blockbook instance for the same network as the RPC node (https://blockbook.syscoin.org/ for mainnet, https://blockbook-dev.syscoin.org/ for testnet)

Local development

git clone https://github.com/syscoin/sysnode-backend.git
cd sysnode-backend
nvm install && nvm use       # exact version from .nvmrc
npm ci
cp .env.example .env        # then edit — see .env.example for inline docs
npm run dev                 # nodemon on :3001
npm test                    # full jest suite (~830 cases)
npm run audit:prod          # fail on critical production dependency issues

Dependency Audit Triage

npm run audit:prod is wired into CI and fails on high or critical production vulnerabilities. The pinned syscoinjs-lib dependency uses ethers v6; the backend does not call ethers directly. Remaining low/moderate findings include the transitive Ethereum proof stack and other application dependencies. Review the current audit output rather than applying npm audit fix --force, which can replace the transaction library with an incompatible version.

pm2 is intentionally not an application dependency. If you use it for process supervision, install it globally or through your host image, as shown in the single-host deployment notes below.

Configuration

All configuration is via environment variables. .env.example is the source of truth and carries inline rationale for every field. The short form:

Variable Purpose
PORT, BASE_URL Where the server listens, and the public URL baked into email links
CORS_ORIGIN, FRONTEND_URL SPA origin for credentialed CORS and verification-link base
TRUST_PROXY Reverse-proxy hop count (or CIDR) so req.ip is the real client
SYSNODE_DB_PATH Path to the SQLite file (auto-created)
SYSNODE_AUTH_PEPPER 32-byte hex secret; required in production
SMTP_*, MAIL_FROM, MAIL_TRANSPORT Mail delivery; MAIL_TRANSPORT=log prints to stdout
SYSCOIN_RPC_HOST, SYSCOIN_RPC_PORT RPC endpoint (default 127.0.0.1:8370)
SYSCOIN_RPC_COOKIE_PATH Preferred — absolute path to Core's .cookie for same-host deployments
SYSCOIN_RPC_USER, SYSCOIN_RPC_PASS Fallback static creds for remote RPC nodes
SYSCOIN_NETWORK, SYSCOIN_BLOCKBOOK_URL Enables the Pay-with-Pali collateral PSBT path

Production authenticated deployment

Automatic, SHA-pinned deployment on the existing persistent host is documented in deploy/automation/README.md. It runs only after successful default-branch CI and preserves the live environment and database.

Real voting-key custody should use a same-origin deployment for the authenticated API surface. Serve the SPA and proxy /auth, /vault, and /gov from the same public HTTPS origin:

https://sysnode.info/        -> sysnode-info build
https://sysnode.info/auth/*  -> sysnode-backend
https://sysnode.info/vault/* -> sysnode-backend
https://sysnode.info/gov/*   -> sysnode-backend

This keeps the sid and csrf cookies host-only with Secure; SameSite=Lax, and lets the SPA read the csrf cookie from the same host before mirroring it into X-CSRF-Token. Do not deploy the real-key auth/vault/voting surface as sysnode.info plus a cross-site API host.

For production, set at least:

NODE_ENV=production
FRONTEND_URL=https://sysnode.info
CORS_ORIGIN=https://sysnode.info
TRUST_PROXY=1              # or the exact trusted proxy/CIDR for your edge
SYSNODE_AUTH_PEPPER=<32-byte-hex-secret>

Production startup refuses non-secure cookies, non-HTTPS FRONTEND_URL, or a credentialed CORS origin that differs from FRONTEND_URL.

Reverse proxy reference

A working same-origin nginx vhost lives at deploy/nginx/sysnode.conf.example. The example is the canonical reference, not a drop-in: copy it to /etc/nginx/conf.d/sysnode.conf, replace sysnode.example.com with your real hostname, then run sudo certbot --nginx -d <hostname> to obtain a Let's Encrypt cert and let Certbot rewrite the listen 443 ssl block. Any TLS terminator that preserves Host and forwards X-Forwarded-Proto: https will work — the example is nginx because that's what we run, not because nginx is special.

HSTS

Both apps emit Strict-Transport-Security from their own code: the backend via helmet's defaults (max-age=31536000; includeSubDomains), the frontend via the security-header map in sysnode-info/server.js. Do not add add_header Strict-Transport-Security at the edge — duplicating it produces two response headers, which is noisy in audits even though browsers only honour the first per RFC 6797 §8.1. The default Certbot snippet at /etc/letsencrypt/options-ssl-nginx.conf ships with HSTS enabled; comment that line out (or override per-vhost) when standing up a new box, otherwise every response will carry it twice.

Owning HSTS in code means any deployer — behind nginx, Caddy, a managed load balancer, or directly on a TLS-terminating Node — gets HSTS without having to remember to add it at their edge.

Production host hardening

On production hosts, expose only SSH and the TLS terminator publicly. The Node processes on :3000 and :3001 are implementation details behind nginx and should not be reachable directly from the internet. If the app processes bind all interfaces, enforce this with the host firewall or cloud security group:

sudo ufw default deny incoming
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Do not allow 3000/tcp or 3001/tcp on production. The /auth, /vault, /gov, /mnstats, /mncount, /mnlist, /mnsearch, and /govlist paths should be reachable only through the same-origin nginx vhost described above. Before syscoind is running, the backend is expected to fail closed if SYSCOIN_RPC_COOKIE_PATH is missing; nginx will return 502 for backend routes rather than exposing partial authenticated functionality.

Cookie vs static RPC auth

The backend supports both authentication modes and picks cookie over static when both are configured (with a one-line warning at boot). Cookie auth is zero-secret-management: syscoind rewrites the cookie on every restart, and the backend picks up the new token automatically via a 401-driven replay. Use it for any deployment where the backend runs on the same host as syscoind.

For remote RPC nodes, either configure rpcauth= in syscoin.conf and use the static SYSCOIN_RPC_USER / SYSCOIN_RPC_PASS here, or mount the cookie file via a secure channel.

Full-stack test deployment (single host)

These steps stand up sysnode-backend + sysnode-info on one Ubuntu box that already runs syscoind. HTTP-only; intended for staging and testing, not production. Everything installs into the user's home directory — no sudo required on most steps (a couple of optional hardening steps do need it; they are clearly marked).

The commands below target Ubuntu 24.04 LTS with Node 26.12.1. Port layout: backend :3001, frontend :3000. For an existing production installation, follow the runtime migration requirements in the deployment guide before restarting either service.

1. Node.js 26.12.1 + basic tooling

Use the exact Node version in .nvmrc; the operating system's default Node package may be older. The package engine requires Node ≥ 26.12.1, < 27. Node 20, 22 and 24 are not qualified for this revision.

# Install the pinned runtime if it is not already available
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc
nvm install 26.12.1 && nvm use 26.12.1

# Use a user-local npm prefix so global installs don't need sudo
mkdir -p ~/.npm-global ~/.local/bin
npm config set prefix ~/.npm-global
echo 'export PATH="$HOME/.npm-global/bin:$HOME/.local/bin:$PATH"' >> ~/.bashrc
export PATH="$HOME/.npm-global/bin:$HOME/.local/bin:$PATH"

npm install -g pm2 serve

2. Transactional email provider

Email delivery (account verification, password-change notices, vote reminders, proposal status updates) goes through any SMTP provider you choose — SMTP2GO, SendGrid, Brevo, Postmark, Mailgun, AWS SES, or a corporate mail relay all work identically from the app's perspective. Pick one, verify a sender domain you control on their dashboard, and note its SMTP host / port / username / password. You'll paste those into .env in the next section.

Governance reminders use a fresh, same-tip Core snapshot, not the market/dashboard cache. SYSCOIN_NETWORK must be mainnet or testnet; the service verifies the configured network's genesis, sync state and governance parameters before sending. Reads abort after a 20-second overall budget and a moving tip gets one retry. The two reminder buckets are 24–72 hours and at most 24 hours before estimated payout-trigger selection, using Core's 150-second block projection and its RPC maturity-block count. Reminders stop once the maturity height is reached. This is not a claim that Core refuses later proposal votes.

Only valid proposal objects with a supported calendar window are included. Timestamp fields must be integer Unix seconds with 0 <= start < end <= 253402300799 (year 9999). This notification/presentation bound does not change Core validity: malformed or millisecond-looking on-chain dates are excluded, never reinterpreted. Payment eligibility follows Core's two-hour window tolerance. Vote receipts are matched to the governance object ID, not its separate data hash. A locally recorded relayed/confirmed vote on any eligible proposal suppresses both buckets; votes made through other tools may be unknown, so email copy does not assert that the recipient has not voted. Preferences and their existing defaults are unchanged.

The log deduplicates by user, next-superblock height and bucket; one in-process tick runs at a time to avoid overlap while SMTP is pending. A snapshot older than 60 seconds stops further deliveries until a fresh tick. SMTP and SQLite are not one atomic transaction: a crash or log failure after SMTP accepts a message can still cause a retry, so this is best-effort delivery, not exactly-once mail.

Governance vote delivery distinguishes rejection from uncertainty. Each Core RPC has a 10-second transport deadline and a vote batch has a 30-second total deadline. No timed-out vote is automatically retried: a response lost after submission is reported as submission_unknown, not as a successful relay or a definite failure. Entries the batch never invoked are not_submitted and do not create receipts. Response totals are accepted, rejected (definite only), unknown, and notSubmitted. A valid Core JSON-RPC rejection remains definite, including when delivered with HTTP 500.

An uncertain receipt records the latest requested intent. Another submission is held until explicit reconciliation: the exact time/outcome/signal confirms it; a newer on-chain vote can supersede it with an explicit marker. Older votes do not confirm a newer uncertain intent. Fresh Core reconciliation after the 10-minute grace period can mark a still-unobserved request stale for an explicit retry; elapsed time or a cached/failed read alone cannot do so. Reconciliation uses conditional updates so late reads cannot overwrite a newer request. No vote signatures or private keys are stored in receipt rows, and no database migration is needed for the additional status. Relay completions follow Core's signed-time/outcome ordering (equal-time yes < no < abstain), retaining a newer or higher-outcome uncertain intent rather than presenting an older success as its result. For the same intent, weaker late results cannot overwrite known success. This does not bypass Core's independent receive-time vote cooldown. When the configured receipt store cannot be read, that entry is not submitted: availability must not bypass an unresolved delivery hold. Other independent entries may still proceed. This does not change vote signatures or key custody. Receipt writes after a broadcast remain best-effort: if storage fails, the API still reports uncertainty and the client must retain its hold, but a restart or lost client state cannot rely on a receipt that was never persisted. This is not an exactly-once submission guarantee.

In production the backend refuses to boot unless SMTP_HOST is set (or MAIL_TRANSPORT=log is set explicitly for stdout-only dry-run), so this step is required before the backend will start with NODE_ENV=production.

3. Clone both repos

mkdir -p ~/apps && cd ~/apps
git clone https://github.com/syscoin/sysnode-backend.git
git clone https://github.com/syscoin/sysnode-info.git

4. Configure the backend

cd ~/apps/sysnode-backend
npm ci

# Locate the Core cookie (path depends on the user that runs syscoind)
ls -l ~/.syscoin/.cookie 2>/dev/null || sudo ls -l /root/.syscoin/.cookie

PEPPER=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")
COOKIE_PATH=/home/ubuntu/.syscoin/.cookie   # adjust to match the ls above
SERVER_IP=$(hostname -I | awk '{print $1}') # or hardcode the public IP

cat > .env <<EOF
PORT=3001
BASE_URL=http://${SERVER_IP}:3001
CORS_ORIGIN=http://${SERVER_IP}:3000
FRONTEND_URL=http://${SERVER_IP}:3000
NODE_ENV=development
TRUST_PROXY=loopback
SYSNODE_DB_PATH=./data/sysnode.db
SYSNODE_AUTH_PEPPER=${PEPPER}

# SMTP — paste your transactional provider's credentials here. Port 465 is
# treated as implicit TLS; any other port (587 is standard) uses STARTTLS.
# MAIL_FROM must be a sender address you have verified at the provider.
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
MAIL_FROM=no-reply@example.com
MAIL_TRANSPORT=smtp

# Syscoin Core RPC (cookie mode, preferred for same-host)
SYSCOIN_RPC_HOST=127.0.0.1
SYSCOIN_RPC_PORT=8370
SYSCOIN_RPC_COOKIE_PATH=${COOKIE_PATH}
SYSCOIN_RPC_LOG_LEVEL=error

# Pay-with-Pali (mainnet)
SYSCOIN_NETWORK=mainnet
SYSCOIN_BLOCKBOOK_URL=https://blockbook.syscoin.org/
EOF

mkdir -p data

The backend does not load .env automatically. It has no dotenv dependency. We load the file with Node's native --env-file= flag (available in the pinned Node runtime), which is why every invocation of node for this repo below passes --env-file=.env.

Cookie file permissions. If the backend user can't read ~/.syscoin/.cookie (different uid than syscoind), add rpccookieperms=group to ~/.syscoin/syscoin.conf and restart syscoind, then add the backend's user to the syscoin group. The backend's boot log prints the exact errno (ENOENT / EACCES) if it can't read the file.

Quick sanity check — confirms .env is loaded and RPC cookie auth works against Core:

node --env-file=.env -e '
  const { client, rpcServices } = require("./services/rpcClient");
  rpcServices(client.callRpc).getBlockchainInfo().call()
    .then(r => console.log(r.chain, r.blocks, "ibd=" + r.initialblockdownload))
    .catch(e => { console.error(e.message); process.exit(1); });
'
# expected: "main <height> ibd=false"

5. Build and serve the frontend

REACT_APP_API_BASE is a Create React App build-time variable — it must be set before npm run build or the bundle will keep pointing at the default.

cd ~/apps/sysnode-info
npm ci
SERVER_IP=$(hostname -I | awk '{print $1}')
REACT_APP_API_BASE=http://${SERVER_IP}:3001 npm run build

6. Start both under pm2

cd ~/apps/sysnode-backend
pm2 start "node --env-file=.env server.js" --name sysnode-backend

cd ~/apps/sysnode-info
pm2 start "serve -s build -l 3000" --name sysnode-info

pm2 save
pm2 list

Optional — survive a full reboot. Requires sudo; skip if you don't have it and just run pm2 resurrect after any reboot:

pm2 startup systemd -u $USER --hp $HOME   # prints one sudo line; paste it

7. Firewall (optional)

If ufw isn't active on the host, your cloud security-group / network-layer rules are what matter — adjust those instead.

sudo ufw status
# If active:
sudo ufw allow 3000/tcp   # frontend
sudo ufw allow 3001/tcp   # backend API

8. Smoke-test end to end

# Backend reachable + RPC cookie auth working (real stats from Core)
curl -s http://<server-ip>:3001/mnstats | head -c 200

# Mail pipeline. Replace TEST_RECIPIENT with an inbox you can open. If SMTP is
# wired up correctly a verification email arrives within seconds — check the
# spam folder too, transactional mail from a brand-new sender domain often
# lands there until reputation builds at the receiver.
cd ~/apps/sysnode-backend
TEST_RECIPIENT=you@example.com node --env-file=.env -e '
  const { createMailer } = require("./lib/mailer");
  createMailer({ transport: "smtp" }).sendVerification({
    to: process.env.TEST_RECIPIENT,
    link: process.env.BASE_URL + "/auth/verify?t=smoketest",
  }).then(() => console.log("sent to " + process.env.TEST_RECIPIENT))
    .catch(e => { console.error("FAILED:", e.message); process.exit(1); });
'

Then exercise the UI:

  1. Open http://<server-ip>:3000 — dashboard loads.
  2. Register a user in the UI with an email address you can open — the verification email should arrive within seconds (check the spam folder too). Click the link to activate the account.
  3. Go into the governance proposal wizard — the Pay with Pali button should be enabled (assuming your browser has Pali installed and the chain guard verified mainnet).

Updating the stack

pm2 stop sysnode-backend sysnode-info

cd ~/apps/sysnode-backend
git pull && npm ci

cd ~/apps/sysnode-info
git pull && npm ci
REACT_APP_API_BASE=http://<server-ip>:3001 npm run build

pm2 restart sysnode-backend sysnode-info

Troubleshooting

Symptom Likely cause Check
Backend exits at boot, failed to read rpc cookie at ... ENOENT Wrong SYSCOIN_RPC_COOKIE_PATH sudo -u <syscoind-user> cat <path>
Backend exits at boot, ... EACCES Backend user can't read the cookie Use rpccookieperms=group + usermod -aG
Backend rejects RPC with 401 after a Core restart once, then recovers Expected — cookie rotated, backend replayed with the new one No action
Pay with Pali button disabled paliChainGuard reports pali_path_chain_mismatch or pali_path_rpc_down GET /gov/proposals/network returns a paliPathReason
Verification emails never arrive SMTP creds wrong, sender domain not verified at the provider, or mail filtered into spam Check backend logs for 5xx SMTP responses, the provider's dashboard for bounces/delivery status, and the recipient's spam folder
Frontend hits https://syscoin.dev instead of the test backend REACT_APP_API_BASE not set at build time Rebuild with the env var inline

Sentry management API

Enable /api/sentry/v1/ with the existing SYSCOIN_NETWORK and SYSCOIN_BLOCKBOOK_URL settings plus SYSCOIN_SENTRY_GENESIS_HASH for the exact configured network. The Core node must provide protx_capabilities and, for PQ operators, extended protx_operator_key_info. Missing capability metadata disables signing; the backend never guesses an activation state from key length. Run Core with txindex=1 and wait for the transaction index to synchronize before enabling management: historical registration and transaction readback use getrawtransaction. Transport errors or an unavailable/syncing index are not treated as transaction absence and do not demote confirmed operation records.

GET /capabilities and GET /context are rate-limited public chain reads for wallets. All node-watch and operation endpoints require a verified session; writes also require the configured exact Origin and the existing CSRF token. The public API remains /api/sentry/v1/, including Pali's default https://sysnode.info/api/sentry/v1/context. The proxy example forwards that path without rewriting. Existing proxies that strip the leading /api are also supported through the internal /sentry/v1/ prefix. Both forms mount the same router, session/CSRF checks and rate-limit buckets; the internal prefix is not a separate public API or a weaker authentication path. Do not expose raw backend ports or change the wallet's trusted service URL to accommodate a proxy. The existing live proxy and Core metadata APIs must be verified after rollout; updating these repository examples alone does not update deployed systems. No route accepts an RPC URL, RPC method name, or owner/operator private key.

POST /api/sentry/v1/nodes accepts a public watch record { network, proTxHash, label?, preserveExisting? }. The optional boolean preserveExisting: true is intended for batch imports: an existing label for the same user, network and ProTx hash is retained atomically, even if another tab saved it during the on-chain lookup. It still validates the registered node independently before inserting. Omit the option (or use false) to retain the existing single-node label-update behavior. The response remains the user's complete watch list. Watching a node grants no signing authority and imports no private key.

GET /api/sentry/v1/voting-context?network=testnet&proposalHash=<hash>&proTxHashes=<hash1>,<hash2> is a public, read-only observation for Pali's governance-vote approval. It accepts at most 20 unique lowercase ProTx hashes and uses the same independently pinned Core network/genesis check. Its fixed gobject_get call verifies a valid, non-deleted proposal and returns the on-chain name/URL, not a dapp-provided title. The optional URL is omitted unless it is an HTTP(S) address without credentials; this does not reject an otherwise valid proposal with a non-web URI. The response is { chain, now, proposalHash, proposal: { name, url? }, nodes }; each node has { proTxHash, collateralOutpoint: { txid, vout }, votingKeyId, valid: true }. valid means a confirmed registered identity with a voting key, not a claim about its hosting provider or operational status. Active PQ voting is not supported by this legacy ECDSA context and is explicitly rejected. The request has a 10-second total deadline, at most four concurrent node reads, and a 64-KiB limit per Core response. It has a separate 12-request-per-minute IP limit shared across both proxy prefixes, in addition to the normal read limit. A changed chain tip rejects the combined observation so the wallet can request a fresh one. This endpoint does not sign, relay, import or persist anything; the existing /gov/vote relay and encrypted browser-vault voting path are unchanged.

After deployment, run the anonymous, read-only verifier with independently trusted chain expectations (do not copy the genesis from the service being checked):

npm run verify:sentry-deployment -- \
  --origin https://sysnode.info --network mainnet \
  --genesis <trusted-genesis-hash> --era legacy-v3

Optionally add --pro-tx-hash <known-node-hash> to check the public node-context route. The command requires HTTPS, rejects redirects, bounds each request to 10 seconds and 128 KiB, and exits nonzero on an HTML/rewritten route, mismatched chain, missing operations or broken anonymous-auth boundary. A legacy-v3 check also requires PQ preparation to be explicitly false and rejects advertised PQ operations. --era pq-v4 is an explicit different expectation, not an automatic fallback. --timeout-ms can set a request deadline up to 30 seconds. Successful output is JSON with ok: true; no server bodies or credentials are printed on failure. It sends only unauthenticated GETs to capabilities, operations and, when requested, context. It does not log in, inspect a user's history, sign or broadcast. Authenticated writes and a real operator lifecycle still require their separate rollout validation; this check cannot certify them.

Preparation uses the shared @sidhujag/sysweb3-sentry codec and public fee-account data. /operations/:id/authorize checks completed wallet authorizations and returns a fee-signing PSBT. /operations/:id/submit checks the stored immutable transaction, current authority, fee limit and testmempoolaccept, then records the exact signed bytes and transaction ID before one broadcast attempt. GET /operations/:id reconciles uncertain submissions and verifies on-chain readback. It never creates a replacement transaction. SQLite journals contain public transaction data only and are isolated by authenticated user ID. After a network failure, the user may explicitly request POST /operations/:id/retry with an empty body. The backend checks for the original transaction first, then revalidates and republishes only the stored signed bytes if needed. A per-operation cooldown and atomic claim bound retries; no new signature, new transaction ID, replacement transaction or fee bump occurs.

Run npm test -- --runInBand and npm run test:sentry-codec. Codec integration uses real legacy/PQ signatures and fee signatures with synthetic RPC fixtures; it does not submit transactions to a public network.

For the actual legacy consensus smoke test, set SENTRY_CORE_BIN to a directory containing the metadata-enabled syscoind and syscoin-cli, then run npm run test:sentry-core. It creates a fresh disconnected regtest and synthetic wallet, registers a node, signs NEVM add/update/remove requests with the shared SDK, and requires Core mempool acceptance plus mined registration readback. The test stops its Core process and prints its isolated temporary data directory for inspection. It never uses a configured service RPC or an existing wallet.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages