corium_transactor/authz.rs
1//! Serving the authorization database from this transactor node.
2//!
3//! The transactor already holds every database it leads, so the authz database
4//! is just another one of them: the policy source hands out a snapshot of the
5//! local `DbState` with no network hop, and the transactor's own basis watch is
6//! the change signal that triggers recompilation. This is also the surface
7//! where write admission is decided, so authorizing a transaction against the
8//! node's own authz snapshot makes admission consistent at the serialization
9//! point.
10
11use std::sync::Arc;
12
13use corium_authz::source::{PolicySource, SourceError};
14use corium_db::Db;
15
16use crate::node::TransactorNode;
17
18/// A [`PolicySource`] reading the authz database this node hosts.
19pub struct NodePolicySource {
20 node: Arc<TransactorNode>,
21 db: String,
22}
23
24impl NodePolicySource {
25 /// Reads policy from the database `db` on `node`.
26 pub fn new(node: Arc<TransactorNode>, db: impl Into<String>) -> Self {
27 Self {
28 node,
29 db: db.into(),
30 }
31 }
32}
33
34#[tonic::async_trait]
35impl PolicySource for NodePolicySource {
36 fn name(&self) -> &str {
37 &self.db
38 }
39
40 async fn snapshot(&self) -> Result<Db, SourceError> {
41 match self.node.db_state(&self.db).await {
42 Ok(state) => Ok(state.db()),
43 // Distinguish "no such database" — a misconfiguration an operator
44 // must see — from a transient read failure.
45 Err(crate::node::NodeError::UnknownDb(name)) => Err(SourceError::Unavailable(name)),
46 Err(error) => Err(SourceError::Failed {
47 db: self.db.clone(),
48 reason: error.to_string(),
49 }),
50 }
51 }
52
53 async fn changed(&self, basis_t: u64) {
54 let Ok(state) = self.node.db_state(&self.db).await else {
55 tokio::time::sleep(corium_authz::source::DEFAULT_POLL_INTERVAL).await;
56 return;
57 };
58 let mut basis = state.basis_watch();
59 // `wait_for` returns immediately when the basis has already moved past
60 // the compiled snapshot, so no policy change can be missed between the
61 // compile and the subscribe.
62 let _ = basis.wait_for(|current| *current > basis_t).await;
63 }
64}