miden_client/remote_prover/
tx_prover.rs1use alloc::string::String;
2use alloc::sync::Arc;
3use core::time::Duration;
4
5use miden_protocol::transaction::{ProvenTransaction, TransactionInputs};
6use miden_protocol::utils::serde::{Deserializable, DeserializationError, Serializable};
7use miden_protocol::vm::FutureMaybeSend;
8use miden_tx::TransactionProverError;
9use tokio::sync::Mutex;
10
11use super::api_client::ApiClient;
12use super::{RemoteProverClientError, generated as proto};
13
14#[derive(Clone)]
25pub struct RemoteTransactionProver {
26 client: Arc<Mutex<Option<ApiClient>>>,
28
29 endpoint: String,
31
32 timeout: Duration,
34}
35
36impl RemoteTransactionProver {
37 pub fn new(endpoint: impl Into<String>) -> Self {
40 RemoteTransactionProver {
41 endpoint: endpoint.into(),
42 client: Arc::new(Mutex::new(None)),
43 timeout: Duration::from_secs(10),
44 }
45 }
46
47 #[must_use]
49 pub fn with_timeout(mut self, timeout: Duration) -> Self {
50 self.timeout = timeout;
51 self
52 }
53
54 async fn connect(&self) -> Result<(), RemoteProverClientError> {
58 let mut client = self.client.lock().await;
59 if client.is_some() {
60 return Ok(());
61 }
62
63 *client = Some(ApiClient::new_client(self.endpoint.clone(), self.timeout).await?);
64
65 Ok(())
66 }
67
68 pub fn prove(
71 &self,
72 tx_inputs: &TransactionInputs,
73 ) -> impl FutureMaybeSend<Result<ProvenTransaction, TransactionProverError>> {
74 async move {
75 self.connect().await.map_err(|err| {
76 TransactionProverError::other_with_source(
77 "failed to connect to the remote prover",
78 err,
79 )
80 })?;
81
82 let mut client = self
83 .client
84 .lock()
85 .await
86 .as_ref()
87 .ok_or_else(|| TransactionProverError::other("client should be connected"))?
88 .clone();
89
90 let request = tonic::Request::new(tx_inputs.into());
91
92 let response = client.prove(request).await.map_err(|err| {
93 TransactionProverError::other_with_source("failed to prove transaction", err)
94 })?;
95
96 ProvenTransaction::try_from(response.into_inner()).map_err(|_| {
97 TransactionProverError::other(
98 "failed to deserialize received response from remote transaction prover",
99 )
100 })
101 }
102 }
103}
104
105impl TryFrom<proto::Proof> for ProvenTransaction {
109 type Error = DeserializationError;
110
111 fn try_from(response: proto::Proof) -> Result<Self, Self::Error> {
112 ProvenTransaction::read_from_bytes(&response.payload)
113 }
114}
115
116impl From<&TransactionInputs> for proto::ProofRequest {
117 fn from(tx_inputs: &TransactionInputs) -> Self {
118 proto::ProofRequest {
119 proof_type: proto::ProofType::Transaction.into(),
120 payload: tx_inputs.to_bytes(),
121 }
122 }
123}