Skip to content

feat: cashu boot + run_cashu + dispatch seam — Cashu foundation CF-5#828

Open
grunch wants to merge 2 commits into
mainfrom
feat/cashu-cf5-boot-integration
Open

feat: cashu boot + run_cashu + dispatch seam — Cashu foundation CF-5#828
grunch wants to merge 2 commits into
mainfrom
feat/cashu-cf5-boot-integration

Conversation

@grunch

@grunch grunch commented Jul 20, 2026

Copy link
Copy Markdown
Member

What & why

The integration PR of the Cashu escrow foundation (docs/cashu/01-fundamentals.md §6, CF-5) — the one sequential join point that makes a [cashu] enabled = true node boot and run with no Lightning node, connect its configured mint, and route events through a Cashu event loop where every trade action is rejected with CantDo(InvalidAction) (nothing is implemented yet). This is what proves the foundation works end-to-end while keeping it inert for real trades. The four feature tracks (Track A onward) fill in the blocked arms one at a time in their own files.

CF-0…CF-4 are already on main; this is the last foundation PR.

The prime directive (merge gate)

With Cashu disabled the daemon behaves exactly as main today.

Verified: the full suite passes unmodified (1023 tests), and the Lightning boot branch is left byte-for-byte unchanged.

Changes

  • main.rs — branch on Settings::is_cashu_enabled(). Cashu mode skips LndConnector::new() and the LN status probe entirely, connects the mint via CashuClient::connect (fail fast with exit(1) if unreachable, mirroring the LND-refusal behaviour), attaches the client to the context, and returns run_cashu(ctx). The spam-gate warm-up is extracted into a shared install_spam_gate() helper used by both paths; the Lightning branch is otherwise untouched.
  • app.rs — factor the transport/validation prologue and the post-dispatch error tail out of run() into accept_event / finalize_dispatch, shared VERBATIM by run (Lightning) and the new run_cashu (Cashu) so the two loops cannot drift. run_cashu differs from run in exactly one line: the dispatch call. Add dispatch_cashu with the closed allow-list from §6.
  • app/add_cashu_escrow.rs (new) — stub add_cashu_escrow_action returning InvalidAction; Track A (TA-1) fills the body in this same file, so it touches no shared file (the G-1 fix).
  • app/context.rsAppContext carries Option<Arc<CashuClient>> with a with_cashu_client setter and a cashu_client() accessor (None in Lightning mode). See design note below.
  • scheduler.rs — gate the LN-only jobs (cancel-orders, retry-payments, dev-fee, bond payouts, stranded-bond reconcile) behind !is_cashu_enabled() so they never call LndConnector::new() on a node with no LND; make job_info_event_send self-skip when LN_STATUS is absent instead of panicking.

dispatch_cashu routing (§6 closed decision)

Action Routing in CF-5
Orders, LastTradeIndex, RestoreSession, TradePubkey handle_message_action_no_ln (read-only / session; never touch escrow, LND, or order lifecycle)
AddCashuEscrow add_cashu_escrow_action (TA-1 stub → InvalidAction for now)
everything else CantDo(InvalidAction)

Design note — escrow field deferred

The spec sketches an escrow: Arc<dyn EscrowBackend> on AppContext. It is deferred: run() still threads &mut LndConnector, and an Arc<dyn EscrowBackend> cannot yield the &mut those hold-invoice calls need, so adding it now would be unused dead weight. Only cashu_client (which Track A actually consumes via ctx.cashu_client()) is added. The escrow field lands when Track B's cashu release path needs it. This keeps CF-5 additive and behaviour-preserving.

Tests

  • dispatch_cashu blocks every order-lifecycle action (NewOrder, takes, FiatSent, AddInvoice, Release, Cancel, Dispute, RateUser, AddCashuEscrow, admin actions, AddBondInvoice) with InvalidAction.
  • dispatch_cashu routes RestoreSession through the no-LN handler (returns Ok), proving the allow-list is not short-circuited.
  • The CF-5 stub add_cashu_escrow_action returns InvalidAction without panicking.

