From 1d8aa5290247847bd66fcc59e2a90c00821d6cb1 Mon Sep 17 00:00:00 2001 From: sword-smith Date: Thu, 21 Aug 2025 07:50:46 +0200 Subject: [PATCH 1/2] Add endpoint for fetching address-specific pow puzzle --- src/main.rs | 2 ++ src/rpc/mod.rs | 1 + src/rpc/pow_puzzle.rs | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 src/rpc/pow_puzzle.rs diff --git a/src/main.rs b/src/main.rs index a5ce3f5..3a36a02 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use neptune_explorer::model::app_state::AppState; use neptune_explorer::neptune_rpc; use neptune_explorer::rpc::block_digest::block_digest; use neptune_explorer::rpc::block_info::block_info; +use neptune_explorer::rpc::pow_puzzle::pow_puzzle; use neptune_explorer::rpc::utxo_digest::utxo_digest; use tower_http::services::ServeDir; use tracing::info; @@ -53,6 +54,7 @@ pub fn setup_routes(app_state: AppState) -> Router { .route("/rpc/block_info/*selector", get(block_info)) .route("/rpc/block_digest/*selector", get(block_digest)) .route("/rpc/utxo_digest/:index", get(utxo_digest)) + .route("/rpc/pow_puzzle/*address", get(pow_puzzle)) // -- Dynamic HTML pages -- .route("/", get(root)) .route("/block/*selector", get(block_page)) diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index 2d1a655..ca1ff31 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -1,3 +1,4 @@ pub mod block_digest; pub mod block_info; +pub mod pow_puzzle; pub mod utxo_digest; diff --git a/src/rpc/pow_puzzle.rs b/src/rpc/pow_puzzle.rs new file mode 100644 index 0000000..109ae8b --- /dev/null +++ b/src/rpc/pow_puzzle.rs @@ -0,0 +1,36 @@ +use axum::extract::Path; +use axum::extract::State; +use axum::response::IntoResponse; +use axum::response::Json; +use neptune_cash::models::state::wallet::address::generation_address::GenerationReceivingAddress; +use neptune_cash::rpc_server::error::RpcError; +use neptune_cash::rpc_server::ProofOfWorkPuzzle; +use std::sync::Arc; +use tarpc::context; + +use crate::http_util::not_found_err; +use crate::http_util::rpc_err; +use crate::http_util::rpc_method_err; +use crate::model::app_state::AppState; + +#[axum::debug_handler] +pub async fn pow_puzzle( + Path(address): Path, + State(state): State>, +) -> Result, impl IntoResponse> { + let s = state.load(); + let Ok(receiving_address) = GenerationReceivingAddress::from_bech32m(&address, s.network) + else { + return Err(rpc_method_err(RpcError::Failed(address))); + }; + match s + .rpc_client + .pow_puzzle_external_key(context::current(), s.token(), receiving_address.into()) + .await + .map_err(rpc_err)? + .map_err(rpc_method_err)? + { + Some(pow_puzzle) => Ok(Json(pow_puzzle)), + None => Err(not_found_err()), + } +} From 5c81a9448768bb58abc2b13d051d02d1d35ca775 Mon Sep 17 00:00:00 2001 From: sword-smith Date: Thu, 21 Aug 2025 09:10:40 +0200 Subject: [PATCH 2/2] Add endpoint for providing a PoW solution --- src/main.rs | 3 +++ src/rpc/mod.rs | 1 + src/rpc/provide_pow_solution.rs | 39 +++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 src/rpc/provide_pow_solution.rs diff --git a/src/main.rs b/src/main.rs index 3a36a02..dbe186e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use anyhow::Context; use axum::routing::get; +use axum::routing::post; use axum::routing::Router; use neptune_explorer::alert_email; use neptune_explorer::html::page::block::block_page; @@ -12,6 +13,7 @@ use neptune_explorer::neptune_rpc; use neptune_explorer::rpc::block_digest::block_digest; use neptune_explorer::rpc::block_info::block_info; use neptune_explorer::rpc::pow_puzzle::pow_puzzle; +use neptune_explorer::rpc::provide_pow_solution::provide_pow_solution; use neptune_explorer::rpc::utxo_digest::utxo_digest; use tower_http::services::ServeDir; use tracing::info; @@ -55,6 +57,7 @@ pub fn setup_routes(app_state: AppState) -> Router { .route("/rpc/block_digest/*selector", get(block_digest)) .route("/rpc/utxo_digest/:index", get(utxo_digest)) .route("/rpc/pow_puzzle/*address", get(pow_puzzle)) + .route("/rpc/provide_pow_solution", post(provide_pow_solution)) // -- Dynamic HTML pages -- .route("/", get(root)) .route("/block/*selector", get(block_page)) diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index ca1ff31..0d9f7ec 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -1,4 +1,5 @@ pub mod block_digest; pub mod block_info; pub mod pow_puzzle; +pub mod provide_pow_solution; pub mod utxo_digest; diff --git a/src/rpc/provide_pow_solution.rs b/src/rpc/provide_pow_solution.rs new file mode 100644 index 0000000..44ffc68 --- /dev/null +++ b/src/rpc/provide_pow_solution.rs @@ -0,0 +1,39 @@ +use crate::http_util::rpc_err; +use crate::http_util::rpc_method_err; +use crate::model::app_state::AppState; +use axum::extract::State; +use axum::response::Json; +use axum::response::Response; +use neptune_cash::models::blockchain::block::block_header::BlockPow; +use neptune_cash::prelude::twenty_first::tip5::Digest; +use serde::Deserialize; +use serde::Serialize; +use std::sync::Arc; +use tarpc::context; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PowSolution { + pow: BlockPow, + proposal_id: Digest, +} + +#[axum::debug_handler] +pub async fn provide_pow_solution( + State(state): State>, + Json(payload): Json, +) -> Result, Response> { + let s = state.load(); + let result = s + .rpc_client + .provide_pow_solution( + context::current(), + s.token(), + payload.pow, + payload.proposal_id, + ) + .await + .map_err(rpc_err)? + .map_err(rpc_method_err)?; + + Ok(Json(result)) +}