mirror of
https://github.com/Such-Software/smirk-backend-core.git
synced 2026-11-12 19:23:55 +01:00
feat(tips): stage 5 — GC workers + fail-closed flag + capabilities + openapi
- GC: cancel_old_drafts (draft >7d -> cancelled), cancel_stuck_pending_confirmation (>7d), log_stuck_claiming (read-only, >15min). Draft GC hourly + lifecycle GC 5min, spawned behind FEATURE_TIPS. Funded-but-unattached safety net is the 7-day window + clawback incl 'cancelled'. - config validate(): tips enabled fails closed unless a supported chain (btc/ltc/xmr/wow) is on AND tip_share_base is set. - capabilities: advertise tips=true only when actually serveable. - regenerated openapi.json (8 /tips/social/* endpoints). Public-tips port COMPLETE (stages 1-5). Full suite green.
This commit is contained in:
@@ -1102,6 +1102,27 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
// Public tips escrow on-chain and deliver by share URL, so an instance
|
||||
// with FEATURE_TIPS on but no chain to escrow on, or no TIP_SHARE_BASE_URL
|
||||
// to build share links from, would advertise a tips subsystem it cannot
|
||||
// actually serve. Fail closed rather than boot broken. (Grin is out of the
|
||||
// tips port, so it is NOT a supported tip chain here.)
|
||||
if self.features.tips {
|
||||
let c = &self.features.chains;
|
||||
if !(c.btc || c.ltc || c.xmr || c.wow) {
|
||||
return Err(cfg_err(
|
||||
"FEATURE_TIPS is on but no supported tip chain is enabled — enable at least \
|
||||
one of FEATURE_BTC / FEATURE_LTC / FEATURE_XMR / FEATURE_WOW",
|
||||
));
|
||||
}
|
||||
if self.tip_share_base.is_none() {
|
||||
return Err(cfg_err(
|
||||
"FEATURE_TIPS is on but TIP_SHARE_BASE_URL is unset — it is required to build \
|
||||
public tip share links",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Pay-to-register gate: when on, the processor wiring must be complete
|
||||
// and sane, or /capabilities would advertise payment_required while every
|
||||
// registration then fails. Fail closed at startup instead.
|
||||
@@ -1561,6 +1582,38 @@ mod tests {
|
||||
assert!(c.validate().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tips_enabled_requires_share_base() {
|
||||
// FEATURE_TIPS on + a tip chain but NO share base → fail closed.
|
||||
let mut c = valid();
|
||||
c.features.tips = true;
|
||||
c.features.chains.btc = true;
|
||||
c.tip_share_base = None;
|
||||
assert!(c.validate().is_err(), "tips on without a share base must fail");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tips_enabled_requires_a_tip_chain() {
|
||||
// FEATURE_TIPS on + a share base but NO tip chain enabled → fail closed.
|
||||
// (valid() has all chains off.)
|
||||
let mut c = valid();
|
||||
c.features.tips = true;
|
||||
c.tip_share_base = Some("https://tips.example".into());
|
||||
assert!(c.validate().is_err(), "tips on with no tip chain must fail");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tips_enabled_with_chain_and_share_base_ok() {
|
||||
let mut c = valid();
|
||||
c.features.tips = true;
|
||||
c.features.chains.btc = true;
|
||||
c.tip_share_base = Some("https://tips.example".into());
|
||||
assert!(
|
||||
c.validate().is_ok(),
|
||||
"tips on with a tip chain + share base is valid"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsupported_price_provider_rejected() {
|
||||
let mut c = valid();
|
||||
|
||||
Reference in New Issue
Block a user