style: apply cargo fmt so the release gate can run

The release gate's first real stage is `cargo fmt --check`, and it had
44 diffs across 15 files — enough to abort `create-release.sh` at step 0
before it touched a version number. Some of that drift is mine from the
last two days, some predates it in files I never opened
(bootstrap.rs, ghost_reaper.rs, openwrt/router.rs), and one is the
regenerated fips/app_ports.rs.

No behaviour change — rustfmt only.

Gate now: 8 of 9 green. The remaining red is cargo-test-weekly exiting
124, which is the 25-minute `timeout` expiring during a cold
CARGO_INCREMENTAL=0 rebuild on a loaded node — the tests never started.
Not a test failure.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-19 12:38:41 -04:00
co-authored by Claude Opus 5
parent bd299318c0
commit c788dff42d
15 changed files with 164 additions and 110 deletions
+8 -2
View File
@@ -765,7 +765,10 @@ mod tests {
let short = "01fc0ec0e59cd6fa";
let full = "01fc0ec0e59cd6fa01b7a88f8cd77fce81fd1e64bca67d752e984992b7a3c3a821";
assert!(is_truncated_v2_keyset_id(short));
assert!(full.starts_with(short), "short form must prefix the full id");
assert!(
full.starts_with(short),
"short form must prefix the full id"
);
// It must survive token validation so the swap path can repair it,
// rather than being rejected as malformed.
assert!(validate_keyset_id(short).is_ok());
@@ -784,7 +787,10 @@ mod tests {
let err = validate_keyset_id("00112233445566778899")
.expect_err("9-byte keyset id must be rejected");
let msg = err.to_string();
assert!(msg.contains("10-byte") || msg.contains("unsupported keyset id"), "{msg}");
assert!(
msg.contains("10-byte") || msg.contains("unsupported keyset id"),
"{msg}"
);
// Non-hex ids (the original base64 keyset format) are named as such
// rather than reported as a length problem.
+17 -8
View File
@@ -397,9 +397,8 @@ pub async fn load_accepted_mints(data_dir: &Path) -> Result<AcceptedMints> {
mints: vec![network.default_mint()],
}
} else {
serde_json::from_str(&content).with_context(|| {
format!("Accepted-mints file {} is damaged", path.display())
})?
serde_json::from_str(&content)
.with_context(|| format!("Accepted-mints file {} is damaged", path.display()))?
};
Ok(mints)
}
@@ -1521,7 +1520,10 @@ pub async fn restore_from_seed(data_dir: &Path, mint_url: &str) -> Result<Restor
let mint_key = match keys.key_for_amount(sig.amount) {
Ok(k) => k,
Err(e) => {
warn!("Restored a {} sat output with no matching key: {e:#}", sig.amount);
warn!(
"Restored a {} sat output with no matching key: {e:#}",
sig.amount
);
continue;
}
};
@@ -2312,7 +2314,11 @@ mod tests {
// mint — never the real coins.
save_network(dir, EcashNetwork::Testnet).await.unwrap();
let test_wallet = load_wallet(dir).await.unwrap();
assert_eq!(test_wallet.balance(), 0, "test wallet must not see real coins");
assert_eq!(
test_wallet.balance(),
0,
"test wallet must not see real coins"
);
assert!(test_wallet.mint_url.contains("testnut"));
assert!(load_accepted_mints(dir).await.unwrap().mints[0].contains("testnut"));
@@ -2341,7 +2347,6 @@ mod tests {
assert_eq!(back.proofs[0].proof.secret, "real");
}
#[tokio::test]
async fn a_damaged_wallet_file_fails_loudly_and_is_left_on_disk() {
let tmp = TempDir::new().unwrap();
@@ -2355,7 +2360,9 @@ mod tests {
// It must NOT read as an empty wallet: that is what caused the real
// balance to be overwritten with nothing on the next save.
let err = load_wallet(dir).await.expect_err("damaged wallet must error");
let err = load_wallet(dir)
.await
.expect_err("damaged wallet must error");
assert!(
err.to_string().contains("damaged"),
"error should name the problem: {err}"
@@ -2372,7 +2379,9 @@ mod tests {
std::fs::create_dir_all(dir.join("wallet")).unwrap();
std::fs::write(dir.join("wallet/ecash.json"), " \n").unwrap();
// A create that never got its first write is not damage.
let w = load_wallet(dir).await.expect("empty file is a fresh wallet");
let w = load_wallet(dir)
.await
.expect("empty file is a fresh wallet");
assert_eq!(w.balance(), 0);
}
+8 -5
View File
@@ -191,7 +191,10 @@ impl MintClient {
&self,
keyset_id: &str,
amounts: &[u64],
) -> Result<(Vec<BlindedMessageRequest>, Vec<(Vec<u8>, secp256k1::SecretKey, u64)>)> {
) -> Result<(
Vec<BlindedMessageRequest>,
Vec<(Vec<u8>, secp256k1::SecretKey, u64)>,
)> {
let derived = match &self.recovery {
Some(source) => match source.next_outputs(keyset_id, amounts.len()).await {
Ok(pairs) => Some(pairs),
@@ -320,9 +323,7 @@ impl MintClient {
.filter(|k| !k.keys.is_empty() && k.unit.eq_ignore_ascii_case("sat"))
// Prefer a keyset the mint will still sign with.
.max_by_key(|k| k.active)
.ok_or_else(|| {
anyhow::anyhow!("No active sat keyset found at mint {}", self.url)
})
.ok_or_else(|| anyhow::anyhow!("No active sat keyset found at mint {}", self.url))
}
// ── Mint quotes (NUT-04) ──
@@ -510,7 +511,9 @@ impl MintClient {
"The mint's fee ({fee} sat) consumes this whole amount — nothing would be left"
);
}
debug!("Reducing swap outputs {requested} -> {spendable} to cover a {fee} sat mint fee");
debug!(
"Reducing swap outputs {requested} -> {spendable} to cover a {fee} sat mint fee"
);
owned_targets = amount_to_denominations(spendable);
&owned_targets
} else {
+39 -22
View File
@@ -280,12 +280,18 @@ pub async fn establish_independent(data_dir: &Path) -> Result<EcashSeed> {
/// dangerous choice if the imported phrase turned out to be the one already
/// in use.
pub async fn import_mnemonic(data_dir: &Path, words: &str, confirm: bool) -> Result<EcashSeed> {
let mnemonic: bip39::Mnemonic = words.split_whitespace().collect::<Vec<_>>().join(" ").parse()
.map_err(|e| anyhow::anyhow!(
"That is not a valid BIP-39 recovery phrase: {e}. Check for typos — \
let mnemonic: bip39::Mnemonic = words
.split_whitespace()
.collect::<Vec<_>>()
.join(" ")
.parse()
.map_err(|e| {
anyhow::anyhow!(
"That is not a valid BIP-39 recovery phrase: {e}. Check for typos — \
every word must come from the BIP-39 word list, and the phrase as \
a whole carries a checksum."
))?;
)
})?;
if let Some(existing) = load_seed(data_dir).await? {
if existing.mnemonic == mnemonic {
@@ -322,19 +328,18 @@ async fn archive_seed(data_dir: &Path) -> Result<()> {
}
let stamp = chrono::Utc::now().format("%Y%m%dT%H%M%SZ");
let to = data_dir.join(format!("wallet/cashu_seed.replaced-{stamp}.json"));
fs::rename(&from, &to)
.await
.with_context(|| format!("Could not archive the previous ecash phrase to {}", to.display()))?;
fs::rename(&from, &to).await.with_context(|| {
format!(
"Could not archive the previous ecash phrase to {}",
to.display()
)
})?;
warn!("Previous ecash phrase archived to {}", to.display());
Ok(())
}
/// Write the seed file at 0600, creating the wallet directory if needed.
async fn write_seed(
data_dir: &Path,
mnemonic: &bip39::Mnemonic,
source: SeedSource,
) -> Result<()> {
async fn write_seed(data_dir: &Path, mnemonic: &bip39::Mnemonic, source: SeedSource) -> Result<()> {
let path = seed_path(data_dir);
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)
@@ -596,8 +601,7 @@ mod tests {
// A *different* master seed must not replace the phrase the existing
// proofs were minted under.
let (other_words, _) = MasterSeed::generate().unwrap();
let (_, other_master) =
MasterSeed::from_mnemonic_words(&other_words.to_string()).unwrap();
let (_, other_master) = MasterSeed::from_mnemonic_words(&other_words.to_string()).unwrap();
let third = establish_from_master(d, &other_master).await.unwrap();
assert_eq!(
first.words(),
@@ -615,10 +619,9 @@ mod tests {
// Stand in for the other wallet: a known phrase and what it derives.
let theirs: bip39::Mnemonic = TEST_MNEMONIC.parse().unwrap();
let expected =
EcashSeed::from_mnemonic(theirs.clone(), SeedSource::Imported)
.derive_output(V1_KEYSET, 3)
.unwrap();
let expected = EcashSeed::from_mnemonic(theirs.clone(), SeedSource::Imported)
.derive_output(V1_KEYSET, 3)
.unwrap();
let imported = import_mnemonic(d, TEST_MNEMONIC, false).await.unwrap();
assert_eq!(imported.source(), SeedSource::Imported);
@@ -644,7 +647,10 @@ mod tests {
let err = import_mnemonic(d, &other.to_string(), false)
.await
.expect_err("must not replace without confirmation");
assert!(err.to_string().contains("already has a backup phrase"), "{err}");
assert!(
err.to_string().contains("already has a backup phrase"),
"{err}"
);
assert_eq!(
load_seed(d).await.unwrap().unwrap().words(),
original_words,
@@ -660,7 +666,11 @@ mod tests {
let archived: Vec<_> = std::fs::read_dir(d.join("wallet"))
.unwrap()
.filter_map(|e| e.ok())
.filter(|e| e.file_name().to_string_lossy().starts_with("cashu_seed.replaced-"))
.filter(|e| {
e.file_name()
.to_string_lossy()
.starts_with("cashu_seed.replaced-")
})
.collect();
assert_eq!(archived.len(), 1, "the replaced phrase must be kept");
}
@@ -677,7 +687,11 @@ mod tests {
let archived = std::fs::read_dir(d.join("wallet"))
.unwrap()
.filter_map(|e| e.ok())
.filter(|e| e.file_name().to_string_lossy().starts_with("cashu_seed.replaced-"))
.filter(|e| {
e.file_name()
.to_string_lossy()
.starts_with("cashu_seed.replaced-")
})
.count();
assert_eq!(archived, 0);
}
@@ -718,7 +732,10 @@ mod tests {
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mode = std::fs::metadata(seed_path(d)).unwrap().permissions().mode();
let mode = std::fs::metadata(seed_path(d))
.unwrap()
.permissions()
.mode();
assert_eq!(mode & 0o777, 0o600, "the ecash phrase must be owner-only");
}
}