Skip to content

Commit 81be73c

Browse files
authored
feat(private-stdin): add PRIVATE_STDIN artifact type (#220)
1 parent 8ede7c2 commit 81be73c

8 files changed

Lines changed: 187 additions & 2 deletions

File tree

crates/network/artifacts/src/lib.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,9 @@ impl Artifact {
381381
}
382382
}
383383

384-
/// Given a S3 URL (e.g. <s3://prover-network-staging/artifacts/artifact_01j92x39ngfnrra5br9n8zr07x>),
385-
/// extract the artifact name from the URL (e.g. `artifact_01j92x39ngfnrra5br9n8zr07x`).
384+
/// Given a S3 URL (e.g.
385+
/// <s3://prover-network-staging/artifacts/artifact_01j92x39ngfnrra5br9n8zr07x>), extract the
386+
/// artifact name from the URL (e.g. `artifact_01j92x39ngfnrra5br9n8zr07x`).
386387
///
387388
/// This is used because the cluster assumes a specific bucket and path already, and just operates
388389
/// on the artifact name.
@@ -402,6 +403,7 @@ pub fn get_s3_prefix(artifact_type: ArtifactType) -> &'static str {
402403
ArtifactType::Stdin => "stdins",
403404
ArtifactType::Proof => "proofs",
404405
ArtifactType::Transaction => "transactions",
406+
ArtifactType::PrivateStdin => "private-stdins",
405407
}
406408
}
407409

@@ -744,3 +746,14 @@ async fn upload_file(
744746

745747
Ok(())
746748
}
749+
750+
#[cfg(test)]
751+
mod tests {
752+
use super::*;
753+
use spn_artifact_types::ArtifactType;
754+
755+
#[test]
756+
fn private_stdin_has_its_own_prefix() {
757+
assert_eq!(get_s3_prefix(ArtifactType::PrivateStdin), "private-stdins");
758+
}
759+
}

crates/types/artifact/src/artifact.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ pub enum ArtifactType {
3232
Proof = 3,
3333
/// A transaction artifact.
3434
Transaction = 4,
35+
/// A private stdin artifact stored under the private-stdins/ prefix.
36+
/// Only fetched via the authenticated GetStdinUri RPC.
37+
PrivateStdin = 7,
3538
}
3639
impl ArtifactType {
3740
/// String value of the enum field names used in the ProtoBuf definition.
@@ -45,6 +48,7 @@ impl ArtifactType {
4548
Self::Stdin => "STDIN",
4649
Self::Proof => "PROOF",
4750
Self::Transaction => "TRANSACTION",
51+
Self::PrivateStdin => "PRIVATE_STDIN",
4852
}
4953
}
5054
/// Creates an enum from field names used in the ProtoBuf definition.
@@ -55,6 +59,7 @@ impl ArtifactType {
5559
"STDIN" => Some(Self::Stdin),
5660
"PROOF" => Some(Self::Proof),
5761
"TRANSACTION" => Some(Self::Transaction),
62+
"PRIVATE_STDIN" => Some(Self::PrivateStdin),
5863
_ => None,
5964
}
6065
}

