Skip to main content

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}