liminal_protocol/algebra/
capacity.rs1use super::types::{
2 BaselineError, MandatoryCapacity, RecoveryTransfer, RecoveryTransferError, ResourceDimension,
3 ResourceVector, WideResourceVector, widen_u64,
4};
5
6pub const fn retained_baseline(
16 retained_charge: ResourceVector,
17 identity_slots: u64,
18 marker_credits: u64,
19 marker_max: ResourceVector,
20) -> Result<WideResourceVector, BaselineError> {
21 if marker_credits > identity_slots {
22 return Err(BaselineError::MarkerCreditsExceedIdentitySlots {
23 identity_slots,
24 marker_credits,
25 });
26 }
27
28 let uncredited_slots = widen_u64(identity_slots) - widen_u64(marker_credits);
29 let marker_entries = uncredited_slots * widen_u64(marker_max.entries);
30 let marker_bytes = uncredited_slots * widen_u64(marker_max.bytes);
31 Ok(WideResourceVector::new(
32 widen_u64(retained_charge.entries) + marker_entries,
33 widen_u64(retained_charge.bytes) + marker_bytes,
34 ))
35}
36
37#[must_use]
42pub const fn zero_debt_capacity_failure(
43 baseline: WideResourceVector,
44 mandatory_bound: ResourceVector,
45 recovery_claim: ResourceVector,
46 configured_cap: ResourceVector,
47) -> Option<ResourceDimension> {
48 if !component_fits(
49 baseline.entries,
50 mandatory_bound.entries,
51 recovery_claim.entries,
52 configured_cap.entries,
53 ) {
54 return Some(ResourceDimension::Entries);
55 }
56 if !component_fits(
57 baseline.bytes,
58 mandatory_bound.bytes,
59 recovery_claim.bytes,
60 configured_cap.bytes,
61 ) {
62 return Some(ResourceDimension::Bytes);
63 }
64 None
65}
66
67#[must_use]
69pub const fn zero_debt_admission(
70 baseline: WideResourceVector,
71 mandatory_bound: ResourceVector,
72 recovery_claim: ResourceVector,
73 configured_cap: ResourceVector,
74) -> bool {
75 zero_debt_capacity_failure(baseline, mandatory_bound, recovery_claim, configured_cap).is_none()
76}
77
78#[must_use]
84pub const fn mandatory_capacity(
85 resulting_baseline: WideResourceVector,
86 mandatory_bound: ResourceVector,
87 remaining_recovery_claim: ResourceVector,
88 configured_cap: ResourceVector,
89) -> MandatoryCapacity {
90 let entries = mandatory_component(
91 resulting_baseline.entries,
92 mandatory_bound.entries,
93 remaining_recovery_claim.entries,
94 configured_cap.entries,
95 );
96 let bytes = mandatory_component(
97 resulting_baseline.bytes,
98 mandatory_bound.bytes,
99 remaining_recovery_claim.bytes,
100 configured_cap.bytes,
101 );
102
103 MandatoryCapacity {
104 debt: WideResourceVector::new(entries.debt, bytes.debt),
105 absolute_fit: entries.absolute_fit && bytes.absolute_fit,
106 debt_within_mandatory_bound: entries.debt_within_bound && bytes.debt_within_bound,
107 }
108}
109
110pub const fn recovery_transfer(
120 baseline_after_removals: WideResourceVector,
121 remaining_recovery_claim: ResourceVector,
122 charge: ResourceVector,
123) -> Result<RecoveryTransfer, RecoveryTransferError> {
124 if charge.entries > remaining_recovery_claim.entries {
125 return Err(RecoveryTransferError {
126 dimension: ResourceDimension::Entries,
127 });
128 }
129 if charge.bytes > remaining_recovery_claim.bytes {
130 return Err(RecoveryTransferError {
131 dimension: ResourceDimension::Bytes,
132 });
133 }
134
135 let Some(entries) = baseline_after_removals
136 .entries
137 .checked_add(widen_u64(charge.entries))
138 else {
139 return Err(RecoveryTransferError {
140 dimension: ResourceDimension::Entries,
141 });
142 };
143 let Some(bytes) = baseline_after_removals
144 .bytes
145 .checked_add(widen_u64(charge.bytes))
146 else {
147 return Err(RecoveryTransferError {
148 dimension: ResourceDimension::Bytes,
149 });
150 };
151
152 Ok(RecoveryTransfer {
153 baseline: WideResourceVector::new(entries, bytes),
154 remaining_recovery_claim: ResourceVector::new(
155 remaining_recovery_claim.entries - charge.entries,
156 remaining_recovery_claim.bytes - charge.bytes,
157 ),
158 })
159}
160
161#[must_use]
163pub const fn no_edge_legal(
164 debt: WideResourceVector,
165 baseline: WideResourceVector,
166 mandatory_bound: ResourceVector,
167 full_recovery_claim: ResourceVector,
168 configured_cap: ResourceVector,
169) -> bool {
170 debt.is_zero()
171 && zero_debt_admission(
172 baseline,
173 mandatory_bound,
174 full_recovery_claim,
175 configured_cap,
176 )
177}
178
179const fn component_fits(baseline: u128, q: u64, k: u64, cap: u64) -> bool {
180 let Some(with_q) = baseline.checked_add(widen_u64(q)) else {
181 return false;
182 };
183 let Some(required) = with_q.checked_add(widen_u64(k)) else {
184 return false;
185 };
186 required <= widen_u64(cap)
187}
188
189struct MandatoryComponent {
190 debt: u128,
191 absolute_fit: bool,
192 debt_within_bound: bool,
193}
194
195const fn mandatory_component(baseline: u128, q: u64, k: u64, cap: u64) -> MandatoryComponent {
196 let q = widen_u64(q);
197 let k = widen_u64(k);
198 let cap = widen_u64(cap);
199 let debt = match baseline.checked_add(q) {
200 Some(with_q) => match with_q.checked_add(k) {
201 Some(required) => required.saturating_sub(cap),
202 None => u128::MAX,
203 },
204 None => u128::MAX,
205 };
206 let absolute_fit = match baseline.checked_add(k) {
207 Some(required) => required <= cap,
208 None => false,
209 };
210 MandatoryComponent {
211 debt,
212 absolute_fit,
213 debt_within_bound: debt <= q,
214 }
215}