Electrum-ABC-style continuous client driver (runFuseLoop,
ContinuousClient, FUSE_LOOP delays) so long-lived participants can rejoin
after fused/idle/failed outcomes. DEPLOY.md documents the warm-pool ops
target and honestly lists what is still missing (TCP, Chronik, signing, Tor).
No network or wallet wiring in this slice.
Details
- Reviewers
Fabien - Group Reviewers
Restricted Project - Commits
- rABC8a8d1172d98c: [alp-fusion] Add continuous fuse loop and deploy notes
- cd apps/alp-fusion && pnpm test
- Read apps/alp-fusion/DEPLOY.md; confirm continuous loop delays and in-tree vs not-yet table match the code
Diff Detail
- Repository
- rABC Bitcoin ABC
- Lint
Lint Not Applicable - Unit
Tests Not Applicable
Event Timeline
Build Bitcoin ABC Diffs / Diff Testing (ai-review) passed.
CodeRabbit Review
Diff : committed changes only
Compare : HEAD → master
Directory : work
────────────────────────────────────────
(\(\
(• .•) Gently exceed your users' expectations. Come to understand your users' expectations, then deliver just that little bit more.
────────────────────────────────────────────────────────────────────────
minor [Performance & Scalability]
→ ]8;;vscode://file//work/apps/alp-fusion/src/client/fuseLoop.ts:74apps/alp-fusion/src/client/fuseLoop.ts:74-78]8;;
Reject invalid delay overrides.
A negative delay skips sleep at Line 93. A non-finite delay also does
not provide a reliable pause. A configuration error can create an
unthrottled rejoin loop and high CPU use.
Validate that each override is finite and non-negative. Keep 0 valid if
immediate rejoin is intentional. Add tests for negative and non-finite
values.
Proposed delay validation
export async function runFuseLoop(opts: RunFuseLoopOptions): Promise<void> {
const sleep = opts.sleep ?? defaultSleep;
+ const resolveDelay = (value: number | undefined, fallback: number): number => {
+ const delayMs = value ?? fallback;
+ if (!Number.isFinite(delayMs) || delayMs < 0) {
+ throw new RangeError('Fuse loop delays must be finite and non-negative');
+ }
+ return delayMs;
+ };
const delays = {
- successDelayMs: opts.successDelayMs ?? FUSE_LOOP.successDelayMs,
- failureDelayMs: opts.failureDelayMs ?? FUSE_LOOP.failureDelayMs,
- idleDelayMs: opts.idleDelayMs ?? FUSE_LOOP.idleDelayMs,
+ successDelayMs: resolveDelay(opts.successDelayMs, FUSE_LOOP.successDelayMs),
+ failureDelayMs: resolveDelay(opts.failureDelayMs, FUSE_LOOP.failureDelayMs),
+ idleDelayMs: resolveDelay(opts.idleDelayMs, FUSE_LOOP.idleDelayMs),
};────────────────────────────────────────────────────────────────────────
major [Stability & Availability]
→ ]8;;vscode://file//work/apps/alp-fusion/src/client/continuous.ts:48apps/alp-fusion/src/client/continuous.ts:48-64]8;;
Prevent overlapping run() calls.
If code calls run() again before the first call completes, Line 50
replaces the first controller. stop() then aborts only the newest loop.
The first loop can remain asleep for its full delay. Its finally block
can also clear the newer controller.
Reject a second call while a loop is active, or track each active
controller. Clear stopAbort only when it still belongs to this
invocation. Add a regression test that starts two loops and calls
stop().
Proposed lifecycle guard
async run(runOnce: () => Promise<FuseLoopOutcome>): Promise<void> {
+ if (this.stopAbort !== null) {
+ throw new Error('ContinuousClient is already running');
+ }
this.stopped = false;
- this.stopAbort = new AbortController();
+ const stopAbort = new AbortController();
+ this.stopAbort = stopAbort;
try {
await runFuseLoop({
shouldStop: () => this.stopped,
- abortSignal: this.stopAbort.signal,
+ abortSignal: stopAbort.signal,
runOnce,
sleep: this.opts.sleep,
successDelayMs: this.opts.successDelayMs,
failureDelayMs: this.opts.failureDelayMs,
idleDelayMs: this.opts.idleDelayMs,
onIteration: this.opts.onIteration,
});
} finally {
- this.stopAbort = null;
+ if (this.stopAbort === stopAbort) {
+ this.stopAbort = null;
+ }
}
}────────────────────────────────────────
Review complete
2 findings ✔
Major 1
Minor 1
6 files reviewed:
- apps/alp-fusion/DEPLOY.md
- apps/alp-fusion/README.md
- apps/alp-fusion/src/client/continuous.ts
- apps/alp-fusion/src/client/fuseLoop.ts
- apps/alp-fusion/src/protocol/constants.ts
- apps/alp-fusion/test/client/fuseLoop.test.ts
────────────────────────────────────────
Print all AI prompts: coderabbit review --show-prompts
Address CodeRabbit: reject overlapping ContinuousClient.run() so stop() cannot orphan the first loop's AbortController; skip negative-delay validation (defaults/callers are non-negative).
Tail of the build log:
/work /work/abc-ci-builds/ai-review Connecting to CodeRabbit... 0s elapsed Preparing review... 1s elapsed ✗ Review limit reached Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. You're only billed for reviews past your plan's rate limits ($0.25/file). You can wait 5 minutes for the limit to reset. https://app.coderabbit.ai/settings/billing?tab=usage&orgId=79839cd4-7849-4bd5-8d6d-5ecaf453356e Build ai-review failed with exit code 1
Build Bitcoin ABC Diffs / Diff Testing (ai-review) passed.
CodeRabbit Review
Diff : committed changes only
Compare : HEAD → master
Directory : work
────────────────────────────────────────
(\(\
(• .•) This is the beginning of a beautiful friendship...between you and bug-free code.
────────────────────────────────────────────────────────────────────────
major [Security & Privacy] → ]8;;vscode://file//work/apps/alp-fusion/DEPLOY.md:64apps/alp-fusion/DEPLOY.md:64-68]8;; Require TLS for public coordinators. Line 66 makes TLS optional on public hosts. This conflicts with the public-coordinator target in README.md. Require TLS for every public listener. Limit plaintext TCP to isolated local correctness labs. Proposed fix -1. **One coordinator** bound on `0.0.0.0:8788` (optional TLS for public hosts). +1. **One coordinator** bound with mandatory TLS on public networks. Use + plaintext TCP only in isolated local correctness labs.
────────────────────────────────────────
Review complete
1 finding ✔
Major 1
6 files reviewed:
- apps/alp-fusion/DEPLOY.md
- apps/alp-fusion/README.md
- apps/alp-fusion/src/client/continuous.ts
- apps/alp-fusion/src/client/fuseLoop.ts
- apps/alp-fusion/src/protocol/constants.ts
- apps/alp-fusion/test/client/fuseLoop.test.ts
────────────────────────────────────────
Print all AI prompts: coderabbit review --show-prompts
| apps/alp-fusion/DEPLOY.md | ||
|---|---|---|
| 7–8 ↗ | (On Diff #60795) | don't tell what it doesn't do |
| 16 ↗ | (On Diff #60795) | OK I suppose it's fine here as a roadmap/current limitations doc |
| 26 ↗ | (On Diff #60795) | |
| 80 ↗ | (On Diff #60795) | |
| apps/alp-fusion/src/client/fuseLoop.ts | ||
| 50 ↗ | (On Diff #60795) | This seems useless and would better be inlined |
| apps/alp-fusion/test/client/fuseLoop.test.ts | ||
| 15 ↗ | (On Diff #60795) | same for the test |
| apps/alp-fusion/DEPLOY.md | ||
|---|---|---|
| 79 ↗ | (On Diff #60816) | This one still holds, should be >= |
Build Bitcoin ABC Diffs / Diff Testing (ai-review) passed.
CodeRabbit Review
Diff : committed changes only
Compare : HEAD → master
Directory : work
────────────────────────────────────────
(\(\
(• .•) Time zones: the final boss of software.
────────────────────────────────────────────────────────────────────────
major [Stability & Availability]
→ ]8;;vscode://file//work/apps/alp-fusion/src/client/fuseLoop.ts:55apps/alp-fusion/src/client/fuseLoop.ts:55-59]8;;
Validate delay overrides before the loop starts.
Negative values and NaN bypass the sleep at line 85. If runOnce fails
immediately, the loop then retries in a tight loop until stopped. Reject
non-finite and negative delay values. Keep 0 as an explicit no-delay
value.
Proposed validation
+function validateDelay(delayMs: number, name: string): number {
+ if (!Number.isFinite(delayMs) || delayMs < 0) {
+ throw new RangeError(`${name} must be a finite non-negative number`);
+ }
+ return delayMs;
+}
+
export async function runFuseLoop(opts: RunFuseLoopOptions): Promise<void> {
const sleep = opts.sleep ?? defaultSleep;
const delays = {
- successDelayMs: opts.successDelayMs ?? FUSE_LOOP.successDelayMs,
- failureDelayMs: opts.failureDelayMs ?? FUSE_LOOP.failureDelayMs,
- idleDelayMs: opts.idleDelayMs ?? FUSE_LOOP.idleDelayMs,
+ successDelayMs: validateDelay(
+ opts.successDelayMs ?? FUSE_LOOP.successDelayMs,
+ 'successDelayMs',
+ ),
+ failureDelayMs: validateDelay(
+ opts.failureDelayMs ?? FUSE_LOOP.failureDelayMs,
+ 'failureDelayMs',
+ ),
+ idleDelayMs: validateDelay(
+ opts.idleDelayMs ?? FUSE_LOOP.idleDelayMs,
+ 'idleDelayMs',
+ ),
};────────────────────────────────────────────────────────────────────────
major [Security & Privacy] → ]8;;vscode://file//work/apps/alp-fusion/DEPLOY.md:65apps/alp-fusion/DEPLOY.md:65]8;; Require TLS for public coordinator endpoints. Line 65 makes TLS optional for public hosts. This conflicts with the README requirement for public coordinators. Plain TCP has no transport confidentiality or integrity. Require TLS for every Internet-reachable coordinator. Restrict cleartext operation to isolated local correctness labs. Proposed documentation fix -1. **One coordinator** bound on `0.0.0.0:8788` (optional TLS for public hosts). +1. **One coordinator** bound on `0.0.0.0:8788` with TLS for public hosts. + Restrict cleartext operation to isolated local correctness labs.
────────────────────────────────────────
Review complete
2 findings ✔
Major 2
6 files reviewed:
- apps/alp-fusion/DEPLOY.md
- apps/alp-fusion/README.md
- apps/alp-fusion/src/client/continuous.ts
- apps/alp-fusion/src/client/fuseLoop.ts
- apps/alp-fusion/src/protocol/constants.ts
- apps/alp-fusion/test/client/fuseLoop.test.ts
────────────────────────────────────────
Print all AI prompts: coderabbit review --show-prompts