Checklist

  • cargo fmt --check
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo test — 1023 passed, existing suite unmodified
  • Off-by-default & behaviour-preserving (Cashu disabled ⇒ identical to main)

Refs: docs/cashu/01-fundamentals.md (CF-5). Foundation is complete once this merges; Track A follows.

Summary by CodeRabbit

  • New Features

    • Added Cashu “escrow mode” startup with Cashu mint connectivity.
    • Added Cashu-mode routing and context support for an optional Cashu client.
  • Bug Fixes

    • Prevented Lightning-only background tasks and LND-dependent scheduler work from running in Cashu mode.
    • Improved event acceptance/validation flow with anti-spam gating, replay protection, and stale-event filtering.
    • Centralized post-dispatch error handling for more consistent behavior.
  • Tests

    • Added tests for Cashu-mode dispatch behavior and unsupported operations.

🧪 Manual testing — step by step

Prereqs: a mostrod dev setup + the throwaway Cashu test mint. Start the mint:

docker compose -f docker-compose.cashu.yml up -d   # nutshell on http://127.0.0.1:3338

Enable Cashu mode in settings.toml (LND is not required in this mode):

[cashu]
enabled = true
mint_url = "http://127.0.0.1:3338"
escrow_locktime_days = 15

Run with RUST_LOG=mostro=info (or =debug) to see the log lines below.

1. Boots in Cashu mode with NO Lightning node

  1. Start mostrod with the config above (no LND running).
  2. Expected: it does not attempt LndConnector::new(), and logs:
    Starting in Cashu escrow mode — connecting mint http://127.0.0.1:3338 (LND not initialised)
    
    then Scheduler Started and the event loop runs. ✔️
  3. Fail-fast: stop the mint (docker compose -f docker-compose.cashu.yml down) and restart mostrod. Expected — refuses to boot (mirrors LND-refusal):
    No connection to Cashu mint http://127.0.0.1:3338 - shutting down Mostro! (...)
    
    process exits. ✔️

2. Every trade action is rejected with InvalidAction

  1. With the mint up and mostrod in Cashu mode, from any client send a trade action — NewOrder, TakeSell, TakeBuy, AddInvoice, FiatSent, Release, Cancel, Dispute, AddCashuEscrow, AdminCancel, AdminSettle.
  2. Expected: each is answered with CantDo(InvalidAction) — no panic, no order created/advanced. ✔️
  3. Read-only / session actions still work: Orders, RestoreSession, TradePubkey, LastTradeIndex respond normally (the node still serves the book and restores sessions). ✔️

3. Scheduler skips Lightning-only jobs

  1. Watch the startup logs. Expected: the LN-only jobs (cancel-orders, retry-payments, dev-fee, bond payouts, stranded-bond reconcile) are not spawned, and the info-event job self-skips:
    Skipping mostro info event: no LN status (Cashu mode)
    
    Mode-agnostic jobs (order expiry, rate publishing, relay list, price, message flush, spam-gate refresh) still run. ✔️

4. RPC warns instead of silently skipping

  1. Set [rpc] enabled = true alongside [cashu] enabled = true and start mostrod.
  2. Expected: the admin gRPC server is not started, and a warning makes that visible:
    [rpc].enabled = true but the admin gRPC server is NOT started in Cashu mode: ...
    
    ✔️

5. Bonds ⊕ Cashu are mutually exclusive

  1. Set both [cashu] enabled = true and [anti_abuse_bond] enabled = true.
  2. Expected: mostrod refuses to start with a config-validation error (CF-1). ✔️

6. Lightning regression — nothing changes when Cashu is off

  1. Set [cashu] enabled = false (or remove the block) and run a normal LND-backed node.
  2. Expected: behaviour is byte-for-byte identical to before this PR — the Cashu branch is never taken. ✔️

