| description | Canonical Spring Boot backend for institutional identity, funding, lab access and on-chain operations. |
|---|
Lab Gateway/blockchain-services is the canonical Java 21 / Spring Boot 4.1
backend
for the DecentraLabs gateway ecosystem. It is also publishable as a standalone
WAR for an institution that only needs consumer funding and wallet operations.
The service owns four areas:
- institutional authentication and access delivery (SAML, Marketplace JWT, WebAuthn, JWKS and opaque access codes);
- institutional wallet, service-credit funding and billing administration;
- signed intent intake, WebAuthn authorization and on-chain execution;
- provider/consumer registration and gateway configuration.
Start with the documentation index and the parent documentation contract. The essential companion documents are the architecture guide, deployment guide, security baseline and API reference.
| Mode | Enablement | Intended use | Provider/auth endpoints |
|---|---|---|---|
| Provider + consumer | BLOCKCHAIN_SERVICES_MODE=provider-consumer |
Full or standalone control-plane backend | Enabled |
| Consumer-only | BLOCKCHAIN_SERVICES_MODE=consumer-only (packaged default) |
Standalone institution funding its own reservations | Disabled |
BLOCKCHAIN_SERVICES_MODE is the explicit backend role and is independent of
the parent gateway topology. Set it to provider-consumer or consumer-only.
When it is left empty, the service keeps the historical
FEATURES_PROVIDERS_ENABLED value as a fallback. An explicit role always wins,
so changing ISSUER or placing the process behind a Lite gateway cannot
silently enable provider operations.
FEATURES_PROVIDERS_REGISTRATION_ENABLED controls provider registration within
the provider-consumer role; it can never elevate a consumer-only backend.
FEATURES_ORGANIZATIONS_ENABLED controls organization features.
The parent Lab Gateway selects Full versus Lite at the gateway boundary; a Lite
gateway does not become the primary identity authority merely because this
backend is present.
flowchart LR
Full["Lab Gateway Full<br/>ISSUER empty/local"] --> Backend["blockchain-services"]
Lite["Lab Gateway Lite<br/>ISSUER points to Full /auth"] -->|access and observation| Full
Standalone["Standalone consumer"] --> Backend
Backend --> Contracts[("Smart Contracts")]
Backend --> DB[("MySQL / Flyway")]
The following is a navigation map, not a generated OpenAPI contract. Paths are
implemented by the controllers in src/main/java/decentralabs/blockchain/controller.
External institutional reservation requests use a five-minute pending TTL and require a ten-minute lead before the requested start. The provider listener retains 12-confirmation canonicality and uses 15-second polling/retry defaults; if finality misses the deadline, the request expires without confirmation or credit capture. Tune the timing and event configuration together with any reviewed Diamond upgrade.
GET /auth/jwksPOST /auth/authorize-and-issuePOST /auth/access-credentialPOST /auth/checkin-institutionalPOST /auth/checkin-institutional/statusPOST /auth/access-code/redeemPOST /auth/access-code/redeem/commitPOST /auth/access-code/redeem/releasePOST /auth/fmu/session-ticket/issuePOST /auth/fmu/session-ticket/redeemPOST /auth/fmu/provider-describe-tokenPOST /webauthn/revokeGET /onboarding/webauthn/key-status/{stableUserId}POST /onboarding/webauthn/optionsPOST /onboarding/webauthn/completeGET /onboarding/webauthn/status/{sessionId}GET /onboarding/webauthn/ceremony/{sessionId}
/auth/jwks and the FMU controllers are conditional on the resolved
provider-consumer role. The provider-side SAML/access routes
(/auth/authorize-and-issue, /auth/access-credential and
/auth/access-code/**) are also denied by the Spring Security boundary when
the backend runs in consumer-only; institutional check-in routes remain
available to the consumer role. FMU ticket issuance validates a booking
bearer; redemption requires a per-gateway session-observer credential and is
denied in consumer-only. Redemption also revalidates the reservation
on-chain, including ACCESS_AUTHORIZED, lab, payer/PUC binding and the active
window; cancellation events eagerly revoke matching tickets.
Access issuance is retryable rather than a long-polling HTTP operation:
/auth/authorize-and-issue and /auth/access-credential return a fast pending
response until the institutional check-in outbox has produced on-chain
ACCESS_AUTHORIZED. Guacamole/FMU provisioning starts only on a later retry
that observes that state; the check-in submission and receipt monitors run in
the background.
The controller maps OIDC discovery at /.well-known/openid-configuration, but
the current security allow-list is /auth/.well-known/*; it is therefore not a
supported reachable integration endpoint until the mappings are aligned.
POST /intentsGET /intents/{requestId}POST /intents/{requestId}/registration-minedPOST /intents/authorizeGET /intents/authorize/status/{sessionId}GET /intents/authorize/ceremony/{sessionId}POST /intents/authorize/completePOST /intents/authorize/client-error
When INTENTS_AUTH_ENABLED=true (default), submit operations require the
configured submit scope and reads require the configured status scope. The
browser ceremony and completion are intentionally session-bound; see the
intent guide.
- Wallet:
POST /wallet/create,POST /wallet/import,POST /wallet/reveal,GET /wallet/{address}/balance,GET /wallet/{address}/transactions,GET /wallet/listen-events,GET /wallet/networks,POST /wallet/switch-network. - Billing administration:
/billing/admin/**, funding orders and provider receivables. Read-only and mutating routes are listed in the wallet/billing guide. - Provisioning:
GET /institution-config/statusplus the challenge/approval flow underPOST /institution-config/*. - After Marketplace confirms the on-chain registration, the backend commits the
token-derived configuration and the role flag (
provider.registeredorconsumer.registered) as one atomicprovider.propertiesreplacement. A failed local commit leaves the previous snapshot intact and must be retried or reconciled against the chain; the filesystem write is not treated as a rollback of an already-mined transaction. - Compliance exports:
/billing/compliance/**. - Lab administration:
/lab-admin/**and/lab-content/**; see Lab administration and content.
These surfaces are network-restricted by LocalhostOnlyFilter; billing admin
also requires a valid internal/access token according to deployment mode.
The backend serves two browser-facing administrative surfaces. They are protected by the localhost/private-network boundary and the configured admin token; they are not public Marketplace pages.
| Surface | Route | Purpose |
|---|---|---|
| Wallet Dashboard | /wallet-dashboard/ |
Institutional wallet, balances, funding and billing administration. |
| Institutional pairing | /institution-config/ |
Marketplace challenge and backend registration ceremony. |
GET /health— detailed application status, including durable queue health.GET /billing/admin/contract-events/dead-letter— localhost/private-network operator view of durable event dead letters.GET /actuator/health/livenessGET /actuator/health/readinessGET /actuator/prometheusGET /actuator/metricsGET /actuator/info
Use readiness for an orchestrator. A DEGRADED detailed health response is not
equivalent to a process that is unavailable; inspect queue_health_errors and
the individual component statuses.
GET /health is the detailed application status page. It reports the operating
mode, key and registration checks, nonce/outbox backlog counters and queue
errors. A database or migration query failure is represented by a null count
and an error code; it must not be mistaken for an empty queue.
Provider receivable status reads use the bounded paginated contract getter.
Monitor provider_receivable.paginated_reads,
provider_receivable.paginated_pages and
provider_receivable.paginated_read_errors through Actuator/Prometheus.
RPC infrastructure should separately alert on legacy selector 0x10b6ba8f
(getLabProviderReceivable(uint256)); the application cannot observe
third-party clients that call the RPC node directly.
Email/ICS notifications are optional and disabled by the noop driver unless
enabled through NOTIFICATIONS_MAIL_ENABLED. Configure the SMTP or Microsoft
Graph driver with the NOTIFICATIONS_MAIL_* variables and use
GET|POST /billing/admin/notifications to inspect or update runtime settings.
The notification service includes the lab, reservation window, renter, payer
and transaction reference when those values are available.
Prerequisites: Java 21 and a POSIX shell or PowerShell. MySQL is required for durable tickets, outboxes, WebAuthn and audit flows; the unit-test suite uses its configured test infrastructure.
./mvnw test
./mvnw -DskipTests package
java -jar target/blockchain-services-1.0-SNAPSHOT.warFor a local consumer-only process, leave the provider flags at their defaults
and open http://localhost:8080/wallet-dashboard/. For a Full gateway, enable
the provider flags and use the parent repository's Docker Compose topology.
The local compose file in this repository is useful for a standalone backend:
cp .env.example .env
docker compose up -dFor the integrated gateway, use the parent Lab Gateway/docker-compose.yml and
its root .env; do not run two copies of the backend against the same port or
database. Persist /app/data, the MySQL volume, and the mounted key material.
Important configuration groups:
- contract and RPC:
CONTRACT_ADDRESS,BLOCKCHAIN_NETWORK_ACTIVE,ETHEREUM_*_RPC_URL; - wallet:
WALLET_FILE_PATH,WALLET_CONFIG_KEY_FILE,INSTITUTIONAL_WALLET_*; - identity:
PRIVATE_KEY_PATH,PUBLIC_KEY_PATH, Marketplace public-key URL, SAML trust and metadata settings; - admin boundary:
ADMIN_DASHBOARD_LOCAL_ONLY,ADMIN_DASHBOARD_ALLOW_PRIVATE,ADMIN_ALLOWED_CIDRS,SECURITY_ALLOW_PRIVATE_NETWORKS,ADMIN_ACCESS_TOKEN_*; - durable backend:
SPRING_DATASOURCE_*and the outbox/monitor intervals.
Configuration precedence is environment/secrets manager, then local .env,
then application.properties. The generated wallet configuration under the
persistent data directory is an additional wallet-specific source and must be
backed up together with its encryption key.
The tracked .env.example is the authoritative list of deployable environment
names. Never commit .env, private keys, wallet files or database volumes. The
deployment guide groups the required settings
and identifies state that must be persistent in production.
- Keep admin, wallet, billing, lab-admin and provisioning routes behind the localhost/private-network policy and a strong access token.
- Use SAML whitelist mode in production even though the development default is
SAML_IDP_TRUST_MODE=any. - Keep metadata HTTP disabled and restrict trusted proxy CIDRs.
- Persist
/app/dataand MySQL before enabling durable access, ticket or wallet flows. - Keep session-observer and gateway credentials per gateway; do not reuse one secret across Full/Lite instances.
See Security Configuration and Authentication and access evidence for the public security and access boundary. Detailed recovery and compliance runbooks are maintainer documentation kept outside the public documentation index.
Before a change is released:
./mvnw test
./mvnw -DskipTests packageFlyway migrations are under src/main/resources/db/migration. The release
workflow publishes the WAR and checksum from target/; keep migrations,
configuration metadata and the endpoint guides in the same change.
Keep changes on a feature branch, add or update tests for behavior changes, and update the relevant document in SUMMARY.md. The executable configuration and controller mappings are the source of truth; documentation must not advertise a route or scheduler that is not present in this repository.
