rhi

Coordinated trade for connected markets
git clone https://radroots.dev/git/rhi.git
Log | Files | Refs | README | LICENSE

presence_desired.rs (38205B)


      1 //! Deterministic durable desired state for RHI service presence.
      2 
      3 use core::fmt;
      4 use std::error::Error;
      5 
      6 use radroots_service_sqlite::{
      7     ServiceSqliteTransaction, ServiceSqliteTransactionError, ServiceSqliteTransactionErrorKind,
      8 };
      9 use serde_json::Value;
     10 use sha2::{Digest, Sha256};
     11 use sqlx::Row;
     12 
     13 use crate::{
     14     RhiConfigDocumentV1, RhiDesiredPresenceRepository, RhiStateHostMode,
     15     state_metadata::normalized_config_digest,
     16 };
     17 
     18 /// Exact version of the deterministic presence desired-state contract.
     19 pub const RHI_PRESENCE_DESIRED_CONTRACT_VERSION: u32 = 1;
     20 
     21 /// Maximum number of configured relay targets in one desired state.
     22 pub const RHI_PRESENCE_DESIRED_MAX_TARGETS: usize = 32;
     23 
     24 const TARGET_SET_DOMAIN: &[u8] = b"radroots.rhi.presence_target_set.v1\0";
     25 const DESIRED_STATE_DOMAIN: &[u8] = b"radroots.rhi.presence_desired_state.v1\0";
     26 
     27 const READ_CURRENT_CONFIG_SQL: &str = r#"SELECT
     28     CASE WHEN typeof(normalized_config_sha256) = 'blob'
     29             AND length(normalized_config_sha256) = 32
     30         THEN normalized_config_sha256 ELSE NULL END AS normalized_config_sha256,
     31     length(CAST(service_public_key AS BLOB)) AS service_public_key_bytes,
     32     substr(service_public_key, 1, 65) AS service_public_key
     33 FROM rhi_config_bindings
     34 ORDER BY generation DESC
     35 LIMIT 1"#;
     36 
     37 const READ_DESIRED_SQL: &str = r#"SELECT singleton, generation,
     38     enabled, profile, application_handler,
     39     CASE WHEN typeof(target_set_sha256) = 'blob' AND length(target_set_sha256) = 32
     40         THEN target_set_sha256 ELSE NULL END AS target_set_sha256,
     41     target_count, required_target_count, queue_capacity,
     42     CASE WHEN typeof(desired_sha256) = 'blob' AND length(desired_sha256) = 32
     43         THEN desired_sha256 ELSE NULL END AS desired_sha256
     44 FROM presence_desired_state
     45 LIMIT 2"#;
     46 
     47 const INSERT_DESIRED_SQL: &str = r#"INSERT INTO presence_desired_state (
     48     singleton, generation, enabled, profile, application_handler,
     49     target_set_sha256, target_count, required_target_count,
     50     queue_capacity, desired_sha256
     51 ) VALUES (1, 1, ?, ?, ?, ?, ?, ?, ?, ?)"#;
     52 
     53 const UPDATE_DESIRED_SQL: &str = r#"UPDATE presence_desired_state
     54 SET generation = generation + 1,
     55     enabled = ?, profile = ?, application_handler = ?,
     56     target_set_sha256 = ?, target_count = ?, required_target_count = ?,
     57     queue_capacity = ?, desired_sha256 = ?
     58 WHERE singleton = 1 AND generation = ? AND desired_sha256 = ?"#;
     59 
     60 /// Closed configured presence posture.
     61 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
     62 pub enum RhiPresenceDesiredMode {
     63     Disabled,
     64     Enabled,
     65 }
     66 
     67 impl RhiPresenceDesiredMode {
     68     /// Returns the exact machine-contract spelling.
     69     #[must_use]
     70     pub const fn code(self) -> &'static str {
     71         match self {
     72             Self::Disabled => "disabled",
     73             Self::Enabled => "enabled",
     74         }
     75     }
     76 }
     77 
     78 /// Closed ordered inventory of presence documents selected by configuration.
     79 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
     80 pub enum RhiPresenceDocumentKind {
     81     ServiceProfile,
     82     ApplicationHandler,
     83 }
     84 
     85 impl RhiPresenceDocumentKind {
     86     /// Returns the exact machine-contract spelling.
     87     #[must_use]
     88     pub const fn code(self) -> &'static str {
     89         match self {
     90             Self::ServiceProfile => "service_profile",
     91             Self::ApplicationHandler => "application_handler",
     92         }
     93     }
     94 }
     95 
     96 /// One immutable presence relay target derived from the admitted configuration.
     97 #[derive(Clone, PartialEq, Eq, Hash)]
     98 pub struct RhiPresenceTarget {
     99     ordinal: u8,
    100     relay_id: Box<str>,
    101     required: bool,
    102 }
    103 
    104 impl RhiPresenceTarget {
    105     /// Returns the stable zero-based target position.
    106     #[must_use]
    107     pub const fn ordinal(&self) -> u8 {
    108         self.ordinal
    109     }
    110 
    111     /// Returns the validated stable relay identifier.
    112     #[must_use]
    113     pub fn relay_id(&self) -> &str {
    114         &self.relay_id
    115     }
    116 
    117     /// Returns whether this relay is required by the admitted relay authority.
    118     #[must_use]
    119     pub const fn required(&self) -> bool {
    120         self.required
    121     }
    122 }
    123 
    124 impl fmt::Debug for RhiPresenceTarget {
    125     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    126         formatter
    127             .debug_struct("RhiPresenceTarget")
    128             .field("ordinal", &self.ordinal)
    129             .field("relay_id", &"[redacted]")
    130             .field("required", &self.required)
    131             .finish()
    132     }
    133 }
    134 
    135 /// Sealed deterministic presence authority derived from one admitted config.
    136 ///
    137 /// This value contains desired document kinds and stable relay authority only.
    138 /// It contains no rendered event, signature, delivery attempt, time, entropy,
    139 /// connection, or retry state.
    140 ///
    141 /// ```compile_fail
    142 /// use rhi::RhiPresenceDesiredAuthority;
    143 ///
    144 /// let _forged = RhiPresenceDesiredAuthority { mode: todo!() };
    145 /// ```
    146 #[derive(Clone, PartialEq, Eq)]
    147 pub struct RhiPresenceDesiredAuthority {
    148     configuration_sha256: [u8; 32],
    149     service_public_key: Box<str>,
    150     mode: RhiPresenceDesiredMode,
    151     document_kinds: Box<[RhiPresenceDocumentKind]>,
    152     targets: Box<[RhiPresenceTarget]>,
    153     queue_capacity: u32,
    154     target_set_sha256: [u8; 32],
    155     desired_sha256: [u8; 32],
    156 }
    157 
    158 impl RhiPresenceDesiredAuthority {
    159     /// Derives the only presence desired-state authority from one admitted config.
    160     pub fn from_config(config: &RhiConfigDocumentV1) -> Result<Self, RhiPresenceDesiredError> {
    161         derive_authority(config.normalized(), config.profile())
    162     }
    163 
    164     /// Returns the explicit configured posture.
    165     #[must_use]
    166     pub const fn mode(&self) -> RhiPresenceDesiredMode {
    167         self.mode
    168     }
    169 
    170     /// Returns the exact ordered desired-document inventory.
    171     #[must_use]
    172     pub fn document_kinds(&self) -> &[RhiPresenceDocumentKind] {
    173         &self.document_kinds
    174     }
    175 
    176     /// Returns the exact ordered presence target inventory.
    177     #[must_use]
    178     pub fn targets(&self) -> &[RhiPresenceTarget] {
    179         &self.targets
    180     }
    181 
    182     /// Returns the configured presence work-queue capacity, or zero when disabled.
    183     #[must_use]
    184     pub const fn queue_capacity(&self) -> u32 {
    185         self.queue_capacity
    186     }
    187 
    188     /// Returns the domain-separated exact target-set identity.
    189     #[must_use]
    190     pub const fn target_set_sha256(&self) -> &[u8; 32] {
    191         &self.target_set_sha256
    192     }
    193 
    194     /// Returns the domain-separated semantic desired-state identity.
    195     #[must_use]
    196     pub const fn desired_sha256(&self) -> &[u8; 32] {
    197         &self.desired_sha256
    198     }
    199 
    200     pub(crate) fn service_public_key(&self) -> &str {
    201         &self.service_public_key
    202     }
    203 }
    204 
    205 impl fmt::Debug for RhiPresenceDesiredAuthority {
    206     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    207         formatter
    208             .debug_struct("RhiPresenceDesiredAuthority")
    209             .field("mode", &self.mode)
    210             .field("document_count", &self.document_kinds.len())
    211             .field("target_count", &self.targets.len())
    212             .field("queue_capacity", &self.queue_capacity)
    213             .finish_non_exhaustive()
    214     }
    215 }
    216 
    217 /// Independently re-derives and validates one desired-state authority.
    218 pub fn validate_rhi_presence_desired_authority(
    219     config: &RhiConfigDocumentV1,
    220     authority: &RhiPresenceDesiredAuthority,
    221 ) -> Result<(), RhiPresenceDesiredError> {
    222     let expected = RhiPresenceDesiredAuthority::from_config(config)?;
    223     (expected == *authority)
    224         .then_some(())
    225         .ok_or_else(|| failure(RhiPresenceDesiredErrorKind::Binding))
    226 }
    227 
    228 /// One validated durable desired-state snapshot.
    229 #[derive(Clone, Copy, PartialEq, Eq)]
    230 pub struct RhiPresenceDesiredState {
    231     generation: u64,
    232     mode: RhiPresenceDesiredMode,
    233     profile: bool,
    234     application_handler: bool,
    235     target_set_sha256: [u8; 32],
    236     target_count: u8,
    237     required_target_count: u8,
    238     queue_capacity: u32,
    239     desired_sha256: [u8; 32],
    240 }
    241 
    242 impl RhiPresenceDesiredState {
    243     /// Returns the monotonically committed desired-state generation.
    244     #[must_use]
    245     pub const fn generation(self) -> u64 {
    246         self.generation
    247     }
    248 
    249     /// Returns the configured desired-state posture.
    250     #[must_use]
    251     pub const fn mode(self) -> RhiPresenceDesiredMode {
    252         self.mode
    253     }
    254 
    255     /// Returns whether the service-profile document is desired.
    256     #[must_use]
    257     pub const fn profile(self) -> bool {
    258         self.profile
    259     }
    260 
    261     /// Returns whether the application-handler document is desired.
    262     #[must_use]
    263     pub const fn application_handler(self) -> bool {
    264         self.application_handler
    265     }
    266 
    267     /// Returns the target-set identity without exposing relay endpoints.
    268     #[must_use]
    269     pub const fn target_set_sha256(&self) -> &[u8; 32] {
    270         &self.target_set_sha256
    271     }
    272 
    273     /// Returns the total configured target count.
    274     #[must_use]
    275     pub const fn target_count(self) -> u8 {
    276         self.target_count
    277     }
    278 
    279     /// Returns the number of configured required targets.
    280     #[must_use]
    281     pub const fn required_target_count(self) -> u8 {
    282         self.required_target_count
    283     }
    284 
    285     /// Returns the configured presence queue bound, or zero when disabled.
    286     #[must_use]
    287     pub const fn queue_capacity(self) -> u32 {
    288         self.queue_capacity
    289     }
    290 
    291     /// Returns the semantic desired-state identity.
    292     #[must_use]
    293     pub const fn desired_sha256(&self) -> &[u8; 32] {
    294         &self.desired_sha256
    295     }
    296 }
    297 
    298 impl fmt::Debug for RhiPresenceDesiredState {
    299     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    300         formatter
    301             .debug_struct("RhiPresenceDesiredState")
    302             .field("generation", &self.generation)
    303             .field("mode", &self.mode)
    304             .field("profile", &self.profile)
    305             .field("application_handler", &self.application_handler)
    306             .field("target_count", &self.target_count)
    307             .field("required_target_count", &self.required_target_count)
    308             .field("queue_capacity", &self.queue_capacity)
    309             .field("digests", &"[redacted]")
    310             .finish()
    311     }
    312 }
    313 
    314 /// Result of one durable desired-state compare-and-swap operation.
    315 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    316 pub struct RhiPresenceDesiredCommitOutcome {
    317     state: RhiPresenceDesiredState,
    318     changed: bool,
    319 }
    320 
    321 impl RhiPresenceDesiredCommitOutcome {
    322     /// Returns the exact committed state.
    323     #[must_use]
    324     pub const fn state(self) -> RhiPresenceDesiredState {
    325         self.state
    326     }
    327 
    328     /// Returns whether this operation created a new durable generation.
    329     #[must_use]
    330     pub const fn changed(self) -> bool {
    331         self.changed
    332     }
    333 }
    334 
    335 /// Stable source-free desired-state failure classes.
    336 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    337 pub enum RhiPresenceDesiredErrorKind {
    338     InvalidConfiguration,
    339     TargetInventory,
    340     InvalidMode,
    341     Binding,
    342     ResourceExhausted,
    343     Storage,
    344     CommitOutcomeUnknown,
    345 }
    346 
    347 impl RhiPresenceDesiredErrorKind {
    348     /// Returns the stable machine-readable failure code.
    349     #[must_use]
    350     pub const fn code(self) -> &'static str {
    351         match self {
    352             Self::InvalidConfiguration => "presence_desired_configuration_invalid",
    353             Self::TargetInventory => "presence_desired_target_inventory_invalid",
    354             Self::InvalidMode => "presence_desired_mode_invalid",
    355             Self::Binding => "presence_desired_binding_invalid",
    356             Self::ResourceExhausted => "resource_exhausted",
    357             Self::Storage => "presence_desired_storage_failed",
    358             Self::CommitOutcomeUnknown => "presence_desired_commit_outcome_unknown",
    359         }
    360     }
    361 }
    362 
    363 /// Redacted source-free desired-state failure.
    364 #[derive(Clone, Copy, PartialEq, Eq)]
    365 pub struct RhiPresenceDesiredError {
    366     kind: RhiPresenceDesiredErrorKind,
    367 }
    368 
    369 impl RhiPresenceDesiredError {
    370     /// Returns the stable failure class.
    371     #[must_use]
    372     pub const fn kind(self) -> RhiPresenceDesiredErrorKind {
    373         self.kind
    374     }
    375 
    376     /// Returns the stable machine-readable failure code.
    377     #[must_use]
    378     pub const fn code(self) -> &'static str {
    379         self.kind.code()
    380     }
    381 }
    382 
    383 impl fmt::Display for RhiPresenceDesiredError {
    384     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    385         formatter.write_str(match self.kind {
    386             RhiPresenceDesiredErrorKind::InvalidConfiguration => {
    387                 "RHI presence desired-state configuration is invalid"
    388             }
    389             RhiPresenceDesiredErrorKind::TargetInventory => {
    390                 "RHI presence desired-state target inventory is invalid"
    391             }
    392             RhiPresenceDesiredErrorKind::InvalidMode => {
    393                 "RHI presence desired-state operation mode is invalid"
    394             }
    395             RhiPresenceDesiredErrorKind::Binding => "RHI presence desired-state binding is invalid",
    396             RhiPresenceDesiredErrorKind::ResourceExhausted => {
    397                 "RHI presence desired-state capacity is exhausted"
    398             }
    399             RhiPresenceDesiredErrorKind::Storage => "RHI presence desired-state storage failed",
    400             RhiPresenceDesiredErrorKind::CommitOutcomeUnknown => {
    401                 "RHI presence desired-state commit outcome is unknown"
    402             }
    403         })
    404     }
    405 }
    406 
    407 impl fmt::Debug for RhiPresenceDesiredError {
    408     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    409         formatter
    410             .debug_struct("RhiPresenceDesiredError")
    411             .field("kind", &self.kind)
    412             .finish()
    413     }
    414 }
    415 
    416 impl Error for RhiPresenceDesiredError {}
    417 
    418 impl RhiDesiredPresenceRepository<'_> {
    419     /// Commits one exact desired state before any presence rendering or relay I/O.
    420     pub async fn commit(
    421         &self,
    422         authority: &RhiPresenceDesiredAuthority,
    423     ) -> Result<RhiPresenceDesiredCommitOutcome, RhiPresenceDesiredError> {
    424         require_writable(self)?;
    425         let authority = authority.clone();
    426         self.host()
    427             .sqlite_host()
    428             .transaction(move |transaction| {
    429                 Box::pin(async move { commit_desired(transaction, &authority).await })
    430             })
    431             .await
    432             .map_err(map_transaction_error)
    433     }
    434 
    435     /// Reads the current validated desired-state snapshot without mutation.
    436     pub async fn current(
    437         &self,
    438     ) -> Result<Option<RhiPresenceDesiredState>, RhiPresenceDesiredError> {
    439         self.host()
    440             .sqlite_host()
    441             .transaction(move |transaction| {
    442                 Box::pin(async move { read_desired(transaction).await })
    443             })
    444             .await
    445             .map_err(map_transaction_error)
    446     }
    447 }
    448 
    449 fn derive_authority(
    450     document: &Value,
    451     profile: crate::RhiConfigProfile,
    452 ) -> Result<RhiPresenceDesiredAuthority, RhiPresenceDesiredError> {
    453     let configuration_sha256 = *normalized_config_digest(profile, document)
    454         .map_err(|_| failure(RhiPresenceDesiredErrorKind::InvalidConfiguration))?
    455         .as_bytes();
    456     let service_public_key = document
    457         .pointer("/identity/service/expected_public_key")
    458         .and_then(Value::as_str)
    459         .filter(|value| valid_public_key(value))
    460         .ok_or_else(|| failure(RhiPresenceDesiredErrorKind::InvalidConfiguration))?;
    461     let enabled = boolean(document, "/presence/enabled")?;
    462     let profile_document = boolean(document, "/presence/profile")?;
    463     let application_handler = boolean(document, "/presence/application_handler")?;
    464     let configured_queue =
    465         integer(document, "/resource_limits/queues/presence").and_then(|value| {
    466             u32::try_from(value)
    467                 .map_err(|_| failure(RhiPresenceDesiredErrorKind::InvalidConfiguration))
    468         })?;
    469     if configured_queue == 0 || configured_queue > 4_096 {
    470         return Err(failure(RhiPresenceDesiredErrorKind::InvalidConfiguration));
    471     }
    472 
    473     let mode = if enabled {
    474         RhiPresenceDesiredMode::Enabled
    475     } else {
    476         RhiPresenceDesiredMode::Disabled
    477     };
    478     let mut document_kinds = Vec::with_capacity(2);
    479     let (targets, queue_capacity) = match mode {
    480         RhiPresenceDesiredMode::Disabled => {
    481             if profile_document
    482                 || application_handler
    483                 || document.pointer("/presence/target_relay_ids").is_some()
    484             {
    485                 return Err(failure(RhiPresenceDesiredErrorKind::InvalidConfiguration));
    486             }
    487             (Vec::new(), 0)
    488         }
    489         RhiPresenceDesiredMode::Enabled => {
    490             if profile_document {
    491                 document_kinds.push(RhiPresenceDocumentKind::ServiceProfile);
    492             }
    493             if application_handler {
    494                 document_kinds.push(RhiPresenceDocumentKind::ApplicationHandler);
    495             }
    496             if document_kinds.is_empty() {
    497                 return Err(failure(RhiPresenceDesiredErrorKind::InvalidConfiguration));
    498             }
    499             (
    500                 derive_targets(document, "/presence/target_relay_ids")?,
    501                 configured_queue,
    502             )
    503         }
    504     };
    505     let target_set_sha256 = target_set_digest(&targets)?;
    506     let desired_sha256 = desired_state_digest(
    507         mode,
    508         &document_kinds,
    509         &targets,
    510         queue_capacity,
    511         service_public_key,
    512     )?;
    513     Ok(RhiPresenceDesiredAuthority {
    514         configuration_sha256,
    515         service_public_key: service_public_key.into(),
    516         mode,
    517         document_kinds: document_kinds.into_boxed_slice(),
    518         targets: targets.into_boxed_slice(),
    519         queue_capacity,
    520         target_set_sha256,
    521         desired_sha256,
    522     })
    523 }
    524 
    525 fn derive_targets(
    526     document: &Value,
    527     pointer: &str,
    528 ) -> Result<Vec<RhiPresenceTarget>, RhiPresenceDesiredError> {
    529     let target_ids = document
    530         .pointer(pointer)
    531         .and_then(Value::as_array)
    532         .ok_or_else(|| failure(RhiPresenceDesiredErrorKind::TargetInventory))?;
    533     if target_ids.is_empty() || target_ids.len() > RHI_PRESENCE_DESIRED_MAX_TARGETS {
    534         return Err(failure(RhiPresenceDesiredErrorKind::TargetInventory));
    535     }
    536     let relays = document
    537         .pointer("/relays")
    538         .and_then(Value::as_array)
    539         .ok_or_else(|| failure(RhiPresenceDesiredErrorKind::TargetInventory))?;
    540     let mut targets = Vec::with_capacity(target_ids.len());
    541     for (ordinal, target_id) in target_ids.iter().enumerate() {
    542         let relay_id = target_id
    543             .as_str()
    544             .filter(|value| valid_relay_id(value))
    545             .ok_or_else(|| failure(RhiPresenceDesiredErrorKind::TargetInventory))?;
    546         if targets
    547             .iter()
    548             .any(|target: &RhiPresenceTarget| target.relay_id() == relay_id)
    549         {
    550             return Err(failure(RhiPresenceDesiredErrorKind::TargetInventory));
    551         }
    552         let relay = relays
    553             .iter()
    554             .find(|relay| relay.pointer("/id").and_then(Value::as_str) == Some(relay_id))
    555             .ok_or_else(|| failure(RhiPresenceDesiredErrorKind::TargetInventory))?;
    556         if relay.pointer("/write").and_then(Value::as_bool) != Some(true) {
    557             return Err(failure(RhiPresenceDesiredErrorKind::TargetInventory));
    558         }
    559         targets.push(RhiPresenceTarget {
    560             ordinal: u8::try_from(ordinal)
    561                 .map_err(|_| failure(RhiPresenceDesiredErrorKind::TargetInventory))?,
    562             relay_id: relay_id.into(),
    563             required: relay
    564                 .pointer("/required")
    565                 .and_then(Value::as_bool)
    566                 .ok_or_else(|| failure(RhiPresenceDesiredErrorKind::TargetInventory))?,
    567         });
    568     }
    569     Ok(targets)
    570 }
    571 
    572 fn target_set_digest(targets: &[RhiPresenceTarget]) -> Result<[u8; 32], RhiPresenceDesiredError> {
    573     let mut digest = Sha256::new();
    574     digest.update(TARGET_SET_DOMAIN);
    575     digest.update(
    576         u32::try_from(targets.len())
    577             .map_err(|_| failure(RhiPresenceDesiredErrorKind::TargetInventory))?
    578             .to_be_bytes(),
    579     );
    580     for target in targets {
    581         digest.update(u32::from(target.ordinal).to_be_bytes());
    582         digest.update(
    583             u64::try_from(target.relay_id.len())
    584                 .map_err(|_| failure(RhiPresenceDesiredErrorKind::TargetInventory))?
    585                 .to_be_bytes(),
    586         );
    587         digest.update(target.relay_id.as_bytes());
    588         digest.update([u8::from(target.required)]);
    589     }
    590     Ok(digest.finalize().into())
    591 }
    592 
    593 fn desired_state_digest(
    594     mode: RhiPresenceDesiredMode,
    595     document_kinds: &[RhiPresenceDocumentKind],
    596     targets: &[RhiPresenceTarget],
    597     queue_capacity: u32,
    598     service_public_key: &str,
    599 ) -> Result<[u8; 32], RhiPresenceDesiredError> {
    600     let mut digest = Sha256::new();
    601     digest.update(DESIRED_STATE_DOMAIN);
    602     digest.update([match mode {
    603         RhiPresenceDesiredMode::Disabled => 0,
    604         RhiPresenceDesiredMode::Enabled => 1,
    605     }]);
    606     digest.update(
    607         u32::try_from(document_kinds.len())
    608             .map_err(|_| failure(RhiPresenceDesiredErrorKind::InvalidConfiguration))?
    609             .to_be_bytes(),
    610     );
    611     for kind in document_kinds {
    612         digest.update([match kind {
    613             RhiPresenceDocumentKind::ServiceProfile => 0,
    614             RhiPresenceDocumentKind::ApplicationHandler => 1,
    615         }]);
    616     }
    617     digest.update(
    618         u32::try_from(targets.len())
    619             .map_err(|_| failure(RhiPresenceDesiredErrorKind::TargetInventory))?
    620             .to_be_bytes(),
    621     );
    622     for target in targets {
    623         digest.update(u32::from(target.ordinal).to_be_bytes());
    624         digest.update(
    625             u64::try_from(target.relay_id.len())
    626                 .map_err(|_| failure(RhiPresenceDesiredErrorKind::TargetInventory))?
    627                 .to_be_bytes(),
    628         );
    629         digest.update(target.relay_id.as_bytes());
    630         digest.update([u8::from(target.required)]);
    631     }
    632     digest.update(queue_capacity.to_be_bytes());
    633     digest.update(
    634         u64::try_from(service_public_key.len())
    635             .map_err(|_| failure(RhiPresenceDesiredErrorKind::InvalidConfiguration))?
    636             .to_be_bytes(),
    637     );
    638     digest.update(service_public_key.as_bytes());
    639     Ok(digest.finalize().into())
    640 }
    641 
    642 fn require_writable(
    643     repository: &RhiDesiredPresenceRepository<'_>,
    644 ) -> Result<(), RhiPresenceDesiredError> {
    645     if repository.host().mode() == RhiStateHostMode::ReadWriteExisting {
    646         Ok(())
    647     } else {
    648         Err(failure(RhiPresenceDesiredErrorKind::InvalidMode))
    649     }
    650 }
    651 
    652 async fn commit_desired(
    653     transaction: &mut ServiceSqliteTransaction<'_>,
    654     authority: &RhiPresenceDesiredAuthority,
    655 ) -> Result<RhiPresenceDesiredCommitOutcome, OperationError> {
    656     require_current_config(transaction, authority).await?;
    657     let current = read_desired(transaction).await?;
    658     if let Some(current) = current {
    659         if matches_authority(current, authority) {
    660             return Ok(RhiPresenceDesiredCommitOutcome {
    661                 state: current,
    662                 changed: false,
    663             });
    664         }
    665         if current.generation == i64::MAX as u64 {
    666             return Err(OperationError::ResourceExhausted);
    667         }
    668         let result = sqlx::query(UPDATE_DESIRED_SQL)
    669             .bind(bool_i64(authority.mode == RhiPresenceDesiredMode::Enabled))
    670             .bind(bool_i64(has_document(
    671                 authority,
    672                 RhiPresenceDocumentKind::ServiceProfile,
    673             )))
    674             .bind(bool_i64(has_document(
    675                 authority,
    676                 RhiPresenceDocumentKind::ApplicationHandler,
    677             )))
    678             .bind(authority.target_set_sha256.as_slice())
    679             .bind(i64_count(authority.targets.len())?)
    680             .bind(i64_count(
    681                 authority
    682                     .targets
    683                     .iter()
    684                     .filter(|target| target.required)
    685                     .count(),
    686             )?)
    687             .bind(i64::from(authority.queue_capacity))
    688             .bind(authority.desired_sha256.as_slice())
    689             .bind(i64_value(current.generation)?)
    690             .bind(current.desired_sha256.as_slice())
    691             .execute(&mut *transaction)
    692             .await
    693             .map_err(|_| OperationError::Storage)?;
    694         if result.rows_affected() != 1 {
    695             return Err(OperationError::Binding);
    696         }
    697     } else {
    698         let result = sqlx::query(INSERT_DESIRED_SQL)
    699             .bind(bool_i64(authority.mode == RhiPresenceDesiredMode::Enabled))
    700             .bind(bool_i64(has_document(
    701                 authority,
    702                 RhiPresenceDocumentKind::ServiceProfile,
    703             )))
    704             .bind(bool_i64(has_document(
    705                 authority,
    706                 RhiPresenceDocumentKind::ApplicationHandler,
    707             )))
    708             .bind(authority.target_set_sha256.as_slice())
    709             .bind(i64_count(authority.targets.len())?)
    710             .bind(i64_count(
    711                 authority
    712                     .targets
    713                     .iter()
    714                     .filter(|target| target.required)
    715                     .count(),
    716             )?)
    717             .bind(i64::from(authority.queue_capacity))
    718             .bind(authority.desired_sha256.as_slice())
    719             .execute(&mut *transaction)
    720             .await
    721             .map_err(|_| OperationError::Storage)?;
    722         if result.rows_affected() != 1 {
    723             return Err(OperationError::Binding);
    724         }
    725     }
    726     let committed = read_desired(transaction)
    727         .await?
    728         .filter(|state| matches_authority(*state, authority))
    729         .ok_or(OperationError::Binding)?;
    730     Ok(RhiPresenceDesiredCommitOutcome {
    731         state: committed,
    732         changed: true,
    733     })
    734 }
    735 
    736 async fn require_current_config(
    737     transaction: &mut ServiceSqliteTransaction<'_>,
    738     authority: &RhiPresenceDesiredAuthority,
    739 ) -> Result<(), OperationError> {
    740     let rows = sqlx::query(READ_CURRENT_CONFIG_SQL)
    741         .fetch_all(&mut *transaction)
    742         .await
    743         .map_err(|_| OperationError::Storage)?;
    744     if rows.len() != 1 {
    745         return Err(OperationError::Binding);
    746     }
    747     let row = &rows[0];
    748     let configuration_sha256 = digest(row, "normalized_config_sha256")?;
    749     let key_bytes = row
    750         .try_get::<i64, _>("service_public_key_bytes")
    751         .ok()
    752         .and_then(|value| usize::try_from(value).ok())
    753         .filter(|value| *value == 64)
    754         .ok_or(OperationError::Binding)?;
    755     let service_public_key = row
    756         .try_get::<String, _>("service_public_key")
    757         .map_err(|_| OperationError::Binding)?;
    758     if service_public_key.len() != key_bytes
    759         || !valid_public_key(&service_public_key)
    760         || configuration_sha256 != authority.configuration_sha256
    761         || service_public_key != authority.service_public_key.as_ref()
    762     {
    763         return Err(OperationError::Binding);
    764     }
    765     Ok(())
    766 }
    767 
    768 async fn read_desired(
    769     transaction: &mut ServiceSqliteTransaction<'_>,
    770 ) -> Result<Option<RhiPresenceDesiredState>, OperationError> {
    771     let rows = sqlx::query(READ_DESIRED_SQL)
    772         .fetch_all(&mut *transaction)
    773         .await
    774         .map_err(|_| OperationError::Storage)?;
    775     match rows.as_slice() {
    776         [] => Ok(None),
    777         [row] => decode_desired(row).map(Some),
    778         _ => Err(OperationError::Binding),
    779     }
    780 }
    781 
    782 fn decode_desired(
    783     row: &sqlx::sqlite::SqliteRow,
    784 ) -> Result<RhiPresenceDesiredState, OperationError> {
    785     if row.try_get::<i64, _>("singleton").ok() != Some(1) {
    786         return Err(OperationError::Binding);
    787     }
    788     let generation = positive_u64(row, "generation")?;
    789     let enabled = boolean_i64(row, "enabled")?;
    790     let profile = boolean_i64(row, "profile")?;
    791     let application_handler = boolean_i64(row, "application_handler")?;
    792     let target_set_sha256 = digest(row, "target_set_sha256")?;
    793     let target_count = count_u8(row, "target_count", RHI_PRESENCE_DESIRED_MAX_TARGETS)?;
    794     let required_target_count = count_u8(row, "required_target_count", usize::from(target_count))?;
    795     let queue_capacity = row
    796         .try_get::<i64, _>("queue_capacity")
    797         .ok()
    798         .and_then(|value| u32::try_from(value).ok())
    799         .filter(|value| *value <= 4_096)
    800         .ok_or(OperationError::Binding)?;
    801     let desired_sha256 = digest(row, "desired_sha256")?;
    802     let valid = if enabled {
    803         (profile || application_handler) && target_count > 0 && queue_capacity > 0
    804     } else {
    805         !profile
    806             && !application_handler
    807             && target_count == 0
    808             && required_target_count == 0
    809             && queue_capacity == 0
    810     };
    811     if !valid {
    812         return Err(OperationError::Binding);
    813     }
    814     Ok(RhiPresenceDesiredState {
    815         generation,
    816         mode: if enabled {
    817             RhiPresenceDesiredMode::Enabled
    818         } else {
    819             RhiPresenceDesiredMode::Disabled
    820         },
    821         profile,
    822         application_handler,
    823         target_set_sha256,
    824         target_count,
    825         required_target_count,
    826         queue_capacity,
    827         desired_sha256,
    828     })
    829 }
    830 
    831 fn matches_authority(
    832     state: RhiPresenceDesiredState,
    833     authority: &RhiPresenceDesiredAuthority,
    834 ) -> bool {
    835     state.mode == authority.mode
    836         && state.profile == has_document(authority, RhiPresenceDocumentKind::ServiceProfile)
    837         && state.application_handler
    838             == has_document(authority, RhiPresenceDocumentKind::ApplicationHandler)
    839         && state.target_set_sha256 == authority.target_set_sha256
    840         && usize::from(state.target_count) == authority.targets.len()
    841         && usize::from(state.required_target_count)
    842             == authority
    843                 .targets
    844                 .iter()
    845                 .filter(|target| target.required)
    846                 .count()
    847         && state.queue_capacity == authority.queue_capacity
    848         && state.desired_sha256 == authority.desired_sha256
    849 }
    850 
    851 pub(crate) fn presence_authority_matches_state(
    852     state: RhiPresenceDesiredState,
    853     authority: &RhiPresenceDesiredAuthority,
    854 ) -> bool {
    855     matches_authority(state, authority)
    856 }
    857 
    858 fn has_document(authority: &RhiPresenceDesiredAuthority, kind: RhiPresenceDocumentKind) -> bool {
    859     authority.document_kinds.contains(&kind)
    860 }
    861 
    862 fn digest(row: &sqlx::sqlite::SqliteRow, field: &str) -> Result<[u8; 32], OperationError> {
    863     row.try_get::<Vec<u8>, _>(field)
    864         .map_err(|_| OperationError::Binding)?
    865         .try_into()
    866         .map_err(|_| OperationError::Binding)
    867 }
    868 
    869 fn positive_u64(row: &sqlx::sqlite::SqliteRow, field: &str) -> Result<u64, OperationError> {
    870     row.try_get::<i64, _>(field)
    871         .ok()
    872         .and_then(|value| u64::try_from(value).ok())
    873         .filter(|value| *value != 0)
    874         .ok_or(OperationError::Binding)
    875 }
    876 
    877 fn boolean_i64(row: &sqlx::sqlite::SqliteRow, field: &str) -> Result<bool, OperationError> {
    878     match row.try_get::<i64, _>(field) {
    879         Ok(0) => Ok(false),
    880         Ok(1) => Ok(true),
    881         Ok(_) | Err(_) => Err(OperationError::Binding),
    882     }
    883 }
    884 
    885 fn count_u8(
    886     row: &sqlx::sqlite::SqliteRow,
    887     field: &str,
    888     maximum: usize,
    889 ) -> Result<u8, OperationError> {
    890     row.try_get::<i64, _>(field)
    891         .ok()
    892         .and_then(|value| u8::try_from(value).ok())
    893         .filter(|value| usize::from(*value) <= maximum)
    894         .ok_or(OperationError::Binding)
    895 }
    896 
    897 fn bool_i64(value: bool) -> i64 {
    898     i64::from(value)
    899 }
    900 
    901 fn i64_count(value: usize) -> Result<i64, OperationError> {
    902     i64::try_from(value).map_err(|_| OperationError::InvalidInput)
    903 }
    904 
    905 fn i64_value(value: u64) -> Result<i64, OperationError> {
    906     i64::try_from(value).map_err(|_| OperationError::ResourceExhausted)
    907 }
    908 
    909 fn boolean(document: &Value, pointer: &str) -> Result<bool, RhiPresenceDesiredError> {
    910     document
    911         .pointer(pointer)
    912         .and_then(Value::as_bool)
    913         .ok_or_else(|| failure(RhiPresenceDesiredErrorKind::InvalidConfiguration))
    914 }
    915 
    916 fn integer(document: &Value, pointer: &str) -> Result<u64, RhiPresenceDesiredError> {
    917     document
    918         .pointer(pointer)
    919         .and_then(Value::as_u64)
    920         .ok_or_else(|| failure(RhiPresenceDesiredErrorKind::InvalidConfiguration))
    921 }
    922 
    923 fn valid_public_key(value: &str) -> bool {
    924     value.len() == 64
    925         && value
    926             .bytes()
    927             .all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase())
    928         && nostr::PublicKey::from_hex(value).is_ok_and(|key| key.xonly().is_ok())
    929 }
    930 
    931 fn valid_relay_id(value: &str) -> bool {
    932     !value.is_empty()
    933         && value.len() <= 64
    934         && value.as_bytes()[0].is_ascii_lowercase()
    935         && value.bytes().all(|byte| {
    936             byte.is_ascii_lowercase() || byte.is_ascii_digit() || matches!(byte, b'_' | b'-')
    937         })
    938 }
    939 
    940 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    941 enum OperationError {
    942     InvalidInput,
    943     Binding,
    944     ResourceExhausted,
    945     Storage,
    946 }
    947 
    948 fn map_transaction_error(
    949     error: ServiceSqliteTransactionError<OperationError>,
    950 ) -> RhiPresenceDesiredError {
    951     if error.kind() == ServiceSqliteTransactionErrorKind::CommitOutcomeUnknown {
    952         return failure(RhiPresenceDesiredErrorKind::CommitOutcomeUnknown);
    953     }
    954     failure(match error.operation_error().copied() {
    955         Some(OperationError::InvalidInput) => RhiPresenceDesiredErrorKind::InvalidConfiguration,
    956         Some(OperationError::Binding) => RhiPresenceDesiredErrorKind::Binding,
    957         Some(OperationError::ResourceExhausted) => RhiPresenceDesiredErrorKind::ResourceExhausted,
    958         Some(OperationError::Storage) | None => RhiPresenceDesiredErrorKind::Storage,
    959     })
    960 }
    961 
    962 const fn failure(kind: RhiPresenceDesiredErrorKind) -> RhiPresenceDesiredError {
    963     RhiPresenceDesiredError { kind }
    964 }
    965 
    966 #[cfg(test)]
    967 mod tests {
    968     use super::*;
    969     use crate::{RhiConfigProfile, parse_rhi_config_v1};
    970 
    971     const EXAMPLE: &str = include_str!("../contracts/services_hardening/config.v1.example.toml");
    972 
    973     fn config(source: &str) -> RhiConfigDocumentV1 {
    974         parse_rhi_config_v1(source.as_bytes(), RhiConfigProfile::RepoLocal).expect("config")
    975     }
    976 
    977     #[test]
    978     fn authority_is_deterministic_ordered_and_sealed() {
    979         let config = config(EXAMPLE);
    980         let first = RhiPresenceDesiredAuthority::from_config(&config).expect("authority");
    981         let second = RhiPresenceDesiredAuthority::from_config(&config).expect("authority");
    982         assert_eq!(first, second);
    983         validate_rhi_presence_desired_authority(&config, &first).expect("independent validation");
    984         assert_eq!(first.mode(), RhiPresenceDesiredMode::Enabled);
    985         assert_eq!(
    986             first.document_kinds(),
    987             &[
    988                 RhiPresenceDocumentKind::ServiceProfile,
    989                 RhiPresenceDocumentKind::ApplicationHandler,
    990             ]
    991         );
    992         assert_eq!(first.targets().len(), 2);
    993         assert_eq!(first.targets()[0].ordinal(), 0);
    994         assert_eq!(first.targets()[0].relay_id(), "relay-primary");
    995         assert!(first.targets()[0].required());
    996         assert_eq!(first.targets()[1].ordinal(), 1);
    997         assert_eq!(first.targets()[1].relay_id(), "relay-secondary");
    998         assert!(!first.targets()[1].required());
    999         assert_eq!(first.queue_capacity(), 64);
   1000         assert_eq!(
   1001             first.target_set_sha256(),
   1002             &[
   1003                 0x95, 0x9f, 0x04, 0x01, 0x28, 0x41, 0xae, 0x6e, 0x9b, 0xf3, 0xe1, 0x09, 0x46, 0x8b,
   1004                 0x4f, 0x66, 0xcf, 0xa9, 0xd9, 0x66, 0xaa, 0xc1, 0xdf, 0x36, 0xdf, 0x09, 0xe4, 0x5c,
   1005                 0x1e, 0x1c, 0x48, 0xf9,
   1006             ]
   1007         );
   1008         assert_eq!(
   1009             first.desired_sha256(),
   1010             &[
   1011                 0x72, 0x35, 0xf1, 0xe3, 0x86, 0xe8, 0x39, 0x42, 0x76, 0x25, 0xdc, 0x36, 0x4d, 0xf7,
   1012                 0xb5, 0x1e, 0xe7, 0x4d, 0x39, 0xd5, 0xf1, 0x70, 0xe1, 0x2b, 0x25, 0xcf, 0x2c, 0x42,
   1013                 0xfd, 0x77, 0x31, 0xf0,
   1014             ]
   1015         );
   1016         let rendered = format!("{first:?} {:?}", first.targets()[0]);
   1017         assert!(!rendered.contains("relay-primary"));
   1018         assert!(!rendered.contains(&"2".repeat(64)));
   1019     }
   1020 
   1021     #[test]
   1022     fn semantic_changes_change_only_the_deterministic_authority() {
   1023         let baseline =
   1024             RhiPresenceDesiredAuthority::from_config(&config(EXAMPLE)).expect("baseline");
   1025         for changed in [
   1026             EXAMPLE.replace("profile = true", "profile = false"),
   1027             EXAMPLE.replace(
   1028                 "target_relay_ids = [\"relay-primary\", \"relay-secondary\"]",
   1029                 "target_relay_ids = [\"relay-secondary\", \"relay-primary\"]",
   1030             ),
   1031             EXAMPLE.replacen("required = true", "required = false", 1),
   1032             EXAMPLE.replace("presence = 64", "presence = 63"),
   1033             EXAMPLE.replace(&"2".repeat(64), &"3".repeat(64)),
   1034         ] {
   1035             let changed = RhiPresenceDesiredAuthority::from_config(&config(&changed))
   1036                 .expect("changed authority");
   1037             assert_ne!(changed.desired_sha256(), baseline.desired_sha256());
   1038         }
   1039     }
   1040 
   1041     #[test]
   1042     fn disabled_authority_contains_no_document_target_or_queue_state() {
   1043         let disabled = EXAMPLE.replace(
   1044             "[presence]\nenabled = true\nprofile = true\napplication_handler = true\ntarget_relay_ids = [\"relay-primary\", \"relay-secondary\"]",
   1045             "[presence]\nenabled = false\nprofile = false\napplication_handler = false",
   1046         );
   1047         let authority = RhiPresenceDesiredAuthority::from_config(&config(&disabled))
   1048             .expect("disabled authority");
   1049         assert_eq!(authority.mode(), RhiPresenceDesiredMode::Disabled);
   1050         assert!(authority.document_kinds().is_empty());
   1051         assert!(authority.targets().is_empty());
   1052         assert_eq!(authority.queue_capacity(), 0);
   1053     }
   1054 
   1055     #[test]
   1056     fn diagnostics_are_closed_source_free_and_redacted() {
   1057         for kind in [
   1058             RhiPresenceDesiredErrorKind::InvalidConfiguration,
   1059             RhiPresenceDesiredErrorKind::TargetInventory,
   1060             RhiPresenceDesiredErrorKind::InvalidMode,
   1061             RhiPresenceDesiredErrorKind::Binding,
   1062             RhiPresenceDesiredErrorKind::ResourceExhausted,
   1063             RhiPresenceDesiredErrorKind::Storage,
   1064             RhiPresenceDesiredErrorKind::CommitOutcomeUnknown,
   1065         ] {
   1066             let error = failure(kind);
   1067             assert_eq!(error.kind(), kind);
   1068             assert!(!error.code().is_empty());
   1069             assert!(Error::source(&error).is_none());
   1070             let rendered = format!("{error} {error:?}");
   1071             assert!(!rendered.contains("wss://"));
   1072             assert!(!rendered.contains("relay-primary"));
   1073             assert!(!rendered.contains(&"2".repeat(64)));
   1074         }
   1075     }
   1076 }