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: 0 additions & 2 deletions ad-server/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,5 +145,3 @@ pub async fn update_rev_membership_list(
.await?;
Ok(())
}

// user/NAME (get groups that user NAME belongs to): /user/MEMBER. Returns { "red": MERKLE_PF, ... }
69 changes: 53 additions & 16 deletions ad-server/src/endpoints.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::sync::Arc;
use std::{path::Path, sync::Arc};

use app::Op;
use common::CustomError;
use pod2::middleware::Value;
use common::{
CustomError,
disk::{load_pod, rev_membership_list_pod_file_name},
};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use warp::Filter;
Expand Down Expand Up @@ -34,6 +36,21 @@ pub async fn handler_membership_list_get(
Ok(warp::reply::json(&membership_list))
}

// GET /reverse_membership_list_pod/{id}
pub async fn handler_reverse_membership_list_pod_get(
id: i64,
ctx: Arc<Context>,
) -> Result<impl warp::Reply, warp::Rejection> {
let num = db::get_rev_membership_list(&ctx.db_pool, id)
.await
.map_err(|e| CustomError(e.to_string()))?
.num;
let rev_name = rev_membership_list_pod_file_name(id, num);
let reverse_index_pod = load_pod(Path::new(&ctx.cfg.pods_path), &rev_name)
.map_err(|e| CustomError(e.to_string()))?;
Ok(warp::reply::json(&reverse_index_pod))
}

