Skip to content

tapgarden: fix busy-loop risk and silent failure in Custodian transaction subscription #1939

@ffranr

Description

@ffranr

The Custodian service in tapgarden/custodian.go relies on WalletAnchor.SubscribeTransactions to detect incoming on-chain asset transfers. The current error handling and channel consumption in mainEventLoop introduces a risk of a busy-loop if the connection to the backing LND node is interrupted.

Issues Identified

1. Busy-Loop Risk on Channel Closure

In mainEventLoop, the newTxChan (type <-chan lndclient.Transaction) is consumed inside a select block:

case tx := <-newTxChan:
    err = c.inspectWalletTx(&tx)

If the newTxChan is closed (e.g., the underlying lndclient stream is terminated), the receive operation returns immediately with the zero value of the Transaction struct (not nil).

  • inspectWalletTx receives a valid pointer to this empty struct.
  • It calls hasWalletTaprootOutput, which checks len(tx.OutputDetails). Since the zero-value slice has length 0, it returns false safely.
  • inspectWalletTx returns nil (no error).
  • The loop repeats immediately, consuming 100% CPU while processing infinite "empty" transactions.

2. Zombie State (Silent Failure)

The error channel txErrChan is handled by logging the error and continuing. There is currently no logic to re-subscribe.
Once the subscription breaks (closed channel or error), the Custodian enters a state where it is technically running but receives no new chain events, meaning incoming asset transfers will be ignored until the daemon is restarted.

Expected Behavior

  1. Detect Closure: The loop must use tx, ok := <-newTxChan to detect channel closure.
  2. Re-subscribe: Upon closure or error, the Custodian should attempt to re-establish the transaction subscription (ideally with a backoff strategy) to resume processing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    🆕 New

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions