Skip to main content

bcx_model/
lib.rs

1#![no_std]
2#![doc = "Causal operation model types for BCX."]
3
4mod event;
5mod statement;
6mod truth;
7
8pub use event::{
9    AdmissionResult, CauseCapsule, CauseCapsuleParts, CauseKind, EffectResult, OperationAction,
10    RelationshipKind,
11};
12pub use statement::{
13    Admission, Checkpoint, Contradiction, Delegation, Effect, Intent, Revocation, StatementKind,
14};
15pub use truth::{AssuranceLevel, TruthStatus};
16
17#[cfg(test)]
18mod tests {
19    use super::*;
20    use bcx_core::{
21        CapabilityRef, CheckpointId, Digest, EventId, PolicyId, StatementId, SubjectId,
22        ValidationError,
23    };
24    use bcx_wire::WireLimits;
25
26    fn event(byte: u8) -> Result<EventId, ValidationError> {
27        EventId::new(Digest::new([byte; Digest::LEN]))
28    }
29
30    fn statement(byte: u8) -> Result<StatementId, ValidationError> {
31        StatementId::new(&[byte; Digest::LEN])
32    }
33
34    fn subject(bytes: &[u8]) -> Result<SubjectId, ValidationError> {
35        SubjectId::new(bytes)
36    }
37
38    fn policy(bytes: &[u8]) -> Result<PolicyId, ValidationError> {
39        PolicyId::new(bytes)
40    }
41
42    fn capability(byte: u8) -> Result<CapabilityRef, ValidationError> {
43        CapabilityRef::new(Digest::new([byte; Digest::LEN]))
44    }
45
46    fn checkpoint(byte: u8) -> Result<CheckpointId, ValidationError> {
47        CheckpointId::new(&[byte; Digest::LEN])
48    }
49
50    #[test]
51    fn cause_capsule_rejects_empty_parents() -> Result<(), ValidationError> {
52        assert_eq!(
53            CauseCapsule::new(
54                CauseCapsuleParts {
55                    event_id: event(1)?,
56                    parents: &[],
57                    relationship: RelationshipKind::CausedBy,
58                    cause_kind: CauseKind::ApplicationAction,
59                    action: OperationAction::Execute,
60                    authority: None,
61                    policy_epoch: None,
62                },
63                WireLimits::UNSAFE_DEVELOPMENT_DO_NOT_USE_IN_PRODUCTION,
64            ),
65            Err(ValidationError::Empty)
66        );
67        Ok(())
68    }
69
70    #[test]
71    fn cause_capsule_rejects_too_many_parents() -> Result<(), ValidationError> {
72        let parents = [event(2)?, event(3)?];
73        let limits = WireLimits::new(1, 1, 1, 1)?;
74
75        assert_eq!(
76            CauseCapsule::new(
77                CauseCapsuleParts {
78                    event_id: event(1)?,
79                    parents: &parents,
80                    relationship: RelationshipKind::JoinedFrom,
81                    cause_kind: CauseKind::ApplicationAction,
82                    action: OperationAction::Execute,
83                    authority: None,
84                    policy_epoch: None,
85                },
86                limits,
87            ),
88            Err(ValidationError::TooLarge)
89        );
90        Ok(())
91    }
92
93    #[test]
94    fn cause_capsule_rejects_self_referential_parent() -> Result<(), ValidationError> {
95        let event_id = event(1)?;
96        let parents = [event_id];
97
98        assert_eq!(
99            CauseCapsule::new(
100                CauseCapsuleParts {
101                    event_id,
102                    parents: &parents,
103                    relationship: RelationshipKind::CausedBy,
104                    cause_kind: CauseKind::ApplicationAction,
105                    action: OperationAction::Execute,
106                    authority: None,
107                    policy_epoch: None,
108                },
109                WireLimits::UNSAFE_DEVELOPMENT_DO_NOT_USE_IN_PRODUCTION,
110            ),
111            Err(ValidationError::Malformed)
112        );
113        Ok(())
114    }
115
116    #[test]
117    fn statement_body_kinds_match_constructors() -> Result<(), ValidationError> {
118        let intent = Intent::new(
119            statement(1)?,
120            subject(b"invoice:123")?,
121            OperationAction::Create,
122        );
123        let admission = Admission::new(
124            statement(2)?,
125            statement(1)?,
126            policy(b"strict")?,
127            AdmissionResult::Allow,
128        )?;
129        let effect = Effect::new(statement(3)?, statement(1)?, EffectResult::Completed)?;
130        let delegation = Delegation::new(
131            statement(4)?,
132            subject(b"issuer")?,
133            subject(b"executor")?,
134            capability(5)?,
135        )?;
136        let revocation = Revocation::new(statement(6)?, statement(4)?, capability(7)?)?;
137        let checkpoint = Checkpoint::new(
138            statement(8)?,
139            checkpoint(9)?,
140            subject(b"ledger:checkpoint")?,
141        );
142        let contradiction = Contradiction::new(statement(10)?, statement(2)?, statement(3)?)?;
143
144        assert_eq!(intent.kind(), StatementKind::Intent);
145        assert_eq!(admission.kind(), StatementKind::Admission);
146        assert_eq!(effect.kind(), StatementKind::Effect);
147        assert_eq!(delegation.kind(), StatementKind::Delegation);
148        assert_eq!(revocation.kind(), StatementKind::Revocation);
149        assert_eq!(checkpoint.kind(), StatementKind::Checkpoint);
150        assert_eq!(contradiction.kind(), StatementKind::Contradiction);
151        Ok(())
152    }
153
154    #[test]
155    fn statement_body_validation_rejects_self_references() -> Result<(), ValidationError> {
156        assert_eq!(
157            Admission::new(
158                statement(1)?,
159                statement(1)?,
160                policy(b"strict")?,
161                AdmissionResult::Allow,
162            ),
163            Err(ValidationError::Malformed)
164        );
165        assert_eq!(
166            Effect::new(statement(2)?, statement(2)?, EffectResult::Completed),
167            Err(ValidationError::Malformed)
168        );
169        assert_eq!(
170            Revocation::new(statement(3)?, statement(3)?, capability(4)?),
171            Err(ValidationError::Malformed)
172        );
173        assert_eq!(
174            Contradiction::new(statement(5)?, statement(6)?, statement(6)?),
175            Err(ValidationError::Malformed)
176        );
177        Ok(())
178    }
179
180    #[test]
181    fn delegation_rejects_same_subject() -> Result<(), ValidationError> {
182        assert_eq!(
183            Delegation::new(
184                statement(1)?,
185                subject(b"same")?,
186                subject(b"same")?,
187                capability(2)?,
188            ),
189            Err(ValidationError::Malformed)
190        );
191        Ok(())
192    }
193}