hardware acceleration and support for NVIDIA cards on nonfree images (#3089)

* add nvidia packages

* add nvidia deps to nonfree

* gpu_acceleration flag & nvidia hacking

* fix gpu_config & /tmp/lxc.log

* implement hardware acceleration more dynamically

* refactor OpenUI

* use mknod

* registry updates for multi-hardware-requirements

* pluralize

* handle new registry types

* remove log

* migrations and driver fixes

* wip

* misc patches

* handle nvidia-container differently

* chore: comments (#3093)

* chore: comments

* revert some sizing

---------

Co-authored-by: Matt Hill <mattnine@protonmail.com>

* Revert "handle nvidia-container differently"

This reverts commit d708ae53df.

* fix debian containers

* cleanup

* feat: add empty array placeholder in forms (#3095)

* fixes from testing, client side device filtering for better fingerprinting resistance

* fix mac builds

---------

Co-authored-by: Sam Sartor <me@samsartor.com>
Co-authored-by: Matt Hill <mattnine@protonmail.com>
Co-authored-by: Alex Inkin <alexander@inkin.ru>
This commit is contained in:
Aiden McClelland
2026-01-15 11:42:17 -08:00
committed by GitHub
parent e8ef39adad
commit 99871805bd
95 changed files with 2758 additions and 1092 deletions

View File

@@ -40,7 +40,9 @@ export namespace Mock {
squashfs: {
aarch64: {
publishedAt: '2025-03-21T23:55:29.583006392Z',
url: 'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_aarch64.squashfs',
urls: [
'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_aarch64.squashfs',
],
commitment: {
hash: 'OUnANnZePtf7rSbj38JESl+iJAV0z0aiZ4opCiwpGbo=',
size: 1331900416,
@@ -52,7 +54,9 @@ export namespace Mock {
},
'aarch64-nonfree': {
publishedAt: '2025-03-21T23:56:38.299572946Z',
url: 'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_aarch64-nonfree.squashfs',
urls: [
'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_aarch64-nonfree.squashfs',
],
commitment: {
hash: '6k+0RcyRQV+5A+h06OqpHxd4IT6IlFkfdy9dfHIP90c=',
size: 1641500672,
@@ -64,7 +68,9 @@ export namespace Mock {
},
raspberrypi: {
publishedAt: '2025-03-22T00:08:17.083064390Z',
url: 'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_raspberrypi.squashfs',
urls: [
'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_raspberrypi.squashfs',
],
commitment: {
hash: 'K+XuTZxo1KVsKjNSV8PPOMruCvAEZwerF9mbpFl53Gk=',
size: 1544417280,
@@ -76,7 +82,9 @@ export namespace Mock {
},
x86_64: {
publishedAt: '2025-03-22T00:05:57.684319247Z',
url: 'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_x86_64.squashfs',
urls: [
'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_x86_64.squashfs',
],
commitment: {
hash: '3UVkx3TQMBPlSU1OnV48Om9vjjA3s+Nk6dX3auYGpBo=',
size: 1424007168,
@@ -88,7 +96,9 @@ export namespace Mock {
},
'x86_64-nonfree': {
publishedAt: '2025-03-22T00:07:11.893777122Z',
url: 'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_x86_64-nonfree.squashfs',
urls: [
'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_x86_64-nonfree.squashfs',
],
commitment: {
hash: 'IS1gJ56n/HlQqFbl1upMOAtLxyxB0cY0H89Ha+9h1lE=',
size: 1743425536,
@@ -110,7 +120,9 @@ export namespace Mock {
squashfs: {
aarch64: {
publishedAt: '2025-04-21T20:58:48.140749883Z',
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_aarch64.squashfs',
urls: [
'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_aarch64.squashfs',
],
commitment: {
hash: '4elBFVkd/r8hNadKmKtLIs42CoPltMvKe2z3LRqkphk=',
size: 1343500288,
@@ -122,7 +134,9 @@ export namespace Mock {
},
'aarch64-nonfree': {
publishedAt: '2025-04-21T21:07:00.249285116Z',
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_aarch64-nonfree.squashfs',
urls: [
'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_aarch64-nonfree.squashfs',
],
commitment: {
hash: 'MrCEi4jxbmPS7zAiGk/JSKlMsiuKqQy6RbYOxlGHOIQ=',
size: 1653075968,
@@ -134,7 +148,9 @@ export namespace Mock {
},
raspberrypi: {
publishedAt: '2025-04-21T21:16:12.933319237Z',
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_raspberrypi.squashfs',
urls: [
'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_raspberrypi.squashfs',
],
commitment: {
hash: '/XTVQRCqY3RK544PgitlKu7UplXjkmzWoXUh2E4HCw0=',
size: 1490731008,
@@ -146,7 +162,9 @@ export namespace Mock {
},
x86_64: {
publishedAt: '2025-04-21T21:14:20.246908903Z',
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_x86_64.squashfs',
urls: [
'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_x86_64.squashfs',
],
commitment: {
hash: '/6romKTVQGSaOU7FqSZdw0kFyd7P+NBSYNwM3q7Fe44=',
size: 1411657728,
@@ -158,7 +176,9 @@ export namespace Mock {
},
'x86_64-nonfree': {
publishedAt: '2025-04-21T21:15:17.955265284Z',
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_x86_64-nonfree.squashfs',
urls: [
'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_x86_64-nonfree.squashfs',
],
commitment: {
hash: 'HCRq9sr/0t85pMdrEgNBeM4x11zVKHszGnD1GDyZbSE=',
size: 1731035136,
@@ -234,6 +254,7 @@ export namespace Mock {
source: 'packed',
arch: ['x86_64', 'aarch64'],
emulateMissingAs: 'aarch64',
nvidiaContainer: false,
},
},
volumes: ['main'],
@@ -242,6 +263,7 @@ export namespace Mock {
arch: null,
ram: null,
},
hardwareAcceleration: false,
}
export const MockManifestLnd: T.Manifest = {
@@ -292,6 +314,7 @@ export namespace Mock {
source: 'packed',
arch: ['x86_64', 'aarch64'],
emulateMissingAs: 'aarch64',
nvidiaContainer: false,
},
},
volumes: ['main'],
@@ -300,6 +323,7 @@ export namespace Mock {
arch: null,
ram: null,
},
hardwareAcceleration: false,
}
export const MockManifestBitcoinProxy: T.Manifest = {
@@ -343,6 +367,7 @@ export namespace Mock {
source: 'packed',
arch: ['x86_64', 'aarch64'],
emulateMissingAs: 'aarch64',
nvidiaContainer: false,
},
},
volumes: ['main'],
@@ -351,6 +376,7 @@ export namespace Mock {
arch: null,
ram: null,
},
hardwareAcceleration: false,
}
export const BitcoinDep: T.DependencyMetadata = {
@@ -376,7 +402,6 @@ export namespace Mock {
'26.1.0:0.1.0': {
title: 'Bitcoin Core',
description: mockDescription,
hardwareRequirements: { arch: null, device: [], ram: null },
license: 'mit',
wrapperRepo: 'https://github.com/start9labs/bitcoind-startos',
upstreamRepo: 'https://github.com/bitcoin/bitcoin',
@@ -398,12 +423,20 @@ export namespace Mock {
stop: 'test',
restore: 'test',
},
s9pk: {
url: 'https://github.com/Start9Labs/bitcoind-startos/releases/download/v26.1.0/bitcoind.s9pk',
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
s9pks: [
[
{ arch: null, device: [], ram: null },
{
urls: [
'https://github.com/Start9Labs/bitcoind-startos/releases/download/v26.1.0/bitcoind.s9pk',
],
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
],
],
hardwareAcceleration: false,
},
'#knots:26.1.20240325:0': {
title: 'Bitcoin Knots',
@@ -411,7 +444,6 @@ export namespace Mock {
short: 'An alternate fully verifying implementation of Bitcoin',
long: 'Bitcoin Knots is a combined Bitcoin node and wallet. Not only is it easy to use, but it also ensures bitcoins you receive are both real bitcoins and really yours.',
},
hardwareRequirements: { arch: null, device: [], ram: null },
license: 'mit',
wrapperRepo: 'https://github.com/start9labs/bitcoinknots-startos',
upstreamRepo: 'https://github.com/bitcoinknots/bitcoin',
@@ -433,12 +465,20 @@ export namespace Mock {
stop: 'test',
restore: 'test',
},
s9pk: {
url: 'https://github.com/Start9Labs/bitcoinknots-startos/releases/download/v26.1.20240513/bitcoind.s9pk',
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
s9pks: [
[
{ arch: null, device: [], ram: null },
{
urls: [
'https://github.com/Start9Labs/bitcoinknots-startos/releases/download/v26.1.20240513/bitcoind.s9pk',
],
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
],
],
hardwareAcceleration: false,
},
},
categories: ['bitcoin', 'featured'],
@@ -456,7 +496,6 @@ export namespace Mock {
'26.1.0:0.1.0': {
title: 'Bitcoin Core',
description: mockDescription,
hardwareRequirements: { arch: null, device: [], ram: null },
license: 'mit',
wrapperRepo: 'https://github.com/start9labs/bitcoind-startos',
upstreamRepo: 'https://github.com/bitcoin/bitcoin',
@@ -478,12 +517,20 @@ export namespace Mock {
stop: 'test',
restore: 'test',
},
s9pk: {
url: 'https://github.com/Start9Labs/bitcoind-startos/releases/download/v26.1.0/bitcoind.s9pk',
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
s9pks: [
[
{ arch: null, device: [], ram: null },
{
urls: [
'https://github.com/Start9Labs/bitcoind-startos/releases/download/v26.1.0/bitcoind.s9pk',
],
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
],
],
hardwareAcceleration: false,
},
'#knots:26.1.20240325:0': {
title: 'Bitcoin Knots',
@@ -491,7 +538,6 @@ export namespace Mock {
short: 'An alternate fully verifying implementation of Bitcoin',
long: 'Bitcoin Knots is a combined Bitcoin node and wallet. Not only is it easy to use, but it also ensures bitcoins you receive are both real bitcoins and really yours.',
},
hardwareRequirements: { arch: null, device: [], ram: null },
license: 'mit',
wrapperRepo: 'https://github.com/start9labs/bitcoinknots-startos',
upstreamRepo: 'https://github.com/bitcoinknots/bitcoin',
@@ -513,12 +559,20 @@ export namespace Mock {
stop: 'test',
restore: 'test',
},
s9pk: {
url: 'https://github.com/Start9Labs/bitcoinknots-startos/releases/download/v26.1.20240513/bitcoind.s9pk',
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
s9pks: [
[
{ arch: null, device: [], ram: null },
{
urls: [
'https://github.com/Start9Labs/bitcoinknots-startos/releases/download/v26.1.20240513/bitcoind.s9pk',
],
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
],
],
hardwareAcceleration: false,
},
},
categories: ['bitcoin', 'featured'],
@@ -538,7 +592,6 @@ export namespace Mock {
'0.17.5:0': {
title: 'LND',
description: mockDescription,
hardwareRequirements: { arch: null, device: [], ram: null },
license: 'mit',
wrapperRepo: 'https://github.com/start9labs/lnd-startos',
upstreamRepo: 'https://github.com/lightningnetwork/lnd',
@@ -563,12 +616,20 @@ export namespace Mock {
stop: 'test',
restore: 'test',
},
s9pk: {
url: 'https://github.com/Start9Labs/lnd-startos/releases/download/v0.17.5/lnd.s9pk',
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
s9pks: [
[
{ arch: null, device: [], ram: null },
{
urls: [
'https://github.com/Start9Labs/lnd-startos/releases/download/v0.17.5/lnd.s9pk',
],
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
],
],
hardwareAcceleration: false,
},
},
categories: ['lightning'],
@@ -586,7 +647,6 @@ export namespace Mock {
'0.17.4-beta:1.0-alpha': {
title: 'LND',
description: mockDescription,
hardwareRequirements: { arch: null, device: [], ram: null },
license: 'mit',
wrapperRepo: 'https://github.com/start9labs/lnd-startos',
upstreamRepo: 'https://github.com/lightningnetwork/lnd',
@@ -611,12 +671,20 @@ export namespace Mock {
stop: 'test',
restore: 'test',
},
s9pk: {
url: 'https://github.com/Start9Labs/lnd-startos/releases/download/v0.17.4/lnd.s9pk',
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
s9pks: [
[
{ arch: null, device: [], ram: null },
{
urls: [
'https://github.com/Start9Labs/lnd-startos/releases/download/v0.17.4/lnd.s9pk',
],
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
],
],
hardwareAcceleration: false,
},
},
categories: ['lightning'],
@@ -638,7 +706,6 @@ export namespace Mock {
'27.0.0:1.0.0': {
title: 'Bitcoin Core',
description: mockDescription,
hardwareRequirements: { arch: null, device: [], ram: null },
license: 'mit',
wrapperRepo: 'https://github.com/start9labs/bitcoind-startos',
upstreamRepo: 'https://github.com/bitcoin/bitcoin',
@@ -660,12 +727,20 @@ export namespace Mock {
stop: 'test',
restore: 'test',
},
s9pk: {
url: 'https://github.com/Start9Labs/bitcoind-startos/releases/download/v27.0.0/bitcoind.s9pk',
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
s9pks: [
[
{ arch: null, device: [], ram: null },
{
urls: [
'https://github.com/Start9Labs/bitcoind-startos/releases/download/v27.0.0/bitcoind.s9pk',
],
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
],
],
hardwareAcceleration: false,
},
'#knots:27.1.0:0': {
title: 'Bitcoin Knots',
@@ -673,7 +748,6 @@ export namespace Mock {
short: 'An alternate fully verifying implementation of Bitcoin',
long: 'Bitcoin Knots is a combined Bitcoin node and wallet. Not only is it easy to use, but it also ensures bitcoins you receive are both real bitcoins and really yours.',
},
hardwareRequirements: { arch: null, device: [], ram: null },
license: 'mit',
wrapperRepo: 'https://github.com/start9labs/bitcoinknots-startos',
upstreamRepo: 'https://github.com/bitcoinknots/bitcoin',
@@ -695,12 +769,20 @@ export namespace Mock {
stop: 'test',
restore: 'test',
},
s9pk: {
url: 'https://github.com/Start9Labs/bitcoinknots-startos/releases/download/v26.1.20240513/bitcoind.s9pk',
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
s9pks: [
[
{ arch: null, device: [], ram: null },
{
urls: [
'https://github.com/Start9Labs/bitcoinknots-startos/releases/download/v26.1.20240513/bitcoind.s9pk',
],
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
],
],
hardwareAcceleration: false,
},
},
categories: ['bitcoin', 'featured'],
@@ -718,7 +800,6 @@ export namespace Mock {
'0.18.0:0.0.1': {
title: 'LND',
description: mockDescription,
hardwareRequirements: { arch: null, device: [], ram: null },
license: 'mit',
wrapperRepo: 'https://github.com/start9labs/lnd-startos',
upstreamRepo: 'https://github.com/lightningnetwork/lnd',
@@ -743,12 +824,20 @@ export namespace Mock {
stop: 'test',
restore: 'test',
},
s9pk: {
url: 'https://github.com/Start9Labs/lnd-startos/releases/download/v0.18.0.1/lnd.s9pk',
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
s9pks: [
[
{ arch: null, device: [], ram: null },
{
urls: [
'https://github.com/Start9Labs/lnd-startos/releases/download/v0.18.0.1/lnd.s9pk',
],
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
],
],
hardwareAcceleration: false,
},
},
categories: ['lightning'],
@@ -766,7 +855,6 @@ export namespace Mock {
'0.3.2.7:0': {
title: 'Bitcoin Proxy',
description: mockDescription,
hardwareRequirements: { arch: null, device: [], ram: null },
license: 'mit',
wrapperRepo: 'https://github.com/Start9Labs/btc-rpc-proxy-wrappers',
upstreamRepo: 'https://github.com/Kixunil/btc-rpc-proxy',
@@ -790,12 +878,20 @@ export namespace Mock {
stop: 'test',
restore: 'test',
},
s9pk: {
url: 'https://github.com/Start9Labs/btc-rpc-proxy-startos/releases/download/v0.3.2.7/btc-rpc-proxy.s9pk',
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
s9pks: [
[
{ arch: null, device: [], ram: null },
{
urls: [
'https://github.com/Start9Labs/btc-rpc-proxy-startos/releases/download/v0.3.2.7/btc-rpc-proxy.s9pk',
],
commitment: mockMerkleArchiveCommitment,
signatures: {},
publishedAt: Date.now().toString(),
},
],
],
hardwareAcceleration: false,
},
},
categories: ['bitcoin'],

View File

@@ -10,13 +10,11 @@ export abstract class ApiService {
abstract uploadFile(guid: string, body: Blob): Promise<void>
// for getting static files: ex license
abstract getStaticProxy(
pkg: MarketplacePkg,
path: 'LICENSE.md',
abstract getStatic(
urls: string[],
params: Record<string, string | number>,
): Promise<string>
abstract getStatic(url: string): Promise<string>
// websocket
abstract openWebsocket$<T>(

View File

@@ -45,29 +45,22 @@ export class LiveApiService extends ApiService {
// for getting static files: ex: license
async getStaticProxy(
pkg: MarketplacePkg,
path: 'LICENSE.md',
async getStatic(
urls: string[],
params: Record<string, string | number>,
): Promise<string> {
const encodedUrl = encodeURIComponent(pkg.s9pk.url)
return this.httpRequest({
method: 'GET',
url: `/s9pk/proxy/${encodedUrl}/${path}`,
params: {
rootSighash: pkg.s9pk.commitment.rootSighash,
rootMaxsize: pkg.s9pk.commitment.rootMaxsize,
},
responseType: 'text',
})
}
async getStatic(url: string): Promise<string> {
return this.httpRequest({
method: 'GET',
url,
responseType: 'text',
})
for (let url in urls) {
try {
const res = await this.httpRequest<string>({
method: 'GET',
url,
params,
responseType: 'text',
})
return res
} catch (e) {}
}
throw new Error('Could not fetch static file')
}
// websocket

View File

@@ -75,19 +75,14 @@ export class MockApiService extends ApiService {
await pauseFor(2000)
}
async getStaticProxy(
pkg: MarketplacePkg,
path: 'LICENSE.md',
async getStatic(
urls: string[],
params: Record<string, string | number>,
): Promise<string> {
await pauseFor(2000)
return markdown
}
async getStatic(url: string): Promise<string> {
await pauseFor(2000)
return markdown
}
// websocket
openWebsocket$<T>(

View File

@@ -142,7 +142,23 @@ export class MarketplaceService {
}
fetchStatic$(pkg: MarketplacePkg): Observable<string> {
return from(this.api.getStaticProxy(pkg, 'LICENSE.md'))
const registryAsset = pkg.s9pks[0]?.[1]
if (!registryAsset) {
throw new Error('No s9pk')
}
const urls =
registryAsset.urls.map(
u => `/s9pk/proxy/${encodeURIComponent(u)}/LICENSE.md`,
) || []
return from(
this.api.getStatic(urls, {
rootSighash: registryAsset.commitment.rootSighash,
rootMaxsize: registryAsset.commitment.rootMaxsize,
}),
)
}
private fetchRegistry$(url: string): Observable<StoreDataWithUrl | null> {