Skip to main content

prns_runtime_embassy/runtime/node_facade/node_lifecycle/
mod.rs

1use core::future::Future;
2use core::mem::MaybeUninit;
3
4use embassy_futures::join::join;
5use embassy_sync::blocking_mutex::raw::RawMutex;
6use embassy_sync::channel::{Channel, Receiver};
7use embedded_storage_async::nor_flash::NorFlash;
8use heapless::Vec as HeaplessVec;
9use static_cell::StaticCell;
10
11use crate::engine::{IssuedCommand, Journaled, ProofRequest, MAX_SEND_REQUEST_DATA_LEN};
12use crate::interfaces::{InterfaceDescriptor, InterfaceId, InterfaceIfac};
13use crate::manifold::driver::{
14    run_pooled, InterfaceLifecycle, PooledEgress, PooledWiring, ResumableHost,
15};
16use crate::manifold::grant::ManifoldLaneReader;
17use crate::manifold::Host;
18use crate::storage::StorageLayout;
19
20use super::super::request_endpoints::RequestEndpointSet;
21use super::super::request_runner::{run_router, RunnerRequest};
22use super::super::{
23    EmbassyInterfaceStore, EmbeddedFlashPersistence, EmbeddedPersistenceDiagnostic,
24    EmbeddedPersistenceRestoreReport, InterfaceInspectionStore, ManifoldPersistence,
25    ManuallyAttached, NoInterfaceInspectionStore, NoManifoldPersistence, PreConfiguredDestination,
26    PrnsEvent, PrnsNodeRecipe, RouteSnapshotKeys,
27};
28use super::command_handle::PrnsNodeHandle;
29use prns_runtime::runtime::placement::assemble_node_in_place;
30use prns_runtime::runtime::{assemble_node, AssembledNode, NoPersistence};
31
32pub struct ManifoldWiring<
33    M,
34    const LANE_COUNT: usize,
35    const NOTIFY: usize,
36    const COMMANDS: usize,
37    const LIFECYCLE: usize,
38    const COMPLETIONS: usize,
39> where
40    M: RawMutex + 'static,
41{
42    pub(super) inbound: HeaplessVec<(InterfaceId, &'static mut dyn ManifoldLaneReader), LANE_COUNT>,
43    pub(super) egress: PooledEgress<LANE_COUNT>,
44    pub(super) initial: HeaplessVec<InterfaceDescriptor, LANE_COUNT>,
45    pub(super) ifacs: HeaplessVec<InterfaceIfac, LANE_COUNT>,
46    pub(super) notify: Receiver<'static, M, InterfaceId, NOTIFY>,
47    pub(super) commands: Receiver<'static, M, IssuedCommand, COMMANDS>,
48    pub(super) lifecycle: Receiver<'static, M, InterfaceLifecycle, LIFECYCLE>,
49    pub(super) handle: PrnsNodeHandle<'static, M, COMMANDS, COMPLETIONS>,
50}
51
52pub struct PrnsNode<
53    St,
54    R,
55    F,
56    S,
57    H,
58    M,
59    const LANE_COUNT: usize,
60    const INTERFACE_CAPACITY: usize,
61    const NOTIFY: usize,
62    const COMMANDS: usize,
63    const LIFECYCLE: usize,
64    const COMPLETIONS: usize,
65    const ROUTED_REQUESTS: usize = 4,
66    const ROUTED_REQUEST_BYTES: usize = MAX_SEND_REQUEST_DATA_LEN,
67> where
68    S: StorageLayout,
69    M: RawMutex + 'static,
70{
71    node: AssembledNode<St, R, F, S>,
72    inbound: HeaplessVec<(InterfaceId, &'static mut dyn ManifoldLaneReader), LANE_COUNT>,
73    egress: PooledEgress<LANE_COUNT>,
74    notify: Receiver<'static, M, InterfaceId, NOTIFY>,
75    commands: Receiver<'static, M, IssuedCommand, COMMANDS>,
76    lifecycle: Receiver<'static, M, InterfaceLifecycle, LIFECYCLE>,
77    handle: PrnsNodeHandle<'static, M, COMMANDS, COMPLETIONS>,
78    host: H,
79    descriptors: HeaplessVec<InterfaceDescriptor, INTERFACE_CAPACITY>,
80    ifacs: HeaplessVec<InterfaceIfac, LANE_COUNT>,
81}
82
83pub struct RequestRoutingCapacity<const REQUESTS: usize, const REQUEST_BYTES: usize>;
84
85impl<const REQUESTS: usize, const REQUEST_BYTES: usize> Default
86    for RequestRoutingCapacity<REQUESTS, REQUEST_BYTES>
87{
88    fn default() -> Self {
89        Self::new()
90    }
91}
92
93impl<const REQUESTS: usize, const REQUEST_BYTES: usize>
94    RequestRoutingCapacity<REQUESTS, REQUEST_BYTES>
95{
96    #[must_use]
97    pub const fn new() -> Self {
98        Self
99    }
100}
101
102impl<
103        St,
104        R,
105        F,
106        S,
107        H,
108        M,
109        const LANE_COUNT: usize,
110        const INTERFACE_CAPACITY: usize,
111        const NOTIFY: usize,
112        const COMMANDS: usize,
113        const LIFECYCLE: usize,
114        const COMPLETIONS: usize,
115    >
116    PrnsNode<
117        St,
118        R,
119        F,
120        S,
121        H,
122        M,
123        LANE_COUNT,
124        INTERFACE_CAPACITY,
125        NOTIFY,
126        COMMANDS,
127        LIFECYCLE,
128        COMPLETIONS,
129        4,
130        MAX_SEND_REQUEST_DATA_LEN,
131    >
132where
133    R: RequestEndpointSet<St>,
134    F: FnMut(PrnsEvent<'_>, &St),
135    S: StorageLayout,
136    H: Host,
137    M: RawMutex + 'static,
138{
139    pub fn new<'d, D>(
140        recipe: PrnsNodeRecipe<D, St, R, F, ManuallyAttached, S>,
141        wiring: ManifoldWiring<M, LANE_COUNT, NOTIFY, COMMANDS, LIFECYCLE, COMPLETIONS>,
142        host: H,
143    ) -> Self
144    where
145        D: IntoIterator<Item = PreConfiguredDestination<'d>>,
146    {
147        Self::build(recipe, wiring, host)
148    }
149}
150
151impl<
152        St,
153        R,
154        F,
155        S,
156        H,
157        M,
158        const LANE_COUNT: usize,
159        const INTERFACE_CAPACITY: usize,
160        const NOTIFY: usize,
161        const COMMANDS: usize,
162        const LIFECYCLE: usize,
163        const COMPLETIONS: usize,
164        const ROUTED_REQUESTS: usize,
165        const ROUTED_REQUEST_BYTES: usize,
166    >
167    PrnsNode<
168        St,
169        R,
170        F,
171        S,
172        H,
173        M,
174        LANE_COUNT,
175        INTERFACE_CAPACITY,
176        NOTIFY,
177        COMMANDS,
178        LIFECYCLE,
179        COMPLETIONS,
180        ROUTED_REQUESTS,
181        ROUTED_REQUEST_BYTES,
182    >
183where
184    R: RequestEndpointSet<St>,
185    F: FnMut(PrnsEvent<'_>, &St),
186    S: StorageLayout,
187    H: Host,
188    M: RawMutex + 'static,
189{
190    pub fn init_static<'d, D>(
191        cell: &'static StaticCell<Self>,
192        recipe: PrnsNodeRecipe<D, St, R, F, ManuallyAttached, S>,
193        wiring: ManifoldWiring<M, LANE_COUNT, NOTIFY, COMMANDS, LIFECYCLE, COMPLETIONS>,
194        host: H,
195    ) -> &'static mut Self
196    where
197        D: IntoIterator<Item = PreConfiguredDestination<'d>>,
198    {
199        let (node, NoPersistence) = Self::init_static_with_persistence(cell, recipe, wiring, host);
200        node
201    }
202
203    #[expect(
204        unsafe_code,
205        clippy::undocumented_unsafe_blocks,
206        clippy::mut_from_ref,
207        reason = "every PrnsNode field is initialized before the slot is exposed"
208    )]
209    pub fn init_static_with_persistence<'d, D, P>(
210        cell: &'static StaticCell<Self>,
211        recipe: PrnsNodeRecipe<D, St, R, F, ManuallyAttached, S, P>,
212        wiring: ManifoldWiring<M, LANE_COUNT, NOTIFY, COMMANDS, LIFECYCLE, COMPLETIONS>,
213        host: H,
214    ) -> (&'static mut Self, P)
215    where
216        D: IntoIterator<Item = PreConfiguredDestination<'d>>,
217    {
218        const {
219            assert!(
220                INTERFACE_CAPACITY >= LANE_COUNT,
221                "PrnsNode INTERFACE_CAPACITY must cover every manifold lane"
222            );
223        }
224        let slot = cell.uninit();
225        let ManifoldWiring {
226            inbound,
227            egress,
228            initial,
229            ifacs,
230            notify,
231            commands,
232            lifecycle,
233            handle,
234        } = wiring;
235        let node = slot.as_mut_ptr();
236        let persistence = unsafe {
237            let assembled = &mut *core::ptr::addr_of_mut!((*node).node)
238                .cast::<MaybeUninit<AssembledNode<St, R, F, S>>>();
239            let (_, ManuallyAttached, persistence) = assemble_node_in_place(assembled, recipe);
240            core::ptr::addr_of_mut!((*node).inbound).write(inbound);
241            core::ptr::addr_of_mut!((*node).egress).write(egress);
242            core::ptr::addr_of_mut!((*node).notify).write(notify);
243            core::ptr::addr_of_mut!((*node).commands).write(commands);
244            core::ptr::addr_of_mut!((*node).lifecycle).write(lifecycle);
245            core::ptr::addr_of_mut!((*node).handle).write(handle);
246            core::ptr::addr_of_mut!((*node).host).write(host);
247            core::ptr::addr_of_mut!((*node).descriptors).write(HeaplessVec::new());
248            core::ptr::addr_of_mut!((*node).ifacs).write(ifacs);
249            persistence
250        };
251        let node = unsafe { slot.assume_init_mut() };
252        for descriptor in initial {
253            if node.descriptors.push(descriptor).is_err() {
254                unreachable!()
255            }
256        }
257        (node, persistence)
258    }
259
260    pub fn new_with_request_capacity<'d, D>(
261        recipe: PrnsNodeRecipe<D, St, R, F, ManuallyAttached, S>,
262        wiring: ManifoldWiring<M, LANE_COUNT, NOTIFY, COMMANDS, LIFECYCLE, COMPLETIONS>,
263        host: H,
264        _capacity: RequestRoutingCapacity<ROUTED_REQUESTS, ROUTED_REQUEST_BYTES>,
265    ) -> Self
266    where
267        D: IntoIterator<Item = PreConfiguredDestination<'d>>,
268    {
269        Self::build(recipe, wiring, host)
270    }
271
272    fn build<'d, D>(
273        recipe: PrnsNodeRecipe<D, St, R, F, ManuallyAttached, S>,
274        wiring: ManifoldWiring<M, LANE_COUNT, NOTIFY, COMMANDS, LIFECYCLE, COMPLETIONS>,
275        host: H,
276    ) -> Self
277    where
278        D: IntoIterator<Item = PreConfiguredDestination<'d>>,
279    {
280        const {
281            assert!(
282                INTERFACE_CAPACITY >= LANE_COUNT,
283                "PrnsNode INTERFACE_CAPACITY must cover every manifold lane"
284            );
285        }
286        let (node, ManuallyAttached, NoPersistence) = assemble_node(recipe);
287        let mut descriptors = HeaplessVec::new();
288        for descriptor in wiring.initial {
289            if descriptors.push(descriptor).is_err() {
290                unreachable!()
291            }
292        }
293
294        PrnsNode {
295            node,
296            inbound: wiring.inbound,
297            egress: wiring.egress,
298            notify: wiring.notify,
299            commands: wiring.commands,
300            lifecycle: wiring.lifecycle,
301            handle: wiring.handle,
302            host,
303            descriptors,
304            ifacs: wiring.ifacs,
305        }
306    }
307
308    pub fn set_protocol_policy(&mut self, policy: crate::engine::EngineProtocolPolicy) {
309        self.node.engine.set_protocol_policy(policy);
310    }
311
312    #[must_use]
313    pub fn handle(&self) -> PrnsNodeHandle<'static, M, COMMANDS, COMPLETIONS> {
314        self.handle
315    }
316
317    /// Runs the manifold with the caller's interface and supervisor tasks.
318    pub async fn run(self, drive: impl Future<Output = ()>) {
319        self.run_with_inspection_store(&NoInterfaceInspectionStore, drive)
320            .await;
321    }
322
323    /// Runs the node with the synchronous application decision used by destinations
324    /// configured with [`ProofStrategy::ProveIf`](crate::routing::ProofStrategy::ProveIf).
325    ///
326    /// The closure lives in this future and is consulted inline after delivery is
327    /// journaled. Prns allocates no policy table or per-packet decision state; capture a
328    /// shared handle to application state when proof policy must change at runtime.
329    pub async fn run_with_proof_decider<P>(self, should_prove: P, drive: impl Future<Output = ()>)
330    where
331        P: FnMut(&ProofRequest) -> bool,
332    {
333        self.run_with_inspection_store_and_proof_decider(
334            &NoInterfaceInspectionStore,
335            should_prove,
336            drive,
337        )
338        .await;
339    }
340
341    pub async fn run_with_interface_store<
342        const INTERFACES: usize,
343        const PACKET_PHY_CAPACITY: usize,
344        const PACKET_PHY_INDEX_BUCKETS: usize,
345    >(
346        self,
347        store: &EmbassyInterfaceStore<M, INTERFACES, PACKET_PHY_CAPACITY, PACKET_PHY_INDEX_BUCKETS>,
348        drive: impl Future<Output = ()>,
349    ) where
350        M: Sync,
351    {
352        const {
353            assert!(
354                INTERFACES >= INTERFACE_CAPACITY,
355                "EmbassyInterfaceStore INTERFACES must cover PrnsNode INTERFACE_CAPACITY"
356            );
357        }
358        self.run_with_inspection_store(store, drive).await;
359    }
360
361    pub async fn run_with_interface_store_and_proof_decider<
362        P,
363        const INTERFACES: usize,
364        const PACKET_PHY_CAPACITY: usize,
365        const PACKET_PHY_INDEX_BUCKETS: usize,
366    >(
367        self,
368        store: &EmbassyInterfaceStore<M, INTERFACES, PACKET_PHY_CAPACITY, PACKET_PHY_INDEX_BUCKETS>,
369        should_prove: P,
370        drive: impl Future<Output = ()>,
371    ) where
372        M: Sync,
373        P: FnMut(&ProofRequest) -> bool,
374    {
375        const {
376            assert!(
377                INTERFACES >= INTERFACE_CAPACITY,
378                "EmbassyInterfaceStore INTERFACES must cover PrnsNode INTERFACE_CAPACITY"
379            );
380        }
381        self.run_with_inspection_store_and_proof_decider(store, should_prove, drive)
382            .await;
383    }
384
385    async fn run_with_inspection_store<Store>(self, store: &Store, drive: impl Future<Output = ()>)
386    where
387        Store: InterfaceInspectionStore,
388    {
389        self.run_with_inspection_store_and_proof_decider(store, |_| false, drive)
390            .await;
391    }
392
393    async fn run_with_inspection_store_and_proof_decider<Store, P>(
394        self,
395        store: &Store,
396        should_prove: P,
397        drive: impl Future<Output = ()>,
398    ) where
399        Store: InterfaceInspectionStore,
400        P: FnMut(&ProofRequest) -> bool,
401    {
402        let PrnsNode {
403            node,
404            mut inbound,
405            mut egress,
406            notify,
407            commands,
408            lifecycle,
409            handle,
410            mut host,
411            mut descriptors,
412            mut ifacs,
413        } = self;
414        let AssembledNode {
415            mut engine,
416            state,
417            mut on_event,
418            request_endpoints: _,
419        } = node;
420        let request_channel =
421            Channel::<M, RunnerRequest<ROUTED_REQUEST_BYTES>, ROUTED_REQUESTS>::new();
422        let request_sender = request_channel.sender();
423        let mut persistence = NoManifoldPersistence;
424        let manifold = run_pooled(
425            &mut engine,
426            &mut host,
427            PooledWiring {
428                descriptors: &mut descriptors,
429                ifacs: &mut ifacs,
430                inbound: &mut inbound,
431                egress: &mut egress,
432                notify,
433                commands,
434                lifecycle,
435            },
436            |journaled| {
437                if let Journaled::CommandSettled { id, settlement } = &journaled {
438                    if handle.settle(*id, settlement.clone()) {
439                        return;
440                    }
441                }
442                if let Some(request) = RunnerRequest::copy_from(&journaled) {
443                    let _ = request_sender.try_send(request);
444                }
445                on_event(PrnsEvent::from(journaled), &state);
446            },
447            crate::manifold::AppDeciders {
448                should_prove,
449                should_accept_resource: |_| false,
450            },
451            store,
452            &mut persistence,
453        );
454        let router =
455            run_router::<St, R, M, COMMANDS, COMPLETIONS, ROUTED_REQUESTS, ROUTED_REQUEST_BYTES>(
456                &state,
457                request_channel.receiver(),
458                handle,
459            );
460        join(join(manifold, router), drive).await;
461    }
462
463    /// Runs only the manifold for boards that schedule interfaces separately.
464    pub async fn run_manifold(&mut self) {
465        self.run_manifold_with_inspection_store(&NoInterfaceInspectionStore)
466            .await;
467    }
468
469    /// Runs only the manifold with a synchronous application proof decision.
470    pub async fn run_manifold_with_proof_decider<P>(&mut self, should_prove: P)
471    where
472        P: FnMut(&ProofRequest) -> bool,
473    {
474        let mut persistence = NoManifoldPersistence;
475        self.run_manifold_with_inspection_store_and_persistence_and_proof_decider(
476            &NoInterfaceInspectionStore,
477            &mut persistence,
478            should_prove,
479        )
480        .await;
481    }
482
483    pub async fn run_manifold_with_interface_store<
484        const INTERFACES: usize,
485        const PACKET_PHY_CAPACITY: usize,
486        const PACKET_PHY_INDEX_BUCKETS: usize,
487    >(
488        &mut self,
489        store: &EmbassyInterfaceStore<M, INTERFACES, PACKET_PHY_CAPACITY, PACKET_PHY_INDEX_BUCKETS>,
490    ) where
491        M: Sync,
492    {
493        const {
494            assert!(
495                INTERFACES >= INTERFACE_CAPACITY,
496                "EmbassyInterfaceStore INTERFACES must cover PrnsNode INTERFACE_CAPACITY"
497            );
498        }
499        self.run_manifold_with_inspection_store(store).await;
500    }
501
502    pub async fn run_manifold_with_interface_store_and_proof_decider<
503        P,
504        const INTERFACES: usize,
505        const PACKET_PHY_CAPACITY: usize,
506        const PACKET_PHY_INDEX_BUCKETS: usize,
507    >(
508        &mut self,
509        store: &EmbassyInterfaceStore<M, INTERFACES, PACKET_PHY_CAPACITY, PACKET_PHY_INDEX_BUCKETS>,
510        should_prove: P,
511    ) where
512        M: Sync,
513        P: FnMut(&ProofRequest) -> bool,
514    {
515        const {
516            assert!(
517                INTERFACES >= INTERFACE_CAPACITY,
518                "EmbassyInterfaceStore INTERFACES must cover PrnsNode INTERFACE_CAPACITY"
519            );
520        }
521        let mut persistence = NoManifoldPersistence;
522        self.run_manifold_with_inspection_store_and_persistence_and_proof_decider(
523            store,
524            &mut persistence,
525            should_prove,
526        )
527        .await;
528    }
529
530    async fn run_manifold_with_inspection_store<Store>(&mut self, store: &Store)
531    where
532        Store: InterfaceInspectionStore,
533    {
534        let mut persistence = NoManifoldPersistence;
535        self.run_manifold_with_inspection_store_and_persistence(store, &mut persistence)
536            .await;
537    }
538
539    pub async fn run_manifold_with_persistence_and_interface_store<
540        Fl,
541        Keys,
542        Observe,
543        const PENDING: usize,
544        const INTERFACES: usize,
545        const PACKET_PHY_CAPACITY: usize,
546        const PACKET_PHY_INDEX_BUCKETS: usize,
547    >(
548        &mut self,
549        store: &EmbassyInterfaceStore<M, INTERFACES, PACKET_PHY_CAPACITY, PACKET_PHY_INDEX_BUCKETS>,
550        persistence: &mut EmbeddedFlashPersistence<Fl, Keys, Observe, PENDING>,
551    ) where
552        M: Sync,
553        Fl: NorFlash,
554        Keys: RouteSnapshotKeys,
555        Observe: FnMut(EmbeddedPersistenceDiagnostic),
556    {
557        const {
558            assert!(
559                INTERFACES >= INTERFACE_CAPACITY,
560                "EmbassyInterfaceStore INTERFACES must cover PrnsNode INTERFACE_CAPACITY"
561            );
562        }
563        self.run_manifold_with_inspection_store_and_persistence(store, persistence)
564            .await;
565    }
566
567    pub async fn run_manifold_with_persistence_and_interface_store_and_proof_decider<
568        Fl,
569        Keys,
570        Observe,
571        Decide,
572        const PENDING: usize,
573        const INTERFACES: usize,
574        const PACKET_PHY_CAPACITY: usize,
575        const PACKET_PHY_INDEX_BUCKETS: usize,
576    >(
577        &mut self,
578        store: &EmbassyInterfaceStore<M, INTERFACES, PACKET_PHY_CAPACITY, PACKET_PHY_INDEX_BUCKETS>,
579        persistence: &mut EmbeddedFlashPersistence<Fl, Keys, Observe, PENDING>,
580        should_prove: Decide,
581    ) where
582        M: Sync,
583        Fl: NorFlash,
584        Keys: RouteSnapshotKeys,
585        Observe: FnMut(EmbeddedPersistenceDiagnostic),
586        Decide: FnMut(&ProofRequest) -> bool,
587    {
588        const {
589            assert!(
590                INTERFACES >= INTERFACE_CAPACITY,
591                "EmbassyInterfaceStore INTERFACES must cover PrnsNode INTERFACE_CAPACITY"
592            );
593        }
594        self.run_manifold_with_inspection_store_and_persistence_and_proof_decider(
595            store,
596            persistence,
597            should_prove,
598        )
599        .await;
600    }
601
602    pub async fn restore_embedded_persistence<Fl, Keys, Observe, const PENDING: usize>(
603        &mut self,
604        persistence: &mut EmbeddedFlashPersistence<Fl, Keys, Observe, PENDING>,
605    ) -> EmbeddedPersistenceRestoreReport
606    where
607        Fl: NorFlash,
608        Keys: RouteSnapshotKeys,
609        Observe: FnMut(EmbeddedPersistenceDiagnostic),
610        H: ResumableHost,
611    {
612        let report = persistence
613            .restore(&mut self.node.engine, self.host.now())
614            .await;
615        self.host.resume_at(report.logical_start);
616        report
617    }
618
619    async fn run_manifold_with_inspection_store_and_persistence<Store, P>(
620        &mut self,
621        store: &Store,
622        persistence: &mut P,
623    ) where
624        Store: InterfaceInspectionStore,
625        P: ManifoldPersistence<S>,
626    {
627        self.run_manifold_with_inspection_store_and_persistence_and_proof_decider(
628            store,
629            persistence,
630            |_| false,
631        )
632        .await;
633    }
634
635    async fn run_manifold_with_inspection_store_and_persistence_and_proof_decider<
636        Store,
637        P,
638        Decide,
639    >(
640        &mut self,
641        store: &Store,
642        persistence: &mut P,
643        should_prove: Decide,
644    ) where
645        Store: InterfaceInspectionStore,
646        P: ManifoldPersistence<S>,
647        Decide: FnMut(&ProofRequest) -> bool,
648    {
649        let PrnsNode {
650            node,
651            inbound,
652            egress,
653            notify,
654            commands,
655            lifecycle,
656            handle,
657            host,
658            descriptors,
659            ifacs,
660        } = self;
661        let AssembledNode {
662            engine,
663            state,
664            on_event,
665            request_endpoints: _,
666        } = node;
667        let request_channel =
668            Channel::<M, RunnerRequest<ROUTED_REQUEST_BYTES>, ROUTED_REQUESTS>::new();
669        let request_sender = request_channel.sender();
670        let manifold = run_pooled(
671            engine,
672            host,
673            PooledWiring {
674                descriptors,
675                ifacs,
676                inbound,
677                egress,
678                notify: *notify,
679                commands: *commands,
680                lifecycle: *lifecycle,
681            },
682            |journaled| {
683                if let Journaled::CommandSettled { id, settlement } = &journaled {
684                    if handle.settle(*id, settlement.clone()) {
685                        return;
686                    }
687                }
688                if let Some(request) = RunnerRequest::copy_from(&journaled) {
689                    let _ = request_sender.try_send(request);
690                }
691                on_event(PrnsEvent::from(journaled), state);
692            },
693            crate::manifold::AppDeciders {
694                should_prove,
695                should_accept_resource: |_| false,
696            },
697            store,
698            persistence,
699        );
700        let router =
701            run_router::<St, R, M, COMMANDS, COMPLETIONS, ROUTED_REQUESTS, ROUTED_REQUEST_BYTES>(
702                state,
703                request_channel.receiver(),
704                *handle,
705            );
706        join(manifold, router).await;
707    }
708}
709
710#[cfg(test)]
711mod tests;