First deposit integration slice
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 = 3;
|
||||
export const CUSTODY_PG_VERSION = 4;
|
||||
export const CUSTODY_WRITE_LOCK = '7140824361';
|
||||
export const CUSTODY_SCHEMA_V1 = `
|
||||
CREATE SCHEMA IF NOT EXISTS wk_custody;
|
||||
@@ -175,9 +175,32 @@ REVOKE ALL ON FUNCTION wk_custody.monero_deposit_allocations_immutable() FROM PU
|
||||
`;
|
||||
export const CUSTODY_SCHEMA_V3_DIGEST = createHash('sha256')
|
||||
.update(`${CUSTODY_SCHEMA_V1}\n-- custody migration v2 --\n${CUSTODY_MIGRATION_V2}\n-- custody migration v3 --\n${CUSTODY_MIGRATION_V3}`).digest('hex');
|
||||
export const CUSTODY_MIGRATION_V4 = `
|
||||
DO $$
|
||||
DECLARE old_constraint text;
|
||||
BEGIN
|
||||
SELECT conname INTO old_constraint FROM pg_constraint
|
||||
WHERE conrelid='wk_custody.monero_transfer_observations'::regclass AND contype='u'
|
||||
AND pg_get_constraintdef(oid)='UNIQUE (wallet_fingerprint, txid, account_index, address_index)';
|
||||
IF old_constraint IS NOT NULL THEN
|
||||
EXECUTE format('ALTER TABLE wk_custody.monero_transfer_observations DROP CONSTRAINT %I',old_constraint);
|
||||
END IF;
|
||||
END $$;
|
||||
ALTER TABLE wk_custody.monero_transfer_observations
|
||||
ADD COLUMN output_public_key text CHECK(output_public_key IS NULL OR output_public_key ~ '^[a-f0-9]{64}$'),
|
||||
ADD COLUMN global_output_index bigint CHECK(global_output_index IS NULL OR global_output_index>=0),
|
||||
ADD CONSTRAINT monero_observation_output_identity CHECK(
|
||||
(output_public_key IS NULL AND global_output_index IS NULL) OR
|
||||
(output_public_key IS NOT NULL AND global_output_index IS NOT NULL AND observation_id=(txid || ':' || output_public_key)));
|
||||
CREATE UNIQUE INDEX monero_observations_output_key
|
||||
ON wk_custody.monero_transfer_observations(wallet_fingerprint,output_public_key)
|
||||
WHERE output_public_key IS NOT NULL;
|
||||
`;
|
||||
export const CUSTODY_SCHEMA_V4_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}`).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_V2_DIGEST;
|
||||
export const CUSTODY_SCHEMA_DIGEST = CUSTODY_SCHEMA_V4_DIGEST;
|
||||
|
||||
/** Explicit operator migration; the HTTP runtime never creates or upgrades schema. */
|
||||
export async function migrateCustody(pool: Pool): Promise<void> {
|
||||
@@ -200,6 +223,11 @@ export async function migrateCustody(pool: Pool): Promise<void> {
|
||||
if (current === 2) {
|
||||
await c.query(CUSTODY_MIGRATION_V3);
|
||||
await c.query('INSERT INTO wk_custody.schema_versions VALUES(3,$1)', [CUSTODY_SCHEMA_V3_DIGEST]);
|
||||
current = 3;
|
||||
}
|
||||
if (current === 3) {
|
||||
await c.query(CUSTODY_MIGRATION_V4);
|
||||
await c.query('INSERT INTO wk_custody.schema_versions VALUES(4,$1)', [CUSTODY_SCHEMA_V4_DIGEST]);
|
||||
}
|
||||
if (current > CUSTODY_PG_VERSION) throw new Error('Custody PostgreSQL schema is newer than this application');
|
||||
await verifyCustodySchema(c);
|
||||
@@ -213,7 +241,7 @@ export async function verifyCustodySchema(c: PoolClient): Promise<void> {
|
||||
}
|
||||
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];
|
||||
const expected = [CUSTODY_SCHEMA_V1_DIGEST, CUSTODY_SCHEMA_V2_DIGEST, CUSTODY_SCHEMA_V3_DIGEST, CUSTODY_SCHEMA_V4_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