Bounded test succeeded; native RandomX miner accepted one block

This commit is contained in:
2026-10-22 21:25:39 -04:00
parent 176d1927a8
commit bd3d36a7e1
12 changed files with 607 additions and 20 deletions
+265
View File
@@ -0,0 +1,265 @@
import { createHash } from 'node:crypto';
import type { Pool, PoolClient } from 'pg';
import { z } from 'zod';
import { XMR_RPC_UINT64_MAX } from '../../shared/xmr-amount.ts';
import { CHAIN_ID } from '../testnet/consensus.ts';
import { IS_PILOT, NETWORK } from '../../shared/network.ts';
import { verifyCustodySchema } from './postgres-schema.ts';
import { pilotCustodyIdentityFromRow } from './pilot-custody-identity.ts';
import { validateXmrSubaddress } from './xmr.ts';
const HEX64 = z.string().regex(/^[a-f0-9]{64}$/);
const UUID = z.string().uuid();
const OBSERVATION_ID = /^[a-f0-9]{64}:[a-f0-9]{64}$/;
const UINT64 = /^(0|[1-9]\d{0,19})$/;
const MAX_EVENT_HISTORY = 256;
const MAX_BLOCK_UNLOCK = 500_000_000n;
export type PilotDepositReviewPolicy = {
minimumConfirmations: number;
maximumObservationAgeMs: number;
};
const subjectWithoutDigestSchema = z.object({
policyVersion: z.literal('pilot-monero-deposit-review-v1'),
preparationOnly: z.literal(true),
crediting: z.literal('disabled'),
marketNetwork: z.literal('wikideck-randomx-pilot-1'),
marketChainId: HEX64,
moneroNetwork: z.literal('mainnet'),
custodianId: UUID,
activationStatus: z.literal('identity-only'),
walletGenerationId: UUID,
walletFingerprint: HEX64,
allocationId: UUID,
beneficiary: HEX64,
accountIndex: z.number().int().nonnegative().max(0xffff_ffff).safe(),
addressIndex: z.number().int().nonnegative().max(0xffff_ffff).safe(),
moneroAddress: z.string().length(95),
observationId: z.string().regex(OBSERVATION_ID),
transactionId: HEX64,
outputPublicKey: HEX64,
amountAtomicXmr: z.string().regex(/^[1-9]\d{0,19}$/),
blockHeight: z.number().int().positive().safe(),
walletHeight: z.number().int().positive().safe(),
confirmations: z.number().int().positive().safe(),
minimumConfirmations: z.number().int().min(10).max(100_000).safe(),
unlockTime: z.string().regex(UINT64),
locked: z.literal(false),
doubleSpendSeen: z.literal(false),
currentlyPresent: z.literal(true),
globalOutputIndex: z.number().int().nonnegative().safe(),
observationDigest: HEX64,
scanId: UUID,
scanFromHeight: z.number().int().nonnegative().safe(),
scanThroughHeight: z.number().int().nonnegative().safe(),
observerScanHeight: z.number().int().nonnegative().safe(),
scanCompletedAt: z.number().int().nonnegative().safe(),
observerUpdatedAt: z.number().int().nonnegative().safe(),
lastObservedAt: z.number().int().nonnegative().safe(),
scanFreshnessMs: z.number().int().nonnegative().safe(),
maximumObservationAgeMs: z.number().int().min(10_000).max(15 * 60_000).safe(),
eventHistorySequence: z.number().int().nonnegative().safe(),
eventHistoryCount: z.number().int().positive().max(MAX_EVENT_HISTORY).safe(),
eventHistoryDigest: HEX64,
preparedAt: z.number().int().nonnegative().safe(),
}).strict();
export type PilotDepositReviewSubject = z.infer<typeof subjectWithoutDigestSchema> & { subjectDigest: string };
const reviewSubjectSchema = subjectWithoutDigestSchema.extend({ subjectDigest: HEX64 }).strict();
const inputSchema = z.object({
walletGenerationId: UUID,
observationId: z.string().regex(OBSERVATION_ID),
}).strict();
function digest(value: string): string {
return createHash('sha256').update(value).digest('hex');
}
function safeInteger(value: unknown, name: string, minimum = 0): number {
if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'bigint') {
throw new Error(`Invalid pilot review ${name}`);
}
const number = Number(value);
if (!Number.isSafeInteger(number) || number < minimum) throw new Error(`Invalid pilot review ${name}`);
return number;
}
function validatePolicy(policy: PilotDepositReviewPolicy): void {
if (!Number.isSafeInteger(policy.minimumConfirmations) || policy.minimumConfirmations < 10 ||
policy.minimumConfirmations > 100_000 || !Number.isSafeInteger(policy.maximumObservationAgeMs) ||
policy.maximumObservationAgeMs < 10_000 || policy.maximumObservationAgeMs > 15 * 60_000) {
throw new Error('Invalid pilot deposit review policy');
}
}
function assertUnlockMature(unlockTime: string, walletHeight: number, scanCompletedAt: number): void {
if (!UINT64.test(unlockTime)) throw new Error('Pilot deposit unlock time is malformed');
const unlock = BigInt(unlockTime);
if (unlock === 0n) return;
const mature = unlock < MAX_BLOCK_UNLOCK
? BigInt(walletHeight) >= unlock
: BigInt(Math.floor(scanCompletedAt / 1000)) >= unlock;
if (!mature) throw new Error('Pilot deposit output has a future unlock time');
}
function validateEvents(rows: Record<string, unknown>[], observationDigest: string) {
if (!rows.length || rows.length > MAX_EVENT_HISTORY) {
throw new Error('Pilot observation event history is missing or exceeds the review bound');
}
const events = rows.map(row => {
const sequence = safeInteger(row.sequence, 'event sequence');
const observedAt = safeInteger(row.observed_at, 'event timestamp');
const walletHeight = safeInteger(row.wallet_height, 'event wallet height');
const payloadDigest = HEX64.parse(row.payload_digest);
const eventType = z.enum(['seen', 'changed', 'reappeared', 'not-seen']).parse(row.event_type);
const scanId = UUID.parse(row.scan_id);
return { sequence, observedAt, walletHeight, payloadDigest, eventType, scanId };
});
if (events.some(event => event.eventType !== 'seen' || event.payloadDigest !== observationDigest)) {
throw new Error('Pilot observation history contains change, disappearance, or reappearance evidence and needs separate review');
}
const last = events.at(-1)!;
const historyDigest = digest(JSON.stringify(events.map(event => [event.sequence, event.eventType,
event.payloadDigest, event.walletHeight, event.observedAt, event.scanId])));
return { sequence: last.sequence, count: events.length, digest: historyDigest };
}
/**
* Build an operator-facing pilot deposit review snapshot from persisted observations only.
* This function is read-only and does not approve, stage, post, release, or credit funds.
*/
export async function preparePilotMoneroDepositReview(pool: Pool, inputValue: unknown,
policy: PilotDepositReviewPolicy, now = Date.now()): Promise<PilotDepositReviewSubject> {
if (!IS_PILOT || NETWORK !== 'wikideck-randomx-pilot-1') {
throw new Error('Pilot deposit review preparation requires the pilot profile');
}
const input = inputSchema.parse(inputValue);
validatePolicy(policy);
if (!Number.isSafeInteger(now) || now < 0) throw new Error('Invalid pilot review time');
const client: PoolClient = await pool.connect();
try {
await client.query('BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY');
await client.query("SET LOCAL statement_timeout='10s'; SET LOCAL lock_timeout='3s'; SET LOCAL idle_in_transaction_session_timeout='10s'");
await verifyCustodySchema(client);
const identityResult = await client.query('SELECT * FROM wk_custody.pilot_custody_identity WHERE singleton=1');
if (identityResult.rowCount !== 1) throw new Error('Pilot custody identity is not initialized');
const identity = pilotCustodyIdentityFromRow(identityResult.rows[0]);
if (identity.marketChainId !== CHAIN_ID || identity.marketNetwork !== NETWORK ||
identity.moneroNetwork !== 'mainnet' || identity.activationStatus !== 'identity-only') {
throw new Error('Pilot custody identity does not permit review preparation');
}
const observations = await client.query(`SELECT
o.wallet_generation_id::text,o.observation_id,o.allocation_id::text,o.classification,o.txid,o.monero_address,
o.amount_atomic_xmr::text AS amount_atomic_xmr,o.block_height::text AS block_height,
o.wallet_height::text AS wallet_height,o.confirmations::text AS confirmations,o.unlock_time,
o.account_index::text AS account_index,o.address_index::text AS address_index,o.output_public_key,
o.global_output_index::text AS global_output_index,o.locked,o.double_spend_seen,o.payload_digest,
o.currently_present,o.last_seen_scan_id::text AS scan_id,o.last_observed_at::text AS last_observed_at,
s.wallet_fingerprint,s.network,s.scan_height::text AS observer_scan_height,s.updated_at::text AS observer_updated_at,
sc.from_height::text AS scan_from_height,sc.through_height::text AS scan_through_height,
sc.completed_at::text AS scan_completed_at
FROM wk_custody.pilot_monero_observations o
JOIN wk_custody.pilot_monero_observer_state s USING(wallet_generation_id)
JOIN wk_custody.pilot_monero_observation_scans sc
ON sc.scan_id=o.last_seen_scan_id AND sc.wallet_generation_id=o.wallet_generation_id
WHERE o.wallet_generation_id=$1 AND o.observation_id=$2`, [input.walletGenerationId, input.observationId]);
if (observations.rowCount !== 1) throw new Error('Pilot deposit observation was not found for this wallet generation');
const row = observations.rows[0];
if (row.wallet_generation_id !== input.walletGenerationId || row.observation_id !== input.observationId ||
row.network !== identity.moneroNetwork || row.classification !== 'assigned' || row.allocation_id === null ||
row.currently_present !== true || row.double_spend_seen !== false || row.locked !== false) {
throw new Error('Pilot deposit observation is not an assigned, present, unlocked, non-double-spent output');
}
const txid = HEX64.parse(row.txid);
const outputPublicKey = HEX64.parse(row.output_public_key);
if (row.observation_id !== `${txid}:${outputPublicKey}`) throw new Error('Pilot observation ID does not match its output identity');
const amountAtomicXmr = z.string().regex(/^[1-9]\d{0,19}$/).parse(row.amount_atomic_xmr);
const amount = BigInt(amountAtomicXmr);
if (amount > XMR_RPC_UINT64_MAX) throw new Error('Pilot deposit amount exceeds the Monero RPC uint64 range');
const blockHeight = safeInteger(row.block_height, 'block height', 1);
const walletHeight = safeInteger(row.wallet_height, 'wallet height', 1);
const confirmations = safeInteger(row.confirmations, 'confirmation count', 1);
const observerScanHeight = safeInteger(row.observer_scan_height, 'observer scan height');
const scanFromHeight = safeInteger(row.scan_from_height, 'scan start height');
const scanThroughHeight = safeInteger(row.scan_through_height, 'scan end height');
const scanCompletedAt = safeInteger(row.scan_completed_at, 'scan completion time');
const observerUpdatedAt = safeInteger(row.observer_updated_at, 'observer update time');
const lastObservedAt = safeInteger(row.last_observed_at, 'last observation time');
const accountIndex = safeInteger(row.account_index, 'account index');
const addressIndex = safeInteger(row.address_index, 'address index');
const globalOutputIndex = safeInteger(row.global_output_index, 'global output index');
if (confirmations !== walletHeight - blockHeight + 1 || confirmations < policy.minimumConfirmations) {
throw new Error('Pilot deposit output is below the configured confirmation floor');
}
if (observerScanHeight < walletHeight || scanThroughHeight < walletHeight ||
scanFromHeight > blockHeight || scanThroughHeight < blockHeight || lastObservedAt !== scanCompletedAt ||
observerUpdatedAt < scanCompletedAt) {
throw new Error('Pilot observation scan is not caught up or its persisted scan context is inconsistent');
}
const scanFreshnessMs = now - observerUpdatedAt;
if (scanFreshnessMs < 0 || now - scanCompletedAt < 0 || now - lastObservedAt < 0 ||
scanFreshnessMs > policy.maximumObservationAgeMs || now - scanCompletedAt > policy.maximumObservationAgeMs ||
now - lastObservedAt > policy.maximumObservationAgeMs) {
throw new Error('Pilot Monero observation scan is stale or has a future timestamp');
}
assertUnlockMature(row.unlock_time, walletHeight, scanCompletedAt);
const allocations = await client.query(`SELECT allocation_id::text,custodian_id::text,market_network,market_chain_id,
monero_network,beneficiary,wallet_generation_id::text,wallet_fingerprint,account_index::text AS account_index,
address_index::text AS address_index,status,monero_address
FROM wk_custody.pilot_monero_deposit_reservations WHERE allocation_id=$1`, [row.allocation_id]);
if (allocations.rowCount !== 1) throw new Error('Pilot assigned output has no unique durable reservation');
const allocation = allocations.rows[0];
const beneficiary = HEX64.parse(allocation.beneficiary);
if (allocation.custodian_id !== identity.custodianId || allocation.market_network !== identity.marketNetwork ||
allocation.market_chain_id !== identity.marketChainId || allocation.monero_network !== identity.moneroNetwork ||
allocation.wallet_generation_id !== input.walletGenerationId || allocation.wallet_fingerprint !== row.wallet_fingerprint ||
safeInteger(allocation.account_index, 'reserved account index') !== accountIndex ||
safeInteger(allocation.address_index, 'reserved address index') !== addressIndex ||
allocation.status !== 'registered' || allocation.monero_address !== row.monero_address) {
throw new Error('Pilot output does not exactly match its immutable registered reservation and identity');
}
const moneroAddress = await validateXmrSubaddress(z.string().length(95).parse(row.monero_address));
const walletFingerprint = HEX64.parse(row.wallet_fingerprint);
const observationDigest = HEX64.parse(row.payload_digest);
const scanId = UUID.parse(row.scan_id);
const history = await client.query(`SELECT sequence::text,event_type,payload_digest,wallet_height::text AS wallet_height,
observed_at::text AS observed_at,scan_id::text
FROM wk_custody.pilot_monero_observation_events
WHERE wallet_generation_id=$1 AND observation_id=$2 ORDER BY sequence LIMIT $3`,
[input.walletGenerationId, input.observationId, MAX_EVENT_HISTORY + 1]);
if (history.rows.length > MAX_EVENT_HISTORY) throw new Error('Pilot observation event history exceeds the review bound');
const eventHistory = validateEvents(history.rows, observationDigest);
const unsigned = subjectWithoutDigestSchema.parse({
policyVersion: 'pilot-monero-deposit-review-v1', preparationOnly: true, crediting: 'disabled',
marketNetwork: identity.marketNetwork, marketChainId: identity.marketChainId, moneroNetwork: identity.moneroNetwork,
custodianId: identity.custodianId, activationStatus: identity.activationStatus,
walletGenerationId: input.walletGenerationId, walletFingerprint, allocationId: allocation.allocation_id,
beneficiary, accountIndex, addressIndex, moneroAddress, observationId: input.observationId,
transactionId: txid, outputPublicKey, amountAtomicXmr, blockHeight, walletHeight, confirmations,
minimumConfirmations: policy.minimumConfirmations, unlockTime: z.string().regex(UINT64).parse(row.unlock_time),
locked: false, doubleSpendSeen: false, currentlyPresent: true, globalOutputIndex, observationDigest,
scanId, scanFromHeight, scanThroughHeight, observerScanHeight, scanCompletedAt, observerUpdatedAt,
lastObservedAt, scanFreshnessMs, maximumObservationAgeMs: policy.maximumObservationAgeMs,
eventHistorySequence: eventHistory.sequence, eventHistoryCount: eventHistory.count,
eventHistoryDigest: eventHistory.digest, preparedAt: now,
});
const subject = reviewSubjectSchema.parse({ ...unsigned, subjectDigest: digest(JSON.stringify(unsigned)) });
await client.query('COMMIT');
return subject;
} catch (error) {
await client.query('ROLLBACK').catch(() => {});
throw error;
} finally {
client.release();
}
}