From b4954f9efec7ba69747a3033bf84fc8582405ce9 Mon Sep 17 00:00:00 2001 From: Mostronator Date: Thu, 12 Feb 2026 14:15:31 +0000 Subject: [PATCH] fix: prevent redundant LND queries for confirmed dev fee payments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The stale real-hash cleanup runs every scheduler cycle and queries all orders with dev_fee_paid=true and a real payment hash. For orders where the payment already succeeded, check_dev_fee_payment_status() would query LND, confirm success, and log the confirmation — but nothing changed in the order to exclude it from the next cycle's query. This caused: 1. Redundant LND TrackPaymentV2 queries every 60s for every paid order 2. Repeated '✅ Order ... dev fee payment confirmed' log messages 3. Unnecessary DB updates (setting dev_fee_paid=true when already true) Fix: Track confirmed order IDs in an in-memory HashSet so each order is only checked once per daemon lifetime. On daemon restart, the set is empty and all orders get re-checked once (preserving crash recovery behavior). Orders confirmed via the normal payment flow are also added to the set. Closes #585 --- src/scheduler.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/scheduler.rs b/src/scheduler.rs index 922e4f3e..19f1afab 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -14,6 +14,7 @@ use mostro_core::prelude::*; use nostr_sdk::EventBuilder; use nostr_sdk::{Kind as NostrKind, Tag}; use sqlx_crud::Crud; +use std::collections::HashSet; use std::sync::Arc; use tokio::sync::RwLock; use tracing::{error, info, warn}; @@ -555,6 +556,11 @@ fn parse_pending_timestamp(marker: &str) -> Option { async fn job_process_dev_fee_payment() { let pool = get_db_pool(); let interval = 60u64; // Every 60 seconds + // Track orders whose dev fee payment has been confirmed via LN status check. + // This prevents redundant LND queries on every scheduler cycle for orders + // that are already in their final state (paid + real hash). On daemon restart, + // the set is empty so each order gets re-checked once (crash recovery). + let mut confirmed_dev_fee_orders: HashSet = HashSet::new(); let mut ln_client = if let Ok(client) = LndConnector::new().await { client @@ -662,11 +668,18 @@ async fn job_process_dev_fee_payment() { { for mut real_hash_order in real_hash_orders { let order_id = real_hash_order.id; + + // Skip orders already confirmed in this daemon session + if confirmed_dev_fee_orders.contains(&order_id) { + continue; + } + match check_dev_fee_payment_status(&real_hash_order, &pool, &mut ln_client) .await { DevFeePaymentState::Succeeded => { - // Already handled by check_dev_fee_payment_status + // Payment confirmed — remember so we don't re-check + confirmed_dev_fee_orders.insert(order_id); } DevFeePaymentState::Failed => { info!( @@ -819,6 +832,7 @@ async fn job_process_dev_fee_payment() { " Amount: {} sats, Hash: {}", dev_fee_amount, payment_hash ); + confirmed_dev_fee_orders.insert(order_id); // Verify update if let Ok(verified_order) = sqlx::query_as::<_, Order>(