132 Commits
Author SHA1 Message Date
ziggie e751d96c13 sqldb: remove unused GetInvoice query 2026-03-04 13:04:26 +01:00
ziggie e2dfd8f034 invoices: add TODO to change the return type of the query 2026-03-04 13:04:26 +01:00
ziggie 0ca69e6f57 invoices/sql: replace catch-all GetInvoice with indexed lookups
The GetInvoice query used an OR IS NULL pattern for each filter
parameter:

  WHERE (i.hash = $1 OR $1 IS NULL)
    AND (i.payment_addr = $2 OR $2 IS NULL)

SQLite's query planner decides on an execution plan at prepare time,
before seeing any parameter values. Because either condition can be
trivially true when its parameter is NULL, the planner conservatively
falls back to a full table scan rather than using the unique indexes on
hash and payment_addr. This caused every invoice lookup and update on
the hot path (HTLC settlement) to scan the entire invoices table.

Replace the single catch-all query with three dedicated queries, each
using a direct equality on a uniquely constrained column:

- GetInvoiceByHash:  WHERE hash = $1
- GetInvoiceByAddr:  WHERE payment_addr = $1  (new, covers AMP path)
- GetInvoiceBySetID: existing, unchanged

Update getInvoiceByRef to route to the appropriate query based on which
fields are present in the InvoiceRef. When both hash and payment address
are provided, we look up by hash and then verify the returned invoice's
payment address matches.

GetInvoice is now unused and removed from the SQLInvoiceQueries
interface.
2026-03-04 13:04:26 +01:00
ziggie 65f6d75511 sqldb: drop redundant and unused invoice indexes
Remove four indexes from the invoices table that either duplicate existing
UNIQUE constraint indexes or are never used in WHERE clauses:

- invoices_hash_idx: redundant, UNIQUE constraint on hash already creates
  an implicit index
- invoices_payment_addr_idx: redundant, UNIQUE constraint on payment_addr
  already creates an implicit index
- invoices_preimage_idx: unused, preimage is NULL on all new invoices and
  is never used as a query filter
- invoices_settled_at_idx: unused, settled_at is NULL on all pending
  invoices and is never used as a query filter (settle_index is used
  instead)

Dropping these reduces B-tree working set size, which improves page cache
utilization as the invoice table grows.
2026-03-04 13:04:26 +01:00
ziggie 74f8f2d9e6 sqldb+payments: add payment_duplicates for legacy duplicate payments
Older LND versions could create multiple payments for the same hash.
We need to preserve those historical records during KV→SQL migration,
but they don’t fit the normal payment schema because we enforce a
unique payment hash constraint. Introduce a lean payment_duplicates
table to store only the essential fields (identifier, amount,
timestamps, settle/fail data).

This keeps the primary payment records stable and makes the migration
deterministic even when duplicate records lack attempt info. The table
is intentionally minimal and can be dropped after migration if no
duplicate payments exist.

For now there is no logic in place which allows the noderunner to
fetch duplicate payments after the migration.
2026-02-25 18:52:32 +01:00
ziggie 2596d34619 paymentsdb+sqldb: add migration related query
Add a migration specific query which allows to set the failure
reason when inserting a payment into the db.
2026-02-25 18:52:31 +01:00
ziggie e9a88267ff paymentsdb: fix duplicate interface check and down migration drop order
- Remove duplicate compile-time interface assertion for SQLStore.

- Fix the down migration to drop payment_intents before payments to
respect the foreign key dependency order. This was not a bug in the
first place bc we have the CASCADE when deleting payments.
2026-02-25 18:36:14 +01:00
ziggie a2cb753428 sqldb: rename 000009_payments to 000010_payments
The 000009 schema version slot is now taken by 000009_graph_v2_columns
which was merged ahead of the payments schema. Bump the payments schema
file number to 000010 to avoid the collision.

