iuna

iuna

iuna - experimental mainnet-candidate protocol
git clone https://getiuna.org/git/iuna.git
Log | Files | Refs | README | LICENSE

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 }