1use alloy_network::Network;
2use alloy_primitives::Address;
3use alloy_provider::Provider;
4use eyre::Result;
5use kabu_core_components::Component;
6use reth_tasks::TaskExecutor;
7use revm::DatabaseRef;
8use revm::{Database, DatabaseCommit};
9use std::marker::PhantomData;
10use std::sync::Arc;
11use tokio::sync::RwLock;
12use tracing::{debug, error, info};
13
14use crate::pool_loader_actor::fetch_and_add_pool_by_pool_id;
15
16use kabu_core_blockchain::{Blockchain, BlockchainState};
17use kabu_evm_db::KabuDBError;
18use kabu_node_debug_provider::DebugProviderExt;
19use kabu_types_market::MarketState;
20use kabu_types_market::required_state::{RequiredState, RequiredStateReader};
21use kabu_types_market::{Market, PoolClass, PoolId, PoolLoaders};
22use reth_node_types::NodePrimitives;
23
24async fn required_pools_loader_worker<P, N, DB, NP>(
25 client: P,
26 pool_loaders: Arc<PoolLoaders<P, N, NP>>,
27 pools: Vec<(PoolId, PoolClass)>,
28 required_state: Option<RequiredState>,
29 market: Arc<RwLock<Market>>,
30 market_state: Arc<RwLock<MarketState<DB>>>,
31) -> Result<String>
32where
33 N: Network<TransactionRequest = alloy_rpc_types::TransactionRequest>,
34 P: Provider<N> + DebugProviderExt<N> + Send + Sync + Clone + 'static,
35 DB: Database<Error = KabuDBError> + DatabaseRef<Error = KabuDBError> + DatabaseCommit + Send + Sync + Clone + 'static,
36 NP: NodePrimitives + 'static,
37{
38 for (pool_id, pool_class) in pools {
39 debug!(class=%pool_class, %pool_id, "Loading pool");
40 match fetch_and_add_pool_by_pool_id(client.clone(), market.clone(), market_state.clone(), pool_loaders.clone(), pool_id, pool_class)
41 .await
42 {
43 Ok(_) => {
44 info!(class=%pool_class, %pool_id, "pool loaded")
45 }
46 Err(error) => {
47 error!(%error, "load_pool_with_provider")
48 }
49 }
50 }
51 if let Some(required_state) = required_state {
77 let update = RequiredStateReader::fetch_calls_and_slots(client.clone(), required_state, None).await?;
78 market_state.write().await.apply_geth_update(update);
79 }
80
81 Ok("required_pools_loader_worker".to_string())
82}
83
84pub struct RequiredPoolLoaderActor<P, N, DB, NP>
85where
86 N: Network,
87 P: Provider<N> + DebugProviderExt<N> + Send + Sync + Clone + 'static,
88 DB: Database + DatabaseRef + DatabaseCommit + Clone + Send + Sync + 'static,
89 NP: NodePrimitives + 'static,
90{
91 client: P,
92 pool_loaders: Arc<PoolLoaders<P, N, NP>>,
93 pools: Vec<(PoolId, PoolClass)>,
94 required_state: Option<RequiredState>,
95
96 market: Option<Arc<RwLock<Market>>>,
97
98 market_state: Option<Arc<RwLock<MarketState<DB>>>>,
99 _n: PhantomData<N>,
100}
101
102impl<P, N, DB, NP> RequiredPoolLoaderActor<P, N, DB, NP>
103where
104 N: Network,
105 P: Provider<N> + DebugProviderExt<N> + Send + Sync + Clone + 'static,
106 DB: Database + DatabaseRef + DatabaseCommit + Clone + Send + Sync + 'static,
107 NP: NodePrimitives + 'static,
108{
109 pub fn new(client: P, pool_loaders: Arc<PoolLoaders<P, N, NP>>) -> Self {
110 Self { client, pools: Vec::new(), pool_loaders, required_state: None, market: None, market_state: None, _n: PhantomData }
111 }
112
113 pub fn with_pool_address(self, address: Address, pool_class: PoolClass) -> Self {
114 let mut pools = self.pools;
115 pools.push((PoolId::Address(address), pool_class));
116 Self { pools, ..self }
117 }
118
119 pub fn on_bc(self, bc: &Blockchain<NP>, state: &BlockchainState<DB, NP>) -> Self {
120 Self { market: Some(bc.market()), market_state: Some(state.market_state_commit()), ..self }
121 }
122
123 pub fn with_required_state(self, required_state: RequiredState) -> Self {
124 Self { required_state: Some(required_state), ..self }
125 }
126}
127
128impl<P, N, DB, NP> Component for RequiredPoolLoaderActor<P, N, DB, NP>
129where
130 N: Network<TransactionRequest = alloy_rpc_types::TransactionRequest>,
131 P: Provider<N> + DebugProviderExt<N> + Send + Sync + Clone + 'static,
132 DB: Database<Error = KabuDBError> + DatabaseRef<Error = KabuDBError> + DatabaseCommit + Send + Sync + Clone + 'static,
133 NP: NodePrimitives + 'static,
134{
135 fn spawn(self, executor: TaskExecutor) -> Result<()> {
136 let _name = self.name();
137 let client = self.client;
138 let pool_loaders = self.pool_loaders;
139 let pools = self.pools;
140 let required_state = self.required_state;
141 let market = self.market.ok_or_else(|| eyre::eyre!("market not set"))?;
142 let market_state = self.market_state.ok_or_else(|| eyre::eyre!("market_state not set"))?;
143
144 executor.spawn(async move {
145 if let Err(e) = required_pools_loader_worker(client, pool_loaders, pools, required_state, market, market_state).await {
146 error!("Required pools loader worker failed: {}", e);
147 }
148 });
149
150 Ok(())
151 }
152 fn name(&self) -> &'static str {
153 "RequiredPoolLoaderActor"
154 }
155}