Real XMR pilot
This commit is contained in:
+11
-2
@@ -1,13 +1,22 @@
|
||||
import { IS_MAINNET, NETWORK, PROFILE } from '../shared/network.ts';
|
||||
import { IS_MAINNET, IS_PILOT, NETWORK, PROFILE } from '../shared/network.ts';
|
||||
import { CHAIN_ID, GENESIS_HASH, GENESIS_TIME } from './testnet/consensus.ts';
|
||||
|
||||
export function launchManifest() {
|
||||
return { profile: PROFILE, network: NETWORK, chainId: CHAIN_ID, genesis: GENESIS_HASH,
|
||||
genesisTime: GENESIS_TIME, launchStatus: IS_MAINNET ? 'candidate-gated' : 'testnet',
|
||||
genesisTime: GENESIS_TIME, launchStatus: IS_MAINNET ? 'candidate-gated' : IS_PILOT ? 'private-pilot-mock-only' : 'testnet',
|
||||
paymentMode: 'mock', audited: false };
|
||||
}
|
||||
/** Operator attestation is an accident-prevention gate, NOT proof of a security audit. */
|
||||
export function assertLaunchAllowed(env: NodeJS.ProcessEnv = process.env, now = Date.now()) {
|
||||
if (IS_PILOT) {
|
||||
if (env.WIKIDECK_PILOT_MODE !== 'private-mock-only') {
|
||||
throw new Error('Private pilot requires WIKIDECK_PILOT_MODE=private-mock-only');
|
||||
}
|
||||
if ((env.WIKIDECK_PAYMENT_MODE ?? 'mock') !== 'mock') {
|
||||
throw new Error('Private pilot supports mock payments only; live XMR remains disabled');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!IS_MAINNET) return;
|
||||
if (env.WIKIDECK_MAINNET_LAUNCH !== CHAIN_ID || env.WIKIDECK_MAINNET_REVIEW_ACK !== 'independent-review-complete') {
|
||||
throw new Error(`Mainnet candidate is launch-gated. Review the launch checklist; explicit chain approval required: ${CHAIN_ID}`);
|
||||
|
||||
@@ -4,10 +4,12 @@ import { join } from 'node:path';
|
||||
import { CustodyMarket } from './custody.ts';
|
||||
import { PostgresCustody, type CustodyOptions } from './postgres-custody.ts';
|
||||
import { custodyStorage, postgresConfig } from './postgres-config.ts';
|
||||
import { PROFILE } from '../../shared/network.ts';
|
||||
|
||||
/** No automatic SQLite reinterpretation or fallback after a database connection/configuration failure. */
|
||||
export async function openCustodyStorage(directory: string, options: CustodyOptions, env = process.env): Promise<CustodyMarket | PostgresCustody> {
|
||||
const storage = custodyStorage(env), marker = join(directory, 'testnet', 'custody-postgres.json');
|
||||
const profileDirectory = join(directory, PROFILE);
|
||||
const storage = custodyStorage(env), marker = join(profileDirectory, 'custody-postgres.json');
|
||||
const observerMode = env.WIKIDECK_CUSTODY_CANONICAL_REHEARSAL;
|
||||
if (observerMode !== undefined && observerMode !== '0' && observerMode !== '1') {
|
||||
throw new Error('WIKIDECK_CUSTODY_CANONICAL_REHEARSAL must be exactly 0 or 1');
|
||||
@@ -16,7 +18,7 @@ export async function openCustodyStorage(directory: string, options: CustodyOpti
|
||||
throw new Error('Canonical observer rehearsal requires PostgreSQL and the disposable database test guard');
|
||||
}
|
||||
const custodyOptions = observerMode === '1' ? { ...options, disposableSaleRehearsal: true } : options;
|
||||
await mkdir(join(directory, 'testnet'), { recursive: true, mode: 0o700 });
|
||||
await mkdir(profileDirectory, { recursive: true, mode: 0o700 });
|
||||
let existing: { version: number; custodianId: string } | undefined;
|
||||
try { existing = JSON.parse(await readFile(marker, 'utf8')); }
|
||||
catch (e) { if ((e as NodeJS.ErrnoException).code !== 'ENOENT') throw e; }
|
||||
@@ -24,7 +26,7 @@ export async function openCustodyStorage(directory: string, options: CustodyOpti
|
||||
if (existing) throw new Error('Custody data directory is bound to PostgreSQL; SQLite fallback prohibited');
|
||||
return CustodyMarket.open(directory, custodyOptions);
|
||||
}
|
||||
const source = join(directory, 'testnet', 'custody-sandbox.sqlite');
|
||||
const source = join(profileDirectory, 'custody-sandbox.sqlite');
|
||||
let frozen: string | undefined;
|
||||
try {
|
||||
const info = await lstat(source);
|
||||
@@ -44,7 +46,7 @@ export async function openCustodyStorage(directory: string, options: CustodyOpti
|
||||
try { await handle.writeFile(JSON.stringify({ version: 1, custodianId: market.id })); await handle.sync(); }
|
||||
finally { await handle.close(); }
|
||||
if (process.platform !== 'win32') {
|
||||
const parent = await open(join(directory, 'testnet'), 'r');
|
||||
const parent = await open(profileDirectory, 'r');
|
||||
try { await parent.sync(); } finally { await parent.close(); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { DatabaseSync } from 'node:sqlite';
|
||||
import { createHash, randomUUID } from 'node:crypto';
|
||||
import { mkdir, chmod } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import { IS_MAINNET } from '../../shared/network.ts';
|
||||
import { IS_MAINNET, PROFILE } from '../../shared/network.ts';
|
||||
import { NETWORK } from '../../shared/testnet.ts';
|
||||
import { ADDITIONAL_MARKET_FEE } from '../../shared/market.ts';
|
||||
import { allocateXmrSale } from '../../shared/xmr-pricing.ts';
|
||||
@@ -50,7 +50,7 @@ export class CustodyMarket {
|
||||
if (IS_MAINNET) throw new Error('Custody sandbox cannot run on mainnet');
|
||||
await validateMarketPolicy(options);
|
||||
if (!Number.isSafeInteger(options.feeBps) || options.feeBps < 0 || options.feeBps > 5000) throw new Error('Invalid custody fee');
|
||||
const folder = join(directory, 'testnet');
|
||||
const folder = join(directory, PROFILE);
|
||||
await mkdir(folder, { recursive: true, mode: 0o700 });
|
||||
const file = join(folder, 'custody-sandbox.sqlite');
|
||||
const db = new DatabaseSync(file);
|
||||
|
||||
@@ -16,6 +16,7 @@ import { RpcError } from '../resources.ts';
|
||||
import type { CanonicalEvents, IndexedNft } from '../testnet/canonical-index.ts';
|
||||
import { z } from 'zod';
|
||||
import { operatorMarketPolicy, resolvedMarketPolicy, permitsMarketAction, validateMarketPolicy, type MarketPolicy } from './policy.ts';
|
||||
import { PROFILE } from '../../shared/network.ts';
|
||||
|
||||
type Chain = { snapshot(): TestnetSnapshot; summary?(): { tip: string; revision: number; height?: number };
|
||||
submitTransfer(raw: unknown): Promise<string>; nft?(token: string): IndexedNft | undefined;
|
||||
@@ -112,7 +113,7 @@ export class Market {
|
||||
static async open(directory: string, chain: Chain, config = marketConfig(), now = Date.now,
|
||||
reconciliation: { worker?: boolean } = {}): Promise<Market> {
|
||||
await validateMarketPolicy(config);
|
||||
const folder = join(directory, NETWORK.includes('mainnet') ? 'mainnet' : 'testnet');
|
||||
const folder = join(directory, PROFILE);
|
||||
await mkdir(folder, { recursive: true, mode: 0o700 });
|
||||
const file = join(folder, 'market.sqlite');
|
||||
const db = new DatabaseSync(file);
|
||||
|
||||
+6
-4
@@ -1,4 +1,4 @@
|
||||
import { IS_MAINNET } from '../shared/network.ts';
|
||||
import { IS_MAINNET, IS_PILOT } from '../shared/network.ts';
|
||||
import { ADDITIONAL_MARKET_FEE } from '../shared/market.ts';
|
||||
import { assertLaunchAllowed, launchManifest } from './launch.ts';
|
||||
import { marketConfig } from './market/store.ts';
|
||||
@@ -7,15 +7,17 @@ export type LaunchCheck = { id: string; status: 'pass' | 'blocked' | 'unverified
|
||||
/** Read-only local assessment. Never opens a ledger, starts PoW, contacts peers, or sets approvals.
|
||||
* Configured approvals cannot resolve findings that require new code or independent evidence. */
|
||||
export function launchPreflight(env: NodeJS.ProcessEnv = process.env, now = Date.now()) {
|
||||
const checks: LaunchCheck[] = [{ id: 'network-selection', status: IS_MAINNET ? 'pass' : 'blocked',
|
||||
detail: IS_MAINNET ? 'Separate mainnet candidate selected.' : 'Testnet selected; this is not a production profile.' }];
|
||||
const checks: LaunchCheck[] = [{ id: 'network-selection', status: IS_MAINNET || IS_PILOT ? 'pass' : 'blocked',
|
||||
detail: IS_MAINNET ? 'Separate mainnet candidate selected.' : IS_PILOT
|
||||
? 'Private pilot chain selected; this is not a public or production profile.'
|
||||
: 'Testnet selected; this is not a production profile.' }];
|
||||
try {
|
||||
marketConfig(env);
|
||||
checks.push({ id: 'mock-payment-boundary', status: 'pass', detail: 'Only mock payments are supported; market configuration is valid.' });
|
||||
} catch {
|
||||
checks.push({ id: 'mock-payment-boundary', status: 'blocked', detail: 'Invalid market configuration or unsupported live payment mode. No secret values are included in this report.' });
|
||||
}
|
||||
if (IS_MAINNET) {
|
||||
if (IS_MAINNET || IS_PILOT) {
|
||||
try {
|
||||
assertLaunchAllowed(env, now);
|
||||
checks.push({ id: 'operator-startup-gates', status: 'pass', detail: 'Local startup gates satisfied; this does not establish production readiness or peer independence.' });
|
||||
|
||||
@@ -33,7 +33,7 @@ import { createMoneroDepositAddressRpc, loadMoneroObserverConfig } from '../mark
|
||||
import { loadMoneroMtlsTransport, loadMoneroMtlsTransportConfig } from '../market/monero-mtls-transport.ts';
|
||||
import { postgresConfig } from '../market/postgres-config.ts';
|
||||
import { validateMarketPolicy } from '../market/policy.ts';
|
||||
import { IS_MAINNET, PROFILE } from '../../shared/network.ts';
|
||||
import { IS_MAINNET, IS_PILOT, PROFILE } from '../../shared/network.ts';
|
||||
import { assertLaunchAllowed, launchManifest } from '../launch.ts';
|
||||
import { resourceConfig, RpcBudget, RpcError } from '../resources.ts';
|
||||
import { trustedProxies, operationsPort, startOperations } from '../operations.ts';
|
||||
@@ -353,7 +353,7 @@ app.use((err:Error & {status?:number},_req:express.Request,res:express.Response,
|
||||
});
|
||||
const port=Number(process.env.PORT??3001),host=process.env.HOST??'127.0.0.1';
|
||||
const server=app.listen(port,host,()=>{
|
||||
const a=server.address();console.log(`Wikideck RandomX ${IS_MAINNET?'mainnet candidate':'testnet'}: http://${host}:${typeof a==='object'&&a?a.port:port} · chain ${CHAIN_ID} · ${ledger.snapshot().blocks.length} blocks`);
|
||||
const a=server.address();console.log(`Wikideck RandomX ${IS_MAINNET?'mainnet candidate':IS_PILOT?'private pilot':'testnet'}: http://${host}:${typeof a==='object'&&a?a.port:port} · chain ${CHAIN_ID} · ${ledger.snapshot().blocks.length} blocks`);
|
||||
peers.start();
|
||||
});
|
||||
const operations=startOperations(opsPort,()=>({network:NETWORK,paymentMode:'mock',
|
||||
|
||||
Reference in New Issue
Block a user