Moreover update the migration_dev.go file to reflect this change and
update the order of migration.
2026-02-25 08:02:27 +01:00
ziggie 969b00e4a5 paymentsdb: implement FetchInFlightPayments for sql backend 2026-02-25 08:02:16 +01:00
ziggie ff12082452 paymentsdb: implement DeletePayments for sql backend 2026-02-25 08:02:16 +01:00
ziggie fd6796e561 multi: implement Fail method for sql backend 2026-02-25 08:02:15 +01:00
ziggie 510f6fb532 paymentsdb: implement InitPayment for sql backend 2026-02-25 08:02:09 +01:00
ziggie 0c96a2d722 sqldb+paymentsdb: add queries to insert all relavant data
In this commit we add all queries which we will need to insert
payment related data into the db.
2026-02-25 08:02:09 +01:00
ziggie 3012eb2ca0 paymentsdb: implement DeleteFailedAttempts for sql backend 2026-02-25 08:02:09 +01:00
ziggie 6faf68c5fa paymentsdb: add query to only fetch resolution type for HTLCs 2026-02-25 08:02:08 +01:00
ziggie bdea68bebf sqldb: add queries for deleting a payment and attempts 2026-02-25 08:02:08 +01:00
ziggie 27071acb6b sqldb: Change payment_intent relationship to payment table
Previously a one(intent)-to-many(payment) relationship it is now
changed to a one-to-one relationship because a payment request
only can have 1 payment related to it. Looking into the future
with BOLT12 offers, the fetched invoice from the offer could be
stored here as well and the relationship would still hold.
2026-02-25 08:02:08 +01:00
ziggie e8fe45fe65 paymentsdb: implement QueryPayments for sql backend 2026-02-25 08:02:08 +01:00
ziggie 18e7768837 multi: add relevant queries for QueryPayments implemenation 2026-02-25 08:02:04 +01:00
ziggie e7a3096621 sqldb: add index and comment to payment tables 2026-02-25 08:01:16 +01:00
ziggie dd585a821b sqldb: add payment sql tables
This does not include duplicate payments yet. They will be added
when the migration code is introduced for payments.
2026-02-25 08:01:15 +01:00
Olaoluwa Osuntokun 0b00c66231 Merge pull request #10601 from ziggie1984/invoice-filter-index-optimization
invoices/sql_store: replace catch-all FilterInvoices with targeted index-friendly queries
2026-02-24 16:34:27 -08:00
ziggie 9becdfa8a3 sqldb/sqlc: remove deprecated FilterInvoices query
All call sites have been migrated to the targeted replacement queries
in the previous commit. Remove FilterInvoices and its associated
params struct from the SQL source and regenerate.
2026-02-21 16:58:31 +01:00
ziggie 866efbd7fb sqldb/sqlc: add targeted invoice queries
The existing FilterInvoices query uses optional parameters via the
pattern `(col >= param OR param IS NULL)` for every filter. SQLite
cannot use indexes with this pattern because the OR prevents the query
planner from determining at plan time which rows satisfy the condition,
resulting in a full table scan regardless of the available indexes
(invoices_state_idx, invoices_settle_index_idx, and the primary-key
clustered index on id).

Additionally, the conditional ORDER BY:

  ORDER BY CASE WHEN reverse = FALSE ... THEN id ELSE NULL END ASC,
           CASE WHEN reverse = TRUE  ... THEN id ELSE NULL END DESC

prevents the planner from using the index ordering and forces an
explicit sort.

Add five focused replacements, each with a plain sargable predicate and
a direct ORDER BY so the planner can always choose an index scan:

  - FetchPendingInvoices:        WHERE state IN (0, 3)
  - FilterInvoicesBySettleIndex: WHERE settle_index >= $1
  - FilterInvoicesByAddIndex:    WHERE id >= $1
  - FilterInvoicesForward:       WHERE id >= $1 ... ORDER BY id ASC
  - FilterInvoicesReverse:       WHERE id <= $1 ... ORDER BY id DESC

FilterInvoicesForward and FilterInvoicesReverse accept non-nullable
timestamp parameters (created_after, created_before) so the planner
always sees plain range predicates on created_at. Callers supply
Go-side defaults when no date filter is needed, following the same
convention already used by the payments query.

FilterInvoices is kept in this commit so all existing call sites
continue to compile. It will be removed once all callers have been
migrated.
2026-02-21 16:09:03 +01:00
Elle Mouton 7c7a0ae13d graph/db: fetch policy version in cache paginated query
The ListChannelsWithPoliciesForCachePaginated query was missing the
policy version column, causing extractChannelPolicies to hardcode
lnwire.GossipVersion1 for that row type. Add cp1.version and
cp2.version to the query and use the fetched values instead.
2026-02-20 09:28:13 +02:00
Elle Mouton fc19a24d07 graph/db: version disabled channel IDs
Add a gossip version parameter to DisabledChannelIDs in the Store
interface and both implementations. Add a new version-filtered SQL
query and update the builder caller.
2026-02-20 09:19:23 +02:00
Elle Mouton 677e6ea89c sqldb: use version-specific staleness checks in UpsertChannelPolicy
Update the UpsertChannelPolicy query to apply different staleness
checks based on gossip version. For v1 policies, continue checking
last_update timestamps. For v2 policies, check block_height instead,
using >= comparison to handle policies from the same block.

