1use crate::context::KabuContext;
4use crate::node::ComponentSet;
5use crate::traits::ComponentBuilder;
6use alloy_network::Ethereum;
7use alloy_provider::Provider;
8use eyre::Result;
9use kabu_core_components::Component;
10use kabu_evm_db::{DatabaseKabuExt, KabuDBError};
11use kabu_node_debug_provider::DebugProviderExt;
12use kabu_types_entities::BlockHistoryState;
13use reth::revm::{Database, DatabaseCommit, DatabaseRef};
14use reth_ethereum_primitives::EthPrimitives;
15use reth_tasks::TaskExecutor;
16use std::marker::PhantomData;
17
18type ConfiguredNodeBuilder<R, P, DB, Evm, N, E, S, M, B, Est, H, Mer, Mon, Sig> =
20 NodeBuilder<R, P, DB, Evm, ComponentSet<N, E, S, M, B, Est, H, Mer, Mon, Sig>>;
21
22pub struct NodeBuilder<R, P, DB, Evm, Components = ()>
24where
25 R: Send + Sync + Clone + 'static,
26 P: Provider<Ethereum> + Send + Sync + Clone + 'static,
27 DB: DatabaseRef<Error = KabuDBError>
28 + Database<Error = KabuDBError>
29 + DatabaseCommit
30 + DatabaseKabuExt
31 + BlockHistoryState<EthPrimitives>
32 + Send
33 + Sync
34 + Clone
35 + Default
36 + 'static,
37 Evm: Clone + Send + Sync + 'static,
38{
39 context: Option<KabuContext<R, P, DB, Evm>>,
40 components: Components,
41 _phantom: PhantomData<(R, P, DB, Evm)>,
42}
43
44impl<R, P, DB, Evm> Default for NodeBuilder<R, P, DB, Evm, ()>
45where
46 R: Send + Sync + Clone + 'static,
47 P: Provider<Ethereum> + Send + Sync + Clone + 'static,
48 DB: DatabaseRef<Error = KabuDBError>
49 + Database<Error = KabuDBError>
50 + DatabaseCommit
51 + DatabaseKabuExt
52 + BlockHistoryState<EthPrimitives>
53 + Send
54 + Sync
55 + Clone
56 + Default
57 + 'static,
58 Evm: Clone + Send + Sync + 'static,
59{
60 fn default() -> Self {
61 Self::new()
62 }
63}
64
65impl<R, P, DB, Evm> NodeBuilder<R, P, DB, Evm, ()>
66where
67 R: Send + Sync + Clone + 'static,
68 P: Provider<Ethereum> + Send + Sync + Clone + 'static,
69 DB: DatabaseRef<Error = KabuDBError>
70 + Database<Error = KabuDBError>
71 + DatabaseCommit
72 + DatabaseKabuExt
73 + BlockHistoryState<EthPrimitives>
74 + Send
75 + Sync
76 + Clone
77 + Default
78 + 'static,
79 Evm: Clone + Send + Sync + 'static,
80{
81 pub fn new() -> Self {
83 Self { context: None, components: (), _phantom: PhantomData }
84 }
85
86 pub fn with_context(mut self, context: KabuContext<R, P, DB, Evm>) -> Self {
88 self.context = Some(context);
89 self
90 }
91
92 #[allow(clippy::type_complexity)]
94 pub fn with_components<N, E, S, M, B, Est, H, Mer, Mon, Sig>(
95 self,
96 components: ComponentSet<N, E, S, M, B, Est, H, Mer, Mon, Sig>,
97 ) -> ConfiguredNodeBuilder<R, P, DB, Evm, N, E, S, M, B, Est, H, Mer, Mon, Sig> {
98 NodeBuilder { context: self.context, components, _phantom: PhantomData }
99 }
100}
101
102impl<R, P, DB, Evm, N, E, S, M, B, Est, H, Mer, Mon, Sig> NodeBuilder<R, P, DB, Evm, ComponentSet<N, E, S, M, B, Est, H, Mer, Mon, Sig>>
103where
104 R: Send + Sync + Clone + 'static,
105 P: Provider<Ethereum> + DebugProviderExt<Ethereum> + Send + Sync + Clone + 'static,
106 DB: DatabaseRef<Error = KabuDBError>
107 + Database<Error = KabuDBError>
108 + DatabaseCommit
109 + DatabaseKabuExt
110 + BlockHistoryState<EthPrimitives>
111 + Send
112 + Sync
113 + Clone
114 + Default
115 + 'static,
116 Evm: Clone + Send + Sync + 'static,
117 N: ComponentBuilder<KabuContext<R, P, DB, Evm>>,
118 E: ComponentBuilder<KabuContext<R, P, DB, Evm>>,
119 S: ComponentBuilder<KabuContext<R, P, DB, Evm>>,
120 M: ComponentBuilder<KabuContext<R, P, DB, Evm>>,
121 B: ComponentBuilder<KabuContext<R, P, DB, Evm>>,
122 Est: ComponentBuilder<KabuContext<R, P, DB, Evm>>,
123 H: ComponentBuilder<KabuContext<R, P, DB, Evm>>,
124 Mer: ComponentBuilder<KabuContext<R, P, DB, Evm>>,
125 Mon: ComponentBuilder<KabuContext<R, P, DB, Evm>>,
126 Sig: ComponentBuilder<KabuContext<R, P, DB, Evm>>,
127{
128 pub async fn launch(self, executor: TaskExecutor) -> Result<KabuHandle> {
130 let context = self.context.expect("Context must be set before launching");
131
132 let network = self.components.network.build(&context)?;
136 network.spawn(executor.clone())?;
137
138 let market = self.components.market.build(&context)?;
140 market.spawn(executor.clone())?;
141
142 let executor_component = self.components.executor.build(&context)?;
144 executor_component.spawn(executor.clone())?;
145
146 let strategy = self.components.strategy.build(&context)?;
148 strategy.spawn(executor.clone())?;
149
150 let estimator = self.components.estimator.build(&context)?;
152 estimator.spawn(executor.clone())?;
153
154 let signer = self.components.signer.build(&context)?;
156 signer.spawn(executor.clone())?;
157
158 let merger = self.components.merger.build(&context)?;
160 merger.spawn(executor.clone())?;
161
162 let broadcaster = self.components.broadcaster.build(&context)?;
164 broadcaster.spawn(executor.clone())?;
165
166 let health = self.components.health.build(&context)?;
168 health.spawn(executor.clone())?;
169
170 let monitoring = self.components.monitoring.build(&context)?;
172 monitoring.spawn(executor.clone())?;
173
174 Ok(KabuHandle { _phantom: PhantomData })
175 }
176}
177
178pub struct KabuHandle {
180 _phantom: PhantomData<()>,
181}
182
183impl KabuHandle {
184 pub async fn wait_for_shutdown(self) -> eyre::Result<()> {
186 tokio::signal::ctrl_c().await?;
188 Ok(())
189 }
190}