Skip to content

Latest commit

 

History

History
227 lines (182 loc) · 11.2 KB

DEVNET.md

File metadata and controls

227 lines (182 loc) · 11.2 KB

Shared DevNet runbook — HackCanton Season 3 node

Noders provides a shared DevNet sandbox for Season 3 teams so you build logic, not infrastructure. Status 2026-09-27: the public demo (https://100-30-125-235.nip.io) runs against the shared node with auto-refreshing offline tokens (EUR €70k→€30k + USD $312k→$40k settled through the public site, receipts + pain.001 verified).

Package note (2026-09-27): the repo now carries hardened contracts — Approval is bound to a proposal-terms hash and fully-netted cycles settle with zero transfers. A Daml change produces a new package id, and the shared node only vets packages the Noders operator approves. The live demo therefore keeps running the previously vetted package (d1b3b958…) until the new one is vetted.

Live state (2026-10-08): the demo runs the audited package netsettle-v2-1.0.0 (5eccaf6d…), vetted, with CANTON_TERMS_BINDING=on. The pre-audit package 0467433b… remains vetted for rollback. Verified on the shared node after the flip: EUR 70k->30k and USD 312k->40k settled with 4 receipts, privacy proof green for all four subsidiaries, and the new authorization guards return 403/404 as designed.

Historical upgrade sequence:

  1. Ask the Noders operator (Discord support / mentor channel) to vet package netsettle-v2-1.0.0 at its new hash — see the ask template below.
  2. Upload daml/.daml/dist/netsettle-v2-1.0.0.dar via the Console UI (same login).
  3. On the demo host (ssh -i ~/.ssh/netsettle-key.pem ec2-user@100.30.125.235):
    cd /opt/netsettle && git pull
    pnpm install --frozen-lockfile
    (cd daml && dpm build)
    # Confirm the built package id equals what was vetted, then point the app at it:
    dpm inspect-dar daml/.daml/dist/netsettle-v2-1.0.0.dar | grep -oE 'netsettle-v2-1\.0\.0-[0-9a-f]{64}' | head -1
    sed -i 's/^CANTON_PACKAGE_ID=.*/CANTON_PACKAGE_ID=<vetted package id>/' apps/web/.env.local
    sed -i 's/^CANTON_TERMS_BINDING=.*/CANTON_TERMS_BINDING=on/' apps/web/.env.local
    sudo systemctl restart netsettle-web.service
    curl -s localhost:3100/api/state | grep -o '"packageId":"[^"]*"'
    Then run the full flow once (ingest → review → propose → approve → settle) and check /api/view before announcing. The parties stay the same; only the package id changes. CANTON_TERMS_BINDING=off is what lets the app keep serving the older package today: leave it off until the new package is vetted, then flip it on with the id change.
  4. Keep the old package vetted for rollback; pointing CANTON_PACKAGE_ID back is the only rollback step.

Operator ask (copy-paste):

Hi Noders team — HackCanton team NetSettle (Track 1, package netsettle, currently live and vetted on hackcanton-01 as d1b3b958…).

We hardened our Daml contracts: approvals now bind to a hash of the exact proposal terms, and fully-netted cycles settle with zero transfers. The new build is package id 5eccaf6d8061169762a7f091a3ee8f69ccf814b69b1dbb5d748b846fa87c8d24, same version netsettle-v2-1.0.0 (592,681 bytes, sha256 17f972f231d4f5d61d9386008c0934d4143846ee8467dcc7ece3320c58cb6670).

It's not on the node yet — our app identity gets a 403 on POST /v2/packages, so we can only upload through the Console UI. Two ways to unblock, whichever is easier: we upload the DAR ourselves and you vet it, or you upload and vet it. Happy to send the DAR however suits. Our existing operator + 4 subsidiary parties can stay exactly as they are — this is a package swap only.

Not urgent: the current vetted package keeps the demo running. Thanks!

Source: Season 3 materials (official) + live endpoint probes.

Endpoints

Resource Endpoint
JSON Ledger API https://ledger-api-json.participant.hackcanton-01.devnet.naas.noders.services
gRPC Ledger API ledger-api-grpc.participant.hackcanton-01.devnet.naas.noders.services:443
Wallet https://wallet.validator.hackcanton-01.devnet.naas.noders.services
CNS https://cns.validator.hackcanton-01.devnet.naas.noders.services
Console https://console.participant.hackcanton-01.devnet.naas.noders.services
Validator / Scan API https://validator-api-http.validator.hackcanton-01.devnet.naas.noders.services
Grafana logs https://grafana.participant.hackcanton-01.devnet.naas.noders.services
OIDC token URL https://keycloak.naas.noders.services/realms/noders-appsfactory/protocol/openid-connect/token
Token audience https://hackcanton-01.devnet.naas.noders.services

Shared node = shared ledger. No sensitive data. Our demo parties and contracts are visible to every team on the node.

Step 1 — Get tokens (needs your platform login, 2 minutes)

Password grants are disabled on the wallet client, but the official guide documents a working grant on the web-app client with offline_access:

curl -sS 'https://keycloak.naas.noders.services/realms/noders-appsfactory/protocol/openid-connect/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=password' \
  --data-urlencode 'client_id=web-app-ui-hackcanton-01-devnet' \
  --data-urlencode 'username=<YOUR_PLATFORM_EMAIL>' \
  --data-urlencode 'password=<YOUR_PLATFORM_PASSWORD>' \
  --data-urlencode 'scope=openid daml_ledger_api offline_access' > tokens.json
  • access_token: valid 3 hours, sent as Authorization: Bearer to the node.
  • refresh_token: offline token, no fixed expiry — valid until revoked or unused too long. This is what makes DevNet fully live: the app auto-refreshes the access token forever (see below). Guard it like a password.

For a quick browser-sourced token instead: wallet → DevTools → Local Storage. That access token works but dies in hours with no refresh path.

Step 2 — Upload via Console UI; vetting + parties need the node operator

Wallet API tokens on the shared node are heavily restricted (probed 2026-09-23, all with a valid token):

Action Result
Read packages / ledger-end / vetting list / whoami ✅ works
Upload DAR (/v2/packages, /v2/dars) ❌ 403
Vet package (/v2/package-vetting/update) ❌ 403
Allocate party (Daml Script over gRPC+TLS) ❌ PERMISSION_DENIED

Status (re-verified 2026-10-01): the demo package d1b3b958…dee64f is vetted and live — /v2/packages returns it, and the running app settles against it. The hardened package 33437385… is not on the node at all: POST /v2/package-vetting/list returns zero unvetted package ids, so an earlier note saying it had been "uploaded via Console" was wrong. POST /v2/packages still returns 403 for our app identity, so the DAR has to go up through the Console UI before anyone can vet it.

Funding: ~900 CC obtained on our party (covers all demo traffic fees with orders of magnitude to spare — one future blocker pre-solved). Once the operator party exists, a small CC transfer to it covers submission fees.

Resolution path: one ask to Noders (Discord support/mentor channel) covers everything — vet the package AND allocate 5 parties (or grant our user party-allocation rights). Draft ask below.

  1. Open https://console.participant.hackcanton-01.devnet.naas.noders.services and sign in.
  2. Upload daml/.daml/dist/netsettle-v2-1.0.0.dar. (0.1.0 done 2026-09-23; 1.0.0 uploaded and vetted 2026-10-08, live.)
  3. Vet package netsettle (uniquely named — no collisions with other teams). (Blocked — needs operator.)
  4. Allocate 5 parties (operator + 4 subsidiaries) or equivalent rights. (Blocked — needs operator.)

Step 3 — One command does the rest

UPLOADED=1 VETTED=1 TOKEN=<paste> bash scripts/devnet-deploy.sh

The script allocates operator + 4 subsidiaries over gRPC and writes apps/web/.env.devnet (git-ignored). If gRPC allocation also hits permission errors, allocate via the Console UI and paste the party IDs into .env.devnet by hand (format in apps/web/.env.local.example).

Note: our DAR builds under SDK 3.5.1; the node runs 3.5.17. Same 3.5 line — expected compatible; the upload response will confirm or deny. If party allocation over gRPC fights TLS, fall back to allocating via the Console UI and paste the party IDs into .env.devnet by hand.

Step 4 — Run the flow against DevNet (staging only)

Point a local app run at .env.devnet and walk ingest → settle → payment file. Do not repoint the public EC2 app — keep the judged demo on the reproducible local ledger unless the DevNet run is fully green.

Staying live: auto-refresh

The gateway accepts a token provider backed by TokenManager (packages/canton-gateway/src/tokenRefresh.ts): cached access token, pre-emptive refresh 60s before expiry, rotation tracking, optional persistence. The web app wires it when CANTON_REFRESH_TOKEN is set (apps/web/lib/ledger.ts):

Variable Purpose
CANTON_REFRESH_TOKEN Offline refresh token from Step 1. Enables indefinite access.
CANTON_OIDC_TOKEN_URL Override (defaults to the DevNet realm).
CANTON_OIDC_CLIENT_ID Override (defaults to web-app-ui-hackcanton-01-devnet).
CANTON_REFRESH_TOKEN_FILE Optional path where rotated refresh tokens persist across restarts.
CANTON_API_TOKEN Fallback: static access token for short sessions.

Refresh tokens are password-equivalent: server-side only (SSM/env), never committed, never sent to browsers, never sent to the ledger — only to the token endpoint. If refresh fails with "Token is not active", re-run the Step 1 password grant.

What DevNet buys us (and what it doesn't)

  • Buys: "settled on shared Canton DevNet" in the pitch + Q&A; real multi-participant topology instead of single-node sandbox.
  • Doesn't buy: real assets (still test obligations), wallet UX (still server-mediated approvals), Featured status.
  • Costs: shared-node flakiness, credential management, ~1 day.

Recommendation: attempt once the MVP freeze holds; timebox to one day. If the node fights back, the local-ledger demo plus this runbook is the fallback story — "DevNet-ready, reproducible locally."

If SSH times out (it will, when your home IP changes)

The demo host's security group netsettle-sg (sg-01274cf91fbb413db) allows SSH only from a single /32. A residential IP changes without warning, and the node then silently drops port 22 — the box looks fine over HTTPS, so it reads as "the host is down" when it is only your source address that stopped matching.

Diagnose in one line:

curl -s https://ifconfig.me                      # your current egress IP
nc -zv 100.30.125.235 443                        # open -> host is alive
nc -zv 100.30.125.235 22                         # timeout -> SG dropped you

Fix with the AWS CLI (no console needed):

aws ec2 authorize-security-group-ingress --group-id sg-01274cf91fbb413db \
  --ip-permissions "IpProtocol=tcp,FromPort=22,ToPort=22,IpRanges=[{CidrIp=$(curl -s https://ifconfig.me)/32,Description='ssh from current egress IP'}]"

ssh -i ~/.ssh/netsettle-key.pem ec2-user@100.30.125.235

Prefer a durable option if you get tired of this: EC2 Instance Connect (push-based, needs no inbound SSH rule at all) or pin the SG to a range you control. Do not leave 0.0.0.0/0 on port 22 for longer than the hackathon.