Commit Graph
407 Commits
Author SHA1 Message Date
Elle Mouton 7bb38651d9 graph/db: convert other node CRUD methods
Convert a few more CRUD methods to handle v2 nodes. Then update some
more tests to be run against both v1 and v2 nodes.
2026-02-13 07:21:21 +02:00
Elle Mouton 7a5a588176 graph/db: add TestVersionedDBs
This will be used to run sub-tests with v2 data.
2026-02-13 07:21:21 +02:00
Elle Mouton d2b47cdbae graph/db: let node helpers take version 2026-02-13 07:21:21 +02:00
Elle Mouton 4db5198079 graph/db: introduce VersionedGraph
For now, all instances will use V1 only so as not to change behaviour
yet.
2026-02-13 07:21:21 +02:00
Elle Mouton d8337be968 graph/db: add helper variable for tests
Add an isSQLDB variable that will let us quickly check in tests if the
backing DB is KVStore or SQLStore.
2026-02-13 07:21:21 +02:00
Elle Mouton c281810ab9 graph/db: move gossip versions up one layer
Update some of the node related graph CRUD methods to take a version
rather than hardcoding them in the SQLStore layer. Move the version up
one layer instead. This will make it easier to make it configurable
later on.
2026-02-13 07:21:20 +02:00
Elle Mouton 97143a74ab graph/db: split HasNode into two methods
HasNode currently is very v1 specific since it returns a time.Time
timestamp which is specific to V1 node announcements. However, it is
mostly only used for the "exists" return value. So here we split it up
into HasNode which just checks existence and HasV1Node which retains the
same behavaiour as before.
2026-02-13 07:21:20 +02:00
Elle Mouton 1738e0cabc graph/db: allow v2 nodes
Update the SQLStore node writer and readers to handle V2 ndoes.
Currently no logic will actually add such nodes. The following commits
will update what is needed so that CRUD for v2 nodes can be tested.
2026-02-13 07:21:20 +02:00
Elle Mouton 628b89cc40 graph/db: explicit redirect to Store
Instead of embedding Store in ChannelGraph so that any methods of the
Store interface not implemented by the ChannelGraph are redirected to
the underlying Store, we update things in this commit to instead
make the "redirection" explicit. This is in preparation for changes we
will make soon where some underlying store methods will take an explicit
"version" parameter but then we will keep the ChannelGraph methods as is
so that existing call-sites dont all need to be updated. We will then
add "Versioned" ChannelGraph wrapper which decides the version use.
Initially, most call-sites will just create a wrapped V1 ChannelGraph so
that the logic remains as it is today.
2026-02-13 07:21:20 +02:00
Elle Mouton 3dfc835354 graph/db: add V2 Node constructor
We add a new NewV2Node constructor which takes a new NodeV2Fields as a
parameter. This NodeV2Fields struct defines the fields that can be set
in a models.Node if the version is V2.
2026-02-13 07:21:20 +02:00
Elle Mouton bc76383e15 graph/db: rename V1Store to Store
The underling store will store gossip messages across gossip versions
and we will instead expose version parameters on many of the methods. So
this interface really just abstracts the underlying store/schema type.
2026-02-13 07:21:20 +02:00
Olaoluwa Osuntokun 56a7f45b99 graphdb: fix backwards-compat for channel edge feature deserialization
This commit fixes a backwards compatibility issue that prevented nodes
from upgrading from v0.19.x to v0.20.x.

In v0.19.x, channel edge features were serialized as raw feature bytes
without a length prefix. In v0.20.x (commit 2f2845dfc), the serialization
changed to use Features.Encode() which adds a 2-byte big-endian length
prefix before the feature bits. The deserialization code was updated to
use Features.Decode() which expects this length prefix.

When v0.20.x reads a database created by v0.19.x, Decode() tries to read
a length prefix that doesn't exist, causing an EOF error:

    unable to decode features: EOF

The fix adds a deserializeChanEdgeFeatures() helper that detects which
format is being read and decodes accordingly:

- New format (v0.20+): First 2 bytes encode the length of the remaining
  bytes. Detected when uint16(bytes[0:2]) == len(bytes)-2.

- Legacy format (pre-v0.20): Raw feature bits without length prefix.
  Uses DecodeBase256 with the known length.

The format detection is safe because in the legacy format, the first byte
always has at least one bit set (the serialization uses minimum bytes),
so the first two bytes can never encode a value equal to len-2.

