dcp-worker 3.3.11 → 3.3.12-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.gitlab-ci.yml CHANGED
@@ -81,6 +81,7 @@ tidelift:
81
81
  # Run `trunk check` on the project to hightlight newly introduced lint issues
82
82
  # when compared to the target branch.
83
83
  check:
84
+ allow_failure: true
84
85
  variables:
85
86
  # Can't cache `~/.cache/trunk/`.
86
87
  TRUNK_CACHE: ${CI_PROJECT_DIR}/.cache/trunk/
package/.trunk/trunk.yaml CHANGED
@@ -27,3 +27,6 @@ runtimes:
27
27
  lint:
28
28
  enabled:
29
29
  - eslint@8.52.0
30
+ threshold:
31
+ - linters: [ALL]
32
+ level: high
package/README.md CHANGED
@@ -1,47 +1,150 @@
1
1
  # DCP-Worker
2
2
 
3
- This is the official Node DCP Worker implementation for DCP, the Distributed Compute Protocol.
4
- This code implements a DCP Worker which is intended to be executed interactively and supplies
5
- necessary library routines and packages for implementing other worker types (eg the DCP Service Worker).
3
+ This is the official DCP Worker program for the Distributive Compute Platform.
6
4
 
7
- Note that, in order to run this DCP Worker, you also need a DCP Evaluator; we use a completely separate
8
- build process, unrelated to NodeJS and NPM, to create our evaluators for security reasons. Our native
9
- evaluator embeds Google's V8 JavaScript engine directly; this evaluator hosts the sandbox which executes
10
- DCP workload.
5
+ This package implements a DCP Worker which can be executive interactively, or a system service, using
6
+ Node.js to communicate with the scheduler and control the DCP Evaluator.
11
7
 
12
- You can find a complete package for Linux, including Evaluator binaries at https://archive.distributed.computer/releases/,
8
+ A companion program, the DCP Evaluator, is required to use this worker. When you install the DCP Worker
9
+ with your system's package manager, the installer will automatically install the DCP Evaluator as
10
+ `dcp-evaluator-v8` or `dcp-evaluator`. The DCP Evaluator is a secure sandboxing tool which uses the V8 JavaScript engine
11
+ and the Dawn WebGPU engine from Google to execute JavaScript, WebAssembly, and WebGPU code.
12
+
13
+ You can find a complete package for Linux, including Evaluator binaries at https://archive.distributed.computer/releases/,
13
14
  and documentation at https://docs.distributed.computer/worker/readme.html. If you are a developer
14
15
  who interested in porting the Evaluator to your own platform, please contact us and we will
15
16
  grant you early access to the MIT-licensed source code. The build is CMake with GN and largely
16
17
  based around V8.
17
18
 
18
- This code, without the evaluator binaries, is used for DCP LocalExec, a debugging tool for DCP Client developers.
19
-
20
- ## Record of Issue
21
-
22
- Date | Author | Change
23
- ----------- | ---------------- | ---------------------------------------------
24
- May 4 2021 | Wes Garland | Updated to reflect Scheduler v4 Release
25
- May 29 2020 | Wes Garland | Early Developer Preview Release
26
- Mar 29 2021 | Wes Garland | DCP Service Worker moved to separate package
19
+ This package is also used for DCP LocalExec, a local debugging tool for developers using DCP Client.
27
20
 
28
21
  ## Release Notes
29
-
30
- ### Implementation Status
31
- DCP is currently (May 2020) in testing for a limited set of developers under our Early Developer Preview program. If you would like to be part of our *First Dev* cohort, visit https://dcp.dev/ and sign up!
22
+ This document was last updated Sep 12, 2024.
32
23
 
33
24
  ### Supported Platforms
34
- - Node.js version 12 (LTS)
35
- - Ubuntu Linux 18.04 (LTS)
36
- - Ubuntu Linux 20.04 (LTS)
25
+ - Node.js (all maintenance, active, current releases)
26
+ - Microsoft Windows 10, 11
27
+ - Ubuntu Linux 20.04
28
+ - Ubuntu Linux 22.04
29
+ - Ubuntu Linux 24.04
37
30
  - More to come
38
31
 
