sp1_sdk/network/builder.rs
1//! # Network Prover Builder
2//!
3//! This module provides a builder for the [`NetworkProver`].
4
5use alloy_primitives::Address;
6
7use crate::{
8 network::{signer::NetworkSigner, NetworkMode, TEE_NETWORK_RPC_URL},
9 NetworkProver,
10};
11
12#[cfg(feature = "tee-2fa")]
13use crate::network::retry::{self, DEFAULT_RETRY_TIMEOUT};
14
15/// A builder for the [`NetworkProver`].
16///
17/// The builder is used to configure the [`NetworkProver`] before it is built.
18#[derive(Default)]
19pub struct NetworkProverBuilder {
20 pub(crate) private_key: Option<String>,
21 pub(crate) rpc_url: Option<String>,
22 pub(crate) tee_signers: Option<Vec<Address>>,
23 pub(crate) signer: Option<NetworkSigner>,
24 pub(crate) network_mode: Option<NetworkMode>,
25}
26
27impl NetworkProverBuilder {
28 /// Sets the Secp256k1 private key (same format as the one used by Ethereum).
29 ///
30 /// # Details
31 /// Sets the private key that will be used sign requests sent to the network. By default, the
32 /// private key is read from the `NETWORK_PRIVATE_KEY` environment variable.
33 ///
34 /// # Example
35 /// ```rust,no_run
36 /// use sp1_sdk::ProverClient;
37 ///
38 /// let prover = ProverClient::builder().network().private_key("...").build();
39 /// ```
40 #[must_use]
41 pub fn private_key(mut self, private_key: &str) -> Self {
42 self.private_key = Some(private_key.to_string());
43 self
44 }
45
46 /// Sets the remote procedure call URL.
47 ///
48 /// # Details
49 /// The URL determines the network that the client will connect to. By default, the URL is
50 /// read from the `NETWORK_RPC_URL` environment variable.
51 ///
52 /// # Example
53 /// ```rust,no_run
54 /// use sp1_sdk::ProverClient;
55 ///
56 /// let prover = ProverClient::builder().network().rpc_url("...").build();
57 /// ```
58 #[must_use]
59 pub fn rpc_url(mut self, rpc_url: &str) -> Self {
60 self.rpc_url = Some(rpc_url.to_string());
61 self
62 }
63
64 /// Process proofs inside a TEE.
65 ///
66 /// # Details
67 /// In order to keep the inputs private, it is possible to route the proof
68 /// requests to a TEE enclave.
69 ///
70 /// # Example
71 /// ```rust,no_run
72 /// use sp1_sdk::ProverClient;
73 ///
74 /// let prover = ProverClient::builder().network().private().build();
75 /// ```
76 #[must_use]
77 pub fn private(mut self) -> Self {
78 self.rpc_url = Some(TEE_NETWORK_RPC_URL.to_string());
79 self
80 }
81
82 /// Sets the list of TEE signers, used for verifying TEE proofs.
83 #[must_use]
84 pub fn tee_signers(mut self, tee_signers: &[Address]) -> Self {
85 self.tee_signers = Some(tee_signers.to_vec());
86 self
87 }
88
89 /// Sets the network signer to use for signing requests.
90 ///
91 /// # Details
92 /// This method allows you to provide a custom signer implementation, such as AWS KMS or
93 /// a local private key signer. If both `signer` and `private_key` are provided, the signer
94 /// takes precedence.
95 ///
96 /// # Examples
97 ///
98 /// Using a local private key:
99 /// ```rust,no_run
100 /// use sp1_sdk::{NetworkSigner, ProverClient};
101 ///
102 /// let private_key = "...";
103 /// let signer = NetworkSigner::local(private_key).unwrap();
104 /// let prover = ProverClient::builder().network().signer(signer).build();
105 /// ```
106 ///
107 /// Using AWS KMS:
108 /// ```rust,no_run
109 /// use sp1_sdk::{NetworkSigner, ProverClient};
110 ///
111 /// # async fn example() {
112 /// let kms_key_arn = "arn:aws:kms:us-east-1:123456789:key/key-id";
113 /// let signer = NetworkSigner::aws_kms(kms_key_arn).await.unwrap();
114 /// let prover = ProverClient::builder().network().signer(signer).build();
115 /// # }
116 /// ```
117 #[must_use]
118 pub fn signer(mut self, signer: NetworkSigner) -> Self {
119 self.signer = Some(signer);
120 self
121 }
122
123 /// Builds a [`NetworkProver`].
124 ///
125 /// # Details
126 /// This method will build a [`NetworkProver`] with the given parameters. If `signer` is
127 /// provided, it will be used directly. Otherwise, if `private_key` is provided, a local
128 /// signer will be created from it. If neither is provided, the method will look for the
129 /// `NETWORK_PRIVATE_KEY` environment variable.
130 ///
131 /// # Examples
132 ///
133 /// Using a private key:
134 /// ```rust,no_run
135 /// use sp1_sdk::ProverClient;
136 ///
137 /// let prover = ProverClient::builder().network().private_key("...").rpc_url("...").build();
138 /// ```
139 ///
140 /// Using a local signer:
141 /// ```rust,no_run
142 /// use sp1_sdk::{NetworkSigner, ProverClient};
143 ///
144 /// let private_key = "...";
145 /// let signer = NetworkSigner::local(private_key).unwrap();
146 /// let prover = ProverClient::builder().network().signer(signer).build();
147 /// ```
148 ///
149 /// Using AWS KMS:
150 /// ```rust,no_run
151 /// use sp1_sdk::{NetworkSigner, ProverClient};
152 ///
153 /// # async fn example() {
154 /// let kms_key_arn = "arn:aws:kms:us-east-1:123456789:key/key-id";
155 /// let signer = NetworkSigner::aws_kms(kms_key_arn).await.unwrap();
156 /// let prover = ProverClient::builder().network().signer(signer).build();
157 /// # }
158 /// ```
159 #[must_use]
160 pub fn build(self) -> NetworkProver {
161 let signer = if let Some(provided_signer) = self.signer {
162 provided_signer
163 } else {
164 let private_key = self
165 .private_key
166 .or_else(|| std::env::var("NETWORK_PRIVATE_KEY").ok().filter(|k| !k.is_empty()))
167 .expect(
168 "NETWORK_PRIVATE_KEY environment variable is not set. \
169 Please set it to your private key or use the .private_key() method.",
170 );
171 NetworkSigner::local(&private_key).expect("Failed to create local signer")
172 };
173
174 let network_mode = self.network_mode.unwrap_or_default();
175
176 let rpc_url = match self.rpc_url {
177 Some(rpc_url) => rpc_url,
178 None => std::env::var("NETWORK_RPC_URL")
179 .unwrap_or_else(|_| super::utils::get_default_rpc_url_for_mode(network_mode)),
180 };
181
182 let tee_signers = self.tee_signers.unwrap_or_else(|| {
183 cfg_if::cfg_if! {
184 if #[cfg(feature = "tee-2fa")] {
185 crate::utils::block_on(
186 async {
187 retry::retry_operation(
188 || async {
189 crate::network::tee::get_tee_signers().await.map_err(Into::into)
190 },
191 Some(DEFAULT_RETRY_TIMEOUT),
192 "get tee signers"
193 ).await.expect("Failed to get TEE signers")
194 }
195 )
196 } else {
197 vec![]
198 }
199 }
200 });
201
202 NetworkProver::new(signer, &rpc_url, network_mode).with_tee_signers(tee_signers)
203 }
204}