@jsm-mit/map-routes-package 0.0.0-stage → 0.2.0
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/README.md +64 -2
- package/declarations/map-routes-coordinator/map-routes-coordinator.did +485 -0
- package/declarations/map-routes-coordinator/map-routes-coordinator.did.d.ts +764 -0
- package/declarations/map-routes-coordinator/map-routes-coordinator.did.js +303 -0
- package/declarations/map-routes-core/map-routes-core.did +107 -0
- package/declarations/map-routes-core/map-routes-core.did.d.ts +171 -0
- package/declarations/map-routes-core/map-routes-core.did.js +108 -0
- package/declarations/map-routes-worker/map-routes-worker.did +172 -0
- package/declarations/map-routes-worker/map-routes-worker.did.d.ts +296 -0
- package/declarations/map-routes-worker/map-routes-worker.did.js +128 -0
- package/dist/canister-actor.d.ts +59 -0
- package/dist/canister-actor.d.ts.map +1 -0
- package/dist/canister-actor.js +150 -0
- package/dist/client.d.ts +109 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +174 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/passes.d.ts +37 -0
- package/dist/passes.d.ts.map +1 -0
- package/dist/passes.js +28 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +51 -5
package/README.md
CHANGED
|
@@ -1,3 +1,65 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @jsm-mit/map-routes-package
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The package of map-routes: the fastest route by car through 2–5 points, with the line of each
|
|
4
|
+
leg, from a group of Internet Computer canisters (replicated shards): a coordinator and copies
|
|
5
|
+
of workers, each holding an OpenStreetMap road graph of one area (© OpenStreetMap
|
|
6
|
+
contributors, ODbL). Queries cost the caller nothing. It replaces the deprecated
|
|
7
|
+
`@jsm-mit/tigi-map-package`.
|
|
8
|
+
|
|
9
|
+
## The group (0.2): `MapRoutesClient`
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { coordinatorPassProvider, errorKeyOf, isTimeoutError, MapRoutesClient } from "@jsm-mit/map-routes-package";
|
|
13
|
+
|
|
14
|
+
const map = new MapRoutesClient({
|
|
15
|
+
coordinatorId, // the coordinator of the group
|
|
16
|
+
identity: user, // the caller of the queries (a pass names it)
|
|
17
|
+
passProvider, // where passes come from (below)
|
|
18
|
+
});
|
|
19
|
+
const route = await map.routeAsyncUnsafe([me, pickup, destination], { line: true, timeoutMs: 5_000 });
|
|
20
|
+
// route.legs[i]: { meters, seconds, line? } line = encoded polyline, precision 5 (as ORS)
|
|
21
|
+
// route.snapMeters, route.osmDate, route.graphSha256, route.copy (the copy that answered)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- The client reads the areas and their live copies from the coordinator and keeps them
|
|
25
|
+
`ttlSeconds`; it picks the area that holds every point.
|
|
26
|
+
- A **pass** (`replicated-shards.md`) names the user, the area, a bbox, a time and one copy.
|
|
27
|
+
The client keeps it per area, asks for the next one in the background in the last quarter
|
|
28
|
+
of its life, and at once (with one retry of the call) when the worker refuses it
|
|
29
|
+
(`PassExpired`, `PassInvalid`, `PassMissing`, `OutsideBbox`).
|
|
30
|
+
- **Pass providers:**
|
|
31
|
+
- a system registered at the coordinator signs `issuePass` itself at the pass core of the
|
|
32
|
+
user (the coordinator names it, `issuerFor`):
|
|
33
|
+
`coordinatorPassProvider({ coordinatorId, system: identity, user })` (often the user is
|
|
34
|
+
the system itself);
|
|
35
|
+
- a front asks its own backend canister (a registered system), which asks the coordinator
|
|
36
|
+
for the front's user: `passProvider: (request) => backend.mapPass(request)`.
|
|
37
|
+
- Without a provider the client draws a live copy and sends no pass — only while the copies
|
|
38
|
+
do not require passes.
|
|
39
|
+
- A copy that does not answer: the list is read again and the call is tried once more.
|
|
40
|
+
|
|
41
|
+
Errors: `CanisterError` with `errorKeyOf(error)` = `OutsideArea` (no area holds every point,
|
|
42
|
+
or a point farther than 1 km from a road), `NoRoute`, `NotReady` (no live copy, no graph),
|
|
43
|
+
`InvalidData`, the pass refusals above (after the renewal), and the refusals of the provider:
|
|
44
|
+
`Blocked` (the user — a clear reason; show it), `RateLimited`, `Waiting`, `NotAuthorized`.
|
|
45
|
+
`Timeout` (`isTimeoutError`; renewals and retries count) and `CriticalCanisterError`
|
|
46
|
+
(transport; also a system the coordinator does not know).
|
|
47
|
+
|
|
48
|
+
## One copy: `MapRoutesActor`
|
|
49
|
+
|
|
50
|
+
`new MapRoutesActor(copyId, { host })` asks one worker copy directly, without a coordinator
|
|
51
|
+
and without a pass (a copy with `passRequired` off; local tests). It is the 0.1 interface.
|
|
52
|
+
|
|
53
|
+
Local replica: `host: "http://127.0.0.1:4943"`.
|
|
54
|
+
|
|
55
|
+
## Scripts
|
|
56
|
+
|
|
57
|
+
- `npm run test-unit` — no canister (the client on a fake transport).
|
|
58
|
+
- `npm run test-smoke` — one copy (`map-routes-worker`) on the LOCAL replica with the newest
|
|
59
|
+
`data/*.tmc`.
|
|
60
|
+
- `npm run test-group` — the group on the LOCAL replica: the coordinator, two copies of Iraq,
|
|
61
|
+
passes required (`../scripts/check/local-coordinator-check.sh iraq`, local test identity
|
|
62
|
+
`mrc-system` as the system).
|
|
63
|
+
- `npm run sync-declarations` — `declarations/` from `../map-routes-worker.did` and
|
|
64
|
+
`../map-routes-coordinator.did`.
|
|
65
|
+
- `npm run publish-public` — human-run; see the script for its refusals.
|
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
// One area as a client sees it: where to ask.
|
|
2
|
+
type AreaInfo = record {
|
|
3
|
+
sha256 : opt text;
|
|
4
|
+
area : text;
|
|
5
|
+
bbox : Bbox;
|
|
6
|
+
// The live copies: a client draws one for every call.
|
|
7
|
+
copies : vec principal;
|
|
8
|
+
osmDate : opt text;
|
|
9
|
+
};
|
|
10
|
+
// Stored: the hysteresis of one area (key = its name).
|
|
11
|
+
type AreaLoad = record {
|
|
12
|
+
// Readings in a row with the average per live copy above H.
|
|
13
|
+
above : nat32;
|
|
14
|
+
// The last copy the load made (created or unmarked).
|
|
15
|
+
lastGrowthNs : opt nat64;
|
|
16
|
+
// Since when the load would fit into one live copy less (sum / (n − 1) < H/2).
|
|
17
|
+
belowSinceNs : opt nat64;
|
|
18
|
+
area : text;
|
|
19
|
+
};
|
|
20
|
+
type Areas = record {
|
|
21
|
+
// How long a client keeps this list.
|
|
22
|
+
ttlSeconds : nat32;
|
|
23
|
+
areas : vec AreaInfo;
|
|
24
|
+
};
|
|
25
|
+
// A rectangle in degrees, edges included.
|
|
26
|
+
type Bbox = record {
|
|
27
|
+
minLat : float64;
|
|
28
|
+
minLon : float64;
|
|
29
|
+
maxLat : float64;
|
|
30
|
+
maxLon : float64;
|
|
31
|
+
};
|
|
32
|
+
type BeginWasmArgs = record {
|
|
33
|
+
sha256 : text;
|
|
34
|
+
// `null` = the worker.
|
|
35
|
+
kind : opt WasmKind;
|
|
36
|
+
size : nat64;
|
|
37
|
+
};
|
|
38
|
+
// Stored: a bisection of one area (key = its name). The users stay in the cores.
|
|
39
|
+
type BisectionRun = record {
|
|
40
|
+
// Set when it ended; a new one starts at least an hour later.
|
|
41
|
+
endedAtNs : opt nat64;
|
|
42
|
+
area : text;
|
|
43
|
+
copyA : principal;
|
|
44
|
+
copyB : principal;
|
|
45
|
+
// Suspects left, summed over the cores.
|
|
46
|
+
suspects : nat64;
|
|
47
|
+
steps : nat32;
|
|
48
|
+
// The split of this step began then.
|
|
49
|
+
stepStartedNs : nat64;
|
|
50
|
+
};
|
|
51
|
+
// Stored: a blocked user (key = system/user). Only a superadmin unblocks.
|
|
52
|
+
type Block = record {
|
|
53
|
+
who : UserKey;
|
|
54
|
+
atNs : nat64;
|
|
55
|
+
// The measured surplus in instructions/s (bisection).
|
|
56
|
+
load : opt float64;
|
|
57
|
+
reason : text;
|
|
58
|
+
};
|
|
59
|
+
// Stored: one worker copy (key = its canister). A new field is `Option<…>` + `#[serde(default)]`.
|
|
60
|
+
type Copy = record {
|
|
61
|
+
area : text;
|
|
62
|
+
createdAtNs : nat64;
|
|
63
|
+
state : CopyState;
|
|
64
|
+
subnet : opt principal;
|
|
65
|
+
canister : principal;
|
|
66
|
+
// The last step that failed; `advanceCopy` tries it again.
|
|
67
|
+
lastError : opt text;
|
|
68
|
+
// When the copy was marked for removal (off the list since then).
|
|
69
|
+
markedAtNs : opt nat64;
|
|
70
|
+
};
|
|
71
|
+
type CopyState = variant {
|
|
72
|
+
// A later copy: it pulls the graph from a live copy of the area.
|
|
73
|
+
Copying;
|
|
74
|
+
// Answers queries and is on the list of the area.
|
|
75
|
+
Live;
|
|
76
|
+
// Created; its wasm is not installed yet.
|
|
77
|
+
Installing;
|
|
78
|
+
// The first copy of an area: an uploader sends the graph (`upload-graph.sh --no-activate`).
|
|
79
|
+
AwaitingData;
|
|
80
|
+
// The load fits without it; only a superadmin deletes it.
|
|
81
|
+
MarkedForRemoval;
|
|
82
|
+
};
|
|
83
|
+
// Stored: a pass core of the group (key = its canister).
|
|
84
|
+
type CoreCanister = record {
|
|
85
|
+
// The snapshot version the core holds.
|
|
86
|
+
syncedVersion : opt nat64;
|
|
87
|
+
createdAtNs : nat64;
|
|
88
|
+
// Its balance at the last round (the round tops it up like a copy).
|
|
89
|
+
cycles : opt nat;
|
|
90
|
+
state : CoreState;
|
|
91
|
+
subnet : opt principal;
|
|
92
|
+
canister : principal;
|
|
93
|
+
lastError : opt text;
|
|
94
|
+
};
|
|
95
|
+
// A core's report (`coreReport`).
|
|
96
|
+
type CoreReport = record {
|
|
97
|
+
// Blocks made in the core (renewals).
|
|
98
|
+
blocks : vec Block;
|
|
99
|
+
// Users with a valid pass, per area.
|
|
100
|
+
users : vec record { text; nat64 };
|
|
101
|
+
// Systems refused for passes a minute.
|
|
102
|
+
rateLimited : vec principal;
|
|
103
|
+
};
|
|
104
|
+
type CoreState = variant {
|
|
105
|
+
// Issues passes; gets the snapshot.
|
|
106
|
+
Live;
|
|
107
|
+
// Created; its wasm is not installed yet (`advanceCore`).
|
|
108
|
+
Installing;
|
|
109
|
+
};
|
|
110
|
+
type Error = variant {
|
|
111
|
+
// A call to another canister failed (named); the step can be tried again.
|
|
112
|
+
CallFailed : text;
|
|
113
|
+
// The user gets no pass: the reason and whom to contact.
|
|
114
|
+
Blocked : text;
|
|
115
|
+
NotFound : text;
|
|
116
|
+
NotAuthorized : text;
|
|
117
|
+
// The limit of copies of the area is reached (`maxCopies`).
|
|
118
|
+
LimitReached : text;
|
|
119
|
+
InvalidData : text;
|
|
120
|
+
// The system asks too often (or the demo used its hour): try later.
|
|
121
|
+
RateLimited : text;
|
|
122
|
+
// The step waits for something outside (named), e.g. the graph upload.
|
|
123
|
+
Waiting : text;
|
|
124
|
+
};
|
|
125
|
+
// Test feed (local replica only: it does not count `query_stats`).
|
|
126
|
+
type FeedArgs = record { totals : QueryTotals; canister : principal };
|
|
127
|
+
// A Candid-encodable representation of an HTTP request. This struct is used by
|
|
128
|
+
// the `http_request` method of the HTTP Gateway Protocol's Candid interface.
|
|
129
|
+
//
|
|
130
|
+
// # Examples
|
|
131
|
+
//
|
|
132
|
+
// ```
|
|
133
|
+
// use ic_http_certification::{HttpRequest, Method};
|
|
134
|
+
//
|
|
135
|
+
// let request = HttpRequest::builder()
|
|
136
|
+
// .with_method(Method::GET)
|
|
137
|
+
// .with_url("/")
|
|
138
|
+
// .with_headers(vec![("X-Custom-Foo".into(), "Bar".into())])
|
|
139
|
+
// .with_body(&[1, 2, 3])
|
|
140
|
+
// .with_certificate_version(2)
|
|
141
|
+
// .build();
|
|
142
|
+
//
|
|
143
|
+
// assert_eq!(request.method(), Method::GET);
|
|
144
|
+
// assert_eq!(request.url(), "/");
|
|
145
|
+
// assert_eq!(request.headers(), &[("X-Custom-Foo".into(), "Bar".into())]);
|
|
146
|
+
// assert_eq!(request.body(), &[1, 2, 3]);
|
|
147
|
+
// assert_eq!(request.certificate_version(), Some(2));
|
|
148
|
+
// ```
|
|
149
|
+
//
|
|
150
|
+
// # Helpers
|
|
151
|
+
//
|
|
152
|
+
// There are also a number of convenience methods for quickly creating an [HttpRequest] with
|
|
153
|
+
// commonly used HTTP methods:
|
|
154
|
+
//
|
|
155
|
+
// - [GET](HttpRequest::get)
|
|
156
|
+
// - [POST](HttpRequest::post)
|
|
157
|
+
// - [PUT](HttpRequest::put)
|
|
158
|
+
// - [PATCH](HttpRequest::patch)
|
|
159
|
+
// - [DELETE](HttpRequest::delete)
|
|
160
|
+
//
|
|
161
|
+
// ```
|
|
162
|
+
// use ic_http_certification::HttpRequest;
|
|
163
|
+
//
|
|
164
|
+
// let request = HttpRequest::get("/").build();
|
|
165
|
+
//
|
|
166
|
+
// assert_eq!(request.method(), "GET");
|
|
167
|
+
// assert_eq!(request.url(), "/");
|
|
168
|
+
// ```
|
|
169
|
+
type HttpRequest = record {
|
|
170
|
+
// HTTP request URL.
|
|
171
|
+
url : text;
|
|
172
|
+
// HTTP request method.
|
|
173
|
+
method : text;
|
|
174
|
+
// HTTP request body as an array of bytes.
|
|
175
|
+
body : blob;
|
|
176
|
+
// HTTP request headers.
|
|
177
|
+
headers : vec record { text; text };
|
|
178
|
+
// The max response verification version to use in the response's
|
|
179
|
+
// certificate.
|
|
180
|
+
certificate_version : opt nat16;
|
|
181
|
+
};
|
|
182
|
+
// A Candid-encodable representation of an HTTP response. This struct is used
|
|
183
|
+
// by the `http_request` method of the HTTP Gateway Protocol's Candid interface.
|
|
184
|
+
//
|
|
185
|
+
// # Examples
|
|
186
|
+
//
|
|
187
|
+
// ```
|
|
188
|
+
// use ic_http_certification::{HttpResponse, StatusCode};
|
|
189
|
+
//
|
|
190
|
+
// let response = HttpResponse::builder()
|
|
191
|
+
// .with_status_code(StatusCode::OK)
|
|
192
|
+
// .with_headers(vec![("Content-Type".into(), "text/plain".into())])
|
|
193
|
+
// .with_body(b"Hello, World!")
|
|
194
|
+
// .with_upgrade(false)
|
|
195
|
+
// .build();
|
|
196
|
+
//
|
|
197
|
+
// assert_eq!(response.status_code(), StatusCode::OK);
|
|
198
|
+
// assert_eq!(response.headers(), &[("Content-Type".into(), "text/plain".into())]);
|
|
199
|
+
// assert_eq!(response.body(), b"Hello, World!");
|
|
200
|
+
// assert_eq!(response.upgrade(), Some(false));
|
|
201
|
+
// ```
|
|
202
|
+
//
|
|
203
|
+
// # Helpers
|
|
204
|
+
//
|
|
205
|
+
// There are also a number of convenience methods for quickly creating an [HttpResponse] with
|
|
206
|
+
// commonly used HTTP status codes:
|
|
207
|
+
//
|
|
208
|
+
// - [OK](HttpResponse::ok)
|
|
209
|
+
// - [CREATED](HttpResponse::created)
|
|
210
|
+
// - [NO_CONTENT](HttpResponse::no_content)
|
|
211
|
+
// - [MOVED_PERMANENTLY](HttpResponse::moved_permanently)
|
|
212
|
+
// - [TEMPORARY_REDIRECT](HttpResponse::temporary_redirect)
|
|
213
|
+
// - [BAD_REQUEST](HttpResponse::bad_request)
|
|
214
|
+
// - [UNAUTHORIZED](HttpResponse::unauthorized)
|
|
215
|
+
// - [FORBIDDEN](HttpResponse::forbidden)
|
|
216
|
+
// - [NOT_FOUND](HttpResponse::not_found)
|
|
217
|
+
// - [METHOD_NOT_ALLOWED](HttpResponse::method_not_allowed)
|
|
218
|
+
// - [TOO_MANY_REQUESTS](HttpResponse::too_many_requests)
|
|
219
|
+
// - [INTERNAL_SERVER_ERROR](HttpResponse::internal_server_error)
|
|
220
|
+
//
|
|
221
|
+
// ```
|
|
222
|
+
// use ic_http_certification::{HttpResponse, StatusCode};
|
|
223
|
+
//
|
|
224
|
+
// let response = HttpResponse::ok(b"Hello, World!", vec![("Content-Type".into(), "text/plain".into())]).build();
|
|
225
|
+
//
|
|
226
|
+
// assert_eq!(response.status_code(), StatusCode::OK);
|
|
227
|
+
// assert_eq!(response.headers(), &[("Content-Type".into(), "text/plain".into())]);
|
|
228
|
+
// assert_eq!(response.body(), b"Hello, World!");
|
|
229
|
+
// ```
|
|
230
|
+
type HttpResponse = record {
|
|
231
|
+
// HTTP response body as an array of bytes.
|
|
232
|
+
body : blob;
|
|
233
|
+
// HTTP response headers.
|
|
234
|
+
headers : vec record { text; text };
|
|
235
|
+
// Whether the corresponding HTTP request should be upgraded to an update
|
|
236
|
+
// call.
|
|
237
|
+
upgrade : opt bool;
|
|
238
|
+
// HTTP response status code.
|
|
239
|
+
status_code : nat16;
|
|
240
|
+
};
|
|
241
|
+
type InitArgs = record { mode : Mode; superadmins : vec principal };
|
|
242
|
+
type Mode = variant {
|
|
243
|
+
// The local replica: copies by the management canister (no CMC there), any subnet.
|
|
244
|
+
Local;
|
|
245
|
+
Stage;
|
|
246
|
+
Prod;
|
|
247
|
+
};
|
|
248
|
+
// Stored: one notification for the superadmin (key = its id).
|
|
249
|
+
type Notice = record {
|
|
250
|
+
id : nat64;
|
|
251
|
+
area : opt text;
|
|
252
|
+
atNs : nat64;
|
|
253
|
+
kind : NoticeKind;
|
|
254
|
+
"text" : text;
|
|
255
|
+
canister : opt principal;
|
|
256
|
+
};
|
|
257
|
+
type NoticeKind = variant {
|
|
258
|
+
// The status of a copy could not be read.
|
|
259
|
+
StatusFailed;
|
|
260
|
+
BisectionStarted;
|
|
261
|
+
CopyCreated;
|
|
262
|
+
CopyDeleted;
|
|
263
|
+
// The load needs another copy, but `maxCopies` is reached.
|
|
264
|
+
MaxCopiesReached;
|
|
265
|
+
// The pass keys of a copy could not be set.
|
|
266
|
+
KeysFailed;
|
|
267
|
+
CopyMarked;
|
|
268
|
+
CopyUnmarked;
|
|
269
|
+
CopyFailed;
|
|
270
|
+
// The bisection found no single user (the load is honest) or lost its copies.
|
|
271
|
+
BisectionEnded;
|
|
272
|
+
// A core did not take the snapshot or an order.
|
|
273
|
+
CoreFailed;
|
|
274
|
+
// A system asked for too many passes in a minute.
|
|
275
|
+
SystemRateLimited;
|
|
276
|
+
// A user is blocked (bisection or too many renewals).
|
|
277
|
+
UserBlocked;
|
|
278
|
+
// A copy runs low and the coordinator cannot top it up.
|
|
279
|
+
CyclesLow;
|
|
280
|
+
};
|
|
281
|
+
type PassState = record {
|
|
282
|
+
// Copy → the id of its newest key and whether it holds `passRequired`.
|
|
283
|
+
keys : vec record { principal; nat32; bool };
|
|
284
|
+
cores : vec CoreCanister;
|
|
285
|
+
// Users with a valid pass, as the cores reported last.
|
|
286
|
+
activePasses : nat64;
|
|
287
|
+
systems : vec System;
|
|
288
|
+
blocks : vec Block;
|
|
289
|
+
bisections : vec BisectionRun;
|
|
290
|
+
};
|
|
291
|
+
// The cumulative `query_stats` of one copy (`canister_status`), as numbers.
|
|
292
|
+
type QueryTotals = record {
|
|
293
|
+
calls : nat;
|
|
294
|
+
instructions : nat;
|
|
295
|
+
responseBytes : nat;
|
|
296
|
+
};
|
|
297
|
+
// The load of one copy between two readings, per second.
|
|
298
|
+
type Rates = record {
|
|
299
|
+
responseBytesPerS : float64;
|
|
300
|
+
callsPerS : float64;
|
|
301
|
+
instructionsPerS : float64;
|
|
302
|
+
};
|
|
303
|
+
// Stored: the last reading of one copy (key = its canister).
|
|
304
|
+
type Reading = record {
|
|
305
|
+
atNs : nat64;
|
|
306
|
+
// The reading before (the rates cover `sinceNs..atNs`).
|
|
307
|
+
sinceNs : opt nat64;
|
|
308
|
+
cycles : nat;
|
|
309
|
+
totals : QueryTotals;
|
|
310
|
+
canister : principal;
|
|
311
|
+
// Since the reading before; none after the first one (or after the totals went down).
|
|
312
|
+
rates : opt Rates;
|
|
313
|
+
};
|
|
314
|
+
type Result = variant { Ok : Shard; Err : Error };
|
|
315
|
+
type Result_1 = variant { Ok : vec principal; Err : Error };
|
|
316
|
+
type Result_10 = variant { Ok : System; Err : Error };
|
|
317
|
+
type Result_11 = variant { Ok : RoundReport; Err : Error };
|
|
318
|
+
type Result_12 = variant { Ok : Settings; Err : Error };
|
|
319
|
+
type Result_13 = variant { Ok : bool; Err : Error };
|
|
320
|
+
type Result_2 = variant { Ok : Copy; Err : Error };
|
|
321
|
+
type Result_3 = variant { Ok : CoreCanister; Err : Error };
|
|
322
|
+
type Result_4 = variant { Ok : WasmMeta; Err : Error };
|
|
323
|
+
type Result_5 = variant { Ok : nat32; Err : Error };
|
|
324
|
+
type Result_6 = variant { Ok; Err : Error };
|
|
325
|
+
type Result_7 = variant { Ok : PassState; Err : Error };
|
|
326
|
+
type Result_8 = variant { Ok : State; Err : Error };
|
|
327
|
+
type Result_9 = variant { Ok : vec Notice; Err : Error };
|
|
328
|
+
// What one round saw and did.
|
|
329
|
+
type RoundReport = record {
|
|
330
|
+
atNs : nat64;
|
|
331
|
+
// What the round did, one line each.
|
|
332
|
+
actions : vec text;
|
|
333
|
+
loads : vec AreaLoad;
|
|
334
|
+
readings : vec Reading;
|
|
335
|
+
};
|
|
336
|
+
// Stored: the settings (key 0).
|
|
337
|
+
type Settings = record {
|
|
338
|
+
hInstructionsPerS : nat64;
|
|
339
|
+
subnets : vec Subnet;
|
|
340
|
+
copyCycles : nat;
|
|
341
|
+
// `null` = false (stored before phase 4).
|
|
342
|
+
passRequired : opt bool;
|
|
343
|
+
mode : Mode;
|
|
344
|
+
// `null` = `DEFAULT_CORE_CYCLES` (stored before 2026-11-06).
|
|
345
|
+
coreCycles : opt nat;
|
|
346
|
+
superadmins : vec principal;
|
|
347
|
+
maxCopies : nat32;
|
|
348
|
+
};
|
|
349
|
+
type SettingsArgs = record {
|
|
350
|
+
hInstructionsPerS : nat64;
|
|
351
|
+
// Where copies may go (stage / prod); ignored on the local replica.
|
|
352
|
+
subnets : vec Subnet;
|
|
353
|
+
copyCycles : nat;
|
|
354
|
+
// Workers refuse a query without a pass (`PassMissing`); `null` keeps the value held.
|
|
355
|
+
passRequired : opt bool;
|
|
356
|
+
// Cycles of a new pass core (≥ 0.6 TC); `null` keeps the value held.
|
|
357
|
+
coreCycles : opt nat;
|
|
358
|
+
maxCopies : nat32;
|
|
359
|
+
};
|
|
360
|
+
// Stored: one area (key = its name).
|
|
361
|
+
type Shard = record {
|
|
362
|
+
// The graph every live copy holds; set when the first copy goes live.
|
|
363
|
+
sha256 : opt text;
|
|
364
|
+
area : text;
|
|
365
|
+
bbox : Bbox;
|
|
366
|
+
osmDate : opt text;
|
|
367
|
+
};
|
|
368
|
+
type State = record {
|
|
369
|
+
coreWasm : opt WasmMeta;
|
|
370
|
+
shards : vec Shard;
|
|
371
|
+
lastRoundNs : opt nat64;
|
|
372
|
+
cores : vec CoreCanister;
|
|
373
|
+
wasm : opt WasmMeta;
|
|
374
|
+
loads : vec AreaLoad;
|
|
375
|
+
// The coordinator's own balance now.
|
|
376
|
+
cycles : nat;
|
|
377
|
+
readings : vec Reading;
|
|
378
|
+
settings : Settings;
|
|
379
|
+
copies : vec Copy;
|
|
380
|
+
};
|
|
381
|
+
type Subnet = record {
|
|
382
|
+
id : principal;
|
|
383
|
+
// A SEV subnet: the first copy of an area must stand on one.
|
|
384
|
+
sev : bool;
|
|
385
|
+
};
|
|
386
|
+
// Stored: one system (key = its principal).
|
|
387
|
+
type System = record {
|
|
388
|
+
id : principal;
|
|
389
|
+
demo : bool;
|
|
390
|
+
blocked : bool;
|
|
391
|
+
name : text;
|
|
392
|
+
hourlyLimit : opt nat32;
|
|
393
|
+
// The demo hour: its start and the passes in it.
|
|
394
|
+
hourStartNs : nat64;
|
|
395
|
+
passesThisHour : nat32;
|
|
396
|
+
perMinute : nat32;
|
|
397
|
+
};
|
|
398
|
+
// A trusted system: a canister of another project or an outside system with a principal.
|
|
399
|
+
type SystemArgs = record {
|
|
400
|
+
// Its principal (`principal` is a Candid keyword).
|
|
401
|
+
id : principal;
|
|
402
|
+
// Demo: short passes, a small bbox, `hourlyLimit` passes an hour for the whole system.
|
|
403
|
+
demo : bool;
|
|
404
|
+
// A blocked system gets nothing (the superadmin's decision).
|
|
405
|
+
blocked : bool;
|
|
406
|
+
name : text;
|
|
407
|
+
hourlyLimit : opt nat32;
|
|
408
|
+
// Passes a minute before `RateLimited`.
|
|
409
|
+
perMinute : nat32;
|
|
410
|
+
};
|
|
411
|
+
type UserKey = record { user : principal; system : principal };
|
|
412
|
+
type WasmChunkArgs = record {
|
|
413
|
+
// `null` = the worker.
|
|
414
|
+
kind : opt WasmKind;
|
|
415
|
+
offset : nat64;
|
|
416
|
+
bytes : blob;
|
|
417
|
+
};
|
|
418
|
+
// Which wasm: the worker of the copies, or the pass core.
|
|
419
|
+
type WasmKind = variant { Core; Worker };
|
|
420
|
+
// Stored: the worker wasm that is uploaded or held (key 0); its bytes lie in their own memory.
|
|
421
|
+
type WasmMeta = record { sha256 : text; size : nat64; ready : bool };
|
|
422
|
+
service : (InitArgs) -> {
|
|
423
|
+
// A new area; its first copy comes with `createCopy`.
|
|
424
|
+
addShard : (text, Bbox) -> (Result);
|
|
425
|
+
// A superadmin adds another (e.g. the Internet Identity principal of the front: it differs
|
|
426
|
+
// from a dfx identity). At most 8; never anonymous.
|
|
427
|
+
addSuperadmin : (principal) -> (Result_1);
|
|
428
|
+
// The next steps of a copy, from where it stands; a failed step is tried again.
|
|
429
|
+
advanceCopy : (principal) -> (Result_2);
|
|
430
|
+
// Installs a core that was created but not installed (a failed `createCore`).
|
|
431
|
+
advanceCore : (principal) -> (Result_3);
|
|
432
|
+
// Where to ask: the areas and their live copies. Public; a client keeps it `ttlSeconds`.
|
|
433
|
+
areas : () -> (Areas) query;
|
|
434
|
+
beginWasm : (BeginWasmArgs) -> (Result_4);
|
|
435
|
+
// The superadmin has read the notifications up to `id`.
|
|
436
|
+
clearNotifications : (nat64) -> (Result_5);
|
|
437
|
+
// `null` = the worker.
|
|
438
|
+
commitWasm : (opt WasmKind) -> (Result_4);
|
|
439
|
+
// A core reports: its users per area (the bisection starts on them), its blocks, the systems
|
|
440
|
+
// it refused. It arms a round (at most every 10 min).
|
|
441
|
+
coreReport : (CoreReport) -> (Result_6);
|
|
442
|
+
// A new copy of `area`: created, installed, then its steps as far as they go (`advanceCopy`
|
|
443
|
+
// goes on).
|
|
444
|
+
createCopy : (text) -> (Result_2);
|
|
445
|
+
// A new pass core: created (on a SEV subnet outside the local replica), installed with the
|
|
446
|
+
// core wasm, then given the snapshot.
|
|
447
|
+
createCore : () -> (Result_3);
|
|
448
|
+
// Only a superadmin deletes, only a marked copy off the list for one list TTL.
|
|
449
|
+
deleteCopy : (principal) -> (Result_6);
|
|
450
|
+
// Local replica only: totals of `query_stats` for the next rounds (it counts none itself).
|
|
451
|
+
feedQueryStats : (vec FeedArgs) -> (Result_6);
|
|
452
|
+
getPassState : () -> (Result_7) query;
|
|
453
|
+
getState : () -> (Result_8) query;
|
|
454
|
+
// Every coordinator (`sharding.md`): the crafting table asks before a reinstall.
|
|
455
|
+
hasDependents : () -> (bool) query;
|
|
456
|
+
// The superadmin front, for everybody: the page and its files. It shows nothing by itself;
|
|
457
|
+
// it asks the methods of the superadmins, as the person who signed in.
|
|
458
|
+
http_request : (HttpRequest) -> (HttpResponse) query;
|
|
459
|
+
// Which core issues the passes of `user` (public; a system keeps it with the list TTL).
|
|
460
|
+
issuerFor : (principal) -> (opt principal) query;
|
|
461
|
+
listDependents : () -> (vec principal) query;
|
|
462
|
+
// A superadmin takes a live copy off the list (the coordinator marks after 24 h of low load).
|
|
463
|
+
markCopy : (principal) -> (Result_2);
|
|
464
|
+
notifications : () -> (Result_9) query;
|
|
465
|
+
// A superadmin removes one; the last one stays.
|
|
466
|
+
removeSuperadmin : (principal) -> (Result_1);
|
|
467
|
+
// A system is gone: the cores forget it (its users' passes are refused from the next sync;
|
|
468
|
+
// passes already given stay valid until they end). E.g. a core of a group replaced by the
|
|
469
|
+
// group's coordinator as the system.
|
|
470
|
+
removeSystem : (principal) -> (Result_10);
|
|
471
|
+
// A round now, whatever the time of the last one; refused while one runs.
|
|
472
|
+
runRound : () -> (Result_11);
|
|
473
|
+
setSettings : (SettingsArgs) -> (Result_12);
|
|
474
|
+
// A system added or changed; the cores get it at once.
|
|
475
|
+
setSystem : (SystemArgs) -> (Result_10);
|
|
476
|
+
// Only a superadmin unblocks: every core lifts the block (the renewal count starts again).
|
|
477
|
+
unblockUser : (UserKey) -> (Result_13);
|
|
478
|
+
// A live (or marked) replicated instance gets the worker wasm held (stop → upgrade → start);
|
|
479
|
+
// its graphs and pass keys stay (stable memory). A failed step is kept in `lastError`.
|
|
480
|
+
upgradeCopy : (principal) -> (Result_2);
|
|
481
|
+
// A live core gets the core wasm held (stop → upgrade → start); its state stays. Then every
|
|
482
|
+
// core gets the snapshot again. A failed step is kept in `lastError`.
|
|
483
|
+
upgradeCore : (principal) -> (Result_3);
|
|
484
|
+
wasmChunk : (WasmChunkArgs) -> (Result_6);
|
|
485
|
+
}
|