Skip to content

Commit 31428b6

Browse files
committed
fix-api
1 parent e3f51d3 commit 31428b6

File tree

5 files changed

+51
-22
lines changed

5 files changed

+51
-22
lines changed

apps/fortuna/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ Each blockchain is configured in `config.yaml`.
1010

1111
## Build & Test
1212

13+
We use sqlx query macros to check the SQL queries at compile time. This requires
14+
a database to be available at build time. You can create an sqlite db and apply the schema migrations on it
15+
via the following command:
16+
17+
```bash
18+
DATABASE_URL="sqlite:fortuna.db?mode=rwc" cargo sqlx migrate run
19+
```
20+
1321
Fortuna uses Cargo for building and dependency management.
1422
Simply run `cargo build` and `cargo test` to build and test the project.
1523

apps/fortuna/src/api.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ pub enum RestError {
111111
InvalidSequenceNumber,
112112
/// The caller passed an unsupported chain id
113113
InvalidChainId,
114+
/// The query is not parsable to a transaction hash, address, or sequence number
115+
InvalidQueryString,
114116
/// The caller requested a random value that can't currently be revealed (because it
115117
/// hasn't been committed to on-chain)
116118
NoPendingRequest,
@@ -120,7 +122,6 @@ pub enum RestError {
120122
/// The server cannot currently communicate with the blockchain, so is not able to verify
121123
/// which random values have been requested.
122124
TemporarilyUnavailable,
123-
BadFilterParameters(String),
124125
/// The server is not able to process the request because the blockchain initialization
125126
/// has not been completed yet.
126127
Uninitialized,
@@ -139,6 +140,11 @@ impl IntoResponse for RestError {
139140
RestError::InvalidChainId => {
140141
(StatusCode::BAD_REQUEST, "The chain id is not supported").into_response()
141142
}
143+
RestError::InvalidQueryString => (
144+
StatusCode::BAD_REQUEST,
145+
"The query string is not parsable to a transaction hash, address, or sequence number",
146+
)
147+
.into_response(),
142148
RestError::NoPendingRequest => (
143149
StatusCode::FORBIDDEN,
144150
"The request with the given sequence number has not been made yet, or the random value has already been revealed on chain.",
@@ -163,11 +169,6 @@ impl IntoResponse for RestError {
163169
"An unknown error occurred processing the request",
164170
)
165171
.into_response(),
166-
RestError::BadFilterParameters(message) => (
167-
StatusCode::BAD_REQUEST,
168-
format!("Invalid filter parameters: {}", message),
169-
)
170-
.into_response(),
171172
}
172173
}
173174
}
@@ -179,7 +180,7 @@ pub fn routes(state: ApiState) -> Router<(), Body> {
179180
.route("/metrics", get(metrics))
180181
.route("/ready", get(ready))
181182
.route("/v1/chains", get(chain_ids))
182-
.route("/v1/explorer", get(explorer))
183+
.route("/v1/logs", get(explorer))
183184
.route(
184185
"/v1/chains/:chain_id/revelations/:sequence",
185186
get(revelation),

apps/fortuna/src/api/explorer.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,46 @@ use crate::api::{ChainId, RestError};
22
use crate::history::RequestStatus;
33
use axum::extract::{Query, State};
44
use axum::Json;
5+
use chrono::{DateTime, Utc};
56
use ethers::types::{Address, TxHash};
67
use std::str::FromStr;
7-
use utoipa::{IntoParams, ToSchema};
8+
use utoipa::IntoParams;
89

910
#[derive(Debug, serde::Serialize, serde::Deserialize, IntoParams)]
1011
#[into_params(parameter_in=Query)]
1112
pub struct ExplorerQueryParams {
12-
pub min_timestamp: Option<u64>,
13-
pub max_timestamp: Option<u64>,
13+
/// Only return logs that are newer or equal to this timestamp.
14+
#[param(value_type = Option<String>, example = "2023-10-01T00:00:00Z")]
15+
pub min_timestamp: Option<DateTime<Utc>>,
16+
/// Only return logs that are older or equal to this timestamp.
17+
#[param(value_type = Option<String>, example = "2023-10-01T00:00:00Z")]
18+
pub max_timestamp: Option<DateTime<Utc>>,
19+
/// The query string to search for. This can be a transaction hash, sender address, or sequence number.
1420
pub query: Option<String>,
1521
#[param(value_type = Option<String>)]
22+
/// The chain ID to filter the results by.
1623
pub chain_id: Option<ChainId>,
1724
}
1825

26+
const LOG_RETURN_LIMIT: u64 = 1000;
27+
1928
#[utoipa::path(
2029
get,
21-
path = "/v1/explorer",
30+
path = "/v1/logs",
2231
responses(
23-
(status = 200, description = "Random value successfully retrieved", body = Vec<RequestJournal>)
32+
(status = 200, description = "Entropy request logs", body = Vec<RequestStatus>)
2433
),
2534
params(ExplorerQueryParams)
2635
)]
2736
pub async fn explorer(
2837
State(state): State<crate::api::ApiState>,
2938
Query(query_params): Query<ExplorerQueryParams>,
3039
) -> anyhow::Result<Json<Vec<RequestStatus>>, RestError> {
40+
if let Some(chain_id) = &query_params.chain_id {
41+
if !state.chains.read().await.contains_key(chain_id) {
42+
return Err(RestError::InvalidChainId);
43+
}
44+
}
3145
if let Some(query) = query_params.query {
3246
if let Ok(tx_hash) = TxHash::from_str(&query) {
3347
return Ok(Json(state.history.get_requests_by_tx_hash(tx_hash).await));
@@ -48,7 +62,17 @@ pub async fn explorer(
4862
.await,
4963
));
5064
}
65+
return Err(RestError::InvalidQueryString);
5166
}
52-
//TODO: handle more types of queries
53-
Ok(Json(vec![]))
67+
Ok(Json(
68+
state
69+
.history
70+
.get_requests_by_time(
71+
query_params.chain_id,
72+
LOG_RETURN_LIMIT,
73+
query_params.min_timestamp,
74+
query_params.max_timestamp,
75+
)
76+
.await,
77+
))
5478
}

