Skip to content

Commit 97dc9b4

Browse files
committed
WIP
1 parent a6da2f5 commit 97dc9b4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1969
-241
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ tracing = "0.1.40"
8888
tracing-core = "0.1.32"
8989
tracing-subscriber = "0.3.18"
9090
url = { version = "2.5.4", features = ["serde"] }
91+
wasm-bindgen = "0.2.99"
9192
webpki = "0.22.4"
92-
worker = { version = "0.5", features = ["http"] }
93+
worker = "0.5"
9394
x509-parser = "0.15.1"
9495

9596
[workspace.dependencies.sentry]

crates/daphne-server/src/roles/aggregator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ impl DapAggregator for crate::App {
7979
#[tracing::instrument(skip(self))]
8080
async fn get_agg_share(
8181
&self,
82+
_version: DapVersion,
8283
task_id: &TaskId,
8384
batch_sel: &BatchSelector,
8485
) -> Result<DapAggregateShare, DapError> {

crates/daphne-server/src/roles/helper.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
use axum::async_trait;
55
use daphne::{
6-
messages::{request::AggregationJobRequestHash, AggregationJobId, TaskId},
6+
fatal_error,
7+
messages::{request::AggregationJobRequestHash, AggregationJobId, AggregationJobResp, TaskId},
78
roles::DapHelper,
89
DapError, DapVersion,
910
};
@@ -20,4 +21,13 @@ impl DapHelper for crate::App {
2021
// the server implementation can't check for this
2122
Ok(())
2223
}
24+
25+
async fn poll_aggregated(
26+
&self,
27+
_version: DapVersion,
28+
_task_id: &TaskId,
29+
_agg_job_id: &AggregationJobId,
30+
) -> Result<AggregationJobResp, DapError> {
31+
Err(fatal_error!(err = "polling not implemented"))
32+
}
2333
}

crates/daphne-service-utils/build.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ fn main() {
1111
#[cfg(feature = "durable_requests")]
1212
compiler
1313
.file("./src/durable_requests/durable_request.capnp")
14-
.file("./src/durable_requests/bindings/aggregation_job_store.capnp");
14+
.file("./src/durable_requests/bindings/aggregation_job_store.capnp")
15+
.file("./src/durable_requests/bindings/new_aggregate_store.capnp")
16+
.file("./src/durable_requests/bindings/agg_job_response_store.capnp")
17+
.file("./src/durable_requests/bindings/replay_checker.capnp");
1518

1619
#[cfg(feature = "cpu_offload")]
1720
compiler.file("./src/cpu_offload/cpu_offload.capnp");

crates/daphne-service-utils/src/cpu_offload/cpu_offload.capnp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
@0xd932f3d934afce3b;
55

6-
# Utilities
7-
86
using Base = import "../capnproto/base.capnp";
97

108
using VdafConfig = Text; # json encoded
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Copyright (c) 2025 Cloudflare, Inc. All rights reserved.
2+
# SPDX-License-Identifier: BSD-3-Clause
3+
4+
@0xd30da336463f3205;
5+
6+
using Base = import "../../capnproto/base.capnp";
7+
8+
struct AggregationJobResponse {
9+
enum ReportError {
10+
reserved @0;
11+
batchCollected @1;
12+
reportReplayed @2;
13+
reportDropped @3;
14+
hpkeUnknownConfigId @4;
15+
hpkeDecryptError @5;
16+
vdafPrepError @6;
17+
batchSaturated @7;
18+
taskExpired @8;
19+
invalidMessage @9;
20+
reportTooEarly @10;
21+
taskNotStarted @11;
22+
}
23+
24+
struct TransitionVar {
25+
union {
26+
continued @0 :Data;
27+
failed @1 :ReportError;
28+
}
29+
}
30+
31+
struct Transition {
32+
reportId @0 :Base.ReportId;
33+
var @1 :TransitionVar;
34+
}
35+
36+
transitions @0 :List(Transition);
37+
}
38+
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// Copyright (c) 2025 Cloudflare, Inc. All rights reserved.
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
4+
use daphne::{
5+
messages::{AggregationJobId, ReadyAggregationJobResp, TaskId, Transition, TransitionVar},
6+
DapVersion,
7+
};
8+
9+
use crate::{
10+
agg_job_response_store_capnp::aggregation_job_response,
11+
capnproto::{
12+
decode_list, encode_list, usize_to_capnp_len, CapnprotoPayloadDecode,
13+
CapnprotoPayloadEncode,
14+
},
15+
durable_requests::ObjectIdFrom,
16+
};
17+
18+
super::define_do_binding! {
19+
const BINDING = "AGGREGATE_JOB_RESULT_STORE";
20+
enum Command {
21+
Get = "/get",
22+
Put = "/put",
23+
}
24+
25+
fn name(
26+
(version, task_id, agg_job_id):
27+
(DapVersion, &'n TaskId, &'n AggregationJobId)
28+
) -> ObjectIdFrom {
29+
ObjectIdFrom::Name(format!("{version}/task/{task_id}/agg_job/{agg_job_id}"))
30+
}
31+
}
32+
33+
impl CapnprotoPayloadEncode for ReadyAggregationJobResp {
34+
type Builder<'a> = aggregation_job_response::Builder<'a>;
35+
36+
fn encode_to_builder(&self, builder: Self::Builder<'_>) {
37+
let Self { transitions } = self;
38+
encode_list(
39+
transitions,
40+
builder.init_transitions(usize_to_capnp_len(transitions.len())),
41+
);
42+
}
43+
}
44+
45+
impl CapnprotoPayloadEncode for Transition {
46+
type Builder<'a> = aggregation_job_response::transition::Builder<'a>;
47+
48+
fn encode_to_builder(&self, mut builder: Self::Builder<'_>) {
49+
let Self { report_id, var } = self;
50+
report_id.encode_to_builder(builder.reborrow().init_report_id());
51+
let mut builder = builder.init_var();
52+
match var {
53+
TransitionVar::Continued(vec) => builder.set_continued(vec),
54+
TransitionVar::Failed(report_error) => builder.set_failed((*report_error).into()),
55+
}
56+
}
57+
}
58+
59+
impl CapnprotoPayloadDecode for Transition {
60+
type Reader<'a> = aggregation_job_response::transition::Reader<'a>;
61+
62+
fn decode_from_reader(reader: Self::Reader<'_>) -> capnp::Result<Self>
63+
where
64+
Self: Sized,
65+
{
66+
Ok(Self {
67+
report_id: <_>::decode_from_reader(reader.get_report_id()?)?,
68+
var: match reader.get_var()?.which()? {
69+
aggregation_job_response::transition_var::Which::Continued(data) => {
70+
TransitionVar::Continued(data?.to_vec())
71+
}
72+
aggregation_job_response::transition_var::Which::Failed(report_error) => {
73+
TransitionVar::Failed(report_error?.into())
74+
}
75+
},
76+
})
77+
}
78+
}
79+
80+
impl CapnprotoPayloadDecode for ReadyAggregationJobResp {
81+
type Reader<'a> = aggregation_job_response::Reader<'a>;
82+
83+
fn decode_from_reader(reader: Self::Reader<'_>) -> capnp::Result<Self>
84+
where
85+
Self: Sized,
86+
{
87+
Ok(Self {
88+
transitions: decode_list::<Transition, _, _>(reader.get_transitions()?)?,
89+
})
90+
}
91+
}
92+
93+
impl From<daphne::messages::ReportError> for aggregation_job_response::ReportError {
94+
fn from(error: daphne::messages::ReportError) -> Self {
95+
match error {
96+
daphne::messages::ReportError::Reserved => Self::Reserved,
97+
daphne::messages::ReportError::BatchCollected => Self::BatchCollected,
98+
daphne::messages::ReportError::ReportReplayed => Self::ReportReplayed,
99+
daphne::messages::ReportError::ReportDropped => Self::ReportDropped,
100+
daphne::messages::ReportError::HpkeUnknownConfigId => Self::HpkeUnknownConfigId,
101+
daphne::messages::ReportError::HpkeDecryptError => Self::HpkeDecryptError,
102+
daphne::messages::ReportError::VdafPrepError => Self::VdafPrepError,
103+
daphne::messages::ReportError::BatchSaturated => Self::BatchSaturated,
104+
daphne::messages::ReportError::TaskExpired => Self::TaskExpired,
105+
daphne::messages::ReportError::InvalidMessage => Self::InvalidMessage,
106+
daphne::messages::ReportError::ReportTooEarly => Self::ReportTooEarly,
107+
daphne::messages::ReportError::TaskNotStarted => Self::TaskNotStarted,
108+
}
109+
}
110+
}
111+
112+
impl From<aggregation_job_response::ReportError> for daphne::messages::ReportError {
113+
fn from(error: aggregation_job_response::ReportError) -> Self {
114+
match error {
115+
aggregation_job_response::ReportError::Reserved => Self::Reserved,
116+
aggregation_job_response::ReportError::BatchCollected => Self::BatchCollected,
117+
aggregation_job_response::ReportError::ReportReplayed => Self::ReportReplayed,
118+
aggregation_job_response::ReportError::ReportDropped => Self::ReportDropped,
119+
aggregation_job_response::ReportError::HpkeUnknownConfigId => Self::HpkeUnknownConfigId,
120+
aggregation_job_response::ReportError::HpkeDecryptError => Self::HpkeDecryptError,
121+
aggregation_job_response::ReportError::VdafPrepError => Self::VdafPrepError,
122+
aggregation_job_response::ReportError::BatchSaturated => Self::BatchSaturated,
123+
aggregation_job_response::ReportError::TaskExpired => Self::TaskExpired,
124+
aggregation_job_response::ReportError::InvalidMessage => Self::InvalidMessage,
125+
aggregation_job_response::ReportError::ReportTooEarly => Self::ReportTooEarly,
126+
aggregation_job_response::ReportError::TaskNotStarted => Self::TaskNotStarted,
127+
}
128+
}
129+
}
130+
131+
#[cfg(test)]
132+
mod test {
133+
use super::*;
134+
use crate::capnproto::{CapnprotoPayloadDecodeExt as _, CapnprotoPayloadEncodeExt as _};
135+
use daphne::messages::ReportId;
136+
use rand::{thread_rng, Rng};
137+
138+
fn gen_agg_job_resp() -> ReadyAggregationJobResp {
139+
ReadyAggregationJobResp {
140+
transitions: vec![
141+
Transition {
142+
report_id: ReportId(thread_rng().gen()),
143+
var: TransitionVar::Continued(vec![1, 2, 3]),
144+
},
145+
Transition {
146+
report_id: ReportId(thread_rng().gen()),
147+
var: TransitionVar::Failed(daphne::messages::ReportError::InvalidMessage),
148+
},
149+
],
150+
}
151+
}
152+
153+
#[test]
154+
fn serialization_deserialization_round_trip() {
155+
let this = gen_agg_job_resp();
156+
let other = ReadyAggregationJobResp::decode_from_bytes(&this.encode_to_bytes()).unwrap();
157+
assert_eq!(this, other);
158+
}
159+
}

0 commit comments

Comments
 (0)