1use itertools::Itertools;
2use ossa_crdt::CRDT;
3use ossa_typeable::{TypeId, Typeable};
4use rand::{seq::SliceRandom as _, thread_rng};
5use replace_with::replace_with_or_abort;
6use serde::{Deserialize, Serialize};
7use std::fmt::Debug;
8use std::{
9 collections::{BTreeMap, BTreeSet},
10 ops::Range,
11};
12use tokio::{
13 sync::{
14 mpsc::{UnboundedReceiver, UnboundedSender},
15 oneshot::{self, Sender},
16 },
17 task::JoinHandle,
18};
19use tracing::{debug, error, warn};
20
21use crate::store::v0::BLOCK_SIZE;
22use crate::time::ConcretizeTime;
23use crate::util::merkle_tree::{MerkleTree, Potential};
24use crate::{
25 auth::DeviceId,
26 core::{OssaType, SharedState},
27 network::{
28 multiplexer::{run_miniprotocol_async, SpawnMultiplexerTask},
29 protocol::MiniProtocol,
30 },
31 protocol::{
32 manager::v0::PeerManagerCommand,
33 store_peer::v0::{MsgStoreSyncRequest, StoreSync, StoreSyncCommand},
34 },
35 store::{
36 ecg::{ECGBody, ECGHeader, RawECGBody},
37 v0::{BLOCK_REQUEST_LIMIT, MERKLE_REQUEST_LIMIT},
38 },
39 util::{self, compress_consecutive_into_ranges},
40};
41
42pub mod ecg;
43pub mod v0; pub use v0::{MetadataBody, MetadataHeader, Nonce};
46
47pub struct State<StoreId, Header: ecg::ECGHeader, T: CRDT, Hash> {
48 peers: BTreeMap<DeviceId, PeerInfo<Header::HeaderId, Header>>, state_machine: StateMachine<StoreId, Header, T, Hash>,
51 metadata_subscribers: BTreeMap<DeviceId, oneshot::Sender<Option<v0::MetadataHeader<Hash>>>>,
52 merkle_subscribers: BTreeMap<DeviceId, (Vec<Range<u64>>, oneshot::Sender<Option<Vec<Hash>>>)>,
53 block_subscribers: BTreeMap<
54 DeviceId,
55 (
56 Vec<Range<u64>>,
57 oneshot::Sender<Option<Vec<Option<Vec<u8>>>>>,
58 ),
59 >,
60 ecg_subscribers:
61 BTreeMap<DeviceId, oneshot::Sender<ecg::UntypedState<Header::HeaderId, Header>>>,
62 }
64
65pub enum StateMachine<StoreId, Header: ecg::ECGHeader, T: CRDT, Hash> {
70 DownloadingMetadata {
71 store_id: StoreId,
72 },
73 DownloadingMerkle {
75 metadata: MetadataHeader<Hash>,
76 partial_merkle_tree: MerkleTree<Potential<Hash>>,
77 },
78 DownloadingInitialState {
80 metadata: MetadataHeader<Hash>,
81 merkle_tree: MerkleTree<Hash>,
82 initial_state: Vec<Option<Vec<u8>>>,
83 },
84 Syncing {
85 metadata: MetadataHeader<Hash>,
86 merkle_tree: MerkleTree<Hash>,
87 initial_state: Vec<u8>, ecg_state: ecg::State<Header, T>,
89 decrypted_state: DecryptedState<Header, T>, },
93}
94
95pub struct DecryptedState<Header: ecg::ECGHeader, T: CRDT> {
96 latest_state: T,
98
99 latest_headers: BTreeSet<Header::HeaderId>,
102}
103
104#[derive(Debug)]
106struct PeerInfo<HeaderId, Header> {
107 incoming_status: PeerStatus<()>,
109 outgoing_status: PeerStatus<OutgoingPeerStatus<HeaderId, Header>>,
111 }
113
114impl<Hash, Header> PeerInfo<Hash, Header> {
125 fn is_ready_for_sync(&self) -> bool {
128 if let PeerStatus::Syncing(s) = &self.outgoing_status {
129 !s.is_outstanding
130 } else {
131 false
132 }
133 }
134}
135
136#[derive(Debug)]
137struct OutgoingPeerStatus<HeaderId, Header> {
139 sender_peer: UnboundedSender<StoreSyncCommand<HeaderId, Header>>,
141 is_outstanding: bool,
143}
144
145#[derive(Debug)]
147pub(crate) enum PeerStatus<T> {
148 Known, Initializing,
152 Syncing(T), }
165
166impl<T> PeerStatus<T> {
167 fn is_known(&self) -> bool {
168 if let PeerStatus::Known = self {
169 true
170 } else {
171 false
172 }
173 }
174
175 fn is_initializing(&self) -> bool {
176 if let PeerStatus::Initializing = self {
177 true
178 } else {
179 false
180 }
181 }
182}
183
184impl<
185 StoreId: Copy + Eq,
186 Header: ecg::ECGHeader + Clone + Debug,
187 T: CRDT + Clone,
188 Hash: util::Hash + Debug + Into<StoreId>,
189 > State<StoreId, Header, T, Hash>
190{
191 pub fn new_syncing(initial_state: T) -> State<StoreId, Header, T, Hash>
194 where
195 T: Serialize + Typeable,
196 {
197 let init_body = MetadataBody::new(&initial_state);
198 debug!("Initialized body: {:?}", init_body);
199 let store_header = MetadataHeader::generate::<T>(&init_body);
200 let decrypted_state = DecryptedState {
201 latest_state: initial_state,
202 latest_headers: BTreeSet::new(),
203 };
204
205 let (merkle_tree, initial_state) = init_body.build();
206
207 let state_machine = StateMachine::Syncing {
208 metadata: store_header,
209 merkle_tree,
210 initial_state,
211 ecg_state: ecg::State::new(),
212 decrypted_state, };
214 State {
215 peers: BTreeMap::new(),
216 state_machine,
217 metadata_subscribers: BTreeMap::new(),
218 merkle_subscribers: BTreeMap::new(),
219 block_subscribers: BTreeMap::new(),
220 ecg_subscribers: BTreeMap::new(),
221 }
222 }
223
224 pub(crate) fn new_downloading(store_id: StoreId) -> Self {
226 let state_machine = StateMachine::DownloadingMetadata { store_id };
227
228 State {
229 peers: BTreeMap::new(),
230 state_machine,
231 metadata_subscribers: BTreeMap::new(),
232 merkle_subscribers: BTreeMap::new(),
233 block_subscribers: BTreeMap::new(),
234 ecg_subscribers: BTreeMap::new(),
235 }
236 }
237
238 pub fn store_id(&self) -> StoreId {
239 match &self.state_machine {
240 StateMachine::DownloadingMetadata { store_id } => *store_id,
241 StateMachine::DownloadingMerkle { metadata, .. } => metadata.store_id(),
242 StateMachine::DownloadingInitialState { metadata, .. } => metadata.store_id(),
243 StateMachine::Syncing { metadata, .. } => metadata.store_id(),
244 }
245 }
246
247 fn insert_known_peer(&mut self, peer: DeviceId) {
249 self.peers
251 .entry(peer)
252 .or_insert(PeerInfo {
261 incoming_status: PeerStatus::Known,
262 outgoing_status: PeerStatus::Known,
263 }); }
265
266 fn update_peer_to_initializing<A>(
268 &mut self,
269 peer: &DeviceId,
270 direction_lambda: fn(&mut PeerInfo<Header::HeaderId, Header>) -> &mut PeerStatus<A>,
271 ) where
272 A: Debug,
273 {
274 let Some(info) = self.peers.get_mut(peer) else {
275 error!(
276 "Invariant violated. Attempted to initialize an unknown peer: {}",
277 peer
278 );
279 panic!();
280 };
281 let status = direction_lambda(info);
282 if status.is_known() {
283 *status = PeerStatus::Initializing;
284 } else {
285 error!("Invariant violated. Attempted to initialize an already initialized peer: {} - {:?}", peer, status);
286 panic!();
287 }
288 }
289
290 fn update_peer_to_initializing_outgoing(&mut self, peer: &DeviceId) {
292 self.update_peer_to_initializing(peer, |info| &mut info.outgoing_status);
293 }
294
295 fn update_peer_to_initializing_incoming(&mut self, peer: &DeviceId) {
297 self.update_peer_to_initializing(peer, |info| &mut info.incoming_status);
298 }
299
300 fn update_peer_to_syncing<A>(
302 &mut self,
303 peer: &DeviceId,
304 direction_lambda: fn(&mut PeerInfo<Header::HeaderId, Header>) -> &mut PeerStatus<A>,
305 sender_m: A,
306 ) where
307 A: Debug,
308 {
309 let Some(info) = self.peers.get_mut(peer) else {
310 error!(
311 "Invariant violated. Attempted to initialize an unknown peer: {}",
312 peer
313 );
314 panic!();
315 };
316 let status = direction_lambda(info);
317 match status {
318 PeerStatus::Initializing => {
319 *status = PeerStatus::Syncing(sender_m);
320 }
321 PeerStatus::Known => {
322 error!(
323 "Invariant violated. Attempted to initialize an unknown peer: {} - {:?}",
324 peer, status
325 );
326 panic!();
327 }
328 PeerStatus::Syncing(_) => {
329 error!(
330 "Invariant violated. Attempted to sync an already syncing peer: {} - {:?}",
331 peer, status
332 );
333 panic!();
334 }
335 }
336 }
337
338 fn update_peer_to_syncing_incoming(&mut self, peer: &DeviceId) {
339 self.update_peer_to_syncing(peer, |info| &mut info.incoming_status, ());
340 }
341
342 fn update_peer_to_syncing_outgoing(
343 &mut self,
344 peer: &DeviceId,
345 sender: OutgoingPeerStatus<Header::HeaderId, Header>,
346 ) {
347 self.update_peer_to_syncing(peer, |info| &mut info.outgoing_status, sender);
348 }
349
350 fn update_outgoing_peer_to_ready(&mut self, peer: &DeviceId) {
351 let Some(info) = self.peers.get_mut(peer) else {
352 error!(
353 "Invariant violated. Attempted to update an unknown peer: {}",
354 peer
355 );
356 panic!();
357 };
358 match info.outgoing_status {
359 PeerStatus::Initializing => {
360 error!("Invariant violated. Attempted to update a peer that is initializing: {} - {:?}", peer, info.outgoing_status);
361 panic!();
362 }
363 PeerStatus::Known => {
364 error!(
365 "Invariant violated. Attempted to update a peer that is not syncing: {} - {:?}",
366 peer, info.outgoing_status
367 );
368 panic!();
369 }
370 PeerStatus::Syncing(ref mut status) => {
371 status.is_outstanding = false;
372 }
373 }
374 }
375
376 fn send_sync_requests(&mut self) {
378 fn send_command<Hash, Header>(
379 i: &mut PeerInfo<Hash, Header>,
380 message: StoreSyncCommand<Hash, Header>,
381 ) {
382 let PeerStatus::Syncing(ref mut s) = i.outgoing_status else {
383 unreachable!("Already checked that the peer is ready.");
384 };
385
386 s.is_outstanding = true;
388 s.sender_peer.send(message).expect("TODO");
389 }
390
391 let mut peers: Vec<_> = self
393 .peers
394 .iter_mut()
395 .filter(|(_, i)| i.is_ready_for_sync())
396 .collect();
397 let mut rng = thread_rng();
399 peers.shuffle(&mut rng);
400
401 match &self.state_machine {
403 StateMachine::DownloadingMetadata { .. } => {
404 peers.iter_mut().take(1).for_each(|(_, i)| {
406 let message = StoreSyncCommand::MetadataHeaderRequest;
407 send_command(i, message);
408 });
409 }
410 StateMachine::DownloadingMerkle {
411 partial_merkle_tree,
412 ..
413 } => {
414 debug!(
415 "send_sync_requests: DownloadingMerkle: {:?}",
416 partial_merkle_tree
417 );
418
419 let needed_hashes = partial_merkle_tree
421 .missing_indices()
422 .chunks(MERKLE_REQUEST_LIMIT as usize);
423 let mut needed_hashes: Vec<_> = needed_hashes.into_iter().collect();
424 if needed_hashes.is_empty() {
425 panic!("Invariant violated: We have all merkle nodes but are in state DownloadingMerkle.");
426 }
427
428 needed_hashes.shuffle(&mut rng);
430
431 peers.iter_mut().zip(needed_hashes).for_each(|(p, hashes)| {
432 let message = StoreSyncCommand::MerkleRequest(
433 compress_consecutive_into_ranges(hashes).collect(),
434 );
435 send_command(p.1, message);
436 });
437 }
438 StateMachine::DownloadingInitialState { initial_state, .. } => {
439 let needed_blocks = initial_state
440 .iter()
441 .enumerate()
442 .filter_map(|h| {
443 if h.1.is_none() {
444 Some(h.0 as u64)
445 } else {
446 None
447 }
448 })
449 .chunks(BLOCK_REQUEST_LIMIT as usize);
450 let mut needed_blocks: Vec<_> = needed_blocks.into_iter().collect();
451 if needed_blocks.is_empty() {
452 panic!("Invariant violated: We have all blocks but are in state DownloadingInitialState.");
453 }
454
455 needed_blocks.shuffle(&mut rng);
457
458 peers.iter_mut().zip(needed_blocks).for_each(|(p, blocks)| {
459 let message = StoreSyncCommand::InitialStateBlockRequest(
460 compress_consecutive_into_ranges(blocks).collect(),
461 );
462 send_command(p.1, message);
463 });
464 }
465 StateMachine::Syncing { ecg_state, .. } => {
466 debug!("Sending ECG sync requests to peers.");
467 peers.iter_mut().for_each(|p| {
469 let ecg_state = ecg_state.state().clone();
471 let message = StoreSyncCommand::ECGSyncRequest { ecg_state };
472 debug!("Sending ECG sync request to peer ({})", p.0);
473 send_command(p.1, message)
474 });
475 }
476 }
477 }
478
479 fn handle_metadata_peer_request(
481 &mut self,
482 peer: DeviceId,
483 response_chan: Sender<HandlePeerResponse<MetadataHeader<Hash>>>,
484 ) {
485 if let Some(metadata) = self.metadata() {
486 response_chan.send(Ok(*metadata)).expect("TODO");
488 } else {
489 let (send_chan, recv_chan) = oneshot::channel();
491 response_chan.send(Err(recv_chan)).expect("TODO");
492
493 self.metadata_subscribers.insert(peer, send_chan); }
496 }
497
498 fn handle_merkle_peer_request(
499 &mut self,
500 peer: DeviceId,
501 node_ids: Vec<Range<u64>>,
502 response_chan: Sender<HandlePeerResponse<Vec<Hash>>>,
503 ) {
504 debug!("Received merkle peer request for node_ids: {node_ids:?}");
505 let hashes = self
506 .merkle_tree()
507 .map(|merkle_tree| handle_merkle_peer_request_helper(merkle_tree, &node_ids));
508
509 if let Some(node_hashes) = hashes {
510 response_chan.send(Ok(node_hashes)).expect("TODO");
512 } else {
513 let (send_chan, recv_chan) = oneshot::channel();
515 response_chan.send(Err(recv_chan)).expect("TODO");
516
517 self.merkle_subscribers.insert(peer, (node_ids, send_chan)); }
520 }
521
522 fn handle_block_peer_request(
523 &mut self,
524 peer: DeviceId,
525 block_ids: Vec<Range<u64>>,
526 response_chan: Sender<HandlePeerResponse<Vec<Option<Vec<u8>>>>>,
527 ) {
528 let blocks = handle_block_peer_request_helper(&self.state_machine, &block_ids);
529
530 if let Some(blocks) = blocks {
531 response_chan.send(Ok(blocks)).expect("TODO");
533 } else {
534 let (send_chan, recv_chan) = oneshot::channel();
536 response_chan.send(Err(recv_chan)).expect("TODO");
537
538 self.block_subscribers.insert(peer, (block_ids, send_chan)); }
541 }
542
543 fn handle_ecg_subscribe(
544 &mut self,
545 peer: DeviceId,
546 tips: Option<BTreeSet<Header::HeaderId>>,
547 response_chan: oneshot::Sender<ecg::UntypedState<Header::HeaderId, Header>>,
548 ) {
549 if let StateMachine::Syncing { ecg_state, .. } = &self.state_machine {
551 let respond_immediately = if let Some(tips) = tips {
552 debug!("our_tips: {:?}", ecg_state.tips());
553 debug!("their_tips: {:?}", tips);
554 !ecg_state.tips().eq(&tips)
555 } else {
556 true
557 };
558
559 if respond_immediately {
560 debug!("Responding immediately with ECG state.");
561 response_chan.send(ecg_state.state.clone()).expect("TODO");
562
563 return;
564 }
565 };
566
567 debug!("Registering subscriber for ECG state for peer: {peer}");
569 self.ecg_subscribers.insert(peer, response_chan);
570 }
571
572 fn handle_received_metadata(
583 &mut self,
584 peer: DeviceId,
585 metadata: MetadataHeader<Hash>,
586 listeners: &[UnboundedSender<StateUpdate<Header, T>>],
587 ) where
588 T: for<'d> Deserialize<'d>,
589 {
590 debug!("Recieved metadata from peer ({peer}): {metadata:?}");
591
592 self.update_outgoing_peer_to_ready(&peer);
594
595 let is_valid = metadata.validate_store_id(self.store_id());
597 warn!("TODO: Validate signature.");
598 warn!("TODO: Validate type id.");
599
600 if !is_valid {
601 warn!("TODO: Peer provided invalid metadata.");
603 return;
604 }
605
606 self.state_machine = StateMachine::DownloadingMerkle {
608 partial_merkle_tree: MerkleTree::new_with_capacity(
609 metadata.merkle_root,
610 metadata.block_count(),
611 ),
612 metadata,
613 };
614 debug!("Updated state machine"); let subs = std::mem::take(&mut self.metadata_subscribers);
618 for (sub_peer, sub) in subs {
619 let peer_knows = sub_peer == peer;
620 let msg = if peer_knows { None } else { Some(metadata) };
621 sub.send(msg).expect("TODO");
622 }
623
624 if metadata.block_count() <= 1 {
626 self.update_state_to_downloading_initial_state(peer, listeners);
627 }
628 }
629
630 fn metadata(&self) -> Option<&MetadataHeader<Hash>> {
631 match &self.state_machine {
632 StateMachine::DownloadingMetadata { .. } => None,
633 StateMachine::DownloadingMerkle { metadata, .. } => Some(metadata),
634 StateMachine::DownloadingInitialState { metadata, .. } => Some(metadata),
635 StateMachine::Syncing { metadata, .. } => Some(metadata),
636 }
637 }
638
639 fn merkle_tree(&self) -> Option<&MerkleTree<Hash>> {
640 match &self.state_machine {
641 StateMachine::DownloadingMetadata { .. } => None,
642 StateMachine::DownloadingMerkle { .. } => {
643 None
646 }
647 StateMachine::DownloadingInitialState { merkle_tree, .. } => Some(merkle_tree),
648 StateMachine::Syncing { merkle_tree, .. } => Some(merkle_tree),
649 }
650 }
651
652 fn handle_received_merkle_hashes(
653 &mut self,
654 peer: DeviceId,
655 node_ids: Vec<Range<u64>>,
656 their_node_hashes: Vec<Hash>,
657 listeners: &[UnboundedSender<StateUpdate<Header, T>>],
658 ) where
659 T: for<'d> Deserialize<'d>,
660 {
661 warn!("TODO: Keep track if you received different hashes from different peers.");
662
663 self.update_outgoing_peer_to_ready(&peer);
665
666 let node_ids: Vec<_> = node_ids.into_iter().flatten().collect();
667 if node_ids.len() != their_node_hashes.len() {
668 warn!("TODO: Peer provided an invalid response");
669 return;
670 }
671
672 let partial_merkle_tree = if let StateMachine::DownloadingMerkle {
674 ref mut partial_merkle_tree,
675 ..
676 } = &mut self.state_machine
677 {
678 partial_merkle_tree
679 } else {
680 return;
682 };
683 node_ids
684 .into_iter()
685 .zip(their_node_hashes)
686 .for_each(|(i, hash)| {
687 let valid = partial_merkle_tree.set(i, hash);
688 if !valid {
689 warn!("TODO: Peer sent us an invalid merkle hash.");
690 } });
692
693 self.update_state_to_downloading_initial_state(peer, listeners);
695 }
696
697 fn handle_received_initial_state_blocks(
698 &mut self,
699 peer: DeviceId,
700 block_ids: Vec<Range<u64>>,
701 their_blocks: Vec<Option<Vec<u8>>>,
702 listeners: &[UnboundedSender<StateUpdate<Header, T>>],
703 ) where
704 T: for<'d> Deserialize<'d>,
705 {
706 self.update_outgoing_peer_to_ready(&peer);
708
709 let block_ids: Vec<_> = block_ids.into_iter().flatten().collect();
710 if block_ids.len() != their_blocks.len() {
711 warn!("TODO: Peer provided an invalid response");
712 return;
713 }
714
715 let (initial_state, merkle_tree) = if let StateMachine::DownloadingInitialState {
717 ref mut initial_state,
718 ref merkle_tree,
719 ..
720 } = &mut self.state_machine
721 {
722 (initial_state, merkle_tree)
723 } else {
724 return;
725 };
726 block_ids
727 .into_iter()
728 .zip(their_blocks)
729 .for_each(|(i, their_block)| {
730 if let Some(their_block) = their_block {
731 let block = &mut initial_state[i as usize];
732 if block.is_none() {
734 if merkle_tree.validate_chunk(i, &their_block) {
736 *block = Some(their_block);
737 } else {
738 warn!("TODO: Peer sent us an invalid block");
739 }
740 }
741 }
742 });
743
744 if initial_state.iter().any(|o| o.is_none()) {
746 return;
747 }
748
749 self.update_state_to_syncing(peer, listeners);
751 }
752
753 fn handle_received_ecg_operations<OT>(
754 &mut self,
755 peer: DeviceId,
756 operations: Vec<(Header, RawECGBody)>,
757 listeners: &[UnboundedSender<StateUpdate<Header, T>>],
758 ) where
759 OT: OssaType<ECGHeader = Header>,
760 T: CRDT<Time = OT::Time> + Debug,
761 OT::ECGBody<T>: for<'d> Deserialize<'d>
762 + Debug
763 + ECGBody<
764 T::Op,
765 <T::Op as ConcretizeTime<<OT::ECGHeader as ECGHeader>::HeaderId>>::Serialized,
766 Header = OT::ECGHeader,
767 >, T::Op: ConcretizeTime<<Header as ECGHeader>::HeaderId>,
770 {
771 self.update_outgoing_peer_to_ready(&peer);
773
774 warn!("TODO: Validate operations from peer");
775
776 let StateMachine::Syncing {
777 ref mut ecg_state,
778 ref mut decrypted_state,
779 ..
780 } = &mut self.state_machine
781 else {
782 unreachable!("We must be syncing");
783 };
784
785 operations.into_iter().for_each(|(header, raw_operations)| {
787 let operations = serde_cbor::from_slice(&raw_operations)
788 .expect("TODO: Peer gave us improperly serialized operations");
789 debug!("Applying operations {operations:?}");
790
791 let success = ecg_state.insert_header(header.clone(), raw_operations);
793 if !success {
794 debug!("Failed to insert operations from peer.");
795 } else {
796 apply_operations::<OT, _>(decrypted_state, ecg_state, &header, operations);
797 }
798 });
799 debug!("New decrypted state {:?}", decrypted_state.latest_state);
800
801 update_listeners(
803 &mut self.ecg_subscribers,
804 listeners,
805 &decrypted_state.latest_state,
806 ecg_state,
807 Some(peer),
808 );
809 }
810
811 fn update_state_to_downloading_initial_state(
813 &mut self,
814 peer: DeviceId,
815 listeners: &[UnboundedSender<StateUpdate<Header, T>>],
816 ) where
817 T: for<'d> Deserialize<'d>,
818 {
819 let StateMachine::DownloadingMerkle {
820 ref partial_merkle_tree,
821 ..
822 } = &self.state_machine
823 else {
824 panic!("Precondition violated. State mush be StateMachine::DownloadingMerkle");
825 };
826 let merkle_tree_m = partial_merkle_tree.try_complete();
828 let Some(merkle_tree) = merkle_tree_m else {
829 return;
830 };
831
832 self.state_machine = match self.state_machine {
841 StateMachine::DownloadingMerkle { metadata, .. } => {
842 let initial_state = vec![None; metadata.block_count() as usize];
843 StateMachine::DownloadingInitialState {
844 metadata,
845 merkle_tree,
846 initial_state,
847 }
848 }
849 _ => unreachable!("We already checked that we're downloading merkle"),
850 };
851
852 let subs = std::mem::take(&mut self.merkle_subscribers);
854 let merkle_tree = self
855 .merkle_tree()
856 .expect("Unreachable: We just set the merkle tree");
857 for (sub_peer, (node_ids, sub)) in subs {
858 let peer_knows = sub_peer == peer;
859 let msg = if peer_knows {
860 None
861 } else {
862 Some(handle_merkle_peer_request_helper(merkle_tree, &node_ids))
863 };
864 sub.send(msg).expect("TODO");
865 }
866
867 if self.metadata().unwrap().initial_state_size == 0 {
869 self.update_state_to_syncing(peer, listeners);
870 }
871 }
872
873 fn update_state_to_syncing(
874 &mut self,
875 peer: DeviceId,
876 listeners: &[UnboundedSender<StateUpdate<Header, T>>],
877 ) where
878 T: for<'d> Deserialize<'d>,
879 {
880 replace_with_or_abort(&mut self.state_machine, |sm| match sm {
881 StateMachine::DownloadingInitialState {
882 metadata,
883 merkle_tree,
884 initial_state,
885 } => {
886 let ecg_state = ecg::State::new();
887 let initial_state: Vec<u8> = initial_state
888 .into_iter()
889 .flatten()
890 .flatten()
891 .collect::<Vec<u8>>();
892 let Ok(latest_state) = serde_cbor::de::from_slice::<T>(&initial_state) else {
893 todo!("TODO: The store is invalid. Initial state does not parse.");
894 };
895 let decrypted_state = DecryptedState {
896 latest_state,
897 latest_headers: BTreeSet::new(),
898 };
899 StateMachine::Syncing {
900 metadata,
901 merkle_tree,
902 initial_state,
903 ecg_state,
904 decrypted_state,
905 }
906 }
907 _ => unreachable!("We already checked that we're downloading the initial state"),
908 });
909
910 let StateMachine::Syncing {
912 ecg_state,
913 decrypted_state,
914 ..
915 } = &self.state_machine
916 else {
917 unreachable!("We just set our state to syncing")
918 };
919 update_listeners(
920 &mut self.ecg_subscribers,
921 listeners,
922 &decrypted_state.latest_state,
923 ecg_state,
924 Some(peer),
925 );
926
927 let subs = std::mem::take(&mut self.block_subscribers);
929 for (_sub_peer, (block_ids, sub)) in subs {
930 let msg = handle_block_peer_request_helper(&self.state_machine, &block_ids)
932 .expect("Unreachable: We just set our state to syncing");
933 sub.send(Some(msg)).expect("TODO");
934 }
935 }
936}
937
938fn update_listeners<Header: ecg::ECGHeader + Clone + Debug, T: CRDT + Clone>(
939 ecg_subscribers: &mut BTreeMap<
940 DeviceId,
941 oneshot::Sender<ecg::UntypedState<Header::HeaderId, Header>>,
942 >,
943 listeners: &[UnboundedSender<StateUpdate<Header, T>>],
944 latest_state: &T,
945 ecg_state: &ecg::State<Header, T>,
946 from_peer: Option<DeviceId>,
947) {
948 for l in listeners {
949 let snapshot: StateUpdate<Header, T> = StateUpdate::Snapshot {
950 snapshot: latest_state.clone(),
951 ecg_state: ecg_state.clone(),
952 };
953 l.send(snapshot).expect("TODO");
954 }
955
956 let subs = std::mem::take(ecg_subscribers);
959 for (sub_peer, sub) in subs {
960 if Some(sub_peer) != from_peer {
962 sub.send(ecg_state.state.clone()).expect("TODO");
963 } else {
964 warn!("TODO: Add headers that they sent us to their_known.");
965 ecg_subscribers.insert(sub_peer, sub);
967 }
968 }
969}
970
971async fn manage_peers<OT: OssaType, T: CRDT<Time = OT::Time> + Clone + Send + 'static>(
974 store: &mut State<OT::StoreId, OT::ECGHeader, T, OT::Hash>,
975 shared_state: &SharedState<OT::StoreId>,
976 send_commands: &UnboundedSender<
977 UntypedStoreCommand<OT::Hash, <OT::ECGHeader as ECGHeader>::HeaderId, OT::ECGHeader>,
978 >,
979) where
980 OT::ECGHeader: Clone + Serialize + for<'d> Deserialize<'d> + Send + Sync,
982 <OT::ECGHeader as ECGHeader>::HeaderId: Serialize + for<'d> Deserialize<'d> + Send,
983 {
986 let peers: Vec<_> = store
989 .peers
990 .iter()
991 .filter(|p| p.1.outgoing_status.is_known())
992 .collect();
993 let peers: Vec<_> = {
994 let peer_states = shared_state.peer_state.read().await;
996 peers
997 .into_iter()
998 .filter_map(|(peer_id, _)| {
999 let chan = peer_states.get(peer_id)?;
1000 Some((*peer_id, chan.clone()))
1001 })
1002 .collect()
1003 };
1004 for (peer_id, command_chan) in peers {
1005 store.update_peer_to_initializing_outgoing(&peer_id);
1007
1008 let send_commands = send_commands.clone();
1010 let spawn_task = Box::new(move |_party, stream_id, sender, receiver| {
1011 tokio::spawn(async move {
1015 let (send_peer, recv_peer) = tokio::sync::mpsc::unbounded_channel::<
1017 StoreSyncCommand<<OT::ECGHeader as ECGHeader>::HeaderId, OT::ECGHeader>,
1018 >();
1019
1020 let register_cmd = UntypedStoreCommand::RegisterOutgoingPeerSyncing {
1021 peer: peer_id,
1022 send_peer,
1023 };
1024 send_commands.send(register_cmd).expect("TODO");
1025
1026 let mp = StoreSync::<OT::Hash, _, _>::new_server(peer_id, recv_peer, send_commands);
1028 run_miniprotocol_async::<_, OT>(mp, false, stream_id, sender, receiver).await;
1029
1030 debug!("Store sync with peer (with initiative) exited.")
1031
1032 })
1045 });
1046
1047 let store_id = store.store_id();
1049 let cmd = PeerManagerCommand::RequestStoreSync {
1050 store_id,
1051 spawn_task,
1052 };
1053 command_chan.send(cmd).expect("TODO");
1054 }
1055}
1056
1057fn apply_operations<OT: OssaType, T>(
1058 decrypted_state: &mut DecryptedState<OT::ECGHeader, T>,
1059 ecg_state: &ecg::State<OT::ECGHeader, T>,
1060 operation_header: &OT::ECGHeader,
1061 operation_body: OT::ECGBody<T>,
1062) where
1063 T: CRDT<Time = OT::Time>,
1064 T::Op: ConcretizeTime<<OT::ECGHeader as ECGHeader>::HeaderId>,
1066 OT::ECGBody<T>: ECGBody<
1067 T::Op,
1068 <T::Op as ConcretizeTime<<OT::ECGHeader as ECGHeader>::HeaderId>>::Serialized,
1069 Header = OT::ECGHeader,
1070 >,
1071{
1072 let causal_state = OT::to_causal_state(ecg_state);
1073 for operation in operation_body.operations(operation_header.get_header_id()) {
1074 replace_with_or_abort(&mut decrypted_state.latest_state, |s| {
1075 s.apply(causal_state, operation)
1076 });
1077 }
1078}
1079
1080pub(crate) async fn run_handler<OT: OssaType, T>(
1083 mut store: State<OT::StoreId, OT::ECGHeader, T, OT::Hash>,
1084 mut recv_commands: UnboundedReceiver<StoreCommand<OT::ECGHeader, OT::ECGBody<T>, T>>,
1085 send_commands_untyped: UnboundedSender<
1086 UntypedStoreCommand<OT::Hash, <OT::ECGHeader as ECGHeader>::HeaderId, OT::ECGHeader>,
1087 >,
1088 mut recv_commands_untyped: UnboundedReceiver<
1089 UntypedStoreCommand<OT::Hash, <OT::ECGHeader as ECGHeader>::HeaderId, OT::ECGHeader>,
1090 >,
1091 shared_state: SharedState<OT::StoreId>,
1092) where
1093 <OT as OssaType>::ECGHeader:
1094 Send + Sync + Clone + Serialize + for<'d> Deserialize<'d> + 'static,
1095 T::Op: ConcretizeTime<<OT::ECGHeader as ECGHeader>::HeaderId>,
1097 OT::ECGBody<T>: Serialize
1098 + for<'d> Deserialize<'d>
1099 + Debug
1100 + ECGBody<
1101 T::Op,
1102 <T::Op as ConcretizeTime<<OT::ECGHeader as ECGHeader>::HeaderId>>::Serialized,
1103 Header = OT::ECGHeader,
1104 >,
1105 <<OT as OssaType>::ECGHeader as ECGHeader>::HeaderId:
1107 Send + Serialize + for<'d> Deserialize<'d>,
1108 T: CRDT<Time = OT::Time> + Debug + Clone + Send + 'static + for<'d> Deserialize<'d>,
1110{
1111 let mut listeners: Vec<UnboundedSender<StateUpdate<OT::ECGHeader, T>>> = vec![];
1112
1113 loop {
1115 tokio::select! {
1116 cmd_m = recv_commands.recv() => {
1117 let Some(cmd) = cmd_m else {
1118 error!("Failed to receive StoreCommand");
1119 return;
1120 };
1121
1122 match cmd {
1126 StoreCommand::Apply {
1127 operation_header,
1128 operation_body,
1129 } => {
1130 store.state_machine = match store.state_machine {
1131 StateMachine::Syncing { metadata, merkle_tree, initial_state , ecg_state, decrypted_state } => {
1159 let mut ecg_state = ecg_state;
1160 let mut decrypted_state = decrypted_state;
1161
1162 let serialized_operations = serde_cbor::to_vec(&operation_body).expect("TODO");
1164 let success = ecg_state.insert_header(operation_header.clone(), serialized_operations);
1165 if !success {
1166 todo!("Invalid header"); }
1168
1169 apply_operations::<OT, _>(&mut decrypted_state, &ecg_state, &operation_header, operation_body);
1175
1176 update_listeners(&mut store.ecg_subscribers, &listeners, &decrypted_state.latest_state, &ecg_state, None);
1178
1179 StateMachine::Syncing { metadata, merkle_tree, initial_state, ecg_state, decrypted_state }
1180 }
1181 _ => {
1182 warn!("JP: Does this ever happen?");
1183 store.state_machine
1184 }
1185 };
1186 }
1187 StoreCommand::SubscribeState { send_state } => {
1188 let snapshot = match &store.state_machine {
1190 StateMachine::DownloadingMetadata { .. } => {
1191 StateUpdate::Downloading { percent: 0 }
1192 }
1193 StateMachine::DownloadingMerkle { .. } => {
1194 StateUpdate::Downloading { percent: 0 }
1195 }
1196 StateMachine::DownloadingInitialState { metadata, initial_state, .. } => {
1197 let percent = if metadata.initial_state_size == 0 {
1198 0
1199 } else {
1200 let downloaded = initial_state.iter().filter(|p| p.is_some()).count() as u64;
1201 100 * downloaded * BLOCK_SIZE / metadata.initial_state_size
1202 };
1203 StateUpdate::Downloading { percent }
1204 }
1205 StateMachine::Syncing { ref ecg_state, ref decrypted_state, .. } => {
1206 StateUpdate::Snapshot {
1207 snapshot: decrypted_state.latest_state.clone(),
1208 ecg_state: ecg_state.clone(),
1209 }
1210 }
1211 };
1212 send_state.send(snapshot).expect("TODO");
1213
1214 listeners.push(send_state);
1216 }
1217 }
1218 }
1219 cmd_m = recv_commands_untyped.recv() => {
1220 let Some(cmd) = cmd_m else {
1221 error!("Failed to receive UntypedStoreCommand");
1222 return;
1223 };
1224 match cmd {
1225 UntypedStoreCommand::RegisterPeers { peers } => {
1228 debug!("Received UntypedStoreCommand::RegisterPeers: {:?}", peers);
1229
1230 for peer in peers {
1232 store.insert_known_peer(peer);
1233 }
1234
1235 debug!("Peer statuses: {:?}", store.peers);
1236
1237 manage_peers::<OT,T>(&mut store, &shared_state, &send_commands_untyped).await;
1241 }
1242 UntypedStoreCommand::SyncWithPeer { peer, response_chan } => {
1246 debug!("Received UntypedStoreCommand::SyncWithPeer: {:?}", peer);
1247
1248 store.insert_known_peer(peer);
1250
1251 let response = {
1252 if let Some(status) = store.peers.get(&peer) {
1254 if status.incoming_status.is_known() {
1255 store.update_peer_to_initializing_incoming(&peer);
1257
1258 let send_commands_untyped = send_commands_untyped.clone();
1260 let spawn_task: Box<SpawnMultiplexerTask> = Box::new(move |party, stream_id, sender, receiver| {
1261 tokio::spawn(async move {
1265 debug!("Sync with peer (without initiative).");
1266
1267 let register_cmd = UntypedStoreCommand::RegisterIncomingPeerSyncing {
1269 peer,
1270 };
1271 send_commands_untyped.send(register_cmd).expect("TODO");
1272
1273 let mp = StoreSync::<OT::Hash, _, _>::new_client(peer, send_commands_untyped);
1275 run_miniprotocol_async::<_, OT>(mp, true, stream_id, sender, receiver).await;
1276 debug!("Store sync with peer (without initiative) exited.")
1277 })
1278 });
1279 Some(spawn_task)
1280 } else {
1281 debug!("Store is already running");
1282 None
1283 }
1284 } else {
1285 unreachable!("Don't know this peer.");
1286 None
1288 }
1289 };
1290
1291 response_chan.send(response).or(Err(())).expect("TODO");
1292 }
1293 UntypedStoreCommand::RegisterOutgoingPeerSyncing{ peer, send_peer } => {
1294 let outgoing_status = OutgoingPeerStatus {
1297 sender_peer: send_peer,
1298 is_outstanding: false,
1299 };
1300 store.update_peer_to_syncing_outgoing(&peer, outgoing_status);
1301
1302 store.send_sync_requests();
1304 }
1305 UntypedStoreCommand::RegisterIncomingPeerSyncing{ peer } => {
1306 store.update_peer_to_syncing_incoming(&peer);
1310 }
1311 UntypedStoreCommand::HandleMetadataPeerRequest(HandlePeerRequest { peer, request, response_chan }) => {
1312 store.handle_metadata_peer_request(peer, response_chan);
1313 }
1314 UntypedStoreCommand::HandleMerklePeerRequest(HandlePeerRequest { peer, request, response_chan }) => {
1315 store.handle_merkle_peer_request(peer, request, response_chan);
1316 }
1317 UntypedStoreCommand::HandleBlockPeerRequest(HandlePeerRequest { peer, request, response_chan }) => {
1318 store.handle_block_peer_request(peer, request, response_chan);
1319 }
1320 UntypedStoreCommand::ReceivedMetadata { peer, metadata } => {
1321 store.handle_received_metadata(peer, metadata, &listeners);
1322 store.send_sync_requests();
1323 }
1324 UntypedStoreCommand::ReceivedMerkleHashes { peer, ranges, nodes } => {
1325 store.handle_received_merkle_hashes(peer, ranges, nodes, &listeners);
1326 store.send_sync_requests();
1327 }
1328 UntypedStoreCommand::ReceivedInitialStateBlocks { peer, ranges, blocks } => {
1329 store.handle_received_initial_state_blocks(peer, ranges, blocks, &listeners);
1330 store.send_sync_requests();
1331 }
1332 UntypedStoreCommand::ReceivedECGOperations { peer, operations } => {
1333 store.handle_received_ecg_operations::<OT>(peer, operations, &listeners);
1334 store.send_sync_requests();
1335 }
1336 UntypedStoreCommand::SubscribeECG { peer, tips, response_chan } => {
1337 store.handle_ecg_subscribe(peer, tips, response_chan);
1338 }
1339 }
1340 }
1341 }
1342 }
1343 debug!("Store thread exiting.");
1344}
1345
1346pub(crate) enum StoreCommand<Header: ECGHeader, Body, T> {
1347 Apply {
1348 operation_header: Header, operation_body: Body, },
1351 SubscribeState {
1353 send_state: UnboundedSender<StateUpdate<Header, T>>,
1354 },
1355}
1356
1357pub enum StateUpdate<Header: ECGHeader, T> {
1358 Downloading {
1359 percent: u64,
1361 },
1362 Snapshot {
1363 snapshot: T,
1364 ecg_state: ecg::State<Header, T>,
1365 },
1367}
1368
1369type HandlePeerResponse<Response> = Result<Response, oneshot::Receiver<Option<Response>>>;
1376
1377pub(crate) enum UntypedStoreCommand<Hash, HeaderId, Header> {
1380 RegisterPeers {
1382 peers: Vec<DeviceId>,
1383 },
1384 SyncWithPeer {
1386 peer: DeviceId,
1387 response_chan: oneshot::Sender<Option<Box<SpawnMultiplexerTask>>>,
1388 },
1389 RegisterOutgoingPeerSyncing {
1390 peer: DeviceId,
1391 send_peer: UnboundedSender<StoreSyncCommand<HeaderId, Header>>,
1392 },
1393 HandleMetadataPeerRequest(HandlePeerRequest<(), v0::MetadataHeader<Hash>>),
1394 HandleMerklePeerRequest(HandlePeerRequest<Vec<Range<u64>>, Vec<Hash>>),
1395 HandleBlockPeerRequest(HandlePeerRequest<Vec<Range<u64>>, Vec<Option<Vec<u8>>>>),
1396 RegisterIncomingPeerSyncing {
1398 peer: DeviceId,
1399 },
1400 ReceivedMetadata {
1401 peer: DeviceId,
1402 metadata: MetadataHeader<Hash>,
1403 },
1404 ReceivedMerkleHashes {
1405 peer: DeviceId,
1406 ranges: Vec<Range<u64>>,
1407 nodes: Vec<Hash>,
1408 },
1409 ReceivedInitialStateBlocks {
1410 peer: DeviceId,
1411 ranges: Vec<Range<u64>>,
1412 blocks: Vec<Option<Vec<u8>>>,
1413 },
1414 ReceivedECGOperations {
1415 peer: DeviceId,
1416 operations: Vec<(Header, RawECGBody)>,
1417 },
1418 SubscribeECG {
1419 peer: DeviceId,
1420 tips: Option<BTreeSet<HeaderId>>,
1421 response_chan: oneshot::Sender<ecg::UntypedState<HeaderId, Header>>,
1422 },
1423}
1424
1425pub(crate) struct HandlePeerRequest<Request, Response> {
1426 pub(crate) peer: DeviceId,
1427 pub(crate) request: Request, pub(crate) response_chan: oneshot::Sender<HandlePeerResponse<Response>>,
1430}
1431
1432fn handle_merkle_peer_request_helper<H: Copy>(
1433 merkle_tree: &MerkleTree<H>,
1434 node_ids: &[Range<u64>],
1435) -> Vec<H> {
1436 warn!("TODO: check ranges are in bounds or return error");
1437 let hashes: Vec<_> = node_ids
1438 .iter()
1439 .cloned()
1440 .flatten()
1441 .map(|i| {
1442 merkle_tree
1443 .get(i)
1444 .expect("TODO: Properly handle invalid requests")
1445 .clone()
1446 })
1447 .collect();
1448 hashes
1449}
1450
1451fn handle_block_peer_request_helper<StoreId, Header: ecg::ECGHeader, T: CRDT, Hash>(
1452 state_machine: &StateMachine<StoreId, Header, T, Hash>,
1453 block_ids: &[Range<u64>],
1454) -> Option<Vec<Option<Vec<u8>>>> {
1455 match state_machine {
1457 StateMachine::DownloadingMetadata { .. } => None,
1458 StateMachine::DownloadingMerkle { .. } => None,
1459 StateMachine::DownloadingInitialState { initial_state, .. } => {
1460 Some(handle_peer_request_range_helper(initial_state, block_ids))
1461 }
1462 StateMachine::Syncing { initial_state, .. } => {
1463 let blocks: Vec<_> = block_ids
1464 .iter()
1465 .cloned()
1466 .flatten()
1467 .map(|i| {
1468 warn!("TODO: Properly handle invalid requests"); let start: usize = (i * BLOCK_SIZE) as usize;
1470 let end = std::cmp::min(((i + 1) * BLOCK_SIZE) as usize, initial_state.len());
1471 Some(initial_state[start..end].to_vec())
1472 })
1473 .collect();
1474 Some(blocks)
1475 }
1476 }
1477}
1478
1479fn handle_peer_request_range_helper<T: Clone>(slice: &[T], ids: &[Range<u64>]) -> Vec<T> {
1480 warn!("TODO: check ranges are in bounds or return error");
1481 let hashes: Vec<_> = ids
1482 .iter()
1483 .cloned()
1484 .flatten()
1485 .map(|i| {
1486 slice
1487 .get(i as usize)
1488 .expect("TODO: Properly handle invalid requests")
1489 .clone()
1490 })
1491 .collect();
1492 hashes
1493}