consolidation.rs (2114B)
1 use axum::{Form, Json, extract::State}; 2 use serde::Deserialize; 3 use serde_json::{Value, json}; 4 5 use super::HttpState; 6 use crate::domain::{Amount, OutPoint}; 7 8 #[derive(Deserialize)] 9 pub(super) struct PreviewForm { 10 fee_per_byte: Amount, 11 #[serde(default)] 12 merge_roots: bool, 13 } 14 15 #[derive(Deserialize)] 16 pub(super) struct SubmitForm { 17 fee_per_byte: Amount, 18 max_fee: Amount, 19 merge_roots: bool, 20 address: String, 21 utxos: String, 22 } 23 24 pub(super) async fn preview( 25 State(state): State<HttpState>, 26 Form(form): Form<PreviewForm>, 27 ) -> Json<Value> { 28 let node = state.node.lock().await; 29 match node.consolidation_plan(form.fee_per_byte, form.merge_roots) { 30 Ok(plan) => Json(json!({ "ok": true, "plan": plan })), 31 Err(error) => Json(json!({ "ok": false, "error": error.to_string() })), 32 } 33 } 34 35 pub(super) async fn submit( 36 State(state): State<HttpState>, 37 Form(form): Form<SubmitForm>, 38 ) -> Json<Value> { 39 let points: Vec<OutPoint> = match serde_json::from_str(&form.utxos) { 40 Ok(points) => points, 41 Err(_) => return Json(json!({ "ok": false, "error": "Invalid output selection" })), 42 }; 43 let (result, outbox) = { 44 let mut node = state.node.lock().await; 45 let result = node.consolidate( 46 &points, 47 form.fee_per_byte, 48 form.max_fee, 49 form.merge_roots, 50 &form.address, 51 ); 52 (result, node.drain_outbox()) 53 }; 54 match result { 55 Ok(transaction_id) => { 56 // Submission has already happened. Return its identifier even if broadcasting fails; 57 // the UI must never blindly retry a possibly accepted financial action. Keep the 58 // legacy `signature` field name for API compatibility with existing clients. 59 let broadcast = state.gossip.broadcast(outbox).await; 60 Json(json!({ "ok": true, "signature": transaction_id, 61 "broadcast_error": broadcast.err().map(|error| error.to_string()) })) 62 } 63 Err(error) => Json(json!({ "ok": false, "error": error.to_string() })), 64 } 65 }