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.
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.
Add a gossip version parameter to HighestChanID in the Store interface
and both KV/SQL implementations. Update callers in the discovery
ChanSeries and server bootstrap code.
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.
Convert testEdgeInfoUpdates and testBatchedUpdateEdgePolicy to run
against both v1 and v2 gossip versions, exercising the versioned
Store methods added in prior commits.
Add a gossip version parameter to the ChannelID method (outpoint to
short channel ID lookup) in the Store interface and both KV/SQL
implementations. Update the VersionedGraph wrapper and tests.
Refactor the createChannelEdge test helper to be version-aware,
supporting both v1 and v2 channel and policy creation. This prepares
the test infrastructure for subsequent commits that version individual
Store methods.
Add a gossip version parameter to ForEachNodeDirectedChannel on the
Store interface and both DB implementations (KVStore, SQLStore). The
NodeTraverser and routing.Graph interfaces remain unversioned since
pathfinding operates on the merged cross-version cache view.
The cache population in populateCache is updated in the same commit
because it is logically atomic with the versioning changes: the graph
cache is the unversioned, merged view used by pathfinding, so it must
be populated with data from all gossip versions. Without this change,
only v1 data would be loaded into the cache, making v2 nodes and
channels invisible to pathfinding.
Add gossip version parameters to ForEachNodeCacheable and
ForEachChannelCacheable in the Store interface and both implementations.
Thread the version through SQL helpers and update call sites/tests
accordingly.
Make fillTestGraph version-aware and update its call sites to pass an
explicit gossip version (currently v1 at these call sites).
This is a test-helper refactor only; cacheable-iteration API versioning
is handled in the next commit.
Introduce gossipV1 and gossipV2 package-level aliases in sql_store.go
to reduce verbosity in version switch statements. Leave hard-coded
v1/v2 call sites untouched so remaining upgrades are obvious.
In other words, it is now easy to see where our remaining work in the
sql_store.go file is by just searching for instances of
`lnwire.GossipVersion1`.
Add a gossip version parameter to ForEachSourceNodeChannel in the Store
interface and both KV/SQL implementations. The VersionedGraph wrapper
delegates with its baked-in version. Convert the
testAddChannelEdgeShellNodes and testForEachSourceNodeChannel tests to
run against both v1 and v2 gossip versions.
Add a channelCacheKey struct keyed by {GossipVersion, chanID}, matching
the pattern already used by rejectCache. This prevents v1 and v2
channel data from colliding in the shared cache.
All callers in KVStore (always GossipVersion1) and SQLStore (version
from context) are updated to pass the version parameter.
This will be needed for later on when we update methods that use this
cache to be versioned (like ChannelUpdatesInHorizon).
Update ForEachNodeChannel to accept a gossip version parameter,
allowing callers to specify which gossip version's channels should be
iterated. This change mirrors the approach taken in ForEachChannel and
prepares the graph database for supporting multiple gossip versions
while maintaining backward compatibility.
The Store interface is updated to include the version parameter, and
both KVStore and SQLStore implementations are updated accordingly:
- KVStore validates that only GossipVersion1 is requested, returning
ErrVersionNotSupportedForKVDB for other versions.
- SQLStore passes the version through to the underlying node query,
enabling version-specific channel iteration.
The ChannelGraph wrapper is updated to accept and pass through the
version parameter. VersionedGraph gains a ForEachNodeChannel method
that automatically uses its configured gossip version, providing a
clean interface for version-specific operations.
Update all call sites to explicitly pass lnwire.GossipVersion1, except
for the local channel manager in server.go which now uses the v1Graph
directly (matching the pattern used in other parts of the codebase).
Convert testEdgePolicyCRUD to a versioned test that runs against both
v1 and v2 gossip versions. Update the test to use version-specific
edge creation helpers and to test version-specific fields and flag
behavior (ChannelFlags/MessageFlags for v1, DisableFlags/
ExtraSignedFields for v2).
Update ForEachChannel to accept a gossip version parameter, allowing
callers to specify which gossip version's channels should be iterated.
This change prepares the graph database for supporting multiple gossip
versions while maintaining backward compatibility.
The KVStore implementation validates that only GossipVersion1 is
requested, returning ErrVersionNotSupportedForKVDB for other versions.
The SQLStore implementation validates known versions and passes the
version through to the underlying paginated query.
Update VersionedGraph to include a ForEachChannel method that
automatically uses its configured gossip version, and update the
DescribeGraph RPC handler to use the v1Graph instead of the global
graphDB.
Add a new HasChannelEdge method that takes a gossip version parameter
and returns only existence and zombie status, without timestamp data.
This supports both v1 and v2 gossip protocols.
The original HasChannelEdge method is renamed to HasV1ChannelEdge to
preserve v1-specific functionality for callers that need timestamp
information. All call sites are updated accordingly.
The SQL store implementation now handles both gossip versions, using
timestamps for v1 and block heights for v2 policies, with proper
reject cache support for both versions.
Make the reject cache version-aware so v1 and v2 policy state can be
cached independently per channel ID. Add helpers to store v1 timestamps
or v2 block heights and thread the versioned cache key through KV/SQL
store cache accesses.
Update buildChanPolicy and related functions in both KV and SQL stores
to properly construct ChannelEdgePolicy with version-specific fields:
KVStore changes:
- Reject non-v1 policies in updateEdgePolicy and serializeChanEdgePolicy
since KV store only supports v1 gossip protocol.
- Set Version to GossipVersion1 when deserializing policies from KV.
SQLStore changes:
- Add isNode1 parameter to buildChanPolicy functions to properly set
SecondPeer field (v2 uses SecondPeer instead of ChannelFlags direction).
- Extract Version from database and populate version-specific fields:
- For v1: MessageFlags, ChannelFlags, LastUpdate, ExtraOpaqueData
- For v2: DisableFlags, LastBlockHeight, ExtraSignedFields
- Thread isNode1 through buildChanPolicyWithBatchData and
buildCachedChanPolicies call sites.
This enables the SQL store to read and reconstruct both v1 and v2
channel policies from the database with proper field mapping.
Add ChanEdgePolicyFromWire to construct ChannelEdgePolicy from channel
update messages, centralizing v1/v2 field mapping.
Update call sites to use the helper:
- discovery/gossiper: handleChanUpdate
- graph/builder: ApplyChannelUpdate
- routing/router_test: ApplyChannelUpdate test helper
This consolidates update-to-policy conversion logic across versions.
Replace MessageFlags and ChannelFlags bitfields in CachedEdgePolicy
with explicit boolean fields to improve clarity and support both v1
and v2 channel updates:
- Replace MessageFlags with HasMaxHTLC boolean.
- Replace ChannelFlags with IsNode1 and IsDisabled booleans.
- Update NewCachedPolicy to extract these fields version-appropriately:
- For v1: derive from MessageFlags and ChannelFlags bits.
- For v2: derive from policy.SecondPeer and policy.DisableFlags.
Update all call sites that used method calls IsNode1() and IsDisabled()
to instead access the fields directly. This includes:
- graph_cache.go: policy direction and disable checks
- unified_edges.go: HasMaxHTLC and IsDisabled checks
- Tests: policy construction and assertions
This refactoring improves readability by making the cached policy's
state explicit rather than encoded in bitfields, and enables seamless
support for both gossip protocol versions.
Extend ChannelEdgePolicy to support v2 channel updates by adding:
- Version field to track gossip protocol version (v1 or v2).
- LastBlockHeight for v2's block-height-based timestamps.
- SecondPeer flag to indicate which peer announced the policy in v2.
- DisableFlags for v2-specific channel disable signaling.
- ExtraSignedFields map for v2 extra signed TLV data.
Add version-aware methods:
- IsNode1() determines if the policy was announced by node_1, handling
both v1 (via ChannelFlags direction bit) and v2 (via SecondPeer).
- IsDisabled() checks disable status using ChannelFlags for v1 and
DisableFlags for v2.
- String() provides version-appropriate string representations.
The new fields use zero values for v1 compatibility (Version defaults
to GossipVersion1, LastBlockHeight to 0, SecondPeer to false). This
lays the groundwork for v2 policy support; a subsequent commit will
handle reading and writing these fields from/to the database.
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.
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.
Make IsZombieEdge version-aware and add corresponding method to
VersionedGraph. Convert TestEdgeInsertionDeletion to versioned test
using the createEdge helper for both v1 and v2 channel testing.
Make channel edge fetching version-aware by adding gossip version
parameter to FetchChannelEdgesByID and FetchChannelEdgesByOutpoint.
Add corresponding methods to VersionedGraph. V2 policy building is
marked as TODO.
Make IsPublicNode version-aware by routing to the appropriate SQL
query based on gossip version. V1 and v2 have different criteria for
determining node publicity (v1 requires four signatures, v2 requires
one). Convert TestNodeIsPublic to versioned test for both protocols.
Add version-aware DeleteChannelEdges method to VersionedGraph and
update call sites in graph builder, rpcserver, and server to use
versioned graphs. This ensures channel deletion operations are
properly scoped to the correct gossip version.
Convert TestPartialNode to a versioned test that runs for both v1 and
v2 gossip versions, ensuring shell node creation works correctly for
both channel types.
Update AddEdgeProof to handle both v1 (four separate signatures) and
v2 (single aggregated signature) channel authentication proofs using
the appropriate SQL queries.
Thread the gossip version through DeleteChannelEdges to enable
version-aware channel deletion. The KVStore rejects non-v1 versions
while SQLStore properly passes the version to the underlying queries.
This prepares for v2 channel zombie handling (strict zombie pruning
for v2 is marked as TODO).
Extend the createEdge test helper to accept a gossip version, enabling
creation of both v1 and v2 test channels. V2 channels include the
appropriate auth proof (single signature), merkle root hash, and
funding script fields.
Extends the SQL store to support v2 (taproot) channel announcements:
- Add version validation in AddChannelEdge
- Store v2-specific fields: FundingPkScript, MerkleRootHash, Signature
- Update buildEdgeInfoWithBatchData to reconstruct v2 channels from DB
with optional bitcoin keys and funding script handling
- Add WithMerkleRootHash edge modifier for ChannelV2Fields
This commit extends ChannelEdgeInfo to support v2 (taproot) channel
announcements by adding:
- MerkleRootHash for the optional Merkle tree commitment
- ExtraSignedFields for additional signed TLV fields
- ChannelV2Fields struct to encapsulate v2-specific optional fields
- NewV2Channel constructor for creating v2 channel edges
- FundingPKScript handling for MuSig2 key aggregation with optional
taproot tweaks
Add FundingPKScript() method that returns the funding output's
pkScript for the channel. The implementation is version-aware:
- V1: generates a 2-of-2 multisig P2WSH script from the two bitcoin
keys
- V2: will use taproot script (to be implemented)
This encapsulates the script generation logic and makes it clear
which bitcoin keys are being used. Replaces direct calls to
genMultiSigP2WSH with the cleaner method call.
Since not all will be required for V2 channels.
Wrap BitcoinKey1Bytes and BitcoinKey2Bytes in fn.Option since these
fields are only required for v1 channel announcements. V2 channels may
or may not have bitcoin keys present in their announcement.
NewV1Channel constructor wraps the bitcoin keys with fn.Some().
All access sites updated to unwrap the options, using UnwrapOr for
non-critical paths and UnwrapOrErr where the keys must be present
(e.g., KV serialization, ToChannelAnnouncement).
So that we have one place that converts from our `models` struct to the
`lnwire.ChannelAnnouncement` struct.
The commit also refactors netann.CreateChanAnnouncement to only take a
ChannelEdgeInfo and get the proof from there instead of needing the
proof to be passed in separately.
Add ToChannelAnnouncement() method to ChannelEdgeInfo that converts
the model struct to a lnwire.ChannelAnnouncement1 message. This:
- Centralizes the conversion logic in one place instead of scattered
across multiple call sites
- Validates that AuthProof is present (can't create announcement
without proof)
- Currently only supports v1 channels, returning error for v2
Refactor netann.CreateChanAnnouncement to use this helper and remove
the separate chanProof parameter since proof is now accessed from
within ChannelEdgeInfo. This improves encapsulation and reduces
parameter count.
This makes it clear what fields must/can be set for a V1 channel.
Introduce NewV1Channel constructor to create v1 channel edges with
proper initialization and validation. The constructor:
- Takes required fields (chanID, chainHash, node keys) as parameters
- Takes v1-specific fields (bitcoin keys, extra opaque data) via
ChannelV1Fields struct
- Accepts optional fields (capacity, channel point, features, proof)
via functional options (WithCapacity, WithChannelPoint, etc.)
- Validates that if an AuthProof is provided, its version matches the
channel version
This makes it clear which fields are required vs optional for v1
channels and prevents incorrectly initialized channel edges. All
tests and production code updated to use the constructor.
Also update it to more closely match the persisted version which has the
v1 and v2 only fields as optional.
Refactor ChannelAuthProof to support both v1 and v2 channel
announcements:
- Add Version field to distinguish v1 from v2 proofs
- Wrap v1-specific fields (NodeSig1/2, BitcoinSig1/2) in fn.Option
since v2 doesn't use them
- Add optional Signature field for v2's single schnorr signature
- Add constructor functions NewV1ChannelAuthProof and
NewV2ChannelAuthProof to enforce correct initialization
- Add getter methods (NodeSig1(), BitcoinSig1(), etc.) that safely
unwrap options, returning empty slices when not present
The IsEmpty() check is updated to handle both versions correctly.
Both stores validate v1-only for now.
And set it to V1 version everywhere.
Add a Version field to ChannelEdgeInfo to distinguish between v1 and
v2 channel announcements. Set it to GossipVersion1 for all existing
channels.
Both KV and SQL stores now validate that only v1 channels are
currently supported, returning an error for v2 channels. The KV store
automatically sets version to v1 when deserializing (since all
persisted channels in KV format are v1).
This versioning is essential for handling the different field
requirements and validation logic between v1 and v2 channels.
Add a version parameter to maybeCreateShellNode to allow callers to
specify which gossip protocol version should be used when creating
shell nodes. Currently all callers pass GossipVersion1, but this
change sets up the foundation for v2 support.
Shell nodes are lightweight node entries containing only a protocol
version and public key, created before full node information is
available.
Replace [33]byte with route.Vertex for NodeKey1Bytes, NodeKey2Bytes,
BitcoinKey1Bytes, and BitcoinKey2Bytes in ChannelEdgeInfo. Since
route.Vertex is defined as [33]byte, this change is functionally
equivalent but provides better type safety and consistency with the
rest of the routing subsystem.
OtherNodeKeyBytes is also updated to return route.Vertex.
Remove the cached parsed signature field and its lazy getter method
from ChannelEdgePolicy. This field was unused throughout the codebase
and the signature is already stored as raw bytes in SigBytes.
The SetSigBytes method is updated to remove the cache invalidation
logic.