diff --git a/bin/miden-tx-prover/Cargo.toml b/bin/miden-tx-prover/Cargo.toml index 664322303..cc6e5cceb 100644 --- a/bin/miden-tx-prover/Cargo.toml +++ b/bin/miden-tx-prover/Cargo.toml @@ -19,6 +19,7 @@ path = "src/bin.rs" [features] default = ["std"] std = [] +testing = ["miden-objects/testing", "miden-lib/testing", "miden-tx/testing"] [dependencies] miden-lib = { workspace = true } @@ -47,3 +48,7 @@ prost = { version = "0.12" } prost-build = { version = "0.12" } protox = { version = "0.6" } tonic-build = { version = "0.11" } + +[dev-dependencies] +tokio = { version = "1.38", features = ["full"] } +tonic = "0.11" diff --git a/bin/miden-tx-prover/src/bin.rs b/bin/miden-tx-prover/src/bin.rs index 403b3b31a..d1fe17e54 100644 --- a/bin/miden-tx-prover/src/bin.rs +++ b/bin/miden-tx-prover/src/bin.rs @@ -1,43 +1,9 @@ use std::env; -use miden_objects::transaction::TransactionWitness; -use miden_tx::{ - utils::{Deserializable, Serializable}, - LocalTransactionProver, TransactionProver, -}; -use miden_tx_prover::{ - server::generated::api::api_server, ProveTransactionRequest, ProveTransactionResponse, -}; +use miden_tx_prover::server::Rpc; use tokio::net::TcpListener; use tokio_stream::wrappers::TcpListenerStream; -use tonic::{Request, Response}; use tracing::info; -use winter_maybe_async::maybe_await; - -pub struct Rpc { - pub(crate) api_service: api_server::ApiServer, - pub(crate) listener: TcpListener, -} -#[derive(Clone)] -struct RpcApi; - -#[tonic::async_trait] -impl api_server::Api for RpcApi { - async fn prove_transaction( - &self, - request: Request, - ) -> Result, tonic::Status> { - info!("Received request to prove transaction"); - let prover = LocalTransactionProver::default(); - - let transaction_witness = - TransactionWitness::read_from_bytes(&request.get_ref().transaction_witness).unwrap(); - - let proof = maybe_await!(prover.prove(transaction_witness)).unwrap(); - - Ok(Response::new(ProveTransactionResponse { proven_transaction: proof.to_bytes() })) - } -} #[tokio::main] async fn main() { @@ -48,10 +14,7 @@ async fn main() { let port = env::var("PROVER_SERVICE_PORT").unwrap_or_else(|_| "50051".to_string()); let addr = format!("{}:{}", host, port); - let rpc = Rpc { - listener: tokio::net::TcpListener::bind(addr).await.unwrap(), - api_service: api_server::ApiServer::new(RpcApi), - }; + let rpc = Rpc::new(TcpListener::bind(addr).await.unwrap()); info!("Server listening on {}", rpc.listener.local_addr().unwrap()); diff --git a/bin/miden-tx-prover/src/server/mod.rs b/bin/miden-tx-prover/src/server/mod.rs index 743aa415e..18e844af3 100644 --- a/bin/miden-tx-prover/src/server/mod.rs +++ b/bin/miden-tx-prover/src/server/mod.rs @@ -1 +1,47 @@ +use generated::api::api_server; +use miden_objects::transaction::TransactionWitness; +use miden_tx::{ + utils::{Deserializable, Serializable}, + LocalTransactionProver, TransactionProver, +}; +use tokio::net::TcpListener; +use tonic::{Request, Response}; +use tracing::info; +use winter_maybe_async::maybe_await; + +use crate::{ProveTransactionRequest, ProveTransactionResponse}; + pub mod generated; + +pub struct Rpc { + pub api_service: api_server::ApiServer, + pub listener: TcpListener, +} + +impl Rpc { + pub fn new(listener: TcpListener) -> Self { + let api_service = api_server::ApiServer::new(RpcApi); + Self { listener, api_service } + } +} + +#[derive(Clone)] +pub struct RpcApi; + +#[tonic::async_trait] +impl api_server::Api for RpcApi { + async fn prove_transaction( + &self, + request: Request, + ) -> Result, tonic::Status> { + info!("Received request to prove transaction"); + let prover = LocalTransactionProver::default(); + + let transaction_witness = + TransactionWitness::read_from_bytes(&request.get_ref().transaction_witness).unwrap(); + + let proof = maybe_await!(prover.prove(transaction_witness)).unwrap(); + + Ok(Response::new(ProveTransactionResponse { proven_transaction: proof.to_bytes() })) + } +} diff --git a/bin/miden-tx-prover/tests/server_test.rs b/bin/miden-tx-prover/tests/server_test.rs new file mode 100644 index 000000000..313ea1dee --- /dev/null +++ b/bin/miden-tx-prover/tests/server_test.rs @@ -0,0 +1,88 @@ +use std::time::Duration; + +use miden_lib::transaction::TransactionKernel; +use miden_objects::{ + accounts::account_id::testing::{ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN, ACCOUNT_ID_SENDER}, + assets::{Asset, FungibleAsset}, + notes::NoteType, + testing::account_code::DEFAULT_AUTH_SCRIPT, + transaction::{TransactionScript, TransactionWitness}, +}; +use miden_tx::{ + testing::mock_chain::{Auth, MockChain}, + utils::Serializable, +}; +use miden_tx_prover::server::{ + generated::api::{api_server::ApiServer, ProveTransactionRequest, ProveTransactionResponse}, + RpcApi, +}; +use tokio::net::TcpListener; +use tonic::{Request, Response}; // Import RpcApi + +#[tokio::test] +async fn test_prove_transaction() { + // Start the server in the background + let listener = TcpListener::bind("127.0.0.1:50052").await.unwrap(); + let api_service = ApiServer::new(RpcApi); // Assuming RpcApi implements Default + + // Spawn the server as a background task + tokio::spawn(async move { + tonic::transport::Server::builder() + .accept_http1(true) + .add_service(tonic_web::enable(api_service)) + .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener)) + .await + .unwrap(); + }); + + // Give the server some time to start + tokio::time::sleep(Duration::from_secs(1)).await; + + // Set up a gRPC client to send the request + let mut client = miden_tx_prover::server::generated::api::api_client::ApiClient::connect( + "http://127.0.0.1:50052", + ) + .await + .unwrap(); + + // Create a mock transaction to send to the server + let mut mock_chain = MockChain::new(); + let account = mock_chain.add_existing_wallet(Auth::BasicAuth, vec![]); + + let fungible_asset_1: Asset = + FungibleAsset::new(ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN.try_into().unwrap(), 100) + .unwrap() + .into(); + let note_1 = mock_chain + .add_p2id_note( + ACCOUNT_ID_SENDER.try_into().unwrap(), + account.id(), + &[fungible_asset_1], + NoteType::Private, + ) + .unwrap(); + + let tx_script = + TransactionScript::compile(DEFAULT_AUTH_SCRIPT, vec![], TransactionKernel::assembler()) + .unwrap(); + let tx_context = mock_chain + .build_tx_context(account.id()) + .input_notes(vec![note_1]) + .tx_script(tx_script) + .build(); + + let executed_transaction = tx_context.execute().unwrap(); + + let transaction_witness = TransactionWitness::from(executed_transaction); + + let request = Request::new(ProveTransactionRequest { + transaction_witness: transaction_witness.to_bytes(), + }); + + // Send the request to the server + let response: Response = + client.prove_transaction(request).await.unwrap(); + + // Check the response + assert!(!response.get_ref().proven_transaction.is_empty(), "Proof generation failed"); +}