apps/fortuna/src/eth_utils/utils.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::history::History;
21
use ethabi::ethereum_types::U64;
32
use {
43
crate::eth_utils::nonce_manager::NonceManaged,
@@ -183,7 +182,6 @@ pub async fn submit_tx_with_backoff<T: Middleware + NonceManaged + 'static>(
183182
padded_gas_limit,
184183
gas_multiplier_pct,
185184
fee_multiplier_pct,
186-
history.clone(),
187185
)
188186
.await
189187
},
@@ -223,7 +221,6 @@ pub async fn submit_tx<T: Middleware + NonceManaged + 'static>(
223221
// A value of 100 submits the tx with the same gas/fee as the estimate.
224222
gas_estimate_multiplier_pct: u64,
225223
fee_estimate_multiplier_pct: u64,
226-
history: Arc<History>,
227224
) -> Result<TransactionReceipt, backoff::Error<anyhow::Error>> {
228225
let gas_estimate_res = call.estimate_gas().await;
229226

apps/fortuna/src/history.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ impl History {
207207
let tx_hash: String = tx_hash.encode_hex();
208208
let rows = sqlx::query_as!(
209209
RequestRow,
210-
"SELECT * FROM request WHERE request_tx_hash = ? || reveal_tx_hash = ?",
210+
"SELECT * FROM request WHERE request_tx_hash = ? OR reveal_tx_hash = ?",
211211
tx_hash,
212212
tx_hash
213213
)
@@ -269,9 +269,9 @@ impl History {
269269
rows.into_iter().map(|row| row.into()).collect()
270270
}
271271

272-
pub async fn get_latest_requests(
272+
pub async fn get_requests_by_time(
273273
&self,
274-
chain_id: Option<&ChainId>,
274+
chain_id: Option<ChainId>,
275275
limit: u64,
276276
min_timestamp: Option<DateTime<chrono::Utc>>,
277277
max_timestamp: Option<DateTime<chrono::Utc>>,
@@ -302,8 +302,7 @@ impl History {
302302
}
303303

304304
mod tests {
305-
use crate::history::{History, RequestEntryState, RequestStatus};
306-
use ethers::types::{Address, TxHash};
305+
use super::*;
307306
use tokio::time::sleep;
308307

309308
#[tokio::test]

0 commit comments

Comments
 (0)