1+ BEGIN ;
2+
3+ -- Enforce that tenants has zero or one row.
4+ DO $$
5+ BEGIN
6+ IF (SELECT COUNT (* ) FROM tenants) > 1 THEN
7+ RAISE EXCEPTION ' Expected zero or one row in tenants table, but found %' , (SELECT COUNT (* ) FROM tenants);
8+ END IF;
9+ END $$;
10+
11+ -- ============================================================
12+ -- New tables: keys, crs, host_chains
13+ -- ============================================================
14+
15+ -- keys: replaces tenants, keeping only key material.
16+ -- key_id contains the key ID from the server key metadata (that is used in ciphertext metadata).
17+ -- key_id_gw contains the key ID from the GW event (that could be different from key_id).
18+ CREATE TABLE keys (
19+ sequence_number BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
20+ key_id_gw BYTEA NOT NULL ,
21+ key_id BYTEA NOT NULL ,
22+ pks_key BYTEA NOT NULL ,
23+ sks_key BYTEA NOT NULL ,
24+ cks_key BYTEA ,
25+ sns_pk OID ,
26+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
27+ CONSTRAINT unique_key_id_gw UNIQUE (key_id_gw),
28+ CONSTRAINT unique_key_id UNIQUE (key_id)
29+ );
30+
31+ INSERT INTO keys (key_id_gw, key_id, pks_key, sks_key, cks_key, sns_pk)
32+ SELECT key_id, ' ' ::BYTEA , pks_key, sks_key, cks_key, sns_pk FROM tenants;
33+
34+ -- crs: split out from tenants.
35+ CREATE TABLE crs (
36+ sequence_number BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
37+ crs_id BYTEA NOT NULL ,
38+ crs BYTEA NOT NULL ,
39+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
40+ CONSTRAINT unique_crs_id UNIQUE (crs_id)
41+ );
42+
43+ -- Use an empty ID for the existing CRS.
44+ INSERT INTO crs (crs_id, crs)
45+ SELECT ' ' ::BYTEA , public_params FROM tenants;
46+
47+ -- host_chains: split out from tenants.
48+ CREATE TABLE host_chains (
49+ chain_id BIGINT PRIMARY KEY NOT NULL CHECK (chain_id >= 0 ),
50+ name TEXT NOT NULL ,
51+ acl_contract_address TEXT NOT NULL ,
52+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
53+ );
54+
55+ INSERT INTO host_chains (chain_id, name, acl_contract_address)
56+ SELECT chain_id, ' ethereum' , acl_contract_address FROM tenants;
57+
58+ -- ============================================================
59+ -- Existing tables: add new columns only
60+ -- ============================================================
61+
62+ -- host_chain_blocks_valid: widen chain_id from INT to BIGINT to match the rest of the schema.
63+ ALTER TABLE host_chain_blocks_valid ALTER COLUMN chain_id TYPE BIGINT ;
64+ ALTER TABLE host_chain_blocks_valid ADD CONSTRAINT host_chain_blocks_valid_chain_id_check CHECK (chain_id >= 0 );
65+
66+ -- Set tenant_id default to the existing tenant's ID (or 0 if empty) so new code
67+ -- can insert without specifying tenant_id and rollback to old code sees real IDs.
68+ DO $$
69+ DECLARE
70+ tid INT ;
71+ BEGIN
72+ SELECT COALESCE((SELECT tenant_id FROM tenants LIMIT 1 ), 0 ) INTO tid;
73+ EXECUTE format(' ALTER TABLE allowed_handles ALTER COLUMN tenant_id SET DEFAULT %s' , tid);
74+ EXECUTE format(' ALTER TABLE input_blobs ALTER COLUMN tenant_id SET DEFAULT %s' , tid);
75+ EXECUTE format(' ALTER TABLE ciphertext_digest ALTER COLUMN tenant_id SET DEFAULT %s' , tid);
76+ EXECUTE format(' ALTER TABLE ciphertexts ALTER COLUMN tenant_id SET DEFAULT %s' , tid);
77+ EXECUTE format(' ALTER TABLE ciphertexts128 ALTER COLUMN tenant_id SET DEFAULT %s' , tid);
78+ EXECUTE format(' ALTER TABLE computations ALTER COLUMN tenant_id SET DEFAULT %s' , tid);
79+ EXECUTE format(' ALTER TABLE pbs_computations ALTER COLUMN tenant_id SET DEFAULT %s' , tid);
80+ END $$;
81+
82+ -- Add unique indices for new code that queries without tenant_id.
83+ CREATE UNIQUE INDEX idx_allowed_handles_no_tenant ON allowed_handles (handle, account_address);
84+ CREATE UNIQUE INDEX idx_input_blobs_no_tenant ON input_blobs (blob_hash);
85+ CREATE UNIQUE INDEX idx_ciphertext_digest_no_tenant ON ciphertext_digest (handle);
86+ CREATE UNIQUE INDEX idx_ciphertexts_no_tenant ON ciphertexts (handle, ciphertext_version);
87+ CREATE UNIQUE INDEX idx_ciphertexts128_no_tenant ON ciphertexts128 (handle);
88+ CREATE UNIQUE INDEX idx_computations_no_tenant ON computations (output_handle, transaction_id);
89+ CREATE UNIQUE INDEX idx_pbs_computations_no_tenant ON pbs_computations (handle);
90+
91+ -- ciphertext_digest: add host_chain_id and key_id_gw.
92+ ALTER TABLE ciphertext_digest ADD COLUMN host_chain_id BIGINT DEFAULT NULL ;
93+ UPDATE ciphertext_digest SET host_chain_id = (SELECT chain_id FROM tenants WHERE tenant_id = ciphertext_digest .tenant_id );
94+ ALTER TABLE ciphertext_digest ALTER COLUMN host_chain_id SET NOT NULL ;
95+ ALTER TABLE ciphertext_digest ADD CONSTRAINT ciphertext_digest_host_chain_id_positive CHECK (host_chain_id >= 0 );
96+ ALTER TABLE ciphertext_digest ADD COLUMN key_id_gw BYTEA DEFAULT NULL ;
97+ UPDATE ciphertext_digest SET key_id_gw = (SELECT key_id FROM tenants LIMIT 1 );
98+ ALTER TABLE ciphertext_digest ALTER COLUMN key_id_gw SET NOT NULL ;
99+
100+ -- computations: add host_chain_id.
101+ -- TODO: host_chain_id can be part of an index, but will be done in the future where we want workers per host chain
102+ ALTER TABLE computations ADD COLUMN host_chain_id BIGINT DEFAULT NULL ;
103+ UPDATE computations SET host_chain_id = (SELECT chain_id FROM tenants WHERE tenant_id = computations .tenant_id );
104+ ALTER TABLE computations ALTER COLUMN host_chain_id SET NOT NULL ;
105+ ALTER TABLE computations ADD CONSTRAINT computations_host_chain_id_positive CHECK (host_chain_id >= 0 );
106+
107+ -- pbs_computations: add host_chain_id, keep tenant_id.
108+ -- TODO: host_chain_id can be part of an index, but will be done in the future where we want workers per host chain
109+ ALTER TABLE pbs_computations ADD COLUMN host_chain_id BIGINT DEFAULT NULL ;
110+ UPDATE pbs_computations SET host_chain_id = (SELECT chain_id FROM tenants WHERE tenant_id = pbs_computations .tenant_id );
111+ ALTER TABLE pbs_computations ALTER COLUMN host_chain_id SET NOT NULL ;
112+ ALTER TABLE pbs_computations ADD CONSTRAINT pbs_computations_host_chain_id_positive CHECK (host_chain_id >= 0 );
113+
114+ COMMIT ;
0 commit comments