Commit graph

238 commits

Author SHA1 Message Date
Oli
8047149c6a
multi: upgrade to btcd v2 modules
Migrate all btcd dependencies to the new per-package v2 modules (wire/v2,
txscript/v2, chaincfg/v2, chainhash/v2, btcutil/v2, psbt/v2, btcec/v2)
introduced by btcd v0.26.0, and pin the tagged ecosystem versions:
btcwallet v0.17.0, neutrino v0.18.0 and lightning-onion v1.4.0.

The bulk of the import rewrite was produced by the scripted diff from
https://github.com/btcsuite/btcd/pull/2547 (followed by 'make rpc'). The
address symbols that moved out of btcutil into the new address package
are imported as btcaddr where a local "address" variable would otherwise
shadow them. The go.mod/go.sum updates and the remaining manual
compilation fixes are folded into this single commit so it builds on its
own (the migration was previously split into a reproducible scripted-diff
plus follow-ups, intended to be squashed on merge).
2026-06-24 10:58:36 -07:00
Erick Cestari
2ae1db83b3
multi: drop tor v2 onion production, keep wire codec faithful
Tor stopped serving v2 onion services in October 2021; lnd should not
produce v2 addresses anymore, but it must still verify signatures on
and re-broadcast peer NodeAnnouncement messages that carry v2 entries.

Stop accepting v2 as configuration input (lncfg), strip the legacy
`--tor.v2` flag from the sample config, and remove the
`tor.OnionHostToFakeIP` helper. Operator entry points (`--externalip`,
`--listen`, `lncli connect`, `lncli wtclient towers add`) fail fast on
a v2 `.onion` string, so upgrading nodes must remove any v2 entry from
`lnd.conf` before lnd will start.

Filter persisted v2 state before use without rewriting on-disk records:
the self-announcement builder strips any v2 entry inherited from the
stored self-node; the watchtower client drops v2 entries from each
persisted tower's address list (skipping the tower entirely if no
non-v2 address remains); the autopilot connector, graph bootstrapper,
and static-channel backup restore paths skip v2 entries before
attempting outbound dials. Restrict the Tor controller's ADD_ONION
path to v3 keys, including the encrypted on-disk legacy-key fallback.

For inbound announcements, keep the wire codec wire-faithful:
`lnwire.WriteOnionAddr`, `graph/db.encodeOnionAddr`, and the matching
decoders round-trip v2 bytes so `DataToSign` reproduces the bytes the
remote peer signed, signature validation succeeds, and the announcement
is persisted to the graph DB and re-broadcast across restarts byte-for-
byte. RPC surfaces continue to expose the full address set so external
tools can independently reproduce and verify the signed bytes.

Add a netann regression test that signs a [v3, v2, ipv4] announcement,
round-trips it through Encode/Decode, verifies the signature, and
confirms the resulting models.Node preserves the v2 entry. Add a
graph bootstrapper test asserting v2 entries are skipped while v3 and
plain TCP entries on the same node still surface as bootstrap
candidates.
2026-05-22 09:42:37 -03:00
Elle Mouton
bfb12b1d81 graph/db: remove address loading from cached node iteration
ForEachNodeCached is now only used for topology-oriented traversal,
so the address-loading option forced one autopilot scoring path to
bypass the in-memory graph cache for data it did not consume. Remove
the withAddrs parameter and the associated SQL/KV address plumbing
so cached node iteration can consistently use the graph cache when
it is loaded.

Autopilot still requires peer addresses before opening channels.
That filtering remains in Agent.openChans via ForEachNode, where the
selected candidates' addresses are collected for ConnectToPeer. The
trade-off is that ForEachNodesChannels no longer excludes
addressless nodes from graph-wide scoring inputs such as median
channel size or centrality, which also feed lncli getnetworkinfo
statistics like graph diameter. In practice the only addressless
nodes our local view tends to know about are nodes with no public
channels (e.g. our own node or peers we share only private channels
with), so the impact on the reported stats should be negligible.
Active channel candidates remain address-filtered before dialing.
2026-05-07 16:29:12 -07:00
Elle Mouton
ebb199d215
graph/db: fix FetchChannelEdgesByID zombie fallback versioning
The zombie fallback in SQLStore.FetchChannelEdgesByID unconditionally
constructed a models.NewV1Channel regardless of the requested gossip
version. Use the passed version to select the correct constructor so
that v2 zombie edges carry the right version.

