This commit adds detailed documentation for the automated backport
workflow and updates the contribution guidelines to reference it.
New documentation (docs/backport-workflow.md):
- Complete overview of the automated backport process
- Step-by-step usage instructions with examples
- Detailed explanation of workflow triggers and label format
- Technical details about workflow implementation
- Conflict resolution procedures and best practices
- Multiple backport scenarios and examples
- Comprehensive troubleshooting guide
Updated contribution guidelines (docs/code_contribution_guidelines.md):
- Replaced detailed backport instructions with brief overview
- Added reference to the new detailed documentation
- Keeps contribution guidelines focused and concise
The detailed documentation provides:
- How to use backport labels correctly
- What happens when labels are added before/after merge
- How the workflow validates branches and handles errors
- Step-by-step conflict resolution instructions
- Solutions for common problems and edge cases
- Examples of valid vs invalid label formats
This documentation ensures contributors and maintainers have clear
guidance on using the automated backport workflow effectively.
This commit introduces an automated GitHub Actions workflow to streamline
the backporting process for merged PRs from master to release branches.
Key features:
- Triggers on merged PRs with labels matching 'backport-v*' pattern
(e.g., backport-v0.20.x-branch)
- Validates that target branches exist before attempting backport
- Creates separate backport PRs for each target branch
- Automatically adds 'no-changelog' label to backport PRs
- Handles merge conflicts by creating draft PRs with conflict markers
- Supports multiple simultaneous backports via multiple labels
Workflow steps:
1. Checkout repository with full git history
2. Validate all target branches exist in the remote repository
3. For each valid backport label:
- Create a new branch (backport-<pr-num>-to-<target-branch>)
- Cherry-pick commits from the master PR
- Create a new PR targeting the release branch
- Link back to the original PR
4. If conflicts occur, create a draft PR for manual resolution
Label format:
- Valid: backport-v0.20.x-branch, backport-v0.19.x-branch
- Invalid: backport candidate, backport-candidate, backport-needed
This automation reduces manual work and ensures consistency in the
backporting process while maintaining full visibility and control
for maintainers.
Fix a race condition where forwarding through a public zero-conf channel
could fail with UnknownNextPeer when using the confirmed SCID. The issue
occurred because ReportShortChanID (which updates the switch's baseIndex
to handle the confirmed SCID) was called AFTER addToGraph (which announces
the confirmed SCID to the network).
With slow backends like postgres, addToGraph takes significant time,
creating a window where other nodes learn about the confirmed SCID from
gossip and attempt to route through it, but the receiving node's switch
hasn't been updated yet to handle forwards using the confirmed SCID.
The fix reorders operations to call ReportShortChanID before addToGraph,
ensuring the switch is ready to handle the confirmed SCID before it's
announced to the network. Forwards using either the alias or confirmed
SCID will work since getLinkByMapping uses baseIndex to map both to the
same link in forwardingIndex.
Fixes flaky test: zero_conf-channel_policy_update_public_zero_conf
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.
We now allow the mission control manager to skip over deserializable
errors. We cannot repair this these results but we just skip over
it so we can startup properly.
When fetchAll() encounters entries that fail to deserialize, in
addition to skipping them, now also:
- Delete the corrupted entries from the database
- Remove them from the in-memory keysMap and keys tracking structures
This prevents corrupted entries from:
- Being counted toward maxRecords, which would cause valid entries
to be pruned prematurely
- Persisting in the database indefinitely
- Causing inaccurate entry counts in startup logs
This commit enhances the integration test to validate the LSP heuristic
end-to-end with real network topology and payment probing.
Network topology additions:
- Added Frank node as a private destination
- Created multi-LSP test scenario with Bob, Eve, and Dave as LSPs
New test cases:
1. "probe based estimate, public target with public hop hints"
- Validates Rule 1: public invoice target routes directly
- Even with public hop hints, direct routing is used
- Expected: standard single-hop fees
2. "probe based estimate, multiple different public LSPs"
- Validates multi-LSP worst-case selection
- Frank has routes through Bob (low fee), Eve (HIGH fee), Dave (medium)
- Expected: Eve's worst-case fees (most expensive)
- Tests griefing protection (max 3 LSP probes)
This commit implements a comprehensive LSP (Lightning Service Provider)
detection heuristic and updates the payment probing logic to handle
multiple LSPs with worst-case fee estimation.
Key changes:
1. LSP Detection Heuristic (isLSP function):
Implements three rules to detect LSP setups:
- Rule 1: If invoice target is public → NOT an LSP (route directly)
- Rule 2: If at least one destination hop is public → IS an LSP
- Rule 3: If all destination hops are private → NOT an LSP
2. LSP Route Preparation (prepareLspRouteHints function):
- Groups route hints by unique public LSP nodes
- Filters out non-LSP routes based on the heuristic
- Tracks worst-case fees and CLTV delays for each LSP
- Returns adjusted route hints with LSP hop stripped
3. Multi-LSP Probing (probePaymentRequest updates):
- Probes up to 3 unique LSPs maximum (griefing protection)
- Selects the WORST-CASE (most expensive) route for conservative
fee estimation
- Adds comprehensive debug logging for worst-case selection process
- Properly formats vertex logging using %v (calls Vertex.String())
The worst-case approach ensures users won't be surprised by higher fees
when the actual payment is sent, providing a more conservative and
reliable fee estimate.
This commit also adds extensive unit test coverage for the LSP detection
heuristic and route preparation logic.
TestIsLsp:
- Edge cases: empty route hints, nil scenarios
- Rule 1: Public invoice target (3 tests)
- Rule 2: All private destination hops (4 tests)
- Rule 3: At least one public destination hop (6 tests)
TestPrepareLspRouteHints:
- LSP grouping and filtering logic
- Worst-case fee selection across route hints
- Worst-case CLTV delta tracking
- Adjusted route hints validation (LSP hop stripped)
- Multi-LSP scenarios with different fees
This commit adds the HasNode function to the RouterBackend struct,
which checks if a node exists in the graph (i.e., has public channels).
This function is needed by the LSP detection heuristic to determine
if a node is publicly reachable.
The function is wired up in rpcserver.go to query the graph database.
Replace hardcoded WithGlobalLock assignment with configurable
options wallet postgres backends. Also add the WithGlobalLock
option to the channeldb table for postgres backends.
Defaults:
- channeldb: false (allow concurrent access)
- wallet: true (maintain safe single-writer behavior)
Users can now override these defaults via:
- db.postgres.channeldb-with-global-lock
- db.postgres.walletdb-with-global-lock
This gives operators flexibility while maintaining safe defaults
until full native SQL migration is complete.
Moreover exclude db.postgres.walletdb-with-global-lock check
in the sample config file script. We cannot easily check the
correct default because we set it later in the LND startup
sequence so we exclude it.
Add two configuration options to control global lock usage for
different postgres database backends:
- ChannelDBWithGlobalLock: for channeldb access (default: false)
- WalletDBWithGlobalLock: for wallet database access (default: true)
These allow fine-grained control over which databases use global
locks, rather than hardcoding the behavior. This is a temporary
measure until the revocation log and wallet are migrated to native
SQL and become fully concurrent-safe.
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.
We now return an error when blinded and non blinded attempts are
combined. This was theoretically possible to register a legacy
attempt in combination with a blinded payment. This would have
been prevented by other checks in the code because legacy payments
are not split into shards.
The config file format changed. The tool golangci-lint migrate
was used to migrate the old config. However old comments and also
the structure of the disabled linters was preserved.
Moreover the new v2 version introduced new linters, we disable
3 of them because they are very noise and we do not really want
to check for them: funcorder, noinlineerr, embeddedstructfieldcheck.
Older LND versions had a bug which would create HTLCs with
0 locktime. The utxonursery will have problems dealing with such
htlc outputs because we do not allow height hints of 0. Now we
will fetch the closeSummary of the channel and will add a
conservative height for rescanning.
Version v1.4.3 has some important bugfixes. We bump both version
in the same go so we do not need to tag the kvdb package and the
latest version of will be used.
This is only used for testing because we have now a unique
contraint on the session key and need to swap it in tests for
the sql backend.
pick f17baec94 paymentsdb: fix linter
we make the index assertion db independant so it is a noop for
a future native sql backend. This allows us to reuse even more
tests for the different db architectures.
This commit starts reusing test cases which are not dependant on
the kv db backend. So they can be later used with the native db
implementation as well.
This commit moves most of the code into its own package. It is
the smallest code move possible without moving import cycles and
keeping the changes to the code base as small as possible during
refactor.
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.
This method is not only used by the payment logic so we need to
move it to a generalized place because in the following commits
we move payment related code into its own package.
We introduce a new package paymentsDB and start by moving the
payment specifc errors from the channeldb package to the
paymentsDB package. We also fix linter issues which showed up
due to changing this code part.
We add a context for the query method because the query method
is part of the paymentDB interface and for the SQL case
we will need the context for this method because the native
SQL drivers demand one. So we add it for the kv implementation
here as well so we can then make use of the new interface type.
We check the context of the payment lifecycle at the beginning of
the `resumepayment` loop. This will make sure we have always the
latest state of the payment before deciding on the next steps in
the function `decideNextStep`.