1use alloc::{boxed::Box, vec::Vec};
10
11use crate::{
12 algebra::ResourceVector,
13 outcome::CandidatePhase,
14 wire::{
15 BindingEpoch, ClosureCheckedEnvelope, DeliverySeq, OrderAllocatingEnvelope,
16 RecordAdmission, RecordAdmissionEnvelope, RecordAdmissionResponse, RecordCommitted,
17 SequenceAllocatingEnvelope, TransactionOrder,
18 },
19};
20
21use super::{
22 super::{
23 AdmissionOrder, BindingRequiredLookupResult, BindingState, CapacityCounter, ClaimFrontiers,
24 ClosureAccounting, ClosureState, ConnectionConversationCapacityCommit,
25 ConnectionConversationTracking, ImmutableSequenceCandidate, ObserverCheckedOperation,
26 ObserverFloorDecision, ObserverFloorPermit, OrderAdmissionError, OrderAllocation,
27 ParticipantBindingRequest, PresentedIdentity, RemainingClosureDecision,
28 RemainingClosurePermit, RequiredCapacityPlan, RequiredCapacityPlanError,
29 SemanticConnectionCapacityDecision, SequenceAdmission, SequenceAdmissionError, StoredEdge,
30 admit_sequence, allocate_order, check_observer_floor, check_record_size,
31 check_remaining_closure, lookup_binding_required, select_semantic_connection_capacity,
32 },
33 OrdinaryProjectionError, OrdinaryProjectionLimits, OrdinaryRecordProjectionDecision,
34 OrdinaryRecordProjectionInput, ProjectedOrdinaryRecord, RetainedRecordCharge,
35};
36
37#[derive(Debug)]
43pub struct RecordAdmissionPrestate<'a, EF, V, LF> {
44 request: RecordAdmission,
45 presented_identity: PresentedIdentity<'a, EF, V, LF>,
46 binding: &'a BindingState,
47 receiving_binding_epoch: BindingEpoch,
48 connection_tracking: ConnectionConversationTracking,
49 connection_capacity: CapacityCounter,
50 closure_accounting: ClosureAccounting,
51 max_ordinary_record_charge: ResourceVector,
52 frontiers: ClaimFrontiers,
53 retained_charges: Vec<RetainedRecordCharge>,
54 observer_progress: DeliverySeq,
55 projection_limits: OrdinaryProjectionLimits,
56}
57
58impl<'a, EF, V, LF> RecordAdmissionPrestate<'a, EF, V, LF> {
59 #[allow(clippy::too_many_arguments)]
62 #[must_use]
63 pub const fn new(
64 request: RecordAdmission,
65 presented_identity: PresentedIdentity<'a, EF, V, LF>,
66 binding: &'a BindingState,
67 receiving_binding_epoch: BindingEpoch,
68 connection_tracking: ConnectionConversationTracking,
69 connection_capacity: CapacityCounter,
70 closure_accounting: ClosureAccounting,
71 max_ordinary_record_charge: ResourceVector,
72 frontiers: ClaimFrontiers,
73 retained_charges: Vec<RetainedRecordCharge>,
74 observer_progress: DeliverySeq,
75 projection_limits: OrdinaryProjectionLimits,
76 ) -> Self {
77 Self {
78 request,
79 presented_identity,
80 binding,
81 receiving_binding_epoch,
82 connection_tracking,
83 connection_capacity,
84 closure_accounting,
85 max_ordinary_record_charge,
86 frontiers,
87 retained_charges,
88 observer_progress,
89 projection_limits,
90 }
91 }
92
93 #[must_use]
95 pub const fn request(&self) -> &RecordAdmission {
96 &self.request
97 }
98
99 #[must_use]
101 pub const fn binding(&self) -> &BindingState {
102 self.binding
103 }
104
105 #[must_use]
107 pub const fn receiving_binding_epoch(&self) -> BindingEpoch {
108 self.receiving_binding_epoch
109 }
110
111 #[must_use]
113 pub const fn frontiers(&self) -> &ClaimFrontiers {
114 &self.frontiers
115 }
116
117 #[must_use]
119 pub const fn connection_capacity(&self) -> CapacityCounter {
120 self.connection_capacity
121 }
122
123 #[must_use]
125 pub const fn closure_accounting(&self) -> ClosureAccounting {
126 self.closure_accounting
127 }
128
129 #[must_use]
131 pub const fn observer_progress(&self) -> DeliverySeq {
132 self.observer_progress
133 }
134
135 pub(super) fn into_live_owner_parts(
136 self,
137 ) -> (
138 RecordAdmission,
139 ClaimFrontiers,
140 ClosureAccounting,
141 Vec<RetainedRecordCharge>,
142 ) {
143 (
144 self.request,
145 self.frontiers,
146 self.closure_accounting,
147 self.retained_charges,
148 )
149 }
150
151 #[must_use]
153 pub fn retained_charges(&self) -> &[RetainedRecordCharge] {
154 &self.retained_charges
155 }
156}
157
158#[derive(Debug)]
160pub struct UnchangedRecordAdmission<'a, EF, V, LF> {
161 prestate: RecordAdmissionPrestate<'a, EF, V, LF>,
162 encoded_record_charge: ResourceVector,
163}
164
165impl<'a, EF, V, LF> UnchangedRecordAdmission<'a, EF, V, LF> {
166 const fn new(
167 prestate: RecordAdmissionPrestate<'a, EF, V, LF>,
168 encoded_record_charge: ResourceVector,
169 ) -> Self {
170 Self {
171 prestate,
172 encoded_record_charge,
173 }
174 }
175
176 #[must_use]
178 pub const fn prestate(&self) -> &RecordAdmissionPrestate<'a, EF, V, LF> {
179 &self.prestate
180 }
181
182 #[must_use]
184 pub const fn encoded_record_charge(&self) -> ResourceVector {
185 self.encoded_record_charge
186 }
187
188 #[must_use]
190 pub fn into_parts(self) -> (RecordAdmissionPrestate<'a, EF, V, LF>, ResourceVector) {
191 (self.prestate, self.encoded_record_charge)
192 }
193}
194
195#[derive(Debug)]
197pub struct RecordAdmissionRefusal<'a, EF, V, LF> {
198 response: RecordAdmissionResponse,
199 unchanged: UnchangedRecordAdmission<'a, EF, V, LF>,
200}
201
202impl<'a, EF, V, LF> RecordAdmissionRefusal<'a, EF, V, LF> {
203 #[must_use]
205 pub const fn response(&self) -> &RecordAdmissionResponse {
206 &self.response
207 }
208
209 #[must_use]
211 pub const fn unchanged(&self) -> &UnchangedRecordAdmission<'a, EF, V, LF> {
212 &self.unchanged
213 }
214
215 #[must_use]
217 pub fn into_parts(
218 self,
219 ) -> (
220 RecordAdmissionResponse,
221 UnchangedRecordAdmission<'a, EF, V, LF>,
222 ) {
223 (self.response, self.unchanged)
224 }
225}
226
227#[derive(Debug)]
229pub struct RecordAdmissionDrainFirst<'a, EF, V, LF> {
230 candidate: ImmutableSequenceCandidate,
231 unchanged: UnchangedRecordAdmission<'a, EF, V, LF>,
232}
233
234impl<'a, EF, V, LF> RecordAdmissionDrainFirst<'a, EF, V, LF> {
235 #[must_use]
237 pub const fn candidate(&self) -> ImmutableSequenceCandidate {
238 self.candidate
239 }
240
241 #[must_use]
243 pub const fn unchanged(&self) -> &UnchangedRecordAdmission<'a, EF, V, LF> {
244 &self.unchanged
245 }
246
247 #[must_use]
249 pub fn into_parts(
250 self,
251 ) -> (
252 ImmutableSequenceCandidate,
253 UnchangedRecordAdmission<'a, EF, V, LF>,
254 ) {
255 (self.candidate, self.unchanged)
256 }
257}
258
259#[derive(Clone, Debug, PartialEq, Eq)]
261pub struct CommittedOrdinaryRecord {
262 request: RecordAdmission,
263 admission_order: AdmissionOrder,
264 delivery_seq: DeliverySeq,
265 encoded_record_charge: ResourceVector,
266}
267
268impl CommittedOrdinaryRecord {
269 #[must_use]
271 pub const fn request(&self) -> &RecordAdmission {
272 &self.request
273 }
274
275 #[must_use]
277 pub const fn admission_order(&self) -> AdmissionOrder {
278 self.admission_order
279 }
280
281 #[must_use]
283 pub const fn delivery_seq(&self) -> DeliverySeq {
284 self.delivery_seq
285 }
286
287 #[must_use]
289 pub const fn encoded_record_charge(&self) -> ResourceVector {
290 self.encoded_record_charge
291 }
292
293 const fn new(
294 request: RecordAdmission,
295 transaction_order: TransactionOrder,
296 delivery_seq: DeliverySeq,
297 encoded_record_charge: ResourceVector,
298 ) -> Self {
299 let participant_id = request.participant_id;
300 Self {
301 request,
302 admission_order: AdmissionOrder::new(
303 transaction_order,
304 CandidatePhase::OrdinaryRecord,
305 participant_id,
306 ),
307 delivery_seq,
308 encoded_record_charge,
309 }
310 }
311}
312
313#[derive(Debug, PartialEq, Eq)]
315pub struct RecordAdmissionCommit {
316 outcome: RecordCommitted,
317 record: CommittedOrdinaryRecord,
318 connection_capacity: ConnectionConversationCapacityCommit,
319 projection: Box<ProjectedOrdinaryRecord>,
320}
321
322#[derive(Debug)]
331pub struct RecordAdmissionPersistenceParts {
332 pub outcome: RecordCommitted,
334 pub record: CommittedOrdinaryRecord,
336 pub connection_capacity: ConnectionConversationCapacityCommit,
338 pub order: OrderAllocation,
340 pub sequence: SequenceAdmission,
342 pub observer_floor: ObserverFloorPermit,
344 pub closure: RemainingClosurePermit,
346 pub frontiers: ClaimFrontiers,
348 pub floor: crate::algebra::FloorComputation,
350 pub retained_charge: crate::algebra::WideResourceVector,
352 pub baseline: crate::algebra::WideResourceVector,
354 pub accounting: ClosureAccounting,
356 pub required_capacity: RequiredCapacityPlan,
358 pub caller_record: super::super::RetainedCausalRecord,
360 pub caller_charge: RetainedRecordCharge,
362 pub retained_charges: Vec<RetainedRecordCharge>,
364 pub marker_candidates: Vec<super::super::MarkerCandidateAuthority>,
366}
367
368impl RecordAdmissionCommit {
369 #[must_use]
371 pub const fn outcome(&self) -> &RecordCommitted {
372 &self.outcome
373 }
374
375 #[must_use]
377 pub const fn record(&self) -> &CommittedOrdinaryRecord {
378 &self.record
379 }
380
381 #[must_use]
383 pub const fn connection_capacity(&self) -> ConnectionConversationCapacityCommit {
384 self.connection_capacity
385 }
386
387 #[must_use]
389 pub const fn order(&self) -> OrderAllocation {
390 self.projection.order()
391 }
392
393 #[must_use]
395 pub const fn sequence(&self) -> SequenceAdmission {
396 self.projection.sequence()
397 }
398
399 #[must_use]
401 pub const fn observer_floor(&self) -> ObserverFloorPermit {
402 self.projection.observer_floor()
403 }
404
405 #[must_use]
407 pub const fn closure(&self) -> &RemainingClosurePermit {
408 &self.projection.closure
409 }
410
411 #[must_use]
413 pub const fn projection(&self) -> &ProjectedOrdinaryRecord {
414 &self.projection
415 }
416
417 #[must_use]
420 pub fn into_persistence_parts(self) -> RecordAdmissionPersistenceParts {
421 let ProjectedOrdinaryRecord {
422 frontiers,
423 floor,
424 retained_charge,
425 baseline,
426 accounting,
427 required_capacity,
428 order,
429 sequence,
430 observer_floor,
431 closure,
432 caller_record,
433 caller_charge,
434 retained_charges,
435 new_marker_candidates,
436 } = *self.projection;
437 RecordAdmissionPersistenceParts {
438 outcome: self.outcome,
439 record: self.record,
440 connection_capacity: self.connection_capacity,
441 order,
442 sequence,
443 observer_floor,
444 closure,
445 frontiers,
446 floor,
447 retained_charge,
448 baseline,
449 accounting,
450 required_capacity,
451 caller_record,
452 caller_charge,
453 retained_charges,
454 marker_candidates: new_marker_candidates,
455 }
456 }
457}
458
459#[derive(Clone, Debug, PartialEq, Eq)]
461pub enum RecordAdmissionFault {
462 Projection(OrdinaryProjectionError),
464 Order(OrderAdmissionError),
466 Sequence(SequenceAdmissionError),
468 RequiredCapacity(RequiredCapacityPlanError),
470 RefusalInvariant,
472}
473
474#[derive(Debug)]
476pub struct RecordAdmissionFailure<'a, EF, V, LF> {
477 fault: RecordAdmissionFault,
478 unchanged: UnchangedRecordAdmission<'a, EF, V, LF>,
479}
480
481impl<'a, EF, V, LF> RecordAdmissionFailure<'a, EF, V, LF> {
482 #[must_use]
484 pub const fn fault(&self) -> &RecordAdmissionFault {
485 &self.fault
486 }
487
488 #[must_use]
490 pub const fn unchanged(&self) -> &UnchangedRecordAdmission<'a, EF, V, LF> {
491 &self.unchanged
492 }
493
494 #[must_use]
496 pub fn into_parts(
497 self,
498 ) -> (
499 RecordAdmissionFault,
500 UnchangedRecordAdmission<'a, EF, V, LF>,
501 ) {
502 (self.fault, self.unchanged)
503 }
504}
505
506#[derive(Debug)]
508pub enum RecordAdmissionDecision<'a, EF, V, LF> {
509 Respond(Box<RecordAdmissionRefusal<'a, EF, V, LF>>),
511 DrainFirst(Box<RecordAdmissionDrainFirst<'a, EF, V, LF>>),
513 Commit(Box<RecordAdmissionCommit>),
515 Fault(Box<RecordAdmissionFailure<'a, EF, V, LF>>),
517}
518
519#[must_use]
530pub fn classify_record_admission_binding<EF, V, LF>(
531 presented_identity: PresentedIdentity<'_, EF, V, LF>,
532 binding: &BindingState,
533 receiving_binding_epoch: BindingEpoch,
534 request: &RecordAdmission,
535) -> Option<RecordAdmissionResponse> {
536 let lookup_request = ParticipantBindingRequest::RecordAdmission(request.clone());
537 match lookup_binding_required(
538 presented_identity,
539 binding,
540 Some(receiving_binding_epoch),
541 &lookup_request,
542 ) {
543 BindingRequiredLookupResult::Retired(value) => {
544 Some(RecordAdmissionResponse::from_retired(value))
545 }
546 BindingRequiredLookupResult::ParticipantUnknown(value) => {
547 Some(RecordAdmissionResponse::from_participant_unknown(value))
548 }
549 BindingRequiredLookupResult::StaleAuthority(value) => {
550 Some(RecordAdmissionResponse::from_stale_authority(value))
551 }
552 BindingRequiredLookupResult::NoBinding(value) => {
553 Some(RecordAdmissionResponse::from_no_binding(value))
554 }
555 BindingRequiredLookupResult::Authorized { .. } => None,
556 }
557}
558
559#[must_use]
566#[allow(
567 clippy::too_many_lines,
568 reason = "the operation keeps the frozen total selector order visible in one function"
569)]
570pub fn apply_record_admission<EF, V, LF>(
571 input: RecordAdmissionPrestate<'_, EF, V, LF>,
572 encoded_record_charge: ResourceVector,
573) -> RecordAdmissionDecision<'_, EF, V, LF> {
574 let envelope = record_envelope(&input.request);
575
576 let lookup_request = ParticipantBindingRequest::RecordAdmission(input.request.clone());
577 match lookup_binding_required(
578 input.presented_identity,
579 input.binding,
580 Some(input.receiving_binding_epoch),
581 &lookup_request,
582 ) {
583 BindingRequiredLookupResult::Retired(value) => {
584 return refused(
585 input,
586 encoded_record_charge,
587 RecordAdmissionResponse::from_retired(value),
588 );
589 }
590 BindingRequiredLookupResult::ParticipantUnknown(value) => {
591 return refused(
592 input,
593 encoded_record_charge,
594 RecordAdmissionResponse::from_participant_unknown(value),
595 );
596 }
597 BindingRequiredLookupResult::StaleAuthority(value) => {
598 return refused(
599 input,
600 encoded_record_charge,
601 RecordAdmissionResponse::from_stale_authority(value),
602 );
603 }
604 BindingRequiredLookupResult::NoBinding(value) => {
605 return refused(
606 input,
607 encoded_record_charge,
608 RecordAdmissionResponse::from_no_binding(value),
609 );
610 }
611 BindingRequiredLookupResult::Authorized { .. } => {}
612 }
613
614 let connection_capacity = match select_semantic_connection_capacity(
615 input.connection_tracking,
616 input.connection_capacity,
617 ) {
618 SemanticConnectionCapacityDecision::Commit(value) => value,
619 SemanticConnectionCapacityDecision::Respond { limit } => {
620 let response =
621 RecordAdmissionResponse::connection_conversation_capacity_exceeded(envelope, limit);
622 return refused(input, encoded_record_charge, response);
623 }
624 };
625
626 let size = match check_record_size(
627 envelope.clone(),
628 encoded_record_charge,
629 input.max_ordinary_record_charge,
630 ) {
631 super::super::RecordSizeDecision::Eligible(value) => value,
632 super::super::RecordSizeDecision::Respond(value) => {
633 return refused(
634 input,
635 encoded_record_charge,
636 RecordAdmissionResponse::record_too_large(value),
637 );
638 }
639 };
640
641 if input.frontiers.sequence().immutable_candidates().is_empty()
642 && !matches!(input.closure_accounting.state(), ClosureState::Clear)
643 {
644 return match nonzero_debt_response(
645 &envelope,
646 &input.frontiers,
647 input.closure_accounting,
648 input.observer_progress,
649 input.projection_limits,
650 ) {
651 Ok(response) => refused(input, encoded_record_charge, response),
652 Err(operation_fault) => fault(input, encoded_record_charge, operation_fault),
653 };
654 }
655
656 let RecordAdmissionPrestate {
657 request,
658 presented_identity,
659 binding,
660 receiving_binding_epoch,
661 connection_tracking,
662 connection_capacity: original_connection_capacity,
663 closure_accounting,
664 max_ordinary_record_charge,
665 frontiers,
666 retained_charges,
667 observer_progress,
668 projection_limits,
669 } = input;
670 let shell = RecordAdmissionProjectionShell {
671 request,
672 presented_identity,
673 binding,
674 connection_tracking,
675 connection_capacity: original_connection_capacity,
676 max_ordinary_record_charge,
677 };
678 let projection_input = OrdinaryRecordProjectionInput::new(
679 envelope.clone(),
680 receiving_binding_epoch,
681 size.encoded_record_charge(),
682 retained_charges,
683 observer_progress,
684 closure_accounting,
685 projection_limits,
686 );
687 let projected = match frontiers.project_ordinary_record(projection_input) {
688 Ok(OrdinaryRecordProjectionDecision::DrainFirst(value)) => {
689 let candidate = value.candidate();
690 let (frontiers, projection_input) = value.into_unchanged_parts();
691 let unchanged = UnchangedRecordAdmission::new(
692 shell.rebuild(frontiers, projection_input),
693 encoded_record_charge,
694 );
695 return RecordAdmissionDecision::DrainFirst(Box::new(RecordAdmissionDrainFirst {
696 candidate,
697 unchanged,
698 }));
699 }
700 Ok(OrdinaryRecordProjectionDecision::Projected(value)) => value,
701 Err(failure) => {
702 let (frontiers, projection_input, error) = failure.into_parts();
703 let prestate = shell.rebuild(frontiers, projection_input);
704 return match projection_failure(error, &envelope, closure_accounting) {
705 Ok(response) => refused(prestate, encoded_record_charge, response),
706 Err(operation_fault) => fault(prestate, encoded_record_charge, operation_fault),
707 };
708 }
709 };
710
711 let order = projected.order();
712 let sequence = projected.sequence();
713 let delivery_seq = sequence.resulting().high_watermark();
714 let record = CommittedOrdinaryRecord::new(
715 shell.request,
716 order.major(),
717 delivery_seq,
718 size.encoded_record_charge(),
719 );
720 RecordAdmissionDecision::Commit(Box::new(RecordAdmissionCommit {
721 outcome: RecordCommitted::new(envelope, delivery_seq),
722 record,
723 connection_capacity,
724 projection: projected,
725 }))
726}
727
728struct RecordAdmissionProjectionShell<'a, EF, V, LF> {
729 request: RecordAdmission,
730 presented_identity: PresentedIdentity<'a, EF, V, LF>,
731 binding: &'a BindingState,
732 connection_tracking: ConnectionConversationTracking,
733 connection_capacity: CapacityCounter,
734 max_ordinary_record_charge: ResourceVector,
735}
736
737impl<'a, EF, V, LF> RecordAdmissionProjectionShell<'a, EF, V, LF> {
738 fn rebuild(
739 self,
740 frontiers: ClaimFrontiers,
741 projection: OrdinaryRecordProjectionInput,
742 ) -> RecordAdmissionPrestate<'a, EF, V, LF> {
743 let (
744 _envelope,
745 receiving_binding_epoch,
746 _encoded_record_charge,
747 retained_charges,
748 observer_progress,
749 closure_accounting,
750 projection_limits,
751 ) = projection.into_parts();
752 RecordAdmissionPrestate {
753 request: self.request,
754 presented_identity: self.presented_identity,
755 binding: self.binding,
756 receiving_binding_epoch,
757 connection_tracking: self.connection_tracking,
758 connection_capacity: self.connection_capacity,
759 closure_accounting,
760 max_ordinary_record_charge: self.max_ordinary_record_charge,
761 frontiers,
762 retained_charges,
763 observer_progress,
764 projection_limits,
765 }
766 }
767}
768
769fn refused<EF, V, LF>(
770 prestate: RecordAdmissionPrestate<'_, EF, V, LF>,
771 encoded_record_charge: ResourceVector,
772 response: RecordAdmissionResponse,
773) -> RecordAdmissionDecision<'_, EF, V, LF> {
774 RecordAdmissionDecision::Respond(Box::new(RecordAdmissionRefusal {
775 response,
776 unchanged: UnchangedRecordAdmission::new(prestate, encoded_record_charge),
777 }))
778}
779
780fn fault<EF, V, LF>(
781 prestate: RecordAdmissionPrestate<'_, EF, V, LF>,
782 encoded_record_charge: ResourceVector,
783 operation_fault: RecordAdmissionFault,
784) -> RecordAdmissionDecision<'_, EF, V, LF> {
785 RecordAdmissionDecision::Fault(Box::new(RecordAdmissionFailure {
786 fault: operation_fault,
787 unchanged: UnchangedRecordAdmission::new(prestate, encoded_record_charge),
788 }))
789}
790
791fn nonzero_debt_response(
792 envelope: &RecordAdmissionEnvelope,
793 frontiers: &ClaimFrontiers,
794 accounting: ClosureAccounting,
795 observer_progress: DeliverySeq,
796 limits: OrdinaryProjectionLimits,
797) -> Result<RecordAdmissionResponse, RecordAdmissionFault> {
798 let order = match allocate_order(
799 OrderAllocatingEnvelope::RecordAdmission(envelope.clone()),
800 frontiers.order().ledger(),
801 frontiers.order().ledger().plan_ordinary_record(),
802 ) {
803 Ok(value) => value,
804 Err(error) => return order_failure(error),
805 };
806 let sequence_plan = match frontiers.sequence().ledger().plan_ordinary_record(0) {
807 Ok(value) => value,
808 Err(error) => return sequence_failure(error),
809 };
810 if let Err(error) = admit_sequence(
811 SequenceAllocatingEnvelope::RecordAdmission(envelope.clone()),
812 sequence_plan,
813 ) {
814 return sequence_failure(error);
815 }
816 match check_observer_floor(
817 ObserverCheckedOperation::RecordAdmission(envelope.clone()),
818 observer_progress,
819 frontiers.retained_floor(),
820 ) {
821 ObserverFloorDecision::Eligible(_) => {}
822 ObserverFloorDecision::Respond(value) => {
823 return Ok(RecordAdmissionResponse::from_observer_backpressure(value));
824 }
825 }
826 let required = match RequiredCapacityPlan::ordinary(
827 accounting.baseline(),
828 limits.mandatory_bound(),
829 accounting.edge_k_remaining(),
830 ) {
831 Ok(value) => value,
832 Err(error) => {
833 return Err(RecordAdmissionFault::RequiredCapacity(error));
834 }
835 };
836 let delivered_marker_awaiting_ack = matches!(
837 accounting.state(),
838 ClosureState::Owed {
839 edge: StoredEdge::ParticipantCursorProgress(progress),
840 ..
841 } if progress.marker_delivery_seq().is_some()
842 );
843 match check_remaining_closure(
844 &ClosureCheckedEnvelope::RecordAdmission(envelope.clone()),
845 accounting,
846 delivered_marker_awaiting_ack,
847 0,
848 required,
849 ) {
850 RemainingClosureDecision::Respond(value) => {
851 Ok(RecordAdmissionResponse::from_marker_closure_capacity_exceeded(value))
852 }
853 RemainingClosureDecision::Eligible(_) => {
854 let _ = order;
855 Err(RecordAdmissionFault::RefusalInvariant)
856 }
857 }
858}
859
860fn projection_failure(
861 error: OrdinaryProjectionError,
862 envelope: &RecordAdmissionEnvelope,
863 accounting: ClosureAccounting,
864) -> Result<RecordAdmissionResponse, RecordAdmissionFault> {
865 match error {
866 OrdinaryProjectionError::Order(error) => order_failure(error),
867 OrdinaryProjectionError::Sequence(error) => sequence_failure(error),
868 OrdinaryProjectionError::ObserverBackpressure {
869 cap_floor,
870 observer_progress,
871 } => match check_observer_floor(
872 ObserverCheckedOperation::RecordAdmission(envelope.clone()),
873 observer_progress,
874 cap_floor,
875 ) {
876 ObserverFloorDecision::Respond(value) => {
877 Ok(RecordAdmissionResponse::from_observer_backpressure(value))
878 }
879 ObserverFloorDecision::Eligible(_) => Err(RecordAdmissionFault::Projection(
880 OrdinaryProjectionError::ObserverBackpressure {
881 cap_floor,
882 observer_progress,
883 },
884 )),
885 },
886 OrdinaryProjectionError::Capacity { required, .. }
887 | OrdinaryProjectionError::MarkerAnchorCapacity { required, .. } => {
888 capacity_failure(required, envelope, accounting)
889 }
890 other => Err(RecordAdmissionFault::Projection(other)),
891 }
892}
893
894fn capacity_failure(
895 required: crate::algebra::WideResourceVector,
896 envelope: &RecordAdmissionEnvelope,
897 accounting: ClosureAccounting,
898) -> Result<RecordAdmissionResponse, RecordAdmissionFault> {
899 let required_capacity = match RequiredCapacityPlan::from_successors(&[required]) {
900 Ok(value) => value,
901 Err(error) => {
902 return Err(RecordAdmissionFault::RequiredCapacity(error));
903 }
904 };
905 match check_remaining_closure(
906 &ClosureCheckedEnvelope::RecordAdmission(envelope.clone()),
907 accounting,
908 false,
909 0,
910 required_capacity,
911 ) {
912 RemainingClosureDecision::Respond(value) => {
913 Ok(RecordAdmissionResponse::from_marker_closure_capacity_exceeded(value))
914 }
915 RemainingClosureDecision::Eligible(_) => Err(RecordAdmissionFault::RefusalInvariant),
916 }
917}
918
919fn order_failure(
920 error: OrderAdmissionError,
921) -> Result<RecordAdmissionResponse, RecordAdmissionFault> {
922 match error {
923 OrderAdmissionError::Exhausted(value) => Ok(
924 RecordAdmissionResponse::from_conversation_order_exhausted(value),
925 ),
926 other => Err(RecordAdmissionFault::Order(other)),
927 }
928}
929
930fn sequence_failure(
931 error: SequenceAdmissionError,
932) -> Result<RecordAdmissionResponse, RecordAdmissionFault> {
933 match error {
934 SequenceAdmissionError::Exhausted(value) => {
935 Ok(RecordAdmissionResponse::from_conversation_sequence_exhausted(value))
936 }
937 other => Err(RecordAdmissionFault::Sequence(other)),
938 }
939}
940
941const fn record_envelope(request: &RecordAdmission) -> RecordAdmissionEnvelope {
942 RecordAdmissionEnvelope {
943 conversation_id: request.conversation_id,
944 participant_id: request.participant_id,
945 capability_generation: request.capability_generation,
946 record_admission_attempt_token: request.record_admission_attempt_token,
947 }
948}