#[derive(Serialize, Deserialize)]
pub struct QueueResp {
req_id: Uuid,
Expand Down Expand Up @@ -81,16 +98,12 @@ pub async fn handler_user_get(
ctx: Arc<Context>,
) -> Result<impl warp::Reply, warp::Rejection> {
let req_id = Uuid::now_v7();
ctx.queue_state
.write()
.await
.insert(req_id, queue::State::Query(queue::StateQuery::Pending));
ctx.queue_state.write().await.insert(
req_id,
queue::State::Query(Box::new(queue::StateQuery::Pending)),
);
ctx.queue_tx
.send(queue::Request::Query {
req_id,
id,
user: Value::from(user),
})
.send(queue::Request::Query { req_id, id, user })
.await
.map_err(|e| CustomError(e.to_string()))?;
Ok(warp::reply::json(&QueueResp { req_id }))
Expand All @@ -103,6 +116,7 @@ pub fn routes(
ctx: Arc<Context>,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
membership_list_get(ctx.clone())
.or(reverse_membership_list_pod_get(ctx.clone()))
.or(request_get(ctx.clone()))
.or(membership_list_create(ctx.clone()))
.or(membership_list_update(ctx.clone()))
Expand All @@ -124,6 +138,15 @@ fn membership_list_get(
.and(with_ctx(ctx))
.and_then(handler_membership_list_get)
}
fn reverse_membership_list_pod_get(
ctx: Arc<Context>,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
warp::path!("reverse_membership_list_pod" / i64)
.and(warp::get())
.and(with_ctx(ctx))
.and_then(handler_reverse_membership_list_pod_get)
}

fn membership_list_create(
ctx: Arc<Context>,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
Expand Down Expand Up @@ -162,7 +185,11 @@ fn with_ctx(
mod tests {
use app::Group;
use common::shrink::ShrunkMainPodSetup;
use pod2::{backends::plonky2::basetypes::DEFAULT_VD_SET, middleware::Params};
use pod2::{
backends::plonky2::basetypes::DEFAULT_VD_SET,
frontend::MainPod,
middleware::{Params, Value},
};
use tokio::{
sync::mpsc,
task,
Expand Down Expand Up @@ -333,9 +360,10 @@ mod tests {
assert_eq!(res.status(), StatusCode::OK);
let resp: queue::State = serde_json::from_slice(res.body()).expect("");
match resp {
queue::State::Query(state_query) => match state_query {
queue::StateQuery::Complete { result } => {
println!("{:?}", result);
queue::State::Query(state_query) => match *state_query {
queue::StateQuery::Complete { groups, proof } => {
assert_eq!(proof.value, Value::from(groups).raw());
assert_eq!(proof.key, Value::from("alice").raw());
break;
}
queue::StateQuery::Error(e) => panic!("StateQuery::Error: {}", e),
Expand All @@ -345,6 +373,15 @@ mod tests {
}
}

// Get reverse membership list POD
let res = warp::test::request()
.method("GET")
.path("/reverse_membership_list_pod/1")
.reply(&api)
.await;
assert_eq!(res.status(), StatusCode::OK);
serde_json::from_slice::<MainPod>(res.body()).expect("Should be a MainPod.");

// Delete Alice.
helper_membership_list_update(
&api,
Expand Down
101 changes: 50 additions & 51 deletions ad-server/src/queue.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::{collections::HashMap, path::Path, str::FromStr, sync::Arc};
use std::{path::Path, sync::Arc};

use alloy::primitives::TxHash;
use anyhow::{Result, anyhow};
use app::{Group, Helper, Op, RevHelper};
use anyhow::Result;
use app::{Helper, Op, RevHelper};
use common::{
ProofType,
disk::{load_pod, store_pod},
disk::{load_pod, rev_membership_list_pod_file_name, store_pod},
groth,
payload::{Payload, PayloadCreate, PayloadProof, PayloadUpdate},
set_from_value,
Expand All @@ -15,7 +15,10 @@ use pod2::{
backends::plonky2::{mainpod::Prover, primitives::merkletree::MerkleClaimAndProof},
dict,
frontend::MainPodBuilder,
middleware::{Hash, RawValue, Statement, TypedValue, Value, containers::Dictionary},
middleware::{
Hash, RawValue, Statement, TypedValue, Value,
containers::{Dictionary, Set},
},
};
use serde::{Deserialize, Serialize};
use tokio::{sync::mpsc::Receiver, task};
Expand All @@ -29,7 +32,7 @@ pub enum State {
Create(StateCreate),
Update(StateUpdate),
UpdateRev(StateUpdateRev),
Query(StateQuery),
Query(Box<StateQuery>),
}

#[derive(Clone, Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -62,7 +65,8 @@ pub enum StateUpdateRev {
pub enum StateQuery {
Pending,
Complete {
result: HashMap<Group, MerkleClaimAndProof>,
groups: Set,
proof: Box<MerkleClaimAndProof>,
},
Error(String),
}
Expand All @@ -72,7 +76,7 @@ pub enum Request {
Create { req_id: Uuid },
Update { req_id: Uuid, id: i64, op: Op },
UpdateRev { req_id: Uuid, id: i64, num: i64 },
Query { req_id: Uuid, id: i64, user: Value },
Query { req_id: Uuid, id: i64, user: String },
}

pub async fn handle_loop(ctx: Arc<Context>, mut queue_rx: Receiver<Request>) {
Expand Down Expand Up @@ -120,10 +124,10 @@ pub async fn handle_req(ctx: Arc<Context>, req: Request) -> Result<()> {
Request::Query { req_id, id, user } => {
if let Err(err) = handle_query(ctx.clone(), req_id, id, user).await {
debug!(req_id = format!("{}", req_id), err = format!("{}", err));
ctx.queue_state
.write()
.await
.insert(req_id, State::Query(StateQuery::Error(err.to_string())));
ctx.queue_state.write().await.insert(
req_id,
State::Query(Box::new(StateQuery::Error(err.to_string()))),
);
}
}
}
Expand Down Expand Up @@ -291,7 +295,7 @@ async fn handle_update_rev(ctx: Arc<Context>, req_id: Uuid, id: i64, num: i64) -
};

let (old_rev_state_pod, rev_state) = if num > 1 {
let rev_name = format!("{:08}-{:08}-rev_membership_list", id, num - 1);
let rev_name = rev_membership_list_pod_file_name(id, num - 1);
let old_rev_state_pod = load_pod(Path::new(&ctx.cfg.pods_path), &rev_name)?;
let rev_state = db::get_rev_membership_list(&ctx.db_pool, id).await?.state;
(Some(old_rev_state_pod), rev_state.0)
Expand Down Expand Up @@ -333,7 +337,7 @@ async fn handle_update_rev(ctx: Arc<Context>, req_id: Uuid, id: i64, num: i64) -

store_pod(
Path::new(&ctx.cfg.pods_path),
&format!("{:08}-{:08}-rev_membership_list", id, num),
&rev_membership_list_pod_file_name(id, num),
&rev_state_pod,
)?;

Expand All @@ -342,51 +346,46 @@ async fn handle_update_rev(ctx: Arc<Context>, req_id: Uuid, id: i64, num: i64) -
Ok(())
}

async fn handle_query(ctx: Arc<Context>, req_id: Uuid, id: i64, user: Value) -> Result<()> {
async fn handle_query(ctx: Arc<Context>, req_id: Uuid, id: i64, user: String) -> Result<()> {
let set_req_state = async |req_state| {
ctx.queue_state
.write()
.await
.insert(req_id, State::Query(req_state));
.insert(req_id, State::Query(Box::new(req_state)));
};

// get state from db
let state = db::get_membership_list(&ctx.db_pool, id).await?.state.0;

let dict_kvs = state
.kvs()
.iter()
.map(|(group, v)| {
set_from_value(v).and_then(|s| {
Group::from_str(group.name())
.map_err(|_| anyhow!("Invalid group: {}", group))
.map(|group| (group, s))
})
})
.collect::<Result<Vec<_>>>()?;

let result = dict_kvs
.into_iter()
.filter_map(|(group, s)| {
s.contains(&user).then(|| {
s.prove(&user)
.map(|proof| {
(
group,
MerkleClaimAndProof {
root: s.commitment(),
key: user.raw(),
value: user.raw(),
proof,
},
)
})
.map_err(|e| e.into())
})
})
.collect::<Result<HashMap<_, _>>>()?;
let state = db::get_rev_membership_list(&ctx.db_pool, id).await?.state.0;

// Get Merkle proof + groups to which the user belongs
let pf_with_groups = state.prove(&user.clone().into());

set_req_state(StateQuery::Complete { result }).await;
match pf_with_groups {
Err(_) => {
set_req_state(StateQuery::Error(format!(
r#"User "{}" is not a member of any group."#,
user
)))
.await
}
Ok((groups, proof)) => {
let (groups, proof) = (
set_from_value(groups)?,
MerkleClaimAndProof {
root: state.commitment(),
key: Value::from(user).raw(),
value: groups.raw(),
proof,
},
);

set_req_state(StateQuery::Complete {
groups,
proof: Box::new(proof),
})
.await;
}
}

Ok(())
}
4 changes: 4 additions & 0 deletions client.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ case "$1" in
user=$3
resp=$(curl $CURL_OPTS -X GET "$BASE_URL/user/$ad_id/$user")
;;
reverse_membership_list_pod_get)
ad_id=$2
resp=$(curl $CURL_OPTS -X GET "$BASE_URL/reverse_membership_list_pod/$ad_id")
;;
*)
usage
exit 1
Expand Down
4 changes: 4 additions & 0 deletions common/src/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@ pub fn load_pod(path: &Path, name: &str) -> Result<MainPod> {
let pod: MainPod = serde_json::from_slice(&pod_json)?;
Ok(pod)
}

pub fn rev_membership_list_pod_file_name(id: i64, num: i64) -> String {
format!("{id:08}-{num:08}-rev_membership_list")
}
6 changes: 6 additions & 0 deletions full-flow-requests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ echo -e "\nadd to membership_list, response:"
echo -e "\ngetting membership_list, response:"
./client.sh --wait-complete membership_list_get 1

echo -e "\ngetting reverse membership list POD, response:"
./client.sh reverse_membership_list_pod_get 1

echo -e "\ngetting proof of membership, response:"
./client.sh --wait-complete user_get 1 alice

echo -e "\ndel from membership_list, response:"
./client.sh --wait-complete membership_list_update 1 '{"del":{"group":"blue","user":"alice"}}'

Expand Down