|
12 | 12 | // See the License for the specific language governing permissions and |
13 | 13 | // limitations under the License. |
14 | 14 |
|
15 | | -//! Relayer handlers for HTTP/Socket calls |
16 | | -
|
17 | | -#![allow(clippy::large_enum_variant)] |
18 | | -#![warn(missing_docs)] |
19 | | -use axum::extract::{Path, State, WebSocketUpgrade}; |
20 | | -use ethereum_types::{Address, U256}; |
21 | | -use std::error::Error; |
22 | | -use std::sync::Arc; |
23 | | - |
24 | | -use futures::prelude::*; |
25 | | - |
26 | | -use axum::extract::ws::{Message, WebSocket}; |
27 | | -use axum::http::StatusCode; |
28 | | -use axum::response::Response; |
29 | | -use axum::Json; |
30 | | -use axum_client_ip::InsecureClientIp; |
31 | | -use tokio::sync::mpsc; |
32 | | -use tokio_stream::wrappers::ReceiverStream; |
33 | | -use webb_proposals::TypedChainId; |
34 | | - |
35 | | -use webb_relayer_context::RelayerContext; |
36 | | -use webb_relayer_handler_utils::{ |
37 | | - Command, CommandResponse, CommandStream, IpInformationResponse, |
38 | | - SubstrateCommandType, |
39 | | -}; |
40 | | -use webb_relayer_tx_relay::evm::fees::{get_evm_fee_info, EvmFeeInfo}; |
41 | | - |
42 | | -use webb_relayer_tx_relay::substrate::fees::{ |
43 | | - get_substrate_fee_info, SubstrateFeeInfo, |
44 | | -}; |
45 | | -use webb_relayer_tx_relay::substrate::vanchor::handle_substrate_vanchor_relay_tx; |
46 | | -use webb_relayer_utils::HandlerError; |
| 15 | +//! Relayer handlers for HTTP calls. |
47 | 16 |
|
48 | 17 | /// Module handles relayer API |
49 | 18 | pub mod routes; |
50 | | - |
51 | | -/// Wait for websocket connection upgrade |
52 | | -pub async fn websocket_handler( |
53 | | - ws: WebSocketUpgrade, |
54 | | - State(ctx): State<Arc<RelayerContext>>, |
55 | | -) -> Response { |
56 | | - ws.on_upgrade(move |socket| accept_websocket_connection(socket, ctx)) |
57 | | -} |
58 | | - |
59 | | -/// Sets up a websocket connection. |
60 | | -/// |
61 | | -/// # Arguments |
62 | | -/// |
63 | | -/// * `ctx` - RelayContext reference that holds the configuration |
64 | | -/// * `stream` - Websocket stream |
65 | | -async fn accept_websocket_connection(ws: WebSocket, ctx: Arc<RelayerContext>) { |
66 | | - let (mut tx, mut rx) = ws.split(); |
67 | | - |
68 | | - // Wait for client to send over text (such as relay transaction requests) |
69 | | - while let Some(msg) = rx.next().await { |
70 | | - match msg { |
71 | | - Ok(msg) => { |
72 | | - if let Ok(text) = msg.to_text() { |
73 | | - // Use inspect_err() here once stabilized |
74 | | - let _ = |
75 | | - handle_text(&ctx, text, &mut tx).await.map_err(|e| { |
76 | | - tracing::warn!("Websocket handler error: {e}") |
77 | | - }); |
78 | | - } |
79 | | - } |
80 | | - Err(e) => { |
81 | | - tracing::warn!("Websocket error: {e}"); |
82 | | - return; |
83 | | - } |
84 | | - } |
85 | | - } |
86 | | -} |
87 | | - |
88 | | -/// Sets up a websocket channels for message sending. |
89 | | -/// |
90 | | -/// This is primarily used for transaction relaying. The intention is |
91 | | -/// that a user will send formatted relay requests to the relayer using |
92 | | -/// the websocket. The command will be extracted and sent to `handle_cmd` |
93 | | -/// if successfully deserialized. |
94 | | -/// |
95 | | -/// Returns `Ok(())` on success |
96 | | -/// |
97 | | -/// # Arguments |
98 | | -/// |
99 | | -/// * `ctx` - RelayContext reference that holds the configuration |
100 | | -/// * `v` - The text (usually in a JSON form) message to be handled. |
101 | | -/// * `tx` - A mutable Trait implementation of the `warp::ws::Sender` trait |
102 | | -pub async fn handle_text<TX>( |
103 | | - ctx: &RelayerContext, |
104 | | - v: &str, |
105 | | - tx: &mut TX, |
106 | | -) -> webb_relayer_utils::Result<()> |
107 | | -where |
108 | | - TX: Sink<Message> + Unpin, |
109 | | - TX::Error: Error + Send + Sync + 'static, |
110 | | -{ |
111 | | - // for every connection, we create a new channel, where we will use to send messages |
112 | | - // over it. |
113 | | - let (my_tx, my_rx) = mpsc::channel(50); |
114 | | - let res_stream = ReceiverStream::new(my_rx); |
115 | | - match serde_json::from_str(v) { |
116 | | - Ok(cmd) => { |
117 | | - if let Err(e) = handle_cmd(ctx.clone(), cmd, my_tx.clone()).await { |
118 | | - tracing::error!("{:?}", e); |
119 | | - let _ = my_tx.send(e).await; |
120 | | - } |
121 | | - // Send back the response, usually a transaction hash |
122 | | - // from processing the transaction relaying command. |
123 | | - res_stream |
124 | | - .fuse() |
125 | | - .map(|v| serde_json::to_string(&v).expect("bad value")) |
126 | | - .inspect(|v| tracing::trace!("Sending: {}", v)) |
127 | | - .map(Message::Text) |
128 | | - .map(Result::Ok) |
129 | | - .forward(tx) |
130 | | - .map_err(|_| webb_relayer_utils::Error::FailedToSendResponse) |
131 | | - .await?; |
132 | | - } |
133 | | - Err(e) => { |
134 | | - tracing::warn!("Got invalid payload: {:?}", e); |
135 | | - tracing::debug!("Invalid payload: {:?}", v); |
136 | | - let error = CommandResponse::Error(e.to_string()); |
137 | | - let value = serde_json::to_string(&error)?; |
138 | | - tx.send(Message::Text(value)) |
139 | | - .map_err(|_| webb_relayer_utils::Error::FailedToSendResponse) |
140 | | - .await?; |
141 | | - } |
142 | | - }; |
143 | | - Ok(()) |
144 | | -} |
145 | | - |
146 | | -/// Handles the socket address response |
147 | | -/// |
148 | | -/// Returns a Result with the `IpInformationResponse` on success |
149 | | -/// |
150 | | -/// # Arguments |
151 | | -/// |
152 | | -/// * `ip` - Extractor for client IP, taking into account x-forwarded-for and similar headers |
153 | | -pub async fn handle_socket_info( |
154 | | - InsecureClientIp(ip): InsecureClientIp, |
155 | | -) -> Json<IpInformationResponse> { |
156 | | - Json(IpInformationResponse { ip: ip.to_string() }) |
157 | | -} |
158 | | - |
159 | | -/// Handles the command prompts for EVM and Substrate chains |
160 | | -/// |
161 | | -/// # Arguments |
162 | | -/// |
163 | | -/// * `ctx` - RelayContext reference that holds the configuration |
164 | | -/// * `cmd` - The command to execute |
165 | | -/// * `stream` - The stream to write the response to |
166 | | -pub async fn handle_cmd( |
167 | | - ctx: RelayerContext, |
168 | | - cmd: Command, |
169 | | - stream: CommandStream, |
170 | | -) -> Result<(), CommandResponse> { |
171 | | - if !ctx.config.features.private_tx_relay { |
172 | | - return Err(CommandResponse::Error( |
173 | | - "Private transaction relaying is not enabled.".to_string(), |
174 | | - )); |
175 | | - } |
176 | | - |
177 | | - match cmd { |
178 | | - Command::Substrate(substrate) => match substrate { |
179 | | - SubstrateCommandType::VAnchor(vanchor) => { |
180 | | - handle_substrate_vanchor_relay_tx(ctx, vanchor, stream).await |
181 | | - } |
182 | | - }, |
183 | | - Command::Ping() => { |
184 | | - let _ = stream.send(CommandResponse::Pong()).await; |
185 | | - Ok(()) |
186 | | - } |
187 | | - _ => { |
188 | | - unimplemented!() |
189 | | - } |
190 | | - } |
191 | | -} |
192 | | - |
193 | | -/// Handler for fee estimation |
194 | | -/// |
195 | | -/// # Arguments |
196 | | -/// |
197 | | -/// * `chain_id` - ID of the blockchain |
198 | | -/// * `vanchor` - Address of the smart contract |
199 | | -/// * `gas_amount` - How much gas the transaction needs. Don't use U256 here because it |
200 | | -/// gets parsed incorrectly. |
201 | | -pub async fn handle_evm_fee_info( |
202 | | - State(ctx): State<Arc<RelayerContext>>, |
203 | | - Path((chain_id, vanchor, gas_amount)): Path<(u32, Address, u64)>, |
204 | | -) -> Result<Json<EvmFeeInfo>, HandlerError> { |
205 | | - let chain_id = TypedChainId::Evm(chain_id); |
206 | | - let gas_amount = U256::from(gas_amount); |
207 | | - Ok( |
208 | | - get_evm_fee_info(chain_id, vanchor, gas_amount, ctx.as_ref()) |
209 | | - .await |
210 | | - .map(Json)?, |
211 | | - ) |
212 | | -} |
213 | | - |
214 | | -/// Handler for fee estimation |
215 | | -/// |
216 | | -/// # Arguments |
217 | | -/// * `chain_id` - ID of the blockchain |
218 | | -/// * `estimated_tx_fees` - Estimated transaction fees |
219 | | -/// * `ctx` - RelayContext reference that holds the configuration |
220 | | -pub async fn handle_substrate_fee_info( |
221 | | - State(ctx): State<Arc<RelayerContext>>, |
222 | | - Path((chain_id, estimated_tx_fees)): Path<(u64, u128)>, |
223 | | -) -> Result<Json<SubstrateFeeInfo>, HandlerError> { |
224 | | - get_substrate_fee_info(chain_id, estimated_tx_fees.into(), ctx.as_ref()) |
225 | | - .await |
226 | | - .map(Json) |
227 | | - .map_err(|e| { |
228 | | - HandlerError(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()) |
229 | | - }) |
230 | | -} |
0 commit comments