zk-credits 0.2.12 → 0.2.14
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 +16 -5
- package/circuits/manifest.json +1 -0
- package/dist/activated-credential-setup.d.ts +18 -0
- package/dist/activated-credential-setup.js +64 -0
- package/dist/base-event-sync.js +7 -2
- package/dist/cli.js +17 -52
- package/dist/gateway-root-check.d.ts +3 -0
- package/dist/gateway-root-check.js +53 -21
- package/dist/investigator.mjs +10 -6
- package/dist/local-x402-agent.js +770 -521
- package/dist/rpc-config.js +4 -3
- package/dist/rpc-transport.d.ts +2 -0
- package/dist/rpc-transport.js +3 -0
- package/dist/zk-credits.js +1506 -1198
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -85,7 +85,7 @@ can observe traffic metadata. This does not hide your IP address.
|
|
|
85
85
|
|
|
86
86
|
Base Sepolia test credits only. The circuit is not independently audited.
|
|
87
87
|
|
|
88
|
-
### Coding-task evidence (0.2.
|
|
88
|
+
### Coding-task evidence (0.2.14 candidate)
|
|
89
89
|
|
|
90
90
|
After setup, `zk-credits codex --task-evidence` launches Codex against a fresh,
|
|
91
91
|
dedicated local sidecar and prints aggregate payment counters when Codex exits.
|
|
@@ -100,10 +100,10 @@ zk-credits codex --task-evidence
|
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
Enter your task, review the change and tests, then exit Codex to see the summary.
|
|
103
|
-
Version 0.2.12
|
|
103
|
+
Version 0.2.12 includes this command; 0.2.11 lacks it.
|
|
104
104
|
See the [indexer sample](https://github.com/mangekyou-labs/haze-api/tree/main/examples/base-usdc-indexer).
|
|
105
105
|
|
|
106
|
-
### Transaction investigator (0.2.
|
|
106
|
+
### Transaction investigator (0.2.14 candidate)
|
|
107
107
|
|
|
108
108
|
After closing Codex, run `zk-credits investigate --chain base <transaction-hash>`
|
|
109
109
|
with the same configured credential. It fetches public execution evidence and
|
|
@@ -112,8 +112,19 @@ the investigated chain; credit funding remains on Base Sepolia and consumption
|
|
|
112
112
|
is offchain. It does not purchase external traces. Keep missing-evidence notices
|
|
113
113
|
visible and distinguish observed errors from model hypotheses.
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
Version 0.2.14 fixes the investigator's packaged payment recipient pin and refuses
|
|
116
|
+
builds with missing or placeholder treasury addresses. Payment requirements must
|
|
117
|
+
still match the reviewed deployment before any proof is authorized.
|
|
118
|
+
|
|
119
|
+
Repeating a transaction hash recovers its existing local task without authorizing
|
|
120
|
+
a new paid call. The report shows the original stopping reason and labels prior
|
|
121
|
+
accounting separately from current invocation counters, including when the saved
|
|
122
|
+
run authorized no credits. Upgrading does not resume a stopped investigation.
|
|
123
|
+
Do not delete task journals or reset
|
|
117
124
|
credential accounting to force a fresh exchange. Unknown payment outcomes must
|
|
118
125
|
be reconciled before another paid task. A saved report must be labeled as a prior
|
|
119
126
|
run, with its own payment summary.
|
|
127
|
+
|
|
128
|
+
`challengeObserved` counts challenges presented for authorization, including
|
|
129
|
+
refused terms. A challenge alone does not imply a proof or consumed credit;
|
|
130
|
+
check confirmed, failed, unknown and retired counters separately.
|
package/circuits/manifest.json
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"deployment": {
|
|
34
34
|
"chainId": 84532,
|
|
35
35
|
"bondAddress": "0xcc1909dD30485d6D9a46e3d33cf04C1378b586Ab",
|
|
36
|
+
"treasuryAddress": "0xa8b9b38e748563AF7FbAA276e8a843Da417D7Bc1",
|
|
36
37
|
"deploymentBlock": "47372040",
|
|
37
38
|
"deploymentDomain": "84532",
|
|
38
39
|
"circuitId": "private-credit-spend-bn254-dev",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type CredentialStore } from './credential-store.js';
|
|
2
|
+
import { type ResolveSetupInputsOptions, type SetupConfig } from './setup-config.js';
|
|
3
|
+
export interface ActivatedCredentialSetupOptions {
|
|
4
|
+
environment?: NodeJS.ProcessEnv;
|
|
5
|
+
homeDirectory?: string;
|
|
6
|
+
stateDirectory?: string;
|
|
7
|
+
credentialStore?: CredentialStore;
|
|
8
|
+
chooseCandidate?: ResolveSetupInputsOptions['chooseCandidate'];
|
|
9
|
+
/** The caller owns hidden terminal input for explicit legacy import. */
|
|
10
|
+
readLegacyPassword?(): Promise<string>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Imports or loads the credential and prepares validated runtime configuration.
|
|
14
|
+
* Configuration is saved only after all checks pass. Credential import, artifact
|
|
15
|
+
* acquisition and witness synchronization may persist progress on failure so a
|
|
16
|
+
* retry can reuse it. Applies RPC and successful setup paths to the environment.
|
|
17
|
+
*/
|
|
18
|
+
export declare function setupActivatedCredential(options?: ActivatedCredentialSetupOptions): Promise<SetupConfig>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** Interactive credential preparation; runtime loading and launch remain separate. */
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { loadCircuitManifest } from './artifact-bundle.js';
|
|
5
|
+
import { validateBaseCreditWitness } from './base-sidecar.js';
|
|
6
|
+
import { importCredentialPath, nativeCredentialStore, readStoredCredential, } from './credential-store.js';
|
|
7
|
+
import { requireGatewayKnownRoot, resolveGatewayOrigin } from './gateway-root-check.js';
|
|
8
|
+
import { createPinnedBaseProofGenerator } from './proof-coordinator.js';
|
|
9
|
+
import { createBaseProofMetrics } from './proof-metrics.js';
|
|
10
|
+
import { applyRpcConfig, checkBaseSepoliaRpc, resolveBaseSepoliaRpc } from './rpc-config.js';
|
|
11
|
+
import { applySetupConfig, readSetupConfig, resolveSetupInputs, writeSetupConfig, } from './setup-config.js';
|
|
12
|
+
import { witnessProviderForSource } from './sidecar-runtime.js';
|
|
13
|
+
/**
|
|
14
|
+
* Imports or loads the credential and prepares validated runtime configuration.
|
|
15
|
+
* Configuration is saved only after all checks pass. Credential import, artifact
|
|
16
|
+
* acquisition and witness synchronization may persist progress on failure so a
|
|
17
|
+
* retry can reuse it. Applies RPC and successful setup paths to the environment.
|
|
18
|
+
*/
|
|
19
|
+
export async function setupActivatedCredential(options = {}) {
|
|
20
|
+
const environment = options.environment ?? process.env;
|
|
21
|
+
const homeDirectory = options.homeDirectory ?? homedir();
|
|
22
|
+
const stateDirectory = options.stateDirectory ?? (environment.ZK_CREDITS_HOME || join(homeDirectory, '.zk-credits'));
|
|
23
|
+
const configPath = join(stateDirectory, 'config.json');
|
|
24
|
+
const credentialStore = options.credentialStore ?? nativeCredentialStore(stateDirectory);
|
|
25
|
+
await applyRpcConfig(environment, stateDirectory);
|
|
26
|
+
const saved = await readSetupConfig(configPath);
|
|
27
|
+
const rpc = resolveBaseSepoliaRpc(environment, saved?.witness.kind === 'base-events' ? saved.witness.rpcUrl : undefined);
|
|
28
|
+
await checkBaseSepoliaRpc(rpc);
|
|
29
|
+
environment.BASE_RPC_URL = rpc;
|
|
30
|
+
const credentialPath = environment.ZK_CREDITS_CREDENTIAL_PATH;
|
|
31
|
+
const legacyPassword = await options.readLegacyPassword?.();
|
|
32
|
+
const credential = credentialPath
|
|
33
|
+
? await importCredentialPath(credentialPath, credentialStore, legacyPassword)
|
|
34
|
+
: await readStoredCredential(credentialStore);
|
|
35
|
+
const manifest = await loadCircuitManifest();
|
|
36
|
+
const config = await resolveSetupInputs({
|
|
37
|
+
environment,
|
|
38
|
+
homeDirectory,
|
|
39
|
+
stateDirectory,
|
|
40
|
+
configPath,
|
|
41
|
+
manifest,
|
|
42
|
+
validateWitness: async (source) => {
|
|
43
|
+
const provider = await witnessProviderForSource(source, join(stateDirectory, 'base-event-sync.json'));
|
|
44
|
+
const witness = validateBaseCreditWitness(await provider.witnessForCredential(credential));
|
|
45
|
+
if (manifest.deployment)
|
|
46
|
+
await requireGatewayKnownRoot(witness.root, resolveGatewayOrigin(environment));
|
|
47
|
+
},
|
|
48
|
+
chooseCandidate: options.chooseCandidate,
|
|
49
|
+
});
|
|
50
|
+
try {
|
|
51
|
+
await createPinnedBaseProofGenerator({
|
|
52
|
+
artifactDirectory: config.artifactDirectory,
|
|
53
|
+
metrics: createBaseProofMetrics(),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error instanceof Error)
|
|
58
|
+
throw new Error(`Pinned proving bundle check failed: ${error.message}`);
|
|
59
|
+
throw new Error('Pinned proving bundle check failed. Reinstall the bundle from your pilot invite.');
|
|
60
|
+
}
|
|
61
|
+
await writeSetupConfig(configPath, config);
|
|
62
|
+
applySetupConfig(environment, config);
|
|
63
|
+
return config;
|
|
64
|
+
}
|
package/dist/base-event-sync.js
CHANGED
|
@@ -13,6 +13,7 @@ import { baseSepolia } from 'viem/chains';
|
|
|
13
13
|
import { createPublicClient, http, parseAbi } from 'viem';
|
|
14
14
|
import { BASE_MEMBERSHIP_TREE_CAPACITY, BN254_FIELD_ORDER, computeCreditLeaf, deriveSparseCreditWitness, } from '@zk-credits/shared/base';
|
|
15
15
|
import { RPC_GUIDANCE } from './rpc-config.js';
|
|
16
|
+
import { rpcFetch } from './rpc-transport.js';
|
|
16
17
|
const BUNDLE_FUNDED_ABI = parseAbi([
|
|
17
18
|
'event BundleFunded(bytes32 indexed commitment, uint8 indexed tierId, uint64 expiry, uint256 leafIndex, uint256 bondAmount, bytes32 root)',
|
|
18
19
|
]);
|
|
@@ -82,12 +83,15 @@ function serializeLeaves(leaves) {
|
|
|
82
83
|
}
|
|
83
84
|
/** Creates a witness provider that syncs finalized BundleFunded events. */
|
|
84
85
|
export function createBaseEventWitnessProvider(options) {
|
|
85
|
-
const client = options.client ?? createPublicClient({ chain: baseSepolia,
|
|
86
|
+
const client = options.client ?? createPublicClient({ chain: baseSepolia,
|
|
87
|
+
transport: http(options.rpcUrl, { fetchFn: rpcFetch, retryCount: 0, timeout: 30_000 }),
|
|
88
|
+
});
|
|
86
89
|
const contract = address(options.contractAddress);
|
|
87
90
|
const confirmations = options.confirmations ?? 3n;
|
|
88
91
|
const maxBlockRange = options.maxBlockRange ?? 2000n;
|
|
89
92
|
let cache;
|
|
90
93
|
let leaves = new Map();
|
|
94
|
+
let pendingSync;
|
|
91
95
|
async function rpcCall(operation) {
|
|
92
96
|
try {
|
|
93
97
|
return await operation;
|
|
@@ -150,7 +154,8 @@ export function createBaseEventWitnessProvider(options) {
|
|
|
150
154
|
}
|
|
151
155
|
return {
|
|
152
156
|
async witnessForCredential(credential) {
|
|
153
|
-
|
|
157
|
+
pendingSync ??= synchronize().finally(() => { pendingSync = undefined; });
|
|
158
|
+
await pendingSync;
|
|
154
159
|
const commitment = field(credential.commitment, 'credential commitment');
|
|
155
160
|
const entry = [...leaves.entries()].find(([, value]) => value.commitment === commitment);
|
|
156
161
|
if (!entry)
|
package/dist/cli.js
CHANGED
|
@@ -1,33 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
3
4
|
import { join } from 'node:path';
|
|
4
5
|
import { createInterface } from 'node:readline/promises';
|
|
5
6
|
import { codingTaskEvidence, codingTaskProviderArgs, validateCodingTaskArgs } from './task-evidence.js';
|
|
6
7
|
import { launchCodexProcess } from './codex-launcher.js';
|
|
7
8
|
import { launchClineProcess } from './cline-launcher.js';
|
|
8
9
|
import { isCodexProfileInstalled, resolveCodexHome, writeCodexProfile, } from './codex-profile.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
10
|
+
import { createSidecarRuntime, RuntimeCredentialError } from './sidecar-runtime.js';
|
|
11
|
+
import { setupActivatedCredential } from './activated-credential-setup.js';
|
|
11
12
|
import { createLocalX402Agent } from './local-x402-agent.js';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { nativeCredentialStore, importCredentialPath, readStoredCredential } from './credential-store.js';
|
|
15
|
-
import { applyRpcConfig, checkBaseSepoliaRpc, writeRpcConfig, RPC_GUIDANCE, resolveBaseSepoliaRpc } from './rpc-config.js';
|
|
13
|
+
import { nativeCredentialStore } from './credential-store.js';
|
|
14
|
+
import { applyRpcConfig, checkBaseSepoliaRpc, writeRpcConfig, RPC_GUIDANCE } from './rpc-config.js';
|
|
16
15
|
import { diagnoseSidecar, stopSidecar } from './sidecar-diagnostics.js';
|
|
17
16
|
import { runCliCommand } from './cli-runtime.js';
|
|
18
17
|
import { createNodeSidecarLifecycle } from './node-sidecar-lifecycle.js';
|
|
19
18
|
import { activateSidecarServer } from './server-startup.js';
|
|
20
19
|
import { createLoopbackToken, sidecarStatePaths } from './sidecar-config.js';
|
|
21
|
-
import { applySetupConfig, readSetupConfig,
|
|
20
|
+
import { applySetupConfig, readSetupConfig, } from './setup-config.js';
|
|
22
21
|
import { ensureSidecarReady } from './sidecar-lifecycle.js';
|
|
23
22
|
import { readLoopbackToken, writeLoopbackToken } from './sidecar-state.js';
|
|
24
23
|
import { createSidecarServer } from './sidecar.js';
|
|
25
24
|
import { buildBaseRegisteredTrialRequestBody } from './base-registered-trial.js';
|
|
26
|
-
import { loadCircuitManifest } from './artifact-bundle.js';
|
|
27
25
|
import { BASE_SEPOLIA_NETWORK } from '@zk-credits/x402-zk-prepaid';
|
|
28
|
-
import {
|
|
26
|
+
import { DEFAULT_GATEWAY_URL, resolveGatewayOrigin } from './gateway-root-check.js';
|
|
29
27
|
import { evaluateGatewayReadiness, isGatewayStatusFresh } from './gateway-trial-status.js';
|
|
30
|
-
const DEFAULT_GATEWAY_URL = 'https://zk-credits-gateway.onrender.com';
|
|
31
28
|
const DEFAULT_PORT = 3210;
|
|
32
29
|
function stateDirectory() {
|
|
33
30
|
return process.env.ZK_CREDITS_HOME || join(homedir(), '.zk-credits');
|
|
@@ -120,6 +117,7 @@ async function readHiddenValue(prompt) {
|
|
|
120
117
|
}
|
|
121
118
|
function printHelp() {
|
|
122
119
|
console.log(`Usage:
|
|
120
|
+
zk-credits --version
|
|
123
121
|
zk-credits cline [cline arguments...]
|
|
124
122
|
zk-credits config rpc
|
|
125
123
|
zk-credits setup [codex|x402] [--legacy] [--model <model>]
|
|
@@ -200,11 +198,7 @@ function safeCount(value) {
|
|
|
200
198
|
return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
201
199
|
}
|
|
202
200
|
function gatewayOrigin() {
|
|
203
|
-
|
|
204
|
-
if (origin.protocol !== 'https:' || origin.username || origin.password || origin.search || origin.hash || origin.pathname !== '/') {
|
|
205
|
-
throw new Error('The internal trial requires a plain HTTPS gateway origin');
|
|
206
|
-
}
|
|
207
|
-
return origin;
|
|
201
|
+
return resolveGatewayOrigin(process.env);
|
|
208
202
|
}
|
|
209
203
|
async function readGatewayJson(url, headers) {
|
|
210
204
|
try {
|
|
@@ -222,9 +216,6 @@ async function readGatewayJson(url, headers) {
|
|
|
222
216
|
return { status: null };
|
|
223
217
|
}
|
|
224
218
|
}
|
|
225
|
-
async function requireGatewayKnownRoot(root) {
|
|
226
|
-
await checkGatewayKnownRoot(root, gatewayOrigin());
|
|
227
|
-
}
|
|
228
219
|
async function gatewayReadiness(origin) {
|
|
229
220
|
const response = await readGatewayJson(new URL('/ready', origin), { accept: 'application/json' });
|
|
230
221
|
const gate = evaluateGatewayReadiness(response.status, response.body);
|
|
@@ -591,6 +582,11 @@ async function runCodingTask(args) {
|
|
|
591
582
|
}
|
|
592
583
|
async function main() {
|
|
593
584
|
const args = process.argv.slice(2);
|
|
585
|
+
if (args[0] === '--version' || args[0] === '-v') {
|
|
586
|
+
const metadata = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8'));
|
|
587
|
+
console.log(metadata.version);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
594
590
|
const localHelp = ['doctor', 'stop', 'status', 'serve', 'setup', 'config', 'investigate'].includes(args[0] ?? '')
|
|
595
591
|
&& args.slice(1).some((arg) => arg === '--help' || arg === '-h');
|
|
596
592
|
if (args[0] === '--help' || args[0] === '-h' || !args[0] || localHelp) {
|
|
@@ -670,45 +666,14 @@ async function main() {
|
|
|
670
666
|
return Boolean(await credentialStore.read());
|
|
671
667
|
},
|
|
672
668
|
validateSetupPrerequisites: async () => {
|
|
673
|
-
await
|
|
674
|
-
const saved = await readSetupConfig(setupConfigPath(sidecarHome));
|
|
675
|
-
const rpc = resolveBaseSepoliaRpc(process.env, saved?.witness.kind === 'base-events' ? saved.witness.rpcUrl : undefined);
|
|
676
|
-
await checkBaseSepoliaRpc(rpc);
|
|
677
|
-
process.env.BASE_RPC_URL = rpc;
|
|
678
|
-
const credentialPath = process.env.ZK_CREDITS_CREDENTIAL_PATH;
|
|
679
|
-
const legacyPassword = args.includes('--legacy') ? await readHiddenValue('Legacy export password: ') : undefined;
|
|
680
|
-
const credential = credentialPath
|
|
681
|
-
? await importCredentialPath(credentialPath, credentialStore, legacyPassword)
|
|
682
|
-
: await readStoredCredential(credentialStore);
|
|
683
|
-
const manifest = await loadCircuitManifest();
|
|
684
|
-
const config = await resolveSetupInputs({
|
|
669
|
+
await setupActivatedCredential({
|
|
685
670
|
environment: process.env,
|
|
686
671
|
homeDirectory: homedir(),
|
|
687
672
|
stateDirectory: sidecarHome,
|
|
688
|
-
|
|
689
|
-
manifest,
|
|
690
|
-
validateWitness: async (source) => {
|
|
691
|
-
const provider = await witnessProviderForSource(source, join(stateDirectory(), 'base-event-sync.json'));
|
|
692
|
-
const witness = validateBaseCreditWitness(await provider.witnessForCredential(credential));
|
|
693
|
-
if (manifest.deployment)
|
|
694
|
-
await requireGatewayKnownRoot(witness.root);
|
|
695
|
-
},
|
|
673
|
+
credentialStore,
|
|
696
674
|
chooseCandidate: chooseSetupCandidate,
|
|
675
|
+
...(args.includes('--legacy') ? { readLegacyPassword: () => readHiddenValue('Legacy export password: ') } : {}),
|
|
697
676
|
});
|
|
698
|
-
const artifactDirectory = config.artifactDirectory;
|
|
699
|
-
try {
|
|
700
|
-
await createPinnedBaseProofGenerator({
|
|
701
|
-
artifactDirectory,
|
|
702
|
-
metrics: createBaseProofMetrics(),
|
|
703
|
-
});
|
|
704
|
-
}
|
|
705
|
-
catch (error) {
|
|
706
|
-
if (error instanceof Error)
|
|
707
|
-
throw new Error(`Pinned proving bundle check failed: ${error.message}`);
|
|
708
|
-
throw new Error('Pinned proving bundle check failed. Reinstall the bundle from your pilot invite.');
|
|
709
|
-
}
|
|
710
|
-
await writeSetupConfig(setupConfigPath(sidecarHome), config);
|
|
711
|
-
applySetupConfig(process.env, config);
|
|
712
677
|
console.log('Pinned proving bundle and witness validated for this activated credential.');
|
|
713
678
|
console.log('Local setup paths saved to ' + setupConfigPath(sidecarHome));
|
|
714
679
|
},
|
|
@@ -1,2 +1,5 @@
|
|
|
1
|
+
export declare const DEFAULT_GATEWAY_URL = "https://zk-credits-gateway.onrender.com";
|
|
2
|
+
/** Shared gateway origin validation for setup and the internal trial. */
|
|
3
|
+
export declare function resolveGatewayOrigin(environment: NodeJS.ProcessEnv): URL;
|
|
1
4
|
/** Public setup check. It sends the public root only and never needs an admin credential. */
|
|
2
5
|
export declare function requireGatewayKnownRoot(root: string, origin: URL, fetcher?: typeof fetch): Promise<void>;
|
|
@@ -1,28 +1,60 @@
|
|
|
1
1
|
function isRecord(value) {
|
|
2
2
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
3
3
|
}
|
|
4
|
+
export const DEFAULT_GATEWAY_URL = 'https://zk-credits-gateway.onrender.com';
|
|
5
|
+
/** Shared gateway origin validation for setup and the internal trial. */
|
|
6
|
+
export function resolveGatewayOrigin(environment) {
|
|
7
|
+
const origin = new URL(environment.ZK_CREDITS_GATEWAY_URL || DEFAULT_GATEWAY_URL);
|
|
8
|
+
if (origin.protocol !== 'https:' || origin.username || origin.password || origin.search || origin.hash || origin.pathname !== '/') {
|
|
9
|
+
throw new Error('The internal trial requires a plain HTTPS gateway origin');
|
|
10
|
+
}
|
|
11
|
+
return origin;
|
|
12
|
+
}
|
|
4
13
|
/** Public setup check. It sends the public root only and never needs an admin credential. */
|
|
5
14
|
export async function requireGatewayKnownRoot(root, origin, fetcher = fetch) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
response
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
body
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
body
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
const deadline = AbortSignal.timeout(60_000);
|
|
16
|
+
for (let attempt = 0; attempt < 3 && !deadline.aborted; attempt += 1) {
|
|
17
|
+
let response;
|
|
18
|
+
let body;
|
|
19
|
+
try {
|
|
20
|
+
response = await fetcher(new URL('/v1/root-known', origin), {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: { accept: 'application/json', 'content-type': 'application/json' },
|
|
23
|
+
body: JSON.stringify({ root }),
|
|
24
|
+
signal: AbortSignal.any([deadline, AbortSignal.timeout(30_000)]),
|
|
25
|
+
});
|
|
26
|
+
if (response.status === 200)
|
|
27
|
+
body = await response.json();
|
|
28
|
+
}
|
|
29
|
+
catch { /* Reachability/body failures remain uncertain, never unknown. */ }
|
|
30
|
+
if (response?.status === 200 && isRecord(body) && body.known === true)
|
|
31
|
+
return;
|
|
32
|
+
if (response?.status === 200 && isRecord(body) && body.known === false) {
|
|
33
|
+
throw new Error('The activated credential root is not in the gateway known-root set; stop setup and reconcile the V2 activation');
|
|
34
|
+
}
|
|
35
|
+
if (response && ![429, 500, 502, 503, 504].includes(response.status))
|
|
36
|
+
break;
|
|
37
|
+
if (attempt === 2)
|
|
38
|
+
break;
|
|
39
|
+
const retry = response?.headers.get('Retry-After');
|
|
40
|
+
const providerDelay = retry ? (/^\d+$/u.test(retry) ? Number(retry) * 1000 : Date.parse(retry) - Date.now()) : 0;
|
|
41
|
+
const delay = Math.max(500 * 2 ** attempt, Number.isFinite(providerDelay) ? providerDelay : 0);
|
|
42
|
+
await response?.body?.cancel().catch(() => { });
|
|
43
|
+
try {
|
|
44
|
+
await waitForGateway(delay, deadline);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
27
49
|
}
|
|
50
|
+
throw new Error('The gateway is temporarily unavailable and could not confirm the activated credential root. Retry zk-credits setup codex; changing the local RPC does not change the gateway connection.');
|
|
51
|
+
}
|
|
52
|
+
function waitForGateway(ms, signal) {
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
const abort = () => { clearTimeout(timer); reject(signal.reason); };
|
|
55
|
+
const timer = setTimeout(() => { signal.removeEventListener('abort', abort); resolve(); }, ms);
|
|
56
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
57
|
+
if (signal.aborted)
|
|
58
|
+
abort();
|
|
59
|
+
});
|
|
28
60
|
}
|
package/dist/investigator.mjs
CHANGED
|
@@ -2450,7 +2450,7 @@ async function persistJournal(stateDir, journalPath, nextRecords) {
|
|
|
2450
2450
|
}
|
|
2451
2451
|
|
|
2452
2452
|
// ../../examples/base-transaction-investigator/.generated/live-defaults.mjs
|
|
2453
|
-
var LIVE_DEFAULTS = { "build": "
|
|
2453
|
+
var LIVE_DEFAULTS = { "build": "67ef6dc5b0f4270103c0c4128a6fc85cf88148513c5d88ad7f471aa5637b4a55", "inference": { "gateway": "https://zk-credits-gateway.onrender.com/v1/chat/completions", "deploymentDomain": "84532", "contract": "0xcc1909dD30485d6D9a46e3d33cf04C1378b586Ab", "recipient": "0xa8b9b38e748563AF7FbAA276e8a843Da417D7Bc1", "circuit": "private-credit-spend-bn254-dev", "verifyingKey": "private-credit-spend-vk-dev-sepolia-v2", "serviceClass": "coding-deepseek-v4-flash-v1" } };
|
|
2454
2454
|
|
|
2455
2455
|
// ../../examples/base-transaction-investigator/live.mjs
|
|
2456
2456
|
var CHAINS = { base: 8453, "base-sepolia": 84532 };
|
|
@@ -2538,10 +2538,10 @@ async function runLiveInvestigation(args, options = {}) {
|
|
|
2538
2538
|
const inferenceFactory = async ({ authorization }) => {
|
|
2539
2539
|
const agent = await prepared.open({
|
|
2540
2540
|
async beforeProof(request) {
|
|
2541
|
+
challengeObserved++;
|
|
2541
2542
|
if ([...observations.values()].some((a) => a.state === "retired" && a.outcome === "unknown"))
|
|
2542
2543
|
throw Error("unknown_inference_outcome");
|
|
2543
2544
|
await authorization.beforeProof(request);
|
|
2544
|
-
challengeObserved++;
|
|
2545
2545
|
observations.set(request.attemptId, { state: "reserved", outcome: "unknown" });
|
|
2546
2546
|
},
|
|
2547
2547
|
async observe(event) {
|
|
@@ -2588,7 +2588,7 @@ async function runLiveInvestigation(args, options = {}) {
|
|
|
2588
2588
|
unknown: attempts.filter((a) => a.state !== "released" && a.outcome === "unknown").length,
|
|
2589
2589
|
retired: attempts.filter((a) => a.state === "retired").length,
|
|
2590
2590
|
modelDeliveryObserved,
|
|
2591
|
-
recoveredPriorTask:
|
|
2591
|
+
recoveredPriorTask: report.stoppingReason === "recovered_stopped",
|
|
2592
2592
|
build: LIVE_DEFAULTS.build
|
|
2593
2593
|
};
|
|
2594
2594
|
return report;
|
|
@@ -2605,6 +2605,8 @@ function formatLiveReport(report) {
|
|
|
2605
2605
|
`Result: ${report.completion} (${report.stoppingReason})`,
|
|
2606
2606
|
""
|
|
2607
2607
|
];
|
|
2608
|
+
if (report.stoppingReason === "recovered_stopped" && report.previousStoppingReason)
|
|
2609
|
+
lines.push(`Original stopping reason: ${report.previousStoppingReason}`);
|
|
2608
2610
|
for (const [label, items] of [
|
|
2609
2611
|
["Observed", report.observedFacts],
|
|
2610
2612
|
["Supported", report.supportedDiagnoses],
|
|
@@ -2615,10 +2617,12 @@ function formatLiveReport(report) {
|
|
|
2615
2617
|
}
|
|
2616
2618
|
for (const gap of [...report.missingEvidence ?? [], ...report.uncertainty ?? []]) lines.push(`Uncertainty: ${gap}`);
|
|
2617
2619
|
if (report.paymentEvidence.unknown > 0 || report.inference?.unknownOutcomes > 0) lines.push("Action: preserve this task and credential state; resolve the unknown outcome before starting another paid task. Repeating this hash only recovers the local report.");
|
|
2618
|
-
|
|
2619
|
-
if (
|
|
2620
|
+
const cause = report.stoppingReason === "recovered_stopped" ? report.previousStoppingReason : report.stoppingReason;
|
|
2621
|
+
if (cause === "inference_terms_refused") lines.push("Action: payment terms did not match the pinned deployment. Update zk-credits and check gateway configuration before starting a new investigation; repeating this hash only recovers the saved report.");
|
|
2622
|
+
if (cause === "inference_unavailable") lines.push("Action: run zk-credits doctor and check gateway/model availability. A useful model diagnosis is unavailable; inspect the separate payment counters.");
|
|
2623
|
+
if (["rpc_unavailable", "evidence_unavailable", "insufficient_evidence", "unsupported_input"].includes(cause)) lines.push("Action: check transaction availability on the selected chain and public RPC access; missing evidence cannot be replaced with fixtures.");
|
|
2620
2624
|
for (const entry of report.evidence ?? []) lines.push(`[${entry.id}] ${entry.operation}: ${entry.provenance}; SHA-256 ${entry.contentDigest}`);
|
|
2621
|
-
if (report.paymentEvidence.recoveredPriorTask) lines.push(`Recovered
|
|
2625
|
+
if (report.paymentEvidence.recoveredPriorTask) lines.push(`Recovered saved investigation; no new inference was authorized. Prior confirmed credits: ${report.inference.confirmedCommitted}; prior unknown outcomes: ${report.inference.unknownOutcomes}.`);
|
|
2622
2626
|
lines.push(
|
|
2623
2627
|
"",
|
|
2624
2628
|
"Payment: custom zk-prepaid; bundle funding on Base Sepolia, credit consumption offchain.",
|