diff --git a/.version b/.version index 85ac303f4aef..492142d0a802 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -v26.06.2 +v26.06.6 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d2ca698442e..83a5498333ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [26.06.6] - 2026-07-20: "Quantum-Resistant Lightning Channel III" + +v26.06.3, v26.06.4, and v26.06.5 had issues during publishing with the pypi releases and were deleted. + +### Fixed + + - update pyln-proto's coincurve to v21 to fix Python build environments + - reject a channel that reuses an existing funding outpoint + +[#9297]: https://github.com/ElementsProject/lightning/pull/9297 +[#9318]: https://github.com/ElementsProject/lightning/pull/9318 + ## [26.06.2] - 2026-06-25: "Quantum-Resistant Lightning Channel II" This point release if recommended for all minimal OS setups, including docker images, that have no root certificates for TLS installed. diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 59e483d97596..913a37e42acb 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -1729,7 +1729,16 @@ void peer_connect_subd(struct daemon *daemon, const u8 *msg, int fd) fmt_node_id(tmpctx, &id))); } - assert(!subd->conn); + /* We only keep one connection per channel_id. If one is already + * attached for this channel_id, drop this fd rather than replacing + * it. */ + if (subd->conn) { + status_peer_debug(&id, + "Already have a subd for channel_id %s: ignoring", + fmt_channel_id(tmpctx, &channel_id)); + close(fd); + return; + } /* This sets subd->conn inside subd_conn_init, and reparents subd! */ io_new_conn(peer, fd, subd_conn_init, subd); diff --git a/contrib/pyln-client/pyln/client/__init__.py b/contrib/pyln-client/pyln/client/__init__.py index 096ba0071859..53e5a6cc5145 100644 --- a/contrib/pyln-client/pyln/client/__init__.py +++ b/contrib/pyln-client/pyln/client/__init__.py @@ -4,7 +4,7 @@ from .gossmapstats import GossmapStats from .version import NodeVersion -__version__ = "v26.06.2" +__version__ = "v26.06.6" __all__ = [ "LightningRpc", diff --git a/contrib/pyln-client/pyproject.toml b/contrib/pyln-client/pyproject.toml index 115adefee996..47858d827f1e 100644 --- a/contrib/pyln-client/pyproject.toml +++ b/contrib/pyln-client/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "pyln-client" -version = "v26.06.2" +version = "v26.06.6" description = "Client library and plugin library for Core Lightning" authors = [{ name = "Christian Decker", email = "decker.christian@gmail.com" }] license = { text = "BSD-MIT" } diff --git a/contrib/pyln-proto/pyln/proto/__init__.py b/contrib/pyln-proto/pyln/proto/__init__.py index 376ef611098e..1bf1100f6bd1 100644 --- a/contrib/pyln-proto/pyln/proto/__init__.py +++ b/contrib/pyln-proto/pyln/proto/__init__.py @@ -4,7 +4,7 @@ from .onion import OnionPayload, TlvPayload, LegacyOnionPayload from .wire import LightningConnection, LightningServerSocket -__version__ = "v26.06.2" +__version__ = "v26.06.6" __all__ = [ "Invoice", diff --git a/contrib/pyln-proto/pyproject.toml b/contrib/pyln-proto/pyproject.toml index e01378a45596..d7bf2d7e5526 100644 --- a/contrib/pyln-proto/pyproject.toml +++ b/contrib/pyln-proto/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "pyln-proto" -version = "v26.06.2" +version = "v26.06.6" description = "This package implements some of the Lightning Network protocol in pure python. It is intended for protocol testing and some minor tooling only. It is not deemed secure enough to handle any amount of real funds (you have been warned!)." authors = [ {name = "Christian Decker", email = "decker.christian@gmail.com"} @@ -11,7 +11,7 @@ requires-python = ">=3.10,<4.0" dependencies = [ "base58>=2.1.1", "bitstring>=4.3.0", - "coincurve==20.0.0", + "coincurve-cp314-fix>=22.0.1", "cryptography>=46", "PySocks>=1" ] diff --git a/contrib/pyln-testing/pyln/testing/__init__.py b/contrib/pyln-testing/pyln/testing/__init__.py index b6057636f040..20304d71c462 100644 --- a/contrib/pyln-testing/pyln/testing/__init__.py +++ b/contrib/pyln-testing/pyln/testing/__init__.py @@ -1,4 +1,4 @@ -__version__ = "v26.06.2" +__version__ = "v26.06.6" __all__ = [ "__version__", diff --git a/contrib/pyln-testing/pyproject.toml b/contrib/pyln-testing/pyproject.toml index e6b1a0cc71c8..03af1b3b67d6 100644 --- a/contrib/pyln-testing/pyproject.toml +++ b/contrib/pyln-testing/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "pyln-testing" -version = "v26.06.2" +version = "v26.06.6" description = "Test your Core Lightning integration, plugins or whatever you want" authors = [{ name = "Christian Decker", email = "decker.christian@gmail.com" }] license = { text = "BSD-MIT" } diff --git a/contrib/reprobuild/Dockerfile.jammy b/contrib/reprobuild/Dockerfile.jammy index dd97604921db..56959cb81693 100644 --- a/contrib/reprobuild/Dockerfile.jammy +++ b/contrib/reprobuild/Dockerfile.jammy @@ -12,23 +12,24 @@ RUN sed -i '/updates/d' /etc/apt/sources.list && \ RUN apt-get update && \ apt-get install -y --no-install-recommends \ - autoconf \ - build-essential \ - ca-certificates \ - file \ - gettext \ - git \ - libsqlite3-dev \ - libpq-dev \ - libsodium23 \ - libsodium-dev \ - libtool \ - m4 \ - sudo \ - unzip \ - wget \ - jq \ - zip \ + autoconf \ + automake \ + build-essential \ + ca-certificates \ + file \ + gettext \ + git \ + libsqlite3-dev \ + libpq-dev \ + libsodium23 \ + libsodium-dev \ + libtool \ + m4 \ + sudo \ + unzip \ + wget \ + jq \ + zip \ && cd /tmp \ && wget https://github.com/kristapsdz/lowdown/archive/refs/tags/VERSION_1_0_2.tar.gz \ && tar -xzf VERSION_1_0_2.tar.gz \ diff --git a/contrib/reprobuild/Dockerfile.noble b/contrib/reprobuild/Dockerfile.noble index 8752d231811e..5a2fbade9fca 100644 --- a/contrib/reprobuild/Dockerfile.noble +++ b/contrib/reprobuild/Dockerfile.noble @@ -1,4 +1,4 @@ -FROM ubuntu:noble +FROM noble ENV TZ=UTC RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone @@ -8,29 +8,31 @@ ENV PATH=/root/.pyenv/shims:/root/.pyenv/bin:/root/.cargo/bin:/root/.local/bin:$ ENV PROTOC_VERSION=29.4 RUN sed -i '/updates/d' /etc/apt/sources.list && \ - sed -i '/security/d' /etc/apt/sources.list + sed -i '/security/d' /etc/apt/sources.list && \ + sed -i 's/^deb \(.*\) noble main$/deb \1 noble main universe/' /etc/apt/sources.list RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - autoconf \ - build-essential \ - ca-certificates \ - file \ - gettext \ - git \ + && apt-get install -y --no-install-recommends \ + autoconf \ + automake \ + build-essential \ + ca-certificates \ + file \ + gettext \ + git \ curl \ libsqlite3-dev \ - libpq-dev \ - libsodium23 \ + libpq-dev \ + libsodium23 \ libsodium-dev \ lowdown \ - libtool \ - m4 \ - sudo \ - unzip \ - wget \ + libtool \ + m4 \ + sudo \ + unzip \ + wget \ jq \ - zip + zip # Configure /repo/.git as 'safe.directory' RUN git config --global --add safe.directory /repo/.git diff --git a/contrib/reprobuild/Dockerfile.resolute b/contrib/reprobuild/Dockerfile.resolute index 9c174f8cf265..e9b67e15cc51 100644 --- a/contrib/reprobuild/Dockerfile.resolute +++ b/contrib/reprobuild/Dockerfile.resolute @@ -1,4 +1,4 @@ -FROM ubuntu:resolute +FROM resolute ENV TZ=UTC RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone @@ -8,11 +8,13 @@ ENV PATH=/root/.pyenv/shims:/root/.pyenv/bin:/root/.cargo/bin:/root/.local/bin:$ ENV PROTOC_VERSION=29.4 RUN sed -i '/updates/d' /etc/apt/sources.list && \ - sed -i '/security/d' /etc/apt/sources.list + sed -i '/security/d' /etc/apt/sources.list && \ + sed -i 's/^deb \(.*\) resolute main$/deb \1 resolute main universe/' /etc/apt/sources.list RUN apt-get update \ && apt-get install -y --no-install-recommends \ autoconf \ + automake \ build-essential \ ca-certificates \ file \ diff --git a/lightningd/channel.c b/lightningd/channel.c index 1cd40871ed2d..692d81980150 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -879,6 +879,18 @@ struct channel *find_channel_by_id(const struct peer *peer, return NULL; } +struct channel *find_channel_by_funding_outpoint(const struct peer *peer, + const struct bitcoin_outpoint *outpoint) +{ + struct channel *c; + + list_for_each(&peer->channels, c, list) { + if (bitcoin_outpoint_eq(&c->funding, outpoint)) + return c; + } + return NULL; +} + struct channel *find_channel_by_scid(const struct peer *peer, struct short_channel_id scid) { diff --git a/lightningd/channel.h b/lightningd/channel.h index 46add63f51a4..8e3a499ad09c 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -918,6 +918,11 @@ struct channel *channel_by_cid(struct lightningd *ld, struct channel *find_channel_by_id(const struct peer *peer, const struct channel_id *cid); +/* Find a channel with this funding outpoint within peer (an outpoint + * funds at most one channel). */ +struct channel *find_channel_by_funding_outpoint(const struct peer *peer, + const struct bitcoin_outpoint *outpoint); + /* Find this channel within peer */ struct channel *find_channel_by_scid(const struct peer *peer, struct short_channel_id scid); diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 74a3277d051e..6cc3d82f1e61 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -533,6 +533,15 @@ static void opening_fundee_finished(struct subd *openingd, derive_channel_id(&cid, &funding); + /* A funding outpoint funds at most one channel; don't accept a second + * channel reusing one we already have. Drop the connection so the + * peer's open fails cleanly instead of waiting for funding_signed. */ + if (find_channel_by_funding_outpoint(uc->peer, &funding)) { + force_peer_disconnect(ld, uc->peer, + "Funding outpoint already in use"); + return; + } + /* old_remote_per_commit not valid yet, copy valid one. */ channel_info.old_remote_per_commit = channel_info.remote_per_commit; diff --git a/tools/build-release.sh b/tools/build-release.sh index 3ad03ddba1b4..fcdc8dce9f82 100755 --- a/tools/build-release.sh +++ b/tools/build-release.sh @@ -31,6 +31,7 @@ fi FORCE_UNCLEAN=false VERIFY_RELEASE=false WITHOUT_ZIP=false +NO_PUSH=false SUDO= ALL_TARGETS="bin-Fedora bin-Ubuntu docker sign" @@ -63,11 +64,14 @@ while [ $# -gt 0 ]; do --without-zip) WITHOUT_ZIP=true ;; + --no-push) + NO_PUSH=true + ;; --sudo) SUDO=sudo ;; --help) - echo "Usage: [--force-version=] [--force-unclean] [--force-mtime=YYYY-MM-DD] [--verify] [TARGETS]" + echo "Usage: [--force-version=] [--force-unclean] [--force-mtime=YYYY-MM-DD] [--verify] [--no-push] [TARGETS]" echo Known targets: "$ALL_TARGETS" echo "Example: tools/build-release.sh" echo "Example: tools/build-release.sh --force-version=v23.05 --force-unclean --force-mtime=2023-05-01 bin-Fedora bin-Ubuntu sign" @@ -209,13 +213,18 @@ for target in $TARGETS; do esac done -if [ -z "${TARGETS##* docker *}" ]; then +if [ -z "${TARGETS##* docker *}" ] || [ -z "${TARGETS##* docker}" ]; then echo "Building Docker Images" DOCKER_USER="elementsproject" echo "Creating multi-platform images tagged as $VERSION and latest" - # --load does not work with multiarch. Only --push works. - # ERROR: docker exporter does not currently support exporting manifest lists - DOCKER_OPTS="--push --platform linux/amd64,linux/arm64,linux/arm/v7" + if $NO_PUSH; then + # Build without publishing: the result only populates the builder's + # cache, so a later run without --no-push pushes from cache quickly. + DOCKER_OPTS="--platform linux/amd64,linux/arm64,linux/arm/v7" + else + DOCKER_OPTS="--push --platform linux/amd64,linux/arm64,linux/arm/v7" + fi + DOCKER_OPTS="$DOCKER_OPTS --build-arg VERSION=$VERSION" DOCKER_OPTS="$DOCKER_OPTS -t $DOCKER_USER/lightningd:$VERSION" DOCKER_OPTS="$DOCKER_OPTS -t $DOCKER_USER/lightningd:latest" DOCKER_OPTS="$DOCKER_OPTS --cache-to=type=local,dest=/tmp/docker-cache --cache-from=type=local,src=/tmp/docker-cache" @@ -227,10 +236,14 @@ if [ -z "${TARGETS##* docker *}" ]; then fi # shellcheck disable=SC2086 $SUDO docker buildx build $DOCKER_OPTS . - echo "Pushed multi-platform images tagged as $VERSION and latest" + if $NO_PUSH; then + echo "Built multi-platform images without pushing (rerun without --no-push to publish)" + else + echo "Pushed multi-platform images tagged as $VERSION and latest" + fi fi -if [ -z "${TARGETS##* sign *}" ]; then +if [ -z "${TARGETS##* sign *}" ] || [ -z "${TARGETS##* sign}" ]; then echo "Signing Release" cd release/ || exit sha256sum clightning-"$VERSION"-*.tar.* clightning-"$VERSION".zip > SHA256SUMS-"$VERSION" diff --git a/tools/reckless b/tools/reckless index 450c2f4b231c..62bfe6259773 100755 --- a/tools/reckless +++ b/tools/reckless @@ -21,7 +21,7 @@ from urllib.error import HTTPError import venv -__VERSION__ = 'v26.06.2' +__VERSION__ = 'v26.06.6' logging.basicConfig( level=logging.INFO, diff --git a/tools/repro-build.sh b/tools/repro-build.sh index eb18a54eb423..621847e71d13 100755 --- a/tools/repro-build.sh +++ b/tools/repro-build.sh @@ -107,13 +107,12 @@ EOF Ubuntu-24.04) cat > /tmp/SHASUMS <