boundless_market/storage/traits.rs
1// Copyright 2026 Boundless Foundation, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Traits for storage operations.
16
17use super::StorageError;
18use async_trait::async_trait;
19use auto_impl::auto_impl;
20use sha2::{Digest as _, Sha256};
21use url::Url;
22
23/// A trait for uploading risc0-zkvm programs and input files to a storage uploader.
24#[async_trait]
25#[auto_impl(Arc)]
26pub trait StorageUploader: Send + Sync {
27 /// Upload raw bytes with the given key.
28 ///
29 /// This is the core upload method that implementations must provide.
30 async fn upload_bytes(&self, data: &[u8], key: &str) -> Result<Url, StorageError>;
31
32 /// Upload a risc0-zkvm program binary.
33 ///
34 /// Returns the URL which can be used to publicly access the uploaded program. This URL can be
35 /// included in a request sent to Boundless.
36 ///
37 /// The default implementation computes the image ID and delegates to [`upload_bytes`](Self::upload_bytes).
38 async fn upload_program(&self, program: &[u8]) -> Result<Url, StorageError> {
39 let image_id = risc0_zkvm::compute_image_id(program)?;
40 self.upload_bytes(program, &format!("{image_id}.bin")).await
41 }
42
43 /// Upload the input for use in a proof request.
44 ///
45 /// Returns the URL which can be used to publicly access the uploaded input. This URL can be
46 /// included in a request sent to Boundless.
47 ///
48 /// The default implementation computes the SHA256 digest and delegates to [`upload_bytes`](Self::upload_bytes).
49 async fn upload_input(&self, input: &[u8]) -> Result<Url, StorageError> {
50 let digest = Sha256::digest(input);
51 self.upload_bytes(input, &format!("{}.input", hex::encode(digest))).await
52 }
53}
54
55/// A trait for downloading data from URLs.
56#[async_trait]
57#[auto_impl(Arc)]
58pub trait StorageDownloader: Send + Sync {
59 /// Downloads data from the given URL, returning at most `limit` bytes.
60 ///
61 /// This method allows callers to override the default size limit configured in the
62 /// downloader. Pass `usize::MAX` to effectively disable the limit for this call.
63 /// This is useful for trusted sources or priority requestors that should not be
64 /// subject to the global size restrictions.
65 async fn download_url_with_limit(
66 &self,
67 url: Url,
68 limit: usize,
69 ) -> Result<Vec<u8>, StorageError>;
70
71 /// Downloads the content from the given URL.
72 ///
73 /// Implementations should apply their configured size limit. For downloaders
74 /// without a configured limit, this typically uses `usize::MAX`.
75 async fn download_url(&self, url: Url) -> Result<Vec<u8>, StorageError>;
76
77 /// Parses `url` and downloads data, returning at most `limit` bytes.
78 async fn download_with_limit(&self, url: &str, limit: usize) -> Result<Vec<u8>, StorageError> {
79 self.download_url_with_limit(Url::parse(url)?, limit).await
80 }
81
82 /// Parses `url` and downloads the content.
83 async fn download(&self, url: &str) -> Result<Vec<u8>, StorageError> {
84 self.download_url(Url::parse(url)?).await
85 }
86}