1use alloy::network::Network;
2use alloy::primitives::Address;
3use alloy::providers::Provider;
4use alloy::rpc::types::{Filter, Log};
5use alloy::sol_types::SolEvent;
6use alloy::transports::Transport;
7use anyhow::anyhow;
8use anyhow::Result;
9use futures::StreamExt;
10use indicatif::ProgressBar;
11use log::info;
12use rand::Rng;
13use std::collections::{BTreeMap, HashMap};
14use std::sync::Arc;
15use tokio::sync::{Mutex, Semaphore};
16use tokio::time::{interval, Duration};
17
18use crate::events::*;
19use crate::pools::pool_builder;
20use crate::pools::pool_structures::v3_structure::process_tick_data;
21use crate::pools::PoolFetcher;
22use crate::util::create_progress_bar;
23use crate::{Chain, Pool, PoolInfo, PoolType};
24
25const MAX_RETRIES: u32 = 5;
27const INITIAL_BACKOFF: u64 = 1000; #[derive(Debug)]
31struct EventConfig {
32 events: &'static [&'static str],
33 step_size: u64,
34 description: &'static str,
35 requires_initial_sync: bool,
36}
37
38pub struct Rpc;
39impl Rpc {
40 pub async fn fetch_pool_addrs<P, T, N>(
42 start_block: u64,
43 end_block: u64,
44 provider: Arc<P>,
45 fetcher: Arc<dyn PoolFetcher>,
46 chain: Chain,
47 rate_limit: u64,
48 ) -> Result<Vec<Address>>
49 where
50 P: Provider<T, N> + 'static,
51 T: Transport + Clone + 'static,
52 N: Network,
53 {
54 let filter = Filter::new()
56 .address(fetcher.factory_address(chain))
57 .event(fetcher.pair_created_signature());
58
59 let step_size: u64 = 500; let num_tasks = (end_block - start_block) / step_size + 1;
61 let pb_info = format!(
62 " 📍 发现 {} 新池地址",
63 fetcher.pool_type()
64 );
65 let progress_bar = Arc::new(create_progress_bar(num_tasks, pb_info));
66
67 let logs = Rpc::fetch_event_logs(
69 start_block,
70 end_block,
71 step_size, provider,
73 rate_limit,
74 progress_bar,
75 filter,
76 )
77 .await?;
78
79 let addresses: Vec<Address> = logs
81 .iter()
82 .map(|log| fetcher.log_to_address(&log.inner))
83 .collect();
84 anyhow::Ok(addresses)
85 }
86
87 pub async fn populate_pools<P, T, N>(
88 pool_addrs: Vec<Address>,
89 provider: Arc<P>,
90 pool: PoolType,
91 fetcher: Arc<dyn PoolFetcher>,
92 rate_limit: u64,
93 chain: Chain
94 ) -> Result<Vec<Pool>>
95 where
96 P: Provider<T, N> + 'static,
97 T: Transport + Clone + 'static,
98 N: Network,
99 {
100 let batch_size = 50; let total_tasks = (pool_addrs.len() + batch_size - 1) / batch_size; let progress_bar = create_progress_bar(total_tasks as u64, format!(" 💾 加载 {} 池数据 ({} 个池)", pool, pool_addrs.len()));
106 let semaphore = Arc::new(Semaphore::new(rate_limit as usize));
107 let interval = Arc::new(tokio::sync::Mutex::new(interval(Duration::from_secs_f64(
108 1.0 / rate_limit as f64,
109 ))));
110
111 let addr_chunks: Vec<Vec<Address>> = pool_addrs
113 .chunks(batch_size)
114 .map(|chunk| chunk.to_vec())
115 .collect();
116
117 let mut stream = futures::stream::iter(addr_chunks.into_iter().map(|chunk| {
118 let provider = provider.clone();
119 let sem = semaphore.clone();
120 let pb = progress_bar.clone();
121 let fetcher = fetcher.clone();
122 let interval = interval.clone();
123 let data = fetcher.get_pool_repr();
124
125 async move {
126 let _permit = sem.acquire().await.unwrap();
127 interval.lock().await.tick().await;
128 let mut retry_count = 0;
129 let mut backoff = 1000; loop {
131 match pool_builder::build_pools(
133 &provider,
134 chunk.clone(),
135 pool,
136 data.clone(),
137 chain
138 )
139 .await
140 {
141 Ok(populated_pools) if !populated_pools.is_empty() => {
142 pb.inc(1);
143 drop(provider);
144 return anyhow::Ok::<Vec<Pool>>(populated_pools);
145 }
146 Err(e) => {
147 if retry_count >= MAX_RETRIES {
148 info!("Failed to populate pools data: {}", e);
149 drop(provider);
150 return Ok(Vec::new());
151 }
152 let jitter = rand::thread_rng().gen_range(0..=100);
153 let sleep_duration = Duration::from_millis(backoff + jitter);
154 tokio::time::sleep(sleep_duration).await;
155 retry_count += 1;
156 backoff *= 2; }
158 _ => continue,
159 }
160 }
161 }
162 }))
163 .buffer_unordered(rate_limit as usize);
164
165 let mut all_pools = Vec::new();
166
167 while let Some(pool_res) = stream.next().await {
168 match pool_res {
169 Ok(pool) => all_pools.extend(pool),
170 Err(e) => return Err(e),
171 }
172 }
173
174 progress_bar.finish_with_message(format!("✅ {} 池数据获取完成", pool));
175 Ok(all_pools)
176 }
177
178 pub async fn populate_liquidity<P, T, N>(
179 start_block: u64,
180 end_block: u64,
181 pools: &mut [Pool],
182 provider: Arc<P>,
183 pool_type: PoolType,
184 rate_limit: u64,
185 is_initial_sync: bool,
186 ) -> anyhow::Result<()>
187 where
188 P: Provider<T, N> + Sync + 'static,
189 T: Transport + Sync + Clone,
190 N: Network,
191 {
192 if pools.is_empty() {
193 return anyhow::Ok(());
194 }
195
196 let address_to_index: HashMap<Address, usize> = pools
197 .iter()
198 .enumerate()
199 .map(|(i, pool)| (pool.address(), i))
200 .collect();
201
202 let batch_size = 1_000_000;
203 let mut current_block = start_block;
204
205 let config = Rpc::get_event_config(pool_type, is_initial_sync);
207 if is_initial_sync && config.requires_initial_sync {
208 return anyhow::Ok(());
209 }
210
211 let num_tasks = (end_block - start_block) / config.step_size + 1;
213 let pb_info = format!(
214 " 🔄 同步 {} 流动性数据 ({} 个池)",
215 pool_type, pools.len()
216 );
217 let progress_bar = Arc::new(create_progress_bar(num_tasks, pb_info));
218
219 while current_block <= end_block {
221 let batch_end = (current_block + batch_size).min(end_block);
222
223 let logs = Rpc::fetch_logs_for_config(
224 &config,
225 current_block,
226 batch_end,
227 provider.clone(),
228 progress_bar.clone(),
229 rate_limit,
230 )
231 .await?;
232
233 let mut ordered_logs: BTreeMap<u64, Vec<Log>> = BTreeMap::new();
235 for log in logs {
236 if let Some(block_number) = log.block_number {
237 ordered_logs.entry(block_number).or_default().push(log);
238 }
239 }
240
241 let mut logs_processed = 0;
243 for (_, log_group) in ordered_logs {
244 for log in log_group {
245 let address = log.address();
246 if let Some(&index) = address_to_index.get(&address) {
247 if let Some(pool) = pools.get_mut(index) {
248 process_tick_data(
250 pool.get_v3_mut().unwrap(),
251 log,
252 pool_type,
253 is_initial_sync,
254 );
255 logs_processed += 1;
256 }
257 }
258 }
259 }
260
261 progress_bar.inc(1);
263 if logs_processed > 0 {
264 progress_bar.set_message(format!("已处理 {} 个事件", logs_processed));
265 }
266 current_block = batch_end + 1;
267 }
268
269 progress_bar.finish_with_message(format!("完成"));
270 anyhow::Ok(())
271 }
272
273 pub async fn fetch_event_logs<T, N, P>(
274 start_block: u64,
275 end_block: u64,
276 step_size: u64,
277 provider: Arc<P>,
278 rate_limit: u64,
279 progress_bar: Arc<ProgressBar>,
280 filter: Filter,
281 ) -> anyhow::Result<Vec<Log>>
282 where
283 T: Transport + Clone,
284 N: Network,
285 P: Provider<T, N> + 'static,
286 {
287 let block_range = Rpc::get_block_range(step_size, start_block, end_block);
289
290 let semaphore = Arc::new(Semaphore::new(rate_limit as usize));
292 let interval = Arc::new(Mutex::new(interval(Duration::from_secs_f64(
293 1.0 / rate_limit as f64,
294 ))));
295
296 let mut stream =
298 futures::stream::iter(block_range.into_iter().map(|(from_block, to_block)| {
299 let provider = provider.clone();
300 let sem = semaphore.clone();
301 let pb = progress_bar.clone();
302 let interval = interval.clone();
303 let filter = filter.clone();
304
305 async move {
306 let _permit = sem.acquire().await.unwrap();
307 interval.lock().await.tick().await;
308
309 let filter = filter.from_block(from_block).to_block(to_block);
310 let logs = Rpc::get_logs_with_retry(provider, &filter).await;
311 if logs.is_ok() {
312 pb.inc(1);
313 }
314 logs
315 }
316 }))
317 .buffer_unordered(rate_limit as usize); let mut all_logs = Vec::new();
320
321 while let Some(result) = stream.next().await {
323 match result {
324 Ok(logs) => all_logs.extend(logs),
325 Err(e) => return Err(e),
326 }
327 }
328
329 progress_bar.finish_with_message(format!("完成 ({} 个事件)", all_logs.len()));
330 Ok(all_logs)
331 }
332
333 async fn fetch_logs_for_config<P, T, N>(
337 config: &EventConfig,
338 start_block: u64,
339 end_block: u64,
340 provider: Arc<P>,
341 progress_bar: Arc<ProgressBar>,
342 rate_limit: u64,
343 ) -> Result<Vec<Log>>
344 where
345 P: Provider<T, N> + 'static,
346 T: Transport + Clone + 'static,
347 N: Network,
348 {
349 let filter = Filter::new().events(config.events.iter().copied());
350 Rpc::fetch_event_logs(
351 start_block,
352 end_block,
353 config.step_size,
354 provider,
355 rate_limit,
356 progress_bar,
357 filter,
358 )
359 .await
360 }
361
362 async fn get_logs_with_retry<P, T, N>(
364 provider: Arc<P>,
365 filter: &Filter,
366 ) -> anyhow::Result<Vec<Log>>
367 where
368 P: Provider<T, N> + 'static,
369 T: Transport + Clone + 'static,
370 N: Network,
371 {
372 let mut retry_count = 0;
373 let mut backoff = INITIAL_BACKOFF;
374
375 loop {
376 match provider.get_logs(filter).await {
377 Ok(logs) => {
378 return anyhow::Ok(logs);
379 }
380 Err(e) => {
381 if retry_count >= MAX_RETRIES {
382 return Err(anyhow!(e));
383 }
384 let jitter = rand::thread_rng().gen_range(0..=100);
385 let sleep_duration = Duration::from_millis(backoff + jitter);
386 tokio::time::sleep(sleep_duration).await;
387 retry_count += 1;
388 backoff *= 2;
389 }
390 }
391 }
392 }
393
394 fn get_event_config(_pool_type: PoolType, is_initial_sync: bool) -> EventConfig {
395 if is_initial_sync {
397 EventConfig {
398 events: &[DataEvents::Mint::SIGNATURE, DataEvents::Burn::SIGNATURE],
399 step_size: 1500,
400 description: "Tick sync",
401 requires_initial_sync: false, }
403 } else {
404 EventConfig {
405 events: &[
406 DataEvents::Mint::SIGNATURE,
407 DataEvents::Burn::SIGNATURE,
408 DataEvents::Swap::SIGNATURE,
409 ],
410 step_size: 50,
411 description: "Full sync",
412 requires_initial_sync: true, }
414 }
415 }
416
417 pub fn get_block_range(step_size: u64, start_block: u64, end_block: u64) -> Vec<(u64, u64)> {
419 if start_block == end_block {
420 return vec![(start_block, end_block)];
421 }
422
423 let block_difference = end_block.saturating_sub(start_block);
424 let (_, step_size) = if block_difference < step_size {
425 (1, block_difference)
426 } else {
427 (
428 ((block_difference as f64) / (step_size as f64)).ceil() as u64,
429 step_size,
430 )
431 };
432 let block_ranges: Vec<(u64, u64)> = (start_block..=end_block)
433 .step_by(step_size as usize)
434 .map(|from_block| {
435 let to_block = (from_block + step_size - 1).min(end_block);
436 (from_block, to_block)
437 })
438 .collect();
439 block_ranges
440 }
441}