Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/CRISP/client/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ VITE_WALLETCONNECT_PROJECT_ID=
# A token with a public mint function. Also used as the fee token for Enclave.
# This is its default address in Hardhat node
VITE_CRISP_TOKEN=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0
# Addresses of requesters for which to show rounds in the UI. Comma separated Ethereum addresses.
VITE_E3_REQUESTERS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266,0x70997970C51812dc3A010C7d01b50e0d17dc79C8
6 changes: 4 additions & 2 deletions examples/CRISP/client/src/hooks/enclave/useEnclaveServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from '@/model/vote.model'
import { useApi } from '../generic/useFetchApi'
import { PollRequestResult } from '@/model/poll.model'
import { ROUND_REQUESTERS } from '@/utils/constants'

const ENCLAVE_API = import.meta.env.VITE_ENCLAVE_API

Expand All @@ -35,10 +36,11 @@ const EnclaveEndpoints = {
export const useEnclaveServer = () => {
const { GetCurrentRound, GetWebAllResult, BroadcastVote, GetRoundStateLite, GetWebResult, GetVoteStatus } = EnclaveEndpoints
const { fetchData, isLoading } = useApi()
const getCurrentRound = () => fetchData<CurrentRound>(GetCurrentRound)
const getCurrentRound = () => fetchData<CurrentRound, { requesters: string[] }>(GetCurrentRound, 'post', { requesters: ROUND_REQUESTERS })
const getRoundStateLite = (round_id: number) => fetchData<VoteStateLite, { round_id: number }>(GetRoundStateLite, 'post', { round_id })
const broadcastVote = (vote: BroadcastVoteRequest) => fetchData<BroadcastVoteResponse, BroadcastVoteRequest>(BroadcastVote, 'post', vote)
const getWebResult = () => fetchData<PollRequestResult[], void>(GetWebAllResult, 'get')
const getWebResult = () =>
fetchData<PollRequestResult[], { requesters: string[] }>(GetWebAllResult, 'post', { requesters: ROUND_REQUESTERS })
const getWebResultByRound = (round_id: number) => fetchData<PollRequestResult, { round_id: number }>(GetWebResult, 'post', { round_id })
const getVoteStatus = (request: VoteStatusRequest) => fetchData<VoteStatusResponse, VoteStatusRequest>(GetVoteStatus, 'post', request)
const getEligibleVoters = (round_id: number) =>
Expand Down
3 changes: 3 additions & 0 deletions examples/CRISP/client/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@
// or FITNESS FOR A PARTICULAR PURPOSE.

export const ROUND_TOKEN = import.meta.env.VITE_CRISP_TOKEN
export const ROUND_REQUESTERS = import.meta.env.VITE_E3_REQUESTERS
? import.meta.env.VITE_E3_REQUESTERS.split(',').map((s: string) => s.trim())
: []
2 changes: 1 addition & 1 deletion examples/CRISP/scripts/dev_client.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ set -euo pipefail

echo "CLIENT SCRIPT RUNNING..."

(cd ./client && pnpm dev-static)
(cd ./client && if [[ ! -f .env ]]; then cp .env.example .env; fi && pnpm dev-static)
7 changes: 7 additions & 0 deletions examples/CRISP/server/src/server/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ pub struct GetRoundRequest {
pub round_id: u64,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct RoundRequestWithRequester {
pub requesters: Vec<String>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct PreviousCiphertextRequest {
pub round_id: u64,
Expand Down Expand Up @@ -156,6 +161,7 @@ pub struct WebResultRequest {
pub option_2_emoji: String,
pub total_votes: u64,
pub end_time: u64,
pub requester: String,
}

#[derive(Debug, Deserialize, Serialize)]
Expand Down Expand Up @@ -245,6 +251,7 @@ impl From<E3> for WebResultRequest {
option_2_emoji: e3.emojis[1].clone(),
total_votes: e3.vote_count,
end_time: e3.expiration,
requester: e3.requester,
}
}
}
Expand Down
33 changes: 33 additions & 0 deletions examples/CRISP/server/src/server/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,41 @@ impl<S: DataStore> CurrentRoundRepository<S> {
.get::<CurrentRound>(&key)
.await
.map_err(|_| eyre::eyre!("Could get e3 at '{key}'"))?;

Ok(round)
}

/// Get the current (most recent) round for a specific requester
///
/// # Arguments
/// * `requester` - The requester address to find the current round for
///
/// # Returns
/// * The CurrentRound object for the most recent round by this requester, or None if not found
pub async fn get_current_round_for_requester(&self, requester: String) -> Result<Option<CurrentRound>> {
// Get the current round count to iterate through all rounds
let round_count = self.get_current_round_id().await?;

// Iterate backwards from the most recent round to find the latest one for this requester
for round_id in (0..=round_count).rev() {
let crisp_repo = CrispE3Repository::new(self.store.clone(), round_id);

match crisp_repo.get_e3_state_lite().await {
Ok(state) => {
if state.requester == requester {
return Ok(Some(CurrentRound { id: round_id }));
}
}
Err(e) => {
info!("Error retrieving state for round {}: {:?}", round_id, e);
continue;
}
}
}

Ok(None)
}

pub async fn get_current_round_id(&self) -> Result<u64> {
let round = self
.get_current_round()
Expand Down Expand Up @@ -219,6 +251,7 @@ impl<S: DataStore> CrispE3Repository<S> {
option_2_emoji: e3_crisp.emojis[1].clone(),
end_time: e3.expiration,
total_votes: self.get_vote_count().await?,
requester: e3_crisp.requester,
})
}

Expand Down
23 changes: 19 additions & 4 deletions examples/CRISP/server/src/server/routes/rounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use crate::config::CONFIG;
use crate::server::app_data::AppData;
use crate::server::models::{
CTRequest, ComputeProviderParams, JsonResponse, PKRequest, RoundRequest,
CTRequest, ComputeProviderParams, JsonResponse, PKRequest, RoundRequest, RoundRequestWithRequester
};

use actix_web::{web, HttpResponse, Responder};
Expand All @@ -22,7 +22,7 @@ use log::{error, info};
pub fn setup_routes(config: &mut web::ServiceConfig) {
config.service(
web::scope("/rounds")
.route("/current", web::get().to(get_current_round))
.route("/current", web::post().to(get_current_round))
.route("/public-key", web::post().to(get_public_key))
.route("/ciphertext", web::post().to(get_ciphertext))
.route("/request", web::post().to(request_new_round)),
Expand Down Expand Up @@ -74,8 +74,23 @@ async fn request_new_round(data: web::Json<RoundRequest>) -> impl Responder {
/// # Returns
///
/// * A JSON response containing the current round
async fn get_current_round(store: web::Data<AppData>) -> impl Responder {
match store.current_round().get_current_round().await {
async fn get_current_round(
data: web::Json<RoundRequestWithRequester>,
store: web::Data<AppData>,
) -> impl Responder {
let incoming = data.into_inner();

// Get the first requester if any exist
// .get(0) returns Option<&String>, so we need to handle that
let result = if let Some(requester) = incoming.requesters.get(0) {
// We have a requester, filter by it
store.current_round().get_current_round_for_requester(requester.clone()).await
} else {
// No requester provided (empty array)
store.current_round().get_current_round().await
};
Comment thread
ctrlc03 marked this conversation as resolved.

match result {
Ok(Some(current_round)) => HttpResponse::Ok().json(current_round),
Ok(None) => HttpResponse::NotFound().json(JsonResponse {
response: "No current round found".to_string(),
Expand Down
29 changes: 19 additions & 10 deletions examples/CRISP/server/src/server/routes/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,12 @@
use std::str::FromStr;

use crate::server::{
app_data::AppData,
models::{
GetRoundRequest, IsSlotEmptyRequest, IsSlotEmptyResponse, PreviousCiphertextRequest,
PreviousCiphertextResponse, WebhookPayload,
},
CONFIG,
CONFIG, app_data::AppData, models::{
GetRoundRequest, IsSlotEmptyRequest, IsSlotEmptyResponse, PreviousCiphertextRequest, PreviousCiphertextResponse, RoundRequestWithRequester, WebhookPayload
}
};
use actix_web::{web, HttpResponse, Responder};
use alloy::primitives::{Address, Bytes, U256};
use alloy::{primitives::{Address, Bytes, U256}};
use e3_sdk::evm_helpers::contracts::{
EnclaveContract, EnclaveContractFactory, EnclaveWrite, ReadWrite,
};
Expand All @@ -26,7 +23,7 @@ pub fn setup_routes(config: &mut web::ServiceConfig) {
config.service(
web::scope("/state")
.route("/result", web::post().to(get_round_result))
.route("/all", web::get().to(get_all_round_results))
.route("/all", web::post().to(get_all_round_results))
.route("/lite", web::post().to(get_round_state_lite))
// Do we need protection on this endpoint? technically they would need to send a valid proof for it to
// be included on chain
Expand Down Expand Up @@ -222,7 +219,9 @@ async fn get_round_result(
/// # Returns
///
/// * A JSON response containing the results for all rounds
async fn get_all_round_results(store: web::Data<AppData>) -> impl Responder {
async fn get_all_round_results(data: web::Json::<RoundRequestWithRequester>, store: web::Data<AppData>) -> impl Responder {
let incoming = data.into_inner();

let round_count = match store.current_round().get_current_round_id().await {
Ok(count) => count,
Err(e) => {
Expand All @@ -232,11 +231,21 @@ async fn get_all_round_results(store: web::Data<AppData>) -> impl Responder {
};

let mut states = Vec::new();
let requesters = incoming.requesters;

// FIXME: This assumes ids are ordered
for i in 0..round_count + 1 {
match store.e3(i).get_web_result_request().await {
Ok(w) => states.push(w),
Ok(w) => {
if !requesters.is_empty() {
// if we have any requesters to filter by, do it
if requesters.contains(&w.requester) {
states.push(w);
}
} else {
states.push(w);
}
}
Err(e) => {
info!("Error retrieving state for round {}: {:?}", i, e);
continue;
Expand Down
Loading