mint_module_tests/
mint-module-tests.rs
1use anyhow::{Context as _, Result};
2use clap::Parser;
3use devimint::cmd;
4use devimint::federation::Federation;
5use fedimint_logging::LOG_DEVIMINT;
6use rand::Rng;
7use tracing::info;
8
9#[derive(Debug, Parser)]
10enum Cmd {
11 Restore,
12 Sanity,
13}
14
15#[tokio::main]
16async fn main() -> anyhow::Result<()> {
17 match Cmd::parse() {
18 Cmd::Restore => restore().await,
19 Cmd::Sanity => sanity().await,
20 }
21}
22
23async fn restore() -> anyhow::Result<()> {
24 devimint::run_devfed_test()
25 .call(|fed, _process_mgr| async move {
26 let fed = fed.fed().await?;
27
28 test_restore_gap_test(fed).await?;
29 Ok(())
30 })
31 .await
32}
33
34pub async fn test_restore_gap_test(fed: &Federation) -> Result<()> {
35 let client = fed.new_joined_client("restore-gap-test").await?;
36 const PEGIN_SATS: u64 = 300000;
37 fed.pegin_client(PEGIN_SATS, &client).await?;
38
39 for i in 0..20 {
40 let gap = rand::thread_rng().gen_range(0..20);
41 info!(target: LOG_DEVIMINT, gap, "Gap");
42 cmd!(
43 client,
44 "dev",
45 "advance-note-idx",
46 "--amount",
47 "1024msat",
48 "--count",
49 &gap.to_string()
53 )
54 .run()
55 .await?;
56
57 let reissure_amount_sats = if i % 2 == 0 {
58 PEGIN_SATS
60 } else {
61 rand::thread_rng().gen_range(10..PEGIN_SATS)
63 };
64 info!(target: LOG_DEVIMINT, i, reissure_amount_sats, "Reissue");
65
66 let notes = cmd!(client, "spend", reissure_amount_sats * 1000)
67 .out_json()
68 .await?
69 .get("notes")
70 .expect("Output didn't contain e-cash notes")
71 .as_str()
72 .unwrap()
73 .to_owned();
74
75 cmd!(client, "reissue", notes).out_json().await?;
77 }
78
79 let secret = cmd!(client, "print-secret").out_json().await?["secret"]
80 .as_str()
81 .map(ToOwned::to_owned)
82 .unwrap();
83
84 let pre_notes = cmd!(client, "info").out_json().await?;
85
86 let pre_balance = pre_notes["total_amount_msat"].as_u64().unwrap();
87
88 info!(target: LOG_DEVIMINT, %pre_notes, pre_balance, "State before backup");
89
90 assert!(0 < pre_balance);
92
93 {
95 let client =
96 devimint::federation::Client::create("restore-gap-test-without-backup").await?;
97 let _ = cmd!(
98 client,
99 "restore",
100 "--mnemonic",
101 &secret,
102 "--invite-code",
103 fed.invite_code()?
104 )
105 .out_json()
106 .await?;
107
108 let _ = cmd!(client, "dev", "wait-complete").out_json().await?;
109 let post_notes = cmd!(client, "info").out_json().await?;
110 let post_balance = post_notes["total_amount_msat"].as_u64().unwrap();
111 info!(target: LOG_DEVIMINT, %post_notes, post_balance, "State after backup");
112 assert_eq!(pre_balance, post_balance);
113 assert_eq!(pre_notes, post_notes);
114 }
115
116 Ok(())
117}
118
119async fn sanity() -> anyhow::Result<()> {
120 devimint::run_devfed_test()
121 .call(|fed, _process_mgr| async move {
122 let fed = fed.fed().await?;
123
124 test_note_consoliation(fed).await?;
125 Ok(())
126 })
127 .await
128}
129
130async fn test_note_consoliation(fed: &devimint::federation::Federation) -> anyhow::Result<()> {
137 let sender = fed.new_joined_client("sender").await?;
138 let receiver = fed.new_joined_client("receiver").await?;
139
140 let can_no_wait = cmd!(sender, "reissue", "--help")
141 .out_string()
142 .await?
143 .contains("no-wait");
144
145 if !can_no_wait {
146 info!("Version before `--no-wait` didn't have consolidation implemented");
147 return Ok(());
148 }
149 fed.pegin_client(10_000, &sender).await?;
150
151 let mut all_notes = vec![];
152 for i in 0..20 {
153 let info = cmd!(sender, "info").out_json().await?;
154 info!(%info, "sender info");
155 if i % 2 == 1 {
157 let notes = cmd!(sender, "spend", "1sat",).out_json().await?["notes"]
158 .as_str()
159 .context("invoice must be string")?
160 .to_owned();
161
162 cmd!(sender, "reissue", notes).run().await?;
163 }
164
165 let notes = cmd!(sender, "spend", "1msat",).out_json().await?["notes"]
166 .as_str()
167 .context("invoice must be string")?
168 .to_owned();
169
170 all_notes.push(notes);
171 }
172
173 for notes in &all_notes[..all_notes.len() - 1] {
174 cmd!(receiver, "reissue", "--no-wait", notes).run().await?;
175 }
176
177 cmd!(receiver, "dev", "wait-complete").run().await?;
179
180 cmd!(receiver, "reissue")
182 .args(&all_notes[all_notes.len() - 1..])
183 .run()
184 .await?;
185
186 let info = cmd!(receiver, "info").out_json().await?;
187 info!(%info, "receiver info");
188 assert_eq!(info["total_amount_msat"].as_i64().unwrap(), 20);
190 assert!(info["denominations_msat"]["1"].as_i64().unwrap() < 20);
192
193 Ok(())
194}