Files
lnd/.github/workflows/main.yml
T
ziggie f6f6064938 scripts: fix backwards compatibility test timing issues
The backwards compatibility test was failing intermittently due to two
related timing issues in the test setup.

The issue was that Dave's `wait_graph_sync dave 3` was hanging
for up to 60 minutes. Dave's initial gossip sync with Charlie could
complete before Charlie had forwarded the alice-bob channel
announcement, leaving Dave stuck at 2 channels until lnd's historical
syncer fired at its default interval of 1 hour. After this 1-hour idle,
some routing state had become stale, causing the subsequent payment from
alice to dave to fail with FAILURE_REASON_NO_ROUTE.

This issues is now addressed by setting `--historicalsyncinterval=10s` on
all nodes. This causes nodes to periodically re-sync the full gossip
state from their peers every 10 seconds instead of every hour. Dave
therefore picks up any missed channel announcements and routing policies
within seconds, and alice's routing graph stays up-to-date throughout
the test.

Additionally, lnd debug logs from all containers are now collected
before teardown on failure and uploaded as a CI artifact, making future
failures easier to diagnose.
2026-03-04 13:04:26 +01:00

666 lines
21 KiB
YAML

name: CI
on:
push:
branches:
- "master"
pull_request:
branches:
- "*"
merge_group:
branches:
- "master"
permissions:
# Required to manage and delete caches.
actions: write
# Default permission for checking out code.
contents: read
concurrency:
# Cancel any previous workflows if they are from a PR or push.
group: ${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
env:
BITCOIN_VERSION: "29"
# TRANCHES defines the number of tranches used in the itests.
TRANCHES: 16
# SMALL_TRANCHES defines the number of tranches used in the less stable itest
# builds
#
# TODO(yy): remove this value and use TRANCHES.
SMALL_TRANCHES: 8
# If you change this please also update GO_VERSION in Makefile (then run
# `make lint` to see where else it needs to be updated as well).
GO_VERSION: 1.25.5
jobs:
static-checks:
name: Static Checks
runs-on: ubuntu-latest
steps:
- name: Git checkout
uses: actions/checkout@v5
with:
# Needed for some checks.
fetch-depth: 0
- name: Clean up runner space
uses: ./.github/actions/cleanup-space
- name: Setup Go ${{ env.GO_VERSION }}
uses: ./.github/actions/setup-go
with:
go-version: '${{ env.GO_VERSION }}'
use-build-cache: 'no'
########################
# sample configuration check
########################
- name: Check default values in sample-lnd.conf file
run: make sample-conf-check
########################
# Check code and RPC format
########################
- name: Check code format
run: make fmt-check
- name: Check go modules tidiness
run: make tidy-module-check
- name: Lint proto files
run: make protolint
########################
# SQLC code gen check
########################
- name: Docker image cache
uses: satackey/action-docker-layer-caching@v0.0.11
# Ignore the failure of a step and avoid terminating the job.
continue-on-error: true
- name: Check SQL models
run: make sqlc-check
########################
# RPC and mobile compilation check
########################
- name: Check RPC format
run: make rpc-check
- name: Check JSON/WASM stub compilation
run: make rpc-js-compile
- name: Check mobile RPC bindings
run: make mobile-rpc
- name: Check mobile specific code
run: go build --tags="mobile" ./mobile
########################
# check commits
########################
check-commits:
if: github.event_name == 'pull_request'
name: Check commits
runs-on: ubuntu-latest
steps:
- name: git checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Clean up runner space
uses: ./.github/actions/cleanup-space
- name: setup go ${{ env.GO_VERSION }}
uses: ./.github/actions/setup-go
with:
go-version: '${{ env.GO_VERSION }}'
# Use the same cache from unit test job to save time.
key-prefix: unit-test
- name: fetch and rebase on ${{ github.base_ref }}
uses: ./.github/actions/rebase
- name: check commits
run: scripts/check-each-commit.sh upstream/${{ github.base_ref }}
########################
# lint code
########################
lint:
name: Lint code
runs-on: ubuntu-latest
steps:
- name: git checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Clean up runner space
uses: ./.github/actions/cleanup-space
- name: setup go ${{ env.GO_VERSION }}
uses: ./.github/actions/setup-go
with:
go-version: '${{ env.GO_VERSION }}'
# Use the same cache from unit test job to save time.
key-prefix: unit-test
- name: lint
run: GOGC=50 make lint
########################
# cross compilation
########################
cross-compile:
name: Cross compilation
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
# Please keep this list in sync with make/release_flags.mk!
include:
- name: i386
sys: freebsd-386 linux-386 windows-386
- name: amd64
sys: darwin-amd64 freebsd-amd64 linux-amd64 netbsd-amd64 openbsd-amd64 windows-amd64
- name: arm
sys: darwin-arm64 freebsd-arm linux-armv6 linux-armv7 linux-arm64 windows-arm
steps:
- name: Git checkout
uses: actions/checkout@v5
- name: Clean up runner space
uses: ./.github/actions/cleanup-space
- name: Setup go ${{ env.GO_VERSION }}
uses: ./.github/actions/setup-go
with:
go-version: '${{ env.GO_VERSION }}'
key-prefix: cross-compile
use-build-cache: 'no'
- name: Build release for all architectures
run: make release sys="${{ matrix.sys }}"
########################
# run unit tests
########################
unit-test:
name: Run unit tests
runs-on: ubuntu-latest
strategy:
# Allow other tests in the matrix to continue if one fails.
fail-fast: false
matrix:
unit_type:
- unit-cover
- unit tags="kvdb_etcd"
- unit tags="kvdb_postgres"
- unit tags="kvdb_sqlite"
- unit tags="test_db_sqlite"
- unit tags="test_db_postgres"
- unit-race
- unit-race tags="test_db_sqlite"
- unit-race tags="test_db_postgres"
- unit-module
steps:
- name: Git checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Clean up runner space
uses: ./.github/actions/cleanup-space
- name: Fetch and rebase on ${{ github.base_ref }}
if: github.event_name == 'pull_request'
uses: ./.github/actions/rebase
- name: Git checkout fuzzing seeds
uses: actions/checkout@v5
with:
repository: lightninglabs/lnd-fuzz
path: lnd-fuzz
- name: Rsync fuzzing seeds
run: rsync -a --ignore-existing lnd-fuzz/ ./
- name: Setup go ${{ env.GO_VERSION }}
uses: ./.github/actions/setup-go
with:
go-version: '${{ env.GO_VERSION }}'
key-prefix: unit-test
- name: Install bitcoind
run: ./scripts/install_bitcoind.sh $BITCOIN_VERSION
- name: Run ${{ matrix.unit_type }}
run: make ${{ matrix.unit_type }}
- name: Clean coverage
run: grep -Ev '(\.pb\.go|\.pb\.json\.go|\.pb\.gw\.go)' coverage.txt > coverage-norpc.txt
if: matrix.unit_type == 'unit-cover'
- name: Send coverage
uses: coverallsapp/github-action@v2
if: matrix.unit_type == 'unit-cover'
continue-on-error: true
with:
file: coverage-norpc.txt
flag-name: 'unit'
format: 'golang'
parallel: true
########################
# run integration tests with TRANCHES
########################
basic-integration-test:
name: Run basic itests
runs-on: ubuntu-latest
strategy:
# Allow other tests in the matrix to continue if one fails.
fail-fast: false
matrix:
include:
- name: btcd
args: backend=btcd cover=1
- name: bitcoind
args: backend=bitcoind cover=1
- name: bitcoind-notxindex
args: backend="bitcoind notxindex"
- name: neutrino
args: backend=neutrino cover=1
steps:
- name: Git checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Check for no-itest label
id: check-label
uses: ./.github/actions/check-label
with:
label: 'no-itest'
skip-message: "Tests auto-passed due to 'no-itest' label"
- name: Clean up runner space
if: steps.check-label.outputs.skip != 'true'
uses: ./.github/actions/cleanup-space
- name: Fetch and rebase on ${{ github.base_ref }}
if: github.event_name == 'pull_request' && steps.check-label.outputs.skip != 'true'
uses: ./.github/actions/rebase
- name: Setup go ${{ env.GO_VERSION }}
if: steps.check-label.outputs.skip != 'true'
uses: ./.github/actions/setup-go
with:
go-version: '${{ env.GO_VERSION }}'
key-prefix: integration-test
- name: Install bitcoind
if: steps.check-label.outputs.skip != 'true'
run: ./scripts/install_bitcoind.sh $BITCOIN_VERSION
- name: Run ${{ matrix.name }}
if: steps.check-label.outputs.skip != 'true'
run: make itest-parallel tranches=${{ env.TRANCHES }} ${{ matrix.args }} shuffleseed=${{ github.run_id }}${{ strategy.job-index }}
- name: Clean coverage
run: grep -Ev '(\.pb\.go|\.pb\.json\.go|\.pb\.gw\.go)' coverage.txt > coverage-norpc.txt
if: ${{ contains(matrix.args, 'cover=1') && steps.check-label.outputs.skip != 'true' }}
- name: Send coverage
if: ${{ contains(matrix.args, 'cover=1') && steps.check-label.outputs.skip != 'true' }}
continue-on-error: true
uses: coverallsapp/github-action@v2
with:
file: coverage-norpc.txt
flag-name: 'itest-${{ matrix.name }}'
format: 'golang'
parallel: true
- name: Zip log files on failure
if: ${{ failure() && steps.check-label.outputs.skip != 'true' }}
timeout-minutes: 5 # timeout after 5 minute
run: 7z a logs-itest-${{ matrix.name }}.zip itest/**/*.log itest/postgres.log
- name: Upload log files on failure
uses: actions/upload-artifact@v4
if: ${{ failure() && steps.check-label.outputs.skip != 'true' }}
with:
name: logs-itest-${{ matrix.name }}
path: logs-itest-${{ matrix.name }}.zip
retention-days: 5
########################
# run integration tests with SMALL_TRANCHES
########################
integration-test:
name: Run itests
runs-on: ubuntu-latest
strategy:
# Allow other tests in the matrix to continue if one fails.
fail-fast: false
matrix:
include:
- name: bitcoind-rpcpolling
args: backend="bitcoind rpcpolling"
- name: bitcoind-etcd
args: backend=bitcoind dbbackend=etcd
- name: bitcoind-sqlite
args: backend=bitcoind dbbackend=sqlite
- name: bitcoind-sqlite-nativesql
args: backend=bitcoind dbbackend=sqlite nativesql=true
- name: bitcoind-sqlite=nativesql-experiment
args: backend=bitcoind dbbackend=sqlite nativesql=true tags=test_native_sql
- name: bitcoind-postgres
args: backend=bitcoind dbbackend=postgres
- name: bitcoind-postgres-nativesql
args: backend=bitcoind dbbackend=postgres nativesql=true
- name: bitcoind-postgres-nativesql-experiment
args: backend=bitcoind dbbackend=postgres nativesql=true tags=test_native_sql
steps:
- name: Git checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Check for no-itest label
id: check-label
uses: ./.github/actions/check-label
with:
label: 'no-itest'
skip-message: "Tests auto-passed due to 'no-itest' label"
- name: Clean up runner space
if: steps.check-label.outputs.skip != 'true'
uses: ./.github/actions/cleanup-space
- name: Fetch and rebase on ${{ github.base_ref }}
if: github.event_name == 'pull_request' && steps.check-label.outputs.skip != 'true'
uses: ./.github/actions/rebase
- name: Setup go ${{ env.GO_VERSION }}
if: steps.check-label.outputs.skip != 'true'
uses: ./.github/actions/setup-go
with:
go-version: '${{ env.GO_VERSION }}'
key-prefix: integration-test
- name: Install bitcoind
if: steps.check-label.outputs.skip != 'true'
run: ./scripts/install_bitcoind.sh $BITCOIN_VERSION
- name: Run ${{ matrix.name }}
if: steps.check-label.outputs.skip != 'true'
run: make itest-parallel tranches=${{ env.SMALL_TRANCHES }} ${{ matrix.args }} shuffleseed=${{ github.run_id }}${{ strategy.job-index }}
- name: Clean coverage
run: grep -Ev '(\.pb\.go|\.pb\.json\.go|\.pb\.gw\.go)' coverage.txt > coverage-norpc.txt
if: ${{ contains(matrix.args, 'cover=1') && steps.check-label.outputs.skip != 'true' }}
- name: Send coverage
if: ${{ contains(matrix.args, 'cover=1') && steps.check-label.outputs.skip != 'true' }}
continue-on-error: true
uses: coverallsapp/github-action@v2
with:
file: coverage-norpc.txt
flag-name: 'itest-${{ matrix.name }}'
format: 'golang'
parallel: true
- name: Zip log files on failure
if: ${{ failure() && steps.check-label.outputs.skip != 'true' }}
timeout-minutes: 5 # timeout after 5 minute
run: 7z a logs-itest-${{ matrix.name }}.zip itest/**/*.log
- name: Upload log files on failure
uses: actions/upload-artifact@v4
if: ${{ failure() && steps.check-label.outputs.skip != 'true' }}
with:
name: logs-itest-${{ matrix.name }}
path: logs-itest-${{ matrix.name }}.zip
retention-days: 5
########################
# run windows integration test
########################
windows-integration-test:
name: Run windows itest
runs-on: windows-latest
steps:
- name: Git checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Check for no-itest label
id: check-label
uses: ./.github/actions/check-label
with:
label: 'no-itest'
skip-message: "Tests auto-passed due to 'no-itest' label"
- name: Fetch and rebase on ${{ github.base_ref }}
if: github.event_name == 'pull_request' && steps.check-label.outputs.skip != 'true'
uses: ./.github/actions/rebase
- name: Setup go ${{ env.GO_VERSION }}
if: steps.check-label.outputs.skip != 'true'
uses: ./.github/actions/setup-go
with:
go-version: '${{ env.GO_VERSION }}'
key-prefix: integration-test
- name: Run itest
if: steps.check-label.outputs.skip != 'true'
run: make itest-parallel tranches=${{ env.SMALL_TRANCHES }} windows=1 shuffleseed=${{ github.run_id }}
- name: Kill any remaining lnd processes
if: ${{ failure() && steps.check-label.outputs.skip != 'true' }}
shell: powershell
run: taskkill /IM lnd-itest.exe /T /F
- name: Zip log files on failure
if: ${{ failure() && steps.check-label.outputs.skip != 'true' }}
timeout-minutes: 5 # timeout after 5 minute
run: 7z a logs-itest-windows.zip itest/**/*.log
- name: Upload log files on failure
uses: actions/upload-artifact@v4
if: ${{ failure() && steps.check-label.outputs.skip != 'true' }}
with:
name: logs-itest-windows
path: logs-itest-windows.zip
retention-days: 5
########################
# run macOS integration test
########################
macos-integration-test:
name: Run macOS itest
runs-on: macos-14
steps:
- name: Git checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Check for no-itest label
id: check-label
uses: ./.github/actions/check-label
with:
label: 'no-itest'
skip-message: "Tests auto-passed due to 'no-itest' label"
- name: Fetch and rebase on ${{ github.base_ref }}
if: github.event_name == 'pull_request' && steps.check-label.outputs.skip != 'true'
uses: ./.github/actions/rebase
- name: Setup go ${{ env.GO_VERSION }}
if: steps.check-label.outputs.skip != 'true'
uses: ./.github/actions/setup-go
with:
go-version: '${{ env.GO_VERSION }}'
key-prefix: integration-test
- name: Run itest
if: steps.check-label.outputs.skip != 'true'
run: make itest-parallel tranches=${{ env.SMALL_TRANCHES }} shuffleseed=${{ github.run_id }}
- name: Zip log files on failure
if: ${{ failure() && steps.check-label.outputs.skip != 'true' }}
timeout-minutes: 5 # timeout after 5 minute
run: 7z a logs-itest-macos.zip itest/**/*.log
- name: Upload log files on failure
uses: actions/upload-artifact@v4
if: ${{ failure() && steps.check-label.outputs.skip != 'true' }}
with:
name: logs-itest-macos
path: logs-itest-macos.zip
retention-days: 5
########################
# check pinned dependencies
########################
dep-pin:
name: Check pinned dependencies
runs-on: ubuntu-latest
strategy:
# Allow other tests in the matrix to continue if one fails.
fail-fast: false
matrix:
pinned_dep:
- google.golang.org/grpc v1.59.0
- github.com/golang/protobuf v1.5.4
steps:
- name: Git checkout
uses: actions/checkout@v5
- name: Clean up runner space
uses: ./.github/actions/cleanup-space
- name: Ensure dependencies at correct version
run: if ! grep -q "${{ matrix.pinned_dep }}" go.mod; then echo dependency ${{ matrix.pinned_dep }} should not be altered ; exit 1 ; fi
########################
# check PR updates release notes
########################
milestone-check:
name: Check release notes updated
runs-on: ubuntu-latest
steps:
- name: Git checkout
uses: actions/checkout@v5
- name: Check for no-changelog label
id: check-label
uses: ./.github/actions/check-label
with:
label: 'no-changelog'
skip-message: "Changelog check auto-passed due to 'no-changelog' label"
- name: Clean up runner space
if: steps.check-label.outputs.skip != 'true'
uses: ./.github/actions/cleanup-space
- name: Release notes check
if: steps.check-label.outputs.skip != 'true'
run: scripts/check-release-notes.sh
########################
# Backwards Compatibility Test
########################
backwards-compatibility-test:
name: Backwards compatibility test
runs-on: ubuntu-latest
steps:
- name: Git checkout
uses: actions/checkout@v5
- name: 🐳 Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: 🛡️ Backwards compatibility test
run: make backwards-compat-test
- name: 📋 Upload node logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: bw-compat-logs
path: scripts/bw-compatibility-test/logs/
retention-days: 7
#########################################
# Auto Cache Cleanup on Pull Requests
#########################################
auto-cleanup-cache:
name: Cache Cleanup
runs-on: ubuntu-latest
# This condition checks for pull requests from authors with write access.
if: >-
contains('OWNER, MEMBER, COLLABORATOR', github.event.pull_request.author_association)
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Delete caches older than 12 hours
continue-on-error: true
env:
# GITHUB_TOKEN is required for the gh CLI.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Finding caches not used in the last 12 hours..."
# Get the current time and the cutoff time (12 hours ago) in Unix
# timestamp format.
cutoff_timestamp=$(date -d "12 hours ago" +%s)
# Use gh and jq to parse caches. Delete any cache last accessed
# before the cutoff time.
gh cache list --json key,lastAccessedAt | jq -r '.[] |
select(.lastAccessedAt != null) | "\(.lastAccessedAt) \(.key)"' |
while read -r last_accessed_at key; do
last_accessed_timestamp=$(date -d "$last_accessed_at" +%s)
if (( last_accessed_timestamp < cutoff_timestamp )); then
echo "Deleting old cache. Key: $key, Last Used: $last_accessed_at"
gh cache delete "$key"
fi
done
# Notify about the completion of all coverage collecting jobs.
finish:
name: Send coverage report
if: ${{ !cancelled() }}
needs: [unit-test, basic-integration-test]
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Send coverage
uses: coverallsapp/github-action@v2
continue-on-error: true
with:
parallel-finished: true