Separate identity-only pilot custody foundation
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { createHash } from 'node:crypto';
|
||||
import type { Pool, PoolClient } from 'pg';
|
||||
|
||||
export const CUSTODY_PG_VERSION = 9;
|
||||
export const CUSTODY_PG_VERSION = 10;
|
||||
export const CUSTODY_WRITE_LOCK = '7140824361';
|
||||
export const MONERO_OBSERVER_WORKER_LOCK = '7140824362';
|
||||
export const CUSTODY_SCHEMA_V1 = `
|
||||
@@ -372,9 +372,32 @@ REVOKE ALL ON FUNCTION wk_custody.monero_withdrawal_intents_immutable() FROM PUB
|
||||
`;
|
||||
export const CUSTODY_SCHEMA_V9_DIGEST = createHash('sha256')
|
||||
.update(`${CUSTODY_SCHEMA_V1}\n-- custody migration v2 --\n${CUSTODY_MIGRATION_V2}\n-- custody migration v3 --\n${CUSTODY_MIGRATION_V3}\n-- custody migration v4 --\n${CUSTODY_MIGRATION_V4}\n-- custody migration v5 --\n${CUSTODY_MIGRATION_V5}\n-- custody migration v6 --\n${CUSTODY_MIGRATION_V6}\n-- custody migration v7 --\n${CUSTODY_MIGRATION_V7}\n-- custody migration v8 --\n${CUSTODY_MIGRATION_V8}\n-- custody migration v9 --\n${CUSTODY_MIGRATION_V9}`).digest('hex');
|
||||
export const CUSTODY_MIGRATION_V10 = `
|
||||
CREATE TABLE wk_custody.pilot_custody_identity(
|
||||
singleton smallint PRIMARY KEY DEFAULT 1 CHECK(singleton=1),
|
||||
version integer NOT NULL CHECK(version=1),
|
||||
mode text NOT NULL CHECK(mode='pilot-custody'),
|
||||
policy text NOT NULL CHECK(policy='pilot-custody-v1'),
|
||||
market_network text NOT NULL CHECK(market_network='wikideck-randomx-pilot-1'),
|
||||
market_chain_id text NOT NULL CHECK(market_chain_id ~ '^[a-f0-9]{64}$'),
|
||||
monero_network text NOT NULL CHECK(monero_network='mainnet'),
|
||||
custodian_id uuid NOT NULL UNIQUE,
|
||||
activation_status text NOT NULL CHECK(activation_status='identity-only'),
|
||||
initialized_at bigint NOT NULL CHECK(initialized_at>=0)
|
||||
);
|
||||
CREATE FUNCTION wk_custody.pilot_custody_identity_immutable() RETURNS trigger LANGUAGE plpgsql
|
||||
SET search_path=wk_custody,pg_catalog AS $$
|
||||
BEGIN RAISE EXCEPTION 'Pilot custody identity is immutable'; END $$;
|
||||
CREATE TRIGGER pilot_custody_identity_immutable BEFORE UPDATE OR DELETE ON wk_custody.pilot_custody_identity
|
||||
FOR EACH ROW EXECUTE FUNCTION wk_custody.pilot_custody_identity_immutable();
|
||||
REVOKE ALL ON wk_custody.pilot_custody_identity FROM PUBLIC;
|
||||
REVOKE ALL ON FUNCTION wk_custody.pilot_custody_identity_immutable() FROM PUBLIC;
|
||||
`;
|
||||
export const CUSTODY_SCHEMA_V10_DIGEST = createHash('sha256')
|
||||
.update(`${CUSTODY_SCHEMA_V1}\n-- custody migration v2 --\n${CUSTODY_MIGRATION_V2}\n-- custody migration v3 --\n${CUSTODY_MIGRATION_V3}\n-- custody migration v4 --\n${CUSTODY_MIGRATION_V4}\n-- custody migration v5 --\n${CUSTODY_MIGRATION_V5}\n-- custody migration v6 --\n${CUSTODY_MIGRATION_V6}\n-- custody migration v7 --\n${CUSTODY_MIGRATION_V7}\n-- custody migration v8 --\n${CUSTODY_MIGRATION_V8}\n-- custody migration v9 --\n${CUSTODY_MIGRATION_V9}\n-- custody migration v10 --\n${CUSTODY_MIGRATION_V10}`).digest('hex');
|
||||
/** Retained alias for callers that need the initial schema definition in disposable fixtures. */
|
||||
export const CUSTODY_SCHEMA = CUSTODY_SCHEMA_V1;
|
||||
export const CUSTODY_SCHEMA_DIGEST = CUSTODY_SCHEMA_V9_DIGEST;
|
||||
export const CUSTODY_SCHEMA_DIGEST = CUSTODY_SCHEMA_V10_DIGEST;
|
||||
|
||||
/** Explicit operator migration; the HTTP runtime never creates or upgrades schema. */
|
||||
export async function migrateCustody(pool: Pool): Promise<void> {
|
||||
@@ -427,6 +450,11 @@ export async function migrateCustody(pool: Pool): Promise<void> {
|
||||
if (current === 8) {
|
||||
await c.query(CUSTODY_MIGRATION_V9);
|
||||
await c.query('INSERT INTO wk_custody.schema_versions VALUES(9,$1)', [CUSTODY_SCHEMA_V9_DIGEST]);
|
||||
current = 9;
|
||||
}
|
||||
if (current === 9) {
|
||||
await c.query(CUSTODY_MIGRATION_V10);
|
||||
await c.query('INSERT INTO wk_custody.schema_versions VALUES(10,$1)', [CUSTODY_SCHEMA_V10_DIGEST]);
|
||||
}
|
||||
if (current > CUSTODY_PG_VERSION) throw new Error('Custody PostgreSQL schema is newer than this application');
|
||||
await verifyCustodySchema(c);
|
||||
@@ -442,7 +470,7 @@ async function verifyCustodySchemaHistory(c: PoolClient): Promise<number> {
|
||||
const rows = await c.query('SELECT version,digest FROM wk_custody.schema_versions ORDER BY version');
|
||||
const expected = [CUSTODY_SCHEMA_V1_DIGEST, CUSTODY_SCHEMA_V2_DIGEST, CUSTODY_SCHEMA_V3_DIGEST,
|
||||
CUSTODY_SCHEMA_V4_DIGEST, CUSTODY_SCHEMA_V5_DIGEST, CUSTODY_SCHEMA_V6_DIGEST, CUSTODY_SCHEMA_V7_DIGEST,
|
||||
CUSTODY_SCHEMA_V8_DIGEST, CUSTODY_SCHEMA_V9_DIGEST];
|
||||
CUSTODY_SCHEMA_V8_DIGEST, CUSTODY_SCHEMA_V9_DIGEST, CUSTODY_SCHEMA_V10_DIGEST];
|
||||
if (!rows.rowCount || rows.rowCount > expected.length || rows.rows.some((row, index) =>
|
||||
Number(row.version) !== index + 1 || row.digest !== expected[index])) {
|
||||
throw new Error('Custody PostgreSQL schema version/digest history mismatch; explicit migration required');
|
||||
|
||||
Reference in New Issue
Block a user