39
- ### Related Products
40
- Other utilities for developers working with DCP can be retrieved via npm, and include:
41
-
42
- * [`dcp-client`](https://npmjs.com/package/dcp-client) - the official client library for DCP, the Distributed Compute Protocol
43
- * [`dcp-util`](https://npmjs.com/package/dcp-util) - a series of utilities for working with DCP; manipulate keystores, cancel jobs, etc.
44
- * [`niim`](https://www.npmjs.com/package/niim) - a command-line debugger for NodeJS (fork of node-inspect) which can debug DCP programs (passphrase prompts cause problems with node-inspect mainline)
32
+ ## Manifest
33
+ | File | Purpose
34
+ |:---------------------------|:------------------------------------------------
35
+ | bin/dcp-worker | Program which requests work from the scheduler and coordinates its evaluation in a secure environment called dcp-evaluator-v8
36
+ | bin/dcp-evaluator-start | Program which launches dcp-evaluator-v8
37
+ | bin/dcp-evaluator-manager | Program which which manages the launching of dcp-evaluator-v8; e.g. based on system load, terminal activity, screensaver activity, etc.
38
+ | etc/dcp-worker-config.js | Default configuration for dcp-worker
39
+
40
+ ### Related Packages
41
+ - dcp-evaluator-v8, our isolated JS/WASM/WebGPU evaluation environment, ships separately. Installing dcp-worker with your system's package manager will automatically install dcp-evaluator-v8 as a dependency.
42
+
43
+ ## Troubleshooting
44
+ The following conditions must be met for a Worker to do work:
45
+ * the Evaluator must be startable - normally managed with `dcp-evaluator-manager`
46
+ * the Worker must be running
47
+ * there must be work available on the scheduler that is suitable for this worker
48
+ * the worker must have the correct capabilities (GPU?)
49
+ * the job's payment must exceed the worker's minimum wage
50
+ * the worker and the job must be in the same Compute Group
51
+
52
+ ### Check: Worker is running
53
+ This varies from platform to platform. This document assumes the Worker was installed from an
54
+ OS-specific package supplied by Distributive.
55
+
56
+ #### All Operating Systems
57
+ The `dcp-worker` program in this package normally runs as a system service, but it can also be run as an
58
+ interactive program. This program displays configuration information and shows what it is doing with the
59
+ Evaluator in real time. `dcp-worker -h` shows a help screen; to run in interactive mode, simply start
60
+ `bin/dcp-worker` from a terminal window without any `-o` options.
61
+
62
+ Administrators with a large number of workers may wish to configure [syslog](https://en.wikipedia.org/wiki/Syslog)
63
+ logging, and use an off-the-shelf logging aggregation service. The full gamut of options relating to
64
+ syslog output are documented in the `dcp-worker` help screen. Note that only one type of output at a
65
+ time is currently possible with `dcp-worker`; Linux administrators who want both system journals and
66
+ syslog output will need to configure their local syslog service to receive messages from systemd.
67
+
68
+ The Worker can log its activities to a variety of destinations (dependent on operating system), and
69
+ emits logs when new jobs are fetched, job slices are completed, and so on.
70
+
71
+ #### Microsoft Windows
72
+ The Worker is installed as a Windows Service, and can be managed via the Windows Service Manager.
73
+ To open the Windows Services Manager on Windows 10 or 11:
74
+ * Press Windows-X or right-click the start button to open the WinX menu
75
+ * Choose `Run`
76
+ * Type `sevices.msc` in the Run box and press enter
77
+
78
+ By default, the DCP Worker service writes logs to the Windows Event Viewer, but can be sent to a remote
79
+ syslog service if so desired.
80
+
81
+ To open the event viewer on Windows 10 or 11, click
82
+ * Start
83
+ * Control Panel
84
+ * System and Security
85
+ * Administrative Tools
86
+
87
+ Next, double-click Event Viewer, and select DCP Worker logs.
88
+
89
+ #### Ubuntu Linux
90
+ On Ubuntu Linux, the Worker is started under the control of [systemd](https://systemd.io/), running as
91
+ the user `dcp`. The Worker communicates with the Scheduler and uses an Evaluator to execute workload.
92
+ By default, the Worker logs are written to the system journal, but can be sent to a remote syslog
93
+ service if so desired. The systemd unit is named `dcp-worker`.
94
+
95
+ | Action | Command
96
+ |:---------------------------|:------------------------------------------------
97
+ | View all DCP systemd units | systemctl --no-pager list-units 'dcp*' --all
98
+ | Stop the Worker | sudo systemctl stop dcp-worker
99
+ | Start the Worker | sudo systemctl start dcp-worker
100
+ | Restart the Worker | sudo systemctl restart dcp-worker
101
+ | View the journal (logs) | sudo systemctl journalctl -u dcp-worker -f
102
+
103
+ The default configuration runs `bin/dcp-worker -o console`, which sends log output to stdout/stderr; this
104
+ output is captured by systemd and recorded in the system journals.
105
+ `sudo systemctl journalctl -u dcp-worker --since='15 minutes ago'` will show recent activity.
106
+
107
+ ### Check: Evaluator is running
108
+ This varies from platform to platform. This document assumes the Worker was installed from an
109
+ OS-specific package supplied by Distributive.
110
+
111
+ #### Microsoft Windows
112
+ The Evaluator is automatically started by the Distributive Screensaver.
113
+
114
+ #### Ubuntu Linux
115
+ On Ubuntu Linux, the Evaluator is started by `dcp-evaluator-manager`, under the control of
116
+ [systemd](https://systemd.io/), running as the user `dcp`. The Evaluator Manager is responsible for
117
+ disabling the Evaluator when the system load changes, the screen saver deactivatees, or a terminal
118
+ becomes active.
119
+
120
+ | Action | Command
121
+ |:---------------------------|:------------------------------------------------
122
+ | View all DCP systemd units | systemctl --no-pager list-units 'dcp*' --all
123
+ | Stop the Evaluator | sudo systemctl stop dcp-evaluator-manager
124
+ | Start the Evaluator | sudo systemctl start dcp-evaluator-manager
125
+ | Restart the Evaluator | sudo systemctl restart dcp-evaluator-manager
126
+ | View the journal (logs) | sudo systemctl journalctl -u dcp-evaluator-manager -f
127
+
128
+ ## Systems Integration
129
+ This DCP Worker package can be integrated into a wide variety of systems. Distributive currently
130
+ (Aug 2024) ships a Windows screensaver, an Ubuntu (Debian) package, and a Dockerized version of the
131
+ Debian package.
132
+
133
+ Systems integrators should be aware that the Evaluator (processes named `dcp-evaluator-v8`) can be
134
+ killed at any time to immediately decrease system load. A program called `dcp-evaluator-manager`
135
+ can be used to automate this; it can kill running Evaluators based on screensaver or terminal activity,
136
+ and refuse to spawn new Evaluators based on current system load. Systems Integrators familiar with
137
+ `inetd` will understand that `dcp-evaluator-manager` is a variation on this theme, and can be replaced
138
+ a similar program should a more suitable one exist to manage load for the environment in question.
139
+
140
+ Systems integrators should leave the `dcp-worker` program running as much as possible. This process
141
+ consumes very few resources, but manages the transmission of results to the Scheduler. During system
142
+ shutdown, delivering a single SIGINT to `dcp-worker` will cause it submit all pending results to the
143
+ Scheduler, return all pending slices, etc. This graceful shutdown will take less than 30 seconds
144
+ (usually much less).
145
+
146
+ No DCP job or process will be irrepairably damanged by killing any process on a Worker node. The worst
147
+ that can happen is that work with pending results will be routed to another node.
45
148
 
46
149
  ## DCP Glossary
47
150
  ### Entities
@@ -61,6 +164,9 @@ A Node.js daemon which
61
164
  * enables the movement of DCC between the ledger and the blockchain
62
165
  * enables the placement of DCC in escrow on behalf of the Scheduler for work which is anticipated to be done
63
166
 
167
+ #### Compute Group
168
+ A collection of Workers and Jobs
169
+
64
170
  #### Portal
65
171
  A user-facing web application which allows or enables
66
172
  * creation and management of user accounts
@@ -83,7 +189,7 @@ A JavaScript program which includes a Supervisor and one or more Sandboxes
83
189
  A component of a Worker, used to execute arbitrary JavaScript code in a secure environment.
84
190
 
85
191
  #### Supervisor
86
- The component of a Worker which communicates with the Scheduler and Sandboxen.
192
+ The component of a Worker which communicates with the Scheduler and Sandboxes.
87
193
 
88
194
  ### Concepts
89
195
  #### Job
@@ -111,24 +217,16 @@ A parallel supercomputer consisting of one or more schedulers and workers. When
111
217
  A ledger which acts a repository for DCC which is not on the block chain. The Bank can move DCC between Bank Accounts much more quickly than it can move DCC between Addresses on the Ethereum block chain network. Meta data attached to bank accounts can restrict certain operations, such as ear-marking funds for use only by job deployment.
112
218
 
113
219
  #### Address
114
- A unique identifier in DCP which can be used as a Bank Account identifier (account number) or Address on the Ethereum network.
220
+ A unique identifier in DCP which can be used to identity a bank account, user, compute group, etc.
115
221
 
116
- #### Wallet
117
- In the general (blockchain) sense, a wallet is a piece of software that allows the user to interact with the greater economy as a whole. So as your actual wallet in your pocket has your cash and credit cards and you access your wallet in order to make a purchase and keep records (by pulling out cash or cards, and stuffing receipts back in), a blockchain wallet performs a similar function in that it gives you a place to store your private keys (your money), it provides a balance of what all those moneys add up to, it provides a way to receive moneys and send moneys, and provides a record of all those sends and receives. Most blockchain wallets provide at least 3 basic functions
118
- 1. generate and stores your public/private key pairs
119
- 2. allow you to use those key pairs through transactions (allows you to craft and transmit transactions to the peers)
120
- 3. keep a record of the transactions
121
-
122
- Additionally, most of the current crypto wallets (such as Bitcoin core) provide blockchain validation and consensus functions in that they can act to create or validate new blocks to the chain in addition to creating or validating transactions.
123
-
124
- ##### Distributed.Computer Wallet
125
- The Distributed.Computer acts as a Wallet; the platform exposes Wallet-related functionality both via software APIs and the portal web site.
126
- - Public/private key pairs are generated via the portal, wallet API, and command-line utilities
127
- - Public/private key pairs are stored in the database as passphrase-protected Keystores
128
- - Public/private key pairs stored in the Distributed.Computer Wallet can be retrieved via the portal webite
222
+ #### Key
223
+ A secret number that corresponds to an address. The address can be derived mathematically from the key, but the key cannot be derived from the address. In DCP, access is granted to a resource identitified by an address by signing a message with the key. This a very common public-key-private-key encryption technique, and is why it is important to safeguard your keys.
129
224
 
130
225
  #### Keystore
131
- A data structure which stores an encrypted key pair (address + private key). Generally speaking, the keystore will be encrypted with a passphrase.
226
+ A data structure which stores a key. The key can be safeguarded from prying eyes by encrypting it with a passphrase within the keystore.
132
227
 
133
228
  ### Keystore File
134
- A file which stores a JSON-encoded Keystore.
229
+ A file which stores a Keystore.
230
+
231
+ #### Wallet
232
+ A collection of Keystores.
@@ -19,13 +19,14 @@
19
19
  */
20
20
  'use strict';
21
21
 
22
- const os = require('os');
23
- const fs = require('fs');
24
- const path = require('path');
25
- const net = require('net');
26
- const dns = require('dns');
27
- const debug = require('debug');
28
- const getopt = require('posix-getopt');
22
+ const os = require('os');
23
+ const fs = require('fs');
24
+ const path = require('path');
25
+ const net = require('net');
26
+ const dns = require('dns');
27
+ const debug = require('debug');
28
+ const getopt = require('posix-getopt');
29
+ const pidfile = require('../lib/pidfile');
29
30
 
30
31
  var userActivity = { /* no props true => okay to launch evaluator */
31
32
  screensaver: true,
@@ -42,6 +43,7 @@ const daemonConfig = {
42
43
  net: new URL('tcpip://localhost:9000/'),
43
44
  proc: require.resolve('./dcp-evaluator-start'),
44
45
  argv: [ '-s', '--prefix', `${path.resolve(defaultPrefix)}/` ],
46
+ pidfile: pidfile.getDefaultPidFilename,
45
47
  limits: {
46
48
  loadavgType: 'short',
47
49
  randomLoadSamples: new Array(5).fill(0.5),
@@ -68,11 +70,13 @@ Usage: ${process.argv[0]} [-h | --help] [--prefix=<dir>] [--pts=<dir>] [-a]
68
70
  [-p port] [-l | --max-load=<number>] [-r | --rate=<number>] [-L]
69
71
  [-s | --signal=[name or number][,<toggle|quick>]]
70
72
  [-T | --loadavg-type=<short,medium,long,random>]
73
+ [-f | --pidfile=</path/to/file.pid>]
71
74
  [-- <options to dcp-evaluator-start, must be last option>]
72
75
  Where:
73
76
  -i sets the idle timeout in seconds for tty sessions (${daemonConfig.session.idleTimeout}s)
74
77
  -p specifies the port to listen on for dcpsaw: worker connections (${daemonConfig.net.port})
75
78
  --prefix specifies the directory where the DCP evaluator package was installed
79
+ --pidfile specifies an alternate location for the pid file (currently ${daemonConfig.pidfile})
76
80
  --pts specifies the location of the system's pseudo terminal (${ptsDir})
77
81
  --disable-monitor=session disables monitoring of ssh/telnet/etc sessions
78
82
  --disable-monitor=screensaver disables monitoring of the screensaver
@@ -228,7 +232,10 @@ function handleConnection (socket, config)
228
232
 
229
233
  const options = {
230
234
  env: Object.assign({}, process.env),
235
+ windowsHide: true,
236
+ maxBuffer: 1024 * 1024 * 1024 * 2,
231
237
  };
238
+ Object.apply(options, daemonConfig.spawnOptions);
232
239
  child = require('child_process').spawn(config.proc, config.argv, options);
233
240
  child.stderr.setEncoding('ascii');
234
241
  child.socket = socket;
@@ -331,10 +338,12 @@ async function dbusScreenSaverMonitor()
331
338
  'org.gnome.ScreenSaver',
332
339
  'org.cinnamon.ScreenSaver',
333
340
  'org.kde.screensaver',
334
- 'org.freedesktop.ScreenSaver'
341
+ 'org.freedesktop.ScreenSaver' // if this ever worked, it doesn't work now as of Ubuntu 24.04 LTS
342
+ // on GNOME, org.freesktop.ScreenSaver will complaint about
343
+ // GetActive isn't a part of offical Freesktop screen saver spec
335
344
  ];
336
345
  var iface;
337
-
346
+ var chosen;
338
347
  for (let ss of screensaverList)
339
348
  {
340
349
  try
@@ -343,6 +352,7 @@ async function dbusScreenSaverMonitor()
343
352
  if (obj)
344
353
  {
345
354
  iface = obj.interfaces[ss];
355
+ chosen = ss;
346
356
  break;
347
357
  }
348
358
  }
@@ -354,23 +364,34 @@ async function dbusScreenSaverMonitor()
354
364
 
355
365
  if (!iface)
356
366
  {
357
- console.error('Could not open dbus session to any screensaver, tried', screensaverList);
367
+ console.warn('Warning: could not open dbus session to any screensaver, tried', screensaverList);
368
+ return;
369
+ }
370
+
371
+ try
372
+ {
373
+ // Note this is almost guranteed to fail if (GNOME is installed + you're accessing it not on GNOME,
374
+ // such as over SSH or on another DE)
375
+ const ssActive = await iface.GetActive(); // eslint-disable-line new-cap
376
+ debug('dcp-evaluator-manager')('Screen saver active:', ssActive);
377
+ userActivity.screensaver = ssActive ? false : 'active dbus screensaver (initial)';
378
+
379
+ /* screensaver not active => user activity */
380
+ iface.on('ActiveChanged', function screenSaverChangeHandler(active) {
381
+ userActivity.screensaver = active ? false : 'active dbus screensaver (change)';
382
+ debug('dcp-evaluator-manager')(`screen saver ${active ? 'started' : 'finished'} at`, new Date());
383
+ if (!daemonConfig.limits.onlyWhenBusy && checkUserActivity())
384
+ killChildren();
385
+ });
386
+
387
+ console.log('Monitoring dbus messages for', iface.$name);
388
+ }
389
+ catch (error)
390
+ {
391
+ const prettyName = chosen.split('.')[1];
392
+ console.error(`${prettyName} screensaver doesn't support activeness query, screensaver is not started, or user ${os.userInfo().username} doesn't have access to dbus\n ${error}`);
358
393
  process.exit(3);
359
394
  }
360
-
361
- const ssActive = await iface.GetActive(); // eslint-disable-line new-cap
362
- debug('dcp-evaluator-manager')('Screen saver active:', ssActive);
363
- userActivity.screensaver = ssActive ? false : 'active dbus screensaver (initial)';
364
-
365
- /* screensaver not active => user activity */
366
- iface.on('ActiveChanged', function screenSaverChangeHandler(active) {
367
- userActivity.screensaver = active ? false : 'active dbus screensaver (change)';
368
- debug('dcp-evaluator-manager')(`screen saver ${active ? 'started' : 'finished'} at`, new Date());
369
- if (!daemonConfig.limits.onlyWhenBusy && checkUserActivity())
370
- killChildren();
371
- });
372
-
373
- console.log('Monitoring dbus messages for', iface.$name);
374
395
  }
375
396
 
376
397
  /* Activate screensaver monitor. Promise resolves when the initial state has been figured out. */
@@ -503,7 +524,7 @@ function odRequire(moduleId)
503
524
  /* Main program entry point */
504
525
  async function main()
505
526
  {
506
- const parser = new getopt.BasicParser('h(help)P:(prefix)d:(disable-monitor)l:(max-load)r:(rate)Li:ap:s:(signal)T:(loadavg-type)', process.argv);
527
+ const parser = new getopt.BasicParser('h(help)P:(prefix)d:(disable-monitor)l:(max-load)r:(rate)Li:ap:s:(signal)T:(loadavg-type)f:(pidfile)', process.argv);
507
528
  var option;
508
529
 
509
530
  while ((option = parser.getopt()) !== undefined)
@@ -599,10 +620,17 @@ async function main()
599
620
  daemonConfig.limits.loadavgType = option.optarg;
600
621
  break;
601
622
  }
623
+
624
+ case 'f':
625
+ {
626
+ daemonConfig.pidfile = option.optarg;
627
+ }
602
628
  }
603
629
  }
604
630
 
605
631
  daemonConfig.argv = daemonConfig.argv.concat(process.argv.slice(parser.optind())); /* All options after -- pass to dcp-evaluator-start */
632
+ if (daemonConfig.pidfile)
633
+ pidfile.write(daemonConfig.pidfile);
606
634
 
607
635
  process.on('uncaughtException', function (error) {
608
636
  console.error('\n---', (new Date()).toLocaleString(), '-------------------------------------------------');
package/bin/dcp-worker CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #! /usr/bin/env node
2
2
  /**
3
3
  * @file dcp-worker.js
4
4
  * Standalone NodeJS DCP Worker
@@ -57,7 +57,7 @@ function parseCliArgs()
57
57
  defaultPidFileName = require('../lib/pidfile').getDefaultPidFileName(dcpConfig.worker.pidfile);
58
58
 
59
59
  const cliArgs = require('dcp/cli')
60
- .base('Standalone NodeJS DCP Worker')
60
+ .base('DCP Worker: Request work from the DCP Scheduler and send it to DCP Evaluators')
61
61
  .options({
62
62
  paymentAddress: {
63
63
  describe: 'The address to deposit funds into, will use the default bank keystore if not provided.',
@@ -407,6 +407,7 @@ async function main()
407
407
 
408
408
  worker = new DCPWorker(identityKeystore, dcpWorkerOptions);
409
409
  worker.on('warning', (...payload) => console.warn (...payload));
410
+ worker.on('job', job => console.log(` . Job: ${job.name} ${job.address.slice(0,8)} ${job.description || ''} ${job.link || ''}`));
410
411
  worker.on('stop', () => { console.log('Worker is stopping') });
411
412
  worker.on('end', () => { logClosing('log', 'Worker has stopped') });
412
413
  // Display clean diagnostic when not debugging and env var
@@ -502,6 +503,19 @@ async function main()
502
503
  introBanner += ` -\t${wt.name}@${wt.versions.join(';')}\n`;
503
504
  }
504
505
 
506
+ const webgpuInfo = await require('../lib/webgpu-info').checkWebGPU();
507
+ if (!webgpuInfo)
508
+ introBanner += ' . WebGPU detection failed\n';
509
+ else if (!webgpuInfo.enabled)
510
+ introBanner += ' . WebGPU not enabled\n';
511
+ else
512
+ {
513
+ introBanner += ' . WebGPU available. GPU info:\n';
514
+ for (let descriptor in webgpuInfo.info)
515
+ introBanner += ` -\t${descriptor}: ${webgpuInfo.info[descriptor]}\n`;
516
+ dcpConfig.evaluator.gpu = webgpuInfo.info.device;
517
+ }
518
+
505
519
  introBanner += ' . Supervisor version: ' + worker.supervisorVersion + '\n';
506
520
  introBanner += ' . Output mode: ' + cliArgs.outputMode + '\n';
507
521
  introBanner += ' * Ready' + '\n';
@@ -558,8 +572,6 @@ function processCoresAndMaxSandboxes (dcpWorkerOptions, cliArgs)
558
572
 
559
573
  if (typeof cliArgs['maxSandboxes'] !== 'undefined')
560
574
  dcpWorkerOptions.maxSandboxes = Number(cliArgs['maxSandboxes']);
561
- else
562
- DCPWorker.defaultMaxSandboxes(dcpWorkerOptions);
563
575
  debugging() && console.debug(`dcp-worker: cores = { ${dcpWorkerOptions.cores.cpu}, ${dcpWorkerOptions.cores.gpu} }`);
564
576
  debugging() && console.debug('dcp-worker: core density =', dcpWorkerOptions.density);
565
577
  }
@@ -1,83 +1,54 @@
1
1
  /**
2
- * @file dcp-worker-config.js
3
- * Default configuration for the standalone DCP Worker package. Copy this file before
4
- * modifying so that changes are preserved during the upgrade cycle. If this file is in the
5
- * "/opt/dcp/.dcp" directory as the result of an application install, do:
6
- * - sudo --user dcp cp /opt/dcp/.dcp/dcp-worker-config.js /opt/dcp/.dcp/dcp-config.js
7
- * Otherwise, suggested locations include:
2
+ * @file dcp-worker-config.js - Default configuration for the DCP Worker.
3
+ * Copy this file before modifying, so that changes are preserved during the upgrade cycle.
4
+ * Remove (or comment out) settings you don't need to change, so that changes to the
5
+ * defaults can be made during an upgrade. Suggested locations include:
8
6
  * - /etc/dcp/dcp-worker/dcp-config.js, or
9
7
  * - ~/.dcp/dcp-worker/dcp-config.js.
10
8
  *
11
- * Those files have a higher precedence than the configuration that ships with the npm
9
+ * Those files have a higher precedence than the configuration that ships with the
12
10
  * package; changes made in those files will be merged into the running configuration,
13
11
  * overriding the defaults specified here.
14
12
  *
15
13
  * Windows users can also affect these changes by adding entries to the registry. This is
16
14
  * the preferred method for enterprise deployment.
17
15
  *
18
- * @author Wes Garland
19
- * @date Feb 2021
16
+ * @author Wes Garland, wes@distributive.network
17
+ * @date Feb 2021, Sep 2024
20
18
  */
21
19
  {
22
- /* The DCP Worker Supervisor spawns evaluator sandboxes that execute job slices. */
23
20
  worker: {
24
- /* The DCP Bank account where earned funds are deposited by default, of the form:
25
- * '0x718cABAabA0d3E85292FD8bCFb78B9f0368d612c'.
26
- */
27
- paymentAddress: undefined,
28
-
29
- /* The number of CPU/GPU cores that the worker can use. */
30
- /*
31
- cores: {
32
- cpu: 7,
33
- gpu: 1,
34
- }
35
- */
36
-
37
- /* The proportion of this machine's cores to use by default. */
38
- defaultCoreDensity: {
39
- cpu: 0.9,
40
- gpu: 0.75,
41
- },
21
+ utilization: { cpu: 1.0, gpu: 0.75 }, /* proportion of this machine's resources to use by defaut. */
22
+ maxSandboxes: undefined, /* maximum number of sandboxes working or idling, undefined = auto */
23
+ cores: { cpu: undefined, gpu: undefined }, /* how many cpus/gpus this machine has; undefined = detect */
24
+ paymentAddress: undefined, /* Bank account for earnings; undefined = read ~/.dcp/default.keystore */
42
25
 
43
- /* Maximum number of sandboxes that can run at the same time. */
44
- /*
45
- maxSandboxes: 10,
46
- */
47
-
48
- /* Trust the scheduler to modify allowOrigins via Compute Group configuration. */
49
- trustComputeGroupOrigins: true,
50
-
51
- /* Allow lists permitting supervisor network access beyond DCP messages to services. */
26
+ /* allowOrigins permit job-related network access by URL origin, default is none */
52
27
  allowOrigins: {
53
- fetchWorkFunctions: [ dcpConfig.scheduler.location.origin ], // Can fetch work functions only from these sources
54
- fetchArguments: [ dcpConfig.scheduler.location.origin ], // Can fetch job arguments only from these sources
55
- fetchData: [ dcpConfig.scheduler.location.origin ], // Can fetch input set data only from these sources
56
- sendResults: [ dcpConfig.scheduler.location.origin ], // Can submit results only to these sources
57
- any: [], // Can fetch anything from these sources
28
+ fetchWorkFunctions: [ dcpConfig.scheduler.location.origin, ],
29
+ fetchArguments: [ dcpConfig.scheduler.location.origin, ],
30
+ fetchData: [ dcpConfig.scheduler.location.origin, ],
31
+ sendResults: [ dcpConfig.scheduler.location.origin, ],
32
+ any: [],
58
33
  },
34
+ trustComputeGroupOrigins: true, /* Allow the scheduler to modify allowOrigins via Compute Group configuration */
59
35
 
60
- /* Vector describing the lowest-value work this worker will accept. */
36
+ /* Lowest-value work this worker will accept - should be based on local cost */
61
37
  minimumWage: {
62
- 'CPU': 0, /* DCC per second of CPU time */
63
- 'GPU': 0, /* DCC per second of GPU time */
64
- 'in': 0, /* DCC per byte of inbound network traffic */
65
- 'out': 0, /* DCC per byte of outbound network traffic */
38
+ 'CPU': 0, /* DCC per hour of CPU time */
39
+ 'GPU': 0, /* DCC per hour of GPU time */
40
+ 'in': 0, /* DCC per megabyte of inbound network traffic */
41
+ 'out': 0, /* DCC per megabyte of outbound network traffic */
66
42
  },
67
43
 
68
44
  /* Extra Compute Groups this worker can participate in. Join credentials are supplied by
69
45
  * Distributive and/or local IT staff at site-licensed locations.
70
46
  */
71
47
  computeGroups: [
72
- // { joinKey: 'demo', joinSecret: 'secret' },
73
- // { joinKey: 'demo', joinHash: 'eh1-...' },
74
- // keystore('~/.dcp/demo'),
48
+ // { joinKey: 'scott', joinSecret: 'tiger' },
49
+ // { joinKey: 'scott', joinHash: 'eh1-672937c2b944982e071185b888770f8b8ea67c11f56d545e403e0d513c609b87' },
50
+ // keystore('~/.dcp/scott'),
75
51
  ],
76
-
77
- /* Can be false to work on any job, or an array of job ID strings (eg.
78
- * ['0xF9D2...F537']) to restrict work to only these jobs.
79
- */
80
- jobAddresses: false,
81
52
  },
82
53
 
83
54
  /* The evaluator is a secure environment used by DCP Worker sandboxes. This configuration specifies
@@ -88,6 +59,5 @@
88
59
  listen: new URL('dcpsaw://localhost:9000/'),
89
60
  },
90
61
 
91
- /* Used to verify that the configuration file was loaded. */
92
- cookie: require('process').env.DCP_CONFIG_COOKIE,
62
+ cookie: require('process').env.DCP_CONFIG_COOKIE, /* Used to verify that this file was loaded. */
93
63
  }
@@ -1,2 +1,2 @@
1
- 8215b6848d83b26af503ed81b87c493c
1
+ 9911ec21ecad5d6fa18b1663715bed5b
2
2
  ### DO NOT MODIFY THIS FILE!!! ###
@@ -52,7 +52,10 @@ exports.init = function dashboard$$init(worker, options)
52
52
  });
53
53
 
54
54
  const grid = new contrib.grid({ rows: 3, cols: 5, screen }); // eslint-disable-line new-cap
55
- const workerInfoPane = grid.set(2, 0, 1, 5, blessed.text);
55
+ const workerInfoPane = grid.set(2, 0, 1, 5, components.log, {
56
+ label: 'Worker Status',
57
+ scrollbar: { bg: 'blue' },
58
+ });
56
59
  const logPane = grid.set(0, 2, 2, 3, components.log, {
57
60
  label: 'Worker Log',
58
61
  scrollbar: { bg: 'blue' },
@@ -83,6 +86,7 @@ exports.init = function dashboard$$init(worker, options)
83
86
  });
84
87
 
85
88
  global.tui = { workerInfoPane, logPane, sandboxPane, screen, grid, passwordBox };
89
+ let lastTask;
86
90
 
87
91
  function askPassword(promptMessage)
88
92
  {
@@ -123,21 +127,30 @@ exports.init = function dashboard$$init(worker, options)
123
127
  screen.key(['\u001c'], () => raise('SIGQUIT')); /* C-\ */
124
128
  screen.key(['escape'], () => raise('SIGINT'));
125
129
 
126
- function updateWorkerInfo()
130
+ setInterval(updateWorkerInfo, 1000).unref();
131
+ function updateWorkerInfo(fetchInfo)
127
132
  {
128
133
  const workerOptions = worker.workerOptions;
134
+ if (fetchInfo)
135
+ lastTask = fetchInfo;
129
136
 
130
137
  workerInfoPane.setLabel(`Worker Status [${sliceFetchStatus}]`);
131
138
  workerInfoPane.setContent([
132
- chalk.green(` DCCs Earned: ${chalk.bold(totalDCCs.toFixed(3))}`),
139
+ chalk.green(` DCCs Earned: ${chalk.bold(totalDCCs.toFixed(3))} ⊇`),
133
140
  '',
134
- ` Scheduler: ${chalk.yellow(dcpConfig.scheduler.location.href)}`,
135
- ` Bank: ${chalk.yellow(dcpConfig.bank.location.href)}`,
136
- `Bank Account: ${chalk.yellow(worker.paymentAddress || 'Starting...')}`,
137
- ` Identity: ${chalk.yellow(worker.identityKeystore? worker.identityKeystore.address : 'Starting...')}`,
138
- ` Jobs: ${workerOptions.jobAddresses?.length ? workerOptions.jobAddresses.join(', ') : '<any>'}`,
139
- ` Priv Groups: ${Object.keys(workerOptions.computeGroups).length}`,
140
- ` Pub Group: ${workerOptions.leavePublicGroup ? 'no' : 'yes'}`,
141
+ ` Scheduler: ${chalk.yellow(dcpConfig.scheduler.location.href)}`,
142
+ ` Bank: ${chalk.yellow(dcpConfig.bank.location.href)}`,
143
+ ` Bank Account: ${chalk.yellow(worker.paymentAddress || 'Starting...')}`,
144
+ ` Identity: ${chalk.yellow(worker.identityKeystore? worker.identityKeystore.address : 'Starting...')}`,
145
+ ` ${dcpConfig.evaluator.gpu ? `GPU Detected: ${dcpConfig.evaluator.gpu}` : 'GPU Not Detected'}`,
146
+ ` Jobs: ${workerOptions.jobAddresses?.length ? workerOptions.jobAddresses.join(', ') : '<any>'}`,
147
+ ` Compute Groups: ${Object.keys(workerOptions.computeGroups).length + (workerOptions.leavePublicGroup ? 0 : 1)}`,
148
+ `Global Compute Group: ${workerOptions.leavePublicGroup ? 'no' : 'yes'}`,
149
+ ` Worker Id: ${worker.workerId}`,
150
+ ` Current Time: ${new Date(Date.now()).toUTCString()}`,
151
+ ` Last Task Request: ${lastTask ? new Date(lastTask.fetchStart).toUTCString() : 0}`,
152
+ ` Slices in task: ${lastTask ? Object.values(lastTask.slices).reduce((acc, val) => acc + val, 0) : 0}`,
153
+ ` Jobs in task: ${lastTask ? Object.keys(lastTask.jobs).length : 0}`,
141
154
  ].join('\n'));
142
155
  screen.render();
143
156
  }
@@ -186,7 +199,7 @@ exports.init = function dashboard$$init(worker, options)
186
199
  console.error('Error fetching slices:', ev);
187
200
  else if ( !(utils.slicesFetched(ev) === 0 && sandboxPane.data.length === 0))
188
201
  sliceFetchStatus = SLICE_FETCH_STATUS.WORKING;
189
- updateWorkerInfo();
202
+ updateWorkerInfo(ev);
190
203
  });
191
204
 
192
205
  /* Sandbox Data
@@ -229,7 +242,6 @@ exports.init = function dashboard$$init(worker, options)
229
242
  }
230
243
  newSandboxCallbacks.push(initSandboxData);
231
244
 
232
- worker.on('job', job => console.log(`new job: ${job.name} ${job.address.slice(0,8)} ${job.description || ''} ${job.link || ''}`));
233
245
  worker.on('payment', function dashboard$$payment(ev) {
234
246
  const payment = parseFloat(ev);
235
247
 
@@ -88,13 +88,13 @@ exports.hook = function defaultUiEvents$$hook(worker, options)
88
88
  delete sliceMap[sandbox.id];
89
89
  };
90
90
 
91
- workerEventHandlers.payment = function paymentHandler(ev) {
92
- const payment = parseFloat(ev);
91
+ workerEventHandlers.payment = function paymentHandler(dcc, account, jobAddress) {
92
+ const payment = parseFloat(dcc);
93
93
 
94
94
  if (isNaN(payment))
95
95
  console.error(' ! Failed to parse payment:', payment);
96
96
  else
97
- console.log(` . Payment: ${payment.toFixed(3)} ⊇`);
97
+ console.log(` . Payment: ${payment.toFixed(3)} ⊇ ${jobAddress.slice(0, 8)}`);
98
98
  };
99
99
 
100
100
  workerEventHandlers.beforeFetch = function beforeFetchHandler() {
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @file node-version-check.js - preload module
3
+ * @author Wes Garland, wes@distributive.network
4
+ * @date Sep 2024
5
+ */
6
+ 'use strict';
7
+
8
+ if (!(parseInt(process.versions.node, 10) >= 18))
9
+ {
10
+ console.error(`Your version of node (${process.version}) is far to old to run this program. Please upgrade to a supported version of Node.js.`);
11
+ console.error('For more information, visit', require('../package').homepage);
12
+ process.exit(1);
13
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @file webgpu-capabilities.js
3
+ * Check evaluator to determine if webgpu is enabled, and what capabilities it has.
4
+ *
5
+ * @author Ryan Saweczko, ryansaweczko@distributive.network
6
+ *
7
+ * @date Sept 2024
8
+ */
9
+ 'use strict';
10
+
11
+ const kvin = require('kvin');
12
+ const evaluatorId = 'webgpuCheck';
13
+
14
+ async function eval$$webgpu()
15
+ {
16
+ if (typeof initWebGPU === 'function')
17
+ await initWebGPU();
18
+
19
+ if (!(typeof globalThis.navigator?.gpu === 'object'))
20
+ return { enabled: false };
21
+
22
+ try
23
+ {
24
+ const info = {};
25
+ const adapter = await navigator.gpu.requestAdapter();
26
+ /*
27
+ * Newer versions of dcp-evaluator use different methods to access the adapter info as the api changes/bugs are fixed.
28
+ * `adapter.info`: spec-compliant method to access adapter info as of writing this (Sept 2024).
29
+ * dcp-evaluator versions supporting: None
30
+ *
31
+ * `adapter.requestAdapterInfo()`: original method. Should return an object with enumerable properties.
32
+ * dcp-evaluator version < 7.2.0 have non-enumerable properties
33
+ * dcp-evaluator version >= 7.2.0 have enumerable properties
34
+ */
35
+ if (adapter.info)
36
+ {
37
+ for (let key in adapter.info)
38
+ info[key] = adapter.info[key];
39
+ return { enabled: true, info: info };
40
+ }
41
+ const properties = ['vendor', 'architecture', 'device', 'description'];
42
+ const adapterInfo = await adapter.requestAdapterInfo();
43
+ for (let key of properties)
44
+ info[key] = adapterInfo[key];
45
+ return { enabled: true, info: info };
46
+ }
47
+ catch (err)
48
+ {
49
+ return { enabled: false };
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Connect to an evaluator instance and return back if webGPU is enabled, and if it is some information on the
55
+ * GPU device.
56
+ * @param {object} evaluatorConfig - Object containing the hostname and port to connect to the evaluator instance on
57
+ * @returns {Promise} which resolves with undefined detection failed (ie couldn't connect to evaluator),
58
+ * or the object {enabled, info} with info on if webgpu exists, and if so what the gpu is.
59
+ */
60
+ function checkEvaluatorWebGPU(evaluatorConfig)
61
+ {
62
+ const StandaloneWorker = require('dcp-client/lib/standaloneWorker').workerFactory(evaluatorConfig);
63
+ const { a$sleep } = require('dcp/utils');
64
+
65
+ const evaluatorHandle = new StandaloneWorker({ name: 'DCP Sandbox #1', });
66
+
67
+ var noResponse, resolve;
68
+ const p$webgpuInfo = new Promise((res, rej) => { resolve = res; }).finally(() => {
69
+ evaluatorHandle.terminate();
70
+ noResponse.intr();
71
+ });
72
+
73
+ noResponse = a$sleep(1);
74
+ noResponse.then(() => { resolve(); });
75
+ process.on('dcpExit', () => noResponse.intr());
76
+
77
+ evaluatorHandle.onmessage = function onmessage(event)
78
+ {
79
+ const reply = kvin.unmarshal(event.data).value;
80
+ if (reply.request === `evalResult::${evaluatorId}`)
81
+ resolve(reply.data);
82
+ }
83
+
84
+ const message = {
85
+ request: 'eval',
86
+ data: '(' + eval$$webgpu.toString() + ')()',
87
+ msgId: evaluatorId,
88
+ }
89
+ evaluatorHandle.postMessage(kvin.marshal(message));
90
+ return p$webgpuInfo;
91
+ }
92
+
93
+ exports.checkWebGPU = checkEvaluatorWebGPU;
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "dcp-worker",
3
- "version": "3.3.11",
4
- "description": "JavaScript portion of DCP Workers for Node.js",
3
+ "version": "3.3.12-1",
4
+ "description": "Node.js Worker for Distributive Compute Platform",
5
5
  "main": "bin/dcp-worker",
6
6
  "keywords": [
7
7
  "dcp"
8
8
  ],
9
- "homepage": "https://gitlab.com/Distributed-Compute-Protocol/dcp-worker#readme",
9
+ "homepage": "https://www.npmjs.com/package/dcp-worker#readme",
10
10
  "bugs": {
11
11
  "url": "https://gitlab.com/Distributed-Compute-Protocol/dcp-worker/issues"
12
12
  },
13
13
  "repository": {
14
14
  "type": "git",
15
- "url": "git@github.com:Distributed-Compute-Labs/dcp-worker.git"
15
+ "url": "git+ssh://git@gitlab.com/Distributed-Compute-Protocol/dcp-worker.git"
16
16
  },
17
17
  "license": "MIT",
18
- "author": "Kings Distributed Systems",
18
+ "author": "Distributive Corp.",
19
19
  "bin": {
20
20
  "dcp-evaluator-manager": "bin/dcp-evaluator-manager",
21
21
  "dcp-evaluator-start": "bin/dcp-evaluator-start",
@@ -37,18 +37,18 @@
37
37
  "prepublishOnly": "npm-hooks/prepublish"
38
38
  },
39
39
  "dependencies": {
40
- "blessed": "0.1.81",
40
+ "blessed": "^0.1.81",
41
41
  "blessed-contrib": "4.11.0",
42
- "chalk": "4.1.2",
43
- "dcp-client": "4.4.10",
44
- "kvin": "1.2.14",
45
- "posix-getopt": "1.2.1",
46
- "semver": "7.6.3",
42
+ "chalk": "^4.1.0",
43
+ "dcp-client": "4.4.11-1",
44
+ "kvin": "^1.2.7",
45
+ "posix-getopt": "^1.2.1",
46
+ "semver": "^7.3.8",
47
47
  "syslog-client": "1.1.1"
48
48
  },
49
49
  "optionalDependencies": {
50
- "dbus-next": "0.10.2",
51
- "telnet-console": "1.0.5"
50
+ "dbus-next": "^0.10.2",
51
+ "telnet-console": "^1.0.5"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@distributive/eslint-config": "2.1.4",