A new testFetchZombieEdgeVersioning versioned test verifies that
zombie edges returned by FetchChannelEdgesByID have the correct
gossip version for both v1 and v2.
2026-04-09 10:45:49 +05:45
Elle Mouton
12f8e50958
graph/db: add gossip version parameter to FilterKnownChanIDs
Add an explicit lnwire.GossipVersion parameter to FilterKnownChanIDs
on the Store interface, SQLStore, KVStore, and ChannelGraph. Since
FilterKnownChanIDs is always called from a version-scoped ChanSeries
context, a single version parameter is cleaner than per-item version
reads. A convenience wrapper on VersionedGraph preserves the existing
ChanSeries call-site signature by threading c.v automatically.
2026-04-09 10:45:49 +05:45
Elle Mouton
bcadafa1ab
graph/db: parameterize forEachChanInSCIDList with gossip version
Replace the hardcoded GossipVersion1 in forEachChanInSCIDList with an
explicit version parameter so the helper can be used for v2 channel
lookups. The caller in FilterKnownChanIDs now passes the version
through.
2026-04-09 10:04:09 +05:45
Elle Mouton
561edf8c96
sqldb/sqlc: split public-only node horizon query and upgrade channel indexes
Split GetNodesByLastUpdateRange into two query variants: one for all
nodes and a new GetPublicNodesByLastUpdateRange for public-only nodes.
The public-only variant uses two separate EXISTS checks (one per
node_id column) instead of a single OR, allowing the planner to do
direct index probes on each channel node-id index.

Also upgrade the channel node-id indexes from single-column
(node_id_1) and (node_id_2) to composite (node_id_1, version) and
(node_id_2, version) to support version-aware public node checks
while preserving usefulness for node-centric lookups.
2026-03-31 12:04:24 +02:00
Elle Mouton
7f5be5a494
graph/db: add v2 block-height path for ChanUpdatesInHorizon
Add GetChannelsByPolicyBlockRange SQL query and wire it into
SQLStore.chanUpdatesInHorizonV2. This mirrors the existing v1
time-based query but filters on policy block_height instead of
last_update, using the same [start, end) exclusive-end semantics
and (max_block_height, channel_id) compound cursor pagination.

