Skip to content

Commit fdd4c9e

Browse files
authored
chore: add endpoints to filter round data by requester (#1152)
1 parent 2c68e60 commit fdd4c9e

8 files changed

Lines changed: 88 additions & 17 deletions

File tree

examples/CRISP/client/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ VITE_WALLETCONNECT_PROJECT_ID=
33
# A token with a public mint function. Also used as the fee token for Enclave.
44
# This is its default address in Hardhat node
55
VITE_CRISP_TOKEN=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0
6+
# Addresses of requesters for which to show rounds in the UI. Comma separated Ethereum addresses.
7+
VITE_E3_REQUESTERS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266,0x70997970C51812dc3A010C7d01b50e0d17dc79C8

examples/CRISP/client/src/hooks/enclave/useEnclaveServer.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
} from '@/model/vote.model'
1717
import { useApi } from '../generic/useFetchApi'
1818
import { PollRequestResult } from '@/model/poll.model'
19+
import { ROUND_REQUESTERS } from '@/utils/constants'
1920

2021
const ENCLAVE_API = import.meta.env.VITE_ENCLAVE_API
2122

@@ -35,10 +36,11 @@ const EnclaveEndpoints = {
3536
export const useEnclaveServer = () => {
3637
const { GetCurrentRound, GetWebAllResult, BroadcastVote, GetRoundStateLite, GetWebResult, GetVoteStatus } = EnclaveEndpoints
3738
const { fetchData, isLoading } = useApi()
38-
const getCurrentRound = () => fetchData<CurrentRound>(GetCurrentRound)
39+
const getCurrentRound = () => fetchData<CurrentRound, { requesters: string[] }>(GetCurrentRound, 'post', { requesters: ROUND_REQUESTERS })
3940
const getRoundStateLite = (round_id: number) => fetchData<VoteStateLite, { round_id: number }>(GetRoundStateLite, 'post', { round_id })
4041
const broadcastVote = (vote: BroadcastVoteRequest) => fetchData<BroadcastVoteResponse, BroadcastVoteRequest>(BroadcastVote, 'post', vote)
41-
const getWebResult = () => fetchData<PollRequestResult[], void>(GetWebAllResult, 'get')
42+
const getWebResult = () =>
43+
fetchData<PollRequestResult[], { requesters: string[] }>(GetWebAllResult, 'post', { requesters: ROUND_REQUESTERS })
4244
const getWebResultByRound = (round_id: number) => fetchData<PollRequestResult, { round_id: number }>(GetWebResult, 'post', { round_id })
4345
const getVoteStatus = (request: VoteStatusRequest) => fetchData<VoteStatusResponse, VoteStatusRequest>(GetVoteStatus, 'post', request)
4446
const getEligibleVoters = (round_id: number) =>

examples/CRISP/client/src/utils/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@
55
// or FITNESS FOR A PARTICULAR PURPOSE.
66

77
export const ROUND_TOKEN = import.meta.env.VITE_CRISP_TOKEN
8+
export const ROUND_REQUESTERS = import.meta.env.VITE_E3_REQUESTERS
9+
? import.meta.env.VITE_E3_REQUESTERS.split(',').map((s: string) => s.trim())
10+
: []

examples/CRISP/scripts/dev_client.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ set -euo pipefail
44

55
echo "CLIENT SCRIPT RUNNING..."
66

7-
(cd ./client && pnpm dev-static)
7+
(cd ./client && if [[ ! -f .env ]]; then cp .env.example .env; fi && pnpm dev-static)

examples/CRISP/server/src/server/models.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ pub struct GetRoundRequest {
105105
pub round_id: u64,
106106
}
107107

108+
#[derive(Debug, Deserialize, Serialize)]
109+
pub struct RoundRequestWithRequester {
110+
pub requesters: Vec<String>,
111+
}
112+
108113
#[derive(Debug, Deserialize, Serialize)]
109114
pub struct PreviousCiphertextRequest {
110115
pub round_id: u64,
@@ -156,6 +161,7 @@ pub struct WebResultRequest {
156161
pub option_2_emoji: String,
157162
pub total_votes: u64,
158163
pub end_time: u64,
164+
pub requester: String,
159165
}
160166

161167
#[derive(Debug, Deserialize, Serialize)]
@@ -245,6 +251,7 @@ impl From<E3> for WebResultRequest {
245251
option_2_emoji: e3.emojis[1].clone(),
246252
total_votes: e3.vote_count,
247253
end_time: e3.expiration,
254+
requester: e3.requester,
248255
}
249256
}
250257
}

examples/CRISP/server/src/server/repo.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,41 @@ impl<S: DataStore> CurrentRoundRepository<S> {
4040
.get::<CurrentRound>(&key)
4141
.await
4242
.map_err(|_| eyre::eyre!("Could get e3 at '{key}'"))?;
43+
4344
Ok(round)
4445
}
4546

47+
/// Get the current (most recent) round for a specific requester
48+
///
49+
/// # Arguments
50+
/// * `requester` - The requester address to find the current round for
51+
///
52+
/// # Returns
53+
/// * The CurrentRound object for the most recent round by this requester, or None if not found
54+
pub async fn get_current_round_for_requester(&self, requester: String) -> Result<Option<CurrentRound>> {
55+
// Get the current round count to iterate through all rounds
56+
let round_count = self.get_current_round_id().await?;
57+
58+
// Iterate backwards from the most recent round to find the latest one for this requester
59+
for round_id in (0..=round_count).rev() {
60+
let crisp_repo = CrispE3Repository::new(self.store.clone(), round_id);
61+
62+
match crisp_repo.get_e3_state_lite().await {
63+
Ok(state) => {
64+
if state.requester == requester {
65+
return Ok(Some(CurrentRound { id: round_id }));
66+
}
67+
}
68+
Err(e) => {
69+
info!("Error retrieving state for round {}: {:?}", round_id, e);
70+
continue;
71+
}
72+
}
73+
}
74+
75+
Ok(None)
76+
}
77+
4678
pub async fn get_current_round_id(&self) -> Result<u64> {
4779
let round = self
4880
.get_current_round()
@@ -219,6 +251,7 @@ impl<S: DataStore> CrispE3Repository<S> {
219251
option_2_emoji: e3_crisp.emojis[1].clone(),
220252
end_time: e3.expiration,
221253
total_votes: self.get_vote_count().await?,
254+
requester: e3_crisp.requester,
222255
})
223256
}
224257