The integration PR of the Cashu foundation (docs/cashu/01-fundamentals.md §6).
A node with `[cashu] enabled = true` now boots with NO Lightning node,
connects its configured mint, and runs a Cashu event loop in which every
trade action is rejected with `CantDo(InvalidAction)` — the feature tracks
replace those arms one at a time. With Cashu disabled the daemon is
behaviourally identical to `main`.

- `main.rs`: branch on `Settings::is_cashu_enabled()`. Cashu mode skips
  `LndConnector::new()` and the LN status probe, connects the mint via
  `CashuClient::connect` (exit(1) if unreachable, mirroring LND-refusal),
  attaches it to the context, and returns `run_cashu(ctx)`. The spam-gate
  warm-up is extracted into `install_spam_gate()` and shared by both paths;
  the Lightning branch is otherwise unchanged.
- `app.rs`: factor the transport/validation prologue and the post-dispatch
  error tail out of `run()` into `accept_event` / `finalize_dispatch`, shared
  VERBATIM by `run` and the new `run_cashu` so the two loops cannot drift.
  Add `dispatch_cashu` with the closed allow-list (`Orders`,
  `LastTradeIndex`, `RestoreSession`, `TradePubkey` → `handle_message_action_no_ln`;
  `AddCashuEscrow` → the TA-1 stub; everything else → `InvalidAction`).
- `app/add_cashu_escrow.rs` (new): stub `add_cashu_escrow_action` returning
  `InvalidAction`; Track A fills the body in its own file (G-1).
- `app/context.rs`: `AppContext` carries `Option<Arc<CashuClient>>` with a
  `with_cashu_client` setter and `cashu_client()` accessor (`None` in
  Lightning mode). The `escrow: Arc<dyn EscrowBackend>` field the spec
  sketches is deferred: `run()` still threads `&mut LndConnector` and an
  unused `Arc<dyn EscrowBackend>` would be dead weight — added when Track B
  needs it.
- `scheduler.rs`: gate the LN-only jobs (cancel-orders, retry-payments,
  dev-fee, bond payouts, stranded-bond reconcile) behind
  `!is_cashu_enabled()` so they never call `LndConnector::new()` on a node
  with no LND; make `job_info_event_send` self-skip when `LN_STATUS` is
  absent instead of panicking.

Tests: `dispatch_cashu` blocks every order-lifecycle action with
`InvalidAction` and routes the allow-list through the no-LN handler; the
CF-5 stub returns `InvalidAction`. Full suite green (1023) with Cashu off.

Refs: docs/cashu/01-fundamentals.md (CF-5)
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds Cashu escrow-mode startup with a mint client, dedicated event routing, shared event validation, Cashu-specific scheduling behavior, and an AddCashuEscrow foundation stub that currently rejects submissions.

Changes

Cashu escrow mode

Layer / File(s) Summary
Cashu context and escrow handler
src/app/context.rs, src/app/add_cashu_escrow.rs
AppContext optionally stores a CashuClient; the new handler returns InvalidAction and is covered by a unit test.
Cashu runtime bootstrap
src/main.rs
Cashu mode connects to the mint, installs the shared spam gate, creates the context, starts the scheduler, and runs run_cashu.
Shared event validation and Cashu dispatch
src/app.rs
Event validation and dispatch error handling are shared by both relay loops; Cashu routing recognizes AddCashuEscrow and tests permitted and rejected actions.
Mode-specific scheduler behavior
src/scheduler.rs
Lightning-only jobs and bond operations are skipped in Cashu mode, and info-event sending returns safely when LN_STATUS is unavailable.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Main
  participant CashuMint
  participant AppContext
  participant Scheduler
  participant CashuLoop
  Main->>CashuMint: connect to configured mint
  Main->>AppContext: attach CashuClient
  Main->>Scheduler: start mode-aware jobs
  Main->>CashuLoop: run Cashu event loop
