diff --git a/server/crates/arbiter-server/migrations/2026-02-14-171124-0000_init/up.sql b/server/crates/arbiter-server/migrations/2026-02-14-171124-0000_init/up.sql index cddc2dc..f9aa593 100644 --- a/server/crates/arbiter-server/migrations/2026-02-14-171124-0000_init/up.sql +++ b/server/crates/arbiter-server/migrations/2026-02-14-171124-0000_init/up.sql @@ -53,7 +53,7 @@ create table if not exists operator_identity ( create unique index if not exists uniq_operator_identity_public_key on operator_identity (public_key); create table if not exists operator ( - id integer primary key references operator_identity(id) on delete restrict, -- same id as operator_identity + id integer not null primary key references operator_identity(id) on delete restrict, -- same id as operator_identity share blob not null, share_nonce blob not null, diff --git a/server/crates/arbiter-server/src/db/custody.rs b/server/crates/arbiter-server/src/db/custody.rs index c4b8454..3d5efa1 100644 --- a/server/crates/arbiter-server/src/db/custody.rs +++ b/server/crates/arbiter-server/src/db/custody.rs @@ -1,18 +1,13 @@ //! Storage for Shamir custody material: the reconstruction threshold and the //! per-operator encrypted shares of the vault seal key. -//! -//! Every query lives here so that the actors above hold no Diesel code of their -//! own. The functions borrow the caller's connection instead of taking one from -//! the pool, which lets the vault write custody material inside the same -//! transaction that stores the root key. use std::collections::HashMap; -use diesel::{ExpressionMethods as _, QueryDsl, sqlite::Sqlite}; +use diesel::{ExpressionMethods as _, QueryDsl, SelectableHelper as _, sqlite::Sqlite}; use diesel_async::{AsyncConnection, RunQueryDsl}; use crate::db::{ - models::{OperatorId, SqliteTimestamp}, + models::{Operator, OperatorId, SqliteTimestamp}, schema, }; @@ -55,7 +50,7 @@ pub async fn write_record( for (operator_id, share) in &record.shares { diesel::replace_into(schema::operator::table) .values(( - schema::operator::id.eq(Some(*operator_id)), + schema::operator::id.eq(*operator_id), schema::operator::share.eq(&share.ciphertext), schema::operator::share_nonce.eq(&share.nonce), schema::operator::share_salt.eq(&share.salt), @@ -90,40 +85,28 @@ pub async fn threshold(conn: &mut impl AsyncConnection) -> Res .ok_or(Error::BrokenThreshold) } -/// One row of the share query: operator id, ciphertext, nonce, salt. -type ShareRow = (Option, Vec, Vec, Vec); - /// Load the shares of `operators` in one query, in the order requested. pub async fn shares( conn: &mut impl AsyncConnection, operators: &[OperatorId], ) -> Result, Error> { - let wanted: Vec> = operators.iter().copied().map(Some).collect(); - - let rows: Vec = schema::operator::table - .filter(schema::operator::id.eq_any(wanted)) - .select(( - schema::operator::id, - schema::operator::share, - schema::operator::share_nonce, - schema::operator::share_salt, - )) + let rows: Vec = schema::operator::table + .filter(schema::operator::id.eq_any(operators)) + .select(Operator::as_select()) .load(conn) .await?; let mut found: HashMap = rows .into_iter() - .filter_map(|(id, ciphertext, nonce, salt)| { - id.map(|id| { - ( - id, - EncryptedShare { - ciphertext, - nonce, - salt, - }, - ) - }) + .map(|row| { + ( + row.id, + EncryptedShare { + ciphertext: row.share, + nonce: row.share_nonce, + salt: row.share_salt, + }, + ) }) .collect(); diff --git a/server/crates/arbiter-server/src/db/models.rs b/server/crates/arbiter-server/src/db/models.rs index ba04ca3..f4c09c2 100644 --- a/server/crates/arbiter-server/src/db/models.rs +++ b/server/crates/arbiter-server/src/db/models.rs @@ -292,7 +292,7 @@ pub struct OperatorClient { pub updated_at: SqliteTimestamp, } -#[derive(Queryable, Debug)] +#[derive(Queryable, Debug, Selectable)] #[diesel(table_name = schema::operator, check_for_backend(Sqlite))] pub struct Operator { pub id: OperatorId, diff --git a/server/crates/arbiter-server/src/db/schema.rs b/server/crates/arbiter-server/src/db/schema.rs index 2772360..4f5902b 100644 --- a/server/crates/arbiter-server/src/db/schema.rs +++ b/server/crates/arbiter-server/src/db/schema.rs @@ -155,7 +155,7 @@ diesel::table! { diesel::table! { operator (id) { - id -> Nullable, + id -> Integer, share -> Binary, share_nonce -> Binary, share_salt -> Binary,