iota/iota-storage/src/util/downstream_relay.rs
2026-09-01 22:17:57 +02:00

69 lines
3.6 KiB
Rust

/* Completes or rejects an Iota-to-Iota relay without leaving retry state behind. */
use crate::storage_error::StorageError;
use crate::util::{db, sync};
use rusqlite::{OptionalExtension, params};
pub fn acknowledge_iota_delivery(
destination_iota: u64,
frame_id: u32,
signer_id: i64,
relay_message_id: &str,
destination_accepted_at: i64,
) -> Result<(), StorageError> {
let destination_iota = i64::try_from(destination_iota)
.map_err(|_| StorageError::Other("relay destination ID exceeds SQLite range".into()))?;
db::with_immediate_transaction(|tx| {
let pending_id = tx.query_row("SELECT id FROM pending_relays WHERE destination_id = ?1 AND target_kind = 1 AND frame_id = ?2", params![destination_iota, i64::from(frame_id)], |row| row.get::<_, i64>(0)).optional()?;
let Some(pending_id) = pending_id else {
return Ok(());
};
let message_id = tx.query_row("SELECT id FROM messages WHERE storage_owner = ?1 AND relay_signer_id = ?1 AND relay_message_id = ?2", params![signer_id, relay_message_id], |row| row.get::<_, i64>(0)).optional()?;
if let Some(message_id) = message_id {
tx.execute("UPDATE messages SET destination_iota_received_at = COALESCE(destination_iota_received_at, ?1), delivery_failed_at = NULL, delivery_failure = NULL, message_state = CASE WHEN message_state = 'sending' THEN 'sent' ELSE message_state END WHERE id = ?2", params![destination_accepted_at, message_id])?;
sync::record_event(
tx,
signer_id,
sync::EntityType::Message,
message_id,
sync::Operation::Upsert,
)?;
}
tx.execute("UPDATE relay_inbox SET state = 'delivered', downstream_acked_at = COALESCE(downstream_acked_at, ?3) WHERE signer_id = ?1 AND message_id = ?2", params![signer_id, relay_message_id, sync::now_millis()])?;
tx.execute("DELETE FROM pending_relays WHERE id = ?1", [pending_id])?;
Ok(())
})
}
pub fn reject_iota_delivery(
destination_iota: u64,
frame_id: u32,
signer_id: i64,
relay_message_id: &str,
failure: &str,
) -> Result<(), StorageError> {
let destination_iota = i64::try_from(destination_iota)
.map_err(|_| StorageError::Other("relay destination ID exceeds SQLite range".into()))?;
db::with_immediate_transaction(|tx| {
let pending_id = tx.query_row("SELECT id FROM pending_relays WHERE destination_id = ?1 AND target_kind = 1 AND frame_id = ?2", params![destination_iota, i64::from(frame_id)], |row| row.get::<_, i64>(0)).optional()?;
let Some(pending_id) = pending_id else {
return Ok(());
};
let message_id = tx.query_row("SELECT id FROM messages WHERE storage_owner = ?1 AND relay_signer_id = ?1 AND relay_message_id = ?2", params![signer_id, relay_message_id], |row| row.get::<_, i64>(0)).optional()?;
if let Some(message_id) = message_id {
tx.execute(
"UPDATE messages SET delivery_failed_at = ?1, delivery_failure = ?2 WHERE id = ?3",
params![sync::now_millis(), failure, message_id],
)?;
sync::record_event(
tx,
signer_id,
sync::EntityType::Message,
message_id,
sync::Operation::Upsert,
)?;
}
tx.execute("UPDATE relay_inbox SET state = 'rejected', rejected_at = COALESCE(rejected_at, ?3) WHERE signer_id = ?1 AND message_id = ?2", params![signer_id, relay_message_id, sync::now_millis()])?;
tx.execute("DELETE FROM pending_relays WHERE id = ?1", [pending_id])?;
Ok(())
})
}