feat(gl-sdk): NodeState snapshot with UTXO-safe balance accounting#704
Open
feat(gl-sdk): NodeState snapshot with UTXO-safe balance accounting#704
Conversation
Collaborator
|
The new channel state |
8dbd635 to
9eb4939
Compare
NodeState - Unified node_state() snapshot aggregating get_info, list_peer_channels, and list_funds into a single record with balances, capacity, utxos, and connected-channel-peer set. - Reserved UTXOs (in-flight PSBTs) excluded from on-chain balance. FundOutput now carries `reserved` from listfunds.outputs[].reserved. - Closing-channel double-count fixed. Onchain-state channels only contribute to pending_onchain_balance_msat when we initiated the close and our payout is still timelocked (DELAYED_OUTPUT_TO_US); otherwise the payout is already a wallet UTXO and would be counted twice. PeerChannel exposes `closer` (ChannelSide) and `status` to support this gate. - ChannelState::from_i32 unknown fallback now maps to a new ChannelState::Unknown variant rather than Onchain (which silently counted unmapped states as closing). Unknown is treated as neither open nor closing by balance math. gl-sdk-cli output formatter handles the new variant too. - Immature outputs (confirmed but timelocked, e.g. coinbase maturation) surface as immature_onchain_balance_msat instead of being silently dropped. OutputStatus match is exhaustive. - The three underlying RPCs run concurrently via tokio::join!. NodeState aggregate fields: - total_onchain_msat (confirmed + unconfirmed + immature) - total_balance_msat (everything the user owns) - spendable_balance_msat (send-screen gate) - max_chan_reserve_msat (protocol reserve locked across channels) - utxos: Vec<FundOutput> for coin-control UIs Other NodeState changes: - channels_balance_msat / max_payable_msat docstrings explicitly name their roles: home-screen display vs send-button gate. - num_active/pending/inactive_channels docstrings clarify which balance fields each count contributes to. - connected_peers renamed to connected_channel_peers (only lists peers we have a channel with); dedup via HashSet. - fees_collected_msat removed from NodeState (still on GetInfoResponse); it's a routing-node concern. Hex identifier surface - Every identifier (pubkey, payment hash, txid, preimage, funding txid, channel id) on public structs is now a lowercase hex String instead of Vec<u8>. Affected: NodeState, PeerChannel, FundOutput, FundChannel, GetInfoResponse, Peer, Invoice, Pay, Payment, SendResponse, OnchainSendResponse (txid only; raw tx stays bytes), InvoicePaidEvent, ParsedInvoice. - Kept as Vec<u8>: Credentials::load/save bytes, raw on-chain tx bytes, Peer.features bitfield, DeveloperCert/Signer constructor arguments. list_payments fixes - Unpaid (open) and expired invoices are dropped from list_payments. Only Paid invoices appear as Payment rows on the received side; list_invoices() still surfaces the full invoice list for callers that want to inspect open invoices directly. - Payment.destination is documented as always-None for PaymentType::Received: Lightning's privacy model does not reveal the sender's pubkey to the recipient, and the only pubkey derivable from a paid invoice is the payee (our own node), which is uninteresting per-row. PaymentStatus::Pending stays on the public type — it remains valid for in-flight sent payments. NAPI mirrors synced (Buffer→String everywhere the underlying field became hex), gl-sdk-cli output formatters simplified, NodeExtensions defaults adjusted, and Python + Kotlin tests updated to match.
9eb4939 to
d882300
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Unified node_state() snapshot aggregating get_info, list_peer_channels, and list_funds into a single NodeState record with balances, capacity, utxos, and connected-channel-peer set.
Balance accounting fixes vs. a naive implementation:
reservedfield sourced from CLN's listfunds.outputs[].reserved; node_state() skips reserved outputs.closer(ChannelSide) andstatusto support this gate.Mobile-developer API surface:
Adds ChannelState::is_open and channel_payout_still_pending helpers, NAPI mirror types synced, and refreshes Python + Kotlin NodeState tests to match the new type shape.