crates/types/network/src/network.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,32 @@ pub mod prover_network_client {
248248
);
249249
self.inner.unary(req, path, codec).await
250250
}
251+
/// Get a short-lived presigned URL to download a private request's stdin.
252+
/// Only callable by the requester, executor, or (post-settlement) fulfiller.
253+
pub async fn get_stdin_uri(
254+
&mut self,
255+
request: impl tonic::IntoRequest<super::super::types::GetStdinUriRequest>,
256+
) -> std::result::Result<
257+
tonic::Response<super::super::types::GetStdinUriResponse>,
258+
tonic::Status,
259+
> {
260+
self.inner
261+
.ready()
262+
.await
263+
.map_err(|e| {
264+
tonic::Status::unknown(
265+
format!("Service was not ready: {}", e.into()),
266+
)
267+
})?;
268+
let codec = tonic::codec::ProstCodec::default();
269+
let path = http::uri::PathAndQuery::from_static(
270+
"/network.ProverNetwork/GetStdinUri",
271+
);
272+
let mut req = request.into_request();
273+
req.extensions_mut()
274+
.insert(GrpcMethod::new("network.ProverNetwork", "GetStdinUri"));
275+
self.inner.unary(req, path, codec).await
276+
}
251277
/// Get the proof requests that meet the filter criteria.
252278
pub async fn get_filtered_proof_requests(
253279
&mut self,
@@ -1715,6 +1741,15 @@ pub mod prover_network_server {
17151741
tonic::Response<super::super::types::GetProofRequestDetailsResponse>,
17161742
tonic::Status,
17171743
>;
1744+
/// Get a short-lived presigned URL to download a private request's stdin.
1745+
/// Only callable by the requester, executor, or (post-settlement) fulfiller.
1746+
async fn get_stdin_uri(
1747+
&self,
1748+
request: tonic::Request<super::super::types::GetStdinUriRequest>,
1749+
) -> std::result::Result<
1750+
tonic::Response<super::super::types::GetStdinUriResponse>,
1751+
tonic::Status,
1752+
>;
17181753
/// Get the proof requests that meet the filter criteria.
17191754
async fn get_filtered_proof_requests(
17201755
&self,
@@ -2524,6 +2559,54 @@ pub mod prover_network_server {
25242559
};
25252560
Box::pin(fut)
25262561
}
2562+
"/network.ProverNetwork/GetStdinUri" => {
2563+
#[allow(non_camel_case_types)]
2564+
struct GetStdinUriSvc<T: ProverNetwork>(pub Arc<T>);
2565+
impl<
2566+
T: ProverNetwork,
2567+
> tonic::server::UnaryService<
2568+
super::super::types::GetStdinUriRequest,
2569+
> for GetStdinUriSvc<T> {
2570+
type Response = super::super::types::GetStdinUriResponse;
2571+
type Future = BoxFuture<
2572+
tonic::Response<Self::Response>,
2573+
tonic::Status,
2574+
>;
2575+
fn call(
2576+
&mut self,
2577+
request: tonic::Request<
2578+
super::super::types::GetStdinUriRequest,
2579+
>,
2580+
) -> Self::Future {
2581+
let inner = Arc::clone(&self.0);
2582+
let fut = async move {
2583+
<T as ProverNetwork>::get_stdin_uri(&inner, request).await
2584+
};
2585+
Box::pin(fut)
2586+
}
2587+
}
2588+
let accept_compression_encodings = self.accept_compression_encodings;
2589+
let send_compression_encodings = self.send_compression_encodings;
2590+
let max_decoding_message_size = self.max_decoding_message_size;
2591+
let max_encoding_message_size = self.max_encoding_message_size;
2592+
let inner = self.inner.clone();
2593+
let fut = async move {
2594+
let method = GetStdinUriSvc(inner);
2595+
let codec = tonic::codec::ProstCodec::default();
2596+
let mut grpc = tonic::server::Grpc::new(codec)
2597+
.apply_compression_config(
2598+
accept_compression_encodings,
2599+
send_compression_encodings,
2600+
)
2601+
.apply_max_message_size_config(
2602+
max_decoding_message_size,
2603+
max_encoding_message_size,
2604+
);
2605+
let res = grpc.unary(method, req).await;
2606+
Ok(res)
2607+
};
2608+
Box::pin(fut)
2609+
}
25272610
"/network.ProverNetwork/GetFilteredProofRequests" => {
25282611
#[allow(non_camel_case_types)]
25292612
struct GetFilteredProofRequestsSvc<T: ProverNetwork>(pub Arc<T>);

crates/types/network/src/types.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ pub struct RequestProofRequestBody {
164164
/// The treasury address.
165165
#[prost(bytes = "vec", tag = "20")]
166166
pub treasury: ::prost::alloc::vec::Vec<u8>,
167+
/// Whether the stdin is private. When true, stdin_uri must be under
168+
/// the private-stdins/ prefix and is only fetchable via GetStdinUri.
169+
#[prost(bool, tag = "21")]
170+
pub stdin_private: bool,
167171
}
168172
#[derive(serde::Serialize, serde::Deserialize)]
169173
#[derive(Clone, PartialEq, ::prost::Message)]
@@ -457,6 +461,10 @@ pub struct ProofRequest {
457461
/// The proof request error, if any.
458462
#[prost(enumeration = "ProofRequestError", tag = "36")]
459463
pub error: i32,
464+
/// Whether this request's stdin is private. When true, stdin_public_uri is
465+
/// empty and stdin is only fetchable via GetStdinUri by an authorized caller.
466+
#[prost(bool, tag = "38")]
467+
pub stdin_private: bool,
460468
}
461469
#[derive(serde::Serialize, serde::Deserialize)]
462470
#[derive(Clone, PartialEq, ::prost::Message)]
@@ -514,6 +522,42 @@ pub struct GetProofRequestDetailsResponse {
514522
}
515523
#[derive(serde::Serialize, serde::Deserialize)]
516524
#[derive(Clone, PartialEq, ::prost::Message)]
525+
pub struct GetStdinUriRequest {
526+
/// The message format of the body.
527+
#[prost(enumeration = "MessageFormat", tag = "1")]
528+
pub format: i32,
529+
/// The signature of the sender.
530+
#[prost(bytes = "vec", tag = "2")]
531+
pub signature: ::prost::alloc::vec::Vec<u8>,
532+
/// The body of the request.
533+
#[prost(message, optional, tag = "3")]
534+
pub body: ::core::option::Option<GetStdinUriRequestBody>,
535+
}
536+
#[derive(serde::Serialize, serde::Deserialize)]
537+
#[derive(Clone, PartialEq, ::prost::Message)]
538+
pub struct GetStdinUriRequestBody {
539+
/// The account nonce of the sender.
540+
#[prost(uint64, tag = "1")]
541+
pub nonce: u64,
542+
/// The identifier for the request.
543+
#[prost(bytes = "vec", tag = "2")]
544+
pub request_id: ::prost::alloc::vec::Vec<u8>,
545+
/// The domain separator bytes for the request.
546+
#[prost(bytes = "vec", tag = "3")]
547+
pub domain: ::prost::alloc::vec::Vec<u8>,
548+
}
549+
#[derive(serde::Serialize, serde::Deserialize)]
550+
#[derive(Clone, PartialEq, ::prost::Message)]
551+
pub struct GetStdinUriResponse {
552+
/// Presigned HTTPS URL for downloading the stdin artifact.
553+
#[prost(string, tag = "1")]
554+
pub stdin_uri: ::prost::alloc::string::String,
555+
/// Unix seconds at which the URL expires.
556+
#[prost(uint64, tag = "2")]
557+
pub expires_at: u64,
558+
}
559+
#[derive(serde::Serialize, serde::Deserialize)]
560+
#[derive(Clone, PartialEq, ::prost::Message)]
517561
pub struct GetFilteredProofRequestsRequest {
518562
/// The optional version of the requests to filter for.
519563
#[prost(string, optional, tag = "1")]

crates/vapp/tests/common/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,7 @@ pub fn create_clear_tx_with_options(
591591
max_price_per_pgu: max_price_per_pgu.unwrap_or("100000").to_string(),
592592
variant: TransactionVariant::RequestVariant as i32,
593593
treasury: signer("treasury").address().to_vec(),
594+
stdin_private: false,
594595
};
595596

596597
// Compute the request ID from the request body and signer.
@@ -902,6 +903,7 @@ pub fn create_clear_tx_with_public_values_hash(
902903
max_price_per_pgu: "100000".to_string(),
903904
variant: TransactionVariant::RequestVariant as i32,
904905
treasury: signer("treasury").address().to_vec(),
906+
stdin_private: false,
905907
};
906908

907909
// Compute the request ID from the request body and signer.
@@ -1108,6 +1110,7 @@ pub fn create_clear_tx_with_version(
11081110
max_price_per_pgu: "100000".to_string(),
11091111
variant: TransactionVariant::RequestVariant as i32,
11101112
treasury: signer("treasury").address().to_vec(),
1113+
stdin_private: false,
11111114
};
11121115

11131116
// Compute the request ID from the request body and signer.

proto/artifact.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,7 @@ enum ArtifactType {
3131
PROOF = 3;
3232
// A transaction artifact.
3333
TRANSACTION = 4;
34+
// A private stdin artifact stored under the private-stdins/ prefix.
35+
// Only fetched via the authenticated GetStdinUri RPC.
36+
PRIVATE_STDIN = 7;
3437
}

proto/network.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ service ProverNetwork {
2727
// Get the details of a proof request.
2828
rpc GetProofRequestDetails(types.GetProofRequestDetailsRequest)
2929
returns (types.GetProofRequestDetailsResponse) {}
30+
// Get a short-lived presigned URL to download a private request's stdin.
31+
// Only callable by the requester, executor, or (post-settlement) fulfiller.
32+
rpc GetStdinUri(types.GetStdinUriRequest) returns (types.GetStdinUriResponse) {}
3033
// Get the proof requests that meet the filter criteria.
3134
rpc GetFilteredProofRequests(types.GetFilteredProofRequestsRequest)
3235
returns (types.GetFilteredProofRequestsResponse) {}

proto/types.proto

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ message RequestProofRequestBody {
147147
TransactionVariant variant = 19;
148148
// The treasury address.
149149
bytes treasury = 20;
150+
// Whether the stdin is private. When true, stdin_uri must be under
151+
// the private-stdins/ prefix and is only fetchable via GetStdinUri.
152+
bool stdin_private = 21;
150153
}
151154

152155
message RequestProofResponse {
@@ -350,6 +353,9 @@ message ProofRequest {
350353
optional string max_price_per_pgu = 35;
351354
// The proof request error, if any.
352355
ProofRequestError error = 36;
356+
// Whether this request's stdin is private. When true, stdin_public_uri is
357+
// empty and stdin is only fetchable via GetStdinUri by an authorized caller.
358+
bool stdin_private = 38;
353359
}
354360

355361
message GetProofRequestStatusRequest {
@@ -391,6 +397,31 @@ message GetProofRequestDetailsResponse {
391397
ProofRequest request = 1;
392398
}
393399

400+
message GetStdinUriRequest {
401+
// The message format of the body.
402+
MessageFormat format = 1;
403+
// The signature of the sender.
404+
bytes signature = 2;
405+
// The body of the request.
406+
GetStdinUriRequestBody body = 3;
407+
}
408+
409+
message GetStdinUriRequestBody {
410+
// The account nonce of the sender.
411+
uint64 nonce = 1;
412+
// The identifier for the request.
413+
bytes request_id = 2;
414+
// The domain separator bytes for the request.
415+
bytes domain = 3;
416+
}
417+
418+
message GetStdinUriResponse {
419+
// Presigned HTTPS URL for downloading the stdin artifact.
420+
string stdin_uri = 1;
421+
// Unix seconds at which the URL expires.
422+
uint64 expires_at = 2;
423+
}
424+
394425
message GetFilteredProofRequestsRequest {
395426
// The optional version of the requests to filter for.
396427
optional string version = 1;

0 commit comments

Comments
 (0)