Fixes #10528.
2026-02-03 09:12:04 -08:00
ziggie c78a75f5d8 graphdb: reduce log noise from WRN to DBG 2026-01-21 20:25:08 +01:00
Abdullahi Yunus 86cde4b93f graphdb: add benchmark for isPublicNode query
In this commit we add a benchmark to test the performance of
IsPublicNode query.
2025-12-23 21:04:36 +01:00
ziggie 2d25bce1bf graphdb: fix potential sql tx exhaustion
We should avoid taking the lock of a mutex inside transaction.
Currently we also take this lock in other places and there is a
chance that in case the application lock aquires the lock but
all transactions are already blocked waiting for the mutex to
unlock, we end up in a deadlock.
2025-12-09 11:51:46 +01:00
Elle bc670fab82 Merge pull request #10396 from ziggie1984/enhance-lsp-heuritic
Enhance Lsp Heuristic when probing a payment
2025-12-09 10:43:43 +02:00
Elle Mouton 9f715555c4 graph/db: fix race in DisconnectBlockAtHeight cache access
The DisconnectBlockAtHeight method was modifying the rejectCache and
chanCache without holding the cacheMu lock. This caused races with
other operations that properly held the lock, such as AddChannelEdge
which modifies the caches in its OnCommit callback while the batch
scheduler holds cacheMu.

Fix by acquiring cacheMu before removing channels from the caches.
2025-12-08 11:56:36 +02:00
Elle Mouton 31b3e7424d graph/db/models: fix race conditions in ChannelEdgeInfo
Both NodeKey1 and NodeKey2 methods had the same race condition as the
Node.PubKey method, where concurrent calls could race to write to the
cached fields.

Remove the caching for the same reasons: parsing overhead is minimal
and doesn't justify the complexity and race risk.
2025-12-08 11:56:36 +02:00
Elle Mouton 9906e61774 graph/db/models: fix race condition in Node.PubKey
The PubKey method had a race condition where concurrent calls could
all pass the nil check and race to write to the cached pubKey field.
This is a classic check-then-act race.

Remove the caching entirely to fix the race. The overhead of parsing
a public key is minimal and doesn't justify the added complexity and
race risk of caching.
2025-12-08 11:56:35 +02:00
Elle Mouton c04aa655b9 graph/db: fix SetSourceNode race with lenient upsert
This commit fixes a race condition where multiple goroutines call
SetSourceNode concurrently during startup, causing sql.ErrNoRows
errors. The race occurs when multiple code paths (setSelfNode,
createNewHiddenService, RPC updates) read the same old timestamp,
independently increment it to the same new value (T+1), and race to
write.

The fix uses the new UpsertSourceNode SQL query (without strict
timestamp constraint) instead of UpsertNode. This allows
last-write-wins semantics for our own node, ensuring all parameter
changes persist even when timestamps collide.

Refactored sql_store.go for reusability:
- upsertNodeAncillaryData: common logic for features/addresses/extras
- populateNodeParams: common parameter building with callback pattern
- buildNodeUpsertParams: builds params for strict UpsertNode
- buildSourceNodeUpsertParams: builds params for lenient UpsertSourceNode
- upsertSourceNode: new function using lenient query

Updated TestSetSourceNodeSameTimestamp to verify that concurrent
updates with the same timestamp now succeed and parameter changes
persist.

Fixes the itest error:
"unable to upsert source node: upserting node(...): sql: no rows in
result set"
2025-12-03 13:08:31 +02:00
Elle Mouton 41615f74a5 graph/db: add test for SetSourceNode same timestamp behavior
This commit adds TestSetSourceNodeSameTimestamp to demonstrate the
current behavior when SetSourceNode is called with the same last update
timestamp. The test reveals a difference between the SQL and bbolt
implementations:

- SQL store returns sql.ErrNoRows when attempting to update with the
  same timestamp, as the upsert query's UPDATE clause requires the new
  timestamp to be strictly greater than the existing one
- bbolt store silently ignores stale updates and returns no error