Also adds extractMaxBlockHeight helper (returns the max of both
policies' block heights for cursor tracking) and
buildChannelFromBlockRangeRow (structurally identical to the v1
variant but accepts the distinct sqlc-generated row type). The
extractChannelPolicies type-switch is extended with a case for the
new GetChannelsByPolicyBlockRangeRow type.
2026-03-31 09:14:49 +02:00
Elle Mouton
c14a79c0ae
graph/db: add v2 block-height path for NodeUpdatesInHorizon
Add GetNodesByBlockHeightRange SQL query and wire it into
SQLStore.nodeUpdatesInHorizonV2. This mirrors the existing v1
time-based query but filters on (version, block_height) instead of
last_update, using the same [start, end) exclusive-end semantics
and (block_height, pub_key) compound cursor pagination.

The public-node filter for v2 checks for channels with a non-empty
channel announcement signature (c.signature), matching the v2
protocol's public channel indicator.
2026-03-31 09:14:49 +02:00
Elle Mouton
497d479440
graph/db: version NodeUpdatesInHorizon and ChanUpdatesInHorizon
Replace the (startTime, endTime time.Time) parameters on
NodeUpdatesInHorizon and ChanUpdatesInHorizon with
(v GossipVersion, r NodeUpdateRange/ChanUpdateRange). The range
types enforce version-correct bounds at the type level: v1 uses unix
timestamps, v2 will use block heights.

The KV store rejects non-v1 versions since it only stores v1 data.
The SQL store dispatches to version-specific helpers
(nodeUpdatesInHorizonV1, chanUpdatesInHorizonV1); the v2
block-height paths return an error for now and will be wired up in
follow-up commits.

VersionedGraph wrappers supply the version from the embedded field,
so callers only pass the range.
2026-03-31 09:14:49 +02:00
Elle Mouton
57a32b9232
graph/db: use exclusive end time for horizon queries per BOLT 07
BOLT 07 specifies that gossip_timestamp_filter range semantics are
"greater or equal to first_timestamp, and less than first_timestamp
plus timestamp_range", i.e. [start, end). Three of the four
implementations (KV ChanUpdatesInHorizon, KV NodeUpdatesInHorizon,
SQL NodeUpdatesInHorizon) were incorrectly using an inclusive end
time (<= instead of <). Only SQL ChanUpdatesInHorizon was correct.

This commit fixes the KV store's fetchNextChanUpdateBatch and
fetchNextNodeBatch to use >= (instead of >) for the end time break
condition, and < (instead of <=) for the hasMore check. It also
fixes the SQL GetNodesByLastUpdateRange query to use < instead of <=
on the end_time bound.

All godocs are updated to reference the BOLT 07 spec language and
explicitly document the [start, end) range semantics. New dedicated
tests (TestNodeUpdatesInHorizonExclusiveEnd and
TestChanUpdatesInHorizonExclusiveEnd) verify that items at exactly
the end time are excluded while items at the start time are included.
2026-03-31 09:14:48 +02:00
Elle Mouton
0806a27abc
graph/db: honor taproot feature bit in v1 funding script construction
Fix FundingPKScript() to check for the taproot staging feature bit on
v1 channel edges. When present, reconstruct a taproot funding script
via GenTaprootFundingScript instead of the legacy P2WSH multisig.

This is a pre-existing bug: private taproot channels have always been
stored as v1 gossip objects with the taproot feature bit, but
FundingPKScript() never checked for it. The discovery/gossiper layer
(makeFundingScript) already handled this correctly on the insertion
path, but any read path that called FundingPKScript() -- notably
ChannelView() used for chain filter reconstruction on restart --
would produce the wrong script.

Update the tests from the previous commit to assert the correct
taproot funding script instead of the legacy P2WSH script.
2026-03-27 14:19:18 +02:00
Elle Mouton
4ae4c70307
graph/db: version ChannelView and add v2 queries
Add a gossip version parameter to ChannelView in the Store interface,
KV and SQL implementations, and the ChannelGraph wrapper. The KVStore
guards v2 requests with ErrVersionNotSupportedForKVDB; the SQLStore
filters by the requested version.

Add three new SQL queries to support version-scoped channel lookups:

  - GetPublicV1ChannelsBySCID: public v1 channels in a SCID range,
    ordered by SCID.
  - GetPublicV2ChannelsBySCID: public v2 channels in a SCID range,
    ordered by SCID.
  - ListChannelsPaginatedV2: paginate v2 channels by internal DB ID,
    used by ChanUpdateRange.

Add TestVersionedDBs/channel_view to verify that v1 and v2 channel
views each return only their respective channels.
2026-03-16 11:29:41 +02:00
Elle Mouton
8a7afc1bac
multi: version ForEachNode, ForEachNodeCached, NumZombies
Add a gossip version parameter to ForEachNode, ForEachNodeCached, and
NumZombies in the Store interface and propagate it through the KV and
SQL implementations and the ChannelGraph wrapper.

The KVStore gates each method against GossipVersion1, returning
ErrVersionNotSupportedForKVDB for any other version. The SQLStore uses
the version to filter the underlying queries.

All call sites—routing graph, autopilot, RPC server, and the graph
migration integration test—are updated to pass the appropriate version
explicitly.
2026-03-16 11:29:41 +02:00
Elle Mouton
3c06daed8b
graph/db: version FilterChannelRange
Add a gossip version parameter to FilterChannelRange in the Store interface,
both KV and SQL implementations, and the ChannelGraph wrapper.

KVStore guards against non-v1 versions with ErrVersionNotSupportedForKVDB.
SQLStore accepts any known gossip version, filtering the channel results by
version and using it in policy lookups. The SQL query still uses
GetPublicV1ChannelsBySCID for now (a TODO marks where a version-aware query
will be substituted in a follow-up).

VersionedGraph.FilterChannelRange shadows the ChannelGraph method with a
version-free signature, passing its baked-in version to the store. This keeps
the ChannelGraphTimeSeries interface and ChanSeries implementation unchanged.

Add TestFilterChannelRangeVersionGuard to verify that the KV store returns
ErrVersionNotSupportedForKVDB for v2 requests while the SQL store handles
them gracefully.
2026-03-16 11:29:40 +02:00
Elle Mouton
23288dce6f
graph/db: version MarkEdgeZombie
Add a gossip version parameter to MarkEdgeZombie in the Store interface,
both KV and SQL implementations, and the ChannelGraph wrapper, following
the same pattern established for MarkEdgeLive.

KVStore guards against non-v1 versions with ErrVersionNotSupportedForKVDB.
SQLStore accepts any known gossip version and uses it in the UpsertZombieChannel
call and cache invalidation.

Builder.MarkZombieEdge (the ad-hoc path for validation failures) passes
GossipVersion1 as all channels in that path are v1.
2026-03-16 11:29:40 +02:00
Elle Mouton
2a9a431516
graph/db: rework ChannelUpdateInfo to use lnwire.Timestamp
Replace the separate Node1UpdateTimestamp/Node2UpdateTimestamp (time.Time)
and Node1BlockHeight/Node2BlockHeight (uint32) fields in ChannelUpdateInfo
with a unified Node1Freshness/Node2Freshness pair typed as lnwire.Timestamp.

The lnwire.Timestamp interface (added in the previous commit) is either a
UnixTimestamp (v1) or BlockHeightTimestamp (v2), making it structurally
impossible to pass block-height values into a v1 constructor or vice versa.

Two version-specific constructors replace the old single constructor:
  - NewV1ChannelUpdateInfo(scid, node1Time, node2Time time.Time)
  - NewV2ChannelUpdateInfo(scid, node1BlockHeight, node2BlockHeight uint32)

Add Node1FreshnessTime/Node2FreshnessTime helper methods on ChannelUpdateInfo
to extract the underlying time.Time from a UnixTimestamp, which the discovery
syncer needs for its v1-only isStale/isSkewed and isStillZombieChannel checks.

All call sites in kv_store, sql_store, graph_test, and syncer are updated
accordingly.
2026-03-16 11:25:32 +02:00
Elle Mouton
08823ac079
graph/db: version FilterKnownChanIDs callback
Change the isZombieChan callback in FilterKnownChanIDs (and its
ChannelGraphTimeSeries interface counterpart) from
func(time.Time, time.Time) bool to func(ChannelUpdateInfo) bool.

This allows callers to make version-aware zombie decisions using the full
ChannelUpdateInfo—including freshness type—rather than two raw time.Time
values that are meaningless for v2 channels.

The GossipSyncer adapts its v1-only isStillZombieChannel check by
wrapping it in a closure that extracts Node1/Node2FreshnessTime from the
ChannelUpdateInfo. All other call sites are updated accordingly.
2026-03-16 11:25:31 +02:00
Elle Mouton
e9eff6297f
graph/db: version MarkEdgeLive
Add a gossip version parameter to MarkEdgeLive throughout the stack:

- Store interface and KVStore/SQLStore implementations now take
  lnwire.GossipVersion; KVStore rejects non-v1 with
  ErrVersionNotSupportedForKVDB, SQLStore uses the version in the
  DeleteZombieChannel query and cache invalidation.
- ChannelGraph.MarkEdgeLive passes the version through to both the
  store call and the FetchChanInfos cache repopulation.
- FilterKnownChanIDs uses GossipVersion1 explicitly for its internal
  MarkEdgeLive call; this site will be properly versioned when
  FilterKnownChanIDs itself is versioned.
- graph.ChannelGraphSource interface and Builder.MarkEdgeLive updated
  accordingly.
- Discovery gossiper and test mock updated to pass GossipVersion1 at
  their (v1-only) call sites.
2026-03-16 11:25:31 +02:00
Elle Mouton
0bb0d66952
graphdb: pass context to GraphSession 2026-02-25 16:11:46 +02:00
Elle Mouton
8722a96a4e
graphdb: pass context to IsClosedScid 2026-02-25 16:11:46 +02:00
Elle Mouton
4dcaf1c16a
graphdb: pass context to PutClosedScid 2026-02-25 16:11:46 +02:00
Elle Mouton
68c5206017
graphdb: pass context to AddEdgeProof 2026-02-25 16:11:46 +02:00
Elle Mouton
3dc2efd7f3
graphdb: pass context to DisconnectBlockAtHeight 2026-02-25 16:11:46 +02:00
Elle Mouton
a31c86b0ee
graphdb: pass context to PruneTip 2026-02-25 16:11:46 +02:00
Elle Mouton
9f855175d5
graphdb: pass context to ChannelView 2026-02-25 16:11:46 +02:00
Elle Mouton
7dbaa691c4
graphdb: pass context to PruneGraph 2026-02-25 16:11:46 +02:00
Elle Mouton
13668ce45f
graphdb: pass context to PruneGraphNodes 2026-02-25 16:11:46 +02:00
Elle Mouton
072244ee18
graphdb: pass context to FilterKnownChanIDs 2026-02-25 16:11:46 +02:00
Elle Mouton
46d37a691f
graphdb: pass context to FetchChanInfos 2026-02-25 16:11:46 +02:00
Elle Mouton
f62ea62cfe
graphdb: pass context to IsPublicNode 2026-02-25 16:11:42 +02:00
Elle Mouton
397330cbdb
graphdb: pass context to ChannelID 2026-02-25 16:11:29 +02:00
Elle Mouton
3079c07afb
graphdb: pass context to HasChannelEdge 2026-02-25 16:11:29 +02:00
Elle Mouton
87ed09a829
graphdb: pass context to HasV1ChannelEdge 2026-02-25 16:11:29 +02:00
Elle Mouton
1d4c6aadb4
graph/db: thread context through FetchChannelEdgesByOutpoint 2026-02-25 16:11:29 +02:00
Elle Mouton
6bbb9a32fc
graph/db: thread context through FetchChannelEdgesByID 2026-02-25 16:11:25 +02:00
Elle Mouton
acdef84d30
graph/db: thread context through DeleteChannelEdges 2026-02-25 15:33:59 +02:00
Elle Mouton
37cc6b29d9
graph/db: thread context through NumZombies 2026-02-25 15:33:34 +02:00
Elle Mouton
f98905ae99
graph/db: thread context through IsZombieEdge 2026-02-25 15:33:34 +02:00
Elle Mouton
8a96e5f3d2
graph/db: thread context through MarkEdgeLive 2026-02-25 15:33:34 +02:00
Elle Mouton
c270367071
graph/db: thread context through MarkEdgeZombie 2026-02-25 15:33:34 +02:00
Elle Mouton
bb38aa8922
graph/db: thread context through FilterChannelRange 2026-02-25 15:33:34 +02:00
Elle Mouton
e8e714f6a3
graph/db: thread context through ForEachChannelCacheable 2026-02-25 15:33:34 +02:00
Elle Mouton
dc9dae8dd6
graph/db: thread context through ChanUpdatesInHorizon 2026-02-25 15:33:34 +02:00
Elle Mouton
6ccf93c2c9
graph/db: thread context through ForEachNodeDirectedChannel 2026-02-25 15:33:34 +02:00
Elle Mouton
2f0d2962dd
graph/db: thread context through NodeUpdatesInHorizon 2026-02-25 15:33:34 +02:00
Elle Mouton
0597250ae4
graph/db: thread context through DisabledChannelIDs 2026-02-25 15:33:33 +02:00
Elle Mouton
b1873e63ec
graph/db: thread context through FetchNodeFeatures 2026-02-25 15:32:05 +02: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
acb3240d3d
graph/db: version fetch chan infos
Add a gossip version parameter to FetchChanInfos in the Store interface
and both KV/SQL implementations. Update the graph builder caller and
refactor related tests.
2026-02-20 09:28:13 +02:00