@genkaku/protocol 0.1.10 → 0.1.12
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/dist/bridge.d.ts +4 -0
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +13 -3
- package/dist/chain.d.ts +10 -2
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +29 -4
- package/dist/dial.d.ts +26 -1
- package/dist/dial.d.ts.map +1 -1
- package/dist/dial.js +167 -20
- package/dist/p2pNode.d.ts +4 -2
- package/dist/p2pNode.d.ts.map +1 -1
- package/dist/p2pNode.js +35 -20
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +4 -1
- package/dist/status.d.ts +8 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +3 -0
- package/package.json +12 -8
package/dist/bridge.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export type BridgeStatus = {
|
|
|
13
13
|
offer: ReturnType<typeof toWire>;
|
|
14
14
|
}>;
|
|
15
15
|
url: string;
|
|
16
|
+
/** addr → the path its last session took: direct libp2p or the seed relay. */
|
|
17
|
+
transports?: Record<string, 'direct' | 'relay'>;
|
|
16
18
|
};
|
|
17
19
|
export type BridgeOptions = {
|
|
18
20
|
workers: string[];
|
|
@@ -25,6 +27,8 @@ export type BridgeOptions = {
|
|
|
25
27
|
settle: boolean;
|
|
26
28
|
log: (line: string) => void;
|
|
27
29
|
/** optional extra fields merged over the base status JSON (dashboard extension hook) */
|
|
30
|
+
/** Relay hops to fall back to once a direct dial keeps failing. */
|
|
31
|
+
getRelays?: () => Promise<string[]>;
|
|
28
32
|
status?: (base: BridgeStatus) => Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
29
33
|
/** optional live mode switch from POST /genkaku/mode */
|
|
30
34
|
onMode?: (mode: RoleMode) => void | Promise<void>;
|
package/dist/bridge.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACpC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAc/B,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,EAAgB,MAAM,EAAc,MAAM,YAAY,CAAA;AAI7D,uEAAuE;AACvE,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAA;KAAE,CAAC,CAAA;IACjE,GAAG,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACpC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAc/B,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,EAAgB,MAAM,EAAc,MAAM,YAAY,CAAA;AAI7D,uEAAuE;AACvE,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAA;KAAE,CAAC,CAAA;IACjE,GAAG,EAAE,MAAM,CAAA;IACX,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAA;CAChD,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,cAAc,CAAA;IACnB,WAAW,EAAE,WAAW,CAAA;IACxB,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;IAC9B,OAAO,EAAE,MAAM,GAAG,CAAA;IAClB,yEAAyE;IACzE,MAAM,EAAE,OAAO,CAAA;IACf,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3B,wFAAwF;IACxF,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACnC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAC3F,wDAAwD;IACxD,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjD;4DACwD;IACxD,MAAM,CAAC,EAAE,CACP,OAAO,EAAE,MAAM,EAAE,KACd,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;CAClH,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B,CAAA;AAuJD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CA6flF"}
|
package/dist/bridge.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { appendFileSync } from 'node:fs';
|
|
6
6
|
import { createServer } from 'node:http';
|
|
7
7
|
import { openEscrow, publicClientFor, readWorker, refundSession, settleSession, signReceiptPayload, walletAddress, walletClientFor, } from "./chain.js";
|
|
8
|
-
import {
|
|
8
|
+
import { dialWorkerAny, fetchOffers, requestSettleCosign } from "./dial.js";
|
|
9
9
|
import { dedupeOffers, toWire } from "./offer.js";
|
|
10
10
|
import { bindingOf, peerIdOf } from "./registry.js";
|
|
11
11
|
import { runUserSession } from "./userSession.js";
|
|
@@ -140,6 +140,7 @@ setInterval(load,5000);
|
|
|
140
140
|
</html>`;
|
|
141
141
|
export async function startOpenAiBridge(opts) {
|
|
142
142
|
const cache = new Map();
|
|
143
|
+
const transports = new Map();
|
|
143
144
|
let bridgeUrl = '';
|
|
144
145
|
async function offersOf(addr) {
|
|
145
146
|
const hit = cache.get(addr);
|
|
@@ -245,6 +246,7 @@ export async function startOpenAiBridge(opts) {
|
|
|
245
246
|
wallet: walletAddress(opts.userKey()),
|
|
246
247
|
offers,
|
|
247
248
|
url: bridgeUrl,
|
|
249
|
+
...(transports.size === 0 ? {} : { transports: Object.fromEntries(transports) }),
|
|
248
250
|
};
|
|
249
251
|
const extra = opts.status == null ? undefined : await opts.status(base);
|
|
250
252
|
json(res, 200, extra == null ? base : { ...base, ...extra });
|
|
@@ -317,7 +319,13 @@ export async function startOpenAiBridge(opts) {
|
|
|
317
319
|
}
|
|
318
320
|
}
|
|
319
321
|
const node = await opts.getNode();
|
|
320
|
-
const
|
|
322
|
+
const relays = opts.getRelays == null ? [] : await opts.getRelays().catch(() => []);
|
|
323
|
+
const dialed = await dialWorkerAny(node, picked.addr, { relays });
|
|
324
|
+
const transport = dialed.transport;
|
|
325
|
+
transports.set(picked.addr, dialed.route);
|
|
326
|
+
if (dialed.route === 'relay') {
|
|
327
|
+
opts.log(`transport: ${picked.addr} reached through the seed relay`);
|
|
328
|
+
}
|
|
321
329
|
const jobId = `dsh-${Date.now().toString(36)}`;
|
|
322
330
|
const created = Math.floor(Date.now() / 1000);
|
|
323
331
|
const id = `chatcmpl-${jobId}`;
|
|
@@ -465,7 +473,9 @@ export async function startOpenAiBridge(opts) {
|
|
|
465
473
|
debugLog(`receipt ${jobId}: hash=${receiptHash} billed=${result.billed} tokens=${result.tokens}`);
|
|
466
474
|
await settle({
|
|
467
475
|
node,
|
|
468
|
-
|
|
476
|
+
// Co-sign over the same path the session used: a worker behind NAT
|
|
477
|
+
// is only reachable through its relay address.
|
|
478
|
+
addr: dialed.addr,
|
|
469
479
|
walletC,
|
|
470
480
|
jobId,
|
|
471
481
|
escrowId,
|
package/dist/chain.d.ts
CHANGED
|
@@ -426,12 +426,20 @@ export declare const MAX_LOCATOR_ADDRS = 4;
|
|
|
426
426
|
* never contains it, so parsing stays unambiguous. */
|
|
427
427
|
export declare function locatorOf(addrs: readonly string[], maxBytes?: number, maxCount?: number): string;
|
|
428
428
|
/** True when this address is reachable from the public internet. LAN, loopback,
|
|
429
|
-
* link-local and CGNAT (100.64/10) ranges are local-only
|
|
430
|
-
*
|
|
429
|
+
* link-local and CGNAT (100.64/10) ranges are local-only. A `/p2p-circuit`
|
|
430
|
+
* address is dialable when its relay hop is a public host: the relay forwards
|
|
431
|
+
* the stream, so a worker behind NAT is still reachable through it (P5). */
|
|
431
432
|
export declare function isPublicAddr(addr: string): boolean;
|
|
432
433
|
/** Does this peer announce any address the global directory can use? Without
|
|
433
434
|
* one, on-chain presence only advertises a dead end (P4.9g §39). */
|
|
434
435
|
export declare function hasPublicAddr(addrs: readonly string[]): boolean;
|
|
436
|
+
/** How this peer is reachable to the internet, best first: a direct public
|
|
437
|
+
* address, a relay circuit through a public hop, or LAN only. The worker panel
|
|
438
|
+
* reports this instead of guessing from a bare address list. */
|
|
439
|
+
export declare function transportOf(addrs: readonly string[]): 'direct' | 'relay' | 'lan';
|
|
440
|
+
/** The address a client should try first: a public direct address, then a
|
|
441
|
+
* relay circuit, then anything (LAN) for a same-network peer. */
|
|
442
|
+
export declare function preferredAddr(addrs: readonly string[]): string | undefined;
|
|
435
443
|
/** Split a locator back into multiaddrs (tolerates `;`, newline, whitespace). */
|
|
436
444
|
export declare function parseLocator(locator: string): string[];
|
|
437
445
|
/** Register (or re-pin) AND publish the locator in one transaction. */
|
package/dist/chain.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"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"}
|
package/dist/chain.js
CHANGED
|
@@ -535,13 +535,17 @@ export function locatorOf(addrs, maxBytes = MAX_LOCATOR_BYTES, maxCount = MAX_LO
|
|
|
535
535
|
return picked.join(';');
|
|
536
536
|
}
|
|
537
537
|
/** True when this address is reachable from the public internet. LAN, loopback,
|
|
538
|
-
* link-local and CGNAT (100.64/10) ranges are local-only
|
|
539
|
-
*
|
|
538
|
+
* link-local and CGNAT (100.64/10) ranges are local-only. A `/p2p-circuit`
|
|
539
|
+
* address is dialable when its relay hop is a public host: the relay forwards
|
|
540
|
+
* the stream, so a worker behind NAT is still reachable through it (P5). */
|
|
540
541
|
export function isPublicAddr(addr) {
|
|
541
542
|
if (!addr.startsWith('/'))
|
|
542
543
|
return false;
|
|
543
|
-
|
|
544
|
-
|
|
544
|
+
const circuit = addr.indexOf('/p2p-circuit');
|
|
545
|
+
if (circuit >= 0) {
|
|
546
|
+
// Judge the relay hop only; the tail after /p2p-circuit is our own peer id.
|
|
547
|
+
return isPublicAddr(addr.slice(0, circuit));
|
|
548
|
+
}
|
|
545
549
|
const v4 = /^\/ip4\/(\d+)\.(\d+)\.(\d+)\.(\d+)\//.exec(addr);
|
|
546
550
|
if (v4 != null) {
|
|
547
551
|
const a = Number(v4[1]);
|
|
@@ -574,6 +578,27 @@ export function isPublicAddr(addr) {
|
|
|
574
578
|
export function hasPublicAddr(addrs) {
|
|
575
579
|
return addrs.some(isPublicAddr);
|
|
576
580
|
}
|
|
581
|
+
/** How this peer is reachable to the internet, best first: a direct public
|
|
582
|
+
* address, a relay circuit through a public hop, or LAN only. The worker panel
|
|
583
|
+
* reports this instead of guessing from a bare address list. */
|
|
584
|
+
export function transportOf(addrs) {
|
|
585
|
+
if (addrs.some(a => isPublicAddr(a) && !a.includes('/p2p-circuit')))
|
|
586
|
+
return 'direct';
|
|
587
|
+
if (addrs.some(a => a.includes('/p2p-circuit') && isPublicAddr(a)))
|
|
588
|
+
return 'relay';
|
|
589
|
+
return 'lan';
|
|
590
|
+
}
|
|
591
|
+
/** The address a client should try first: a public direct address, then a
|
|
592
|
+
* relay circuit, then anything (LAN) for a same-network peer. */
|
|
593
|
+
export function preferredAddr(addrs) {
|
|
594
|
+
const direct = addrs.find(a => isPublicAddr(a) && !a.includes('/p2p-circuit'));
|
|
595
|
+
if (direct != null)
|
|
596
|
+
return direct;
|
|
597
|
+
const relay = addrs.find(a => a.includes('/p2p-circuit') && isPublicAddr(a));
|
|
598
|
+
if (relay != null)
|
|
599
|
+
return relay;
|
|
600
|
+
return addrs.find(a => a.startsWith('/'));
|
|
601
|
+
}
|
|
577
602
|
/** Split a locator back into multiaddrs (tolerates `;`, newline, whitespace). */
|
|
578
603
|
export function parseLocator(locator) {
|
|
579
604
|
return locator
|
package/dist/dial.d.ts
CHANGED
|
@@ -2,6 +2,13 @@ import type { Libp2p } from 'libp2p';
|
|
|
2
2
|
import { type HelloProof } from './hello.ts';
|
|
3
3
|
import { type Offer } from './offer.ts';
|
|
4
4
|
import type { OpenEnvelope } from './workerSession.ts';
|
|
5
|
+
/** Direct dials before a worker's address is considered unreachable and the
|
|
6
|
+
* seed-VM relay path is preferred for subsequent sessions. */
|
|
7
|
+
export declare const DIRECT_ATTEMPTS_BEFORE_RELAY = 3;
|
|
8
|
+
export type DialRoute = 'direct' | 'relay';
|
|
9
|
+
/** Build `/p2p-circuit` addresses for `peerId` from the relays the seed handed
|
|
10
|
+
* out. The relay hop keeps its own `/p2p/<id>`; ours is appended last. */
|
|
11
|
+
export declare function circuitAddrsFor(relays: readonly string[], peerId: string): string[];
|
|
5
12
|
export type WorkerToolCall = {
|
|
6
13
|
index: number;
|
|
7
14
|
id: string;
|
|
@@ -21,15 +28,33 @@ export type WorkerTransport = {
|
|
|
21
28
|
close(): Promise<void>;
|
|
22
29
|
};
|
|
23
30
|
export declare function dialWorker(node: Libp2p, addr: string): Promise<WorkerTransport>;
|
|
24
|
-
/** Fetch + deserialize a worker's offer board (one dial, whole-board read). */
|
|
25
31
|
/** P4.9e: ask the peer to prove it holds the EVM key of the wallet it puts on
|
|
26
32
|
* its offers. Throws when the answer is missing, malformed, signed by another
|
|
27
33
|
* key, or claims a different PeerId than the one we dialed. */
|
|
28
34
|
export declare function helloWorker(node: Libp2p, addr: string): Promise<HelloProof>;
|
|
35
|
+
/** Dial a worker: direct libp2p first, and after repeated failures fall back
|
|
36
|
+
* to the seed-VM circuit relay. The route is returned so the caller can say
|
|
37
|
+
* which path a session actually took. */
|
|
38
|
+
export declare function dialWorkerAny(node: Libp2p, addr: string, opts?: {
|
|
39
|
+
relays?: readonly string[];
|
|
40
|
+
}): Promise<{
|
|
41
|
+
transport: WorkerTransport;
|
|
42
|
+
route: DialRoute;
|
|
43
|
+
addr: string;
|
|
44
|
+
}>;
|
|
45
|
+
/** Open (or reuse) a connection to a relay hop. The circuit transport only
|
|
46
|
+
* reserves a slot while a HOP-capable peer is connected, so a seed restart
|
|
47
|
+
* needs this again with the seed's new peer id. */
|
|
48
|
+
export declare function connectRelay(node: Libp2p, relay: string): void;
|
|
49
|
+
/** Fetch + deserialize a worker's offer board (one dial, whole-board read). */
|
|
29
50
|
export declare function fetchOffers(node: Libp2p, addr: string): Promise<Offer[]>;
|
|
30
51
|
/** P4.5 seed discovery: ask a bootstrap seed which peers it currently sees.
|
|
31
52
|
* The seed is a pure matchmaker — one frame in, one frame out, no storage. */
|
|
32
53
|
export declare function fetchSeedPeers(node: Libp2p, addr: string): Promise<string[]>;
|
|
54
|
+
/** Relay hops the seed advertises. A worker reserves a slot on one of these and
|
|
55
|
+
* a client uses them to reach workers that are not directly dialable. Both the
|
|
56
|
+
* HTTP and the libp2p seed paths answer with a `relay` array. */
|
|
57
|
+
export declare function fetchSeedRelays(node: Libp2p | null, seed: string): Promise<string[]>;
|
|
33
58
|
/**
|
|
34
59
|
* P4.4 settle co-sign (one dial, one frame each way): the user, at session
|
|
35
60
|
* end, presents (jobId, escrowId, receiptHash, spend); the worker checks its
|
package/dist/dial.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dial.d.ts","sourceRoot":"","sources":["../src/dial.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dial.d.ts","sourceRoot":"","sources":["../src/dial.ts"],"names":[],"mappings":"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"}
|
package/dist/dial.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// open handler never blocks on them. Offers are fetched per-discovered peer
|
|
5
5
|
// and sorted locally — the marketplace columns never touch the wire twice.
|
|
6
6
|
import { multiaddr } from '@multiformats/multiaddr';
|
|
7
|
+
import { peerIdFromString } from '@libp2p/peer-id';
|
|
7
8
|
import { newNonce, verifyHello } from "./hello.js";
|
|
8
9
|
import { FrameReader, lpEncode, WriteQueue } from "./lp.js";
|
|
9
10
|
import { fromWire } from "./offer.js";
|
|
@@ -12,6 +13,29 @@ import { peerIdOf } from "./registry.js";
|
|
|
12
13
|
/** How long to wait for the worker's admission ack before assuming an older
|
|
13
14
|
* worker that streams without one. */
|
|
14
15
|
const ADMISSION_TIMEOUT_MS = 8_000;
|
|
16
|
+
/** Direct dials before a worker's address is considered unreachable and the
|
|
17
|
+
* seed-VM relay path is preferred for subsequent sessions. */
|
|
18
|
+
export const DIRECT_ATTEMPTS_BEFORE_RELAY = 3;
|
|
19
|
+
/** addr → consecutive direct-dial failures. Kept per process so a client that
|
|
20
|
+
* learned a worker is behind NAT stops paying the direct timeout every turn. */
|
|
21
|
+
const directFailures = new Map();
|
|
22
|
+
/** A circuit-relayed connection carries a relay-imposed byte/duration limit, so
|
|
23
|
+
* libp2p marks it "limited" and refuses new streams unless the caller opts in.
|
|
24
|
+
* Every GenKaKu protocol is application data and must opt in; on a direct
|
|
25
|
+
* connection the flag is ignored. */
|
|
26
|
+
const RELAY_STREAM = { runOnLimitedConnection: true };
|
|
27
|
+
/** Build `/p2p-circuit` addresses for `peerId` from the relays the seed handed
|
|
28
|
+
* out. The relay hop keeps its own `/p2p/<id>`; ours is appended last. */
|
|
29
|
+
export function circuitAddrsFor(relays, peerId) {
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const relay of relays) {
|
|
32
|
+
if (!relay.startsWith('/') || !relay.includes('/p2p/'))
|
|
33
|
+
continue;
|
|
34
|
+
const hop = relay.split('/p2p-circuit')[0] ?? relay;
|
|
35
|
+
out.push(`${hop}/p2p-circuit/p2p/${peerId}`);
|
|
36
|
+
}
|
|
37
|
+
return [...new Set(out)];
|
|
38
|
+
}
|
|
15
39
|
export async function dialWorker(node, addr) {
|
|
16
40
|
const ma = multiaddr(addr);
|
|
17
41
|
const oq = new WriteQueue();
|
|
@@ -97,7 +121,7 @@ export async function dialWorker(node, addr) {
|
|
|
97
121
|
}
|
|
98
122
|
return {
|
|
99
123
|
async open(env) {
|
|
100
|
-
openStream = await node.dialProtocol(ma, '/genkaku/open/0');
|
|
124
|
+
openStream = await node.dialProtocol(ma, '/genkaku/open/0', RELAY_STREAM);
|
|
101
125
|
// errors surface via the read side
|
|
102
126
|
openSinkDone = openStream.sink(oq.source()).catch(() => { });
|
|
103
127
|
oq.push(lpEncode(env));
|
|
@@ -131,7 +155,7 @@ export async function dialWorker(node, addr) {
|
|
|
131
155
|
onError(cb) { errCbs.add(cb); },
|
|
132
156
|
async sendReceipt(jobId, seq, amount, sig = '', inputHash = ZERO_HASH, outputHash = ZERO_HASH) {
|
|
133
157
|
if (!receiptStream) {
|
|
134
|
-
receiptStream = await node.dialProtocol(ma, '/genkaku/receipt/0');
|
|
158
|
+
receiptStream = await node.dialProtocol(ma, '/genkaku/receipt/0', RELAY_STREAM);
|
|
135
159
|
receiptSinkDone = receiptStream.sink(rq.source()).catch(() => { });
|
|
136
160
|
}
|
|
137
161
|
rq.push(lpEncode({
|
|
@@ -153,14 +177,13 @@ export async function dialWorker(node, addr) {
|
|
|
153
177
|
},
|
|
154
178
|
};
|
|
155
179
|
}
|
|
156
|
-
/** Fetch + deserialize a worker's offer board (one dial, whole-board read). */
|
|
157
180
|
/** P4.9e: ask the peer to prove it holds the EVM key of the wallet it puts on
|
|
158
181
|
* its offers. Throws when the answer is missing, malformed, signed by another
|
|
159
182
|
* key, or claims a different PeerId than the one we dialed. */
|
|
160
183
|
export async function helloWorker(node, addr) {
|
|
161
184
|
const expectedPeer = peerIdOf(addr);
|
|
162
185
|
const nonce = newNonce();
|
|
163
|
-
const stream = await node.dialProtocol(multiaddr(addr), '/genkaku/hello/0');
|
|
186
|
+
const stream = await node.dialProtocol(multiaddr(addr), '/genkaku/hello/0', RELAY_STREAM);
|
|
164
187
|
let reply;
|
|
165
188
|
try {
|
|
166
189
|
stream.sink([lpEncode({ proto: 'hello/0', nonce })]).catch(() => { });
|
|
@@ -194,6 +217,76 @@ export async function helloWorker(node, addr) {
|
|
|
194
217
|
}
|
|
195
218
|
return proof;
|
|
196
219
|
}
|
|
220
|
+
/** Which path an established connection actually uses. libp2p reuses an
|
|
221
|
+
* existing connection to the same peer even when a different address was
|
|
222
|
+
* requested, so the request alone cannot tell us: read the connection's
|
|
223
|
+
* remote address. */
|
|
224
|
+
function routeOf(node, addr) {
|
|
225
|
+
const peer = peerIdOf(addr);
|
|
226
|
+
if (peer == null)
|
|
227
|
+
return null;
|
|
228
|
+
try {
|
|
229
|
+
const conns = node.getConnections(peerIdFromString(peer));
|
|
230
|
+
if (conns.length === 0)
|
|
231
|
+
return null;
|
|
232
|
+
const relayed = conns.some(c => c.remoteAddr.toString().includes('/p2p-circuit'));
|
|
233
|
+
const direct = conns.some(c => !c.remoteAddr.toString().includes('/p2p-circuit'));
|
|
234
|
+
if (direct)
|
|
235
|
+
return 'direct';
|
|
236
|
+
if (relayed)
|
|
237
|
+
return 'relay';
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/** Dial a worker: direct libp2p first, and after repeated failures fall back
|
|
245
|
+
* to the seed-VM circuit relay. The route is returned so the caller can say
|
|
246
|
+
* which path a session actually took. */
|
|
247
|
+
export async function dialWorkerAny(node, addr, opts = {}) {
|
|
248
|
+
// The board already handed us a relay address: no direct attempt to make.
|
|
249
|
+
if (addr.includes('/p2p-circuit')) {
|
|
250
|
+
return { transport: await dialWorker(node, addr), route: 'relay', addr };
|
|
251
|
+
}
|
|
252
|
+
const peer = peerIdOf(addr);
|
|
253
|
+
const circuits = peer == null ? [] : circuitAddrsFor(opts.relays ?? [], peer);
|
|
254
|
+
const failures = directFailures.get(addr) ?? 0;
|
|
255
|
+
const relayFirst = failures >= DIRECT_ATTEMPTS_BEFORE_RELAY && circuits.length > 0;
|
|
256
|
+
const order = relayFirst ? ['relay', 'direct'] : ['direct', 'relay'];
|
|
257
|
+
let lastError;
|
|
258
|
+
for (const route of order) {
|
|
259
|
+
if (route === 'relay' && circuits.length === 0)
|
|
260
|
+
continue;
|
|
261
|
+
const target = route === 'relay' ? circuits[0] : addr;
|
|
262
|
+
try {
|
|
263
|
+
const transport = await dialWorker(node, target);
|
|
264
|
+
// Trust the connection, not the request: a relay connection established
|
|
265
|
+
// earlier is reused for a "direct" dial to the same peer.
|
|
266
|
+
const actual = routeOf(node, target) ?? route;
|
|
267
|
+
if (actual === 'direct')
|
|
268
|
+
directFailures.delete(addr);
|
|
269
|
+
else
|
|
270
|
+
directFailures.set(addr, DIRECT_ATTEMPTS_BEFORE_RELAY);
|
|
271
|
+
return { transport, route: actual, addr: target };
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
lastError = error;
|
|
275
|
+
if (route === 'direct')
|
|
276
|
+
directFailures.set(addr, (directFailures.get(addr) ?? 0) + 1);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
280
|
+
}
|
|
281
|
+
/** Open (or reuse) a connection to a relay hop. The circuit transport only
|
|
282
|
+
* reserves a slot while a HOP-capable peer is connected, so a seed restart
|
|
283
|
+
* needs this again with the seed's new peer id. */
|
|
284
|
+
export function connectRelay(node, relay) {
|
|
285
|
+
if (!relay.startsWith('/'))
|
|
286
|
+
return;
|
|
287
|
+
void node.dial(multiaddr(relay)).catch(() => { });
|
|
288
|
+
}
|
|
289
|
+
/** Fetch + deserialize a worker's offer board (one dial, whole-board read). */
|
|
197
290
|
export async function fetchOffers(node, addr) {
|
|
198
291
|
const offers = await fetchOfferBoard(node, addr);
|
|
199
292
|
let proof;
|
|
@@ -215,7 +308,7 @@ export async function fetchOffers(node, addr) {
|
|
|
215
308
|
});
|
|
216
309
|
}
|
|
217
310
|
async function fetchOfferBoard(node, addr) {
|
|
218
|
-
const s = await node.dialProtocol(multiaddr(addr), '/genkaku/offers/0');
|
|
311
|
+
const s = await node.dialProtocol(multiaddr(addr), '/genkaku/offers/0', RELAY_STREAM);
|
|
219
312
|
const reader = new FrameReader();
|
|
220
313
|
let board = [];
|
|
221
314
|
for await (const chunk of s.source) {
|
|
@@ -254,7 +347,7 @@ export async function fetchSeedPeers(node, addr) {
|
|
|
254
347
|
return [];
|
|
255
348
|
}
|
|
256
349
|
}
|
|
257
|
-
const s = await node.dialProtocol(multiaddr(addr), '/genkaku/peers/0');
|
|
350
|
+
const s = await node.dialProtocol(multiaddr(addr), '/genkaku/peers/0', RELAY_STREAM);
|
|
258
351
|
const reader = new FrameReader();
|
|
259
352
|
for await (const chunk of s.source) {
|
|
260
353
|
reader.push(chunk);
|
|
@@ -267,6 +360,46 @@ export async function fetchSeedPeers(node, addr) {
|
|
|
267
360
|
await s.close().catch(() => { });
|
|
268
361
|
return [];
|
|
269
362
|
}
|
|
363
|
+
/** Relay hops the seed advertises. A worker reserves a slot on one of these and
|
|
364
|
+
* a client uses them to reach workers that are not directly dialable. Both the
|
|
365
|
+
* HTTP and the libp2p seed paths answer with a `relay` array. */
|
|
366
|
+
export async function fetchSeedRelays(node, seed) {
|
|
367
|
+
if (seed.startsWith('http://') || seed.startsWith('https://')) {
|
|
368
|
+
try {
|
|
369
|
+
const res = await fetch(`${seed.replace(/\/$/, '')}/peers`);
|
|
370
|
+
if (!res.ok)
|
|
371
|
+
return [];
|
|
372
|
+
const body = (await res.json());
|
|
373
|
+
return Array.isArray(body.relay)
|
|
374
|
+
? body.relay.filter((p) => typeof p === 'string' && p.startsWith('/'))
|
|
375
|
+
: [];
|
|
376
|
+
}
|
|
377
|
+
catch {
|
|
378
|
+
return [];
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
if (node == null)
|
|
382
|
+
return [];
|
|
383
|
+
try {
|
|
384
|
+
const s = await node.dialProtocol(multiaddr(seed), '/genkaku/peers/0', RELAY_STREAM);
|
|
385
|
+
const reader = new FrameReader();
|
|
386
|
+
for await (const chunk of s.source) {
|
|
387
|
+
reader.push(chunk);
|
|
388
|
+
const f = reader.next();
|
|
389
|
+
if (f?.proto === 'peers/0') {
|
|
390
|
+
await s.close().catch(() => { });
|
|
391
|
+
return Array.isArray(f.relay)
|
|
392
|
+
? f.relay.filter((p) => typeof p === 'string' && p.startsWith('/'))
|
|
393
|
+
: [];
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
await s.close().catch(() => { });
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
// fall through
|
|
400
|
+
}
|
|
401
|
+
return [];
|
|
402
|
+
}
|
|
270
403
|
/**
|
|
271
404
|
* P4.4 settle co-sign (one dial, one frame each way): the user, at session
|
|
272
405
|
* end, presents (jobId, escrowId, receiptHash, spend); the worker checks its
|
|
@@ -276,7 +409,7 @@ export async function fetchSeedPeers(node, addr) {
|
|
|
276
409
|
* digest JobEscrow.settle recovers against the session's worker address.
|
|
277
410
|
*/
|
|
278
411
|
export async function requestSettleCosign(node, addr, args) {
|
|
279
|
-
const s = await node.dialProtocol(multiaddr(addr), '/genkaku/settle/0');
|
|
412
|
+
const s = await node.dialProtocol(multiaddr(addr), '/genkaku/settle/0', RELAY_STREAM);
|
|
280
413
|
const reader = new FrameReader();
|
|
281
414
|
let reply = null;
|
|
282
415
|
const sinkDone = s.sink([lpEncode({
|
|
@@ -310,20 +443,34 @@ export async function requestSettleCosign(node, addr, args) {
|
|
|
310
443
|
export async function announceToSeed(node, seed, addrs) {
|
|
311
444
|
if (addrs.length === 0)
|
|
312
445
|
return false;
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
446
|
+
// A seed may be configured as a URL (the shipped default): its peer id
|
|
447
|
+
// changes on restart, so the address to dial is whatever it reports right
|
|
448
|
+
// now. `relay` is the seed's own address; `peers` are workers, never dial
|
|
449
|
+
// those for an announcement.
|
|
450
|
+
const targets = seed.startsWith('http://') || seed.startsWith('https://')
|
|
451
|
+
? await fetchSeedRelays(node, seed)
|
|
452
|
+
: [seed];
|
|
453
|
+
for (const target of targets) {
|
|
454
|
+
try {
|
|
455
|
+
const s = await node.dialProtocol(multiaddr(target), '/genkaku/announce/0', RELAY_STREAM);
|
|
456
|
+
try {
|
|
457
|
+
s.sink([lpEncode({ proto: 'announce/0', addrs })]).catch(() => { });
|
|
458
|
+
const reader = new FrameReader();
|
|
459
|
+
for await (const chunk of s.source) {
|
|
460
|
+
reader.push(chunk);
|
|
461
|
+
const f = reader.next();
|
|
462
|
+
if (f?.proto === 'announced/0' && f.ok === true)
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
finally {
|
|
467
|
+
await s.close().catch(() => { });
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
catch {
|
|
471
|
+
// try the next address the URL reported
|
|
322
472
|
}
|
|
323
|
-
return false;
|
|
324
|
-
}
|
|
325
|
-
finally {
|
|
326
|
-
await s.close().catch(() => { });
|
|
327
473
|
}
|
|
474
|
+
return false;
|
|
328
475
|
}
|
|
329
476
|
//# sourceMappingURL=dial.js.map
|
package/dist/p2pNode.d.ts
CHANGED
|
@@ -23,10 +23,12 @@ export type SidecarOptions = {
|
|
|
23
23
|
/** P4.4: with a worker wallet, priced receipts MUST carry a valid signature,
|
|
24
24
|
* offers self-report the wallet, and settle co-signing becomes available. */
|
|
25
25
|
workerKey?: Hex;
|
|
26
|
+
/** Public relay multiaddrs (the seed VM). Dialed at boot so the circuit
|
|
27
|
+
* transport can reserve a slot, which makes a NAT'd worker dialable. */
|
|
28
|
+
relayHints?: string[];
|
|
26
29
|
};
|
|
27
30
|
/** One stored (latest) receipt per jobId — the evidence the settle co-sign
|
|
28
|
-
* defends against (spend == max cumulative receipt the client piped). */
|
|
29
|
-
export type StoredReceipt = {
|
|
31
|
+
* defends against (spend == max cumulative receipt the client piped). */ export type StoredReceipt = {
|
|
30
32
|
seq: number;
|
|
31
33
|
amount: bigint;
|
|
32
34
|
sig: string;
|
package/dist/p2pNode.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"p2pNode.d.ts","sourceRoot":"","sources":["../src/p2pNode.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"p2pNode.d.ts","sourceRoot":"","sources":["../src/p2pNode.ts"],"names":[],"mappings":"AAcA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAA;AAClD,OAAO,EAAE,KAAK,GAAG,EAAW,MAAM,MAAM,CAAA;AAIxC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAE5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAGnD,OAAO,EAAoB,KAAK,KAAK,EAAU,MAAM,YAAY,CAAA;AAajE,OAAO,KAAK,EAAgB,YAAY,EAAiB,MAAM,oBAAoB,CAAA;AAGnF,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACzD,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC,eAAO,MAAM,iBAAiB,2JAQpB,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG;IAC3B,WAAW,EAAE,WAAW,CAAA;IACxB,MAAM,EAAE,qBAAqB,CAAA;IAC7B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,2EAA2E;IAC3E,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,+EAA+E;IAC/E,OAAO,EAAE,KAAK,EAAE,CAAA;IAChB,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,CAAA;IACzC,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;kFAC8E;IAC9E,SAAS,CAAC,EAAE,GAAG,CAAA;IACf;6EACyE;IACzE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CACtB,CAAA;AAED;0EAC0E,CAAA,MAAM,MAAM,aAAa,GAAG;IACpG,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAA;IAChB,kEAAkE;IAClE,SAAS,EAAE,KAAK,MAAM,EAAE,CAAA;IACxB,UAAU,EAAE,KAAK,MAAM,EAAE,CAAA;CAC1B,CAAA;AAkBD,+EAA+E;AAC/E,wBAAsB,cAAc,CAAC,MAAM,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAY3E;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,MAAM,EAAE,CAAA;IACzB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACrB,cAAc,EAAE,MAAM,MAAM,CAAA;IAC5B,+DAA+D;IAC/D,SAAS,EAAE,MAAM,MAAM,CAAA;IACvB,qEAAqE;IACrE,UAAU,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,CAAA;CACtC,CAAA;AAOD,wBAAsB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAggBjF"}
|
package/dist/p2pNode.js
CHANGED
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
// in depth, P4-ADAPTATION §2).
|
|
6
6
|
import { noise } from '@chainsafe/libp2p-noise';
|
|
7
7
|
import { yamux } from '@chainsafe/libp2p-yamux';
|
|
8
|
-
import {
|
|
8
|
+
import { circuitRelayTransport } from '@libp2p/circuit-relay-v2';
|
|
9
|
+
import { generateKeyPair, privateKeyFromRaw } from '@libp2p/crypto/keys';
|
|
9
10
|
import { identify } from '@libp2p/identify';
|
|
10
|
-
import {
|
|
11
|
+
import { peerIdFromPrivateKey } from '@libp2p/peer-id';
|
|
11
12
|
import { tcp } from '@libp2p/tcp';
|
|
13
|
+
import { multiaddr } from '@multiformats/multiaddr';
|
|
12
14
|
import { createLibp2p } from 'libp2p';
|
|
13
15
|
import { toBytes } from 'viem';
|
|
14
16
|
import { settleDigest, walletAddress } from "./chain.js";
|
|
@@ -43,17 +45,21 @@ const RECEIPT_DRAIN_MS = 250;
|
|
|
43
45
|
const CLOCK_SLACK_MS = 2_000;
|
|
44
46
|
/** A bare libp2p node for the USER side (no genkaku handlers — dials only). */
|
|
45
47
|
export async function createUserNode(listen = []) {
|
|
46
|
-
const
|
|
48
|
+
const privateKey = await generateKeyPair('secp256k1');
|
|
47
49
|
return createLibp2p({
|
|
48
|
-
|
|
50
|
+
privateKey,
|
|
49
51
|
nodeInfo: NODE_INFO,
|
|
50
52
|
addresses: { listen },
|
|
51
|
-
transports: [tcp()],
|
|
52
|
-
|
|
53
|
+
transports: [tcp(), circuitRelayTransport()],
|
|
54
|
+
connectionEncrypters: [noise()],
|
|
53
55
|
streamMuxers: [yamux()],
|
|
54
56
|
services: { identify: identify() },
|
|
55
57
|
});
|
|
56
58
|
}
|
|
59
|
+
/** Every GenKaKu protocol must accept a relayed (limited) connection: a worker
|
|
60
|
+
* behind NAT is ONLY reachable that way. libp2p refuses streams on a limited
|
|
61
|
+
* connection unless both the dialer and the handler opt in. */
|
|
62
|
+
const RELAY_HANDLER = { runOnLimitedConnection: true };
|
|
57
63
|
export async function createSidecar(opts) {
|
|
58
64
|
// D-block: do not even construct listeners without a sharing-capable mode.
|
|
59
65
|
const mode = opts.modeManager.current();
|
|
@@ -101,19 +107,28 @@ export async function createSidecar(opts) {
|
|
|
101
107
|
// SAME curve as the EVM wallet, so the P4.4 registry binding proves one key
|
|
102
108
|
// owns both sides of (PeerId, wallet) address. With a worker wallet, derive
|
|
103
109
|
// the PeerId from that exact key; otherwise keep a random identity.
|
|
104
|
-
const
|
|
105
|
-
?
|
|
106
|
-
: await
|
|
110
|
+
const privateKey = opts.workerKey != null
|
|
111
|
+
? privateKeyFromRaw(toBytes(opts.workerKey))
|
|
112
|
+
: await generateKeyPair('secp256k1');
|
|
113
|
+
const peerId = peerIdFromPrivateKey(privateKey);
|
|
107
114
|
const node = await createLibp2p({
|
|
108
|
-
|
|
115
|
+
privateKey,
|
|
109
116
|
nodeInfo: NODE_INFO,
|
|
110
|
-
addresses: { listen: opts.listen },
|
|
111
|
-
transports: [tcp()],
|
|
112
|
-
|
|
117
|
+
addresses: { listen: [...new Set([...opts.listen, '/p2p-circuit'])] },
|
|
118
|
+
transports: [tcp(), circuitRelayTransport()],
|
|
119
|
+
connectionEncrypters: [noise()],
|
|
113
120
|
streamMuxers: [yamux()],
|
|
114
121
|
services: { identify: identify() },
|
|
115
122
|
});
|
|
116
|
-
|
|
123
|
+
// Connect to the public relay up front: the circuit transport reserves a
|
|
124
|
+
// slot only once a HOP-capable peer is connected. Failures are non-fatal —
|
|
125
|
+
// a worker with a public address is still directly dialable.
|
|
126
|
+
for (const hint of opts.relayHints ?? []) {
|
|
127
|
+
void node.dial(multiaddr(hint)).catch(() => { });
|
|
128
|
+
}
|
|
129
|
+
/** Register a protocol that may run over a relayed (limited) connection. */
|
|
130
|
+
const handle = (protocol, handler) => node.handle(protocol, handler, RELAY_HANDLER);
|
|
131
|
+
await handle('/genkaku/open/0', ({ connection, stream }) => {
|
|
117
132
|
void (async () => {
|
|
118
133
|
// Read ONLY the open envelope, then start serving — the client keeps its
|
|
119
134
|
// write half open for the session, so a drain-to-EOS read would deadlock
|
|
@@ -236,7 +251,7 @@ export async function createSidecar(opts) {
|
|
|
236
251
|
void connection;
|
|
237
252
|
})();
|
|
238
253
|
});
|
|
239
|
-
await
|
|
254
|
+
await handle('/genkaku/receipt/0', ({ stream }) => {
|
|
240
255
|
void (async () => {
|
|
241
256
|
const reader = new FrameReader();
|
|
242
257
|
for await (const chunk of stream.source) {
|
|
@@ -299,7 +314,7 @@ export async function createSidecar(opts) {
|
|
|
299
314
|
// only compared against it), and the spend must equal the held max
|
|
300
315
|
// cumulative receipt — anti-inflation by construction (P1 §8). JobEscrow.
|
|
301
316
|
// settle() then recovers this EIP-191 sig against the session's worker.
|
|
302
|
-
await
|
|
317
|
+
await handle('/genkaku/settle/0', ({ stream }) => {
|
|
303
318
|
void (async () => {
|
|
304
319
|
const reader = new FrameReader();
|
|
305
320
|
let req;
|
|
@@ -356,7 +371,7 @@ export async function createSidecar(opts) {
|
|
|
356
371
|
});
|
|
357
372
|
// P4.9e identity proof: one nonce in, one signed proof out. The client
|
|
358
373
|
// recovers the signer and refuses offers whose wallet it cannot prove.
|
|
359
|
-
await
|
|
374
|
+
await handle('/genkaku/hello/0', ({ stream }) => {
|
|
360
375
|
void (async () => {
|
|
361
376
|
const reader = new FrameReader();
|
|
362
377
|
let req;
|
|
@@ -385,14 +400,14 @@ export async function createSidecar(opts) {
|
|
|
385
400
|
// locally (P4.3). bigint prices travel as decimal strings (OfferWire); the
|
|
386
401
|
// wallet here is a CLAIM — the client only trusts it after /genkaku/hello/0
|
|
387
402
|
// proves the key (P4.9e) or the registry binds it (P4.5).
|
|
388
|
-
await
|
|
403
|
+
await handle('/genkaku/offers/0', ({ stream }) => {
|
|
389
404
|
const wallet = opts.workerKey != null ? walletAddress(opts.workerKey) : undefined;
|
|
390
405
|
const board = currentCatalog.map(o => toWire(wallet == null ? o : { ...o, workerWallet: wallet }));
|
|
391
406
|
void stream.sink([lpEncode({ proto: 'offers/0', board })]).then(() => stream.close());
|
|
392
407
|
});
|
|
393
408
|
// token is served in-session (open handler); policy is reserved v0.
|
|
394
|
-
await
|
|
395
|
-
await
|
|
409
|
+
await handle('/genkaku/token/0', ({ stream }) => { void stream.close(); });
|
|
410
|
+
await handle('/genkaku/policy/0', ({ stream }) => {
|
|
396
411
|
// P4.5: the wire advertises the SAME digest the worker pins on
|
|
397
412
|
// WorkerRegistry, so a user can compare registry.policyHash against it.
|
|
398
413
|
void stream.sink([lpEncode({ proto: 'policy/0', policyHash: policyHashOf(POLICY_VERSION), policyVersion: POLICY_VERSION })]).then(() => stream.close());
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAoBA,6EAA6E;AAC7E,eAAO,MAAM,cAAc,aAAa,CAAA;AAExC,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,CAM5D;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,CAE1D;AAED,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAoBA,6EAA6E;AAC7E,eAAO,MAAM,cAAc,aAAa,CAAA;AAExC,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,CAM5D;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,CAE1D;AAED,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYpD;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,EAAE,KAAK,MAAM,EAAE,CAAA;IACrB,UAAU,EAAE,KAAK,MAAM,EAAE,CAAA;CAC1B,CAAA;AAED;;;qEAGqE;AACrE,wBAAgB,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAMrG"}
|
package/dist/registry.js
CHANGED
|
@@ -30,7 +30,10 @@ export function policyHashOf(policy) {
|
|
|
30
30
|
}
|
|
31
31
|
/** The libp2p PeerId encoded in a worker multiaddr (the grain of the compare). */
|
|
32
32
|
export function peerIdOf(addr) {
|
|
33
|
-
|
|
33
|
+
// A relay address carries TWO peer ids (relay and destination); the
|
|
34
|
+
// destination is the tail. Taking the first one would identify the seed.
|
|
35
|
+
const segments = addr.split('/p2p/');
|
|
36
|
+
const tail = segments.length > 1 ? segments[segments.length - 1] : undefined;
|
|
34
37
|
if (tail != null && tail !== '') {
|
|
35
38
|
// trim any stray suffix (addresses end at the peer id in our dialer)
|
|
36
39
|
return tail.split('/')[0] || null;
|
package/dist/status.d.ts
CHANGED
|
@@ -18,6 +18,14 @@ export type StatusSnapshot = {
|
|
|
18
18
|
reachable: boolean;
|
|
19
19
|
/** config.publishAddress: may a public address be written to the chain? */
|
|
20
20
|
publishAddress: boolean;
|
|
21
|
+
/** publishAddress AND a globally dialable address: the entry can be dialed. */
|
|
22
|
+
published?: boolean;
|
|
23
|
+
/** true when the profile forces publishing on, so the switch cannot turn it off. */
|
|
24
|
+
publishForced?: boolean;
|
|
25
|
+
/** How this worker is reachable: direct libp2p, a relay circuit, or LAN only. */
|
|
26
|
+
transport?: 'direct' | 'relay' | 'lan';
|
|
27
|
+
/** Relay hops this worker reserved (seed VM), for the panel to explain relay mode. */
|
|
28
|
+
relayHints?: string[];
|
|
21
29
|
};
|
|
22
30
|
export type StatusHandle = {
|
|
23
31
|
url: string;
|
package/dist/status.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C,+CAA+C;AAC/C,MAAM,MAAM,WAAW,GAAG;IACxB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,SAAS,CAAA;CACjB,CAAA;AAED,0EAA0E;AAC1E,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,4EAA4E;IAC5E,SAAS,EAAE,OAAO,CAAA;IAClB,2EAA2E;IAC3E,cAAc,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C,+CAA+C;AAC/C,MAAM,MAAM,WAAW,GAAG;IACxB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,SAAS,CAAA;CACjB,CAAA;AAED,0EAA0E;AAC1E,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,4EAA4E;IAC5E,SAAS,EAAE,OAAO,CAAA;IAClB,2EAA2E;IAC3E,cAAc,EAAE,OAAO,CAAA;IACvB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,oFAAoF;IACpF,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,iFAAiF;IACjF,SAAS,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAA;IACtC,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B,CAAA;AAED,mEAAmE;AACnE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB,CAAA;AAED,6DAA6D;AAC7D,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,EAAE,iBAAiB,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAEzF,0DAA0D;AAC1D,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAExE,2DAA2D;AAC3D,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAE7E,8DAA8D;AAC9D,MAAM,MAAM,aAAa,GAAG;IAC1B,mEAAmE;IACnE,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7B,2CAA2C;IAC3C,aAAa,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IACrC,sEAAsE;IACtE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,QAAQ,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,KAAK,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC1H,0CAA0C;IAC1C,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACzC,CAAA;AAyKD,6DAA6D;AAC7D,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,EACxD,SAAS,CAAC,EAAE,oBAAoB,EAChC,MAAM,CAAC,EAAE,iBAAiB,EAC1B,MAAM,CAAC,EAAE,aAAa,EACtB,SAAS,CAAC,EAAE,oBAAoB,GAC/B,OAAO,CAAC,YAAY,CAAC,CA+LvB"}
|
package/dist/status.js
CHANGED
|
@@ -84,6 +84,9 @@ function renderInfo(s){
|
|
|
84
84
|
document.getElementById('info').innerHTML=roleRow(s.role)+card('peer id',s.peerId)
|
|
85
85
|
+card('peer addresses',(s.peerAddrs||[]).join(', '))+card('wallet',s.wallet)
|
|
86
86
|
+card('active sessions',s.activeSessions)
|
|
87
|
+
+card('connection',s.transport==='direct'?'libp2p direct'
|
|
88
|
+
:s.transport==='relay'?'seed VM relay (traffic is forwarded; clients try direct first)'
|
|
89
|
+
:'this network only — no public address and no relay reservation yet')
|
|
87
90
|
+card('discovery',s.reachable
|
|
88
91
|
? (s.publishAddress
|
|
89
92
|
? 'global directory (public address published)'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genkaku/protocol",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "GenKaKu protocol core: on-chain worker directory, USDC escrow billing, libp2p transport, Ollama lifecycle",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -21,14 +21,15 @@
|
|
|
21
21
|
"LICENSE"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@chainsafe/libp2p-noise": "
|
|
25
|
-
"@chainsafe/libp2p-yamux": "
|
|
26
|
-
"@libp2p/
|
|
27
|
-
"@libp2p/
|
|
28
|
-
"@libp2p/
|
|
29
|
-
"@libp2p/
|
|
24
|
+
"@chainsafe/libp2p-noise": "16.1.5",
|
|
25
|
+
"@chainsafe/libp2p-yamux": "7.0.4",
|
|
26
|
+
"@libp2p/circuit-relay-v2": "3.2.24",
|
|
27
|
+
"@libp2p/crypto": "5.1.8",
|
|
28
|
+
"@libp2p/identify": "3.0.39",
|
|
29
|
+
"@libp2p/peer-id": "5.1.9",
|
|
30
|
+
"@libp2p/tcp": "10.1.19",
|
|
30
31
|
"@multiformats/multiaddr": "12.5.1",
|
|
31
|
-
"libp2p": "
|
|
32
|
+
"libp2p": "2.10.0",
|
|
32
33
|
"viem": "2.57.16"
|
|
33
34
|
},
|
|
34
35
|
"repository": {
|
|
@@ -51,6 +52,9 @@
|
|
|
51
52
|
"usdc",
|
|
52
53
|
"base"
|
|
53
54
|
],
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=22"
|
|
57
|
+
},
|
|
54
58
|
"scripts": {
|
|
55
59
|
"build": "tsc -p tsconfig.json",
|
|
56
60
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|