Skip to content

assets: harden tapd client lifecycle and RFQ handling - #1189

Open
hieblmi wants to merge 4 commits into
lightninglabs:masterfrom
hieblmi:tapd-client-fixes
Open

assets: harden tapd client lifecycle and RFQ handling#1189
hieblmi wants to merge 4 commits into
lightninglabs:masterfrom
hieblmi:tapd-client-fixes

Conversation

@hieblmi

@hieblmi hieblmi commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

Improve the tapd client’s lifecycle, timeout handling, concurrency, and validation.

  • Close tapd gRPC connections during daemon shutdown, initialization failures, and view completion.
  • Validate RFQ timeout durations before creating the client.
  • Round positive fractional timeouts up to tapd’s whole-second representation.
  • Allow cached asset-name reads while another universe lookup is in progress.
  • Reject nil, malformed, non-positive, and invalid-scale RFQ asset rates instead of risking a panic.
  • Add regression tests for timeout boundaries, concurrent cache access, and malformed rates.

@hieblmi
hieblmi requested a review from starius July 31, 2026 19:26
hieblmi added 4 commits July 31, 2026 21:28
Close the TapdClient when daemon initialization fails, during normal
shutdown, and after the view command completes. This prevents gRPC
transport resources from leaking across embedded daemon lifecycles and
error paths.
Convert the configured duration once during client creation. Round
positive fractional durations up to the whole seconds accepted by tapd.
Reject zero, negative, and overflowing values, and cover the conversion
boundaries with unit tests.
Restrict the asset-name cache mutex to map access so a slow
QueryAssetStats call cannot block cached readers. Use an RWMutex for
independent cache reads and add a concurrent regression test.
Validate the rate pointer and decimal coefficient before converting
asset units. Return errors for nil, malformed, non-positive, and
oversized-scale rates instead of allowing nil dereferences or
division-by-zero panics. Add regression tests for each case.
@hieblmi
hieblmi force-pushed the tapd-client-fixes branch from 25dd676 to d8910ea Compare July 31, 2026 19:35

@starius starius left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM! 💾

Left come comments. The main one is hardening for GetRfqForAsset.

Comment thread loopd/daemon.go
if d.assetClient != nil {
d.assetClient.Close()
d.assetClient = nil
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I propose to add defer inside if d.cfg.Tapd.Activate block above and close it there.

Comment thread assets/client.go
Comment on lines +298 to +299
// seconds accepted by tapd. Sub-second precision is rounded up so a positive
// timeout can never become tapd's invalid zero value.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Isn't there a stronger reason to do it so we don't get a timeout error?

If we account on 1.5s timeout (and actively using it, e.g. use it at time 1.4s, i.e. 0.1s before the timeout), but tapd enforces the timeout of just 1s (rounded down, as before), we get a timeout error. So we round up to request enough time, right?

Comment thread assets/client.go
}
if coefficient.Sign() <= 0 {
return 0, fmt.Errorf("asset rate coefficient must be positive")
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We need a similar hardening for GetRfqForAsset. Here is an example how to fix it: https://gist.github.com/starius/c23dd24330c3d36c9e852d2f4596313f

Comment thread assets/client.go
Comment on lines 165 to 172

c.assetNameMutex.Lock()
defer c.assetNameMutex.Unlock()
assetIdStr := hex.EncodeToString(assetId)
c.assetNameMutex.RLock()
if name, ok := c.assetNameCache[assetIdStr]; ok {
c.assetNameMutex.RUnlock()
return name, nil
}
c.assetNameMutex.RUnlock()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's preserve the defer pattern somehow. Maybe make private accessor methods for this map? To encapsulate map+mutex work there.

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