Loading

Possibly related PRs

Suggested reviewers: arkanoider

Poem

I’m a rabbit with minty paws,
Routing escrow without applause.
Events are checked in a tidy queue,
Lightning jobs know when to shoo.
The stub says “not yet”—what a view!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is clearly related to the Cashu boot path, run_cashu flow, and dispatch changes in this PR.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cashu-cf5-boot-integration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 07936897cd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/scheduler.rs
info!("Creating scheduler");

// Mode-agnostic jobs run in both Lightning and Cashu mode.
job_expire_pending_older_orders(ctx.clone()).await;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Gate bond expiry in Cashu mode

When Cashu mode is enabled but the database still contains an expired waiting-maker-bond or pending order with active bond rows (for example after an operator switches modes or reuses an existing DB), this unconditionally spawned expiry job still runs the bond cleanup paths in job_expire_pending_older_orders. Those paths persist the order as Expired and then call the release_*_bonds... helpers, which open LndConnector::new(); because the Cashu boot path deliberately has no LND, release fails after the order leaves the statuses selected by find_order_by_date, so the bond is not retried by this job. Either gate the bond-related expiry paths in Cashu mode or avoid terminalizing those orders when no LND is available.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in b8116e3. Gated all three bond-release calls in job_expire_pending_older_orders (WaitingMakerBond, taker-bond, range maker bond) behind !Settings::is_cashu_enabled(), so a cashu node never opens LndConnector::new() here. The order still expires; the bond release is skipped (bonds are mutually exclusive with Cashu per CF-1, so this only guards a reused/mode-switched DB).

Comment thread src/main.rs
start_scheduler(ctx.clone()).await;

// Run the Mostro Cashu event loop and be happy!!
return run_cashu(ctx).await;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not silently skip RPC in Cashu mode

With both [cashu].enabled = true and [rpc].enabled = true, this early return bypasses the existing RpcServer::is_enabled() startup block, so the configured admin gRPC listener never starts and there is no validation error or warning. Some exposed RPCs such as version/password validation and solver management do not require Lightning, so operators that enable RPC lose that API only in Cashu mode. If RPC is unsupported for Cashu, reject or warn on that config; otherwise start the compatible subset without constructing an LND client.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in b8116e3. The Cashu boot branch now warns when [rpc].enabled = true instead of silently skipping the admin gRPC server. Starting the LN-independent RPC subset in Cashu mode is left as a follow-up: RpcServer::start currently requires an Arc<Mutex<LndConnector>>, so serving the compatible subset needs a signature change that is out of scope for this foundation PR.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/main.rs (1)

180-202: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consolidate shared initialization before the Cashu block.

The initialization of AppContext and the call to install_spam_gate().await are exactly duplicated in the Lightning path further down the file (lines 245-263). Since neither of these setups relies on LndConnector or any branch-specific logic, you can hoist them above the Settings::is_cashu_enabled() check to keep the code DRY.

♻️ Proposed refactor
+    // Install the protocol-v2 anti-spam gate and warm its active-trade-pubkey
+    // cache before the event loop starts (mode-agnostic).
+    install_spam_gate().await;
+
+    // Build AppContext explicitly with all dependencies
+    let settings = Arc::new(
+        MOSTRO_CONFIG
+            .get()
+            .expect("MOSTRO_CONFIG not initialized")
+            .clone(),
+    );
+    let ctx = AppContext::new(
+        get_db_pool(),
+        client.clone(),
+        settings,
+        MESSAGE_QUEUES.queue_order_msg.clone(),
+        mostro_keys.clone(),
+    );
+
     if Settings::is_cashu_enabled() {
         // `mint_url` non-emptiness + scheme were validated at config load
         // (CF-1); this expect is unreachable for a validated config.
         let mint_url = Settings::get_cashu()
             .map(|c| c.mint_url.clone())
             .expect("cashu enabled but [cashu] settings missing after validation");
         tracing::info!(
             "Starting in Cashu escrow mode — connecting mint {mint_url} (LND not initialised)"
         );
         let cashu_client = match cashu::CashuClient::connect(&mint_url).await {
             Ok(client) => Arc::new(client),
             Err(e) => {
                 tracing::error!(
                     "No connection to Cashu mint {mint_url} - shutting down Mostro! ({e})"
                 );
                 exit(1);
             }
         };
 
-        // Warm the anti-spam gate exactly as the Lightning path does.
-        install_spam_gate().await;
-
-        let settings = Arc::new(
-            MOSTRO_CONFIG
-                .get()
-                .expect("MOSTRO_CONFIG not initialized")
-                .clone(),
-        );
-        let ctx = AppContext::new(
-            get_db_pool(),
-            client.clone(),
-            settings,
-            MESSAGE_QUEUES.queue_order_msg.clone(),
-            mostro_keys.clone(),
-        )
-        .with_cashu_client(cashu_client);
+        let cashu_ctx = ctx.with_cashu_client(cashu_client);
 
-        start_scheduler(ctx.clone()).await;
+        start_scheduler(cashu_ctx.clone()).await;
 
         // Run the Mostro Cashu event loop and be happy!!
-        return run_cashu(ctx).await;
+        return run_cashu(cashu_ctx).await;
     }

