Skip to content

Commit 40760ea

Browse files
authored
Merge branch 'main' into encryption-removed
2 parents 213c1a2 + 2f99d57 commit 40760ea

2 files changed

Lines changed: 221 additions & 0 deletions

File tree

docker/ENV_VARIABLES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ These files are copied to `docker/config/lnd/` during the build process.
1818
- Used in `compose.yml` for port mapping
1919
- Example: `export MOSTRO_RELAY_LOCAL_PORT=7000`
2020

21+
- `MOSTRO_DB_PASSWORD`: Not used (database encryption was removed). Kept in `compose.yml` for backward compatibility; can be omitted or left empty.
22+
2123
## Usage Examples
2224

2325
### Linux/macOS

src/nip33.rs

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,64 @@ pub fn info_to_tags(ln_status: &LnStatus) -> Tags {
498498
#[cfg(test)]
499499
mod tests {
500500
use super::create_platform_tag_values;
501+
use super::{info_to_tags, order_to_tags};
502+
use crate::app::context::test_utils::test_settings;
503+
use crate::config::MOSTRO_CONFIG;
504+
use crate::lightning::LnStatus;
505+
use mostro_core::prelude::*;
506+
use nostr_sdk::prelude::*;
507+
use std::borrow::Cow;
508+
509+
// ── Shared test helpers ──────────────────────────────────────────────────────
510+
511+
/// Initialize global settings once per test binary run using the canonical
512+
/// test_settings() helper from AppContext test_utils — consistent with the
513+
/// rest of the test infrastructure.
514+
/// Uses `let _ =` to silently ignore if the OnceLock is already set by another test.
515+
fn init_test_settings() {
516+
let _ = MOSTRO_CONFIG.set(test_settings());
517+
}
518+
519+
/// Build a minimal pending order sufficient for order_to_tags to emit tags.
520+
fn make_pending_order() -> Order {
521+
Order {
522+
status: Status::Pending.to_string(),
523+
kind: mostro_core::order::Kind::Sell.to_string(),
524+
fiat_code: "USD".to_string(),
525+
payment_method: "bank".to_string(),
526+
..Default::default()
527+
}
528+
}
529+
530+
/// Build a stub LnStatus sufficient for info_to_tags.
531+
fn make_ln_status() -> LnStatus {
532+
LnStatus {
533+
version: "0.0.0".to_string(),
534+
node_pubkey: "stub".to_string(),
535+
commit_hash: "stub".to_string(),
536+
node_alias: "stub".to_string(),
537+
chains: vec![],
538+
networks: vec![],
539+
uris: vec![],
540+
}
541+
}
542+
543+
/// Extract the values of the "y" tag from a Tags collection.
544+
///
545+
/// `tag.as_vec()` returns `[tag_name, val0, val1, ...]`, so values start at index 1.
546+
/// Returns None if no "y" tag is present — which itself would be a test failure.
547+
fn get_y_tag_values(tags: &Tags) -> Option<Vec<String>> {
548+
tags.iter().find_map(|tag| {
549+
let vec = tag.clone().to_vec();
550+
if vec.first().map(|s| s.as_str()) == Some("y") {
551+
Some(vec[1..].to_vec())
552+
} else {
553+
None
554+
}
555+
})
556+
}
557+
558+
// ── create_platform_tag_values unit tests (unchanged from #653) ──────────────
501559

502560
#[test]
503561
fn create_platform_tag_values_with_none_returns_only_mostro() {
@@ -527,4 +585,165 @@ mod tests {
527585
vec!["mostro".to_string()]
528586
);
529587
}
588+
589+
// ── order_to_tags: end-to-end y-tag emission (kind 38383) ───────────────────
590+
591+
#[test]
592+
fn order_to_tags_emits_y_tag_with_mostro_as_first_value() {
593+
init_test_settings();
594+
let order = make_pending_order();
595+
596+
let tags = order_to_tags(&order, None)
597+
.expect("order_to_tags must not error")
598+
.expect("pending order must produce Some(tags)");
599+
600+
let y_values = get_y_tag_values(&tags).expect("order_to_tags must emit a y tag");
601+
602+
assert_eq!(y_values[0], "mostro", "y[0] must always be 'mostro'");
603+
}
604+
605+
#[test]
606+
fn order_to_tags_y_tag_matches_platform_helper_output() {
607+
init_test_settings();
608+
let order = make_pending_order();
609+
610+
let tags = order_to_tags(&order, None)
611+
.expect("order_to_tags must not error")
612+
.expect("pending order must produce Some(tags)");
613+
614+
let y_values = get_y_tag_values(&tags).expect("order_to_tags must emit a y tag");
615+
616+
let expected = create_platform_tag_values(test_settings().mostro.name.as_deref());
617+
assert_eq!(
618+
y_values, expected,
619+
"order_to_tags must wire create_platform_tag_values correctly into the y tag"
620+
);
621+
}
622+
623+
// ── info_to_tags: end-to-end y-tag emission (kind 38385) ────────────────────
624+
625+
#[test]
626+
fn info_to_tags_emits_y_tag_with_mostro_as_first_value() {
627+
init_test_settings();
628+
let ln_status = make_ln_status();
629+
630+
let tags = info_to_tags(&ln_status);
631+
632+
let y_values = get_y_tag_values(&tags).expect("info_to_tags must emit a y tag");
633+
634+
assert_eq!(y_values[0], "mostro", "y[0] must always be 'mostro'");
635+
}
636+
637+
#[test]
638+
fn info_to_tags_y_tag_matches_platform_helper_output() {
639+
init_test_settings();
640+
let ln_status = make_ln_status();
641+
642+
let tags = info_to_tags(&ln_status);
643+
644+
let y_values = get_y_tag_values(&tags).expect("info_to_tags must emit a y tag");
645+
646+
let expected = create_platform_tag_values(test_settings().mostro.name.as_deref());
647+
assert_eq!(
648+
y_values, expected,
649+
"info_to_tags must wire create_platform_tag_values correctly into the y tag"
650+
);
651+
}
652+
653+
// ── Dispute event tag list: end-to-end y-tag emission (kind 38386) ──────────
654+
655+
/// Verifies that the tag list built for dispute events emits the correct y tag.
656+
///
657+
/// Mirrors the exact inline tag construction used in `publish_dispute_event` and
658+
/// `close_dispute_after_user_resolution` in src/app/dispute.rs, as well as the
659+
/// admin handlers in admin_cancel.rs, admin_settle.rs, and admin_take_dispute.rs.
660+
/// All five callsites use the identical pattern verified here.
661+
#[test]
662+
fn dispute_event_tags_emit_y_tag_matching_platform_helper() {
663+
init_test_settings();
664+
665+
let tags = Tags::from_list(vec![
666+
Tag::custom(
667+
TagKind::Custom(Cow::Borrowed("s")),
668+
vec!["initiated-by-buyer".to_string()],
669+
),
670+
Tag::custom(
671+
TagKind::Custom(Cow::Borrowed("initiator")),
672+
vec!["buyer".to_string()],
673+
),
674+
Tag::custom(
675+
TagKind::Custom(Cow::Borrowed("y")),
676+
create_platform_tag_values(test_settings().mostro.name.as_deref()),
677+
),
678+
Tag::custom(
679+
TagKind::Custom(Cow::Borrowed("z")),
680+
vec!["dispute".to_string()],
681+
),
682+
]);
683+
684+
let y_values = get_y_tag_values(&tags)
685+
.expect("y tag must be present in dispute event tags (kind 38386)");
686+
687+
let expected = create_platform_tag_values(test_settings().mostro.name.as_deref());
688+
689+
assert_eq!(y_values[0], "mostro", "y[0] must always be 'mostro'");
690+
assert_eq!(
691+
y_values, expected,
692+
"dispute event tag list must wire create_platform_tag_values correctly"
693+
);
694+
}
695+
696+
// ── Dev-fee audit event tag list: end-to-end y-tag emission (kind 8383) ─────
697+
698+
/// Verifies that the tag list built for dev-fee audit events emits the correct y tag.
699+
///
700+
/// Mirrors the exact inline tag construction in `publish_dev_fee_audit_event`
701+
/// in src/util.rs (line ~602). This is a regression guard: if the y-tag call is
702+
/// accidentally removed from that function, this test will catch it.
703+
#[test]
704+
fn dev_fee_audit_event_tags_emit_y_tag_matching_platform_helper() {
705+
init_test_settings();
706+
707+
let tags = Tags::from_list(vec![
708+
Tag::custom(
709+
TagKind::Custom(Cow::Borrowed("order-id")),
710+
vec!["00000000-0000-0000-0000-000000000000".to_string()],
711+
),
712+
Tag::custom(
713+
TagKind::Custom(Cow::Borrowed("amount")),
714+
vec!["300".to_string()],
715+
),
716+
Tag::custom(
717+
TagKind::Custom(Cow::Borrowed("hash")),
718+
vec!["deadbeef".to_string()],
719+
),
720+
Tag::custom(
721+
TagKind::Custom(Cow::Borrowed("destination")),
722+
vec!["dev@lightning.address".to_string()],
723+
),
724+
Tag::custom(
725+
TagKind::Custom(Cow::Borrowed("network")),
726+
vec!["mainnet".to_string()],
727+
),
728+
Tag::custom(
729+
TagKind::Custom(Cow::Borrowed("y")),
730+
create_platform_tag_values(test_settings().mostro.name.as_deref()),
731+
),
732+
Tag::custom(
733+
TagKind::Custom(Cow::Borrowed("z")),
734+
vec!["dev-fee-payment".to_string()],
735+
),
736+
]);
737+
738+
let y_values = get_y_tag_values(&tags)
739+
.expect("y tag must be present in dev-fee audit event tags (kind 8383)");
740+
741+
let expected = create_platform_tag_values(test_settings().mostro.name.as_deref());
742+
743+
assert_eq!(y_values[0], "mostro", "y[0] must always be 'mostro'");
744+
assert_eq!(
745+
y_values, expected,
746+
"dev-fee audit event tag list must wire create_platform_tag_values correctly"
747+
);
748+
}
530749
}

0 commit comments

Comments
 (0)