The version-specific WHERE clause ensures that policy updates are only
applied when they contain newer information according to the versioning
scheme appropriate for that gossip version.
2026-02-13 07:21:24 +02:00
Elle Mouton 0aa93c93e7 graph/db: add v2 policy fields to database layer
Extend channel policy queries and structs to support v2-specific fields:

- Add BlockHeight field to track the block height for v2 policy updates.
- Add DisableFlags field for v2 channel disable messages.

Both fields are nullable (sql.NullInt64/Int16) to maintain backwards
compatibility with v1 channels. The fields are initialized as null in
updateChanEdgePolicy and threaded through all policy-related queries
(GetChannelBySCIDWithPolicies, ListChannelsByNodeID, UpsertEdgePolicy,
etc.) and the extractChannelPolicies helper.

This commit includes both the hand-written SQL query updates and the
corresponding sqlc-generated Go code.
2026-02-13 07:21:23 +02:00
Elle Mouton 6328c4d897 graph/db: treat empty channel signatures as missing
This commit improves handling of missing channel signatures in the
database:

- Return nil from auth proof accessors instead of empty slices so that
  missing signatures are stored as NULL in SQL.
- Update public channel checks to require signature length > 0, which
  properly handles existing empty bytea values in the database.
- Add regression test covering empty v1 and v2 channel signatures to
  prevent future issues.
2026-02-13 07:21:23 +02:00
Elle Mouton a99604c7d7 sqldb/sqlc: add IsPublicV2Node query
Add SQL query to determine if a node has public v2 channels. Unlike
v1 which requires all four individual signatures, v2 channels are
considered public when the single aggregated signature is present.
2026-02-13 07:21:23 +02:00
Elle Mouton 315f5ed741 sqldb/sqlc: add AddV2ChannelProof query
Add SQL query to update the signature column for v2 channel auth proofs.
Unlike v1 which requires four separate signatures, v2 channels use a
single aggregated signature.
2026-02-13 07:21:23 +02:00
Elle Mouton ec46480a86 sqldb/sqlc: update graph CreateChannel query for v2
Add three new optional fields to the CreateChannel SQL query to
support v2 channel announcements:
- signature: single schnorr signature (replaces four ECDSA sigs)
- funding_pk_script: the funding output script
- merkle_root_hash: for taproot channels

These fields are NULL for v1 channels and populated for v2 channels.
2026-02-13 07:21:21 +02:00
Elle Mouton 5a3c013e91 sqldb/sqlc: add NodeExists query 2026-02-13 07:21:20 +02:00
Elle Mouton c61617200b sqldb: update node query for v2
Here we update the UpdateNode query so that it can be used to insert
the new blockheight field for a v2 node.
2026-02-13 07:21:20 +02:00
Elle Mouton cb2fc6621e sqldb: add new gossip v2 columns to graph tables
Add a new migration that updates the graph tables (nodes, channels and
policies) in preparation for the new columns required for V2
announcements. This migration has to be added to the set of "live"
migrations instead of "dev only" since it edits the columns of existing
tables and so changes the existing sql models. We are going to prep the
SQLStore code to handle the V2 types in the coming commits, so we need
this migration to be in place.

In this commit we also remove the TestSchemaMigrationIdempotency test
since this test fails with the new "ALTER TABLE" migrations which dont
have "IF NOT EXISTS" options like tables and indexes do. Migrations
should be idempotent anyways due to the migration tracker file and/or
the sqlc migration tracker.
2026-02-13 07:21:20 +02:00
Abdullahi Yunus ac2cec462c graph: use UNION for isPublicNode query
In this commit we updated the IsPublicV1Node query to use UNION
instead of OR, since sqlite struggles to efficiently use
multiple indexes in a single query involving OR conditions across
different columns.

We use UNION ALL since the query doesn't care about duplicates.
2025-12-23 21:04:36 +01:00
Elle Mouton 8349a6f84d sqldb: add UpsertSelfNode query
This query is less strict in terms of the latest update timestamp field.
We want to be less strict with our own node data since we always want
our own updates recorded.
2025-12-03 13:08:31 +02:00
Elle Mouton 352b4d620a graph/db: freeze sql migration queries 2025-11-12 22:54:06 +08:00
Olaoluwa Osuntokun 31ab2ae4b6 sqldb: implement iterator support for ChanUpdatesInHorizon
In this commit, we update the SQL store implementation to support the
new iterator-based API for ChanUpdatesInHorizon. This includes adding
SQL query pagination support and helper functions for efficient batch
processing.

