use std::sync::atomic::{AtomicBool, AtomicU64};
use std::sync::{Arc, Mutex};
use arc_swap::ArcSwap;
use dashmap::DashMap;
use super::*;
use std::collections::BTreeMap;
use std::time::Duration;
use super::construction::KernelBuildError;
#[derive(Debug, Clone)]
pub struct HotPathDeadlineConfig {
pub guard_pipeline_budget_ms: u64,
pub per_guard_budget_ms: BTreeMap<String, u64>,
pub always_offload_guards: bool,
pub dispatch_budget_ms: u64,
pub per_server_dispatch_budget_ms: BTreeMap<String, u64>,
pub receipt_append_budget_ms: u64,
pub receipt_writer_poll_ms: u64,
pub receipt_writer_stall_ms: u64,
}
pub const DEFAULT_RECEIPT_APPEND_BUDGET_MS: u64 = 5_000;
pub const MIN_RECEIPT_APPEND_BUDGET_MS: u64 = 250;
pub const DEFAULT_RECEIPT_WRITER_POLL_MS: u64 = 1_000;
pub const DEFAULT_RECEIPT_WRITER_STALL_MS: u64 = 10_000;
impl Default for HotPathDeadlineConfig {
fn default() -> Self {
Self {
guard_pipeline_budget_ms: 0,
per_guard_budget_ms: BTreeMap::new(),
always_offload_guards: false,
dispatch_budget_ms: 0,
per_server_dispatch_budget_ms: BTreeMap::new(),
receipt_append_budget_ms: DEFAULT_RECEIPT_APPEND_BUDGET_MS,
receipt_writer_poll_ms: DEFAULT_RECEIPT_WRITER_POLL_MS,
receipt_writer_stall_ms: DEFAULT_RECEIPT_WRITER_STALL_MS,
}
}
}
impl HotPathDeadlineConfig {
pub fn validate(&self) -> Result<(), KernelBuildError> {
if self.receipt_append_budget_ms < MIN_RECEIPT_APPEND_BUDGET_MS {
return Err(KernelBuildError::InvalidDeadlineConfig(format!(
"receipt_append_budget_ms must be >= {MIN_RECEIPT_APPEND_BUDGET_MS}"
)));
}
if self.receipt_writer_poll_ms == 0 || self.receipt_writer_stall_ms == 0 {
return Err(KernelBuildError::InvalidDeadlineConfig(
"receipt writer poll and stall thresholds must be non-zero".to_string(),
));
}
Ok(())
}
fn ms_to_budget(ms: u64) -> Option<Duration> {
match ms {
0 => None,
v => Some(Duration::from_millis(v)),
}
}
pub fn guard_pipeline_budget(&self) -> Option<Duration> {
Self::ms_to_budget(self.guard_pipeline_budget_ms)
}
pub fn guard_budget_for(&self, name: &str) -> Option<Duration> {
match self.per_guard_budget_ms.get(name) {
None | Some(0) => self.guard_pipeline_budget(),
Some(ms) => Self::ms_to_budget(*ms),
}
}
pub fn dispatch_budget_for(&self, server_id: &str) -> Option<Duration> {
match self.per_server_dispatch_budget_ms.get(server_id) {
Some(ms) => Self::ms_to_budget(*ms),
None => Self::ms_to_budget(self.dispatch_budget_ms),
}
}
pub fn receipt_append_budget(&self) -> Duration {
Duration::from_millis(
self.receipt_append_budget_ms
.max(MIN_RECEIPT_APPEND_BUDGET_MS),
)
}
}
#[cfg(test)]
mod hot_path_deadline_config_tests {
use super::*;
#[test]
fn default_disables_guard_and_dispatch_but_bounds_append() {
let cfg = HotPathDeadlineConfig::default();
assert_eq!(cfg.guard_pipeline_budget(), None);
assert_eq!(cfg.dispatch_budget_for("any-server"), None);
assert_eq!(
cfg.receipt_append_budget(),
Duration::from_millis(DEFAULT_RECEIPT_APPEND_BUDGET_MS)
);
}
#[test]
fn validate_rejects_zero_append_budget() {
let cfg = HotPathDeadlineConfig {
receipt_append_budget_ms: 0,
..HotPathDeadlineConfig::default()
};
assert!(cfg.validate().is_err());
}
#[test]
fn validate_rejects_below_floor_append_budget() {
let cfg = HotPathDeadlineConfig {
receipt_append_budget_ms: MIN_RECEIPT_APPEND_BUDGET_MS - 1,
..HotPathDeadlineConfig::default()
};
assert!(cfg.validate().is_err());
}
#[test]
fn validate_rejects_zero_poll_or_stall() {
let cfg = HotPathDeadlineConfig {
receipt_writer_poll_ms: 0,
..HotPathDeadlineConfig::default()
};
assert!(cfg.validate().is_err());
}
#[test]
fn append_budget_is_clamped_to_floor_even_without_validation() {
let cfg = HotPathDeadlineConfig {
receipt_append_budget_ms: 1,
..HotPathDeadlineConfig::default()
};
assert_eq!(
cfg.receipt_append_budget(),
Duration::from_millis(MIN_RECEIPT_APPEND_BUDGET_MS)
);
}
#[test]
fn per_guard_and_per_server_overrides_resolve() {
let mut per_guard = BTreeMap::new();
per_guard.insert("slow-guard".to_string(), 200u64);
let mut per_server = BTreeMap::new();
per_server.insert("slow-srv".to_string(), 300u64);
let cfg = HotPathDeadlineConfig {
guard_pipeline_budget_ms: 100,
per_guard_budget_ms: per_guard,
dispatch_budget_ms: 150,
per_server_dispatch_budget_ms: per_server,
..HotPathDeadlineConfig::default()
};
assert_eq!(
cfg.guard_budget_for("slow-guard"),
Some(Duration::from_millis(200))
);
assert_eq!(
cfg.guard_budget_for("other-guard"),
Some(Duration::from_millis(100))
);
assert_eq!(
cfg.dispatch_budget_for("slow-srv"),
Some(Duration::from_millis(300))
);
assert_eq!(
cfg.dispatch_budget_for("other-srv"),
Some(Duration::from_millis(150))
);
}
#[test]
fn per_guard_zero_override_inherits_pipeline_budget() {
let mut per_guard = BTreeMap::new();
per_guard.insert("disabled-override".to_string(), 0u64);
let cfg = HotPathDeadlineConfig {
guard_pipeline_budget_ms: 1_000,
per_guard_budget_ms: per_guard,
..HotPathDeadlineConfig::default()
};
assert_eq!(
cfg.guard_budget_for("disabled-override"),
Some(Duration::from_millis(1_000))
);
}
#[test]
fn per_guard_zero_override_stays_unbounded_without_pipeline_budget() {
let mut per_guard = BTreeMap::new();
per_guard.insert("disabled-override".to_string(), 0u64);
let cfg = HotPathDeadlineConfig {
guard_pipeline_budget_ms: 0,
per_guard_budget_ms: per_guard,
..HotPathDeadlineConfig::default()
};
assert_eq!(cfg.guard_budget_for("disabled-override"), None);
}
}
pub struct KernelConfig {
pub keypair: Keypair,
pub ca_public_keys: Vec<chio_core::PublicKey>,
pub max_delegation_depth: u32,
pub policy_hash: String,
pub allow_sampling: bool,
pub allow_sampling_tool_use: bool,
pub allow_elicitation: bool,
pub max_stream_duration_secs: u64,
pub max_stream_total_bytes: u64,
pub require_web3_evidence: bool,
pub allow_ephemeral_receipt_log: bool,
pub allow_ephemeral_revocation_store: bool,
pub checkpoint_batch_size: u64,
pub retention_config: Option<crate::receipt_store::RetentionConfig>,
pub memory_budget: MemoryBudgetConfig,
pub deadlines: HotPathDeadlineConfig,
}
impl KernelConfig {
pub(crate) fn memory_budget_receipt_mirror_capacity(&self) -> usize {
self.memory_budget.receipt_mirror_capacity
}
pub(crate) fn memory_budget_federation_cache_capacity(&self) -> usize {
self.memory_budget.federation_cache_capacity
}
pub(crate) fn memory_budget_federation_cache_idle_ttl_secs(&self) -> u64 {
self.memory_budget.federation_cache_idle_ttl_secs
}
}
#[derive(Debug, Clone, Default)]
pub struct HybridSigningConfig {
pub crypto_floor: KernelCryptoFloor,
pub pq_signing_seed: Option<[u8; 32]>,
}
pub(crate) fn capability_crypto_floor(
floor: KernelCryptoFloor,
) -> chio_core::capability::crypto_floor::CapabilityCryptoFloor {
match floor {
KernelCryptoFloor::AllowClassical => {
chio_core::capability::crypto_floor::CapabilityCryptoFloor::AllowClassical
}
KernelCryptoFloor::AllowHybrid => {
chio_core::capability::crypto_floor::CapabilityCryptoFloor::AllowHybrid
}
KernelCryptoFloor::PqRequired => {
chio_core::capability::crypto_floor::CapabilityCryptoFloor::PqRequired
}
}
}
pub(crate) fn receipt_crypto_floor(
floor: KernelCryptoFloor,
) -> chio_core::receipt::crypto_floor::ReceiptCryptoFloor {
match floor {
KernelCryptoFloor::AllowClassical => {
chio_core::receipt::crypto_floor::ReceiptCryptoFloor::AllowClassical
}
KernelCryptoFloor::AllowHybrid => {
chio_core::receipt::crypto_floor::ReceiptCryptoFloor::AllowHybrid
}
KernelCryptoFloor::PqRequired => {
chio_core::receipt::crypto_floor::ReceiptCryptoFloor::PqRequired
}
}
}
pub const DEFAULT_MAX_STREAM_DURATION_SECS: u64 = 300;
pub const DEFAULT_MAX_STREAM_TOTAL_BYTES: u64 = 256 * 1024 * 1024;
pub const DEFAULT_MAX_STREAM_CHUNKS: u64 = 1_048_576;
pub const DEFAULT_CHECKPOINT_BATCH_SIZE: u64 = 100;
pub const DEFAULT_RETENTION_DAYS: u64 = 90;
pub const DEFAULT_MAX_SIZE_BYTES: u64 = 10_737_418_240;
#[derive(Debug, Clone)]
pub struct MemoryBudgetConfig {
pub receipt_mirror_capacity: usize,
pub federation_cache_capacity: usize,
pub federation_cache_idle_ttl_secs: u64,
pub velocity_bucket_cap: usize,
pub admission_key_cap: usize,
pub journal_entry_cap: usize,
pub max_stream_chunks: u64,
pub journal_tool_counts_cap: usize,
pub rss_soft_limit_bytes: Option<u64>,
pub rss_sample_interval_secs: u64,
}
impl MemoryBudgetConfig {
pub fn defaults() -> Self {
Self {
receipt_mirror_capacity: 4096,
federation_cache_capacity: 8192,
federation_cache_idle_ttl_secs: 3600,
velocity_bucket_cap: 65_536,
admission_key_cap: 4096,
journal_entry_cap: 4096,
max_stream_chunks: DEFAULT_MAX_STREAM_CHUNKS,
journal_tool_counts_cap: 4096,
rss_soft_limit_bytes: None,
rss_sample_interval_secs: 30,
}
}
}
impl Default for MemoryBudgetConfig {
fn default() -> Self {
Self::defaults()
}
}
pub(crate) struct RssSamplerHandle {
stop: Arc<AtomicBool>,
join: Option<std::thread::JoinHandle<()>>,
}
impl RssSamplerHandle {
pub(crate) fn spawn(shed: Arc<AtomicBool>, soft_limit_bytes: u64, interval_secs: u64) -> Self {
let stop = Arc::new(AtomicBool::new(false));
let worker_stop = Arc::clone(&stop);
let interval = std::time::Duration::from_secs(interval_secs.max(1));
let join = std::thread::spawn(move || {
use std::sync::atomic::Ordering;
while !worker_stop.load(Ordering::SeqCst) {
if let Some(rss) = read_process_rss_bytes() {
shed.store(rss > soft_limit_bytes, Ordering::Relaxed);
}
let mut waited = std::time::Duration::ZERO;
let slice = std::time::Duration::from_millis(200);
while waited < interval && !worker_stop.load(Ordering::SeqCst) {
std::thread::sleep(slice);
waited += slice;
}
}
});
Self {
stop,
join: Some(join),
}
}
}
impl Drop for RssSamplerHandle {
fn drop(&mut self) {
self.stop.store(true, std::sync::atomic::Ordering::SeqCst);
if let Some(join) = self.join.take() {
let _ = join.join();
}
}
}
#[cfg(target_os = "linux")]
fn read_process_rss_bytes() -> Option<u64> {
let statm = std::fs::read_to_string("/proc/self/statm").ok()?;
let resident_pages: u64 = statm.split_whitespace().nth(1)?.parse().ok()?;
Some(resident_pages.saturating_mul(linux_page_size()))
}
#[cfg(target_os = "linux")]
fn linux_page_size() -> u64 {
use std::sync::OnceLock;
static PAGE_SIZE: OnceLock<u64> = OnceLock::new();
*PAGE_SIZE.get_or_init(|| {
let raw = unsafe { libc::sysconf(libc::_SC_PAGESIZE) };
if raw > 0 {
raw as u64
} else {
4096
}
})
}
#[cfg(not(target_os = "linux"))]
fn read_process_rss_bytes() -> Option<u64> {
None
}
pub struct ChioKernel {
pub(super) config: KernelConfig,
pub(super) durable_admission_mode: crate::admission_operation::DurableAdmissionMode,
pub(super) durable_admission_runtime: Option<DurableAdmissionRuntime>,
pub(super) unsafe_ephemeral_financial_dispatch: bool,
pub(super) guards: Arc<Vec<Arc<dyn Guard>>>,
pub(super) post_invocation_pipeline: crate::post_invocation::PostInvocationPipeline,
pub(super) budget_store: Arc<dyn BudgetStore>,
pub(super) budget_store_lock: Mutex<()>,
pub(super) revocation_store: Arc<dyn RevocationStore>,
pub(super) capability_authority: Box<dyn CapabilityAuthority>,
pub(super) tool_servers: HashMap<ServerId, Arc<dyn ToolServerConnection>>,
pub(super) resource_providers: Vec<Box<dyn ResourceProvider>>,
pub(super) prompt_providers: Vec<Box<dyn PromptProvider>>,
pub(super) sessions: DashMap<SessionId, Arc<Session>>,
pub(super) receipt_log: Mutex<ReceiptLog>,
pub(super) child_receipt_log: Mutex<ChildReceiptLog>,
pub(super) receipt_mirror_gauge: chio_bounded::SizeGauge,
pub(super) child_receipt_mirror_gauge: chio_bounded::SizeGauge,
pub(super) receipt_store: Option<Arc<dyn ReceiptStore>>,
pub(super) receipt_store_write_lock: Mutex<()>,
pub(super) retention_maintenance: Option<crate::receipt_store::RetentionMaintenanceHandle>,
pub(super) payment_adapter: Option<Box<dyn PaymentAdapter>>,
pub(super) price_oracle: Option<Box<dyn PriceOracle>>,
pub(super) runtime_admission_hook: Option<Arc<dyn RuntimeAdmissionHook>>,
pub(super) attestation_trust_policy: Option<AttestationTrustPolicy>,
pub(super) capability_crypto_floor: KernelCryptoFloor,
pub(super) checkpoint_batch_size: u64,
pub(super) checkpoint_seq_counter: AtomicU64,
pub(super) last_checkpoint_seq: AtomicU64,
pub(super) dpop_nonce_store: Option<dpop::DpopNonceStore>,
pub(super) dpop_config: Option<dpop::DpopConfig>,
pub(super) execution_nonce_config: Option<crate::execution_nonce::ExecutionNonceConfig>,
pub(super) execution_nonce_store: Option<Box<dyn crate::execution_nonce::ExecutionNonceStore>>,
pub(super) approval_replay_store: Option<dpop::DpopNonceStore>,
pub(super) threshold_approval_requirement_resolver:
Option<Arc<dyn crate::threshold_approval::ThresholdApprovalRequirementResolver>>,
pub(super) supplemental_quota_verifier:
Option<crate::supplemental_quota::SupplementalQuotaVerifierRuntime>,
pub(super) emergency_stopped: AtomicBool,
pub(super) emergency_stopped_since: AtomicU64,
pub(super) emergency_stop_reason: ArcSwap<Option<String>>,
pub(super) lock_poison: chio_supervisor::HealthFlag,
pub(super) memory_provenance: Option<Arc<dyn crate::memory_provenance::MemoryProvenanceStore>>,
pub(super) federation_peers:
ArcSwap<HashMap<String, chio_federation::trust_establishment::FederationPeer>>,
pub(super) capability_trust_roots:
ArcSwap<HashMap<String, chio_core::capability::attenuation::ScopeHash>>,
pub(super) capability_trust_roots_write_lock: Mutex<()>,
pub(super) federation_cosigner:
Option<Arc<dyn chio_federation::bilateral::BilateralCoSigningProtocol>>,
pub(super) federation_dual_receipts:
Mutex<chio_bounded::BoundedMap<String, chio_federation::bilateral::DualSignedReceipt>>,
pub(super) federation_dual_receipts_gauge: chio_bounded::SizeGauge,
pub(super) federation_dsse_envelopes:
Mutex<chio_bounded::BoundedMap<String, chio_federation::bilateral_dsse::DsseEnvelope>>,
pub(super) federation_dsse_envelopes_gauge: chio_bounded::SizeGauge,
pub(super) federation_artifact_store:
Option<std::sync::Arc<dyn crate::federation_artifact_store::FederationArtifactStore>>,
pub(super) receipt_tenant_ids: Arc<DashMap<String, String>>,
pub(super) receipt_federation_admissions: Arc<DashMap<String, ReceiptFederationAdmission>>,
pub(super) federation_local_kernel_id: ArcSwap<Option<String>>,
pub(super) signing_task: std::sync::Arc<signing_task::SigningTaskHandle>,
pub(super) settlement_observer: Option<crate::settlement_routing::SettlementObserverRuntime>,
pub(super) revocation_view: Option<std::sync::Arc<chio_kernel_core::RevocationView>>,
pub(super) budget_registry: Mutex<chio_kernel_core::InMemoryBudgetRegistry>,
pub(super) reserved_sibling_shares: Mutex<HashMap<String, ReservedSiblingShare>>,
pub(super) restart_reserved_hold_gate: Mutex<RestartReservedHoldGate>,
pub(super) rss_shed: Arc<AtomicBool>,
pub(super) rss_sampler: Option<RssSamplerHandle>,
pub(super) receipt_writer_watchdog:
std::sync::Arc<receipt_writer_watchdog::ReceiptWriterWatchdogHandle>,
}
#[derive(Debug, Clone)]
pub(crate) struct ReservedSiblingShare {
pub(crate) parent_token_id: String,
pub(crate) child_token_id: String,
pub(crate) share_bps: u16,
}
#[derive(Debug, Clone)]
pub(crate) enum RestartReservedHoldGate {
Clear,
PendingHolds(std::collections::HashSet<String>),
PendingOpaqueCount,
}
impl ChioKernel {
pub fn with_hybrid_signing_backend(
&mut self,
hybrid: &HybridSigningConfig,
self_quote_bytes: &[u8],
verifier: &dyn crate::boot::KernelSelfQuoteVerifier,
) -> Result<Box<dyn chio_core::crypto::SigningBackend>, crate::boot::KernelBootError> {
let backend = crate::boot::load_kernel_signing_backend_after_self_quote(
hybrid.crypto_floor,
self.config.keypair.clone(),
hybrid.pq_signing_seed.as_ref(),
self_quote_bytes,
verifier,
)?;
self.capability_crypto_floor = hybrid.crypto_floor;
Ok(backend)
}
}