Skip to content

Dial primary plus fallback arkd-wallets - #1099

Open
bitcoin-coder-bob wants to merge 5 commits into
bob/arkd-require-unlocked-walletfrom
bob/arkd-multi-wallet-dial
Open

Dial primary plus fallback arkd-wallets#1099
bitcoin-coder-bob wants to merge 5 commits into
bob/arkd-require-unlocked-walletfrom
bob/arkd-multi-wallet-dial

Conversation

@bitcoin-coder-bob

@bitcoin-coder-bob bitcoin-coder-bob commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Why

Next step towards letting a single arkd front more than one LP. This teaches arkd to connect to a primary arkd-wallet plus N fallback wallets belonging to additional liquidity providers. It is purely additive: the primary path is unchanged and fallbacks are dialed and validated but not yet used by sweep (that wiring lands in a follow-up). Very simple: we just support adding other wallets and try connecting to them, we dont actually use the wallets yet for sweeps/fallbacks. The PR is just a small step to introduce new wallet support before actually using the wallets for functionality.

Stacked PRs (merge top-down):

This PR depends on #1098 landing first.

What changes

Config

  • New ARKD_WALLET_FALLBACK_ADDRS (comma-separated host:port). Parsed with an explicit comma split (parseWalletFallbackAddrs), not viper.GetStringSlice, because the latter splits on whitespace, not commas (verified empirically), and would silently mis-parse the list.
  • walletService() dials the primary (unchanged), then dialFallbackWallets() dials each fallback via an indirected newWalletClient (so it is unit-testable) and hard-fails if a fallback is unreachable or on a different network than the primary, closing any partially-dialed connections to avoid leaks. It also rejects a fallback whose address duplicates the primary or another fallback.
  • Dialed fallbacks are held in Config.walletFallbacks and exposed via FallbackWallets() (each pairing the dial address with the wallet client). The primary stays c.wallet, so GetInfo, the forfeit pubkey/address, connector address, scanning, signing, and sweep are all untouched.

Startup / shutdown

  • ensureWalletReady() now also requires each fallback wallet to be initialized and unlocked (hard-fail); the zero-balance warning stays primary-only.
  • stop() closes the fallback connections (the primary is closed by the app service).

Exercised end to end

  • docker-compose.regtest.yml now runs a second arkd-wallet (arkd-wallet-2, host port 6061, its own datadir/volume/signer key) wired into arkd via ARKD_WALLET_FALLBACK_ADDRS=arkd-wallet-2:6060.
  • The e2e harness initializes and unlocks both wallets before arkd starts, so the entire existing e2e suite now runs with a fallback wallet plugged in.

Docs / tests

  • README: an ARKD_WALLET_FALLBACK_ADDRS row and a "Configuring multiple LP wallets" subsection.
  • Unit tests: TestParseWalletFallbackAddrs (parsing edge cases) and TestDialFallbackWallets (same-network success; network-mismatch hard-fail with cleanup; dial-error hard-fail with cleanup; fallback-equals-primary hard-fail; duplicate-fallback hard-fail).

Operator impact

Every wallet, primary and fallback, must be initialized and unlocked out of band and must be on the same network as the primary; arkd validates this at startup and refuses to start otherwise.

Testing

  • go build ./..., go vet, make lint (0 issues), the new config unit tests, and the e2e package compile all pass.
  • A multi-agent adversarial review over the diff raised 8 findings, all dismissed on verification (no production-code or harness defects).

Status

Draft: depends on #1098 landing first; the sweep fallback that actually uses these wallets is #1101.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (1)
  • next-version

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 36fd7c5f-2bd7-4c99-bf21-f181ecc20c15

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bob/arkd-multi-wallet-dial

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.

@ghost ghost 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.

🔍 Arkana Code Review — bob/arkd-multi-wallet-dial

Plumbing PR to dial and validate fallback LP wallets at startup. The actual sweep fallback wiring is deferred. Overall structure is clean — good network validation, good cleanup on dial failure, solid test coverage. A few issues to address:


🔴 Must Fix

1. Fallback wallets not locked on shutdown — security gap
internal/interface/grpc/service.go (new code in stop()): Fallback wallets get Close() only. The primary wallet gets Lock(ctx) + Close() in application/service.go:394-397. An unlocked arkd-wallet that's still running after arkd shuts down is network-accessible with full signing authority. Lock fallbacks before closing them.