The SQL implementation uses cursor-based pagination with configurable
batch sizes, allowing efficient iteration over large result sets without
loading everything into memory. The query is optimized to use indexes
effectively and minimize database round trips.

New SQL query GetChannelsByPolicyLastUpdateRange is updated to support:
- Cursor-based pagination using (max_update_time, id) compound cursor
- Configurable batch sizes via MaxResults parameter
- Efficient batch caching with updateChanCacheBatch helper
2025-09-26 16:58:11 -07:00
Olaoluwa Osuntokun c69971c20b sqldb: implement iterator support for NodeUpdatesInHorizon
In this commit, we update the SQL store implementation to support the
new iterator-based API for NodeUpdatesInHorizon. This includes adding a
new SQL query that supports efficient pagination through result sets.

The SQL implementation uses cursor-based pagination with configurable
batch sizes, allowing efficient iteration over large result sets without
loading everything into memory. The query is optimized to use indexes
effectively and minimize database round trips.

New SQL query GetNodesByLastUpdateRange is updated to support:
  * Cursor-based pagination using (last_update, pub_key) compound cursor
  * Optional filtering for public nodes only
  * Configurable batch sizes via MaxResults parameter
2025-09-26 16:57:41 -07:00
Elle Mouton f2ed5564ef graph/db+sqldb: improve performance of chan update sql migration
This commit simplifies insertChanEdgePolicyMig. Much of the logic can be
removed given that this method is only used in the context of the graph
SQL migration.

This should improve the performance of the migration quite a lot since
it removes the extra GetChannelAndNodesBySCID call.
2025-09-01 08:07:57 +02:00
Elle Mouton 22bf88e900 graph/db+sqldb: make policy migration idempotent
Finally, we make the channel-policy part of the SQL migration idempotent
by adding a migration-only policy insert query which will not error out
if the policy already exists and does not have a timestamp that is newer
than the existing records timestamp. To keep the commit simple, a
insertChanEdgePolicyMig function is added which is basically identical
to the updateChanEdgePolicy function except for the fact that it uses
the newly added query. In the next commit, it will be simplified even
more.
2025-09-01 08:06:12 +02:00
Elle Mouton 8736fcafa8 graph/db+sqldb: make channel SQL mig retry-safe
In this commit, we make the channel part of the graph SQL migration
idempotent (retry-safe!). We do this by adding a migration-only channel
insert query that will not error out if a the query is called and a
chanenl with the given scid&version already exists. We also ensure that
errors are not thrown if existing channel features & extra types are
re-added.
2025-09-01 08:05:21 +02:00
Elle Mouton a291d6f1a6 graph/db+sqldb: improve efficiency of node migration
There is no need to use the "collect-then-update" pattern for node
insertion during the SQL migration since if we do have any previously
persisted data for the node and happen to re-run the insertion for that
node, the data will be exactly the same. So we can make use of "On
conflict, no nothing" here too.
2025-09-01 08:02:38 +02:00
Elle Mouton ddea6d59ce graph/db+sqldb: make node migration idempotent
In this commit, the graph SQL migration is updated so that the node
migration step is retry-safe. This is done by using migration specific
logic & queries that do not use the same node-update-constraint as the
normal node upsert logic. For normal "run-time" logic, we always expect
a node update to have a newer timestamp than any previously stored one.
But for the migration, we will only ever be dealing with a single
announcement for a given node & to make things retry-safe, we dont want
the query to error if we re-insert the exact same node.
2025-09-01 07:56:34 +02:00
Oliver Gugger 31fc556507 Merge pull request #10155 from ziggie1984/add-missing-invoice-settle-index
Add missing invoice index for native sql
2025-08-14 09:23:37 -06:00
ziggie ea9fb80eff sqldb: use the new schema
We put this new schema update into the main line and change the
versions of the schema updates which are currently only available
in dev builds. The schemas need to be chronological therefore we
also need to rename the file numbers.
2025-08-14 11:59:09 +02:00
ziggie 506d226eb3 sqldb: add missing index for settled invoices 2025-08-14 08:17:15 +02:00
ziggie 22fbbee837 sqldb: delete wrong index names and add missing one 2025-08-14 08:17:15 +02:00
Elle Mouton 5b06474744 graph/db+sqldb: batch validation for zombie index migration
Finally, we update the migrateZombieIndex function to use batch
validation just like was done in the previous commits. Here, we
additionally make sure to validate the entire zombie index entry and not
just the SCID.
2025-08-14 08:00:07 +02:00