praborrow_core/lib.rs
1//! Core primitives for distributed ownership enforcement.
2//!
3//! This crate provides `Sovereign<T>`, a wrapper type that tracks ownership
4//! across network boundaries. When a resource is "annexed" (moved to another node),
5//! local access is prohibited.
6//!
7//! # The Garuda Proof System
8//!
9//! With `praborrow-prover`, this crate now supports **formally verified** state
10//! transitions. Use `annex_verified()` to require SMT proof before annexation.
11//!
12//! # Safety
13//! Uses `UnsafeCell` and `AtomicU8` for interior mutability with thread-safety.
14//! The `Send`/`Sync` implementations are safe when `T` is `Send`/`Sync`.
15
16#![cfg_attr(not(feature = "std"), no_std)]
17
18extern crate alloc;
19
20use alloc::string::String;
21use core::cell::UnsafeCell;
22use core::marker::PhantomData;
23use core::ops::{Deref, DerefMut};
24use core::sync::atomic::{AtomicU8, Ordering};
25
26/// The state of a Sovereign resource.
27/// 0: Domestic (Local jurisdiction)
28/// 1: Exiled (Foreign jurisdiction - moved to another node)
29#[derive(Debug, PartialEq, Eq, Clone, Copy)]
30#[repr(u8)]
31pub enum SovereignState {
32 Domestic = 0,
33 Exiled = 1,
34}
35
36/// A token that proves a resource has been returned to domestic jurisdiction.
37///
38/// This token is required to call `Sovereign::repatriate`. It can only be constructed
39/// by trusted system components (like the lease manager) that can guarantee the
40/// resource is safe to reclaim.
41pub struct RepatriationToken {
42 _private: (),
43}
44
45impl RepatriationToken {
46 /// Creates a new repatriation token.
47 ///
48 /// # Safety
49 ///
50 /// This function is unsafe because creating a token allows the holder to
51 /// repatriate a sovereign resource. The caller must guarantee that the
52 /// resource is indeed back in domestic jurisdiction and no longer accessed
53 /// remotely.
54 pub unsafe fn new() -> Self {
55 Self { _private: () }
56 }
57}
58
59/// A wrapper that enforces ownership semantics across network boundaries.
60///
61/// "Memory safety with sovereign integrity."
62pub struct Sovereign<T> {
63 inner: UnsafeCell<T>,
64 state: AtomicU8,
65}
66
67/// Error enforcing constitutional invariants.
68#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
69pub enum ConstitutionError {
70 #[error("Invariant violated: {0}")]
71 InvariantViolation(String),
72}
73
74/// Error returned when accessing a Sovereign resource fails.
75#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
76pub enum SovereigntyError {
77 /// Resource is under foreign jurisdiction (Exiled).
78 #[error("SOVEREIGNTY VIOLATION: Resource is under foreign jurisdiction.")]
79 ForeignJurisdiction,
80}
81
82impl<T> Sovereign<T> {
83 /// Creates a new Sovereign resource under domestic jurisdiction.
84 ///
85 /// # Atomic Ordering
86 ///
87 /// Uses `SeqCst` ordering for maximum safety in distributed scenarios.
88 /// This ensures all threads see state changes in a consistent order,
89 /// which is critical for ownership semantics across network boundaries.
90 pub fn new(value: T) -> Self {
91 Self {
92 inner: UnsafeCell::new(value),
93 state: AtomicU8::new(SovereignState::Domestic as u8),
94 }
95 }
96
97 /// Creates a new Sovereign resource that is already under foreign jurisdiction.
98 ///
99 /// This is useful for nodes receiving data that has been transferred from
100 /// another node - the resource starts in an Exiled state.
101 ///
102 /// # Example
103 ///
104 /// ```
105 /// use praborrow_core::{Sovereign, SovereignState};
106 ///
107 /// let foreign_data = Sovereign::new_exiled(42i32);
108 /// assert!(foreign_data.is_exiled());
109 /// ```
110 pub fn new_exiled(value: T) -> Self {
111 Self {
112 inner: UnsafeCell::new(value),
113 state: AtomicU8::new(SovereignState::Exiled as u8),
114 }
115 }
116
117 /// Annexes the resource, moving it to foreign jurisdiction.
118 ///
119 /// Once annexed, the resource cannot be accessed locally.
120 /// Access attempts will result in a Sovereignty Violation.
121 pub fn annex(&self) -> Result<(), AnnexError> {
122 let current = self.state.load(Ordering::SeqCst);
123 if current == SovereignState::Exiled as u8 {
124 return Err(AnnexError::AlreadyExiled);
125 }
126
127 // Diplomatically transition state
128 self.state
129 .store(SovereignState::Exiled as u8, Ordering::SeqCst);
130
131 tracing::debug!(
132 from = "Domestic",
133 to = "Exiled",
134 "Resource annexed to foreign jurisdiction"
135 );
136
137 Ok(())
138 }
139
140 /// Returns a reference to the inner value without jurisdiction check.
141 ///
142 /// # Safety
143 ///
144 /// This is safe because we're returning a shared reference and the caller
145 /// is responsible for ensuring the resource is domestic. Use `try_get()`
146 /// for safe access with jurisdiction verification.
147 pub fn inner_ref(&self) -> &T {
148 // SAFETY: We're only reading, and this is safe when called from
149 // contexts that have already verified jurisdiction.
150 unsafe { &*self.inner.get() }
151 }
152
153 /// Returns the current state of the resource.
154 #[inline]
155 pub fn state(&self) -> SovereignState {
156 match self.state.load(Ordering::SeqCst) {
157 0 => SovereignState::Domestic,
158 _ => SovereignState::Exiled,
159 }
160 }
161
162 /// Returns `true` if the resource is under domestic jurisdiction.
163 #[inline]
164 pub fn is_domestic(&self) -> bool {
165 self.state.load(Ordering::SeqCst) == SovereignState::Domestic as u8
166 }
167
168 /// Returns `true` if the resource is under foreign jurisdiction (exiled).
169 #[inline]
170 pub fn is_exiled(&self) -> bool {
171 self.state.load(Ordering::SeqCst) == SovereignState::Exiled as u8
172 }
173
174 /// Attempts to get a reference to the value, returning an error if Exiled.
175 pub fn try_get(&self) -> Result<&T, SovereigntyError> {
176 if self.is_exiled() {
177 return Err(SovereigntyError::ForeignJurisdiction);
178 }
179 // SAFETY: We verified the resource is domestic.
180 unsafe { Ok(&*self.inner.get()) }
181 }
182
183 /// Attempts to get a mutable reference to the value, returning an error if Exiled.
184 pub fn try_get_mut(&mut self) -> Result<&mut T, SovereigntyError> {
185 if self.is_exiled() {
186 return Err(SovereigntyError::ForeignJurisdiction);
187 }
188 // SAFETY: We verified resource is domestic and have &mut self.
189 unsafe { Ok(&mut *self.inner.get()) }
190 }
191
192 /// Repatriates a resource, transitioning it from Exiled back to Domestic.
193 ///
194 /// Requires a `RepatriationToken` as proof that the resource is safe to reclaim.
195 ///
196 /// # Example
197 ///
198 /// ```
199 /// use praborrow_core::{Sovereign, SovereignState, RepatriationToken};
200 ///
201 /// let resource = Sovereign::new(42i32);
202 /// resource.annex().unwrap();
203 /// assert!(resource.is_exiled());
204 ///
205 /// // ... resource is sent to foreign node and returned ...
206 ///
207 /// // SAFETY: construction of token implies safety verification
208 /// let token = unsafe { RepatriationToken::new() };
209 /// resource.repatriate(token);
210 /// assert!(resource.is_domestic());
211 /// ```
212 pub fn repatriate(&self, _token: RepatriationToken) {
213 let previous = self
214 .state
215 .swap(SovereignState::Domestic as u8, Ordering::SeqCst);
216
217 if previous == SovereignState::Exiled as u8 {
218 tracing::debug!(
219 from = "Exiled",
220 to = "Domestic",
221 "Resource repatriated to domestic jurisdiction"
222 );
223 }
224 }
225
226 /// Checks if the resource is currently domestic, panicking if not.
227 ///
228 /// Used internally by Deref/DerefMut. Prefer `try_get()` for non-panicking access.
229 fn verify_jurisdiction(&self) {
230 if self.is_exiled() {
231 panic!("SOVEREIGNTY VIOLATION: Resource is under foreign jurisdiction.");
232 }
233 }
234}
235
236impl<T> Deref for Sovereign<T> {
237 type Target = T;
238
239 fn deref(&self) -> &Self::Target {
240 self.verify_jurisdiction();
241 // SAFETY: We've verified the resource is domestic, so access is valid.
242 unsafe { &*self.inner.get() }
243 }
244}
245
246impl<T> DerefMut for Sovereign<T> {
247 fn deref_mut(&mut self) -> &mut Self::Target {
248 self.verify_jurisdiction();
249 // SAFETY: We've verified the resource is domestic and have &mut self.
250 unsafe { &mut *self.inner.get() }
251 }
252}
253
254// SAFETY: Sovereign<T> is Send/Sync if T is Send/Sync, as we use AtomicU8 for state
255// and check it before access. The UnsafeCell is protected by the atomic state check.
256unsafe impl<T: Send> Send for Sovereign<T> {}
257unsafe impl<T: Sync> Sync for Sovereign<T> {}
258
259/// Protocol for enforcing constitutional invariants (runtime checks).
260///
261/// Types implementing this trait can validate their internal state against
262/// a set of invariants defined via the `#[derive(Constitution)]` macro.
263pub trait CheckProtocol {
264 /// Enforces all invariants, returning an error if any are violated.
265 ///
266 /// # Returns
267 ///
268 /// - `Ok(())` if all invariants are satisfied
269 /// - `Err(ConstitutionError)` containing a description of the violated invariant
270 ///
271 /// # Example
272 ///
273 /// ```ignore
274 /// use praborrow_core::CheckProtocol;
275 ///
276 /// let data = MyStruct { value: -1 };
277 /// match data.enforce_law() {
278 /// Ok(()) => println!("All invariants satisfied"),
279 /// Err(e) => println!("Invariant violated: {}", e),
280 /// }
281 /// ```
282 fn enforce_law(&self) -> Result<(), ConstitutionError>;
283}
284
285/// A value carrying cryptographic proof of verification.
286///
287/// This type can only be constructed by successful SMT verification.
288/// Its existence in a type signature proves that formal verification occurred.
289///
290/// # Type Safety Guarantee
291///
292/// `ProofCarrying<T>` cannot be forged - the private `_proof` field
293/// ensures only the prover crate can construct it.
294#[derive(Debug)]
295pub struct ProofCarrying<T> {
296 /// The carried value.
297 pub value: T,
298 /// Private marker ensuring construction only via verification.
299 _proof: PhantomData<()>,
300}
301
302impl<T> ProofCarrying<T> {
303 /// Creates a new proof-carrying value.
304 ///
305 /// This should only be called after successful verification.
306 #[doc(hidden)]
307 pub fn new_unchecked(value: T) -> Self {
308 Self {
309 value,
310 _proof: PhantomData,
311 }
312 }
313
314 /// Extracts the inner value, consuming the proof.
315 pub fn into_inner(self) -> T {
316 self.value
317 }
318}
319
320impl<T: Clone> Clone for ProofCarrying<T> {
321 fn clone(&self) -> Self {
322 Self {
323 value: self.value.clone(),
324 _proof: PhantomData,
325 }
326 }
327}
328
329/// Error type for verified annexation operations.
330#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
331pub enum AnnexError {
332 /// Resource is already under foreign jurisdiction.
333 #[error("Resource is already under foreign jurisdiction")]
334 AlreadyExiled,
335 /// SMT verification failed.
336 #[error("Verification failed: {0}")]
337 VerificationFailed(String),
338 /// Prover encountered an error.
339 #[error("Prover error: {0}")]
340 ProverError(String),
341}
342
343/// Error returned when a lease operation fails.
344#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
345pub enum LeaseError {
346 /// Resource is already leased to another holder.
347 #[error("Resource is already leased to another holder")]
348 AlreadyLeased,
349 /// Resource is under foreign jurisdiction.
350 #[error("Resource is under foreign jurisdiction")]
351 ForeignJurisdiction,
352}
353
354/// Represents a lease on a Sovereign resource.
355pub struct Lease<T> {
356 /// The holder's unique identifier.
357 pub holder: u128,
358 /// Duration of the lease.
359 pub duration: core::time::Duration,
360 /// Phantom data for the resource type.
361 _phantom: PhantomData<T>,
362}
363
364impl<T> Lease<T> {
365 /// Creates a new lease.
366 ///
367 /// # Duration Validation
368 ///
369 /// If `duration` is zero, it will be coerced to a minimum of 1 millisecond
370 /// to prevent immediate expiration edge cases.
371 pub fn new(holder: u128, duration: core::time::Duration) -> Self {
372 // Prevent zero-duration leases which could cause immediate expiration
373 let duration = if duration.is_zero() {
374 tracing::warn!(
375 holder = holder,
376 "Zero-duration lease requested, coercing to 1ms minimum"
377 );
378 core::time::Duration::from_millis(1)
379 } else {
380 duration
381 };
382
383 Self {
384 holder,
385 duration,
386 _phantom: PhantomData,
387 }
388 }
389
390 /// Returns the duration of the lease.
391 #[inline]
392 pub fn duration(&self) -> core::time::Duration {
393 self.duration
394 }
395
396 /// Returns the holder ID.
397 #[inline]
398 pub fn holder(&self) -> u128 {
399 self.holder
400 }
401}
402
403/// Trait for distributed borrow operations.
404pub trait DistributedBorrow<T> {
405 /// Attempt to acquire a lease on the resource.
406 fn try_hire(
407 &self,
408 candidate_id: u128,
409 term: core::time::Duration,
410 ) -> Result<Lease<T>, LeaseError>;
411}
412
413impl<T> DistributedBorrow<T> for Sovereign<T> {
414 fn try_hire(
415 &self,
416 candidate_id: u128,
417 term: core::time::Duration,
418 ) -> Result<Lease<T>, LeaseError> {
419 let current = self.state.load(Ordering::SeqCst);
420 if current == SovereignState::Exiled as u8 {
421 return Err(LeaseError::AlreadyLeased);
422 }
423
424 // Transition to exiled state (leased)
425 self.state
426 .store(SovereignState::Exiled as u8, Ordering::SeqCst);
427 Ok(Lease::<T>::new(candidate_id, term))
428 }
429}
430
431/// Extension trait for Sovereign types whose inner types implement formal verification.
432///
433/// This trait is automatically implemented for `Sovereign<T>` where `T` can be
434/// formally verified via the Garuda Proof System.
435pub trait VerifiedAnnex<T> {
436 /// Annexes the resource after successful formal verification.
437 ///
438 /// Unlike `annex()`, this method requires mathematical proof that all
439 /// invariants are satisfied before the state transition occurs.
440 ///
441 /// # Returns
442 ///
443 /// - `Ok(ProofCarrying<()>)` - Verification passed, resource is now Exiled
444 /// - `Err(AnnexError)` - Verification failed or resource already Exiled
445 ///
446 /// # Example
447 ///
448 /// ```ignore
449 /// use praborrow_core::{Sovereign, VerifiedAnnex};
450 ///
451 /// let resource = Sovereign::new(MyVerifiableStruct { balance: 100 });
452 ///
453 /// // This will run SMT verification before annexing
454 /// match resource.annex_verified() {
455 /// Ok(proof) => println!("Annexation proven safe!"),
456 /// Err(e) => println!("Cannot annex: {}", e),
457 /// }
458 /// ```
459 fn annex_verified(&self) -> Result<ProofCarrying<()>, AnnexError>;
460}
461
462// Note: The actual implementation of VerifiedAnnex requires praborrow-prover,
463// which would create a circular dependency. Instead, the implementation is
464// provided via blanket impl in praborrow-prover or via the facade crate.
465//
466// Users should use the `praborrow` facade crate for full functionality.
467
468#[cfg(test)]
469mod tests {
470 use super::*;
471
472 #[test]
473 fn test_sovereign_new() {
474 let s = Sovereign::new(42i32);
475 assert_eq!(s.state(), SovereignState::Domestic);
476 assert!(s.is_domestic());
477 assert!(!s.is_exiled());
478 }
479
480 #[test]
481 fn test_sovereign_new_exiled() {
482 let s = Sovereign::new_exiled(42i32);
483 assert_eq!(s.state(), SovereignState::Exiled);
484 assert!(s.is_exiled());
485 assert!(!s.is_domestic());
486 }
487
488 #[test]
489 fn test_sovereign_deref() {
490 let s = Sovereign::new(42i32);
491 assert_eq!(*s, 42);
492 }
493
494 #[test]
495 fn test_sovereign_deref_mut() {
496 let mut s = Sovereign::new(42i32);
497 *s = 100;
498 assert_eq!(*s, 100);
499 }
500
501 #[test]
502 fn test_sovereign_annex() {
503 let s = Sovereign::new(42i32);
504 assert!(s.annex().is_ok());
505 assert_eq!(s.state(), SovereignState::Exiled);
506 assert!(s.is_exiled());
507 }
508
509 #[test]
510 fn test_sovereign_double_annex() {
511 let s = Sovereign::new(42i32);
512 assert!(s.annex().is_ok());
513 assert!(s.annex().is_err());
514 }
515
516 #[test]
517 fn test_sovereign_repatriate() {
518 let s = Sovereign::new(42i32);
519 s.annex().unwrap();
520 assert!(s.is_exiled());
521
522 // SAFETY: In test context, we control both sides
523 // SAFETY: In test context, we control both sides
524 let token = unsafe { RepatriationToken::new() };
525 s.repatriate(token);
526 assert!(s.is_domestic());
527
528 // Should be able to access again
529 assert_eq!(*s, 42);
530 }
531
532 #[test]
533 #[should_panic(expected = "SOVEREIGNTY VIOLATION")]
534 fn test_sovereignty_violation() {
535 let s = Sovereign::new(42i32);
536 s.annex().unwrap();
537 let _ = *s; // This should panic
538 }
539
540 #[test]
541 fn test_try_get_domestic() {
542 let s = Sovereign::new(42i32);
543 assert_eq!(*s.try_get().unwrap(), 42);
544 }
545
546 #[test]
547 fn test_try_get_exiled() {
548 let s = Sovereign::new(42i32);
549 s.annex().unwrap();
550 assert!(matches!(
551 s.try_get(),
552 Err(SovereigntyError::ForeignJurisdiction)
553 ));
554 }
555
556 #[test]
557 fn test_proof_carrying() {
558 let proof = ProofCarrying::new_unchecked(42i32);
559 assert_eq!(proof.value, 42);
560 assert_eq!(proof.into_inner(), 42);
561 }
562
563 #[test]
564 fn test_annex_error_display() {
565 let e = AnnexError::AlreadyExiled;
566 assert!(e.to_string().contains("foreign jurisdiction"));
567
568 let e = AnnexError::VerificationFailed("test".to_string());
569 assert!(e.to_string().contains("test"));
570 }
571
572 #[test]
573 fn test_lease_zero_duration_coercion() {
574 let lease = Lease::<i32>::new(1, core::time::Duration::ZERO);
575 assert_eq!(lease.duration(), core::time::Duration::from_millis(1));
576 }
577
578 #[test]
579 fn test_lease_normal_duration() {
580 let duration = core::time::Duration::from_secs(10);
581 let lease = Lease::<i32>::new(1, duration);
582 assert_eq!(lease.duration(), duration);
583 assert_eq!(lease.holder(), 1);
584 }
585}