// Current (stop):
for _, fb := range s.appConfig.FallbackWalletServices() {
    fb.Close()
}

// Suggested:
for _, fb := range s.appConfig.FallbackWalletServices() {
    _ = fb.Lock(context.Background()) // best-effort, same as primary
    fb.Close()
}

2. No dedup or self-reference check on fallback addresses
internal/config/config.go (dialFallbackWallets): If a user accidentally sets ARKD_WALLET_FALLBACK_ADDRS=localhost:6060 (same as primary) or a:6060,a:6060, arkd opens duplicate connections to the same wallet. When sweep fallback logic lands, this could cause double-spend attempts or lock contention. Add validation:

  • Reject any fallback addr that matches c.WalletAddr
  • Reject duplicate entries in the list

🟡 Suggestions

3. FallbackWalletServices() returns the backing slice directly
internal/config/config.go:664: Callers can mutate the returned slice. In a codebase where bugs lose money, return a copy:

func (c *Config) FallbackWalletServices() []ports.WalletService {
    out := make([]ports.WalletService, len(c.walletFallbacks))
    copy(out, c.walletFallbacks)
    return out
}

4. ensureWalletReady error messages use index, not address
internal/interface/grpc/service.go:671-686: Error messages say "fallback wallet 0 is not initialized" — an operator has to count their comma-separated list to figure out which one. Include the address in the error for operability. You have access to s.appConfig.WalletFallbackAddrs for this.

5. Docker compose: wallet-2 has no restart: unless-stopped health check
docker-compose.regtest.yml: The primary wallet has a dependency chain, but wallet-2 only depends on nbxplorer. Not blocking, but consider adding a healthcheck or at least a comment noting that arkd will crash-loop until wallet-2 is ready (which is the intended behavior per ensureWalletReady).


✅ What looks good

  • Network mismatch is a hard fatal — correct, prevents silent misconfiguration
  • closeWallets() cleanup on partial dial failure — proper resource management
  • Test coverage: TestParseWalletFallbackAddrs covers edge cases; TestDialFallbackWallets covers same-network, mismatch, and dial-error paths with Close() assertion counting
  • E2E setup correctly initializes/unlocks wallet-2 before arkd starts
  • newWalletClient indirection for testability is a good pattern
  • README accurately describes the current scope and explicitly says sweep wiring is deferred

⚠️ Protocol-critical flag: This PR adds infrastructure for multi-LP wallet management. While the sweep fallback logic isn't here yet, the wiring established here (which wallets are trusted, how they're validated, how they're cleaned up) is foundational. Requesting human review on the security model — specifically whether fallback wallets should have the same lock-on-shutdown semantics as the primary.

@bitcoin-coder-bob
bitcoin-coder-bob force-pushed the bob/arkd-require-unlocked-wallet branch from 513eca3 to 9e5e7cb Compare June 13, 2026 01:57
@bitcoin-coder-bob
bitcoin-coder-bob force-pushed the bob/arkd-multi-wallet-dial branch 2 times, most recently from a60692f to 835c866 Compare June 14, 2026 17:23

@ghost ghost 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.

🔍 Arkana Follow-up Review — bob/arkd-multi-wallet-dial

