1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! Common trait for sync protocol implementations.
//!
//! This module defines the [`SyncProtocolExecutor`] trait that all sync protocols
//! implement. This enables:
//!
//! - Protocol implementation details contained within each protocol module
//! - Common interface for `SyncManager` to invoke any protocol
//! - Same code path for production and simulation (only `Store` backend differs)
//!
//! # Architecture
//!
//! ```text
//! ┌─────────────────────────────────────────────────────────────────┐
//! │ SyncProtocolExecutor trait │
//! │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
//! │ │ HashComparison │ │ Snapshot │ │ LevelWise │ │
//! │ │ Protocol │ │ Protocol │ │ Protocol │ │
//! │ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
//! │ │ │ │ │
//! │ └────────────────────┼────────────────────┘ │
//! │ │ │
//! │ ┌───────────┴───────────┐ │
//! │ │ SyncTransport │ │
//! │ │ (Stream or SimStream) │ │
//! │ └───────────────────────┘ │
//! └─────────────────────────────────────────────────────────────────┘
//! ```
//!
//! # Responder Dispatch Model
//!
//! The `SyncManager` dispatches incoming sync requests using this flow:
//!
//! 1. Manager receives stream and calls `recv()` to get the first message
//! 2. Manager matches on `InitPayload` to determine which protocol to use
//! 3. Manager extracts protocol-specific data from the first message
//! 4. Manager calls `run_responder()` passing the extracted data via `ResponderInit`
//!
//! This design is necessary because the manager must peek at the first message
//! for routing, but once consumed it cannot be "un-read". The `ResponderInit`
//! associated type allows each protocol to declare what data it needs from
//! the first request.
//!
//! # Example
//!
//! ```ignore
//! use calimero_node_primitives::sync::{SyncProtocolExecutor, HashComparisonProtocol};
//!
//! // Production initiator
//! let mut transport = StreamTransport::new(&mut stream);
//! let stats = HashComparisonProtocol::run_initiator(
//! &mut transport,
//! &store,
//! context_id,
//! identity,
//! HashComparisonConfig { remote_root_hash },
//! ).await?;
//!
//! // Production responder (manager extracts first request data)
//! let first_request = HashComparisonFirstRequest { node_id, max_depth };
//! HashComparisonProtocol::run_responder(
//! &mut transport,
//! &store,
//! context_id,
//! identity,
//! first_request,
//! ).await?;
//! ```
use async_trait;
use ContextId;
use PublicKey;
use Store;
use Result;
use SyncTransport;
/// Trait for sync protocol implementations.
///
/// Each sync protocol (HashComparison, Snapshot, LevelWise, etc.) implements
/// this trait. The protocol logic is generic over:
///
/// - `T: SyncTransport` - the transport layer (production streams or simulation channels)
/// - `Store` - the storage backend (RocksDB or InMemoryDB)
///
/// This enables the same protocol code to run in both production and simulation.
///
/// Note: Uses `?Send` because `RuntimeEnv` (used for storage access) contains `Rc`
/// which is not `Send`. Callers must not spawn these futures across threads.