examples/CRISP/server/src/server/routes/rounds.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use crate::config::CONFIG;
88
use crate::server::app_data::AppData;
99
use crate::server::models::{
10-
CTRequest, ComputeProviderParams, JsonResponse, PKRequest, RoundRequest,
10+
CTRequest, ComputeProviderParams, JsonResponse, PKRequest, RoundRequest, RoundRequestWithRequester
1111
};
1212

1313
use actix_web::{web, HttpResponse, Responder};
@@ -22,7 +22,7 @@ use log::{error, info};
2222
pub fn setup_routes(config: &mut web::ServiceConfig) {
2323
config.service(
2424
web::scope("/rounds")
25-
.route("/current", web::get().to(get_current_round))
25+
.route("/current", web::post().to(get_current_round))
2626
.route("/public-key", web::post().to(get_public_key))
2727
.route("/ciphertext", web::post().to(get_ciphertext))
2828
.route("/request", web::post().to(request_new_round)),
@@ -74,8 +74,23 @@ async fn request_new_round(data: web::Json<RoundRequest>) -> impl Responder {
7474
/// # Returns
7575
///
7676
/// * A JSON response containing the current round
77-
async fn get_current_round(store: web::Data<AppData>) -> impl Responder {
78-
match store.current_round().get_current_round().await {
77+
async fn get_current_round(
78+
data: web::Json<RoundRequestWithRequester>,
79+
store: web::Data<AppData>,
80+
) -> impl Responder {
81+
let incoming = data.into_inner();
82+
83+
// Get the first requester if any exist
84+
// .get(0) returns Option<&String>, so we need to handle that
85+
let result = if let Some(requester) = incoming.requesters.get(0) {
86+
// We have a requester, filter by it
87+
store.current_round().get_current_round_for_requester(requester.clone()).await
88+
} else {
89+
// No requester provided (empty array)
90+
store.current_round().get_current_round().await
91+
};
92+
93+
match result {
7994
Ok(Some(current_round)) => HttpResponse::Ok().json(current_round),
8095
Ok(None) => HttpResponse::NotFound().json(JsonResponse {
8196
response: "No current round found".to_string(),

examples/CRISP/server/src/server/routes/state.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,12 @@
77
use std::str::FromStr;
88

99
use crate::server::{
10-
app_data::AppData,
11-
models::{
12-
GetRoundRequest, IsSlotEmptyRequest, IsSlotEmptyResponse, PreviousCiphertextRequest,
13-
PreviousCiphertextResponse, WebhookPayload,
14-
},
15-
CONFIG,
10+
CONFIG, app_data::AppData, models::{
11+
GetRoundRequest, IsSlotEmptyRequest, IsSlotEmptyResponse, PreviousCiphertextRequest, PreviousCiphertextResponse, RoundRequestWithRequester, WebhookPayload
12+
}
1613
};
1714
use actix_web::{web, HttpResponse, Responder};
18-
use alloy::primitives::{Address, Bytes, U256};
15+
use alloy::{primitives::{Address, Bytes, U256}};
1916
use e3_sdk::evm_helpers::contracts::{
2017
EnclaveContract, EnclaveContractFactory, EnclaveWrite, ReadWrite,
2118
};
@@ -26,7 +23,7 @@ pub fn setup_routes(config: &mut web::ServiceConfig) {
2623
config.service(
2724
web::scope("/state")
2825
.route("/result", web::post().to(get_round_result))
29-
.route("/all", web::get().to(get_all_round_results))
26+
.route("/all", web::post().to(get_all_round_results))
3027
.route("/lite", web::post().to(get_round_state_lite))
3128
// Do we need protection on this endpoint? technically they would need to send a valid proof for it to
3229
// be included on chain
@@ -222,7 +219,9 @@ async fn get_round_result(
222219
/// # Returns
223220
///
224221
/// * A JSON response containing the results for all rounds
225-
async fn get_all_round_results(store: web::Data<AppData>) -> impl Responder {
222+
async fn get_all_round_results(data: web::Json::<RoundRequestWithRequester>, store: web::Data<AppData>) -> impl Responder {
223+
let incoming = data.into_inner();
224+
226225
let round_count = match store.current_round().get_current_round_id().await {
227226
Ok(count) => count,
228227
Err(e) => {
@@ -232,11 +231,21 @@ async fn get_all_round_results(store: web::Data<AppData>) -> impl Responder {
232231
};
233232

234233
let mut states = Vec::new();
234+
let requesters = incoming.requesters;
235235

236236
// FIXME: This assumes ids are ordered
237237
for i in 0..round_count + 1 {
238238
match store.e3(i).get_web_result_request().await {
239-
Ok(w) => states.push(w),
239+
Ok(w) => {
240+
if !requesters.is_empty() {
241+
// if we have any requesters to filter by, do it
242+
if requesters.contains(&w.requester) {
243+
states.push(w);
244+
}
245+
} else {
246+
states.push(w);
247+
}
248+
}
240249
Err(e) => {
241250
info!("Error retrieving state for round {}: {:?}", i, e);
242251
continue;

0 commit comments

Comments
 (0)