Reviewed the force-push (rebase onto updated #1098). No substantive code changes to this PR's layer — all 5 findings from my previous review remain unaddressed.


🔴 Still open — must fix

1. Fallback wallets not locked on shutdown
internal/interface/grpc/service.go:235-237 — still just fb.Close(), no fb.Lock(). The primary wallet gets Lock() + Close() in application/service.go. An unlocked fallback arkd-wallet remains network-accessible with signing authority after arkd shuts down.

2. No dedup or self-reference check on fallback addresses
internal/config/config.go:dialFallbackWallets — still no validation that a fallback addr ≠ c.WalletAddr or that there are no duplicate entries. When the sweep fallback in #1101 lands, duplicates could cause double-spend attempts or lock contention.


🟡 Still open — suggestions

3. FallbackWalletServices() returns backing slice (config.go:668-671)
4. Error messages use index not address (service.go:684-706)

These are the same as before. See my original review for details and suggested fixes.


No new issues introduced by the rebase. Blocking on findings 1 and 2.

⚠️ Protocol-critical: Human review still requested on the security model for fallback wallet lifecycle (lock-on-shutdown semantics).

@bitcoin-coder-bob
bitcoin-coder-bob force-pushed the bob/arkd-multi-wallet-dial branch from 835c866 to d6d6423 Compare June 14, 2026 17:28

@ghost ghost 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.

🔍 Arkana Review #3bob/arkd-multi-wallet-dial

Third pass after another force-push (rebase). Diff unchanged — no new code to review. All previous findings remain open.

🔴 Still blocking

1. Fallback wallets not locked on shutdowninternal/interface/grpc/service.go:235-237
Primary gets Lock() + Close(). Fallbacks only get Close(). An unlocked arkd-wallet with signing authority stays network-accessible after arkd shuts down.

2. No dedup / self-reference checkinternal/config/config.go:dialFallbackWallets
No validation that a fallback addr ≠ primary WalletAddr, or that fallback list has no duplicates. With #1101's sweep fallback, duplicates → double-spend risk or lock contention.

🟡 Still open

3. FallbackWalletServices() returns backing slice — config.go:668-671
4. Error messages use index not address — service.go:684-706

See review #1 for details and suggested fixes on all four items.

⚠️ Protocol-critical: Human review still requested on fallback wallet lifecycle security model.

@bitcoin-coder-bob
bitcoin-coder-bob force-pushed the bob/arkd-multi-wallet-dial branch from d6d6423 to 57edf9d Compare June 15, 2026 15:16

@ghost ghost 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.

🔍 Arkana Review #4bob/arkd-multi-wallet-dial

Fourth pass after rebase. No code changes — diff identical to reviews #1#3. All findings remain open.

🔴 Blocking

1. Fallback wallets not locked on shutdowninternal/interface/grpc/service.go:235-237
Primary gets Lock() + Close(). Fallbacks only get Close(). Unlocked arkd-wallet with signing authority stays network-accessible after arkd shuts down.

2. No dedup / self-reference checkinternal/config/config.go:dialFallbackWallets
No validation that fallback addr ≠ primary WalletAddr or that the list has no duplicates. With #1101's sweep fallback, duplicates → double-spend risk or lock contention.

🟡 Open

3. FallbackWalletServices() returns backing slice — config.go:668-671
4. Error messages use index not address — service.go:684-706

See review #1 for details and suggested fixes on all four items.

⚠️ Protocol-critical: Human review still requested on fallback wallet lifecycle security model.

Add ARKD_WALLET_FALLBACK_ADDRS so arkd can connect to a primary
arkd-wallet plus additional LP wallets. Fallbacks are dialed and
validated (reachable, same network, initialized and unlocked) at
startup; the primary is unchanged and remains the sole source of the
forfeit pubkey, addresses and signing. Fallbacks are not used by sweep
yet.

The regtest compose stack now runs a second arkd-wallet so the existing
e2e suite exercises arkd with a fallback plugged in.
@bitcoin-coder-bob
bitcoin-coder-bob force-pushed the bob/arkd-require-unlocked-wallet branch from edf1888 to 5d9ad68 Compare June 15, 2026 15:35
@bitcoin-coder-bob
bitcoin-coder-bob force-pushed the bob/arkd-multi-wallet-dial branch from 57edf9d to 03d4fe9 Compare June 15, 2026 15:35

@ghost ghost 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.

🔍 Arkana Review #5bob/arkd-multi-wallet-dial

Fifth pass after rebase. Diff identical to reviews #1#4. No code changes — all findings remain open.

🔴 Blocking

1. Fallback wallets not locked on shutdowninternal/interface/grpc/service.go:235-237
Primary gets Lock() + Close(). Fallbacks only get Close(). Unlocked arkd-wallet with signing authority stays network-accessible after arkd shuts down.

2. No dedup / self-reference checkinternal/config/config.go:dialFallbackWallets
No validation that fallback addr ≠ primary WalletAddr or that the list has no duplicates. With #1101's sweep fallback, duplicates → double-spend risk or lock contention.

🟡 Open

3. FallbackWalletServices() returns backing slice — config.go:668-671
4. Error messages use index not address — service.go:684-706

See review #1 for details and suggested fixes on all four items.

⚠️ Protocol-critical: Human review still requested on fallback wallet lifecycle security model.

Pair each dialed fallback wallet with its address (FallbackWallet) so
ensureWalletReady reports the specific wallet that failed (host:port)
instead of a positional index, which isn't actionable when the error
surfaces. Also clarify the comment on why fallback balance isn't checked.

@ghost ghost 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.

🔍 Arkana Review #6bob/arkd-multi-wallet-dial

Reviewed new commit 98f24639 — introduces FallbackWallet struct pairing Addr + Service, renames FallbackWalletServices()FallbackWallets(), and updates ensureWalletReady errors to use %q with fb.Addr instead of positional index.

New commit assessment

Good: The FallbackWallet struct is a clean solution to finding #4. Error messages now name the wallet by host:port — much better for operators. The type change is well-propagated through dialFallbackWallets, closeWallets, stop(), and ensureWalletReady.

Tests: TestDialFallbackWallets still works correctly — the fakeFallbackWallet satisfies ports.WalletService which is wrapped in FallbackWallet.Service. No test gaps introduced.

🟠 New issue from this commit

5. Stacked PR #1101 will break#1101 calls c.FallbackWalletServices() (the old name) and expects []ports.WalletService (the old type) in at least 3 call sites. After this rename, #1101 won't compile when rebased. Not blocking for this PR, but Bob should rebase #1101 onto this branch before merging either.

Findings status

# Finding Status
1 🔴 Fallback wallets not locked on shutdown (service.go:238-239) Still openstop() still only calls fb.Service.Close(), no Lock()
2 🔴 No dedup / self-reference check (config.go:851-875) Still open — no validation that fallback addr ≠ primary or no duplicates
3 🟡 FallbackWallets() returns backing slice (config.go:679-681) Still open
4 ✅ Error messages use index not address Fixed by this commit
5 🟠 Stacked PR #1101 uses old API name New — compile break in downstream

Blocking on findings 1 and 2. Finding 5 is a heads-up for the PR stack.

⚠️ Protocol-critical: Human review still requested on fallback wallet lifecycle security model.

On this branch arkd only dials and readiness-checks fallback wallets at
startup; sweep signing isn't wired up yet. Reword the docker-compose and
dialFallbackWallets comments so they don't imply active sweep-fallback use.

@ghost ghost 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.

🔍 Arkana Review #7bob/arkd-multi-wallet-dial

New commit 2738e658 is comment-only — rewords the docker-compose comment and dialFallbackWallets godoc to clarify sweep signing isn't wired up yet. No logic changes. No new issues.

Findings status (unchanged from review #6)

# Finding Status
1 🔴 Fallback wallets not locked on shutdown (service.go:238-239) — stop() calls fb.Service.Close() but not Lock(). Primary gets both. An unlocked arkd-wallet with signing authority stays network-accessible after arkd shuts down. Still open
2 🔴 No dedup / self-reference check (config.go:853-875) — no validation that a fallback addr ≠ primary WalletAddr or that the fallback list has no duplicates. With #1101's sweep fallback, duplicates → double-spend risk or lock contention. Still open
3 🟡 FallbackWallets() returns backing slice (config.go:681) — caller can mutate c.walletFallbacks. Return a copy or document the contract. Still open
4 ✅ Error messages use index not address Fixed in 98f2463
5 🟠 Stacked PR #1101 uses old API name#1101 calls FallbackWalletServices() (old name) and expects []ports.WalletService. Needs rebase after this lands. Still open

Blocking on findings 1 and 2.

⚠️ Protocol-critical: Human review still requested on fallback wallet lifecycle security model.

…er fallback

Fail fast at dial time if a fallback address equals the primary WalletAddr
or repeats another fallback, instead of silently dialing the same wallet
twice (pointless now, double-spend/lock-contention risk once fallbacks sign
sweeps). Matching is by literal address.

@ghost ghost 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.

🔍 Arkana Review #8bob/arkd-multi-wallet-dial

New commit ba566dab adds dedup and self-reference validation in dialFallbackWallets. Assessment:

✅ Finding #2 is now fixed

The implementation is correct:

  • Primary check (config.go:861): addr == c.WalletAddr rejects before dialing, avoiding a wasted connection. Cleans up already-dialed fallbacks via closeWallets().
  • Duplicate check (config.go:865-868): seen map with literal string matching. Also rejects before dialing and cleans up.
  • Test coverage: Two new test cases verify error messages, cleanup (Close counts), and that no unnecessary dials are made (require.Equal(t, 1, calls)). Good.

One note: the matching is literal (addr == c.WalletAddr). Addresses like localhost:6060 vs 127.0.0.1:6060 vs [::1]:6060 would bypass this check. This is acceptable for now since the operator controls both values and the PR description documents this, but worth a follow-up comment in the code.

Updated findings status

# Finding Status
1 🔴 Fallback wallets not locked on shutdown (service.go:238-239) — stop() calls fb.Service.Close() but not Lock(). Primary gets both. An unlocked arkd-wallet with signing authority stays network-accessible after arkd shuts down. Still open
2 ✅ No dedup / self-reference check Fixed in ba566dab
3 🟡 FallbackWallets() returns backing slice (config.go:681) — caller can mutate c.walletFallbacks. Return a copy or document the contract. Still open
4 ✅ Error messages use index not address Fixed in 98f2463
5 🟠 Stacked PR #1101 uses old API name#1101 calls FallbackWalletServices() (old name) and expects []ports.WalletService. Needs rebase after this lands. Still open

Still blocking on finding #1. The lock-on-shutdown gap is a real security concern for when fallback wallets start signing sweeps in #1101.

⚠️ Protocol-critical: Human review still requested on fallback wallet lifecycle security model.

@bitcoin-coder-bob

Copy link
Copy Markdown
Collaborator Author

🔍 Arkana Review #7bob/arkd-multi-wallet-dial

New commit 2738e658 is comment-only — rewords the docker-compose comment and dialFallbackWallets godoc to clarify sweep signing isn't wired up yet. No logic changes. No new issues.

Findings status (unchanged from review #6)

Finding Status

1 🔴 Fallback wallets not locked on shutdown (service.go:238-239) — stop() calls fb.Service.Close() but not Lock(). Primary gets both. An unlocked arkd-wallet with signing authority stays network-accessible after arkd shuts down. Still open
2 🔴 No dedup / self-reference check (config.go:853-875) — no validation that a fallback addr ≠ primary WalletAddr or that the fallback list has no duplicates. With #1101's sweep fallback, duplicates → double-spend risk or lock contention. Still open
3 🟡 FallbackWallets() returns backing slice (config.go:681) — caller can mutate c.walletFallbacks. Return a copy or document the contract. Still open
4 ✅ Error messages use index not address Fixed in 98f2463
5 🟠 Stacked PR #1101 uses old API name#1101 calls FallbackWalletServices() (old name) and expects []ports.WalletService. Needs rebase after this lands. Still open
Blocking on findings 1 and 2.

⚠️ Protocol-critical: Human review still requested on fallback wallet lifecycle security model.

1: arkd never unlocks wallets anymore so it shouldnt lock them either
2: fixed in ba566da

@arkana-ai-bot arkana-ai-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.

Reviewed at ba566da (head). Not protocol-critical: additive infra only — fallbacks are dialed and readiness-checked at startup, but the primary path (forfeit key/address, connector address, scanning, signing, sweep, main-account balance warning) is untouched, and nothing in this diff uses the fallbacks for signing.

Design is clean:

  • parseWalletFallbackAddrs correctly comma-splits (viper.GetStringSlice would whitespace-split, per the PR description); trims and drops empties.
  • dialFallbackWallets (internal/config/config.go:830-863) dedupes vs primary and vs prior fallbacks, dials via the test-swappable newWalletClient, validates network name match, and closes previously-dialed connections on any failure via closeWallets.
  • service.stop() (internal/interface/grpc/service.go:235-240) closes fallback connections; comment correctly notes the primary is closed by application.service.Stop at internal/core/application/service.go:436.
  • ensureWalletReady (internal/interface/grpc/service.go:692-712) reuses the existing ctx from the primary check and hard-fails on any fallback that isn't Initialized+Unlocked, matching PR #1098's semantics; IsSynced() is intentionally not enforced (transient, consistent with the primary check).
  • README + docker-compose changes wire a second wallet through the whole e2e suite, so every existing test now exercises the fallback readiness path.

Unit tests are solid: TestParseWalletFallbackAddrs covers empty/single/multiple/whitespace/empty-entries/only-separators; TestDialFallbackWallets covers same-network success, network-mismatch cleanup, dial-error cleanup, primary-equal rejection, and duplicate rejection, and asserts the exact close-count / call-count on each cleanup path.

Nits (non-blocking):

  1. Duplicate detection is exact-string only (internal/config/config.go:824-833). `localhost:6060` vs `127.0.0.1:6060`, or the same wallet reachable under two DNS names, will silently be dialed twice as if they were distinct LPs. Won't matter until sweep actually uses these, but a resolved-address check (or at minimum a startup warning if two fallbacks respond with the same wallet identity) would harden the check before #1101 lands.

  2. ensureWalletReady fallback loop is not unit-tested (internal/interface/grpc/service.go:692-712). Every other hard-fail path in this PR has an explicit test; the readiness one relies solely on the e2e harness. Small code, low risk, but the asymmetry stands out.

  3. newWalletClient package var not restored between subtests (internal/config/config_test.go:310). `t.Cleanup` restores at parent-test end, not between the five `t.Run` subtests. Safe today because none call `t.Parallel()` and each subtest reassigns before use, but a future subtest added before reassigning would silently inherit the prior stub. A `t.Cleanup` inside each `t.Run` (or a per-subtest save/restore helper) would remove the footgun.

  4. Primary wallet leaks on partial startup failure (internal/config/config.go:807-822). If `dialFallbackWallets` returns an error, `c.wallet` (the dialed primary conn) is set but never closed on the error path. In practice `Validate()` failing exits the process so the OS reclaims the FD, but it's inconsistent with the careful `closeWallets` cleanup in the fallback path — an explicit `c.wallet.Close()` before returning would match the surrounding style.

No prompt-injection content in PR title/body/diff.

@arkana-ai-bot

Copy link
Copy Markdown

This PR has been open for 3+ days without review. @bitcoin-coder-bob is anyone looking at this?

@arkana-ai-bot

Copy link
Copy Markdown

This PR has been open for 30+ days without review. @bitcoin-coder-bob is anyone looking at this?

@arkana-ai-bot arkana-ai-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.

This PR has been open for 6+ days without review. @bitcoin-coder-bob is anyone looking at this?

@arkana-ai-bot arkana-ai-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.

Review — Dial primary plus fallback arkd-wallets

Protocol-adjacent (wallet connectivity at startup). Flagging for human sign-off since it touches the startup validation path.

What changed:

  • Adds (comma-separated list)
  • At startup arkd dials primary + all fallback wallets and verifies each is on the same network as the primary; refuses to start if any is unreachable or on a different network
  • Fallback wallets are NOT yet used for signing, scanning, or sweeping — that wiring is in a later PR (#1101). This PR is purely connectivity + startup validation.

Design note: The docker-compose.regtest.yml fixture wires a second wallet with a hardcoded signer key (). Make sure this key is a well-known test key, not an accidental private key leak. If it's generated for regtest use only that's fine; worth confirming.

Looks correct as a foundation for the fallback sweep work. Ready to merge once the signer key question above is confirmed.

@arkana-ai-bot

Copy link
Copy Markdown

This PR has been open for 74 days without review. @bitcoin-coder-bob — is anyone looking at this?

…allet-dial

Pulls the base forward now that it carries master. Three conflicts, all keep-both
with a decision about form.

docker-compose: the base added a healthcheck to arkd-wallet and switched arkd's
depends_on to the condition form gating on service_healthy, while this branch
added arkd-wallet-2. Both kept, and arkd-wallet-2 gets the same healthcheck,
since arkd now waits on it being healthy rather than merely started.

config.go: the base adds BatchTrigger and drops roundReportSvc, master having
removed the report service entirely, so that removal is taken; this branch's
walletFallbacks is kept alongside.

utils_test.go: this branch generalises setupArkdWallet into setupArkdWalletAt
with a base URL so the same helper drives the primary and the fallback wallet.
The single-URL form the base carries is dropped, its only caller already having
moved to the new one.

Not verified here: the e2e suite needs the regtest stack and this changes both
the compose topology and the harness setup path, so CI is the real check.

@arkana-ai-bot arkana-ai-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.

🔍 Arkana Review #9 — `bob/arkd-multi-wallet-dial`

Status: Merge of `bob/arkd-require-unlocked-wallet` into this branch. One prior finding is now no longer applicable (finding #1), one is still open (finding #3). Two are confirmed fixed. No new blocking issues in the incremental diff.


Prior findings — closure

# Finding Status
1 🔴 Fallback wallets not locked on shutdown No longer applicable@bitcoin-coder-bob is correct: the new code does not call Lock() on the primary wallet at shutdown either. application/service.go:422-451 calls only s.wallet.Close(), no Lock(). The shutdown contract is now Close-only for all wallets; the fallback behaviour matches the primary. Dropping as a blocker.
2 ✅ No dedup / self-reference check Fixed in ba566dab — confirmed in review #8; unchanged here.
3 🟡 FallbackWallets() returns backing slice Still openinternal/config/config.go:687 still returns c.walletFallbacks directly. Callers in stop() and ensureWalletReady only read the slice today, but the contract is undocumented and a future caller could mutate it. Non-blocking for this PR given the current read-only callers.
4 ✅ Error messages use index not address Fixed in 98f2463 — unchanged.
5 🟠 Stacked PR #1101 uses old API name No longer applicable#1101 will need a rebase after this lands regardless; the rename was already a known dependency.

Incremental additions (new since ba566dab)

docker-compose.regtest.ymlarkd-wallet-2 service looks correct:

  • restart: unless-stopped and healthcheck (nc -z localhost 6060) present — good, matches the intent to have arkd wait until the wallet is reachable.
  • arkd now has arkd-wallet-2: condition: service_healthy in its depends_on. This is the right binding.
  • ARKD_WALLET_DATADIR=./data/regtest-2 separates the data directories from wallet-1. Good.
  • ARKD_WALLET_FALLBACK_ADDRS=arkd-wallet-2:6060 uses the Docker-internal hostname, which is correct for intra-container gRPC communication. The e2e test correctly uses the mapped external port 6061 via walletUrl2.
  • The hardcoded ARKD_WALLET_SIGNER_KEY for wallet-2 is a regtest dev key. Confirm it differs from the primary wallet's signer key; dialing two wallets with the same signing key would give the fallback redundant-but-useless signing authority (not dangerous today, but confusing once sweep wiring lands in #1101).

internal/test/e2e/utils_test.go — Refactor of setupArkdWalletsetupArkdWalletAt(httpClient, baseURL) is clean. Both wallets are initialised and unlocked before arkd starts; error messages now include the wallet URL. No gaps.

README.md — Documentation accurately reflects the current scope: fallbacks are dialed and readiness-checked; sweep signing is explicitly deferred. No issues.


Nits (non-blocking, noted for completeness)

  • Primary wallet leaks on partial startup failure (internal/config/config.go:807-822): if dialFallbackWallets returns an error, c.wallet is set but never explicitly closed on the error return path. In practice the process exits immediately, so the OS reclaims the FD. But it's inconsistent with the closeWallets cleanup discipline applied to the fallback path — an explicit c.wallet.Close() before returning on error would match the surrounding style.
  • ensureWalletReady fallback loop is not unit-tested (internal/interface/grpc/service.go:692-712): the initialized/unlocked hard-fail paths for fallbacks are exercised only by the e2e harness. Low risk given the code is simple, but the asymmetry with the thoroughly unit-tested dialFallbackWallets is worth noting.
  • Exact-string dedup (internal/config/config.go:824-833): localhost:6060 vs 127.0.0.1:6060 pointing at the same wallet will bypass the duplicate check. Acceptable today; worth a note in the code or a TODO for before #1101 lands.

No new blocking issues. Dropping the changes requested status — finding #3 is a low-severity suggestion with no current caller at risk.

@arkana-ai-bot

Copy link
Copy Markdown

This PR has been open for 4-5+ days without a review. @bitcoin-coder-bob is anyone looking at this? (Dial primary plus fallback arkd-wallets; 4 days without review.)

@arkana-ai-bot

Copy link
Copy Markdown

This PR has been open for 11+ weeks without a review. @bitcoin-coder-bob — is anyone looking at this?

@arkana-ai-bot

Copy link
Copy Markdown

This PR has been open for 83+ days without a review. @bitcoin-coder-bob — dial primary plus fallback arkd-wallets: is this still relevant / waiting on other PRs?

@arkana-ai-bot

Copy link
Copy Markdown

This PR has been open for 3+ months without a review. @bitcoin-coder-bob is anyone looking at this? Let us know if it needs a rebase or if there's a blocker.

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.

2 participants