This behavior is important to document because our own node
announcements may change quickly with the same timestamp, unlike
announcements from other nodes where same timestamp typically means
identical parameters.
2025-12-03 13:08:30 +02:00
ziggie 06886e71b2 graph/db: fix HasNode comment
The comment was incorrectly referring to HasLightningNode but the
function is named HasNode. Update the comment to match the actual
function name.
2025-11-29 01:04:25 +01:00
ziggie 5225b9bbbc graph: add regression test for the fixed behaviour 2025-11-19 16:09:33 +01:00
ziggie 575766c5f4 graph: fix graph cache population for channels with both policies disabled
Fix a bug where channels with both policies disabled were not added to
the graph cache during startup. When a policy update later re-enabled
one of the directions, the update would succeed in the database but fail
to update the graph cache (since the channel structure was never added),
preventing the channel from being used for routing.
2025-11-19 10:12:08 +01:00
Elle Mouton 352b4d620a graph/db: freeze sql migration queries 2025-11-12 22:54:06 +08:00
Elle Mouton 125325f625 multi: freeze graph SQL migration logic
Copy over all the code that the graph SQL migration needs to a
separate folder. This will let us advance the main graph SQL CRUD code
without worrying about changing the sql migration code. It will also let
us change the SQL queries without changing the migration. In this
commit, only the migration logic is "frozen" but in an upcoming commit,
the sqlc queries & models will be frozen too.
2025-11-12 22:54:05 +08:00
Elle Mouton 07d0f0842c graph/db: remove TestPopulateViaMigration
This tests was a temporary helper to let devs test the graph SQL
migration before it was plugged in to LND. But that migration has now
shipped and so we can remove this.
2025-11-12 22:54:05 +08:00
Elle Mouton 33c3809e4b graph/db: remove outdated comment 2025-11-12 22:54:05 +08:00
Elle Mouton 855e579c3f graph: remove DB interface 2025-11-12 22:54:05 +08:00
Elle Mouton edc021f711 graph/db: simplify auth proof and edge info
Remove various unused fields and methods.
2025-11-12 22:54:05 +08:00
Elle Mouton 80e70096cb multi: add models.Node V1 constructor
Add a version field to models.Node and a V1 constructor for it.
2025-11-12 22:54:05 +08:00
Elle Mouton 8f205e2d1c multi: remove HaveNodeAnnouncement field from Node
Remove the 2 sources of truth here. If we have a signature for the
node, then we have the announcement.
2025-11-12 22:54:04 +08:00
Elle Mouton a394938dfd models: simplify models.Node
Simplify the struct by removing un-used methods and outdated comments.
2025-11-12 22:54:04 +08:00
Elle Mouton b57714b00c graph/db: use lnwire.GossipVersion instead of ProtocolVersion 2025-11-12 22:54:03 +08:00
Elle Mouton eb67757a07 graph/db: gracefully handle duplicate channel policy announcements 2025-10-06 11:37:39 +02:00
Elle Mouton abb9654856 graph/db: gracefully handle duplicate node announcements
It can happen that we are handling 2 of the same node announcements in
the same batch transaction. In that case, our `UpsertNode` conflict
assertion may fail. We need to handle this gracefully.
2025-10-06 11:28:33 +02:00
Elle Mouton 14cf937419 graph: fix log formatting 2025-10-06 10:59:39 +02:00
Elle Mouton b8abe130a5 multi: rename lnwire.NodeAnnouncement
In preparation for adding a NodeAnnouncement2 struct along with a
NodeAnnouncement interface, this commit renames the existing
NodeAnnouncment struct to NodeAnnouncement1.
2025-10-01 13:13:32 +02:00
Olaoluwa Osuntokun f3a8fd842d graph+discovery: update graph/db gossip backlog interfaces to use iter.Seq2
This lets us emit a rich error if things fail when first creating the
iterator, or if any of the yield attempts fail.
2025-09-26 17:01:11 -07:00
Olaoluwa Osuntokun 32528afa0a graph/db: add tests for iterator implementations 2025-09-26 16:58:41 -07: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
Olaoluwa Osuntokun 069888b51a graph/db: convert ChanUpdatesInHorizon to use iterators
In this commit, we refactor the ChanUpdatesInHorizon method to return
an iterator instead of a slice. This change significantly reduces
memory usage when dealing with large result sets by allowing callers to
process items incrementally rather than loading everything into memory
at once.
2025-09-26 16:57:11 -07:00
Olaoluwa Osuntokun 1d6d54e5db graph/db: convert NodeUpdatesInHorizon to use iterators
In this commit, we refactor the NodeUpdatesInHorizon method to return
an iterator instead of a slice. This change significantly reduces
memory usage when dealing with large result sets by allowing callers to
process items incrementally rather than loading everything into memory
at once.

The new implementation uses Go 1.23's iter.Seq type to provide a
standard iterator interface. The method now supports configurable batch
sizes through functional options, allowing fine-tuned control over
memory usage and performance characteristics.

Rather than reading all the entries from disk into memory (before this
commit, we did consult the cache for most entries, skipping the disk
hits), we now expose a chunked iterator instead.

We also make the process of filtering out public nodes first class. This
saves many newly created db transactions later.
2025-09-26 16:56:41 -07:00
Olaoluwa Osuntokun f8ce00b84a graph/db: add options infrastructure for iterator configuration
In this commit, we introduce a new options pattern for configuring
iterator behavior in the graph database. This includes configuration
for batch sizes when iterating over channel and node updates, as well
as an option to filter for public nodes only.

The new functional options pattern allows callers to customize iterator
behavior without breaking existing APIs. Default batch sizes are set to
1000 entries for both channel and node updates, which provides a good
balance between memory usage and performance.
2025-09-26 16:56:20 -07:00
Elle Mouton f2fa0a4da6 graph/db: fix type name 2025-09-04 17:10:44 +02:00
Yong e46c676894 Merge pull request #10162 from ellemouton/graphMigUnwrapDNSAddrs
graph/db: unwrap dns addresses from opaque ones during migration
2025-09-04 22:29:49 +08:00
Elle d9647f8b79 Merge pull request #10193 from ellemouton/fixSQLStrHelper
sqldb: fix SQLStr helper
2025-09-04 12:07:25 +02:00
Elle Mouton 40b279687f sqldb: add SQLStrValid helper
The SQL* helpers are meant to always set the `Valid` field of the
sql.Null* type to true. Otherwise they cannot be used to set a valid,
empty field. However, we dont want to break the behaviour of the
existing SQLStr helper and so this commit adds a new helper with the
desired functionality.
2025-09-03 15:46:11 +02:00
Elle Mouton 6e98b336f6 graph/db+channeldb: rename test helper 2025-09-03 10:14:35 +02:00