Skip to content

chainbackends: fix double-conversion in LndClientFeeEstimator - #238

Merged
ellemouton merged 1 commit into
mainfrom
fix-fee-estimator-double-conversion
Apr 7, 2026
Merged

chainbackends: fix double-conversion in LndClientFeeEstimator#238
ellemouton merged 1 commit into
mainfrom
fix-fee-estimator-double-conversion

Conversation

@ellemouton

Copy link
Copy Markdown
Member

Summary

  • lndclient.WalletKitClient.EstimateFeeRate returns chainfee.SatPerKWeight directly (it does SatPerKWeight(resp.SatPerKw) internally)
  • LndClientFeeEstimator.EstimateFeePerKW was assigning the result to satPerVByte and converting again via SatPerVByte().FeePerKWeight(), inflating the fee rate by ~250x
  • Fix: return the SatPerKWeight value directly without double-conversion

This bug was dormant until lightninglabs/darepo#222 wired LndClientFeeEstimator into the server's round subsystem for batch commitment transactions.

Test plan

  • Verified lndclient.WalletKitClient.EstimateFeeRate return type is chainfee.SatPerKWeight in lndclient@v1.0.1
  • make fmt-check passes
  • make lint passes

lndclient.WalletKitClient.EstimateFeeRate returns
chainfee.SatPerKWeight directly (it does
SatPerKWeight(resp.SatPerKw) internally). The adapter was
incorrectly assigning the result to a variable named satPerVByte
and converting again via SatPerVByte().FeePerKWeight(), inflating
the fee rate by ~250x.

Fix by returning the SatPerKWeight value directly without
double-conversion.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request refactors the EstimateFeePerKW method in LndClientFeeEstimator to remove a redundant fee rate conversion. The EstimateFeeRate call now directly returns the expected chainfee.SatPerKWeight value, and the code has been updated with explanatory comments and minor formatting adjustments. I have no feedback to provide.

@ellemouton
ellemouton merged commit 87016a5 into main Apr 7, 2026
17 checks passed
@ellemouton
ellemouton deleted the fix-fee-estimator-double-conversion branch April 7, 2026 17:32
Roasbeef added a commit that referenced this pull request Apr 10, 2026
Three landed PRs since the last broad gardening sweep touch subsystems
whose CLAUDE.md/AGENTS.md did not yet reflect the new shape: PR #225
(send-in-round-followup), PR #238 (fee-estimator fix, no doc impact),
and PR #239 (partial-unroll-harness-accessor). The most significant
structural changes are the introduction of a data-driven pkScript
ownership path and a dedicated actor that materializes round-produced
VTXOs from indexer push notifications.

The round FSM no longer relies on a per-intent IsOwner flag. Instead,
buildOwnedClientVTXOs resolves ownership at round confirmation time by
asking a round.OwnedScriptChecker whether each VTXO's pkScript is
recognized by the local wallet, and round.OwnedScriptRegistrar persists
locally-owned scripts at intent-build time and inside
handleRegisterIntent for incoming intents whose owner key has a
non-zero KeyLocator. The darepod package exposes both interfaces as
thin adapters over the OOR owned-receive-scripts store, which means the
same table now backs three abstractions (OwnedScriptChecker,
OwnedScriptRegistrar, and vtxo.OwnedScriptLookup). The per-package docs
pick up these new interfaces, the adapter types, and the invariants
they enforce; ARCHITECTURE.md gains a new "Data-Driven Script
Ownership" pattern section so agents encountering the code can follow
the flow without re-deriving it from commits.

The vtxo package now hosts an IncomingVTXOHandler actor that decodes
arkrpc.IncomingVTXOEvent push notifications, materializes the VTXO
descriptor via lib/scripts.VTXOTapScript, persists it, and notifies the
VTXO manager via VTXOsMaterializedNotification. darepod registers the
actor under vtxo.IncomingVTXOServiceKey and wires a new
MethodIncomingVTXO route into the EventRouter. The vtxo CLAUDE.md now
documents the handler's inputs, validation rules (only VTXO_CREATED
events, bounds-checked values, nil-safe pkScripts), and the fact that
CommitmentTxID comes from the event rather than the leaf txid. The
darepod doc picks up the route registration and the service-key
bootstrap; ARCHITECTURE.md mentions the new route under the
RPC-over-Mailbox pattern.

Smaller updates round out the sweep. wallet/CLAUDE.md describes the
hardened handleSendVTXOs path: recipient amounts are now bounded by
MaxSatoshi, the running total uses overflow-safe accumulation, and the
old releaseAndFail helper is replaced by a deferred release that uses
context.WithoutCancel so cleanup survives caller disconnect. The
darepod doc records the matching RPC-side validation cap
(maxRecipients = 256) and notes that s.clk is now a cached clock
instance so sub-stores share a single Clock for deterministic tests,
plus the new GetStoredVTXO harness accessor used by partial unroll
itests. Round, darepod, vtxo, and wallet docs all cross-reference the
new ownership interfaces where relevant so navigating the per-package
graph reaches the same explanation from any entry point.

make doc-check is clean after these changes.
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