(You can then safely remove the duplicated install_spam_gate().await and AppContext building blocks currently at lines 245-263).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main.rs` around lines 180 - 202, Move the shared
install_spam_gate().await call and AppContext construction out of the
Cashu-specific branch and place them before the Settings::is_cashu_enabled()
check. Preserve the existing AppContext inputs and retain branch-specific setup
only where required, then remove the duplicated initialization from the Cashu
and Lightning paths while keeping each branch’s scheduler and event-loop
behavior unchanged.
src/app.rs (1)

1094-1111: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extend Cashu allow-list test coverage beyond RestoreSession.

allows_restore_session_through_no_ln_router only proves RestoreSession reaches the no-LN handler. dispatch_cashu's allow-list also includes Orders, LastTradeIndex, and TradePubkey (Line 561); none of those are asserted here, so a future edit that accidentally drops one of them from the match arm wouldn't be caught by this test.

✅ Suggested test extension
         #[tokio::test]
         async fn allows_restore_session_through_no_ln_router() {
             let ctx = create_ctx().await;
             let my_keys = create_test_keys();
             let event = create_test_unwrapped_message();
             let msg = Message::new_restore(None);

             let result = dispatch_cashu(&Action::RestoreSession, msg, &event, &my_keys, &ctx).await;
             assert!(
                 result.is_ok(),
                 "RestoreSession must route to the no-LN handler, got {result:?}"
             );
         }
+
+        #[tokio::test]
+        async fn allows_orders_last_trade_index_and_trade_pubkey_through_no_ln_router() {
+            let ctx = create_ctx().await;
+            let my_keys = create_test_keys();
+            let event = create_test_unwrapped_message();
+
+            for action in [Action::Orders, Action::LastTradeIndex, Action::TradePubkey] {
+                let msg = create_test_message(action.clone(), None);
+                let result = dispatch_cashu(&action, msg, &event, &my_keys, &ctx).await;
+                assert!(
+                    !is_invalid_action(result),
+                    "{action:?} must not be blocked with InvalidAction in Cashu mode"
+                );
+            }
+        }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app.rs` around lines 1094 - 1111, Extend the Cashu allow-list coverage
around dispatch_cashu and allows_restore_session_through_no_ln_router by adding
equivalent assertions for Orders, LastTradeIndex, and TradePubkey. Construct
suitable messages for each action, dispatch them through the no-LN path, and
assert each result is Ok so removal from the allow-list is detected.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app.rs`:
- Around line 396-402: The trade-index mutation currently runs before Cashu
dispatch can reject unsupported actions. In the message handling flow around
check_trade_index and dispatch_cashu, ensure check_trade_index executes only
after dispatchability is confirmed, or bypass it for NewOrder, TakeBuy, and
TakeSell actions that Cashu always blocks, so rejected probes cannot persist or
advance trade state.

---

Nitpick comments:
In `@src/app.rs`:
- Around line 1094-1111: Extend the Cashu allow-list coverage around
dispatch_cashu and allows_restore_session_through_no_ln_router by adding
equivalent assertions for Orders, LastTradeIndex, and TradePubkey. Construct
suitable messages for each action, dispatch them through the no-LN path, and
assert each result is Ok so removal from the allow-list is detected.

In `@src/main.rs`:
- Around line 180-202: Move the shared install_spam_gate().await call and
AppContext construction out of the Cashu-specific branch and place them before
the Settings::is_cashu_enabled() check. Preserve the existing AppContext inputs
and retain branch-specific setup only where required, then remove the duplicated
initialization from the Cashu and Lightning paths while keeping each branch’s
scheduler and event-loop behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 49b7eccb-9154-4e4a-b27a-d8ec72797905

📥 Commits

Reviewing files that changed from the base of the PR and between 57b8ff5 and 0793689.

📒 Files selected for processing (5)
  • src/app.rs
  • src/app/add_cashu_escrow.rs
  • src/app/context.rs
  • src/main.rs
  • src/scheduler.rs

Comment thread src/app.rs
…ashu mode

Two review findings from PR #828:

- Bond-expiry paths in `job_expire_pending_older_orders` open
  `LndConnector::new()` via the bond-release helpers. Cashu mode has no LND,
  so gate all three release calls (WaitingMakerBond, taker-bond, range maker
  bond) behind `!Settings::is_cashu_enabled()`. Bonds are mutually exclusive
  with Cashu (CF-1), so a cashu node carries no bond rows by construction; this
  only matters defensively for a reused/mode-switched DB, where the order still
  expires but no doomed LND connection is attempted.
- The Cashu boot branch early-returns before the RPC startup block, silently
  skipping the admin gRPC server. Warn when `[rpc].enabled = true` in Cashu
  mode so the missing API is visible instead of a surprise (the LN-independent
  RPC subset is a follow-up — the server currently requires an LND client).

Skipped (with reasons posted on the PR): the `check_trade_index`-before-dispatch
note (pre-existing shared-prologue behaviour, identical to the Lightning loop;
the actions become valid in TA-2 where the check belongs) and the boot-init DRY
hoist (it reorders the Lightning boot, violating the byte-identical guarantee).

cargo fmt + clippy -D warnings + full suite (1023) green.
@grunch

grunch commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

Review addressed — b8116e3

Fixed (both Codex P2):

  • Bond expiry in Cashu mode — gated the three bond-release calls in job_expire_pending_older_orders behind !Settings::is_cashu_enabled(), so no doomed LndConnector::new() on a cashu node.
  • Silent RPC skip — the Cashu boot branch now warns when [rpc].enabled = true (the LN-independent RPC subset is a scoped follow-up; RpcServer::start currently requires an LND client).

Skipped, with reasons:

  • check_trade_index before dispatch (CodeRabbit) — pre-existing shared-prologue behaviour, identical to the Lightning loop; the actions become valid in TA-2 where the check belongs. Special-casing CF-5 would diverge the two loops (the zero-drift design) and be reverted in TA-2. (See inline reply.)
  • DRY: hoist AppContext/spam-gate init before the branch (CodeRabbit nitpick) — the suggested hoist moves the Lightning install_spam_gate() from after the RPC/LND setup to before it, reordering the Lightning boot path. The milestone prime directive is that Lightning behaviour stays byte-identical, so I kept the boot ordering intact; the duplication is boot-only and small.

cargo fmt + clippy -D warnings + full suite (1023) green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant