aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rwxr-xr-xcontrib/devtools/security-check.py2
-rwxr-xr-xcontrib/devtools/symbol-check.py22
-rwxr-xr-xcontrib/devtools/test-symbol-check.py25
-rwxr-xr-xcontrib/guix/libexec/build.sh13
-rwxr-xr-xcontrib/guix/libexec/codesign.sh1
-rw-r--r--contrib/guix/manifest.scm158
-rw-r--r--contrib/guix/patches/glibc-2.24-elfm-loadaddr-dynamic-rewrite.patch62
-rw-r--r--contrib/guix/patches/glibc-2.24-guix-prefix.patch25
-rw-r--r--contrib/guix/patches/glibc-2.24-no-build-time-cxx-header-run.patch100
-rw-r--r--contrib/guix/patches/glibc-2.27-dont-redefine-nss-database.patch87
-rw-r--r--contrib/guix/patches/glibc-2.27-fcommon.patch (renamed from contrib/guix/patches/glibc-2.24-fcommon.patch)10
-rw-r--r--contrib/guix/patches/glibc-2.27-guix-prefix.patch3
-rw-r--r--contrib/guix/patches/glibc-ldd-x86_64.patch4
-rwxr-xr-xcontrib/install_db4.sh259
-rw-r--r--contrib/seeds/README.md12
-rwxr-xr-xcontrib/seeds/generate-seeds.py2
-rwxr-xr-xcontrib/seeds/makeseeds.py20
-rw-r--r--contrib/seeds/nodes_main.txt1157
-rw-r--r--contrib/seeds/nodes_main_manual.txt71
-rwxr-xr-xcontrib/signet/getcoins.py2
-rw-r--r--contrib/tracing/README.md50
-rwxr-xr-xcontrib/tracing/mempool_monitor.py372
-rw-r--r--contrib/valgrind.supp29
-rw-r--r--contrib/verify-binaries/README.md88
-rwxr-xr-xcontrib/verify-binaries/test.py59
-rwxr-xr-xcontrib/verify-binaries/verify.py713
-rw-r--r--contrib/verify-commits/README.md4
-rw-r--r--contrib/verify-commits/allow-incorrect-sha512-commits2
-rw-r--r--contrib/verify-commits/allow-revsig-commits645
-rw-r--r--contrib/verify-commits/allow-unclean-merge-commits4
-rwxr-xr-xcontrib/verify-commits/gpg.sh42
-rw-r--r--contrib/verify-commits/trusted-git-root2
-rw-r--r--contrib/verify-commits/trusted-keys2
-rwxr-xr-xcontrib/verify-commits/verify-commits.py62
-rw-r--r--contrib/verifybinaries/README.md41
-rwxr-xr-xcontrib/verifybinaries/verify.py183
36 files changed, 2099 insertions, 2234 deletions
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index 8377b92736..6cd022ef17 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -34,7 +34,7 @@ def check_ELF_RELRO(binary) -> bool:
flags = binary.get(lief.ELF.DYNAMIC_TAGS.FLAGS)
if flags.value & lief.ELF.DYNAMIC_FLAGS.BIND_NOW:
have_bindnow = True
- except:
+ except Exception:
have_bindnow = False
return have_gnu_relro and have_bindnow
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index 4b1cceb57c..f26236dd59 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -15,19 +15,19 @@ from typing import List, Dict
import lief #type:ignore
-# Debian 9 (Stretch) EOL: 2022. https://wiki.debian.org/DebianReleases#Production_Releases
+# Debian 10 (Buster) EOL: 2024. https://wiki.debian.org/LTS
#
-# - g++ version 6.3.0 (https://packages.debian.org/search?suite=stretch&arch=any&searchon=names&keywords=g%2B%2B)
-# - libc version 2.24 (https://packages.debian.org/search?suite=stretch&arch=any&searchon=names&keywords=libc6)
+# - libgcc version 8.3.0 (https://packages.debian.org/search?suite=buster&arch=any&searchon=names&keywords=libgcc1)
+# - libc version 2.28 (https://packages.debian.org/search?suite=buster&arch=any&searchon=names&keywords=libc6)
#
-# Ubuntu 16.04 (Xenial) EOL: 2026. https://wiki.ubuntu.com/Releases
+# Ubuntu 18.04 (Bionic) EOL: 2028. https://wiki.ubuntu.com/ReleaseTeam
#
-# - g++ version 5.3.1
-# - libc version 2.23
+# - libgcc version 8.4.0 (https://packages.ubuntu.com/bionic/libgcc1)
+# - libc version 2.27 (https://packages.ubuntu.com/bionic/libc6)
#
# CentOS Stream 8 EOL: 2024. https://wiki.centos.org/About/Product
#
-# - g++ version 8.5.0 (http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os/Packages/)
+# - libgcc version 8.5.0 (http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os/Packages/)
# - libc version 2.28 (http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os/Packages/)
#
# See https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html for more info.
@@ -35,10 +35,10 @@ import lief #type:ignore
MAX_VERSIONS = {
'GCC': (4,8,0),
'GLIBC': {
- lief.ELF.ARCH.x86_64: (2,18),
- lief.ELF.ARCH.ARM: (2,18),
- lief.ELF.ARCH.AARCH64:(2,18),
- lief.ELF.ARCH.PPC64: (2,18),
+ lief.ELF.ARCH.x86_64: (2,27),
+ lief.ELF.ARCH.ARM: (2,27),
+ lief.ELF.ARCH.AARCH64:(2,27),
+ lief.ELF.ARCH.PPC64: (2,27),
lief.ELF.ARCH.RISCV: (2,27),
},
'LIBATOMIC': (1,0),
diff --git a/contrib/devtools/test-symbol-check.py b/contrib/devtools/test-symbol-check.py
index de73b02090..e304880140 100755
--- a/contrib/devtools/test-symbol-check.py
+++ b/contrib/devtools/test-symbol-check.py
@@ -38,31 +38,6 @@ class TestSymbolChecks(unittest.TestCase):
executable = 'test1'
cc = determine_wellknown_cmd('CC', 'gcc')
- # there's no way to do this test for RISC-V at the moment; we build for
- # RISC-V in a glibc 2.27 environment and we allow all symbols from 2.27.
- if 'riscv' in get_machine(cc):
- self.skipTest("test not available for RISC-V")
-
- # nextup was introduced in GLIBC 2.24, so is newer than our supported
- # glibc (2.18), and available in our release build environment (2.24).
- with open(source, 'w', encoding="utf8") as f:
- f.write('''
- #define _GNU_SOURCE
- #include <math.h>
-
- double nextup(double x);
-
- int main()
- {
- nextup(3.14);
- return 0;
- }
- ''')
-
- self.assertEqual(call_symbol_check(cc, source, executable, ['-lm']),
- (1, executable + ': symbol nextup from unsupported version GLIBC_2.24(3)\n' +
- executable + ': failed IMPORTED_SYMBOLS'))
-
# -lutil is part of the libc6 package so a safe bet that it's installed
# it's also out of context enough that it's unlikely to ever become a real dependency
source = 'test2.c'
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index f2be3677eb..e0bd15493f 100755
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -188,9 +188,9 @@ make -C depends --jobs="$JOBS" HOST="$HOST" \
${SDK_PATH+SDK_PATH="$SDK_PATH"} \
x86_64_linux_CC=x86_64-linux-gnu-gcc \
x86_64_linux_CXX=x86_64-linux-gnu-g++ \
- x86_64_linux_AR=x86_64-linux-gnu-ar \
- x86_64_linux_RANLIB=x86_64-linux-gnu-ranlib \
- x86_64_linux_NM=x86_64-linux-gnu-nm \
+ x86_64_linux_AR=x86_64-linux-gnu-gcc-ar \
+ x86_64_linux_RANLIB=x86_64-linux-gnu-gcc-ranlib \
+ x86_64_linux_NM=x86_64-linux-gnu-gcc-nm \
x86_64_linux_STRIP=x86_64-linux-gnu-strip \
FORCE_USE_SYSTEM_CLANG=1
@@ -238,13 +238,6 @@ case "$HOST" in
*mingw*) HOST_LDFLAGS="-Wl,--no-insert-timestamp" ;;
esac
-# Using --no-tls-get-addr-optimize retains compatibility with glibc 2.18, by
-# avoiding a PowerPC64 optimisation available in glibc 2.22 and later.
-# https://sourceware.org/binutils/docs-2.35/ld/PowerPC64-ELF64.html
-case "$HOST" in
- *powerpc64*) HOST_LDFLAGS="${HOST_LDFLAGS} -Wl,--no-tls-get-addr-optimize" ;;
-esac
-
# Make $HOST-specific native binaries from depends available in $PATH
export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}"
mkdir -p "$DISTSRC"
diff --git a/contrib/guix/libexec/codesign.sh b/contrib/guix/libexec/codesign.sh
index f6322d761c..6ffa0f07b2 100755
--- a/contrib/guix/libexec/codesign.sh
+++ b/contrib/guix/libexec/codesign.sh
@@ -77,6 +77,7 @@ mkdir -p "$DISTSRC"
osslsigncode attach-signature \
-in "$infile" \
-out "${OUTDIR}/${infile_base/-unsigned}" \
+ -CAfile "$GUIX_ENVIRONMENT/etc/ssl/certs/ca-certificates.crt" \
-sigin codesignatures/win/"$infile_base".pem
done
;;
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index 8e5c89cc5e..d83ff08713 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -28,6 +28,7 @@
(gnu packages shells)
(gnu packages tls)
(gnu packages version-control)
+ (guix build-system cmake)
(guix build-system gnu)
(guix build-system python)
(guix build-system trivial)
@@ -139,15 +140,17 @@ chain for " target " development."))
;; https://gcc.gnu.org/install/configure.html
(define (hardened-gcc gcc)
(package-with-extra-configure-variable (
- package-with-extra-configure-variable gcc
- "--enable-default-ssp" "yes")
- "--enable-default-pie" "yes"))
+ package-with-extra-configure-variable (
+ package-with-extra-configure-variable gcc
+ "--enable-initfini-array" "yes")
+ "--enable-default-ssp" "yes")
+ "--enable-default-pie" "yes"))
(define* (make-bitcoin-cross-toolchain target
#:key
(base-gcc-for-libc base-gcc)
(base-kernel-headers base-linux-kernel-headers)
- (base-libc (make-glibc-with-bind-now (make-glibc-without-werror glibc-2.24)))
+ (base-libc (hardened-glibc glibc-2.27))
(base-gcc (make-gcc-rpath-link (hardened-gcc base-gcc))))
"Convenience wrapper around MAKE-CROSS-TOOLCHAIN with default values
desirable for building Bitcoin Core release binaries."
@@ -205,60 +208,58 @@ chain for " target " development."))
(package-with-extra-patches lief
(search-our-patches "lief-fix-ppc64-nx-default.patch")))
-(define-public lief
+;; Our python-lief package can be removed once we are using
+;; guix 83bfdb409787cb2737e68b093a319b247b7858e6 or later.
+;; Note we currently use cmake-minimal.
+(define-public python-lief
(package
- (name "python-lief")
- (version "0.12.1")
- (source
- (origin
- (method git-fetch)
- (uri (git-reference
- (url "https://github.com/lief-project/LIEF.git")
- (commit version)))
- (file-name (git-file-name name version))
- (sha256
- (base32
- "1xzbh3bxy4rw1yamnx68da1v5s56ay4g081cyamv67256g0qy2i1"))))
- (build-system python-build-system)
- (arguments
- `(#:phases
- (modify-phases %standard-phases
- (add-after 'unpack 'parallel-jobs
- ;; build with multiple cores
- (lambda _
- (substitute* "setup.py" (("self.parallel if self.parallel else 1") (number->string (parallel-job-count)))))))))
- (native-inputs
- `(("cmake" ,cmake)))
- (home-page "https://github.com/lief-project/LIEF")
- (synopsis "Library to Instrument Executable Formats")
- (description "Python library to to provide a cross platform library which can
-parse, modify and abstract ELF, PE and MachO formats.")
- (license license:asl2.0)))
+ (name "python-lief")
+ (version "0.12.3")
+ (source (origin
+ (method git-fetch)
+ (uri (git-reference
+ (url "https://github.com/lief-project/LIEF")
+ (commit version)))
+ (file-name (git-file-name name version))
+ (sha256
+ (base32
+ "11i6hqmcjh56y554kqhl61698n9v66j2qk1c1g63mv2w07h2z661"))))
+ (build-system python-build-system)
+ (native-inputs (list cmake-minimal))
+ (arguments
+ (list
+ #:tests? #f ;needs network
+ #:phases #~(modify-phases %standard-phases
+ (replace 'build
+ (lambda _
+ (invoke
+ "python" "setup.py" "--sdk" "build"
+ (string-append
+ "-j" (number->string (parallel-job-count)))))))))
+ (home-page "https://github.com/lief-project/LIEF")
+ (synopsis "Library to instrument executable formats")
+ (description
+ "@code{python-lief} is a cross platform library which can parse, modify
+and abstract ELF, PE and MachO formats.")
+ (license license:asl2.0)))
(define osslsigncode
(package
(name "osslsigncode")
- (version "2.0")
+ (version "2.5")
(source (origin
(method url-fetch)
(uri (string-append "https://github.com/mtrojnar/"
name "/archive/" version ".tar.gz"))
(sha256
(base32
- "0byri6xny770wwb2nciq44j5071122l14bvv65axdd70nfjf0q2s"))))
- (build-system gnu-build-system)
- (native-inputs
- `(("pkg-config" ,pkg-config)
- ("autoconf" ,autoconf)
- ("automake" ,automake)
- ("libtool" ,libtool)))
+ "03by9706gg0an6dn48pljx38vcb76ziv11bgm8ilwsf293x2k4hv"))))
+ (build-system cmake-build-system)
(inputs
- `(("openssl" ,openssl)))
+ `(("openssl", openssl)))
(arguments
- `(#:configure-flags
- `("--without-gsf"
- "--without-curl"
- "--disable-dependency-tracking")))
+ '(#:configure-flags
+ (list "-DCMAKE_DISABLE_FIND_PACKAGE_CURL=TRUE")))
(home-page "https://github.com/mtrojnar/osslsigncode")
(synopsis "Authenticode signing and timestamping tool")
(description "osslsigncode is a small tool that implements part of the
@@ -534,36 +535,18 @@ and endian independent.")
inspecting signatures in Mach-O binaries.")
(license license:expat))))
-(define (make-glibc-without-werror glibc)
- (package-with-extra-configure-variable glibc "enable_werror" "no"))
-
-(define (make-glibc-with-stack-protector glibc)
- (package-with-extra-configure-variable glibc "--enable-stack-protector" "all"))
-
-(define (make-glibc-with-bind-now glibc)
- (package-with-extra-configure-variable glibc "--enable-bind-now" "yes"))
-
-(define-public glibc-2.24
- (package
- (inherit glibc-2.31)
- (version "2.24")
- (source (origin
- (method git-fetch)
- (uri (git-reference
- (url "https://sourceware.org/git/glibc.git")
- (commit "0d7f1ed30969886c8dde62fbf7d2c79967d4bace")))
- (file-name (git-file-name "glibc" "0d7f1ed30969886c8dde62fbf7d2c79967d4bace"))
- (sha256
- (base32
- "0g5hryia5v1k0qx97qffgwzrz4lr4jw3s5kj04yllhswsxyjbic3"))
- (patches (search-our-patches "glibc-ldd-x86_64.patch"
- "glibc-versioned-locpath.patch"
- "glibc-2.24-elfm-loadaddr-dynamic-rewrite.patch"
- "glibc-2.24-no-build-time-cxx-header-run.patch"
- "glibc-2.24-fcommon.patch"
- "glibc-2.24-guix-prefix.patch"))))))
+;; https://www.gnu.org/software/libc/manual/html_node/Configuring-and-compiling.html
+;; We don't use --disable-werror directly, as that would be passed through to bash,
+;; and cause it's build to fail.
+(define (hardened-glibc glibc)
+ (package-with-extra-configure-variable (
+ package-with-extra-configure-variable (
+ package-with-extra-configure-variable glibc
+ "enable_werror" "no")
+ "--enable-stack-protector" "all")
+ "--enable-bind-now" "yes"))
-(define-public glibc-2.27/bitcoin-patched
+(define-public glibc-2.27
(package
(inherit glibc-2.31)
(version "2.27")
@@ -571,22 +554,23 @@ inspecting signatures in Mach-O binaries.")
(method git-fetch)
(uri (git-reference
(url "https://sourceware.org/git/glibc.git")
- (commit "23158b08a0908f381459f273a984c6fd328363cb")))
- (file-name (git-file-name "glibc" "23158b08a0908f381459f273a984c6fd328363cb"))
+ (commit "73886db6218e613bd6d4edf529f11e008a6c2fa6")))
+ (file-name (git-file-name "glibc" "73886db6218e613bd6d4edf529f11e008a6c2fa6"))
(sha256
(base32
- "1b2n1gxv9f4fd5yy68qjbnarhf8mf4vmlxk10i3328c1w5pmp0ca"))
+ "0azpb9cvnbv25zg8019rqz48h8i2257ngyjg566dlnp74ivrs9vq"))
(patches (search-our-patches "glibc-ldd-x86_64.patch"
+ "glibc-versioned-locpath.patch"
"glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch"
- "glibc-2.27-dont-redefine-nss-database.patch"
+ "glibc-2.27-fcommon.patch"
"glibc-2.27-guix-prefix.patch"))))))
(packages->manifest
(append
(list ;; The Basics
- bash
+ bash-minimal
which
- coreutils
+ coreutils-minimal
util-linux
;; File(system) inspection
file
@@ -614,25 +598,21 @@ inspecting signatures in Mach-O binaries.")
gcc-toolchain-10
(list gcc-toolchain-10 "static")
;; Scripting
- python-3
+ python-minimal ;; (3.9)
;; Git
git-minimal
;; Tests
- (fix-ppc64-nx-default lief))
+ (fix-ppc64-nx-default python-lief))
(let ((target (getenv "HOST")))
(cond ((string-suffix? "-mingw32" target)
;; Windows
(list zip
(make-mingw-pthreads-cross-toolchain "x86_64-w64-mingw32")
(make-nsis-for-gcc-10 nsis-x86_64)
+ nss-certs
osslsigncode))
((string-contains target "-linux-")
- (list (cond ((string-contains target "riscv64-")
- (make-bitcoin-cross-toolchain target
- #:base-libc (make-glibc-with-stack-protector
- (make-glibc-with-bind-now (make-glibc-without-werror glibc-2.27/bitcoin-patched)))))
- (else
- (make-bitcoin-cross-toolchain target)))))
+ (list (make-bitcoin-cross-toolchain target)))
((string-contains target "darwin")
- (list clang-toolchain-10 binutils cmake xorriso python-signapple))
+ (list clang-toolchain-10 binutils cmake-minimal xorriso python-signapple))
(else '())))))
diff --git a/contrib/guix/patches/glibc-2.24-elfm-loadaddr-dynamic-rewrite.patch b/contrib/guix/patches/glibc-2.24-elfm-loadaddr-dynamic-rewrite.patch
deleted file mode 100644
index 5c4d0c6ebe..0000000000
--- a/contrib/guix/patches/glibc-2.24-elfm-loadaddr-dynamic-rewrite.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-https://sourceware.org/git/?p=glibc.git;a=commit;h=a68ba2f3cd3cbe32c1f31e13c20ed13487727b32
-
-commit 6b02af31e9a721bb15a11380cd22d53b621711f8
-Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
-Date: Wed Oct 18 17:26:23 2017 +0100
-
- [AARCH64] Rewrite elf_machine_load_address using _DYNAMIC symbol
-
- This patch rewrites aarch64 elf_machine_load_address to use special _DYNAMIC
- symbol instead of _dl_start.
-
- The static address of _DYNAMIC symbol is stored in the first GOT entry.
- Here is the change which makes this solution work (part of binutils 2.24):
- https://sourceware.org/ml/binutils/2013-06/msg00248.html
-
- i386, x86_64 targets use the same method to do this as well.
-
- The original implementation relies on a trick that R_AARCH64_ABS32 relocation
- being resolved at link time and the static address fits in the 32bits.
- However, in LP64, normally, the address is defined to be 64 bit.
-
- Here is the C version one which should be portable in all cases.
-
- * sysdeps/aarch64/dl-machine.h (elf_machine_load_address): Use
- _DYNAMIC symbol to calculate load address.
-
-diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
-index e86d8b5b63..5a5b8a5de5 100644
---- a/sysdeps/aarch64/dl-machine.h
-+++ b/sysdeps/aarch64/dl-machine.h
-@@ -49,26 +49,11 @@ elf_machine_load_address (void)
- /* To figure out the load address we use the definition that for any symbol:
- dynamic_addr(symbol) = static_addr(symbol) + load_addr
-
-- The choice of symbol is arbitrary. The static address we obtain
-- by constructing a non GOT reference to the symbol, the dynamic
-- address of the symbol we compute using adrp/add to compute the
-- symbol's address relative to the PC.
-- This depends on 32bit relocations being resolved at link time
-- and that the static address fits in the 32bits. */
--
-- ElfW(Addr) static_addr;
-- ElfW(Addr) dynamic_addr;
--
-- asm (" \n"
--" adrp %1, _dl_start; \n"
--" add %1, %1, #:lo12:_dl_start \n"
--" ldr %w0, 1f \n"
--" b 2f \n"
--"1: \n"
--" .word _dl_start \n"
--"2: \n"
-- : "=r" (static_addr), "=r" (dynamic_addr));
-- return dynamic_addr - static_addr;
-+ _DYNAMIC sysmbol is used here as its link-time address stored in
-+ the special unrelocated first GOT entry. */
-+
-+ extern ElfW(Dyn) _DYNAMIC[] attribute_hidden;
-+ return (ElfW(Addr)) &_DYNAMIC - elf_machine_dynamic ();
- }
-
- /* Set up the loaded object described by L so its unrelocated PLT
diff --git a/contrib/guix/patches/glibc-2.24-guix-prefix.patch b/contrib/guix/patches/glibc-2.24-guix-prefix.patch
deleted file mode 100644
index 875e8cd611..0000000000
--- a/contrib/guix/patches/glibc-2.24-guix-prefix.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-Without ffile-prefix-map, the debug symbols will contain paths for the
-guix store which will include the hashes of each package. However, the
-hash for the same package will differ when on different architectures.
-In order to be reproducible regardless of the architecture used to build
-the package, map all guix store prefixes to something fixed, e.g. /usr.
-
-We might be able to drop this in favour of using --with-nonshared-cflags
-when we being using newer versions of glibc.
-
---- a/Makeconfig
-+++ b/Makeconfig
-@@ -950,6 +950,10 @@ object-suffixes-for-libc += .oS
- # shared objects. We don't want to use CFLAGS-os because users may, for
- # example, make that processor-specific.
- CFLAGS-.oS = $(CFLAGS-.o) $(PIC-ccflag)
-+
-+# Map Guix store paths to /usr
-+CFLAGS-.oS += `find /gnu/store -maxdepth 1 -mindepth 1 -type d -exec echo -n " -ffile-prefix-map={}=/usr" \;`
-+
- CPPFLAGS-.oS = $(CPPFLAGS-.o) -DPIC -DLIBC_NONSHARED=1
- libtype.oS = lib%_nonshared.a
- endif
---
-2.35.1
-
diff --git a/contrib/guix/patches/glibc-2.24-no-build-time-cxx-header-run.patch b/contrib/guix/patches/glibc-2.24-no-build-time-cxx-header-run.patch
deleted file mode 100644
index 11fe7fdc99..0000000000
--- a/contrib/guix/patches/glibc-2.24-no-build-time-cxx-header-run.patch
+++ /dev/null
@@ -1,100 +0,0 @@
-https://sourceware.org/git/?p=glibc.git;a=commit;h=fc3e1337be1c6935ab58bd13520f97a535cf70cc
-
-commit dc23a45db566095e83ff0b7a57afc87fb5ca89a1
-Author: Florian Weimer <fweimer@redhat.com>
-Date: Wed Sep 21 10:45:32 2016 +0200
-
- Avoid running $(CXX) during build to obtain header file paths
-
- This reduces the build time somewhat and is particularly noticeable
- during rebuilds with few code changes.
-
-diff --git a/Makerules b/Makerules
-index 7e4077ee50..c338850de5 100644
---- a/Makerules
-+++ b/Makerules
-@@ -121,14 +121,10 @@ ifneq (,$(CXX))
- # will be used instead of /usr/include/stdlib.h and /usr/include/math.h.
- before-compile := $(common-objpfx)cstdlib $(common-objpfx)cmath \
- $(before-compile)
--cstdlib=$(shell echo "\#include <cstdlib>" | $(CXX) -M -MP -x c++ - \
-- | sed -n "/cstdlib:/{s/:$$//;p}")
--$(common-objpfx)cstdlib: $(cstdlib)
-+$(common-objpfx)cstdlib: $(c++-cstdlib-header)
- $(INSTALL_DATA) $< $@T
- $(move-if-change) $@T $@
--cmath=$(shell echo "\#include <cmath>" | $(CXX) -M -MP -x c++ - \
-- | sed -n "/cmath:/{s/:$$//;p}")
--$(common-objpfx)cmath: $(cmath)
-+$(common-objpfx)cmath: $(c++-cmath-header)
- $(INSTALL_DATA) $< $@T
- $(move-if-change) $@T $@
- endif
-diff --git a/config.make.in b/config.make.in
-index 95c6f36876..04a8b3ed7f 100644
---- a/config.make.in
-+++ b/config.make.in
-@@ -45,6 +45,8 @@ defines = @DEFINES@
- sysheaders = @sysheaders@
- sysincludes = @SYSINCLUDES@
- c++-sysincludes = @CXX_SYSINCLUDES@
-+c++-cstdlib-header = @CXX_CSTDLIB_HEADER@
-+c++-cmath-header = @CXX_CMATH_HEADER@
- all-warnings = @all_warnings@
- enable-werror = @enable_werror@
-
-diff --git a/configure b/configure
-index 17625e1041..6ff252744b 100755
---- a/configure
-+++ b/configure
-@@ -635,6 +635,8 @@ BISON
- INSTALL_INFO
- PERL
- BASH_SHELL
-+CXX_CMATH_HEADER
-+CXX_CSTDLIB_HEADER
- CXX_SYSINCLUDES
- SYSINCLUDES
- AUTOCONF
-@@ -5054,6 +5056,18 @@ fi
-
-
-
-+# Obtain some C++ header file paths. This is used to make a local
-+# copy of those headers in Makerules.
-+if test -n "$CXX"; then
-+ find_cxx_header () {
-+ echo "#include <$1>" | $CXX -M -MP -x c++ - | sed -n "/$1:/{s/:\$//;p}"
-+ }
-+ CXX_CSTDLIB_HEADER="$(find_cxx_header cstdlib)"
-+ CXX_CMATH_HEADER="$(find_cxx_header cmath)"
-+fi
-+
-+
-+
- # Test if LD_LIBRARY_PATH contains the notation for the current directory
- # since this would lead to problems installing/building glibc.
- # LD_LIBRARY_PATH contains the current directory if one of the following
-diff --git a/configure.ac b/configure.ac
-index 33bcd62180..9938ab0dc2 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1039,6 +1039,18 @@ fi
- AC_SUBST(SYSINCLUDES)
- AC_SUBST(CXX_SYSINCLUDES)
-
-+# Obtain some C++ header file paths. This is used to make a local
-+# copy of those headers in Makerules.
-+if test -n "$CXX"; then
-+ find_cxx_header () {
-+ echo "#include <$1>" | $CXX -M -MP -x c++ - | sed -n "/$1:/{s/:\$//;p}"
-+ }
-+ CXX_CSTDLIB_HEADER="$(find_cxx_header cstdlib)"
-+ CXX_CMATH_HEADER="$(find_cxx_header cmath)"
-+fi
-+AC_SUBST(CXX_CSTDLIB_HEADER)
-+AC_SUBST(CXX_CMATH_HEADER)
-+
- # Test if LD_LIBRARY_PATH contains the notation for the current directory
- # since this would lead to problems installing/building glibc.
- # LD_LIBRARY_PATH contains the current directory if one of the following
diff --git a/contrib/guix/patches/glibc-2.27-dont-redefine-nss-database.patch b/contrib/guix/patches/glibc-2.27-dont-redefine-nss-database.patch
deleted file mode 100644
index 16a595d613..0000000000
--- a/contrib/guix/patches/glibc-2.27-dont-redefine-nss-database.patch
+++ /dev/null
@@ -1,87 +0,0 @@
-commit 78a90c2f74a2012dd3eff302189e47ff6779a757
-Author: Andreas Schwab <schwab@linux-m68k.org>
-Date: Fri Mar 2 23:07:14 2018 +0100
-
- Fix multiple definitions of __nss_*_database (bug 22918)
-
- (cherry picked from commit eaf6753f8aac33a36deb98c1031d1bad7b593d2d)
-
-diff --git a/nscd/gai.c b/nscd/gai.c
-index d081747797..576fd0045b 100644
---- a/nscd/gai.c
-+++ b/nscd/gai.c
-@@ -45,3 +45,6 @@
- #ifdef HAVE_LIBIDN
- # include <libidn/idn-stub.c>
- #endif
-+
-+/* Some variables normally defined in libc. */
-+service_user *__nss_hosts_database attribute_hidden;
-diff --git a/nss/nsswitch.c b/nss/nsswitch.c
-index d5e655974f..b0f0c11a3e 100644
---- a/nss/nsswitch.c
-+++ b/nss/nsswitch.c
-@@ -62,7 +62,7 @@ static service_library *nss_new_service (name_database *database,
-
- /* Declare external database variables. */
- #define DEFINE_DATABASE(name) \
-- extern service_user *__nss_##name##_database attribute_hidden; \
-+ service_user *__nss_##name##_database attribute_hidden; \
- weak_extern (__nss_##name##_database)
- #include "databases.def"
- #undef DEFINE_DATABASE
-diff --git a/nss/nsswitch.h b/nss/nsswitch.h
-index eccb535ef5..63573b9ebc 100644
---- a/nss/nsswitch.h
-+++ b/nss/nsswitch.h
-@@ -226,10 +226,10 @@ libc_hidden_proto (__nss_hostname_digits_dots)
- #define MAX_NR_ADDRS 48
-
- /* Prototypes for __nss_*_lookup2 functions. */
--#define DEFINE_DATABASE(arg) \
-- service_user *__nss_##arg##_database attribute_hidden; \
-- int __nss_##arg##_lookup2 (service_user **, const char *, \
-- const char *, void **); \
-+#define DEFINE_DATABASE(arg) \
-+ extern service_user *__nss_##arg##_database attribute_hidden; \
-+ int __nss_##arg##_lookup2 (service_user **, const char *, \
-+ const char *, void **); \
- libc_hidden_proto (__nss_##arg##_lookup2)
- #include "databases.def"
- #undef DEFINE_DATABASE
-diff --git a/posix/tst-rfc3484-2.c b/posix/tst-rfc3484-2.c
-index f509534ca9..8c64ac59ff 100644
---- a/posix/tst-rfc3484-2.c
-+++ b/posix/tst-rfc3484-2.c
-@@ -58,6 +58,7 @@ _res_hconf_init (void)
- #undef USE_NSCD
- #include "../sysdeps/posix/getaddrinfo.c"
-
-+service_user *__nss_hosts_database attribute_hidden;
-
- /* This is the beginning of the real test code. The above defines
- (among other things) the function rfc3484_sort. */
-diff --git a/posix/tst-rfc3484-3.c b/posix/tst-rfc3484-3.c
-index ae44087a10..1c61aaf844 100644
---- a/posix/tst-rfc3484-3.c
-+++ b/posix/tst-rfc3484-3.c
-@@ -58,6 +58,7 @@ _res_hconf_init (void)
- #undef USE_NSCD
- #include "../sysdeps/posix/getaddrinfo.c"
-
-+service_user *__nss_hosts_database attribute_hidden;
-
- /* This is the beginning of the real test code. The above defines
- (among other things) the function rfc3484_sort. */
-diff --git a/posix/tst-rfc3484.c b/posix/tst-rfc3484.c
-index 7f191abbbc..8f45848e44 100644
---- a/posix/tst-rfc3484.c
-+++ b/posix/tst-rfc3484.c
-@@ -58,6 +58,7 @@ _res_hconf_init (void)
- #undef USE_NSCD
- #include "../sysdeps/posix/getaddrinfo.c"
-
-+service_user *__nss_hosts_database attribute_hidden;
-
- /* This is the beginning of the real test code. The above defines
- (among other things) the function rfc3484_sort. */
diff --git a/contrib/guix/patches/glibc-2.24-fcommon.patch b/contrib/guix/patches/glibc-2.27-fcommon.patch
index 2bc32ede90..f3baacab98 100644
--- a/contrib/guix/patches/glibc-2.24-fcommon.patch
+++ b/contrib/guix/patches/glibc-2.27-fcommon.patch
@@ -18,15 +18,15 @@ Date: Fri May 6 11:03:04 2022 +0100
https://sourceware.org/git/?p=glibc.git;a=commit;h=7650321ce037302bfc2f026aa19e0213b8d02fe6
diff --git a/Makeconfig b/Makeconfig
-index ee379f5852..63c4a2f234 100644
+index 86a71e5802..aa2166be60 100644
--- a/Makeconfig
+++ b/Makeconfig
-@@ -824,7 +824,7 @@ ifeq "$(strip $(+cflags))" ""
- +cflags := $(default_cflags)
+@@ -896,7 +896,7 @@ ifeq "$(strip $(+cflags))" ""
endif # $(+cflags) == ""
--+cflags += $(cflags-cpu) $(+gccwarn) $(+merge-constants) $(+math-flags)
-++cflags += $(cflags-cpu) $(+gccwarn) $(+merge-constants) $(+math-flags) -fcommon
+ +cflags += $(cflags-cpu) $(+gccwarn) $(+merge-constants) $(+math-flags) \
+- $(+stack-protector)
++ $(+stack-protector) -fcommon
+gcc-nowarn := -w
# Don't duplicate options if we inherited variables from the parent.
diff --git a/contrib/guix/patches/glibc-2.27-guix-prefix.patch b/contrib/guix/patches/glibc-2.27-guix-prefix.patch
index d777af74f0..6648bc6c05 100644
--- a/contrib/guix/patches/glibc-2.27-guix-prefix.patch
+++ b/contrib/guix/patches/glibc-2.27-guix-prefix.patch
@@ -20,6 +20,3 @@ when we being using newer versions of glibc.
libtype.o := lib%.a
object-suffixes += .o
ifeq (yes,$(build-shared))
---
-2.35.1
-
diff --git a/contrib/guix/patches/glibc-ldd-x86_64.patch b/contrib/guix/patches/glibc-ldd-x86_64.patch
index b1b6d5a548..a23b095caa 100644
--- a/contrib/guix/patches/glibc-ldd-x86_64.patch
+++ b/contrib/guix/patches/glibc-ldd-x86_64.patch
@@ -1,8 +1,8 @@
By default, 'RTDLLIST' in 'ldd' refers to 'lib64/ld-linux-x86-64.so', whereas
it's in 'lib/' for us. This patch fixes that.
---- glibc-2.17/sysdeps/unix/sysv/linux/x86_64/ldd-rewrite.sed 2012-12-25 04:02:13.000000000 +0100
-+++ glibc-2.17/sysdeps/unix/sysv/linux/x86_64/ldd-rewrite.sed 2013-09-15 23:08:03.000000000 +0200
+--- a/sysdeps/unix/sysv/linux/x86_64/ldd-rewrite.sed
++++ b/sysdeps/unix/sysv/linux/x86_64/ldd-rewrite.sed
@@ -1,3 +1,3 @@
/LD_TRACE_LOADED_OBJECTS=1/a\
add_env="$add_env LD_LIBRARY_VERSION=\\$verify_out"
diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh
deleted file mode 100755
index c7d39f5b99..0000000000
--- a/contrib/install_db4.sh
+++ /dev/null
@@ -1,259 +0,0 @@
-#!/bin/sh
-# Copyright (c) 2017-2021 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-# Install libdb4.8 (Berkeley DB).
-
-export LC_ALL=C
-set -e
-
-if [ -z "${1}" ]; then
- echo "Usage: $0 <base-dir> [<extra-bdb-configure-flag> ...]"
- echo
- echo "Must specify a single argument: the directory in which db4 will be built."
- echo "This is probably \`pwd\` if you're at the root of the bitcoin repository."
- exit 1
-fi
-
-expand_path() {
- cd "${1}" && pwd -P
-}
-
-BDB_PREFIX="$(expand_path "${1}")/db4"; shift;
-BDB_VERSION='db-4.8.30.NC'
-BDB_HASH='12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef'
-BDB_URL="https://download.oracle.com/berkeley-db/${BDB_VERSION}.tar.gz"
-
-check_exists() {
- command -v "$1" >/dev/null
-}
-
-sha256_check() {
- # Args: <sha256_hash> <filename>
- #
- if [ "$(uname)" = "FreeBSD" ]; then
- # sha256sum exists on FreeBSD, but takes different arguments than the GNU version
- sha256 -c "${1}" "${2}"
- elif check_exists sha256sum; then
- echo "${1} ${2}" | sha256sum -c
- elif check_exists sha256; then
- echo "${1} ${2}" | sha256 -c
- else
- echo "${1} ${2}" | shasum -a 256 -c
- fi
-}
-
-http_get() {
- # Args: <url> <filename> <sha256_hash>
- #
- # It's acceptable that we don't require SSL here because we manually verify
- # content hashes below.
- #
- if [ -f "${2}" ]; then
- echo "File ${2} already exists; not downloading again"
- elif check_exists curl; then
- curl --insecure --retry 5 "${1}" -o "${2}"
- elif check_exists wget; then
- wget --no-check-certificate "${1}" -O "${2}"
- else
- echo "Simple transfer utilities 'curl' and 'wget' not found. Please install one of them and try again."
- exit 1
- fi
-
- sha256_check "${3}" "${2}"
-}
-
-# Ensure the commands we use exist on the system
-if ! check_exists patch; then
- echo "Command-line tool 'patch' not found. Install patch and try again."
- exit 1
-fi
-
-mkdir -p "${BDB_PREFIX}"
-http_get "${BDB_URL}" "${BDB_VERSION}.tar.gz" "${BDB_HASH}"
-tar -xzvf ${BDB_VERSION}.tar.gz -C "$BDB_PREFIX"
-cd "${BDB_PREFIX}/${BDB_VERSION}/"
-
-# Apply a patch necessary when building with clang and c++11 (see https://community.oracle.com/thread/3952592)
-patch --ignore-whitespace -p1 << 'EOF'
-commit 3311d68f11d1697565401eee6efc85c34f022ea7
-Author: fanquake <fanquake@gmail.com>
-Date: Mon Aug 17 20:03:56 2020 +0800
-
- Fix C++11 compatibility
-
-diff --git a/dbinc/atomic.h b/dbinc/atomic.h
-index 0034dcc..7c11d4a 100644
---- a/dbinc/atomic.h
-+++ b/dbinc/atomic.h
-@@ -70,7 +70,7 @@ typedef struct {
- * These have no memory barriers; the caller must include them when necessary.
- */
- #define atomic_read(p) ((p)->value)
--#define atomic_init(p, val) ((p)->value = (val))
-+#define atomic_init_db(p, val) ((p)->value = (val))
-
- #ifdef HAVE_ATOMIC_SUPPORT
-
-@@ -144,7 +144,7 @@ typedef LONG volatile *interlocked_val;
- #define atomic_inc(env, p) __atomic_inc(p)
- #define atomic_dec(env, p) __atomic_dec(p)
- #define atomic_compare_exchange(env, p, o, n) \
-- __atomic_compare_exchange((p), (o), (n))
-+ __atomic_compare_exchange_db((p), (o), (n))
- static inline int __atomic_inc(db_atomic_t *p)
- {
- int temp;
-@@ -176,7 +176,7 @@ static inline int __atomic_dec(db_atomic_t *p)
- * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
- * which configure could be changed to use.
- */
--static inline int __atomic_compare_exchange(
-+static inline int __atomic_compare_exchange_db(
- db_atomic_t *p, atomic_value_t oldval, atomic_value_t newval)
- {
- atomic_value_t was;
-@@ -206,7 +206,7 @@ static inline int __atomic_compare_exchange(
- #define atomic_dec(env, p) (--(p)->value)
- #define atomic_compare_exchange(env, p, oldval, newval) \
- (DB_ASSERT(env, atomic_read(p) == (oldval)), \
-- atomic_init(p, (newval)), 1)
-+ atomic_init_db(p, (newval)), 1)
- #else
- #define atomic_inc(env, p) __atomic_inc(env, p)
- #define atomic_dec(env, p) __atomic_dec(env, p)
-diff --git a/mp/mp_fget.c b/mp/mp_fget.c
-index 5fdee5a..0b75f57 100644
---- a/mp/mp_fget.c
-+++ b/mp/mp_fget.c
-@@ -617,7 +617,7 @@ alloc: /* Allocate a new buffer header and data space. */
-
- /* Initialize enough so we can call __memp_bhfree. */
- alloc_bhp->flags = 0;
-- atomic_init(&alloc_bhp->ref, 1);
-+ atomic_init_db(&alloc_bhp->ref, 1);
- #ifdef DIAGNOSTIC
- if ((uintptr_t)alloc_bhp->buf & (sizeof(size_t) - 1)) {
- __db_errx(env,
-@@ -911,7 +911,7 @@ alloc: /* Allocate a new buffer header and data space. */
- MVCC_MPROTECT(bhp->buf, mfp->stat.st_pagesize,
- PROT_READ);
-
-- atomic_init(&alloc_bhp->ref, 1);
-+ atomic_init_db(&alloc_bhp->ref, 1);
- MUTEX_LOCK(env, alloc_bhp->mtx_buf);
- alloc_bhp->priority = bhp->priority;
- alloc_bhp->pgno = bhp->pgno;
-diff --git a/mp/mp_mvcc.c b/mp/mp_mvcc.c
-index 34467d2..f05aa0c 100644
---- a/mp/mp_mvcc.c
-+++ b/mp/mp_mvcc.c
-@@ -276,7 +276,7 @@ __memp_bh_freeze(dbmp, infop, hp, bhp, need_frozenp)
- #else
- memcpy(frozen_bhp, bhp, SSZA(BH, buf));
- #endif
-- atomic_init(&frozen_bhp->ref, 0);
-+ atomic_init_db(&frozen_bhp->ref, 0);
- if (mutex != MUTEX_INVALID)
- frozen_bhp->mtx_buf = mutex;
- else if ((ret = __mutex_alloc(env, MTX_MPOOL_BH,
-@@ -428,7 +428,7 @@ __memp_bh_thaw(dbmp, infop, hp, frozen_bhp, alloc_bhp)
- #endif
- alloc_bhp->mtx_buf = mutex;
- MUTEX_LOCK(env, alloc_bhp->mtx_buf);
-- atomic_init(&alloc_bhp->ref, 1);
-+ atomic_init_db(&alloc_bhp->ref, 1);
- F_CLR(alloc_bhp, BH_FROZEN);
- }
-
-diff --git a/mp/mp_region.c b/mp/mp_region.c
-index e6cece9..ddbe906 100644
---- a/mp/mp_region.c
-+++ b/mp/mp_region.c
-@@ -224,7 +224,7 @@ __memp_init(env, dbmp, reginfo_off, htab_buckets, max_nreg)
- MTX_MPOOL_FILE_BUCKET, 0, &htab[i].mtx_hash)) != 0)
- return (ret);
- SH_TAILQ_INIT(&htab[i].hash_bucket);
-- atomic_init(&htab[i].hash_page_dirty, 0);
-+ atomic_init_db(&htab[i].hash_page_dirty, 0);
- }
-
- /*
-@@ -269,7 +269,7 @@ __memp_init(env, dbmp, reginfo_off, htab_buckets, max_nreg)
- hp->mtx_hash = (mtx_base == MUTEX_INVALID) ? MUTEX_INVALID :
- mtx_base + i;
- SH_TAILQ_INIT(&hp->hash_bucket);
-- atomic_init(&hp->hash_page_dirty, 0);
-+ atomic_init_db(&hp->hash_page_dirty, 0);
- #ifdef HAVE_STATISTICS
- hp->hash_io_wait = 0;
- hp->hash_frozen = hp->hash_thawed = hp->hash_frozen_freed = 0;
-diff --git a/mutex/mut_method.c b/mutex/mut_method.c
-index 2588763..5c6d516 100644
---- a/mutex/mut_method.c
-+++ b/mutex/mut_method.c
-@@ -426,7 +426,7 @@ atomic_compare_exchange(env, v, oldval, newval)
- MUTEX_LOCK(env, mtx);
- ret = atomic_read(v) == oldval;
- if (ret)
-- atomic_init(v, newval);
-+ atomic_init_db(v, newval);
- MUTEX_UNLOCK(env, mtx);
-
- return (ret);
-diff --git a/mutex/mut_tas.c b/mutex/mut_tas.c
-index f3922e0..e40fcdf 100644
---- a/mutex/mut_tas.c
-+++ b/mutex/mut_tas.c
-@@ -46,7 +46,7 @@ __db_tas_mutex_init(env, mutex, flags)
-
- #ifdef HAVE_SHARED_LATCHES
- if (F_ISSET(mutexp, DB_MUTEX_SHARED))
-- atomic_init(&mutexp->sharecount, 0);
-+ atomic_init_db(&mutexp->sharecount, 0);
- else
- #endif
- if (MUTEX_INIT(&mutexp->tas)) {
-@@ -486,7 +486,7 @@ __db_tas_mutex_unlock(env, mutex)
- F_CLR(mutexp, DB_MUTEX_LOCKED);
- /* Flush flag update before zeroing count */
- MEMBAR_EXIT();
-- atomic_init(&mutexp->sharecount, 0);
-+ atomic_init_db(&mutexp->sharecount, 0);
- } else {
- DB_ASSERT(env, sharecount > 0);
- MEMBAR_EXIT();
-EOF
-
-# The packaged config.guess and config.sub are ancient (2009) and can cause build issues.
-# Replace them with modern versions.
-# See https://github.com/bitcoin/bitcoin/issues/16064
-CONFIG_GUESS_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=4550d2f15b3a7ce2451c1f29500b9339430c877f'
-CONFIG_GUESS_HASH='c8f530e01840719871748a8071113435bdfdf75b74c57e78e47898edea8754ae'
-CONFIG_SUB_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=4550d2f15b3a7ce2451c1f29500b9339430c877f'
-CONFIG_SUB_HASH='3969f7d5f6967ccc6f792401b8ef3916a1d1b1d0f0de5a4e354c95addb8b800e'
-
-rm -f "dist/config.guess"
-rm -f "dist/config.sub"
-
-http_get "${CONFIG_GUESS_URL}" dist/config.guess "${CONFIG_GUESS_HASH}"
-http_get "${CONFIG_SUB_URL}" dist/config.sub "${CONFIG_SUB_HASH}"
-
-cd build_unix/
-
-"${BDB_PREFIX}/${BDB_VERSION}/dist/configure" \
- --enable-cxx --disable-shared --disable-replication --with-pic --prefix="${BDB_PREFIX}" \
- "${@}"
-
-make install
-
-echo
-echo "db4 build complete."
-echo
-# shellcheck disable=SC2016
-echo 'When compiling bitcoind, run `./configure` in the following way:'
-echo
-echo " export BDB_PREFIX='${BDB_PREFIX}'"
-# shellcheck disable=SC2016
-echo ' ./configure BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include" ...'
diff --git a/contrib/seeds/README.md b/contrib/seeds/README.md
index b2ea7522ac..6db77cbbea 100644
--- a/contrib/seeds/README.md
+++ b/contrib/seeds/README.md
@@ -11,8 +11,10 @@ to addrman with).
The seeds compiled into the release are created from sipa's DNS seed and AS map
data. Run the following commands from the `/contrib/seeds` directory:
- curl https://bitcoin.sipa.be/seeds.txt.gz | gzip -dc > seeds_main.txt
- curl https://bitcoin.sipa.be/asmap-filled.dat > asmap-filled.dat
- python3 makeseeds.py -a asmap-filled.dat < seeds_main.txt > nodes_main.txt
- cat nodes_main_manual.txt >> nodes_main.txt
- python3 generate-seeds.py . > ../../src/chainparamsseeds.h
+```
+curl https://bitcoin.sipa.be/seeds.txt.gz | gzip -dc > seeds_main.txt
+curl https://bitcoin.sipa.be/asmap-filled.dat > asmap-filled.dat
+python3 makeseeds.py -a asmap-filled.dat -s seeds_main.txt > nodes_main.txt
+cat nodes_main_manual.txt >> nodes_main.txt
+python3 generate-seeds.py . > ../../src/chainparamsseeds.h
+```
diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py
index a6f435af0d..e921757802 100755
--- a/contrib/seeds/generate-seeds.py
+++ b/contrib/seeds/generate-seeds.py
@@ -3,7 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
-Script to generate list of seed nodes for chainparams.cpp.
+Script to generate list of seed nodes for kernel/chainparams.cpp.
This script expects two text files in the directory that is passed as an
argument:
diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py
index eda58c370f..af408c2df5 100755
--- a/contrib/seeds/makeseeds.py
+++ b/contrib/seeds/makeseeds.py
@@ -37,19 +37,26 @@ PATTERN_AGENT = re.compile(
r"0.19.(0|1|2|99)|"
r"0.20.(0|1|2|99)|"
r"0.21.(0|1|2|99)|"
- r"22.(0|99)|"
- r"23.(0|99)|"
- r"24.99"
+ r"22.(0|1|99)|"
+ r"23.(0|1|99)|"
+ r"24.(0|1|99)|"
+ r"25.99"
r")")
def parseline(line: str) -> Union[dict, None]:
""" Parses a line from `seeds_main.txt` into a dictionary of details for that line.
or `None`, if the line could not be parsed.
"""
+ if line.startswith('#'):
+ # Ignore line that starts with comment
+ return None
sline = line.split()
if len(sline) < 11:
# line too short to be valid, skip it.
return None
+ # Skip bad results.
+ if int(sline[1]) == 0:
+ return None
m = PATTERN_IPV4.match(sline[0])
sortkey = None
ip = None
@@ -83,9 +90,6 @@ def parseline(line: str) -> Union[dict, None]:
sortkey = ip
ipstr = m.group(1)
port = int(m.group(6))
- # Skip bad results.
- if sline[1] == 0:
- return None
# Extract uptime %.
uptime30 = float(sline[7][:-1])
# Extract Unix timestamp of last success.
@@ -173,6 +177,7 @@ def ip_stats(ips: List[Dict]) -> str:
def parse_args():
argparser = argparse.ArgumentParser(description='Generate a list of bitcoin node seed ip addresses.')
argparser.add_argument("-a","--asmap", help='the location of the asmap asn database file (required)', required=True)
+ argparser.add_argument("-s","--seeds", help='the location of the DNS seeds file (required)', required=True)
return argparser.parse_args()
def main():
@@ -184,7 +189,8 @@ def main():
print('Done.', file=sys.stderr)
print('Loading and parsing DNS seeds…', end='', file=sys.stderr, flush=True)
- lines = sys.stdin.readlines()
+ with open(args.seeds, 'r', encoding='utf8') as f:
+ lines = f.readlines()
ips = [parseline(line) for line in lines]
print('Done.', file=sys.stderr)
diff --git a/contrib/seeds/nodes_main.txt b/contrib/seeds/nodes_main.txt
index f8572b26c7..100fe09685 100644
--- a/contrib/seeds/nodes_main.txt
+++ b/contrib/seeds/nodes_main.txt
@@ -1,857 +1,896 @@
-2.3.25.181:8333 # AS3215
-2.152.78.124:8333 # AS12430
-5.39.74.166:8333 # AS16276
-5.45.79.81:18332 # AS50673
-5.53.16.128:8333 # AS50923
-5.95.186.78:8333 # AS30722
+1.65.195.98:8333 # AS4760
+2.59.236.56:8333 # AS24904
+2.83.114.20:8333 # AS8657
+2.248.194.16:8333 # AS3301
+5.2.154.6:8333 # AS8708
+5.101.140.30:8333 # AS42831
5.128.87.126:8333 # AS31200
-5.133.65.82:8333 # AS15440
-5.146.20.229:8333 # AS3209
-5.180.41.119:8333 # AS18978
+5.144.21.49:8333 # AS15600
+5.172.132.104:8333 # AS15600
5.188.62.18:8333 # AS34665
-5.199.173.66:8333 # AS16125
-5.255.97.25:8333 # AS60404
-5.255.103.180:8333 # AS60404
-8.209.70.77:8333 # AS45102
+5.200.2.180:8333 # AS49544
+8.129.184.255:8333 # AS37963
8.209.105.138:8333 # AS45102
-18.162.208.153:48332 # AS16509
-23.175.0.200:8333 # AS395502
+12.34.98.148:8333 # AS7018
+14.199.102.151:8333 # AS9269
+18.27.79.17:8333 # AS3
+18.27.124.231:8333 # AS3
+18.216.249.151:8333 # AS16509
+23.88.155.58:8333 # AS10242
+23.93.101.158:8333 # AS46375
+23.109.156.76:8333 # AS7979
+23.175.0.220:8333 # AS395502
23.175.0.222:8333 # AS395502
-23.233.107.21:8333 # AS5645
-23.236.25.169:8333 # AS30029
-24.35.68.229:8333 # AS11404
-24.84.164.50:8333 # AS6327
-24.116.153.115:8333 # AS11492
-24.184.0.146:8333 # AS6128
-27.33.160.196:8333 # AS7545
+24.232.36.225:8333 # AS7303
27.124.108.19:8333 # AS58511
27.148.206.140:8333 # AS4134
-31.17.64.192:8333 # AS204028
-31.18.114.135:8333 # AS204028
+31.7.70.195:8333 # AS49666
+31.25.98.16:8333 # AS48635
31.41.23.249:8333 # AS31287
-31.42.176.138:8333 # AS43641
+31.47.102.92:8333 # AS8251
31.47.202.112:8333 # AS34385
-34.65.45.157:8333 # AS15169
-34.80.134.68:8333 # AS15169
+31.165.78.146:8333 # AS6730
+31.165.228.138:8333 # AS6730
+34.64.101.4:8333 # AS139070
+34.105.19.97:8333 # AS15169
+34.126.107.179:8333 # AS396982
34.126.115.35:8333 # AS396982
-37.1.204.231:8333 # AS50673
+35.245.186.117:8333 # AS15169
+37.15.60.144:8333 # AS12479
+37.16.105.63:8333 # AS20904
37.120.155.34:8333 # AS9009
-37.143.118.174:8333 # AS48926
+37.120.179.29:8333 # AS47147
+37.139.102.73:8333 # AS35816
37.193.227.16:8333 # AS31200
37.220.135.151:8333 # AS41206
-37.235.146.236:8333 # AS41268
-38.124.126.42:8333 # AS11550
+38.53.129.67:8333 # AS40237
+38.54.14.89:8333 # AS138915
38.141.134.140:8333 # AS174
38.145.151.150:8333 # AS40545
-40.115.137.28:8333 # AS8075
41.72.154.66:8333 # AS37153
-41.79.70.146:8333 # AS37349
-42.193.55.135:8333 # AS45090
-43.225.62.107:8333 # AS63953
+43.143.203.198:8333 # AS45090
+45.15.124.117:8333 # AS35913
45.43.97.103:8333 # AS26827
-45.85.48.58:8333 # AS208016
-45.126.26.229:8333 # AS45763
+45.44.213.116:8333 # AS54198
+45.58.187.101:8333 # AS46844
+45.79.192.236:8333 # AS63949
+45.81.241.97:8333 # AS30823
+45.83.220.102:8333 # AS39351
+45.83.241.46:8333 # AS206238
+45.87.106.57:8333 # AS39238
+45.129.38.5:8333 # AS49666
+45.130.20.177:8333 # AS3214
45.134.142.40:8333 # AS60068
-45.154.252.162:8333 # AS13335
-46.13.216.169:8333 # AS6855
+45.135.4.143:8333 # AS25596
+45.135.92.127:8333 # AS12555
+45.145.188.112:8333 # AS206805
46.23.87.218:8333 # AS51088
-46.40.127.164:8333 # AS43205
-46.48.126.58:8333 # AS12668
-46.59.13.35:8333 # AS8473
-46.72.238.17:8333 # AS12714
-46.128.141.184:8333 # AS16097
-46.146.248.89:8333 # AS9049
-46.165.221.209:9333 # AS28753
+46.32.50.98:8333 # AS39642
+46.32.78.17:8333 # AS48416
+46.59.40.91:8333 # AS8473
+46.138.246.77:8333 # AS8359
46.166.142.2:8333 # AS43350
+46.166.162.59:8333 # AS16125
46.175.178.3:8333 # AS28725
-47.36.144.51:8333 # AS20115
-47.180.49.158:8333 # AS5650
-49.228.131.133:2210 # AS133481
+46.188.15.6:8333 # AS39153
+46.188.30.118:8333 # AS39153
+46.223.223.216:8333 # AS51185
+46.226.18.135:8333 # AS52176
+47.88.86.79:8333 # AS45102
+47.148.7.69:8333 # AS5650
+47.198.223.60:8333 # AS5650
50.2.13.164:8333 # AS62904
-50.35.71.51:8333 # AS20055
+50.4.135.84:8333 # AS12083
+50.53.39.237:8333 # AS20055
50.53.250.162:8333 # AS20055
-51.68.36.57:8333 # AS16276
-51.138.4.135:30001 # AS8075
+50.68.121.44:8333 # AS6327
+50.117.132.178:8333 # AS577
51.154.62.103:8333 # AS15796
51.158.150.155:8333 # AS12876
+51.250.46.215:8333 # AS200350
54.176.63.16:8333 # AS16509
58.158.0.86:8333 # AS2519
-59.138.115.137:8333 # AS2516
-59.167.191.60:8333 # AS4739
60.205.205.119:8333 # AS37963
-60.234.122.245:8333 # AS9790
-60.240.210.155:8333 # AS7545
-61.239.91.250:8333 # AS9269
-62.74.143.11:8333 # AS3329
-62.138.162.12:8333 # AS20773
-62.169.74.233:8333 # AS2860
+61.74.99.193:8333 # AS4766
+61.92.59.104:8333 # AS9269
+62.122.173.171:8333 # AS50245
62.171.129.32:8333 # AS51167
-62.209.198.65:8333 # AS6855
-63.247.147.166:8333 # AS30221
-64.98.76.62:8333 # AS32133
+62.178.27.239:8333 # AS8412
+62.209.210.3:8333 # AS6855
+62.215.127.73:8333 # AS21050
+62.238.148.104:8333 # AS15435
+62.245.153.8:8333 # AS8767
+64.146.136.45:8333 # AS16713
+65.21.134.184:8333 # AS24940
+66.18.13.146:8333 # AS13767
+66.23.233.43:8333 # AS19318
+66.27.98.216:8333 # AS20001
66.29.129.218:8333 # AS22612
-66.96.235.28:8333 # AS63859
-66.130.120.52:8333 # AS5769
-66.198.209.243:8333 # AS33152
+66.38.94.13:8333 # AS11979
+66.45.141.46:8333 # AS11232
+66.58.243.215:8333 # AS8047
+66.114.33.49:8333 # AS23175
+66.198.211.167:8333 # AS10835
66.208.64.128:8333 # AS10352
-66.225.231.148:8333 # AS23352
-67.55.3.200:8333 # AS33139
-67.58.232.107:8333 # AS14051
-67.211.92.2:8333 # AS11711
-67.223.119.122:8333 # AS22612
-68.48.131.251:8333 # AS7922
-68.181.4.12:8333 # AS47
-69.14.185.9:8333 # AS12083
-69.54.29.193:8333 # AS12282
+66.219.196.170:8333 # AS29933
+67.210.228.203:8333 # AS7819
+68.183.75.251:8333 # AS14061
+68.194.125.140:8333 # AS6128
+68.199.120.17:8333 # AS6128
+69.4.94.226:8333 # AS36352
+69.8.175.201:8333 # AS21766
69.59.18.22:8333 # AS397444
-69.131.101.176:8333 # AS4181
-69.165.205.142:8833 # AS5645
+69.196.152.33:8333 # AS5645
69.228.219.124:8333 # AS7018
-70.59.123.25:8333 # AS209
-70.62.13.150:8333 # AS7843
-70.66.248.170:8333 # AS6327
-70.112.153.229:8333 # AS7843
+70.64.27.12:8333 # AS6327
70.160.240.132:8333 # AS22773
-70.190.177.204:8333 # AS22773
-71.28.189.239:8333 # AS398465
-71.234.125.198:8333 # AS1351
-72.74.123.179:8333 # AS701
-72.253.236.217:8333 # AS36149
-73.219.254.120:8333 # AS1351
+71.79.109.128:8333 # AS7843
+71.184.193.75:8333 # AS701
+72.15.59.173:8333 # AS21949
+72.48.253.168:8333 # AS7459
+72.207.171.210:8333 # AS22773
+73.117.132.138:8333 # AS7922
+73.212.226.59:8333 # AS7922
+74.76.151.110:8333 # AS7843
74.91.115.229:8333 # AS14586
74.118.137.119:8333 # AS20326
-74.195.166.100:8333 # AS19108
+74.213.175.108:8333 # AS21949
+74.213.251.239:8333 # AS14978
74.220.255.190:8333 # AS23175
-76.67.211.110:8333 # AS577
-76.169.163.14:8333 # AS20001
-77.32.121.162:8333 # AS35612
-77.53.135.74:8333 # AS45011
+74.221.189.109:8333 # AS26827
+75.83.203.225:8333 # AS20001
+75.172.52.186:8333 # AS209
+76.24.143.22:8333 # AS1351
+76.69.202.247:8333 # AS577
+76.73.198.242:8333 # AS12083
+76.119.248.240:8333 # AS1351
+77.20.48.144:8333 # AS3209
+77.22.152.239:8333 # AS204028
+77.37.224.222:8333 # AS42610
+77.48.196.234:8333 # AS16019
77.70.16.245:8333 # AS8717
-77.85.204.149:8333 # AS8866
-77.107.38.239:8333 # AS62183
-77.120.26.102:8333 # AS25229
77.162.190.90:8333 # AS1136
78.20.227.249:8333 # AS6848
78.21.167.8:8333 # AS6848
-78.27.139.13:8333 # AS6723
-78.90.91.220:8333 # AS8717
+78.35.147.203:8333 # AS8422
78.108.108.25:8333 # AS8251
-78.108.108.38:8333 # AS8251
-79.77.182.183:8333 # AS13285
-79.98.159.7:11333 # AS44065
-79.189.211.201:8333 # AS5617
-80.55.225.158:8333 # AS5617
-80.83.186.35:8333 # AS33891
-80.88.172.227:64264 # AS31263
-80.209.87.103:9333 # AS31027
+78.154.237.60:8333 # AS9155
+79.11.31.76:8333 # AS3269
+79.87.88.235:8333 # AS15557
+79.101.1.25:8333 # AS8400
+79.124.7.241:8333 # AS203380
+79.124.7.253:8333 # AS203380
+79.150.68.42:8333 # AS3352
+79.249.10.53:8333 # AS3320
+80.82.21.77:8333 # AS42927
+80.82.76.59:8333 # AS202425
+80.88.172.227:8333 # AS31263
+80.93.213.246:8333 # AS42910
+80.111.142.213:8333 # AS6830
+80.208.227.134:8333 # AS62282
+80.208.228.9:8333 # AS62282
+80.209.64.86:8333 # AS31027
80.229.28.60:8333 # AS2856
81.7.16.182:8333 # AS35366
-81.7.17.202:8333 # AS35366
81.19.10.2:8333 # AS24641
-81.88.221.190:8333 # AS39709
+81.162.196.43:8333 # AS34955
81.171.22.143:8333 # AS60781
+81.172.221.4:8333 # AS12430
81.224.44.164:8333 # AS3301
-81.224.160.81:8333 # AS3301
+81.245.96.36:8333 # AS5432
82.1.68.54:8333 # AS5089
-82.21.164.47:8333 # AS5089
-82.64.116.5:8333 # AS12322
82.66.10.11:8333 # AS12322
+82.66.211.31:8333 # AS12322
+82.71.4.154:8333 # AS13037
82.96.96.40:8333 # AS29686
82.116.50.101:8333 # AS30936
-82.129.68.62:8333 # AS48945
-82.136.99.122:8333 # AS8821
-82.154.24.209:8333 # AS8657
-82.197.215.125:8333 # AS25596
-83.128.132.91:8333 # AS15435
+82.136.98.249:8333 # AS8821
+82.195.237.253:8333 # AS1836
83.137.41.10:8333 # AS31394
-83.208.6.211:8333 # AS5610
+83.171.175.5:8333 # AS8767
83.208.193.242:8333 # AS5610
-83.222.138.85:8333 # AS31736
-83.240.124.68:8333 # AS31246
-83.243.191.199:8333 # AS41164
-84.9.5.211:8333 # AS5378
-84.28.57.90:8333 # AS6830
+83.233.76.165:8333 # AS29518
+83.240.89.196:8333 # AS31246
84.38.3.249:8333 # AS196691
-84.112.60.16:8333 # AS8412
-84.215.56.119:8333 # AS41164
-84.226.243.175:8333 # AS6730
-84.245.14.73:8333 # AS25596
-84.252.157.90:18333 # AS200590
+84.54.23.48:8333 # AS35913
+84.126.216.77:8333 # AS12430
+84.211.187.211:8333 # AS41164
+84.246.200.122:8333 # AS42455
84.255.244.61:8333 # AS34779
-85.23.24.123:8333 # AS16086
-85.52.185.29:8666 # AS12479
-85.58.120.201:8333 # AS12479
-85.93.96.18:8333 # AS29208
-85.165.8.197:8333 # AS2119
-85.173.165.66:8333 # AS12389
-85.184.143.105:8333 # AS39642
-85.191.74.103:8333 # AS39642
+85.165.42.115:8333 # AS2119
85.194.238.134:8333 # AS47605
-85.195.54.110:8333 # AS35706
-85.195.196.142:8333 # AS13030
-85.208.69.11:8333 # AS25091
85.208.69.21:8333 # AS25091
85.208.71.36:8333 # AS42275
-85.208.71.39:8333 # AS42275
+85.209.240.91:8333 # AS205581
85.214.118.71:8333 # AS6724
85.214.161.252:8333 # AS6724
-85.216.32.73:8333 # AS51185
-85.254.98.221:8333 # AS13194
-86.58.11.152:8333 # AS3212
+85.236.190.252:8333 # AS35032
+85.243.115.136:8333 # AS8657
+86.22.20.13:8333 # AS5089
+86.49.34.92:8333 # AS16019
86.95.8.249:8333 # AS1136
-86.100.26.188:8333 # AS39007
-86.106.143.143:55373 # AS9009
-86.124.145.184:8333 # AS8708
-86.133.251.239:8901 # AS2856
+86.104.228.10:8333 # AS31638
+86.104.228.23:8333 # AS31638
87.79.94.221:8333 # AS8422
-87.120.8.5:20008 # AS34224
-87.125.157.220:8333 # AS12430
-88.9.76.133:8333 # AS3352
-88.90.184.68:8333 # AS2119
-88.151.101.14:5000 # AS41075
-88.151.101.253:5000 # AS41075
-88.198.92.47:8333 # AS24940
+88.10.89.23:8333 # AS3352
+88.84.223.30:8333 # AS21453
+88.86.125.50:8333 # AS39392
+88.90.77.100:8333 # AS2119
+88.97.40.50:8333 # AS13037
+88.137.109.62:8333 # AS15557
+88.147.244.250:8333 # AS12389
88.208.115.70:8333 # AS29208
-88.210.15.24:8333 # AS212702
-88.212.45.166:8333 # AS42841
-89.102.206.238:8333 # AS16019
-89.103.111.34:8333 # AS16019
-89.114.143.113:8333 # AS12353
-89.134.62.74:8333 # AS21334
-89.152.8.231:8333 # AS2860
-89.161.26.78:8333 # AS39375
-89.207.131.19:8333 # AS49544
-89.248.193.229:8333 # AS49505
-90.3.48.62:8333 # AS3215
-90.146.121.97:8333 # AS12605
+88.212.53.246:8333 # AS42841
+89.35.142.168:8333 # AS34977
+89.78.111.197:8333 # AS6830
+89.117.59.129:8333 # AS1239
+89.147.108.200:8333 # AS44735
+89.163.132.180:8333 # AS24961
+89.165.232.242:8333 # AS48161
+89.216.21.96:8333 # AS31042
+90.50.172.182:8333 # AS3215
90.146.130.214:8333 # AS12605
-90.196.169.58:8333 # AS5607
-90.250.9.1:8333 # AS5378
+90.146.208.162:8333 # AS12605
+90.156.26.148:8333 # AS12741
+90.163.172.139:8333 # AS12479
+90.177.163.77:8333 # AS5610
+91.67.145.110:8333 # AS3209
91.93.194.154:8333 # AS34984
-91.126.40.109:8333 # AS35699
-91.204.99.178:8333 # AS20485
+91.123.182.164:8333 # AS51648
+91.123.183.219:8333 # AS51792
+91.135.0.187:8333 # AS12496
+91.147.232.98:8333 # AS5483
+91.184.168.249:8333 # AS9063
+91.193.237.116:8333 # AS42916
+91.199.41.45:8333 # AS6866
91.204.149.5:8333 # AS42765
-91.206.17.195:8333 # AS13259
-91.209.51.131:8333 # AS48239
91.215.91.254:8333 # AS48078
-92.91.27.60:8333 # AS15557
+91.219.25.232:8333 # AS50448
+91.237.88.218:8333 # AS56813
+92.27.150.46:8333 # AS13285
+92.27.150.47:8333 # AS13285
92.221.20.232:8333 # AS29695
-92.255.85.31:8333 # AS9002
-93.4.101.37:8333 # AS15557
-93.46.81.5:8333 # AS12874
-93.57.81.162:8333 # AS12874
-93.73.39.196:8333 # AS25229
-93.90.82.226:8333 # AS47626
+92.221.126.65:8333 # AS29695
+93.33.192.204:8333 # AS12874
+93.41.237.78:8333 # AS12874
93.95.88.13:8333 # AS35434
+93.95.227.125:8333 # AS44735
+93.103.13.1:8333 # AS34779
+93.115.86.239:8333 # AS3223
93.123.180.164:8333 # AS35539
-93.189.145.169:8333 # AS12555
-94.17.185.107:8333 # AS12709
-94.75.198.120:8333 # AS60781
-94.114.196.169:8333 # AS3209
-94.142.213.250:55544 # AS5524
+93.186.201.173:8333 # AS24961
+93.190.117.26:8333 # AS196881
+94.19.7.55:8333 # AS35807
+94.23.21.80:8333 # AS16276
+94.23.205.110:8333 # AS16276
+94.131.0.73:8333 # AS29632
+94.142.237.4:8333 # AS48926
94.154.159.99:8333 # AS62240
-94.158.246.183:8333 # AS39798
-94.239.145.32:8333 # AS5410
-95.31.12.22:8333 # AS8402
-95.31.196.15:8333 # AS3216
-95.110.133.223:8333 # AS31034
+94.202.50.200:8333 # AS15802
+94.231.253.18:8333 # AS35224
+95.42.140.142:8333 # AS8866
+95.67.18.100:8333 # AS34867
+95.70.238.176:8333 # AS12735
+95.83.73.31:8333 # AS8359
+95.90.128.3:8333 # AS204028
95.110.234.93:8333 # AS31034
95.161.12.45:8333 # AS39598
+95.172.62.167:8333 # AS201826
+95.179.128.87:8333 # AS20473
95.191.130.100:8333 # AS12389
-95.208.158.161:8333 # AS51185
-95.213.145.218:8333 # AS49505
95.214.53.154:8333 # AS201814
-95.214.53.160:8333 # AS201814
-96.44.156.199:8333 # AS8100
+96.3.53.254:8333 # AS11232
97.75.145.12:8333 # AS22709
+97.81.198.180:8333 # AS20115
+97.87.216.110:8333 # AS20115
+99.229.210.111:8333 # AS812
+99.246.87.2:8333 # AS812
+101.43.124.195:8333 # AS45090
102.132.192.141:8333 # AS37680
-103.14.245.250:8333 # AS24482
-103.85.38.205:8333 # AS134090
-103.88.92.78:8332 # AS17547
+103.21.3.89:8333 # AS38195
+103.35.121.72:8333 # AS9498
103.99.168.100:8333 # AS6939
103.99.168.140:8333 # AS6939
103.99.170.210:8333 # AS54415
103.99.170.220:8333 # AS54415
-103.100.44.70:8333 # AS10143
-103.178.236.27:8333 # AS49981
-103.209.12.144:8333 # AS58511
-104.59.147.15:8333 # AS7018
-104.129.171.121:8333 # AS174
-104.200.65.234:8333 # AS23033
+103.105.202.50:8333 # AS137764
104.238.220.199:8333 # AS23470
+104.243.33.165:8333 # AS23470
104.244.73.6:8333 # AS53667
-106.71.119.230:8333 # AS4804
-107.173.166.43:8333 # AS23352
-108.161.22.78:8333 # AS54154
-108.174.63.234:8333 # AS36352
+108.26.125.214:8333 # AS701
+109.86.60.33:8333 # AS13188
109.99.63.159:8333 # AS9050
-109.105.40.247:8333 # AS12570
-109.107.185.130:8333 # AS48282
-109.110.239.4:8333 # AS35432
-109.173.41.43:8333 # AS42610
+109.120.194.136:8333 # AS34569
+109.123.233.138:8333 # AS15685
+109.123.240.53:8333 # AS15685
+109.153.94.35:8333 # AS2856
+109.173.126.157:8333 # AS42610
+109.193.76.200:8333 # AS51185
+109.221.229.197:8333 # AS3215
109.236.90.117:8333 # AS49981
109.248.206.13:8333 # AS203493
-109.255.106.206:8333 # AS6830
111.90.140.23:8333 # AS45839
111.90.140.46:8333 # AS45839
-111.90.159.246:8333 # AS34309
-112.118.188.50:8333 # AS4760
-115.47.141.250:8885 # AS4134
+111.90.145.37:8333 # AS18106
+114.173.159.209:8333 # AS4713
116.58.171.67:8333 # AS2514
-118.92.107.108:8333 # AS9500
+119.31.179.202:8333 # AS17408
119.42.55.203:8333 # AS133159
-120.79.71.72:8333 # AS37963
-121.99.240.87:8333 # AS9790
+122.222.160.190:8333 # AS2519
123.60.213.192:8333 # AS55990
-124.156.158.100:8333 # AS132203
-124.222.123.238:8333 # AS45090
-125.178.6.116:8333 # AS3786
+124.197.54.113:8333 # AS9790
+125.168.140.108:8333 # AS4826
128.0.190.26:8333 # AS30764
128.65.194.136:8333 # AS29222
129.13.189.212:8333 # AS34878
-129.126.172.115:8333 # AS17547
-129.146.52.174:8333 # AS31898
-130.44.168.202:8333 # AS6079
-131.161.80.166:8333 # AS263694
+129.13.189.215:8333 # AS34878
+129.226.216.148:8333 # AS132203
131.188.40.191:8333 # AS680
+134.65.9.63:8333 # AS19653
+134.122.200.160:8333 # AS64050
134.195.185.52:8333 # AS13536
-135.134.238.47:8333 # AS4181
-135.180.218.58:8333 # AS46375
-135.181.215.237:8333 # AS24940
-136.29.109.180:8333 # AS19165
+135.19.253.101:8333 # AS5769
+136.29.109.58:8333 # AS19165
136.32.238.6:8333 # AS16591
-136.56.170.96:8333 # AS16591
-137.25.38.108:8333 # AS20115
+136.49.201.24:8333 # AS16591
137.226.34.46:8333 # AS680
-138.207.211.106:8333 # AS11776
+138.207.211.189:8333 # AS11776
139.130.41.82:8333 # AS1221
-139.153.255.107:8333 # AS786
-140.190.12.129:8333 # AS14828
+140.238.220.99:8333 # AS31898
142.54.181.218:8333 # AS32097
+142.166.19.23:8333 # AS855
+142.254.87.115:8333 # AS46375
143.177.229.149:8333 # AS50266
-143.178.64.10:8333 # AS50266
-144.24.245.183:8333 # AS31898
-144.126.130.178:8333 # AS40021
-146.4.124.129:8333 # AS3303
+144.2.101.21:8333 # AS3303
+144.24.236.64:8333 # AS31898
+145.40.51.52:8333 # AS49808
146.71.69.103:8333 # AS7782
-146.83.56.69:8333 # AS23140
-147.194.177.165:8333 # AS15128
-149.90.214.78:8333 # AS12353
-149.102.157.156:8333 # AS13768
-151.248.156.55:8333 # AS8821
-151.252.193.245:8333 # AS29582
-153.92.93.114:8333 # AS41998
-154.211.6.2:8333 # AS140224
-156.17.103.2:8088 # AS8970
+146.120.241.173:8333 # AS208515
+147.50.238.53:8333 # AS45265
+148.103.101.132:8333 # AS28118
+149.75.48.92:8333 # AS6079
+152.44.137.83:8333 # AS11404
+154.0.3.194:8333 # AS37680
+154.26.137.105:8333 # AS174
+154.26.154.73:8333 # AS1299
+154.57.5.11:8333 # AS200736
+155.4.55.21:8333 # AS8473
+156.146.137.142:8333 # AS1448
156.146.177.221:8333 # AS1448
-157.131.143.173:8333 # AS46375
-158.58.188.37:8333 # AS57497
-158.248.39.239:8333 # AS29695
-159.89.230.128:8333 # AS14061
+157.22.72.175:8333 # AS397379
+157.97.0.118:8333 # AS43571
+158.140.141.69:8333 # AS132132
+158.181.132.84:8333 # AS41750
+159.2.215.98:8333 # AS855
159.196.3.239:8333 # AS4764
159.224.189.250:8333 # AS13188
-160.72.51.154:8333 # AS46887
-161.29.236.55:8333 # AS4826
-161.97.119.166:8333 # AS51167
+160.80.12.16:8333 # AS137
+161.230.38.160:8333 # AS12353
161.246.11.230:8333 # AS9486
+162.0.210.152:8333 # AS22612
162.62.18.226:8333 # AS132203
-162.250.123.179:8333 # AS19318
-162.250.191.222:8333 # AS26832
162.254.118.20:8333 # AS6130
-163.172.81.70:8333 # AS12876
-164.90.47.8:8333 # AS53449
+163.158.168.181:8333 # AS15435
+165.173.19.33:8333 # AS132132
165.228.174.117:8333 # AS1221
-166.70.145.151:8333 # AS6315
-168.91.238.8:8333 # AS11039
-170.253.11.25:8333 # AS15704
-171.103.170.115:8333 # AS7470
-172.93.166.135:8333 # AS22653
-172.103.217.236:8333 # AS25668
+165.255.241.184:8333 # AS327693
+167.88.11.203:8333 # AS20278
+167.179.147.155:8333 # AS4764
+170.17.151.235:8333 # AS3303
+170.64.174.230:8333 # AS15108
+172.92.102.115:8333 # AS11404
172.105.21.216:8333 # AS63949
-172.112.153.95:8333 # AS20001
-173.3.218.91:8333 # AS6128
-173.12.119.133:8333 # AS7922
-173.34.127.181:8333 # AS812
-173.76.123.173:8333 # AS701
-173.176.198.68:8333 # AS5769
-173.208.152.218:8333 # AS32097
-173.241.227.243:8333 # AS19009
-173.246.27.7:8333 # AS1403
-173.255.240.205:8333 # AS63949
-174.30.47.15:8333 # AS209
-174.114.250.86:8333 # AS812
-174.138.35.229:8333 # AS14061
-174.142.191.136:8333 # AS32613
-176.10.143.190:8333 # AS8473
+172.111.176.244:8333 # AS46562
+172.255.98.108:8333 # AS7979
+173.82.5.202:8333 # AS35916
+173.181.35.50:8333 # AS395570
+173.212.253.137:8333 # AS51167
+173.235.73.87:8333 # AS11272
+174.30.29.85:8333 # AS209
+174.141.209.40:8333 # AS6461
+176.9.17.121:8333 # AS24940
+176.12.16.135:8333 # AS8717
176.74.136.237:8333 # AS35613
-176.118.220.29:8333 # AS60042
-176.126.116.7:8333 # AS20473
+176.74.139.120:8333 # AS35613
+176.122.122.134:8333 # AS50581
176.126.167.10:8333 # AS8449
+176.151.244.130:8333 # AS5410
+176.186.19.106:8333 # AS5410
176.212.185.153:8333 # AS9049
-176.235.209.186:8333 # AS34984
-177.81.236.117:8333 # AS28573
-177.89.205.70:8333 # AS28220
-178.48.168.12:8333 # AS21334
+177.142.146.193:8333 # AS4230
+178.21.118.178:8333 # AS49544
+178.61.141.198:8333 # AS21050
178.124.162.209:8333 # AS6697
+178.143.25.194:8333 # AS15962
+178.154.233.197:8333 # AS200350
178.159.98.133:8333 # AS202390
-178.196.89.209:8333 # AS3303
+178.232.186.191:8333 # AS41164
178.236.137.63:8333 # AS44843
-178.252.123.24:8333 # AS42893
-179.43.170.186:8333 # AS51852
-180.150.46.187:8333 # AS4764
-181.117.128.140:8333 # AS19037
-184.19.19.16:8333 # AS5650
-185.21.217.48:8333 # AS200052
+179.60.149.4:8333 # AS395839
+184.160.110.104:8333 # AS5769
+184.174.37.139:8333 # AS1239
+185.8.104.179:8333 # AS16125
+185.14.30.25:8333 # AS21100
185.25.48.184:8333 # AS61272
-185.31.136.246:8333 # AS47605
185.52.93.45:8333 # AS39449
185.64.116.15:8333 # AS31736
-185.68.249.91:8333 # AS51184
+185.69.105.117:8333 # AS6855
185.98.54.20:8333 # AS39572
185.107.83.55:8333 # AS43350
+185.132.109.122:8333 # AS38919
+185.135.81.50:8333 # AS57494
185.140.253.169:8333 # AS200735
-185.148.145.74:8333 # AS44901
+185.148.3.227:8333 # AS47605
+185.154.2.3:8333 # AS29119
+185.162.92.36:8333 # AS41722
+185.163.44.36:8333 # AS39798
185.165.170.19:8333 # AS3223
185.167.113.59:8333 # AS207054
-185.185.26.141:8111 # AS201206
-185.197.163.136:8333 # AS60144
+185.185.59.12:8333 # AS48614
+185.203.41.148:8333 # AS9009
185.209.12.76:8333 # AS212323
185.209.70.17:8333 # AS204568
-185.227.156.226:8333 # AS209846
+185.210.125.33:8333 # AS205671
185.233.189.210:8333 # AS61303
+185.238.131.19:8333 # AS206238
+185.239.220.210:8333 # AS61282
185.239.221.5:8333 # AS61282
-185.244.100.106:8333 # AS2586
-185.254.97.164:8333 # AS44486
-186.33.167.11:8333 # AS1299
-186.176.98.37:8333 # AS262197
+185.250.90.246:8333 # AS61955
186.249.217.25:8333 # AS7195
186.250.95.132:8333 # AS262967
-188.32.14.31:8334 # AS42610
188.35.167.14:8333 # AS34123
-188.68.45.143:8333 # AS47147
-188.117.200.212:8333 # AS25447
-188.138.88.14:8333 # AS20773
-188.151.237.158:8333 # AS1257
-188.154.236.49:8333 # AS6730
-189.123.177.128:8333 # AS4230
+188.68.53.44:8333 # AS47147
+188.120.255.115:8333 # AS29182
+189.6.195.111:8333 # AS28573
+190.2.130.44:8333 # AS49981
+190.13.122.89:8333 # AS33576
190.123.27.11:8333 # AS52468
190.145.127.254:8333 # AS14080
-192.69.53.77:8333 # AS11142
+191.220.156.64:8333 # AS8167
+192.31.136.90:8333 # AS54098
+192.69.53.43:8333 # AS11142
192.146.137.44:8333 # AS25376
-192.222.24.54:8333 # AS22646
-192.222.147.141:8333 # AS1403
-193.32.127.162:60969 # AS39351
-193.111.198.187:8111 # AS24961
-193.196.37.62:8333 # AS34878
-194.13.80.185:15430 # AS47147
-194.147.113.201:8333 # AS21232
-194.165.30.20:8333 # AS35162
-194.191.239.98:8333 # AS1836
-195.56.63.4:8333 # AS5483
-195.56.63.10:8333 # AS5483
-195.123.239.185:8333 # AS64010
-195.140.226.154:8333 # AS35614
-198.1.231.6:8333 # AS30236
-198.148.112.27:8333 # AS35916
-199.126.234.237:8333 # AS395570
-199.193.174.173:8333 # AS7992
+192.174.121.33:8333 # AS11492
+192.222.147.175:8333 # AS1403
+193.198.34.24:8333 # AS2108
+193.222.130.14:8333 # AS29208
+194.35.185.167:8333 # AS9063
+194.54.83.234:8333 # AS41018
+194.233.84.100:8333 # AS141995
+195.2.73.88:8333 # AS48282
+195.48.12.8:8333 # AS1836
+195.154.200.157:8333 # AS12876
+197.211.133.15:8333 # AS51265
+198.84.146.8:8333 # AS5645
+198.98.55.86:8333 # AS53667
199.247.7.208:8333 # AS20473
-200.122.181.46:8333 # AS3790
+200.116.154.131:8333 # AS13489
201.191.6.103:8333 # AS11830
-201.212.36.209:8333 # AS7303
201.221.234.200:8333 # AS27928
+202.47.225.242:8333 # AS9931
+202.107.219.130:8333 # AS4134
202.108.211.135:8333 # AS4837
-202.169.17.178:8333 # AS137549
-202.177.24.140:8333 # AS7479
-203.130.48.117:8885 # AS54994
-203.132.94.196:8333 # AS38195
+202.138.13.122:8333 # AS4826
+203.86.195.32:8333 # AS23655
+203.184.52.247:8333 # AS9790
+204.111.163.114:8333 # AS4922
205.178.41.124:8333 # AS11039
-206.72.201.228:8333 # AS19318
206.192.203.0:8333 # AS7029
-206.223.153.52:8333 # AS19214
-207.134.216.145:8334 # AS395570
-207.188.154.50:8333 # AS15704
207.229.46.80:8333 # AS852
+207.244.248.81:8333 # AS40021
207.255.193.47:8333 # AS11776
-208.104.92.74:8333 # AS14615
+208.59.133.63:8333 # AS11039
209.58.145.157:8333 # AS394380
-209.58.158.232:8335 # AS394380
-209.141.43.243:8333 # AS53667
-209.226.142.62:8333 # AS577
-209.237.127.227:8333 # AS1299
+209.97.189.249:8333 # AS14061
+209.177.138.245:8333 # AS7832
209.237.133.54:8333 # AS53859
-211.248.90.50:8333 # AS4766
-212.21.18.78:8333 # AS20485
+210.54.37.190:8333 # AS4648
+210.54.39.238:8333 # AS4648
212.34.225.118:8333 # AS44395
-212.51.146.137:8333 # AS13030
-212.227.211.87:8333 # AS8560
-213.0.69.76:8333 # AS3352
-213.5.36.58:8333 # AS49974
+212.41.9.30:8333 # AS49505
+212.51.132.176:8333 # AS13030
+212.69.60.77:8333 # AS12496
+212.86.32.106:8333 # AS15366
213.47.64.105:8333 # AS8412
-213.89.135.151:8333 # AS1257
213.141.154.201:8333 # AS12714
-213.159.198.45:8333 # AS8359
+213.142.148.169:8333 # AS6762
213.184.244.24:8333 # AS60280
-213.214.66.182:8333 # AS43205
-213.226.123.76:8333 # AS49943
+213.227.147.244:8333 # AS60781
+213.250.21.112:8333 # AS5603
216.146.251.8:8333 # AS54579
-216.186.238.14:8333 # AS12083
-217.5.150.114:8333 # AS3320
+216.232.157.104:8333 # AS395570
217.15.178.11:8333 # AS25534
-217.24.239.109:8333 # AS9063
-217.64.47.138:8333 # AS39324
-217.73.80.104:8333 # AS44291
-217.79.181.38:8333 # AS24961
+217.26.32.10:8333 # AS197312
+217.64.47.200:8333 # AS39324
+217.76.51.25:8333 # AS39597
217.92.55.246:8333 # AS3320
-217.113.121.169:8333 # AS8416
-217.115.116.250:8333 # AS30900
-217.155.244.170:8333 # AS13037
217.170.124.170:8333 # AS35401
-220.132.135.54:8333 # AS3462
-220.233.178.199:8333 # AS38195
-222.154.111.46:8333 # AS4648
-[2001:1620:510::2]:8333 # AS13030
-[2001:19f0:6001:39aa:5400:3ff:fef0:916]:8333 # AS20473
-[2001:19f0:8001:f71:5400:4ff:fe10:6a63]:8333 # AS20473
+217.180.221.162:8333 # AS30600
+217.180.238.137:8333 # AS30600
+220.84.232.46:8333 # AS4766
+220.133.39.61:8333 # AS3462
+220.233.91.182:8333 # AS38195
+[2001:19f0:1000:1db3:5400:4ff:fe56:5a8d]:8333 # AS20473
+[2001:19f0:5:24da:3eec:efff:feb9:f36e]:8333 # AS20473
+[2001:19f0:5:24da::]:8333 # AS20473
+[2001:19f0:5:4535:3eec:efff:feb9:87e4]:8333 # AS20473
+[2001:19f0:5:4535::]:8333 # AS20473
[2001:1bc0:c1::2000]:8333 # AS29686
-[2001:1c02:11e:3500:df25:6321:8260:d9be]:8333 # AS6830
-[2001:41d0:1004:1b79::]:8339 # AS16276
+[2001:1c04:4008:6300:8a5f:2678:114b:a660]:8333 # AS6830
[2001:41d0:203:3739::]:8333 # AS16276
-[2001:41d0:203:aacc::]:8333 # AS16276
+[2001:41d0:203:8f49::]:8333 # AS16276
[2001:41d0:203:bb0a::]:8333 # AS16276
[2001:41d0:2:bf8f::]:8333 # AS16276
-[2001:41d0:303:6586::]:8333 # AS16276
-[2001:41d0:602:4493::]:8333 # AS16276
-[2001:41d0:8:b9d8::1]:8333 # AS16276
+[2001:41d0:303:de8b::]:8333 # AS16276
+[2001:41d0:403:3d61::]:8333 # AS16276
+[2001:41d0:405:9600::]:8333 # AS16276
+[2001:41d0:8:ed7f::1]:8333 # AS16276
[2001:41d0:a:69a2::1]:8333 # AS16276
[2001:41f0::62:6974:636f:696e]:8333 # AS6830
-[2001:44b8:256:5d11:216:3eff:fe39:d5d4]:8333 # AS4739
[2001:470:1b62::]:8333 # AS6939
-[2001:470:1f07:803:20c:29ff:fe2d:5879]:8333 # AS6939
+[2001:470:1f05:43b:2831:8530:7179:5864]:8333 # AS6939
+[2001:470:1f09:b14::11]:8333 # AS6939
[2001:470:1f15:106:e2d5:5eff:fe42:7ae5]:8333 # AS6939
-[2001:470:1f15:c43::11]:8333 # AS6939
-[2001:470:26:472::b7c]:8333 # AS6939
+[2001:470:1f1b:365:aa20:66ff:fe3f:1909]:8333 # AS6939
+[2001:470:1f1b:5a6:216:3eff:fe24:1162]:8333 # AS6939
+[2001:470:6a7c::]:8333 # AS6939
[2001:470:75e9:1::10]:8333 # AS6939
-[2001:470:de5a::ec]:9333 # AS6939
-[2001:4ba0:babe:584::1]:8333 # AS24961
+[2001:470:8ca0:2:4e72:b9ff:fe56:f8b8]:8333 # AS6939
+[2001:470:dbc7:0:1010::100]:8333 # AS6939
+[2001:4ba0:cafe:14cc::1]:8333 # AS24961
[2001:4ba0:ffff:24::1]:8333 # AS24961
[2001:4dd0:3564:0:30b7:1d7b:6fec:4c5c]:8333 # AS8422
[2001:4dd0:3564:0:88e:b4ff:2ad0:699b]:8333 # AS8422
[2001:4dd0:3564:0:9c1c:cc31:9fe8:5505]:8333 # AS8422
[2001:4dd0:3564:0:a0c4:d41f:4c4:1bb0]:8333 # AS8422
-[2001:4dd0:3564:0:fd76:c1d3:1854:5bd9]:8333 # AS8422
[2001:4dd0:3564:1::7676:8090]:8333 # AS8422
[2001:4dd0:3564:1:b977:bd71:4612:8e40]:8333 # AS8422
[2001:4dd0:af0e:3564::69:1]:8333 # AS8422
[2001:4dd0:af0e:3564::69:90]:8333 # AS8422
-[2001:4de8:b1b2:1:0:dead:beef:7]:8333 # AS29208
+[2001:560:441f:1::4]:8333 # AS18530
[2001:638:a000:4140::ffff:191]:8333 # AS680
-[2001:678:acc:42::]:8333 # AS60404
+[2001:67c:25dc:91::2]:8333 # AS41018
[2001:67c:26b4:ff00::44]:8333 # AS25376
[2001:67c:2db8:6::36]:8333 # AS39798
-[2001:7c0:2310:0:f816:3eff:fe0d:4ab6]:8333 # AS34878
[2001:7c0:2310:0:f816:3eff:fe6c:4f58]:8333 # AS34878
-[2001:861:3246:a10::40]:8333 # AS5410
-[2001:b07:2e6:38d7:ba27:ebff:fe60:3dc1]:8333 # AS12874
+[2001:861:3242:8420::40]:8333 # AS5410
+[2001:8b0:1301:1000::60]:8333 # AS20712
+[2001:b030:2422::208d]:8333 # AS3462
+[2001:b07:2ef:6e4a:3d:974e:784a:684b]:8333 # AS12874
+[2001:b07:5d32:b142:8f77:3c7d:a2fd:ed2e]:8333 # AS12874
[2001:b07:6461:7811:489:d2da:e07:1af7]:8333 # AS12874
-[2001:b07:ac9:442b:79d6:bbbe:b37c:a783]:8333 # AS12874
+[2001:b07:646b:8074:32e8:9243:a337:e60a]:8333 # AS12874
+[2001:b07:646b:8074:4cc6:79a5:3af7:7132]:8333 # AS12874
+[2001:b07:ad4:ca4b:7dd5:8471:50c3:5363]:8333 # AS12874
+[2001:bc8:1201:71a:2e59:e5ff:fe42:52f4]:8333 # AS12876
[2001:bc8:1600:0:208:a2ff:fe0c:8a2e]:8333 # AS12876
[2001:bc8:323c:ff:a634:384f:1849:f4bc]:8333 # AS12876
[2001:bc8:323c:ff:d217:c2ff:fe07:2cd9]:8333 # AS12876
-[2001:bc8:3bec:100::1]:8333 # AS12876
-[2002:2f5b:a5f9::2f5b:a5f9]:8885 # AS6939
-[2003:cb:8713:6102:aaa1:59ff:fe57:7779]:8333 # AS3320
-[2003:e0:370e:1400::5]:8333 # AS3320
-[2003:f6:3f10:6700:4c9f:7620:8324:d4a7]:8333 # AS3320
-[2400:2410:cea2:d00:41bc:c9ea:861b:51ee]:8333 # AS17676
-[2400:2411:a3e1:4900:2568:684b:e99:7120]:8333 # AS17676
-[2400:2411:a3e1:4900:2987:b88f:61e0:84fa]:8333 # AS17676
-[2400:3b00:20:c:bacb:29ff:feab:8886]:8333 # AS18229
+[2001:bc8:700:2b14::1]:8333 # AS12876
+[2001:bc8:700:8d16::1]:8333 # AS12876
+[2001:e68:5400:58d0:bd15:ea8c:5b20:7523]:8333 # AS4788
+[2400:2411:a3e1:4900:7298:f550:67e7:b99b]:8333 # AS17676
+[2400:8901::f03c:93ff:fe2b:5c0b]:8333 # AS63949
+[2400:8901::f03c:93ff:fe5a:685c]:8333 # AS63949
[2401:b140:1::100:210]:8333 # AS54415
[2401:b140:1::100:220]:8333 # AS54415
-[2401:b140::42:100]:8333 # AS6939
-[2401:b140::44:130]:8333 # AS6939
[2401:d002:3902:700:d72c:5e22:4e95:389d]:8333 # AS38195
-[2404:4408:6752:c000::1999]:8333 # AS9790
-[2404:7a85:4161:2b00:49a1:427a:fac:3409]:8333 # AS2518
-[2405:9800:b972:ab58:c05:e938:267e:271]:8333 # AS45430
+[2404:4408:63a4:a01::250]:8333 # AS9790
+[2406:3400:216:8b00:211:32ff:feca:336b]:8333 # AS10143
+[2406:8c00:0:3422:133:18:228:108]:8333 # AS24282
[2406:da11:169:b03:32b5:f901:9f7c:3e4b]:8333 # AS16509
-[2406:da14:335:b601:ceb7:b4fc:a855:f3a5]:8333 # AS16509
+[2406:da18:9f1:f301:7d2e:c256:c112:f2be]:8333 # AS16509
+[2406:da18:9f1:f303:c1c9:c569:b799:2057]:8333 # AS16509
+[2406:da1e:a4e:8a00:20db:dd8d:3670:28f0]:8333 # AS16509
[2406:da1e:a4e:8a03:2aad:496b:768d:e497]:8333 # AS16509
-[2407:8800:bc61:2202:a0c6:107:502b:4e3b]:8333 # AS7545
-[2409:10:ca20:1df0:224:e8ff:fe1f:60d9]:8333 # AS55391
-[2600:1700:22f1:641f:e8:39c8:eb1d:a1eb]:8333 # AS7018
-[2600:1700:9c5d:ed0::38]:8333 # AS7018
-[2600:1700:9c5d:ed0:d0d6:1d9:5cc2:ab47]:8333 # AS7018
-[2600:1702:1ce0:4010::40]:8333 # AS7018
-[2600:1f14:40e:e301:d155:aa3a:77be:960e]:8333 # AS16509
-[2600:1f16:a08:b901:1afa:ef4e:4ce7:2ba4]:8333 # AS16509
-[2600:1f1c:2d3:2403:5bac:3fc6:6513:7a63]:8333 # AS16509
+[2407:3640:2107:1278::1]:8333 # AS141995
+[2407:3640:3010:4012::1]:8333 # AS141995
+[2407:8800:bc61:2202:d63d:7eff:fe6c:dc36]:8333 # AS7545
+[2600:1700:5c5b:b0:aaa1:59ff:fe5f:615a]:8333 # AS7018
+[2600:1700:ec7b:5730::48]:8333 # AS7018
+[2600:1900:4000:4cc4:0:1::]:8333 # AS15169
+[2600:1900:4000:4cc4:0:2::]:8333 # AS15169
+[2600:1900:4000:4cc4:0:3::]:8333 # AS15169
+[2600:1900:4000:4cc4::]:8333 # AS15169
+[2600:1900:4030:a25e::]:8333 # AS15169
+[2600:1f14:40e:e301:afdd:ad00:e568:d220]:8333 # AS16509
+[2600:1f1c:2d3:2400:f15e:2f2a:760d:a33d]:8333 # AS16509
[2600:2104:1003:c5ab:dc5e:90ff:fe18:1d08]:8333 # AS11404
[2600:3c00::f03c:92ff:fe92:2745]:8333 # AS63949
[2600:3c00::f03c:92ff:fecf:61b6]:8333 # AS63949
-[2600:3c00::f03c:93ff:feb3:1b6]:8333 # AS63949
[2600:3c00:e002:2e32::1:14]:8333 # AS63949
+[2600:3c01::f03c:93ff:fe2a:5266]:8333 # AS63949
+[2600:3c01::f03c:93ff:fe74:5f59]:8333 # AS63949
+[2600:3c01::f03c:93ff:fee6:2146]:8333 # AS63949
[2600:3c02::f03c:92ff:fe5d:9fb]:8333 # AS63949
-[2600:4040:2854:5e00:c6e9:84ff:fe46:ee8]:8666 # AS13786
-[2600:6c54:7100:1ad1:bddf:550e:91be:f9e1]:8333 # AS20115
+[2600:4040:2004:3201:459f:8fe8:444d:baf1]:8333 # AS13786
+[2600:4040:4541:4900:4e1:b58a:8438:450e]:8333 # AS13786
+[2600:6c54:7100:1ad1:c92e:36d:651:bd18]:8333 # AS20115
+[2600:8801:2f80:477::141c]:8333 # AS22773
+[2600:8801:8d00:3eb0:20c:29ff:fec3:d799]:8333 # AS22773
[2600:8805:2400:14e:12dd:b1ff:fef2:3013]:8333 # AS22773
-[2601:184:300:bde:3c29:8e94:1ba8:fde3]:8333 # AS7922
-[2601:18c:8080:300f:219:d1ff:fe75:dc2f]:8333 # AS7922
-[2601:18d:4600:43f1:20e7:b3ff:fecf:a99]:8333 # AS7922
-[2601:18d:8701:c290::3330]:8333 # AS7922
-[2601:246:4d7f:9e28:f321:36ca:7a71:c687]:8333 # AS7922
-[2601:640:c201:960d:86eb:f27d:66a2:f2c1]:8333 # AS7922
-[2602:241:75d1:2b90::7840]:8333 # AS46375
-[2602:ffb8::208:72:57:200]:8333 # AS2914
+[2601:184:300:156c:ba4c:30:9da:6c06]:8333 # AS7922
+[2601:346:d7f:fff7:18c6:4856:ef75:744c]:8333 # AS7922
+[2601:405:4a00:876:c8d3:f081:2ce8:ba8e]:8333 # AS7922
+[2602:24c:b8f:cd90::7840]:8333 # AS46375
+[2602:fec3:0:1::69]:8333 # AS62563
+[2602:ff16:1:0:1:412:0:1]:8333 # AS29802
+[2603:3001:2618:c000:2ec1:df1f:a463:9119]:8333 # AS7922
+[2603:3003:11b:e100:20c:29ff:fe38:bbc0]:8333 # AS7922
[2603:3004:6a1:3800:851f:584d:7aba:affb]:8333 # AS7922
-[2603:3004:6a1:3800::4402]:8333 # AS7922
-[2603:3004:70d:1400:8532:2900:ce6f:acdf]:8333 # AS7922
-[2603:3004:745:900:f0d7:556a:a8c:ced5]:8333 # AS7922
-[2603:6080:c000:5d8a::104f]:8333 # AS7843
-[2603:8000:d100:8991:cc29:ccff:fe42:300c]:8333 # AS7843
+[2603:3004:6a1:3800::7bba]:8333 # AS7922
+[2603:3004:6a1:3800::f667]:8333 # AS7922
+[2603:3024:1606:1400::29ec]:8333 # AS7922
+[2603:3024:18ee:8000:20e:c4ff:fed1:ef15]:8333 # AS7922
+[2603:6000:a400:9300::2000]:8333 # AS7843
+[2603:6010:7001:4830::2:1]:8333 # AS7843
[2603:8080:1f07:6fdd:7de2:d969:78c9:b7ea]:8333 # AS7843
-[2603:8080:7300:531::13ea]:8333 # AS7843
-[2603:80a0:703:40f8::38]:8333 # AS7843
-[2604:180:f3::218]:8333 # AS3842
-[2604:3d08:0:5:d941:4b03:a093:131b]:8333 # AS6327
-[2604:7c00:120:4b::eb24]:8333 # AS174
-[2604:a00:21:3043:bf6a:535e:dfeb:5b7b]:8333 # AS19318
-[2604:a880:400:d0::1ce7:4001]:8333 # AS14061
-[2604:a880:400:d0::1d44:e001]:8333 # AS14061
+[2603:8080:d600:1800:7ce1:74a2:6a8a:4643]:8333 # AS7843
+[2603:8081:6c00:306e:215:5dff:fe02:150a]:8333 # AS7843
+[2604:3d09:7182:8700:bba9:cde6:5b37:a8df]:8333 # AS6327
+[2604:4080:1036:80b1::3be]:8333 # AS11404
+[2604:a00:3:1223:216:3eff:fe27:76e0]:8333 # AS19318
[2604:a880:400:d0::261f:6001]:8333 # AS14061
-[2604:a880:400:d1::7e2:e001]:8333 # AS14061
-[2604:a880:4:1d0::14:3000]:8333 # AS14061
+[2604:a880:4:1d0::13e:f000]:8333 # AS14061
+[2604:a880:4:1d0::17a:7000]:8333 # AS14061
+[2604:a880:4:1d0::c1:3000]:8333 # AS14061
[2604:a880:4:1d0::e5:b000]:8333 # AS14061
+[2605:4a80:a302:7940:7254:1ed4:90d7:4f39]:8333 # AS11232
+[2605:4a80:a302:7940::2]:8333 # AS11232
[2605:6400:30:f220::]:8333 # AS53667
-[2605:6f80:0:7:fc1b:ccff:fe8a:d822]:8333 # AS53340
-[2605:a140:2076:8253::1]:8333 # AS40021
-[2605:a140:3007:1287::1]:8333 # AS40021
+[2605:a140:3010:4014::1]:8333 # AS40021
[2605:ae00:203::203]:8333 # AS7819
+[2605:b40:14d0:5b00:7988:eb8:6bb6:66e2]:8333 # AS174
[2605:c000:2a0a:1::102]:8333 # AS7393
-[2607:1a00:1:d::11:7c4d]:8333 # AS22653
-[2607:5300:203:1214::]:8333 # AS16276
+[2607:5300:61:854::1]:8333 # AS16276
[2607:9280:b:73b:250:56ff:fe14:25b5]:8333 # AS395502
[2607:9280:b:73b:250:56ff:fe21:9c2f]:8333 # AS395502
[2607:9280:b:73b:250:56ff:fe21:bf32]:8333 # AS395502
[2607:9280:b:73b:250:56ff:fe33:4d1b]:8333 # AS395502
[2607:9280:b:73b:250:56ff:fe3d:401]:8333 # AS395502
-[2607:f2c0:e1c2:69:12c3:7bff:fe4d:9431]:8333 # AS5645
-[2607:f2c0:e1c2:69:ecb2:6e88:9f33:5057]:8333 # AS5645
-[2620:6:2003:105:2d8:61ff:fe0f:853]:8333 # AS25682
[2620:6e:a000:1:42:42:42:42]:8333 # AS397444
-[2620:a6:2000:1::3:d570]:8333 # AS27566
-[2620:a6:2000:1::5:162a]:8333 # AS27566
-[2620:a6:2000:1::5:1631]:8333 # AS27566
-[2620:a6:2000:1::c:e634]:8333 # AS27566
-[2800:40:33:8ab:a0e7:b215:fc83:5c31]:8333 # AS16814
-[2800:bf0:149:f4b:f8df:8d7d:801b:e25e]:8333 # AS27947
-[2804:14c:198:80d5:7603:41d1:d3fc:e797]:8333 # AS28573
-[2804:14d:ae81:827b:99a8:1e3f:6db2:29db]:8333 # AS4230
-[2804:d57:5537:4800:3e7c:3fff:fe7b:80aa]:8333 # AS8167
-[2a00:12e0:101:99:20c:29ff:fe29:d03f]:8333 # AS6798
-[2a00:1328:e101:c00::163]:8333 # AS31078
+[2620:a6:2000:1:1:0:5:1601]:8333 # AS27566
+[2620:a6:2000:1:2:0:9:900b]:8333 # AS27566
+[2620:a6:2000:1:2:0:b:300e]:8333 # AS27566
+[2800:150:11d:d2f:bdac:7807:2f5:4aa0]:8333 # AS22047
+[2803:9800:a007:82ba:650b:82b8:8377:d0]:8333 # AS19037
+[2804:14c:155:45e0:1e86:15a3:efd9:7287]:8333 # AS28573
+[2804:14c:657d:4030:28b4:eff:fe9b:8894]:8333 # AS28573
+[2804:14d:1087:9434::1002]:8333 # AS4230
+[2804:954:24:2:b390:d83b:358a:db53]:8333 # AS263073
+[2804:d57:554d:de00:3e7c:3fff:fe7b:80aa]:8333 # AS8167
+[2a00:1028:838c:563a:fd25:87b6:5a54:811]:8333 # AS5610
+[2a00:1298:8001::6542]:8333 # AS5578
[2a00:1398:4:2a03:215:5dff:fed6:1033]:8333 # AS34878
[2a00:1398:4:2a03::bc03]:8333 # AS34878
-[2a00:1630:10:1003:0:b19:b00b:babe]:8333 # AS49544
[2a00:1768:2001:27::ef6a]:8333 # AS43350
-[2a00:1828:a004:2::666]:8333 # AS34240
-[2a00:1c10:2:709::217]:22220 # AS50300
[2a00:1f40:5001:108:5d17:7703:b0f5:4133]:8333 # AS42864
[2a00:23c5:fe80:7301:d6ae:52ff:fed5:56a5]:8333 # AS2856
-[2a00:23c6:5c91:5808:c05a:4dff:fe65:9d69]:8333 # AS2856
-[2a00:6020:1bfa:d400:20c:29ff:fe61:4a4c]:8333 # AS60294
-[2a00:6020:b482:9200:491a:358c:d8f7:1da]:8333 # AS60294
+[2a00:6020:13dc:bc00:5559:258:27d:b52b]:8333 # AS60294
+[2a00:6020:4503:3700:20c:29ff:fe61:4a4c]:8333 # AS60294
+[2a00:6020:b434:eb00:dea6:32ff:fe0d:a5c0]:8333 # AS60294
[2a00:6020:b489:2000:5054:ff:fefc:5ed8]:8333 # AS60294
+[2a00:7c80:0:10c::2]:8333 # AS49981
[2a00:7c80:0:25::e37a]:8333 # AS49981
-[2a00:7c80:0:71::8]:8333 # AS49981
[2a00:8a60:e012:a00::21]:8333 # AS680
-[2a00:ae40:240e:3200::3]:8333 # AS50923
+[2a00:bbe0:cc:0:5a11:22ff:feb4:8f5c]:8333 # AS47605
[2a00:bbe0:cc:0:62a4:4cff:fe23:7510]:8333 # AS47605
-[2a00:ca8:a1f:3025:f949:e442:c940:13e8]:8333 # AS30764
-[2a00:d4e0:2:d002:4467:31e0:6fa5:b3ef]:8333 # AS15600
+[2a00:ca8:a15:9a5b:8b42:a886:7d48:7a21]:8333 # AS30764
+[2a00:ca8:a1f:f9b7:cb55:5766:524b:acaa]:8333 # AS30764
+[2a00:d4e0:ff:fc02:5e55:4a7c:b83b:e5a1]:8333 # AS15600
+[2a00:d520:9:9300:420b:544e:8019:6d3a]:8333 # AS15600
+[2a00:d880:5:c2::d329]:8333 # AS198203
[2a00:ee2:1200:1900:8d3:d2ff:feb1:bc58]:8333 # AS5603
-[2a01:238:420f:9200:fa5a:1a4b:1e6a:fadf]:8333 # AS6724
-[2a01:238:4389:c400:3b26:d94e:38d5:44ef]:8333 # AS6724
-[2a01:490:16:301::2]:8333 # AS8251
-[2a01:4b00:807c:3100:cda1:c6a:2bad:2418]:8333 # AS56478
-[2a01:4f8:141:2254::2]:8333 # AS24940
[2a01:4f8:173:230a::2]:8333 # AS24940
-[2a01:4f8:190:91c4::2]:8333 # AS24940
[2a01:4f8:200:7222::2]:8333 # AS24940
[2a01:4f8:202:3e6::2]:8333 # AS24940
[2a01:4f8:221:44d7::2]:8333 # AS24940
[2a01:4f8:231:915::2]:8333 # AS24940
-[2a01:4f9:2a:1ce0::2]:8333 # AS24940
+[2a01:4f8:261:2bcd::2]:8333 # AS24940
+[2a01:4f8:261:3cae::2]:8333 # AS24940
+[2a01:4f8:261:420c::2]:8333 # AS24940
[2a01:4f9:2b:29a::2]:8333 # AS24940
-[2a01:4f9:4a:31de::2]:8333 # AS24940
-[2a01:5200:6c:6162:7a61:746b:6f2e:736b]:8333 # AS6855
-[2a01:6380:fffe:73:10fb:d012:8581:b4d7]:8333 # AS25540
+[2a01:4f9:3a:2dd2::2]:8333 # AS24940
[2a01:7a7:2:2804:ae1f:6bff:fe9d:6c94]:8333 # AS20773
-[2a01:7c8:aaac:89:5054:ff:feb7:f5cb]:8333 # AS20857
+[2a01:7c8:aac2:180:5054:ff:fe56:8d10]:8333 # AS20857
[2a01:7c8:aac9:c9:5054:ff:fedf:ff95]:8333 # AS20857
-[2a01:7c8:d001:1c1:5054:ff:feee:3e1a]:8333 # AS20857
-[2a01:7c8:d009:2aa:5054:ff:fe1b:a196]:11520 # AS20857
-[2a01:7c8:fffa:50e:ddfe:c924:ca0a:cbab]:8333 # AS20857
-[2a01:7e00::f03c:93ff:fe59:66dc]:8333 # AS63949
-[2a01:7e01::f03c:93ff:fe3b:bb5b]:8333 # AS63949
+[2a01:7e01::f03c:93ff:fe49:2f5b]:8333 # AS63949
+[2a01:8740:1:753::e5cb]:8333 # AS57344
[2a01:8740:1:ffc5::8c6a]:8333 # AS57344
-[2a01:9f40:a000::100]:8333 # AS42908
-[2a01:cb00:d3d:7700:227:eff:fe28:c565]:8333 # AS3215
-[2a01:e0a:20:7350:919c:b1c3:8b83:adf9]:8333 # AS12322
+[2a01:cb00:b63:c000:227:eff:fe28:c565]:8333 # AS3215
+[2a01:cb19:688:e900:aa60:b6ff:fe29:bbae]:8333 # AS3215
+[2a01:e0a:163:c0b0:9da5:1690:a12b:bede]:8333 # AS12322
+[2a01:e0a:282:67b0:b4f4:aaff:fe7c:44a6]:8333 # AS12322
[2a01:e0a:301:7010:b87d:e14b:cea9:b998]:8333 # AS12322
-[2a01:e0a:48b:2d10:94f2:4d5c:ca5f:bf49]:8333 # AS12322
-[2a01:e0a:530:a0a0:f465:af5:be1b:9075]:8333 # AS12322
-[2a01:e0a:aa7:c8c0:9679:affa:b6e5:efc7]:8333 # AS12322
+[2a01:e0a:320:39a0:325a:3aff:fe02:3180]:8333 # AS12322
+[2a01:e0a:351:9fb0:6bf2:95d6:b7bd:b846]:8333 # AS12322
+[2a01:e0a:5fa:a0a0:ca1f:66ff:fece:b8a2]:8333 # AS12322
+[2a01:e0a:83d:dd30:3676:5d8e:8a6f:115a]:8333 # AS12322
+[2a01:e0a:9e9:c240:7b44:f32a:6ec0:a8af]:8333 # AS12322
+[2a01:e0a:b5:7f50:c257:a55b:4846:97e1]:8333 # AS12322
[2a01:e11:100c:70:cbc8:9e31:4b77:1626]:8333 # AS12322
-[2a01:e34:ee78:3060:230:48ff:fe81:f1c6]:8333 # AS12322
-[2a02:1210:14a9:6700:a00:27ff:fe4e:82b6]:8333 # AS3303
-[2a02:1210:4639:f00:10a7:e965:509a:7a4a]:8333 # AS3303
-[2a02:1210:7c92:5100:211:32ff:feae:152d]:8333 # AS3303
-[2a02:1210:86bf:f100:3178:d700:d44d:6bb1]:8333 # AS3303
-[2a02:1210:9487:a200:edc1:93a4:945:9a92]:8333 # AS3303
+[2a02:1210:2cdf:4600:2bc:e03e:43e8:4718]:8333 # AS3303
+[2a02:1210:86bf:f100:a9ac:d041:1f8e:6925]:8333 # AS3303
+[2a02:1210:94c3:3400:d8c3:743c:90f6:a48a]:8333 # AS3303
+[2a02:168:2000:96::12]:8333 # AS13030
[2a02:168:420b:a::20]:8333 # AS13030
-[2a02:168:6328:0:4a21:bff:fe26:38c3]:8333 # AS13030
[2a02:168:676e:0:e65f:1ff:fe09:3591]:8333 # AS13030
-[2a02:1748:f39f:5872:dead:beef:b1ac:c0fe]:8333 # AS51184
+[2a02:1748:f39f:5872:216:3eff:fe21:266]:8333 # AS51184
[2a02:180:1:1::517:10b6]:8333 # AS35366
-[2a02:2168:a379:d100:96de:80ff:fea3:fd00]:8333 # AS42610
[2a02:2780:9000:70::7]:8333 # AS35434
[2a02:2780:9000:70::f]:8333 # AS35434
[2a02:2780::e01a]:8333 # AS35434
-[2a02:2e02:3900:5400:a099:e1ff:feb6:d0e]:8333 # AS12479
-[2a02:2f05:660e:8b00::1]:8333 # AS48571
-[2a02:58:97:7d20::60]:8333 # AS25596
-[2a02:6d40:3073:c01:dea6:32ff:fe44:4b25]:8333 # AS42652
+[2a02:2f05:6008:ce00::1]:8333 # AS48571
+[2a02:390:9000:0:aaa1:59ff:fe43:b57b]:8333 # AS12496
+[2a02:578:85ce:1600:1e1b:dff:fee3:774b]:8333 # AS9031
+[2a02:768:f92b:db46:5e46:772b:71d:29b7]:8333 # AS44489
[2a02:7a01::91:228:45:130]:8333 # AS16019
+[2a02:7b40:50d0:e386::1]:8333 # AS62282
+[2a02:7b40:50d1:e35b::1]:8333 # AS62282
[2a02:7b40:5928:89::1]:8333 # AS62282
-[2a02:7b40:c3b5:f583::1]:8333 # AS62282
-[2a02:8308:8087:aa00:9ea8:1b2:ef98:56bf]:8333 # AS16019
+[2a02:7b40:b945:344d::1]:8333 # AS62282
+[2a02:7b40:d418:6d9a::1]:8333 # AS62282
+[2a02:8070:b84:6ae0:f9c6:fbb9:1c41:81aa]:8333 # AS51185
+[2a02:8070:f186:38e0::d5a6]:8333 # AS51185
+[2a02:8084:103:6810:1e69:7aff:fea2:1acc]:8333 # AS6830
+[2a02:8308:8081:f300:3b8:7ec0:2837:1b57]:8333 # AS16019
+[2a02:8388:e302:7980:6f85:a0b3:4b4d:8b0f]:8333 # AS8412
+[2a02:8388:e5c3:4a80:201:2eff:fe82:b3cc]:8333 # AS8412
[2a02:842a:1df:8a01:1e1b:dff:fe0b:236d]:8333 # AS15557
+[2a02:a210:28be:5f80::111]:8333 # AS6830
+[2a02:a44b:5cf9:1:b62e:99ff:fe49:d492]:8333 # AS1136
[2a02:a44d:14d6:1:2c0:8ff:fe8f:b3b2]:8333 # AS1136
[2a02:a45a:94cd:f00d::1]:8333 # AS1136
-[2a02:a45f:3b9d:30::3]:8333 # AS1136
-[2a02:a467:7833:1:7285:c2ff:fe2c:21e9]:8333 # AS1136
-[2a02:aa14:2380:b300:4040:be88:8b01:d38]:8333 # AS6830
+[2a02:a45f:3b9d:31::199]:8333 # AS1136
+[2a02:a464:3d6b::1:2]:8333 # AS1136
+[2a02:a46c:7f8e:1:35bf:3aeb:137c:1d35]:8333 # AS1136
+[2a02:a46d:36f:1:20d:b9ff:fe4e:6398]:8333 # AS1136
+[2a02:c205:2021:4216::1]:8333 # AS51167
[2a02:c206:2044:9826::1]:8333 # AS51167
-[2a02:c206:2082:1246::1]:8333 # AS51167
-[2a02:c206:3008:2368::1]:8333 # AS51167
-[2a02:c207:0:4971::1]:5332 # AS51167
+[2a02:c206:2075:3351::1]:8333 # AS51167
+[2a02:c207:0:3829::1]:8333 # AS51167
[2a02:c207:2014:4199::1]:8333 # AS51167
-[2a02:c207:2024:6115::1]:8333 # AS51167
+[2a02:c207:2014:8757::1]:8333 # AS51167
[2a02:c207:2026:6682::1]:8333 # AS51167
+[2a02:c207:2034:7358::1]:8333 # AS51167
[2a02:c207:3002:7468::1]:8333 # AS51167
+[2a02:c207:3008:4592::1]:8333 # AS51167
+[2a02:cb43:4000::178]:8333 # AS33891
+[2a02:e5e:1:10::27]:8333 # AS25057
[2a02:e98:20:1504::1]:8333 # AS24641
-[2a03:4000:6:416c::43]:8333 # AS47147
-[2a03:4000:6:f814:548b:17ff:fe31:b64a]:8333 # AS47147
+[2a03:4000:28:68:7411:53ff:fe4c:21d]:8333 # AS47147
+[2a03:4000:65:fdc:3462:66ff:fe05:ec5c]:8333 # AS47147
[2a03:6000:870:0:46:23:87:218]:8333 # AS51088
[2a03:94e0:ffff:185:243:218:0:19]:8333 # AS56655
[2a03:b0c0:1:e0::397:6001]:8333 # AS14061
-[2a03:b0c0:2:f0::163:3001]:8333 # AS14061
-[2a03:b0c0:2:f0::18a:d001]:8333 # AS14061
-[2a03:b0c0:3:d0::f3e:2001]:8333 # AS14061
-[2a03:e2c0:1347::2]:8333 # AS50113
-[2a03:ec0:0:928::701:701]:8333 # AS199669
-[2a04:52c0:103:c455::1]:8334 # AS60404
-[2a04:52c0:3007:200::2000]:8333 # AS60404
+[2a03:b0c0:1:e0::794:9001]:8333 # AS14061
+[2a03:b0c0:2:f0::288:c001]:8333 # AS14061
+[2a03:b0c0:2:f0::30c:1]:8333 # AS14061
+[2a03:b0c0:3:d0::e3b:5001]:8333 # AS14061
+[2a03:cfc0:8000:7::5fd6:3557]:8333 # AS201814
+[2a04:2180:dc05:2::3b]:8333 # AS61272
+[2a04:2180:ffff:fffe::d]:8333 # AS61272
+[2a04:52c0:103:c455::1]:8333 # AS60404
[2a04:bc40:1dc3:8d::2:1001]:8333 # AS35277
-[2a05:1500:702:0:1c00:40ff:fe00:c]:8333 # AS48635
-[2a05:3580:d101:3700::]:8333 # AS20764
-[2a05:3580:db0b:1600:c489:76ed:313d:b33]:8333 # AS20764
-[2a05:d014:a55:4001:8127:afa7:daf9:d91b]:8333 # AS16509
-[2a05:d014:a55:4001:f6ab:dd5e:4039:b46c]:8333 # AS16509
-[2a05:d014:a55:4003:6523:50a1:152:e88c]:8333 # AS16509
-[2a05:d01a:b7b:3c01:8bf7:ae14:afb3:33ae]:8333 # AS16509
+[2a05:3580:dc0b:1600:def4:5a62:de42:324a]:8333 # AS20764
+[2a05:d014:a55:4000:8dde:69f:4ac7:b26]:8333 # AS16509
+[2a05:d016:98f:5201:6be0:a4de:80c7:32d5]:8333 # AS16509
+[2a05:d018:a75:6c03:75b:2c73:8caa:414b]:8333 # AS16509
[2a05:f480:1800:697:5400:2ff:feb6:c36d]:8333 # AS20473
[2a06:e040:7603:2918:c6ef:464e:9fe5:73ec]:8333 # AS198507
-[2a07:abc4::1:946]:8333 # AS62000
+[2a07:abc4::89:234:180:194]:8333 # AS62000
+[2a07:d884::127e]:8333 # AS6762
+[2a09:2681:1010:10::5]:8333 # AS61282
[2a09:2681:102::210]:8333 # AS61282
-[2a0a:c801:1:7::183]:8333 # AS39798
-[2a0c:5a80:1210:a800:6af7:28ff:fee5:6b3a]:8333 # AS57269
-[2a0d:5600:24:a8e::a91e]:55373 # AS9009
-[2a0d:7c40:3000:b04::2]:8333 # AS54290
+[2a0b:f300:2:6::2]:8333 # AS62240
[2a0d:8340:24::2]:8333 # AS50113
-[2a0f:df00:0:2010::162]:8333 # AS41281
-[2a10:3781:16b9:1:fe3f:dbff:fe04:2d4c]:8333 # AS206238
-[2a10:3781:84b:1:b123:6306:943a:f09b]:8333 # AS206238
+[2a0e:8f02:21d1:144::101]:8333 # AS20473
+[2a0e:b780::55d1:f05b]:8333 # AS205581
+[2a10:3781:2c19::1]:8333 # AS206238
[2a10:d200:1:33:a6bf:1ff:fe6a:46a9]:8333 # AS212323
-[2c0f:f4c0:2202:20b0:261c:4ff:fe14:daa0]:8333 # AS327693
-[2c0f:f8f0:da51:0:70c3:eea9:9717:9579]:8333 # AS30844
+[2a12:8e40:5668:e40a::1]:8333 # AS34465
+[2a12:8e40:5668:e40b::1]:8333 # AS34465
+[2a12:8e40:5668:e40c::1]:8333 # AS34465
+[2a12:8e40:5668:e40d::1]:8333 # AS34465
+[2a12:8e40:5668:e40e::1]:8333 # AS34465
+[2a12:8e40:5668:e40f::1]:8333 # AS34465
+[2a12:8e40:5668:e410::1]:8333 # AS34465
+[2a12:8e40:5668:e411::1]:8333 # AS34465
+[2a12:8e40:5668:e412::1]:8333 # AS34465
+[2a12:8e40:5668:e417::1]:8333 # AS34465
+[2c0f:f8f0:da51:0:3a45:fc57:5e30:2593]:8333 # AS30844
-# manually updated 2022-08 for minimal torv3 bootstrap support
+# manually updated 2023-04 for minimal torv3 bootstrap support
+
+2bqghnldu6mcug4pikzprwhtjjnsyederctvci6klcwzepnjd46ikjyd.onion:8333
+4lr3w2iyyl5u5l6tosizclykf5v3smqroqdn2i4h3kq6pfbbjb2xytad.onion:8333
5g72ppm3krkorsfopcm2bi7wlv4ohhs4u4mlseymasn7g7zhdcyjpfid.onion:8333
+5sbmcl4m5api5tqafi4gcckrn3y52sz5mskxf3t6iw4bp7erwiptrgqd.onion:8333
+776aegl7tfhg6oiqqy76jnwrwbvcytsx2qegcgh2mjqujll4376ohlid.onion:8333
+77mdte42srl42shdh2mhtjr7nf7dmedqrw6bkcdekhdvmnld6ojyyiad.onion:8333
+azbpsh4arqlm6442wfimy7qr65bmha2zhgjg7wbaji6vvaug53hur2qd.onion:8333
b64xcbleqmwgq2u46bh4hegnlrzzvxntyzbmucn3zt7cssm7y4ubv3id.onion:8333
-fjdyxicpm4o42xmedlwl3uvk5gmqdfs5j37wir52327vncjzvtpfv7yd.onion:8333
+bsqbtcparrfihlwolt4xgjbf4cgqckvrvsfyvy6vhiqrnh4w6ghixoid.onion:8333
+bsqbtctulf2g4jtjsdfgl2ed7qs6zz5wqx27qnyiik7laockryvszqqd.onion:8333
+cwi3ekrwhig47dhhzfenr5hbvckj7fzaojygvazi2lucsenwbzwoyiqd.onion:8333
+devinbtcmwkuitvxl3tfi5of4zau46ymeannkjv6fpnylkgf3q5fa3id.onion:8333
+devinbtctu7uctl7hly2juu3thbgeivfnvw3ckj3phy6nyvpnx66yeyd.onion:8333
+devinbtcyk643iruzfpaxw3on2jket7rbjmwygm42dmdyub3ietrbmid.onion:8333
+dtql5vci4iaml4anmueftqr7bfgzqlauzfy4rc2tfgulldd3ekyijjyd.onion:8333
+emzybtc25oddoa2prol2znpz2axnrg6k77xwgirmhv7igoiucddsxiad.onion:8333
+emzybtc3ewh7zihpkdvuwlgxrhzcxy2p5fvjggp7ngjbxcytxvt4rjid.onion:8333
+emzybtc454ewbviqnmgtgx3rgublsgkk23r4onbhidcv36wremue4kqd.onion:8333
+emzybtc5bnpb2o6gh54oquiox54o4r7yn4a2wiiwzrjonlouaibm2zid.onion:8333
fpz6r5ppsakkwypjcglz6gcnwt7ytfhxskkfhzu62tnylcknh3eq6pad.onion:8333
-gxo5anvfnffnftfy5frkgvplq3rpga2ie3tcblo2vl754fvnhgorn5yd.onion:8333
-ifdu5qvbofrt4ekui2iyb3kbcyzcsglazhx2hn4wfskkrx2v24qxriid.onion:8333
-itz3oxsihs62muvknc237xabl5f6w6rfznfhbpayrslv2j2ubels47yd.onion:8333
+hanvo3hzqbhcqm5vahhi5a3czxxdwc7vt56p5gr7bifcvelaqurv6iid.onion:8333
+hz7oqntvj4adrwtqappcgaxfribg5u4rvfkpwlo3xup5fcuyvylkxlqd.onion:8333
+ityrxhidvjnjnf6imzyuqqnkkwridjnebkbokx25so3suq3fzezmksid.onion:8333
+jto2jfbsxhb6yvhcrrjddrgbakte6tgsy3c3z3prss64gndgvovvosyd.onion:8333
+k7nb3r7hxi5exvr4xmvnilhfw6hei7sw4rwz2t6onh4py6wbora6tuyd.onion:8333
kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion:8333
+l7kw3vjs4cf5mnuejjgqcxrw6wwsjmabllq3h3amy4f5q33d6cgo2kyd.onion:8333
m7cbpjolo662uel7rpaid46as2otcj44vvwg3gccodnvaeuwbm3anbyd.onion:8333
+mowb2qwpjgs2a6q3yj3xa7nxklfssul4w7ynonyycw3uyopfu3x6ujad.onion:8333
mwmfluek4au6mxxpw6fy7sjhkm65bdfc7izc7lpz3trewfdghyrzsbid.onion:8333
-rp7k2go3s5lyj3fnj6zn62ktarlrsft2ohlsxkyd7v3e3idqyptvread.onion:8333
+rfqmn3qe36uaptkxhdvi74p4hyrzhir6vhmzb2hqryxodig4gue2zbyd.onion:8333
+rsgwtnousfc7zyg4qsm3gvczjx7cihh2njyjbjl3qvcj3xg7wmvhddqd.onion:8333
+s2d52bbttuwcl3pdrwzhxpmhtxn3jg23havjqg5eygwhtiw6lgyelpqd.onion:8333
+upvthy74hgvgbqi6w3zd2mlchoi5tvvw7b5hpmmhcddd5fnnwrixneid.onion:8333
+who3qs4eqlqzoxhqqgan4mg54ua5uz3mk4lj33ag53ei4orvnznrjbad.onion:8333
+wizbit5555bsslwv4ctronnsgk5vh2w2pdx7v7eyuivlyuoteejk7lid.onion:8333
+yrmedr35tt4wqfnwgilltxh5bnukeukxjpgg3jzmmsyld5lgsn5amvyd.onion:8333
-# manually updated 2022-08 for minimal i2p bootstrap support
+# manually updated 2023-04 for minimal i2p bootstrap support
255fhcp6ajvftnyo7bwz3an3t4a4brhopm3bamyh2iu5r3gnr2rq.b32.i2p:0
27yrtht5b5bzom2w5ajb27najuqvuydtzb7bavlak25wkufec5mq.b32.i2p:0
-2el6enckmfyiwbfcwsygkwksovtynzsigmyv3bzyk7j7qqahooua.b32.i2p:0
3gocb7wc4zvbmmebktet7gujccuux4ifk3kqilnxnj5wpdpqx2hq.b32.i2p:0
-3tns2oov4tnllntotazy6umzkq4fhkco3iu5rnkxtu3pbfzxda7q.b32.i2p:0
4fcc23wt3hyjk3csfzcdyjz5pcwg5dzhdqgma6bch2qyiakcbboa.b32.i2p:0
4osyqeknhx5qf3a73jeimexwclmt42cju6xdp7icja4ixxguu2hq.b32.i2p:0
4umsi4nlmgyp4rckosg4vegd2ysljvid47zu7pqsollkaszcbpqq.b32.i2p:0
-52v6uo6crlrlhzphslyiqblirux6olgsaa45ixih7sq5np4jujaa.b32.i2p:0
6j2ezegd3e2e2x3o3pox335f5vxfthrrigkdrbgfbdjchm5h4awa.b32.i2p:0
6n36ljyr55szci5ygidmxqer64qr24f4qmnymnbvgehz7qinxnla.b32.i2p:0
72yjs6mvlby3ky6mgpvvlemmwq5pfcznrzd34jkhclgrishqdxva.b32.i2p:0
-7r4ri53lby2i3xqbgpw3idvhzeku7ubhftlf72ldqkg5kde6dauq.b32.i2p:0
a5qsnv3maw77mlmmzlcglu6twje6ttctd3fhpbfwcbpmewx6fczq.b32.i2p:0
aovep2pco7v2k4rheofrgytbgk23eg22dczpsjqgqtxcqqvmxk6a.b32.i2p:0
-bddbsmkas3z6fakorbkfjhv77i4hv6rysyjsvrdjukxolfghc23q.b32.i2p:0
bitcoi656nll5hu6u7ddzrmzysdtwtnzcnrjd4rfdqbeey7dmn5a.b32.i2p:0
brifkruhlkgrj65hffybrjrjqcgdgqs2r7siizb5b2232nruik3a.b32.i2p:0
c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p:0
day3hgxyrtwjslt54sikevbhxxs4qzo7d6vi72ipmscqtq3qmijq.b32.i2p:0
-di2zq6fr3fegf2jdcd7hdwyql4umr462gonsns2nxz5qg5vz4bka.b32.i2p:0
+du5kydummi23bjfp6bd7owsvrijgt7zhvxmz5h5f5spcioeoetwq.b32.i2p:0
e55k6wu46rzp4pg5pk5npgbr3zz45bc3ihtzu2xcye5vwnzdy7pq.b32.i2p:0
eciohu5nq7vsvwjjc52epskuk75d24iccgzmhbzrwonw6lx4gdva.b32.i2p:0
ejlnngarmhqvune74ko7kk55xtgbz5i5ncs4vmnvjpy3l7y63xaa.b32.i2p:0
-g47cqoppu26pr4n2cfaioqx7lbdi7mea7yqhlrkdz3wjwxjxdh2a.b32.i2p:0
-h3r6bkn46qxftwja53pxiykntegfyfjqtnzbm6iv6r5mungmqgmq.b32.i2p:0
+fhzlp3xroabohnmjonu5iqazwhlbbwh5cpujvw2azcu3srqdceja.b32.i2p:0
+fx6np3oheacr3t7gluftrqo2qxldbbatgw4hepp7ulb4j5ry57ca.b32.i2p:0
+gehtac45oaghz54ypyopim64mql7oad2bqclla74l6tfeolzmodq.b32.i2p:0
hhfi4yqkg2twqiwezrfksftjjofbyx3ojkmlnfmcwntgnrjjhkya.b32.i2p:0
-hpiibrflqkbrcshfhmrtwfyeb7mds7a3obzwrgarejevddzamvsq.b32.i2p:0
-i4pyhsfdq4247dunel7paatdaq5gusi2hnybp2yf5wxwdnrgxaqq.b32.i2p:0
-iw6tgpmbdykffceku5da6nzf2bmz66fvp5fpcvemfu3df6aq6pga.b32.i2p:0
-jkfuajo4ayvo2rbv5qdj443q6adqmnormbhsf2f7rlp5t24xomda.b32.i2p:0
jz3s4eurm5vzjresf4mwo7oni4bk36daolwxh4iqtewakylgkxmq.b32.i2p:0
liu75cvktv4icbctg72w7nxbk4eibt7wamizfdii4omz7gcke5vq.b32.i2p:0
-ljsquuu3y4xje6l32p32inn6r2y6ull6oocgup6jtjrohrqxbz6a.b32.i2p:0
lrah7acdsgopybg43shadwwiv6igezaw64i6jb5muqdg7dmhj3la.b32.i2p:0
lzuu6mjtu7vd55d2biphicihufipoa7vyym6xfnkmmlra3tiziia.b32.i2p:0
m6bpynxkv2ktwxkg6p2gyudjfhdupb6kuzabeqdnckkdkf4kxjla.b32.i2p:0
m6v454xd6p3bt5swujgmveklsp7lzbkqlqqfc2p36cjlwv5dbucq.b32.i2p:0
mlgeizrroynuhpxbzeosajt5u4ddcvynxfmcbm6kwjpaufilxigq.b32.i2p:0
+o6t4fr5ayfadzieutstgwcllvwxeuzjlxmzsmpj3hpkvefhzfaea.b32.i2p:0
ofubxr2ir7u2guzjwyrvujicivzmvinwa36nuzlrg7tnsmebal7a.b32.i2p:0
-okfxeoh6itu4f5f43dhbzvkqwfrvm5c66lj6lvjj4q2b35i4pk4q.b32.i2p:0
oz2ia3flpm3du2tyusulrn7h7e2eo3juzkrmn34bvnrlcrugv7ia.b32.i2p:0
+pohfcrfc7prn4bvn4xstw6nt3e7hjmb7kuj4djtsfqsskwhmhnna.b32.i2p:0
qd6jlsevsexww3wefpqs7iglxb3f63y4e6ydulfzrvwflpicmdqa.b32.i2p:0
-qddg7myylinn4tw6kdjmmp6fsyetkosnrbp2gsjx77tmkqyqv6ua.b32.i2p:0
+rfjkzdzv4cwpxo6hzuncicvuyui76wxqx3a23lynq72ktwqs7aja.b32.i2p:0
rizfinyses2r3or4iubs5wx66gdy6mpf73w7uobfacm2l5cral3q.b32.i2p:0
-s5hhjtmlg53bko3nwwskas7xgsmeqzy6thtsj5aa64djyrljgqaq.b32.i2p:0
sedndhv5vpcgdmykyi5st4yqhdxl3hpdtglta4do435wupahhx6q.b32.i2p:0
-tsl4dlpu2id252b6crbdnblruct664se6f2iw35fuqwa3te7wcoq.b32.i2p:0
tugq6wa2ls2bv27pr2iy3da3k5ow3fzefbcvjcr22uc7w5vmevja.b32.i2p:0
usztavbib756k5vqggzgkyswoj6mttihjvp3c2pa642t2mb4pvsa.b32.i2p:0
vgu6llqbyjphml25umd5ztvyxrxuplz2g74fzbx75g3kkaetoyiq.b32.i2p:0
wjrul5jwwb4vqdmkkrjbmly7osj6amecdpsac5xvaoqrti4nb3ha.b32.i2p:0
-wvktcp7hy4l6immhi5cxyz2dlsbhhvtcmskjemrnqehacnoap23q.b32.i2p:0
wwbw7nqr3ahkqv62cuqfwgtneekvvpnuc4i4f6yo7tpoqjswvcwa.b32.i2p:0
-xlqndzjoe5nr2nsxo6xwibh44ghyz4jfqevu62xykvemextpmjbq.b32.i2p:0
+xfkarmvk43vfkfvhkehy7ioj2b6wtfdlezvmlakblz3q4r7mccfq.b32.i2p:0
yc4xwin5ujenvcr6ynwkz7lnmmq3nmzxvfguele6ovqqpxgjvonq.b32.i2p:0
zdoabsg7ugzothyawodjhq54nvlofa746rxfkxpnjzj6nukmha6a.b32.i2p:0
zsxwyo6qcn3chqzwxnseusqgsnuw3maqnztkiypyfxtya4snkoka.b32.i2p:0
zysrlpii5ftrzivfcyhdrwpeyyqddbrdefnfu5q6otk5gtugmh2a.b32.i2p:0
-# manually added 2022-01 for minimal cjdns bootstrap support
+# manually updated 2023-04 for minimal cjdns bootstrap support
[fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa]:8333
[fcc7:be49:ccd1:dc91:3125:f0da:457d:8ce]:8333
+[fcdc:73ae:b1a9:1bf8:d4c2:811:a4c7:c34e]:8333
diff --git a/contrib/seeds/nodes_main_manual.txt b/contrib/seeds/nodes_main_manual.txt
index 286448d95d..91a64c6e51 100644
--- a/contrib/seeds/nodes_main_manual.txt
+++ b/contrib/seeds/nodes_main_manual.txt
@@ -1,78 +1,95 @@
-# manually updated 2022-08 for minimal torv3 bootstrap support
+# manually updated 2023-04 for minimal torv3 bootstrap support
+
+2bqghnldu6mcug4pikzprwhtjjnsyederctvci6klcwzepnjd46ikjyd.onion:8333
+4lr3w2iyyl5u5l6tosizclykf5v3smqroqdn2i4h3kq6pfbbjb2xytad.onion:8333
5g72ppm3krkorsfopcm2bi7wlv4ohhs4u4mlseymasn7g7zhdcyjpfid.onion:8333
+5sbmcl4m5api5tqafi4gcckrn3y52sz5mskxf3t6iw4bp7erwiptrgqd.onion:8333
+776aegl7tfhg6oiqqy76jnwrwbvcytsx2qegcgh2mjqujll4376ohlid.onion:8333
+77mdte42srl42shdh2mhtjr7nf7dmedqrw6bkcdekhdvmnld6ojyyiad.onion:8333
+azbpsh4arqlm6442wfimy7qr65bmha2zhgjg7wbaji6vvaug53hur2qd.onion:8333
b64xcbleqmwgq2u46bh4hegnlrzzvxntyzbmucn3zt7cssm7y4ubv3id.onion:8333
-fjdyxicpm4o42xmedlwl3uvk5gmqdfs5j37wir52327vncjzvtpfv7yd.onion:8333
+bsqbtcparrfihlwolt4xgjbf4cgqckvrvsfyvy6vhiqrnh4w6ghixoid.onion:8333
+bsqbtctulf2g4jtjsdfgl2ed7qs6zz5wqx27qnyiik7laockryvszqqd.onion:8333
+cwi3ekrwhig47dhhzfenr5hbvckj7fzaojygvazi2lucsenwbzwoyiqd.onion:8333
+devinbtcmwkuitvxl3tfi5of4zau46ymeannkjv6fpnylkgf3q5fa3id.onion:8333
+devinbtctu7uctl7hly2juu3thbgeivfnvw3ckj3phy6nyvpnx66yeyd.onion:8333
+devinbtcyk643iruzfpaxw3on2jket7rbjmwygm42dmdyub3ietrbmid.onion:8333
+dtql5vci4iaml4anmueftqr7bfgzqlauzfy4rc2tfgulldd3ekyijjyd.onion:8333
+emzybtc25oddoa2prol2znpz2axnrg6k77xwgirmhv7igoiucddsxiad.onion:8333
+emzybtc3ewh7zihpkdvuwlgxrhzcxy2p5fvjggp7ngjbxcytxvt4rjid.onion:8333
+emzybtc454ewbviqnmgtgx3rgublsgkk23r4onbhidcv36wremue4kqd.onion:8333
+emzybtc5bnpb2o6gh54oquiox54o4r7yn4a2wiiwzrjonlouaibm2zid.onion:8333
fpz6r5ppsakkwypjcglz6gcnwt7ytfhxskkfhzu62tnylcknh3eq6pad.onion:8333
-gxo5anvfnffnftfy5frkgvplq3rpga2ie3tcblo2vl754fvnhgorn5yd.onion:8333
-ifdu5qvbofrt4ekui2iyb3kbcyzcsglazhx2hn4wfskkrx2v24qxriid.onion:8333
-itz3oxsihs62muvknc237xabl5f6w6rfznfhbpayrslv2j2ubels47yd.onion:8333
+hanvo3hzqbhcqm5vahhi5a3czxxdwc7vt56p5gr7bifcvelaqurv6iid.onion:8333
+hz7oqntvj4adrwtqappcgaxfribg5u4rvfkpwlo3xup5fcuyvylkxlqd.onion:8333
+ityrxhidvjnjnf6imzyuqqnkkwridjnebkbokx25so3suq3fzezmksid.onion:8333
+jto2jfbsxhb6yvhcrrjddrgbakte6tgsy3c3z3prss64gndgvovvosyd.onion:8333
+k7nb3r7hxi5exvr4xmvnilhfw6hei7sw4rwz2t6onh4py6wbora6tuyd.onion:8333
kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion:8333
+l7kw3vjs4cf5mnuejjgqcxrw6wwsjmabllq3h3amy4f5q33d6cgo2kyd.onion:8333
m7cbpjolo662uel7rpaid46as2otcj44vvwg3gccodnvaeuwbm3anbyd.onion:8333
+mowb2qwpjgs2a6q3yj3xa7nxklfssul4w7ynonyycw3uyopfu3x6ujad.onion:8333
mwmfluek4au6mxxpw6fy7sjhkm65bdfc7izc7lpz3trewfdghyrzsbid.onion:8333
-rp7k2go3s5lyj3fnj6zn62ktarlrsft2ohlsxkyd7v3e3idqyptvread.onion:8333
+rfqmn3qe36uaptkxhdvi74p4hyrzhir6vhmzb2hqryxodig4gue2zbyd.onion:8333
+rsgwtnousfc7zyg4qsm3gvczjx7cihh2njyjbjl3qvcj3xg7wmvhddqd.onion:8333
+s2d52bbttuwcl3pdrwzhxpmhtxn3jg23havjqg5eygwhtiw6lgyelpqd.onion:8333
+upvthy74hgvgbqi6w3zd2mlchoi5tvvw7b5hpmmhcddd5fnnwrixneid.onion:8333
+who3qs4eqlqzoxhqqgan4mg54ua5uz3mk4lj33ag53ei4orvnznrjbad.onion:8333
+wizbit5555bsslwv4ctronnsgk5vh2w2pdx7v7eyuivlyuoteejk7lid.onion:8333
+yrmedr35tt4wqfnwgilltxh5bnukeukxjpgg3jzmmsyld5lgsn5amvyd.onion:8333
-# manually updated 2022-08 for minimal i2p bootstrap support
+# manually updated 2023-04 for minimal i2p bootstrap support
255fhcp6ajvftnyo7bwz3an3t4a4brhopm3bamyh2iu5r3gnr2rq.b32.i2p:0
27yrtht5b5bzom2w5ajb27najuqvuydtzb7bavlak25wkufec5mq.b32.i2p:0
-2el6enckmfyiwbfcwsygkwksovtynzsigmyv3bzyk7j7qqahooua.b32.i2p:0
3gocb7wc4zvbmmebktet7gujccuux4ifk3kqilnxnj5wpdpqx2hq.b32.i2p:0
-3tns2oov4tnllntotazy6umzkq4fhkco3iu5rnkxtu3pbfzxda7q.b32.i2p:0
4fcc23wt3hyjk3csfzcdyjz5pcwg5dzhdqgma6bch2qyiakcbboa.b32.i2p:0
4osyqeknhx5qf3a73jeimexwclmt42cju6xdp7icja4ixxguu2hq.b32.i2p:0
4umsi4nlmgyp4rckosg4vegd2ysljvid47zu7pqsollkaszcbpqq.b32.i2p:0
-52v6uo6crlrlhzphslyiqblirux6olgsaa45ixih7sq5np4jujaa.b32.i2p:0
6j2ezegd3e2e2x3o3pox335f5vxfthrrigkdrbgfbdjchm5h4awa.b32.i2p:0
6n36ljyr55szci5ygidmxqer64qr24f4qmnymnbvgehz7qinxnla.b32.i2p:0
72yjs6mvlby3ky6mgpvvlemmwq5pfcznrzd34jkhclgrishqdxva.b32.i2p:0
-7r4ri53lby2i3xqbgpw3idvhzeku7ubhftlf72ldqkg5kde6dauq.b32.i2p:0
a5qsnv3maw77mlmmzlcglu6twje6ttctd3fhpbfwcbpmewx6fczq.b32.i2p:0
aovep2pco7v2k4rheofrgytbgk23eg22dczpsjqgqtxcqqvmxk6a.b32.i2p:0
-bddbsmkas3z6fakorbkfjhv77i4hv6rysyjsvrdjukxolfghc23q.b32.i2p:0
bitcoi656nll5hu6u7ddzrmzysdtwtnzcnrjd4rfdqbeey7dmn5a.b32.i2p:0
brifkruhlkgrj65hffybrjrjqcgdgqs2r7siizb5b2232nruik3a.b32.i2p:0
c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p:0
day3hgxyrtwjslt54sikevbhxxs4qzo7d6vi72ipmscqtq3qmijq.b32.i2p:0
-di2zq6fr3fegf2jdcd7hdwyql4umr462gonsns2nxz5qg5vz4bka.b32.i2p:0
+du5kydummi23bjfp6bd7owsvrijgt7zhvxmz5h5f5spcioeoetwq.b32.i2p:0
e55k6wu46rzp4pg5pk5npgbr3zz45bc3ihtzu2xcye5vwnzdy7pq.b32.i2p:0
eciohu5nq7vsvwjjc52epskuk75d24iccgzmhbzrwonw6lx4gdva.b32.i2p:0
ejlnngarmhqvune74ko7kk55xtgbz5i5ncs4vmnvjpy3l7y63xaa.b32.i2p:0
-g47cqoppu26pr4n2cfaioqx7lbdi7mea7yqhlrkdz3wjwxjxdh2a.b32.i2p:0
-h3r6bkn46qxftwja53pxiykntegfyfjqtnzbm6iv6r5mungmqgmq.b32.i2p:0
+fhzlp3xroabohnmjonu5iqazwhlbbwh5cpujvw2azcu3srqdceja.b32.i2p:0
+fx6np3oheacr3t7gluftrqo2qxldbbatgw4hepp7ulb4j5ry57ca.b32.i2p:0
+gehtac45oaghz54ypyopim64mql7oad2bqclla74l6tfeolzmodq.b32.i2p:0
hhfi4yqkg2twqiwezrfksftjjofbyx3ojkmlnfmcwntgnrjjhkya.b32.i2p:0
-hpiibrflqkbrcshfhmrtwfyeb7mds7a3obzwrgarejevddzamvsq.b32.i2p:0
-i4pyhsfdq4247dunel7paatdaq5gusi2hnybp2yf5wxwdnrgxaqq.b32.i2p:0
-iw6tgpmbdykffceku5da6nzf2bmz66fvp5fpcvemfu3df6aq6pga.b32.i2p:0
-jkfuajo4ayvo2rbv5qdj443q6adqmnormbhsf2f7rlp5t24xomda.b32.i2p:0
jz3s4eurm5vzjresf4mwo7oni4bk36daolwxh4iqtewakylgkxmq.b32.i2p:0
liu75cvktv4icbctg72w7nxbk4eibt7wamizfdii4omz7gcke5vq.b32.i2p:0
-ljsquuu3y4xje6l32p32inn6r2y6ull6oocgup6jtjrohrqxbz6a.b32.i2p:0
lrah7acdsgopybg43shadwwiv6igezaw64i6jb5muqdg7dmhj3la.b32.i2p:0
lzuu6mjtu7vd55d2biphicihufipoa7vyym6xfnkmmlra3tiziia.b32.i2p:0
m6bpynxkv2ktwxkg6p2gyudjfhdupb6kuzabeqdnckkdkf4kxjla.b32.i2p:0
m6v454xd6p3bt5swujgmveklsp7lzbkqlqqfc2p36cjlwv5dbucq.b32.i2p:0
mlgeizrroynuhpxbzeosajt5u4ddcvynxfmcbm6kwjpaufilxigq.b32.i2p:0
+o6t4fr5ayfadzieutstgwcllvwxeuzjlxmzsmpj3hpkvefhzfaea.b32.i2p:0
ofubxr2ir7u2guzjwyrvujicivzmvinwa36nuzlrg7tnsmebal7a.b32.i2p:0
-okfxeoh6itu4f5f43dhbzvkqwfrvm5c66lj6lvjj4q2b35i4pk4q.b32.i2p:0
oz2ia3flpm3du2tyusulrn7h7e2eo3juzkrmn34bvnrlcrugv7ia.b32.i2p:0
+pohfcrfc7prn4bvn4xstw6nt3e7hjmb7kuj4djtsfqsskwhmhnna.b32.i2p:0
qd6jlsevsexww3wefpqs7iglxb3f63y4e6ydulfzrvwflpicmdqa.b32.i2p:0
-qddg7myylinn4tw6kdjmmp6fsyetkosnrbp2gsjx77tmkqyqv6ua.b32.i2p:0
+rfjkzdzv4cwpxo6hzuncicvuyui76wxqx3a23lynq72ktwqs7aja.b32.i2p:0
rizfinyses2r3or4iubs5wx66gdy6mpf73w7uobfacm2l5cral3q.b32.i2p:0
-s5hhjtmlg53bko3nwwskas7xgsmeqzy6thtsj5aa64djyrljgqaq.b32.i2p:0
sedndhv5vpcgdmykyi5st4yqhdxl3hpdtglta4do435wupahhx6q.b32.i2p:0
-tsl4dlpu2id252b6crbdnblruct664se6f2iw35fuqwa3te7wcoq.b32.i2p:0
tugq6wa2ls2bv27pr2iy3da3k5ow3fzefbcvjcr22uc7w5vmevja.b32.i2p:0
usztavbib756k5vqggzgkyswoj6mttihjvp3c2pa642t2mb4pvsa.b32.i2p:0
vgu6llqbyjphml25umd5ztvyxrxuplz2g74fzbx75g3kkaetoyiq.b32.i2p:0
wjrul5jwwb4vqdmkkrjbmly7osj6amecdpsac5xvaoqrti4nb3ha.b32.i2p:0
-wvktcp7hy4l6immhi5cxyz2dlsbhhvtcmskjemrnqehacnoap23q.b32.i2p:0
wwbw7nqr3ahkqv62cuqfwgtneekvvpnuc4i4f6yo7tpoqjswvcwa.b32.i2p:0
-xlqndzjoe5nr2nsxo6xwibh44ghyz4jfqevu62xykvemextpmjbq.b32.i2p:0
+xfkarmvk43vfkfvhkehy7ioj2b6wtfdlezvmlakblz3q4r7mccfq.b32.i2p:0
yc4xwin5ujenvcr6ynwkz7lnmmq3nmzxvfguele6ovqqpxgjvonq.b32.i2p:0
zdoabsg7ugzothyawodjhq54nvlofa746rxfkxpnjzj6nukmha6a.b32.i2p:0
zsxwyo6qcn3chqzwxnseusqgsnuw3maqnztkiypyfxtya4snkoka.b32.i2p:0
zysrlpii5ftrzivfcyhdrwpeyyqddbrdefnfu5q6otk5gtugmh2a.b32.i2p:0
-# manually added 2022-01 for minimal cjdns bootstrap support
+# manually updated 2023-04 for minimal cjdns bootstrap support
[fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa]:8333
[fcc7:be49:ccd1:dc91:3125:f0da:457d:8ce]:8333
+[fcdc:73ae:b1a9:1bf8:d4c2:811:a4c7:c34e]:8333
diff --git a/contrib/signet/getcoins.py b/contrib/signet/getcoins.py
index d4e436626f..19751ae269 100755
--- a/contrib/signet/getcoins.py
+++ b/contrib/signet/getcoins.py
@@ -142,7 +142,7 @@ if args.captcha != '': # Retrieve a captcha
try:
res = session.post(args.faucet, data=data)
-except:
+except Exception:
raise SystemExit(f"Unexpected error when contacting faucet: {sys.exc_info()[0]}")
# Display the output as per the returned status code
diff --git a/contrib/tracing/README.md b/contrib/tracing/README.md
index a409a23ef8..206bec1647 100644
--- a/contrib/tracing/README.md
+++ b/contrib/tracing/README.md
@@ -286,3 +286,53 @@ Spent a05880b8c77971ed0b9f73062c7c4cdb0ff3856ab14cbf8bc481ed571cd34b83:1
Added eb689865f7d957938978d6207918748f74e6aa074f47874724327089445b0960:0 5589696005 2094513 No
Added eb689865f7d957938978d6207918748f74e6aa074f47874724327089445b0960:1 1565556 2094513 No
```
+
+### mempool_monitor.py
+
+A BCC Python script producing mempool statistics and an event log. Based on the
+`mempool:added`, `mempool:removed`, `mempool:replaced`, and `mempool:rejected`
+tracepoints.
+
+Statistics include incidence and rate for each event type since the script was
+started (`total`) as well as during the last minute (`1 min`) and ten minutes
+(`10 min`). The event log shows mempool events in real time, each entry
+comprising a timestamp along with all event data available via the event's
+tracepoint.
+
+```console
+$ python3 contrib/tracing/mempool_monitor.py ./src/bitcoind
+```
+
+```
+ Mempool Monitor
+ Press CTRL-C to stop.
+
+ ┌─Event count───────────────────────┐ ┌─Event rate──────────────────────────┐
+ │ Event total 1 min 10 min │ │ Event total 1 min 10 min │
+ │ added 1425tx 201tx 1425tx │ │ added 4.7tx/s 3.4tx/s 4.7tx/s │
+ │ removed 35tx 4tx 35tx │ │ removed 0.1tx/s 0.1tx/s 0.1tx/s │
+ │ replaced 35tx 4tx 35tx │ │ replaced 0.1tx/s 0.1tx/s 0.1tx/s │
+ │ rejected 0tx 0tx 0tx │ │ rejected 0.0tx/s 0.0tx/s 0.0tx/s │
+ └───────────────────────────────────┘ └─────────────────────────────────────┘
+
+ ┌─Event log────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+ │ 13:10:30Z added f9064ca5bfc87cdd191faa42bf697217cd920b2b94838c1f1192e4f06c4fd217 with feerate 8.92 sat/vB (981 sat, 110 vbytes) │
+ │ 13:10:30Z added 53ffa3afbe57b1bfe423e1755ca2b52c5b6cb4aa91b8b7ee9cb694953f47f234 with feerate 5.00 sat/vB (550 sat, 110 vbytes) │
+ │ 13:10:30Z added 4177df5e19465eb5e53c3f8b6830a293f57474921bc6c2ae89375e0986e1f0f9 with feerate 2.98 sat/vB (429 sat, 144 vbytes) │
+ │ 13:10:30Z added 931a10d83f0a268768da75dc4b9e199f2f055f12979ae5491cc304ee10f890ea with feerate 3.55 sat/vB (500 sat, 141 vbytes) │
+ │ 13:10:30Z added 4cf32b295723cc4ab73f2a2e51d4bb276c0042760a4c00a3eb9595b8ebb24721 with feerate 89.21 sat/vB (12668 sat, 142 vbytes) │
+ │ 13:10:31Z replaced d1eecf9d662121322f4f31f0c2267a752d14bb3956e6016ba96e87f47890e1db with feerate 27.12 sat/vB received 23.3 seconds ago (7213 sat, 266 vbytes) with c412db908│
+ │ 9b7ed53f3e5e36d2819dd291278b59ccaabaeb17fd37c3d87fdcd57 with feerate 28.12 sat/vB (8351 sat, 297 vbytes) │
+ │ 13:10:31Z added c412db9089b7ed53f3e5e36d2819dd291278b59ccaabaeb17fd37c3d87fdcd57 with feerate 28.12 sat/vB (8351 sat, 297 vbytes) │
+ │ 13:10:31Z added b8388a5bdc421b11460bdf477d5a85a1a39c2784e7dd7bffabe688740424ea57 with feerate 25.21 sat/vB (3554 sat, 141 vbytes) │
+ │ 13:10:31Z added 4ddb88bc90a122cd9eae8a664e73bdf5bebe75f3ef901241b4a251245854a98e with feerate 24.15 sat/vB (5072 sat, 210 vbytes) │
+ │ 13:10:31Z added 19101e4161bca5271ad5d03e7747f2faec7793b274dc2f3c4cf516b7cef1aac3 with feerate 7.06 sat/vB (1080 sat, 153 vbytes) │
+ │ 13:10:31Z removed d1eecf9d662121322f4f31f0c2267a752d14bb3956e6016ba96e87f47890e1db with feerate 27.12 sat/vB (7213 sat, 266 vbytes): replaced │
+ │ 13:10:31Z added 6c511c60d9b95b9eff81df6ecba5c86780f513fe62ce3ad6be2c5340d957025a with feerate 4.00 sat/vB (440 sat, 110 vbytes) │
+ │ 13:10:31Z added 44d66f7f004bd52c46be4dff3067cab700e51c7866a84282bd8aab560a5bfb79 with feerate 3.15 sat/vB (448 sat, 142 vbytes) │
+ │ 13:10:31Z added b17b7c9ec5acfbbf12f0eeef8e29826fad3105bb95eef7a47d2f1f22b4784643 with feerate 4.10 sat/vB (1348 sat, 329 vbytes) │
+ │ 13:10:31Z added b7a4ad93554e57454e8a8049bfc0bd803fa962bd3f0a08926aa72e7cb23e2276 with feerate 1.01 sat/vB (205 sat, 202 vbytes) │
+ │ 13:10:32Z added c78e87be86c828137a6e7e00a177c03b52202ce4c39029b99904c2a094b9da87 with feerate 11.00 sat/vB (1562 sat, 142 vbytes) │
+ │ │
+ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+```
diff --git a/contrib/tracing/mempool_monitor.py b/contrib/tracing/mempool_monitor.py
new file mode 100755
index 0000000000..9d427d4632
--- /dev/null
+++ b/contrib/tracing/mempool_monitor.py
@@ -0,0 +1,372 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+""" Example logging Bitcoin Core mempool events using the mempool:added,
+ mempool:removed, mempool:replaced, and mempool:rejected tracepoints. """
+
+import curses
+import sys
+from datetime import datetime, timezone
+
+from bcc import BPF, USDT
+
+# BCC: The C program to be compiled to an eBPF program (by BCC) and loaded into
+# a sandboxed Linux kernel VM.
+PROGRAM = """
+# include <uapi/linux/ptrace.h>
+
+// The longest rejection reason is 118 chars and is generated in case of SCRIPT_ERR_EVAL_FALSE by
+// strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))
+#define MAX_REJECT_REASON_LENGTH 118
+// The longest string returned by RemovalReasonToString() is 'sizelimit'
+#define MAX_REMOVAL_REASON_LENGTH 9
+#define HASH_LENGTH 32
+
+struct added_event
+{
+ u8 hash[HASH_LENGTH];
+ u64 vsize;
+ s64 fee;
+};
+
+struct removed_event
+{
+ u8 hash[HASH_LENGTH];
+ char reason[MAX_REMOVAL_REASON_LENGTH];
+ u64 vsize;
+ s64 fee;
+ u64 entry_time;
+};
+
+struct rejected_event
+{
+ u8 hash[HASH_LENGTH];
+ char reason[MAX_REJECT_REASON_LENGTH];
+};
+
+struct replaced_event
+{
+ u8 replaced_hash[HASH_LENGTH];
+ u64 replaced_vsize;
+ s64 replaced_fee;
+ u64 replaced_entry_time;
+ u8 replacement_hash[HASH_LENGTH];
+ u64 replacement_vsize;
+ s64 replacement_fee;
+};
+
+// BPF perf buffer to push the data to user space.
+BPF_PERF_OUTPUT(added_events);
+BPF_PERF_OUTPUT(removed_events);
+BPF_PERF_OUTPUT(rejected_events);
+BPF_PERF_OUTPUT(replaced_events);
+
+int trace_added(struct pt_regs *ctx) {
+ struct added_event added = {};
+
+ bpf_usdt_readarg_p(1, ctx, &added.hash, HASH_LENGTH);
+ bpf_usdt_readarg(2, ctx, &added.vsize);
+ bpf_usdt_readarg(3, ctx, &added.fee);
+
+ added_events.perf_submit(ctx, &added, sizeof(added));
+ return 0;
+}
+
+int trace_removed(struct pt_regs *ctx) {
+ struct removed_event removed = {};
+
+ bpf_usdt_readarg_p(1, ctx, &removed.hash, HASH_LENGTH);
+ bpf_usdt_readarg_p(2, ctx, &removed.reason, MAX_REMOVAL_REASON_LENGTH);
+ bpf_usdt_readarg(3, ctx, &removed.vsize);
+ bpf_usdt_readarg(4, ctx, &removed.fee);
+ bpf_usdt_readarg(5, ctx, &removed.entry_time);
+
+ removed_events.perf_submit(ctx, &removed, sizeof(removed));
+ return 0;
+}
+
+int trace_rejected(struct pt_regs *ctx) {
+ struct rejected_event rejected = {};
+
+ bpf_usdt_readarg_p(1, ctx, &rejected.hash, HASH_LENGTH);
+ bpf_usdt_readarg_p(2, ctx, &rejected.reason, MAX_REJECT_REASON_LENGTH);
+
+ rejected_events.perf_submit(ctx, &rejected, sizeof(rejected));
+ return 0;
+}
+
+int trace_replaced(struct pt_regs *ctx) {
+ struct replaced_event replaced = {};
+
+ bpf_usdt_readarg_p(1, ctx, &replaced.replaced_hash, HASH_LENGTH);
+ bpf_usdt_readarg(2, ctx, &replaced.replaced_vsize);
+ bpf_usdt_readarg(3, ctx, &replaced.replaced_fee);
+ bpf_usdt_readarg(4, ctx, &replaced.replaced_entry_time);
+ bpf_usdt_readarg_p(5, ctx, &replaced.replacement_hash, HASH_LENGTH);
+ bpf_usdt_readarg(6, ctx, &replaced.replacement_vsize);
+ bpf_usdt_readarg(7, ctx, &replaced.replacement_fee);
+
+ replaced_events.perf_submit(ctx, &replaced, sizeof(replaced));
+ return 0;
+}
+"""
+
+
+def main(bitcoind_path):
+ bitcoind_with_usdts = USDT(path=str(bitcoind_path))
+
+ # attaching the trace functions defined in the BPF program
+ # to the tracepoints
+ bitcoind_with_usdts.enable_probe(probe="mempool:added", fn_name="trace_added")
+ bitcoind_with_usdts.enable_probe(probe="mempool:removed", fn_name="trace_removed")
+ bitcoind_with_usdts.enable_probe(probe="mempool:replaced", fn_name="trace_replaced")
+ bitcoind_with_usdts.enable_probe(probe="mempool:rejected", fn_name="trace_rejected")
+ bpf = BPF(text=PROGRAM, usdt_contexts=[bitcoind_with_usdts])
+
+ events = []
+
+ def get_timestamp():
+ return datetime.now(timezone.utc)
+
+ def handle_added(_, data, size):
+ event = bpf["added_events"].event(data)
+ events.append((get_timestamp(), "added", event))
+
+ def handle_removed(_, data, size):
+ event = bpf["removed_events"].event(data)
+ events.append((get_timestamp(), "removed", event))
+
+ def handle_rejected(_, data, size):
+ event = bpf["rejected_events"].event(data)
+ events.append((get_timestamp(), "rejected", event))
+
+ def handle_replaced(_, data, size):
+ event = bpf["replaced_events"].event(data)
+ events.append((get_timestamp(), "replaced", event))
+
+ bpf["added_events"].open_perf_buffer(handle_added)
+ # By default, open_perf_buffer uses eight pages for a buffer, making for a total
+ # buffer size of 32k on most machines. In practice, this size is insufficient:
+ # Each `mempool:removed` event takes up 57 bytes in the buffer (32 bytes for txid,
+ # 9 bytes for removal reason, and 8 bytes each for vsize and fee). Full blocks
+ # contain around 2k transactions, requiring a buffer size of around 114kB. To cover
+ # this amount, 32 4k pages are required.
+ bpf["removed_events"].open_perf_buffer(handle_removed, page_cnt=32)
+ bpf["rejected_events"].open_perf_buffer(handle_rejected)
+ bpf["replaced_events"].open_perf_buffer(handle_replaced)
+
+ curses.wrapper(loop, bpf, events)
+
+
+def loop(screen, bpf, events):
+ dashboard = Dashboard(screen)
+ while True:
+ try:
+ bpf.perf_buffer_poll(timeout=50)
+ dashboard.render(events)
+ except KeyboardInterrupt:
+ exit()
+
+
+class Dashboard:
+ """Visualization of mempool state using ncurses."""
+
+ INFO_WIN_HEIGHT = 2
+ EVENT_WIN_HEIGHT = 7
+
+ def __init__(self, screen):
+ screen.nodelay(True)
+ curses.curs_set(False)
+ self._screen = screen
+ self._time_started = datetime.now(timezone.utc)
+ self._timestamps = {"added": [], "removed": [], "rejected": [], "replaced": []}
+ self._event_history = {"added": 0, "removed": 0, "rejected": 0, "replaced": 0}
+ self._init_windows()
+
+ def _init_windows(self):
+ """Initialize all windows."""
+ self._init_info_win()
+ self._init_event_count_win()
+ self._init_event_rate_win()
+ self._init_event_log_win()
+
+ @staticmethod
+ def create_win(x, y, height, width, title=None):
+ """Helper function to create generic windows and decorate them with box and title if requested."""
+ win = curses.newwin(height, width, x, y)
+ if title:
+ win.box()
+ win.addstr(0, 2, title, curses.A_BOLD)
+ return win
+
+ def _init_info_win(self):
+ """Create and populate the info window."""
+ self._info_win = Dashboard.create_win(
+ x=0, y=1, height=Dashboard.INFO_WIN_HEIGHT, width=22
+ )
+ self._info_win.addstr(0, 0, "Mempool Monitor", curses.A_REVERSE)
+ self._info_win.addstr(1, 0, "Press CTRL-C to stop.", curses.A_NORMAL)
+ self._info_win.refresh()
+
+ def _init_event_count_win(self):
+ """Create and populate the event count window."""
+ self._event_count_win = Dashboard.create_win(
+ x=3, y=1, height=Dashboard.EVENT_WIN_HEIGHT, width=37, title="Event count"
+ )
+ header = " {:<8} {:>8} {:>7} {:>7} "
+ self._event_count_win.addstr(
+ 1, 1, header.format("Event", "total", "1 min", "10 min"), curses.A_UNDERLINE
+ )
+ self._event_count_win.refresh()
+
+ def _init_event_rate_win(self):
+ """Create and populate the event rate window."""
+ self._event_rate_win = Dashboard.create_win(
+ x=3, y=40, height=Dashboard.EVENT_WIN_HEIGHT, width=42, title="Event rate"
+ )
+ header = " {:<8} {:>9} {:>9} {:>9} "
+ self._event_rate_win.addstr(
+ 1, 1, header.format("Event", "total", "1 min", "10 min"), curses.A_UNDERLINE
+ )
+ self._event_rate_win.refresh()
+
+ def _init_event_log_win(self):
+ """Create windows showing event log. This comprises a dummy boxed window and an
+ inset window so line breaks don't overwrite box."""
+ # dummy boxed window
+ num_rows, num_cols = self._screen.getmaxyx()
+ space_above = Dashboard.INFO_WIN_HEIGHT + 1 + Dashboard.EVENT_WIN_HEIGHT + 1
+ box_win_height = num_rows - space_above
+ box_win_width = num_cols - 2
+ win_box = Dashboard.create_win(
+ x=space_above,
+ y=1,
+ height=box_win_height,
+ width=box_win_width,
+ title="Event log",
+ )
+ # actual logging window
+ log_lines = box_win_height - 2 # top and bottom box lines
+ log_line_len = box_win_width - 2 - 1 # box lines and left padding
+ win = win_box.derwin(log_lines, log_line_len, 1, 2)
+ win.idlok(True)
+ win.scrollok(True)
+ win_box.refresh()
+ win.refresh()
+ self._event_log_win_box = win_box
+ self._event_log_win = win
+
+ def calculate_metrics(self, events):
+ """Calculate count and rate metrics."""
+ count, rate = {}, {}
+ for event_ts, event_type, event_data in events:
+ self._timestamps[event_type].append(event_ts)
+ for event_type, ts in self._timestamps.items():
+ # remove timestamps older than ten minutes but keep track of their
+ # count for the 'total' metric
+ #
+ self._event_history[event_type] += len(
+ [t for t in ts if Dashboard.timestamp_age(t) >= 600]
+ )
+ ts = [t for t in ts if Dashboard.timestamp_age(t) < 600]
+ self._timestamps[event_type] = ts
+ # count metric
+ count_1m = len([t for t in ts if Dashboard.timestamp_age(t) < 60])
+ count_10m = len(ts)
+ count_total = self._event_history[event_type] + len(ts)
+ count[event_type] = (count_total, count_1m, count_10m)
+ # rate metric
+ runtime = Dashboard.timestamp_age(self._time_started)
+ rate_1m = count_1m / min(60, runtime)
+ rate_10m = count_10m / min(600, runtime)
+ rate_total = count_total / runtime
+ rate[event_type] = (rate_total, rate_1m, rate_10m)
+ return count, rate
+
+ def _update_event_count(self, count):
+ """Update the event count window."""
+ w = self._event_count_win
+ row_format = " {:<8} {:>6}tx {:>5}tx {:>5}tx "
+ for line, metric in enumerate(["added", "removed", "replaced", "rejected"]):
+ w.addstr(2 + line, 1, row_format.format(metric, *count[metric]))
+ w.refresh()
+
+ def _update_event_rate(self, rate):
+ """Update the event rate window."""
+ w = self._event_rate_win
+ row_format = " {:<8} {:>5.1f}tx/s {:>5.1f}tx/s {:>5.1f}tx/s "
+ for line, metric in enumerate(["added", "removed", "replaced", "rejected"]):
+ w.addstr(2 + line, 1, row_format.format(metric, *rate[metric]))
+ w.refresh()
+
+ def _update_event_log(self, events):
+ """Update the event log window."""
+ w = self._event_log_win
+ for event in events:
+ w.addstr(Dashboard.parse_event(event) + "\n")
+ w.refresh()
+
+ def render(self, events):
+ """Render the dashboard."""
+ count, rate = self.calculate_metrics(events)
+ self._update_event_count(count)
+ self._update_event_rate(rate)
+ self._update_event_log(events)
+ events.clear()
+
+ @staticmethod
+ def parse_event(event):
+ """Converts events into human-readable messages"""
+
+ ts_dt, type_, data = event
+ ts = ts_dt.strftime("%H:%M:%SZ")
+ if type_ == "added":
+ return (
+ f"{ts} added {bytes(data.hash)[::-1].hex()}"
+ f" with feerate {data.fee/data.vsize:.2f} sat/vB"
+ f" ({data.fee} sat, {data.vsize} vbytes)"
+ )
+
+ if type_ == "removed":
+ return (
+ f"{ts} removed {bytes(data.hash)[::-1].hex()}"
+ f" with feerate {data.fee/data.vsize:.2f} sat/vB"
+ f" ({data.fee} sat, {data.vsize} vbytes)"
+ f" received {ts_dt.timestamp()-data.entry_time:.1f} seconds ago"
+ f": {data.reason.decode('UTF-8')}"
+ )
+
+ if type_ == "rejected":
+ return (
+ f"{ts} rejected {bytes(data.hash)[::-1].hex()}"
+ f": {data.reason.decode('UTF-8')}"
+ )
+
+ if type_ == "replaced":
+ return (
+ f"{ts} replaced {bytes(data.replaced_hash)[::-1].hex()}"
+ f" with feerate {data.replaced_fee/data.replaced_vsize:.2f} sat/vB"
+ f" received {ts_dt.timestamp()-data.replaced_entry_time:.1f} seconds ago"
+ f" ({data.replaced_fee} sat, {data.replaced_vsize} vbytes)"
+ f" with {bytes(data.replacement_hash)[::-1].hex()}"
+ f" with feerate {data.replacement_fee/data.replacement_vsize:.2f} sat/vB"
+ f" ({data.replacement_fee} sat, {data.replacement_vsize} vbytes)"
+ )
+
+ raise NotImplementedError("Unsupported event type: {type_}")
+
+ @staticmethod
+ def timestamp_age(timestamp):
+ """Return age of timestamp in seconds."""
+ return (datetime.now(timezone.utc) - timestamp).total_seconds()
+
+
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ print("USAGE: ", sys.argv[0], "path/to/bitcoind")
+ exit(1)
+
+ path = sys.argv[1]
+ main(path)
diff --git a/contrib/valgrind.supp b/contrib/valgrind.supp
index d6856b4274..faba1f6ae6 100644
--- a/contrib/valgrind.supp
+++ b/contrib/valgrind.supp
@@ -13,19 +13,8 @@
#
# Note that suppressions may depend on OS and/or library versions.
# Tested on:
-# * aarch64 (Ubuntu 22.04 system libs, clang, without gui)
-# * x86_64 (Ubuntu 22.04 system libs, clang, without gui)
-{
- Suppress libstdc++ warning - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65434
- Memcheck:Leak
- match-leak-kinds: reachable
- fun:malloc
- obj:*/libstdc++.*
- fun:call_init.part.0
- fun:call_init
- fun:_dl_init
- obj:*/ld-*.so
-}
+# * aarch64 (Debian Bookworm system libs, clang, without gui)
+# * x86_64 (Debian Bookworm system libs, clang, without gui)
{
Suppress libdb warning - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=662917
Memcheck:Cond
@@ -71,12 +60,6 @@
fun:_Z8ShutdownR11NodeContext
}
{
- Ignore GUI warning
- Memcheck:Leak
- ...
- obj:/usr/lib64/libgdk-3.so.0.2404.7
-}
-{
Suppress leveldb leak
Memcheck:Leak
match-leak-kinds: reachable
@@ -99,14 +82,6 @@
fun:_Z11LogInstancev
}
{
- Suppress secp256k1_context_create still reachable memory warning
- Memcheck:Leak
- match-leak-kinds: reachable
- fun:malloc
- ...
- fun:secp256k1_context_create
-}
-{
Suppress BCLog::Logger::StartLogging() still reachable memory warning
Memcheck:Leak
match-leak-kinds: reachable
diff --git a/contrib/verify-binaries/README.md b/contrib/verify-binaries/README.md
new file mode 100644
index 0000000000..c62d760e1a
--- /dev/null
+++ b/contrib/verify-binaries/README.md
@@ -0,0 +1,88 @@
+### Verify Binaries
+
+#### Preparation
+
+As of Bitcoin Core v22.0, releases are signed by a number of public keys on the basis
+of the [guix.sigs repository](https://github.com/bitcoin-core/guix.sigs/). When
+verifying binary downloads, you (the end user) decide which of these public keys you
+trust and then use that trust model to evaluate the signature on a file that contains
+hashes of the release binaries. The downloaded binaries are then hashed and compared to
+the signed checksum file.
+
+First, you have to figure out which public keys to recognize. Browse the [list of frequent
+builder-keys](https://github.com/bitcoin-core/guix.sigs/tree/main/builder-keys) and
+decide which of these keys you would like to trust. For each key you want to trust, you
+must obtain that key for your local GPG installation.
+
+You can obtain these keys by
+ - through a browser using a key server (e.g. keyserver.ubuntu.com),
+ - manually using the `gpg --keyserver <url> --recv-keys <key>` command, or
+ - you can run the packaged `verify.py ... --import-keys` script to
+ have it automatically retrieve unrecognized keys.
+
+#### Usage
+
+This script attempts to download the checksum file (`SHA256SUMS`) and corresponding
+signature file `SHA256SUMS.asc` from https://bitcoincore.org and https://bitcoin.org.
+
+It first checks if the checksum file is valid based upon a plurality of signatures, and
+then downloads the release files specified in the checksum file, and checks if the
+hashes of the release files are as expected.
+
+If we encounter pubkeys in the signature file that we do not recognize, the script
+can prompt the user as to whether they'd like to download the pubkeys. To enable
+this behavior, use the `--import-keys` flag.
+
+The script returns 0 if everything passes the checks. It returns 1 if either the
+signature check or the hash check doesn't pass. An exit code of >2 indicates an error.
+
+See the `Config` object for various options.
+
+#### Examples
+
+Validate releases with default settings:
+```sh
+./contrib/verify-binaries/verify.py pub 22.0
+./contrib/verify-binaries/verify.py pub 22.0-rc3
+```
+
+Get JSON output and don't prompt for user input (no auto key import):
+
+```sh
+./contrib/verify-binaries/verify.py --json pub 22.0-x86
+```
+
+Rely only on local GPG state and manually specified keys, while requiring a
+threshold of at least 10 trusted signatures:
+```sh
+./contrib/verify-binaries/verify.py \
+ --trusted-keys 74E2DEF5D77260B98BC19438099BAD163C70FBFA,9D3CC86A72F8494342EA5FD10A41BDC3F4FAFF1C \
+ --min-good-sigs 10 pub 22.0-x86
+```
+
+If you only want to download the binaries for a certain platform, add the corresponding suffix, e.g.:
+
+```sh
+./contrib/verify-binaries/verify.py pub 24.0.1-darwin
+./contrib/verify-binaries/verify.py pub 23.1-rc1-win64
+```
+
+If you do not want to keep the downloaded binaries, specify the cleanup option.
+
+```sh
+./contrib/verify-binaries/verify.py pub --cleanup 22.0
+```
+
+Use the bin subcommand to verify all files listed in a local checksum file
+
+```sh
+./contrib/verify-binaries/verify.py bin SHA256SUMS
+```
+
+Verify only a subset of the files listed in a local checksum file
+
+```sh
+./contrib/verify-binaries/verify.py bin ~/Downloads/SHA256SUMS \
+ ~/Downloads/bitcoin-24.0.1-x86_64-linux-gnu.tar.gz \
+ ~/Downloads/bitcoin-24.0.1-arm-linux-gnueabihf.tar.gz
+```
diff --git a/contrib/verify-binaries/test.py b/contrib/verify-binaries/test.py
new file mode 100755
index 0000000000..22d718ece3
--- /dev/null
+++ b/contrib/verify-binaries/test.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+
+import json
+import sys
+import subprocess
+from pathlib import Path
+
+
+def main():
+ """Tests ordered roughly from faster to slower."""
+ expect_code(run_verify("", "pub", '0.32'), 4, "Nonexistent version should fail")
+ expect_code(run_verify("", "pub", '0.32.awefa.12f9h'), 11, "Malformed version should fail")
+ expect_code(run_verify('--min-good-sigs 20', "pub", "22.0"), 9, "--min-good-sigs 20 should fail")
+
+ print("- testing verification (22.0)", flush=True)
+ _220 = run_verify("--json", "pub", "22.0")
+ try:
+ result = json.loads(_220.stdout.decode())
+ except Exception:
+ print("failed on 22.0 --json:")
+ print_process_failure(_220)
+ raise
+
+ expect_code(_220, 0, "22.0 should succeed")
+ v = result['verified_binaries']
+ assert result['good_trusted_sigs']
+ assert v['bitcoin-22.0-aarch64-linux-gnu.tar.gz'] == 'ac718fed08570a81b3587587872ad85a25173afa5f9fbbd0c03ba4d1714cfa3e'
+ assert v['bitcoin-22.0-osx64.tar.gz'] == '2744d199c3343b2d94faffdfb2c94d75a630ba27301a70e47b0ad30a7e0155e9'
+ assert v['bitcoin-22.0-x86_64-linux-gnu.tar.gz'] == '59ebd25dd82a51638b7a6bb914586201e67db67b919b2a1ff08925a7936d1b16'
+
+
+def run_verify(global_args: str, command: str, command_args: str) -> subprocess.CompletedProcess:
+ maybe_here = Path.cwd() / 'verify.py'
+ path = maybe_here if maybe_here.exists() else Path.cwd() / 'contrib' / 'verify-binaries' / 'verify.py'
+
+ if command == "pub":
+ command += " --cleanup"
+
+ return subprocess.run(
+ f"{path} {global_args} {command} {command_args}",
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+
+
+def expect_code(completed: subprocess.CompletedProcess, expected_code: int, msg: str):
+ if completed.returncode != expected_code:
+ print(f"{msg!r} failed: got code {completed.returncode}, expected {expected_code}")
+ print_process_failure(completed)
+ sys.exit(1)
+ else:
+ print(f"✓ {msg!r} passed")
+
+
+def print_process_failure(completed: subprocess.CompletedProcess):
+ print(f"stdout:\n{completed.stdout.decode()}")
+ print(f"stderr:\n{completed.stderr.decode()}")
+
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/verify-binaries/verify.py b/contrib/verify-binaries/verify.py
new file mode 100755
index 0000000000..d0749f503f
--- /dev/null
+++ b/contrib/verify-binaries/verify.py
@@ -0,0 +1,713 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Script for verifying Bitcoin Core release binaries.
+
+This script attempts to download the sum file SHA256SUMS and corresponding
+signature file SHA256SUMS.asc from bitcoincore.org and bitcoin.org and
+compares them.
+
+The sum-signature file is signed by a number of builder keys. This script
+ensures that there is a minimum threshold of signatures from pubkeys that
+we trust. This trust is articulated on the basis of configuration options
+here, but by default is based upon local GPG trust settings.
+
+The builder keys are available in the guix.sigs repo:
+
+ https://github.com/bitcoin-core/guix.sigs/tree/main/builder-keys
+
+If a minimum good, trusted signature threshold is met on the sum file, we then
+download the files specified in SHA256SUMS, and check if the hashes of these
+files match those that are specified. The script returns 0 if everything passes
+the checks. It returns 1 if either the signature check or the hash check
+doesn't pass. If an error occurs the return value is >= 2.
+
+Logging output goes to stderr and final binary verification data goes to stdout.
+
+JSON output can by obtained by setting env BINVERIFY_JSON=1.
+"""
+import argparse
+import difflib
+import json
+import logging
+import os
+import subprocess
+import typing as t
+import re
+import sys
+import shutil
+import tempfile
+import textwrap
+import urllib.request
+import urllib.error
+import enum
+from hashlib import sha256
+from pathlib import PurePath, Path
+
+# The primary host; this will fail if we can't retrieve files from here.
+HOST1 = "https://bitcoincore.org"
+HOST2 = "https://bitcoin.org"
+VERSIONPREFIX = "bitcoin-core-"
+SUMS_FILENAME = 'SHA256SUMS'
+SIGNATUREFILENAME = f"{SUMS_FILENAME}.asc"
+
+
+class ReturnCode(enum.IntEnum):
+ SUCCESS = 0
+ INTEGRITY_FAILURE = 1
+ FILE_GET_FAILED = 4
+ FILE_MISSING_FROM_ONE_HOST = 5
+ FILES_NOT_EQUAL = 6
+ NO_BINARIES_MATCH = 7
+ NOT_ENOUGH_GOOD_SIGS = 9
+ BINARY_DOWNLOAD_FAILED = 10
+ BAD_VERSION = 11
+
+
+def set_up_logger(is_verbose: bool = True) -> logging.Logger:
+ """Set up a logger that writes to stderr."""
+ log = logging.getLogger(__name__)
+ log.setLevel(logging.INFO if is_verbose else logging.WARNING)
+ console = logging.StreamHandler(sys.stderr) # log to stderr
+ console.setLevel(logging.DEBUG)
+ formatter = logging.Formatter('[%(levelname)s] %(message)s')
+ console.setFormatter(formatter)
+ log.addHandler(console)
+ return log
+
+
+log = set_up_logger()
+
+
+def indent(output: str) -> str:
+ return textwrap.indent(output, ' ')
+
+
+def bool_from_env(key, default=False) -> bool:
+ if key not in os.environ:
+ return default
+ raw = os.environ[key]
+
+ if raw.lower() in ('1', 'true'):
+ return True
+ elif raw.lower() in ('0', 'false'):
+ return False
+ raise ValueError(f"Unrecognized environment value {key}={raw!r}")
+
+
+VERSION_FORMAT = "<major>.<minor>[.<patch>][-rc[0-9]][-platform]"
+VERSION_EXAMPLE = "22.0-x86_64 or 23.1-rc1-darwin"
+
+def parse_version_string(version_str):
+ parts = version_str.split('-')
+ version_base = parts[0]
+ version_rc = ""
+ version_os = ""
+ if len(parts) == 2: # "<version>-rcN" or "version-platform"
+ if "rc" in parts[1]:
+ version_rc = parts[1]
+ else:
+ version_os = parts[1]
+ elif len(parts) == 3: # "<version>-rcN-platform"
+ version_rc = parts[1]
+ version_os = parts[2]
+
+ return version_base, version_rc, version_os
+
+
+def download_with_wget(remote_file, local_file):
+ result = subprocess.run(['wget', '-O', local_file, remote_file],
+ stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+ return result.returncode == 0, result.stdout.decode().rstrip()
+
+
+def download_lines_with_urllib(url) -> t.Tuple[bool, t.List[str]]:
+ """Get (success, text lines of a file) over HTTP."""
+ try:
+ return (True, [
+ line.strip().decode() for line in urllib.request.urlopen(url).readlines()])
+ except urllib.error.HTTPError as e:
+ log.warning(f"HTTP request to {url} failed (HTTPError): {e}")
+ except Exception as e:
+ log.warning(f"HTTP request to {url} failed ({e})")
+ return (False, [])
+
+
+def verify_with_gpg(
+ filename,
+ signature_filename,
+ output_filename: t.Optional[str] = None
+) -> t.Tuple[int, str]:
+ with tempfile.NamedTemporaryFile() as status_file:
+ args = [
+ 'gpg', '--yes', '--verify', '--verify-options', 'show-primary-uid-only', "--status-file", status_file.name,
+ '--output', output_filename if output_filename else '', signature_filename, filename]
+
+ env = dict(os.environ, LANGUAGE='en')
+ result = subprocess.run(args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, env=env)
+
+ gpg_data = status_file.read().decode().rstrip()
+
+ log.debug(f'Result from GPG ({result.returncode}): {result.stdout.decode()}')
+ log.debug(f"{gpg_data}")
+ return result.returncode, gpg_data
+
+
+def remove_files(filenames):
+ for filename in filenames:
+ os.remove(filename)
+
+
+class SigData:
+ """GPG signature data as parsed from GPG stdout."""
+ def __init__(self):
+ self.key = None
+ self.name = ""
+ self.trusted = False
+ self.status = ""
+
+ def __bool__(self):
+ return self.key is not None
+
+ def __repr__(self):
+ return (
+ "SigData(%r, %r, trusted=%s, status=%r)" %
+ (self.key, self.name, self.trusted, self.status))
+
+
+def parse_gpg_result(
+ output: t.List[str]
+) -> t.Tuple[t.List[SigData], t.List[SigData], t.List[SigData]]:
+ """Returns good, unknown, and bad signatures from GPG stdout."""
+ good_sigs: t.List[SigData] = []
+ unknown_sigs: t.List[SigData] = []
+ bad_sigs: t.List[SigData] = []
+ total_resolved_sigs = 0
+
+ # Ensure that all lines we match on include a prefix that prevents malicious input
+ # from fooling the parser.
+ def line_begins_with(patt: str, line: str) -> t.Optional[re.Match]:
+ return re.match(r'^(\[GNUPG:\])\s+' + patt, line)
+
+ curr_sigs = unknown_sigs
+ curr_sigdata = SigData()
+
+ for line in output:
+ if line_begins_with(r"NEWSIG(?:\s|$)", line):
+ total_resolved_sigs += 1
+ if curr_sigdata:
+ curr_sigs.append(curr_sigdata)
+ curr_sigdata = SigData()
+ newsig_split = line.split()
+ if len(newsig_split) == 3:
+ curr_sigdata.name = newsig_split[2]
+
+ elif line_begins_with(r"GOODSIG(?:\s|$)", line):
+ curr_sigdata.key, curr_sigdata.name = line.split(maxsplit=3)[2:4]
+ curr_sigs = good_sigs
+
+ elif line_begins_with(r"EXPKEYSIG(?:\s|$)", line):
+ curr_sigdata.key, curr_sigdata.name = line.split(maxsplit=3)[2:4]
+ curr_sigs = good_sigs
+ curr_sigdata.status = "expired"
+
+ elif line_begins_with(r"REVKEYSIG(?:\s|$)", line):
+ curr_sigdata.key, curr_sigdata.name = line.split(maxsplit=3)[2:4]
+ curr_sigs = good_sigs
+ curr_sigdata.status = "revoked"
+
+ elif line_begins_with(r"BADSIG(?:\s|$)", line):
+ curr_sigdata.key, curr_sigdata.name = line.split(maxsplit=3)[2:4]
+ curr_sigs = bad_sigs
+
+ elif line_begins_with(r"ERRSIG(?:\s|$)", line):
+ curr_sigdata.key, _, _, _, _, _ = line.split()[2:8]
+ curr_sigs = unknown_sigs
+
+ elif line_begins_with(r"TRUST_(UNDEFINED|NEVER)(?:\s|$)", line):
+ curr_sigdata.trusted = False
+
+ elif line_begins_with(r"TRUST_(MARGINAL|FULLY|ULTIMATE)(?:\s|$)", line):
+ curr_sigdata.trusted = True
+
+ # The last one won't have been added, so add it now
+ assert curr_sigdata
+ curr_sigs.append(curr_sigdata)
+
+ all_found = len(good_sigs + bad_sigs + unknown_sigs)
+ if all_found != total_resolved_sigs:
+ raise RuntimeError(
+ f"failed to evaluate all signatures: found {all_found} "
+ f"but expected {total_resolved_sigs}")
+
+ return (good_sigs, unknown_sigs, bad_sigs)
+
+
+def files_are_equal(filename1, filename2):
+ with open(filename1, 'rb') as file1:
+ contents1 = file1.read()
+ with open(filename2, 'rb') as file2:
+ contents2 = file2.read()
+ eq = contents1 == contents2
+
+ if not eq:
+ with open(filename1, 'r', encoding='utf-8') as f1, \
+ open(filename2, 'r', encoding='utf-8') as f2:
+ f1lines = f1.readlines()
+ f2lines = f2.readlines()
+
+ diff = indent(
+ ''.join(difflib.unified_diff(f1lines, f2lines)))
+ log.warning(f"found diff in files ({filename1}, {filename2}):\n{diff}\n")
+
+ return eq
+
+
+def get_files_from_hosts_and_compare(
+ hosts: t.List[str], path: str, filename: str, require_all: bool = False
+) -> ReturnCode:
+ """
+ Retrieve the same file from a number of hosts and ensure they have the same contents.
+ The first host given will be treated as the "primary" host, and is required to succeed.
+
+ Args:
+ filename: for writing the file locally.
+ """
+ assert len(hosts) > 1
+ primary_host = hosts[0]
+ other_hosts = hosts[1:]
+ got_files = []
+
+ def join_url(host: str) -> str:
+ return host.rstrip('/') + '/' + path.lstrip('/')
+
+ url = join_url(primary_host)
+ success, output = download_with_wget(url, filename)
+ if not success:
+ log.error(
+ f"couldn't fetch file ({url}). "
+ "Have you specified the version number in the following format?\n"
+ f"{VERSION_FORMAT} "
+ f"(example: {VERSION_EXAMPLE})\n"
+ f"wget output:\n{indent(output)}")
+ return ReturnCode.FILE_GET_FAILED
+ else:
+ log.info(f"got file {url} as {filename}")
+ got_files.append(filename)
+
+ for i, host in enumerate(other_hosts):
+ url = join_url(host)
+ fname = filename + f'.{i + 2}'
+ success, output = download_with_wget(url, fname)
+
+ if require_all and not success:
+ log.error(
+ f"{host} failed to provide file ({url}), but {primary_host} did?\n"
+ f"wget output:\n{indent(output)}")
+ return ReturnCode.FILE_MISSING_FROM_ONE_HOST
+ elif not success:
+ log.warning(
+ f"{host} failed to provide file ({url}). "
+ f"Continuing based solely upon {primary_host}.")
+ else:
+ log.info(f"got file {url} as {fname}")
+ got_files.append(fname)
+
+ for i, got_file in enumerate(got_files):
+ if got_file == got_files[-1]:
+ break # break on last file, nothing after it to compare to
+
+ compare_to = got_files[i + 1]
+ if not files_are_equal(got_file, compare_to):
+ log.error(f"files not equal: {got_file} and {compare_to}")
+ return ReturnCode.FILES_NOT_EQUAL
+
+ return ReturnCode.SUCCESS
+
+
+def check_multisig(sums_file: str, sigfilename: str, args: argparse.Namespace) -> t.Tuple[int, str, t.List[SigData], t.List[SigData], t.List[SigData]]:
+ # check signature
+ #
+ # We don't write output to a file because this command will almost certainly
+ # fail with GPG exit code '2' (and so not writing to --output) because of the
+ # likely presence of multiple untrusted signatures.
+ retval, output = verify_with_gpg(sums_file, sigfilename)
+
+ if args.verbose:
+ log.info(f"gpg output:\n{indent(output)}")
+
+ good, unknown, bad = parse_gpg_result(output.splitlines())
+
+ if unknown and args.import_keys:
+ # Retrieve unknown keys and then try GPG again.
+ for unsig in unknown:
+ if prompt_yn(f" ? Retrieve key {unsig.key} ({unsig.name})? (y/N) "):
+ ran = subprocess.run(
+ ["gpg", "--keyserver", args.keyserver, "--recv-keys", unsig.key])
+
+ if ran.returncode != 0:
+ log.warning(f"failed to retrieve key {unsig.key}")
+
+ # Reparse the GPG output now that we have more keys
+ retval, output = verify_with_gpg(sums_file, sigfilename)
+ good, unknown, bad = parse_gpg_result(output.splitlines())
+
+ return retval, output, good, unknown, bad
+
+
+def prompt_yn(prompt) -> bool:
+ """Return true if the user inputs 'y'."""
+ got = ''
+ while got not in ['y', 'n']:
+ got = input(prompt).lower()
+ return got == 'y'
+
+def verify_shasums_signature(
+ signature_file_path: str, sums_file_path: str, args: argparse.Namespace
+) -> t.Tuple[
+ ReturnCode, t.List[SigData], t.List[SigData], t.List[SigData], t.List[SigData]
+]:
+ min_good_sigs = args.min_good_sigs
+ gpg_allowed_codes = [0, 2] # 2 is returned when untrusted signatures are present.
+
+ gpg_retval, gpg_output, good, unknown, bad = check_multisig(sums_file_path, signature_file_path, args)
+
+ if gpg_retval not in gpg_allowed_codes:
+ if gpg_retval == 1:
+ log.critical(f"Bad signature (code: {gpg_retval}).")
+ else:
+ log.critical(f"unexpected GPG exit code ({gpg_retval})")
+
+ log.error(f"gpg output:\n{indent(gpg_output)}")
+ return (ReturnCode.INTEGRITY_FAILURE, [], [], [], [])
+
+ # Decide which keys we trust, though not "trust" in the GPG sense, but rather
+ # which pubkeys convince us that this sums file is legitimate. In other words,
+ # which pubkeys within the Bitcoin community do we trust for the purposes of
+ # binary verification?
+ trusted_keys = set()
+ if args.trusted_keys:
+ trusted_keys |= set(args.trusted_keys.split(','))
+
+ # Tally signatures and make sure we have enough goods to fulfill
+ # our threshold.
+ good_trusted = [sig for sig in good if sig.trusted or sig.key in trusted_keys]
+ good_untrusted = [sig for sig in good if sig not in good_trusted]
+ num_trusted = len(good_trusted) + len(good_untrusted)
+ log.info(f"got {num_trusted} good signatures")
+
+ if num_trusted < min_good_sigs:
+ log.info("Maybe you need to import "
+ f"(`gpg --keyserver {args.keyserver} --recv-keys <key-id>`) "
+ "some of the following keys: ")
+ log.info('')
+ for sig in unknown:
+ log.info(f" {sig.key} ({sig.name})")
+ log.info('')
+ log.error(
+ "not enough trusted sigs to meet threshold "
+ f"({num_trusted} vs. {min_good_sigs})")
+
+ return (ReturnCode.NOT_ENOUGH_GOOD_SIGS, [], [], [], [])
+
+ for sig in good_trusted:
+ log.info(f"GOOD SIGNATURE: {sig}")
+
+ for sig in good_untrusted:
+ log.info(f"GOOD SIGNATURE (untrusted): {sig}")
+
+ for sig in [sig for sig in good if sig.status == 'expired']:
+ log.warning(f"key {sig.key} for {sig.name} is expired")
+
+ for sig in bad:
+ log.warning(f"BAD SIGNATURE: {sig}")
+
+ for sig in unknown:
+ log.warning(f"UNKNOWN SIGNATURE: {sig}")
+
+ return (ReturnCode.SUCCESS, good_trusted, good_untrusted, unknown, bad)
+
+
+def parse_sums_file(sums_file_path: str, filename_filter: t.List[str]) -> t.List[t.List[str]]:
+ # extract hashes/filenames of binaries to verify from hash file;
+ # each line has the following format: "<hash> <binary_filename>"
+ with open(sums_file_path, 'r', encoding='utf8') as hash_file:
+ return [line.split()[:2] for line in hash_file if len(filename_filter) == 0 or any(f in line for f in filename_filter)]
+
+
+def verify_binary_hashes(hashes_to_verify: t.List[t.List[str]]) -> t.Tuple[ReturnCode, t.Dict[str, str]]:
+ offending_files = []
+ files_to_hashes = {}
+
+ for hash_expected, binary_filename in hashes_to_verify:
+ with open(binary_filename, 'rb') as binary_file:
+ hash_calculated = sha256(binary_file.read()).hexdigest()
+ if hash_calculated != hash_expected:
+ offending_files.append(binary_filename)
+ else:
+ files_to_hashes[binary_filename] = hash_calculated
+
+ if offending_files:
+ joined_files = '\n'.join(offending_files)
+ log.critical(
+ "Hashes don't match.\n"
+ f"Offending files:\n{joined_files}")
+ return (ReturnCode.INTEGRITY_FAILURE, files_to_hashes)
+
+ return (ReturnCode.SUCCESS, files_to_hashes)
+
+
+def verify_published_handler(args: argparse.Namespace) -> ReturnCode:
+ WORKINGDIR = Path(tempfile.gettempdir()) / f"bitcoin_verify_binaries.{args.version}"
+
+ def cleanup():
+ log.info("cleaning up files")
+ os.chdir(Path.home())
+ shutil.rmtree(WORKINGDIR)
+
+ # determine remote dir dependent on provided version string
+ try:
+ version_base, version_rc, os_filter = parse_version_string(args.version)
+ version_tuple = [int(i) for i in version_base.split('.')]
+ except Exception as e:
+ log.debug(e)
+ log.error(f"unable to parse version; expected format is {VERSION_FORMAT}")
+ log.error(f" e.g. {VERSION_EXAMPLE}")
+ return ReturnCode.BAD_VERSION
+
+ remote_dir = f"/bin/{VERSIONPREFIX}{version_base}/"
+ if version_rc:
+ remote_dir += f"test.{version_rc}/"
+ remote_sigs_path = remote_dir + SIGNATUREFILENAME
+ remote_sums_path = remote_dir + SUMS_FILENAME
+
+ # create working directory
+ os.makedirs(WORKINGDIR, exist_ok=True)
+ os.chdir(WORKINGDIR)
+
+ hosts = [HOST1, HOST2]
+
+ got_sig_status = get_files_from_hosts_and_compare(
+ hosts, remote_sigs_path, SIGNATUREFILENAME, args.require_all_hosts)
+ if got_sig_status != ReturnCode.SUCCESS:
+ return got_sig_status
+
+ # Multi-sig verification is available after 22.0.
+ if version_tuple[0] < 22:
+ log.error("Version too old - single sig not supported. Use a previous "
+ "version of this script from the repo.")
+ return ReturnCode.BAD_VERSION
+
+ got_sums_status = get_files_from_hosts_and_compare(
+ hosts, remote_sums_path, SUMS_FILENAME, args.require_all_hosts)
+ if got_sums_status != ReturnCode.SUCCESS:
+ return got_sums_status
+
+ # Verify the signature on the SHA256SUMS file
+ sigs_status, good_trusted, good_untrusted, unknown, bad = verify_shasums_signature(SIGNATUREFILENAME, SUMS_FILENAME, args)
+ if sigs_status != ReturnCode.SUCCESS:
+ if sigs_status == ReturnCode.INTEGRITY_FAILURE:
+ cleanup()
+ return sigs_status
+
+ # Extract hashes and filenames
+ hashes_to_verify = parse_sums_file(SUMS_FILENAME, [os_filter])
+ if not hashes_to_verify:
+ log.error("no files matched the platform specified")
+ return ReturnCode.NO_BINARIES_MATCH
+
+ # remove binaries that are known not to be hosted by bitcoincore.org
+ fragments_to_remove = ['-unsigned', '-debug', '-codesignatures']
+ for fragment in fragments_to_remove:
+ nobinaries = [i for i in hashes_to_verify if fragment in i[1]]
+ if nobinaries:
+ remove_str = ', '.join(i[1] for i in nobinaries)
+ log.info(
+ f"removing *{fragment} binaries ({remove_str}) from verification "
+ f"since {HOST1} does not host *{fragment} binaries")
+ hashes_to_verify = [i for i in hashes_to_verify if fragment not in i[1]]
+
+ # download binaries
+ for _, binary_filename in hashes_to_verify:
+ log.info(f"downloading {binary_filename} to {WORKINGDIR}")
+ success, output = download_with_wget(
+ HOST1 + remote_dir + binary_filename, binary_filename)
+
+ if not success:
+ log.error(
+ f"failed to download {binary_filename}\n"
+ f"wget output:\n{indent(output)}")
+ return ReturnCode.BINARY_DOWNLOAD_FAILED
+
+ # verify hashes
+ hashes_status, files_to_hashes = verify_binary_hashes(hashes_to_verify)
+ if hashes_status != ReturnCode.SUCCESS:
+ return hashes_status
+
+
+ if args.cleanup:
+ cleanup()
+ else:
+ log.info(f"did not clean up {WORKINGDIR}")
+
+ if args.json:
+ output = {
+ 'good_trusted_sigs': [str(s) for s in good_trusted],
+ 'good_untrusted_sigs': [str(s) for s in good_untrusted],
+ 'unknown_sigs': [str(s) for s in unknown],
+ 'bad_sigs': [str(s) for s in bad],
+ 'verified_binaries': files_to_hashes,
+ }
+ print(json.dumps(output, indent=2))
+ else:
+ for filename in files_to_hashes:
+ print(f"VERIFIED: {filename}")
+
+ return ReturnCode.SUCCESS
+
+
+def verify_binaries_handler(args: argparse.Namespace) -> ReturnCode:
+ binary_to_basename = {}
+ for file in args.binary:
+ binary_to_basename[PurePath(file).name] = file
+
+ sums_sig_path = None
+ if args.sums_sig_file:
+ sums_sig_path = Path(args.sums_sig_file)
+ else:
+ log.info(f"No signature file specified, assuming it is {args.sums_file}.asc")
+ sums_sig_path = Path(args.sums_file).with_suffix(".asc")
+
+ # Verify the signature on the SHA256SUMS file
+ sigs_status, good_trusted, good_untrusted, unknown, bad = verify_shasums_signature(str(sums_sig_path), args.sums_file, args)
+ if sigs_status != ReturnCode.SUCCESS:
+ return sigs_status
+
+ # Extract hashes and filenames
+ hashes_to_verify = parse_sums_file(args.sums_file, [k for k, n in binary_to_basename.items()])
+ if not hashes_to_verify:
+ log.error(f"No files in {args.sums_file} match the specified binaries")
+ return ReturnCode.NO_BINARIES_MATCH
+
+ # Make sure all files are accounted for
+ sums_file_path = Path(args.sums_file)
+ missing_files = []
+ files_to_hash = []
+ if len(binary_to_basename) > 0:
+ for file_hash, file in hashes_to_verify:
+ files_to_hash.append([file_hash, binary_to_basename[file]])
+ del binary_to_basename[file]
+ if len(binary_to_basename) > 0:
+ log.error(f"Not all specified binaries are in {args.sums_file}")
+ return ReturnCode.NO_BINARIES_MATCH
+ else:
+ log.info(f"No binaries specified, assuming all files specified in {args.sums_file} are located relatively")
+ for file_hash, file in hashes_to_verify:
+ file_path = Path(sums_file_path.parent.joinpath(file))
+ if file_path.exists():
+ files_to_hash.append([file_hash, str(file_path)])
+ else:
+ missing_files.append(file)
+
+ # verify hashes
+ hashes_status, files_to_hashes = verify_binary_hashes(files_to_hash)
+ if hashes_status != ReturnCode.SUCCESS:
+ return hashes_status
+
+ if args.json:
+ output = {
+ 'good_trusted_sigs': [str(s) for s in good_trusted],
+ 'good_untrusted_sigs': [str(s) for s in good_untrusted],
+ 'unknown_sigs': [str(s) for s in unknown],
+ 'bad_sigs': [str(s) for s in bad],
+ 'verified_binaries': files_to_hashes,
+ "missing_binaries": missing_files,
+ }
+ print(json.dumps(output, indent=2))
+ else:
+ for filename in files_to_hashes:
+ print(f"VERIFIED: {filename}")
+ for filename in missing_files:
+ print(f"MISSING: {filename}")
+
+ return ReturnCode.SUCCESS
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ '-v', '--verbose', action='store_true',
+ default=bool_from_env('BINVERIFY_VERBOSE'),
+ )
+ parser.add_argument(
+ '-q', '--quiet', action='store_true',
+ default=bool_from_env('BINVERIFY_QUIET'),
+ )
+ parser.add_argument(
+ '--import-keys', action='store_true',
+ default=bool_from_env('BINVERIFY_IMPORTKEYS'),
+ help='if specified, ask to import each unknown builder key'
+ )
+ parser.add_argument(
+ '--min-good-sigs', type=int, action='store', nargs='?',
+ default=int(os.environ.get('BINVERIFY_MIN_GOOD_SIGS', 3)),
+ help=(
+ 'The minimum number of good signatures to require successful termination.'),
+ )
+ parser.add_argument(
+ '--keyserver', action='store', nargs='?',
+ default=os.environ.get('BINVERIFY_KEYSERVER', 'hkps://keys.openpgp.org'),
+ help='which keyserver to use',
+ )
+ parser.add_argument(
+ '--trusted-keys', action='store', nargs='?',
+ default=os.environ.get('BINVERIFY_TRUSTED_KEYS', ''),
+ help='A list of trusted signer GPG keys, separated by commas. Not "trusted keys" in the GPG sense.',
+ )
+ parser.add_argument(
+ '--json', action='store_true',
+ default=bool_from_env('BINVERIFY_JSON'),
+ help='If set, output the result as JSON',
+ )
+
+ subparsers = parser.add_subparsers(title="Commands", required=True, dest="command")
+
+ pub_parser = subparsers.add_parser("pub", help="Verify a published release.")
+ pub_parser.set_defaults(func=verify_published_handler)
+ pub_parser.add_argument(
+ 'version', type=str, help=(
+ f'version of the bitcoin release to download; of the format '
+ f'{VERSION_FORMAT}. Example: {VERSION_EXAMPLE}')
+ )
+ pub_parser.add_argument(
+ '--cleanup', action='store_true',
+ default=bool_from_env('BINVERIFY_CLEANUP'),
+ help='if specified, clean up files afterwards'
+ )
+ pub_parser.add_argument(
+ '--require-all-hosts', action='store_true',
+ default=bool_from_env('BINVERIFY_REQUIRE_ALL_HOSTS'),
+ help=(
+ f'If set, require all hosts ({HOST1}, {HOST2}) to provide signatures. '
+ '(Sometimes bitcoin.org lags behind bitcoincore.org.)')
+ )
+
+ bin_parser = subparsers.add_parser("bin", help="Verify local binaries.")
+ bin_parser.set_defaults(func=verify_binaries_handler)
+ bin_parser.add_argument("--sums-sig-file", "-s", help="Path to the SHA256SUMS.asc file to verify")
+ bin_parser.add_argument("sums_file", help="Path to the SHA256SUMS file to verify")
+ bin_parser.add_argument(
+ "binary", nargs="*",
+ help="Path to a binary distribution file to verify. Can be specified multiple times for multiple files to verify."
+ )
+
+ args = parser.parse_args()
+ if args.quiet:
+ log.setLevel(logging.WARNING)
+
+ return args.func(args)
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/contrib/verify-commits/README.md b/contrib/verify-commits/README.md
index b8b15280ba..020890c366 100644
--- a/contrib/verify-commits/README.md
+++ b/contrib/verify-commits/README.md
@@ -27,6 +27,10 @@ Note that the above isn't a good UI/UX yet, and needs significant improvements
to make it more convenient and reduce the chance of errors; pull-reqs
improving this process would be much appreciated.
+Unless `--clean-merge 0` is specified, `verify-commits.py` will attempt to verify that
+each merge commit applies cleanly (with some exceptions). This requires using at least
+git v2.38.0.
+
Configuration files
-------------------
diff --git a/contrib/verify-commits/allow-incorrect-sha512-commits b/contrib/verify-commits/allow-incorrect-sha512-commits
index c572806f26..e69de29bb2 100644
--- a/contrib/verify-commits/allow-incorrect-sha512-commits
+++ b/contrib/verify-commits/allow-incorrect-sha512-commits
@@ -1,2 +0,0 @@
-f8feaa4636260b599294c7285bcf1c8b7737f74e
-8040ae6fc576e9504186f2ae3ff2c8125de1095c
diff --git a/contrib/verify-commits/allow-revsig-commits b/contrib/verify-commits/allow-revsig-commits
index 0bb299b8fa..e69de29bb2 100644
--- a/contrib/verify-commits/allow-revsig-commits
+++ b/contrib/verify-commits/allow-revsig-commits
@@ -1,645 +0,0 @@
-a06ede9a138d0fb86b0de17c42b936d9fe6e2158
-923dc447eaa8e017985b2afbbb12dd1283fbea0e
-71148b8947fe8b4d756822420a7f31c380159425
-6696b4635ceb9b47aaa63244bff9032fa7b08354
-812714fd80e96e28cd288c553c83838cecbfc2d9
-8a445c5651edb9a1f51497055b7ddf4402be9188
-e126d0c12ca66278d9e7b12187c5ff4fc02a7e6c
-3908fc4728059719bed0e1c7b1c8b388c2d4a8da
-8b66bf74e2a349e71eaa183af81fa63eaee76ad2
-05950427d310654774031764a7141a1a4fd9c6e4
-07fd147b9f12e9205afd66a624edce357977d615
-12e31127948fa4bb01c3bddc1b8c85b432f7465b
-8c87f175d335e9d9e93f987d871ae9f05f6a10a7
-46b249e578e8a3dfbe85bc7253a12e82ef4b658b
-a55716abe5662ec74c2f8af93023f1e7cca901fc
-f646275b90b1de93bc62b4c4d045d75ac0b96eee
-c252685aa5867631e9a5ef07ccae7c7c25cae8ff
-a7d55c93385359952d85decd5037843ac70ba3d4
-7dac1e5e9e887f5f6ff146e812a05bd3bf281eae
-2a524b8e8fe69ef487fd8ea1b4f7a03f473ed201
-ce5c1f4acae43477989cdf9a82ed33703919cda2
-2db4cbcc437f51f5dac82cc4de46f383b92e6f11
-7aa700424cbda387536373d8dfec88aee43f950e
-b99a093afed880f23fb279c443cc6ae5e379cc43
-b83264d9c7a8ddb79f64bd9540caddc8632ef31f
-57e337d40e94ba33d8cd265c134d6ef857b32b59
-a1dcf2e1087beaf3981739fd2bb74f35ecad630a
-d38b0d7a6b6056cba26999b702815775e2437d87
-815640ec6af9a38d6a2da4a4400056e2f4105080
-09c4fd157c5b88df2d97fad4826c79b094db90c9
-2efcfa5acfacb958973d9e8125e1d81f102e2dfd
-dc6dee41f7cf2ba93fcd0fea7c157e4b2775d439
-ad826b3df9f763b49f1e3e3d50c4efdd438c7547
-c1a52276848d8caa9a9789dff176408c1aa6b1ed
-3bf06e9bac57b5b5a746677b75e297a7b154bdbd
-72ae6f8cf0224370e8121d6769b21e612ca15d6f
-a143b88dbd4971ecfdd1d39a494489c8f2db0344
-76fec09d878d6dbf214bdb6228d480bd9195db4c
-93566e0c37c5ae104095474fea89f00dcb40f551
-407d9232ef5cb1ebf6cff21f3d13e07ea4158eeb
-9346f8429957e356d21c665bab59fe45bcf1f74e
-6eeac6e30d65f9a972067c1ea8c49978c8e631ac
-dc6b9406bdfab2af8c86cb080cb3e6cf8f2385d8
-9f554e03ebe5701c1b75ff03b3d6152095c0cad3
-05009935f9ac070197113954d680bc2c9150b9b3
-508404de98a8a5435f52916cef8f328e82651961
-ed0cc50afed146c27f6d8129c683c225fb940093
-6429cfa8a70308241c576aeb92ffe3db5203b2ef
-6898213409811b140843c3d89af43328c3b22fad
-5b2ea29cf4fd298346437bb16a54407f8c1f9dca
-e2a1a1ee895149c544d4ae295466611f0cec3094
-e82fb872ff5cc8fd22d43327c1ee3e755f61c562
-19b0f33de0efd9da788e8e4f3fdc2a9e159abdb1
-89de1538ce1f8c00f80e8d11f43e1b77e24d7dea
-de07fdcf77e97b8613091285e4d0a734f5de7492
-01680195f8aa586c55c44767397380def3a23b54
-05e1c85fb687c82ae477c72d4a7e2d6b0c692167
-c072b8fd95cd4fa84f08189a0cd8b173ea2dbb8e
-9a0ed08b40b15ae2b791aa8549b53e69934b4ea7
-53f8f226bd1d627c4a6dec5862a1d4ea5a933e45
-9d0f43b7ca7241d8a018fd35dd3bc01555235ec6
-f12d2b5a8ac397e4bcaefcc19898f8ff5705dea5
-8250de13587ed05ca45df3e12c5dc9bcb1500e2c
-d727f77e390426e9e463336bda08d50c451c7086
-484312bda2d43e3ea60047be076332299463adf8
-c7e05b35ab0a791c7a8e2d863e716fdec6f3f671
-b9c1cd81848da9de1baf9c2f29c19c50e549de13
-8ea7d31e384975019733b5778feabbd9955c79d8
-f798b891bcecea9548eedacae70eeb9906c1ddbf
-ebefe7a00b46579cdd1e033a8c7fd8ce9aa578e4
-ad087638ee4864d6244ec9381ff764bfa6ee5086
-66db2d62d59817320c9182fc18e75a93b76828ea
-7ce9ac5c83b1844a518ef2e12e87aae3cacdfe58
-4286f43025149cf44207c3ad98e4a1f068520ada
-cd0c5135ab2291aaa5410ac919bad3fc87249a4a
-66ed450d771a8fc01c159a8402648ebd1c35eb4c
-a82f03393a32842d49236e8666ee57805ca701f8
-f972b04d63eb8af79ff3cec1dc561ed13dfa6053
-ec45cc5e27668171b55271b0c735194c70e7da41
-715e9fd7454f7a48d7adba7d42f662c20a3e3367
-2e0a99037dcc35bc63ba0d54371bc678af737c8e
-7fa8d758598407f3bf0beb0118dc122ea5340736
-6a22373771edbc3c7513cacb9355f880c73c2cbf
-b89ef131147f71a96152a7b5c4374266cdf539b2
-01d8359983e2f77b5118fede3ffa947072c666c8
-58f0c929a3d70a4bff79cc200f1c186f71ef1675
-950be19727a581970591d8f8138dfe4725750382
-425278d17bd0edf8a3a7cc81e55016f7fd8e7726
-c028c7b7557da2baff7af8840108e8be4db8e0c6
-47a7cfb0aa2498f6801026d258a59f9de48f60b0
-f6b7df3155ddb4cedfbcf5d3eb3383d4614b3a85
-d72098038f3b55a714ed8adb34fab547b15eb0d5
-c49c825bd9f4764536b45df5a684d97173673fc7
-33799afe83eec4200ff140e9bf5eae83701a4d7f
-5c3f8ddcaa1164079105c452429fccf8127b01b6
-1f01443567b03ac75a91c810f1733f5c21b5699d
-b3e42b6d02e8d19658a9135e427ebceab5367779
-69b3a6dd9d9a0adf5506c8b9fde42187356bd4a8
-bafd075c5e6a1088ef0f1aa0b0b224e026a3d3e0
-7daa3adb242d9c8728fdb15c6af6596aaad5502f
-514993554c370f4cf30a109ac28d5d64893dbf0a
-c8d2473e6cb042e7275a10c49d3f6a4a91bf0166
-386f4385ab04b0b2c3d47bddc0dc0f2de7354964
-9f33dba05c01ecc5c56eb1284ab7d64d42f55171
-7466a26cab5d66665991433947964a638f5b957e
-b43aba89e356ff95b706e80d4802f60fc46a569a
-02b7e8319aef2a870264ad4fa2e3bb18664dcc36
-f686002a8eba820a40ac2f34a6e8f57b2b5cc54c
-2b1c50b9352ab1dc40b0f877db23c1fa4048fae3
-2405ce1df043f778b8efb9205009500cbc17313a
-4ad3b3c72c73d61e0a0cab541dca20acf651320d
-4ba3d4f4393d81148422d24d222fe7ed00130194
-8ee5c7b747171e335793c74cd9d2f7491da58164
-872c921c0a208b04bd0713758e52fcab5b7c1684
-00d1680498c5550e7db1f359202d3433a092fafd
-585db41e9ab7a6fb262c8bad7f427cdbdc497188
-18462960c0f13bd07d8f52b61e7d7bc17e991eea
-0630974647dacaf25e7fcb7f9cbb785bb078ede6
-0f58d7f3d62f012f2584f5e781fc73de4763dd9e
-3d16f581538b0974853e820508e8b3093269d2fd
-66e91420ab233cf1dac64504e0dc129019bf8c0d
-d8d9162f5bad39b2720dd2b2da237c6159e4755f
-29fad97c320c892ab6a480c81e2078ec22ab354b
-791c3ea61b4e49fd46a1a71b84ca99ddf69d2ff7
-a312e201ba56742499a5480b5f2115f01505c217
-ce56fdd2e8cdf94fd0ab76d71adbfa755e23ce7d
-480f42630cbd598c04fa59ee0e406f56904ecffb
-6012f1caf744ac9b53383d7d10a8f1b70ca2c0e1
-ded6a2afa549f693dcabb430ce0862f8631360c8
-07090c5339436f856e79a8036d1c85deeb453803
-0e265916d1c6a63e4a3821dab9db597b5ec64b46
-e4ffcacc2187d3419c8ea12b82fb06d82d8751d2
-e117cfe45eee9169409e74a44ef4a866be25bc35
-dcfe218626b05204e9fbc95ba5d95ca0eb72ec9b
-23481fa50301201ef5a60675ef899aa6ce94ca03
-27c59dc502f29cf1d76290556c21e366145e3b2e
-4a62ddd01873d18dbca96c81d756be1020249b45
-a233fb4f1d037e68ff70eef3a9f5b7bf1d631918
-b2089c51cc4af2f7e1c0ec75be9449ee222b1d69
-c997f8808256521397f1c003bb1e9896fee6eaa0
-5dc00f68c49c46a380a98d06233f90528b8e2557
-fe53d5f3636aed064823bc220d828c7ff08d1d52
-935eb8de039dec65669a96a1c3b86f4b03a1b86c
-0277173b1defb63216d40a8d8805ae6d5d563c26
-2a30e67d20f76bbcd9a7d445f616f005316e0a1a
-d32528e733f2711b34dbc41fbb2bb0f153bf7e9a
-4cad91663df381d0dff8526f3b4aa74569dfb626
-1b06ed136f17b526360617a70026aed5ded5746c
-895fbd768f0c89cea3f78acac58b233d4e3a145e
-f0295becbf3ef1fb78095306408789253fe0c114
-8d573198638e52e2dbd9abc609861430f9d2bcc3
-9d9c4185fadaf243bb97c226e2fef16b65299699
-eebe4580bc8d6484d79ecb24dd87412221cf2ea7
-9cf6393a4f82b9c81d3b4b468a17a89db10531a2
-598a9c4e4dcd03c6d80fba005de729a6a3aeba7e
-6970b30c6f1d2be7947295fe18f2390649b17a4b
-f359afcc410432ed5d30001acda0c66741ee8935
-126000ba9e7ff16271be2f4eef3df99ade8d624f
-b5e4b9b5100ec15217d43edb5f4149439f4b20a5
-b987ca4ee495a7fff82f0ac14ef0753bfb7586e2
-b03013396cb2f4bf25746388b3982a2c3616e16b
-9a97f39afaa890caa7987c6bc001b9a66e3e74e8
-cad504bf4c302f7a72e0a0e191f3fdbafda7340f
-45cf8a03cb57b8639a8d47323bde46ba22d9eeaf
-b7450cdbd89a1c862f4d4d8bf093f8a0b5448f9c
-0910cbe4ef31eb95fd76c7c2f820419fe64a3150
-92a810d04b906722c9efe60e3997243c71ff3d4c
-45173fa6fca9537abb0a0554f731d14b9f89c456
-fd4ca17360e6fc0c9bb76bf6b5b07c9102c12728
-ddff3447f29b62d79a33f728791f42fa9436216e
-36a5a4404836da323c755523fbd27563a8e84f94
-c991b304dee368f506cfee27ddaa333f1f82c518
-d38d1a3e75aa97ffa8755ddd431754a6d0942964
-a332a7d5a15214015f9553fdb2bcf80a1a4b8dc0
-604e08c83cf58ca7e7cda2ab284c1ace7bb12977
-18a1bbad98bd4321f15e7921d9aec91661499d90
-8049241e226c16bd07b029c0cb4b62ac40f0c923
-797441ee995aac59f55d59a93ecb55e8ecbe7dbc
-62fdf9b07087b80d2142799bdd2324f61483359d
-f60b4ad57912b78a96af08046a503f7905610a8c
-13e31dd6548d64a5992f439e74bb424bf88aca04
-fbce66a982679b5409a295be5c99a2eef429cabf
-9f2c2dba21855b8cb9b193b1819be73fa4a23a99
-a89221873a3ee2451c73b41bbe2d99d36f439d31
-3d6ad407770e13958e157bf026cae0bfb9254899
-901ba3e3819405306414628306746552b0aa1d28
-7a43fbb959c38e025e558e472ad57de357539894
-0d89fa0877930c6c8a539a656c1009ad8ab6755b
-54aedc013744c86b11157423fa3cffc9a51eef02
-f0c1f8abb0182da557d07372b938f3a0a4bb906f
-4ed818060ecf4a38a02c8cb48f6cbc78d2ee7708
-3bdf242fc68a8d767932c6214455d4d413effbc9
-5e468994fbb349e8eefc996954a31a67a34aaa15
-41aa9c4a801a01eca1fad22a7095372d23dace60
-2adbddb03840ad71e843c6c4a207a13e871cd1d4
-13e352dc53dec0127c5f94a60055d0ca829420dc
-95e14dc81dd30ee0d396ad08dca9a6980d16eee1
-61fb80660f73e5aa5b69302ecc7ac33da206ba5a
-05a761932edd05cf94ffe938908baf058f38632a
-ee92243e66f2df03b3a759a8ffb75dc06f0cea0d
-22cdf93c062eeaa0f8f9d6220f01b67240073dfb
-76b33491596736ca804e3a29bd8398d7a1516ab7
-6e4e98ee8ce2da3cca2e2fd210e9e8dbc9b1c936
-c838283ecdfb9490425bb071b7c22e542de46c7c
-5e3f5e4f25b65b583d3bfefac9e1148035781089
-f7388e93d3dd91a90239aedac4ec58404f103a2e
-0a2f46b0158b6fc7244a585913b0925c0acf707f
-dd561667cb7ccbbfed3134b05a565971ef6f5873
-6f01dcf63873a5e42798635ab4026c9a5f9fa213
-70fec9e36bcd1a3d93df019be084aaf89cecd7d7
-f9b74ef3fc74fd7d2aa94560820341f03cda8e12
-998c3046fab2b52bc9f141cfb588a18c05506a86
-89cc4f905e30b913ca20e4192d538cc5cbe2c38d
-87d90efd69b64f769116956a5db89e536e9e3714
-5aeaa9ccd1568a77e075dbe2bd2435bd60c87c91
-bfb270acfa30713dc8c968bb9ee40cf5a2360359
-1b8c88451b0554502435d3883c528ad0aad1b09b
-57ee73990f1ce29916adfd99f93eae1ccea1a43b
-808c84f89d0edcef9ddaab0b849a382719f6ec9e
-14b860bf64020451ced823b859da8cb912278ab9
-c63364610f4a041df1c1bd81d01b1f6856160749
-92eadc395071876d77f3babddc056b4325bdbabc
-e93fff1463ae906fc986bf98c3b118c82f171546
-9ccafb1d7bdd172a9b963444072a844da379c4f7
-b4a509a3f817121c3df98ddfd96b2769e18a3e5a
-dbc4ae03963014ab4b7957d62ba59dbd8f938c33
-8ddf60db7ad636b6a31b590251c671ded635fa1d
-f199b8a33d9443a258a1f49a1a29674cd9ee9a20
-e542728cde676f218c552d841d0af29b92f9800b
-763231051596b8e3455b839911ad6a3a1f1c3c74
-ff4cd6075b12fb32b9a906deea3ed033e3f9560a
-9c3c9cdae3e20b5bdea91a0631edac5116bbc89f
-93d20a734d2ee873832bed8ca5c05cf8e539c53c
-ef8340d25f7c5dd5682bdecea97ce84cfce1493c
-69c7ecef405d168f658a9cc7996da84c17f61e66
-4ce2f3d0d33346e9f0e96851689ee6550b2a72e3
-44e1fd926cfb0df0fbd8c41de8cd65ed8d5d6e18
-d6d2c8503c4039b682196d83a67dc28359c10c5c
-ae233c4ec3d14a97c6195059f52873cdba2b4755
-0f399a9ff227896265cafab9b2e9fab6cdb9b5b9
-f4ed44ab4a8f9a87ba678d5fd1449fbf636103dc
-7fcd61b2613c211bb042a82a889655178be6a212
-42973f834445d7735738bdba8847812ba3c34d95
-8df48b36ed3201d938b9974ecbee455d7dc2fb84
-96ac26e56627f0c24213fcd3a1cce9fc95f1f661
-cce94c518a46b7b0006f984bbe4d69e8749182d2
-801dd40666d1e6009920ad3ff755c7bb993b2a62
-ce829855cfca103dde55661fa1524e66b139d063
-b148803b181e30213e8a7f3bd89c8239e9dcb866
-c377feaad87f8109f85da6caf62602b30c20effc
-b37cab65c63e051ebc5b491da9bd687581df94df
-16e41844e7d6c5876d2caaeef6010656950c6ec5
-ee50c9e48786dea0d9df2e45805c25565c100fe3
-11dacc6154c42bc6fe3ba94c1823f8a46e4fe81a
-791a0e6ddade27d1b69f4861a6640de60b9553cf
-638e6c59da4fad987c437592174b188510193b2e
-52f8877525d5238f3440e73710507be889d14127
-2a56baf395bf11835d784c4f8634f4525deed6a1
-bc561b4b7d6a3f71649d37d5eb9047c29efa2b13
-31809d6f8514c4a8d5677e947e3f1ebb0db210b9
-a31e9ad4f027955d43c04a05517244647e250161
-777519bd96f68c18150a0f5942f8f97a91937f5e
-4eb1f39d421024d9666cec61deaf96715ffae4c6
-50fae68d416b4b8ec4ca192923dfd5ae9ea42773
-ce665863b137ac4a7470cf006a92aa7694faca71
-81f8c0378b2ab5ea0d7b65635cb529bd3c69127c
-108222b9c323a05cc9339368f10ddd0859f62b43
-28f788e47e58f2b462351d6989348a4e1a241b2b
-d81dccf191a48a6b59c3747d7b4ccbe3535dde40
-a90e6d2bffc422ddcdb771c53aac0bceb970a2c4
-91e49c51f1aecc9e1d75457f4920d52a4b0a133c
-60dd9cc470584960431de425e2a9ffbed0e8034a
-ede386c2193fc31351e193b3a8cf30030d6be62c
-a084767b40c0d3ba8fa8f8d60f1e8d99a9dc3457
-3f726c99f819f97f2ab21b94d34c6b3129cd883a
-77fc469fc78cdd87c29f398d46ac58dbb9ef62c0
-4ae6d0fbef60ccbecf8f23bb482e201b3678f7a3
-8858b6ddd3bce9daa08da6e05de3ca863a399c15
-22e301a3d56dc9e6878380ee92c7d19ca43119d2
-c484ec6c9b85ca4e331e395c564ae232fd0681dd
-a46a671e253528e450bd57645c400bf761da07ab
-655970d9c60ae6850daf452457e14e21047c0e1b
-b6a48914c50631914192aa11b19205436a9c664d
-7db65c363a0cc6ca7cdb04de9a973ab70013baad
-6366941275344dac7e2130b0c972e90117d37ed0
-4fb2586661471a1572c2df2a5a091011d45eb7c4
-d7be7b39fa1021ec4518186afe145ee948e12a94
-85aec87b11ec41295558175c63f1f5a849460fdf
-aeb31756276034dd506fdf97c8aaade0e7e584f5
-ac016e17d20253129a0287cee7e1d06b7ef15966
-bf74d377fb8e20140da6eac1407414928384bcea
-2c811e08db651a4aed6ea0f7c1972d60de6de8ab
-e5d26e47c7a482c072a7fe47bb84c56854734184
-96a63a3e0cefe920819bd42add0041837b1214a1
-e526ca6284b9e13be1b912b80dd73a34e739b539
-ecd21357f16106e541e9c2854ead2a906659b938
-4b5a7ce0c301ad971f383eb60f61bf9b4026efda
-929fd7276c0f0c30b9416f61a6f5f35d763d81e4
-fa8a0639f7b0ce04030b72b4d5be4f0aa36fc5cb
-f1f1605c22a6283bbfd757055fcf2b584a857709
-0c173a15ca1bf20999f74987988985508c9de463
-df0793f324e33066cc746c0cb1d053d35733d626
-2b0179d8a9b75397937126b36114df0dddeab40c
-bf0a08be281dc42241e7f264c2a20515eb4781bb
-3895e25a77363ae8b49358fb793f50fa8b271e2d
-1fc783fc08bc078239537535f174ab8a489772c0
-1d4805ce04645f3203b0cfd3d66ea710e7433eb4
-d3b58704d1d325875fc605580c1c02b825c1bbcc
-ed88e3194c4bc43aeafef929da7b419d03dea1ad
-dd07f47b79628668e29cc0143b21e790100ee445
-65cc7aacfbfc7b747926375280a1d839e88d576b
-080ec5209172ac9605f1434559dbb3c1e012b10a
-416af3edf5b5ab265acf95568f2bc9eabd3d96de
-e0a7801223fd573863939e76cb633f1dcc2d22c4
-4bc853b50fd9127687eb9e4f3b679dd261a4fa96
-c68a9a69278aa194fed96bd9733d32af3690a11e
-c38f540298f0e188df5ed68fd56c623b9ac8331b
-643fa0b22d70e459d7f7ec3d728ae4811dc5158f
-e053e05c130549f43953f1d70e724dc9ce3e1b85
-75e898c094eea533d1dfaf141c6afccc3072c49f
-2805d606bc46bf5589093a1b92d3542c13ce50c2
-32751807c9c06011eb689cba56b401a6302699c0
-30853e16d332816752dafcfca92147c7ffef5b54
-bea5b00cfe95cd37832305c0f93c339a22a7d79d
-c871f323b418fac27bf834843ca26985010df53f
-329fc1dce7a1c372c8b10c2f2f8732b2c60daff0
-1aefc94dd78d6e0c9209cb09fc16f53dedf42108
-8e5725666b519b61fcdc3141da5c6a57c1959909
-a4ca0b042365061020627a8c045cddacea3312ec
-8bd16ee12fc8ef6723e0572c29b979c15b92b4f4
-87abe20fc118721cc5efdbd94a8462468cd1da2b
-4b766fcdd4ca16399075d1e081a321b3b05ce516
-f6241b3e420e19f3f0507cbbc872fe9218916a02
-7ee523604851af62c0a47c07ee023a8710ef32f7
-776ba233e939fe41a74c6b2632b93a0679a32c71
-6a796b2b53fe542e0f340f250f4f20d69efed8d0
-23d78c4dd01bc74ba35db3e3df95280f6f1b2e22
-f4b15e2de97c4f8cdbb40bef4c9d0ab2807974d9
-fff72de5bf8ac7b70208e655f237b80e70e18851
-170bc2c381f86a523de2fc8b71d62ade66303c0d
-314ebdfcb38d4b4c977579f787d5e1a20d068c94
-e9274839bf316b1972d80d28e45759f898edbf86
-75171f099e82e3527d7c3469b15891bd92227ec2
-3c5e6c94caf40395e031fbde44a0cca46fdd76ec
-dc8fc0c73bebbc1c48ac5540026030c9cc00ec23
-492d22f92919d8d9d59568318c26c1e2ac4890cc
-80c3a734298e824f9321c4efdd446086a3baad89
-47535d7c3ec79c5978cdcc03a5351ddbbb22538d
-1b25b6df0f08f7474228c5b6ed13b58682e1e440
-c530c15180631cea95e9c292cf7fabde9dca9db3
-2723bcdce3248417e98e6c43207bef74d34076c1
-ed22eb4a62bd8d5369aaec87d4cbdc03c9f16368
-9111df9673beb6d6616d491a5478f09b5f14d040
-d86bb075bf6d1e78c1e4f3dd38b0ea828ef5ecfe
-50a1cc0f0aef1514b917a5a3f4476967170b429d
-6ce733747e160ca699711f2c47e686284ca9aa07
-b44adf92342ad4f9c343ba29c081a91687932936
-88799ea1b1c08f4bc1a487c9e3c2effd5e1650ae
-080d7c700fc3291560d79fc590e05b8e2bad984f
-12af74b289f8cdc6caf850dc6c802f9936b1e8b3
-8e4f7e72410df3ba430082c7cf385f26fd75b033
-8ac80412867118172dc4172494304e19969e9489
-f2734c2828f69d9cfd535e5eab0592a7674b2b61
-0b9fb682890b8fe10cec54072b809a5efe57d33d
-5b029aaedb5fcf7cadd249607dd28eb3f233ab8c
-79af9fbd8c3c0e54702a9c92b171f134bd4466c8
-c412fd805ddf3282dc2e1f28e30f51ffcb1f1da2
-111849345bb5140f86b48e730ceab4bff45fa2e9
-a0b1e57b20a17177ed5a9a54e4a8aab597a546b4
-ca209230c8e73745cf8cfc79f500c9c46e103306
-a230b0588788dbe1ac84622aea169c577b381241
-dfef6b6af08097f0676a2323085558fbbd3c48c6
-3192e5278abca7c1f3b4a2a7f77a0ce941c73985
-7c7ddd9ead99a8b5033a1a5d4698032c9e2b3a92
-10b930dde8f14e9cb661810e97a33bbf144fc55c
-9225de2cf652fe2bf6e50636824cdb641546f57d
-598ef9c44b3ea2cc142c175f077b493f39f5ba22
-c49355c7170a64bdd7864cc3ba9a64916b67fe7c
-857d1e171e051b254a617f27b39f6a551054cee2
-21833f9456f6ad5bc06321ad6d9590f42ce0195c
-8910b4717e5bb946ee6988f7fe9fd461f53a5935
-5703dff0939f05c7457cebd6fc61d88ab13afe41
-8bfa13b15b84cb372950fb7b25a1080173060b6a
-ac23a7c1f19b3d8c326ffe75c8e13edf285f90fe
-19be26afe3d04783a92d032b55bf3fb1e2ae63cc
-f7ec7cfd38b543ba81ac7bed5b77f9a19739460b
-36afd4db4442c45d4078b1a7ad16a1872b5bee0d
-88c2ae3ed2bb5d367dd408c9255cd8f1e7a36c7d
-a13a417cdcfdfd1f1b3bf997bb6ffe6e69b096b9
-d6064a89ac97dc0d2ce9da3982e1a4e25afaeda8
-7146d96de3e15a80cafbab2af48ff6f65d8e41bb
-5628c70f2a44567695e5331fe2293c5b7f35b629
-7ff4a538a8682cdf02a4bcd6f15499c841001b73
-aa5fa642b0e7ce2ea55e2298886f212f11a8894e
-8efd1c820b9a782d8608d54d924658536178295c
-50a226563cd8d7c0a5e8448e87fede0eb72a8354
-b860915f8b0dae98e57a254d11575ea41f5c5a79
-d304fef3746039183f51b3ac8f4774dcf3a64f59
-53ab12d9318d5d195ccc77028b0e3ae66dc6e1fd
-668de70be039a4f1ffcf20aeae2a22ee71fc55a8
-0fea960ca917b73aff853fe88476174c8a313863
-f89502306dcf6393a2c7b0efbb0fa728fc582137
-ff58b1c3bdff5e5f687f10f9e40ce495ca49674e
-0b96abc35f1a9d46a27eeddd7df418d107c29c57
-b0b57a17306a7e963a4fe463f84e2b150a00a859
-4105cb6fd964ad13099ca83b1fdf3d35f3961f74
-23281a4dc3afc42a001346caec4dbb8193f0bb53
-8daf103fa138f9a184448ebf1c2e03b9dbd96f21
-02e5308c1b9f3771bbe49bc5036215fa2bd66aa9
-a65ced1a66575c652baf5084644b8647f531be8c
-2456a835f0bc7796d9ff71f64837fa6790e2b7cc
-9ec1330b455c1ab2eb6b89f8a2ab885677d4ae8a
-0b738075bd43fbd4410e30a51e0498cbfd2b7513
-98c80e374b84e5a9c2d5c36889a0b1ebed5b814b
-25720fc394e27a951bcad26095fb5a711bfacb8f
-4cfd57d2e38207d78722ce8c9274ba8dd700d1cc
-0fc1c31a878e93d938c67db3f958e82e3c39659f
-df1ab5b4d67b46b5e9e840b1fbe0ff02520831f9
-5bc3b6cede8dabdf3f4f27ddb03723cbb7cde51a
-c2ea1e6561caba3abffce361abc800822b9e0efe
-caa2f106d704ec3ade63498031dd58d34510bc76
-dce853ef76ef90c46d84294225088d595467d08c
-dbc8a8c86ae50059fddb2d6834fa5f0c9bbf9b71
-0f921e6a0492c4e9f037a9ed91f474885032d68c
-041331e1da23e4136fd046ed870cdcc177464176
-e6ba5068f107ac234576e77cedbd748b665369c2
-76fcd9d5034143a5b041766552670d19f926097d
-72bf1b3d0962304850a3ef5fe375db4bff1d0a39
-919db037f1f5cc73cdcaef92dd9cb0e7f5c8dec3
-c36229b0b2e9d4554053f5c9fc451ac29a493b1f
-9e4bb312e6958d2baa309ba670e5eed1523c6f47
-d7ba4a233bd5a6f8fadee681c68a995e23fe36d7
-98514988a3d3e8b7dbf0463884a5c38f5ed5562d
-5412c08c3cf13577566064edd04da021c37b7cbe
-31bcc667863f368157efa1143a78623a5db8f0d1
-7bd1aa566fb4a4fe194f209085649f2c722b0cff
-c4522e71c7e1d8ecfd70112e9375b9d00d6733a8
-e22f409f18881b63a8e747036584a71217f40e6e
-97ec6e5c9098a1240655cfcab05b6cd5eedb6cd1
-bc121b0eb19713ec72002b5be03ba5ac35903a17
-c98f6b3d93a2cc1b49a6db425ea2b661089d0f9e
-0de7fd36de57a68e543b4c1f184fba192c398c73
-e662d281b837c25b2b70525aa8fe8af894339823
-44adf683ad232db8ce0cb89b3e236a1f5944cfb0
-cb2ed300a89ebf9f0654da869ced665ed8b2abe7
-0a6d48d9ed60b0b02177059ab116f8f46d2cbed3
-b42291334651fff46dbfe5947a726f65cb9d7dfe
-e5364991daecb73aca3bb5ac37f2619d7a89211b
-4a2b170c075ce703cbdc82519a48016a9ee3f99c
-924de0bd75a7f75df65d7d15f9d1587a2e794abf
-1253f8692fc3a11be9430685cd405236a68df6c3
-2b799ae9e1e0a540f9a5971ddf27d83254668279
-c9bdf9a75f9fde8cd011e4aa94be4ed4347078a3
-3d69ecb4edeb80003a1a41442e320898a30dbd9c
-f08222e882b18c1f279308636e03beceece2dbf1
-23e03f8d26d7bd03273a5dcbdcfe3905dfb49ffb
-03dd707dc027fbf6f24120213f8eb66571600374
-d0754799698de2c032abcb8198ee5d5401063213
-072116fceb2294b97d1c40f79305f2e3ff71812b
-e66cc1d58e16bf1650dd6479fed64ecaca8c6098
-f137753a2dcd8229f89d1d1ac28039364e5850b4
-61d191fbf953700ba8aeadc9c8cf4c195efbd10c
-76f3c02fb01a6df98fbd8c16ac21d159d4649d37
-6013c73b3312e11b447ed387426749014716f820
-6faffb8a83db3f209a303a4464dbdd597faad5a4
-cc9e8aca5f950c78dcfeff63c441ba993c1fe12f
-8ca69a2a88a77eb06149fa049ab1a7e6de38b321
-2f71490d21796594ca6f55e375558944de9db5a0
-08cc5fd666456cb476467473ed1880c90c92dedb
-e31a43c725ebe641d7c219c3886eee18eebf0bb8
-52b5a8785de760a204b2b0aab19dfaf79c2c3ff0
-483e8e4f4875a1a621ec9e9df2880d3037d95ed7
-1e5799c52535a3fc20e885916f1e7ed33ecc7f46
-a82e5d8220bbc8b5d786bed99b0876f530b9b7cc
-7fe6c5c993706e8395cdaf7977bee793c06f48f3
-2a0836f6d5e7c1d7e97bedb0e0ea33dcaf981f77
-ddc308068d69c6c9aa629ee3c4ce75e1d1cf08b5
-ec139a5621a9c9f03e1988391a3c7c6c5d849776
-c01a6c48b982d625fd9f4f69005878781d3d56fa
-95a983d56dbda457e3bf8766d59bac74c7aa5699
-760741a00833876976389ed7a6b73f36ee5b4c13
-6e5e5abba6f8bbbe61c22795df440dfafcfdc378
-cf2cecb18779ce83de9adebf382dff1c19b12840
-af9b7a9f2f73b1a2f9728106774dd13e8d1cdd8d
-115735d547fdeade822f547eb3e8c8f9961a9b07
-c2c69edf37b5c02aafa01d0407dadbf5ef8751b5
-a072d1a83787e786d074a4b5871b0b961781f7c6
-ed2cd59e258f756b2eaed7909a60956ade6ef7ee
-ae5575ba41c8a782805afb1c08730343cfc22397
-6ff2c8d29f6b5a5c2ce63f0a16f3bb0dbd049451
-a80de15113166354cdf208e3d8b6e25f4511a591
-06bd4f637f15e769f088d9051a5af94bbb0217a3
-6700cc993cc07fb0f5b8b577ff8c4afcf0b18274
-37f9a1f627c0995d89b62923e75cd092600894f9
-8844ef15ded02d5ed86fb95aaf251235fcef2396
-1b87e5b5b184a0a6c683eda23b36393822b57f03
-e2bf830bb6c1bfa038c943dd6f5d92a406bd723f
-423ca302a3ee87000530da3c105f269b8fabece7
-4e14afe42fdd468d5de11df8cc13defdcb8e83f8
-3e90fe6534206412ea22beaa445cf20d28fbe718
-88b77c7da0a672c89e24df37ea6e9085b4e2a05c
-0ad104190465d8d65c2344bbe10dcf3df025d86c
-5c7df7022bcd360e6af00b9458b1a3fd54e1cc9a
-59ad56851a342d2c62f6b38bf15002b23ab439e1
-d8cd7b137fb075616f31d2b43b85fa2e27ea7477
-655937ebcbf681ededf86b1f0f60aac45c73393d
-abdfd2d0e3ebec7dbead89317ee9192189a35809
-e439aeb30c0439001a781c5979aec41e1fc2aa50
-b9b26d9c3615d15669ae0a049c1dede39a9e59a9
-fdf146f3293c487afdc4d6d9f6b64099aa8bd28a
-16e3b175781caacee403a2dc40cd6c70448e12ef
-b30c62d4b954df05bf404cfbeb5b728282201496
-b3f377daaa86cd7755a552fa3adfeb195835f58e
-0a8f519a0626d7cd385114ce610d23215c051b3f
-544f3234384b2f6c290e987ad18576e1b50d7db9
-91482e5bf22d283d32c9f83c8057f10971848107
-e754c6e33194e9ed69ba5350c5139b0423b645fe
-dc1e54206d76e5fa378d28a18ae1fb2bcf714485
-b2863c0685a5c12f829095cbabaf26ccc49e46ec
-b14db5abab405a708f0166293f1ea12222a6bf03
-8010ded6da56842c09b14665343cd189d7e08401
-d387507aeca652a5569825af65243536f2ce26ea
-27bf14f6f3e0fb1f348f13c1b54fc6b67b3bef6e
-f8d470e24606297dab95e30b1d39ff664fbda31d
-b25a4c2284babdf1e8cf0ec3b1402200dd25f33f
-1329ef1f00e4fad83937ddd8721d0292ccfe7808
-9a1ad2c5cbdfa3114d05df57103c34f72e087f26
-1e90862f5d0b5f7dcc18fb018b2bbaa323dcca1d
-ad552a54c56a420be84b47154882c3e4c76f9bdd
-90b1c7e5c50551f39d4983008d1d5ab3b085803e
-d6b2235ca45e072961e25a35e6a159e97c9e556b
-2643fa50869f22672cbc72ac497d9c30234075b8
-01f909828d126d5443bc28758f51781eccdf5848
-f54f3738c8ce839c413d7b6b719be2ff341536ca
-418ae49ee1eac2c9d6cd4ba83c036a41f1afe922
-5a666428b0f11d62af2002bd54a45ff2f79f30cd
-a07e8caa5d5000286604458e6887f57fec7fdcbb
-8b262eb2d80bfa27ae8501078ce47bc1407e9c55
-5df84de583c900e00fef63bedaef32786f205a33
-4ba6da55743a55189164e29e45ac9e73a074d808
-88430cbab4dca36b6a867364cab319cde6a9ebca
-e0f7515f5500968c86e5a9f4912d83d4abc5b2b9
-9b8b1079ddab64ac955766536c38d23dc57bc499
-af20f9b1d485582b8c8aa8294bac4f2c540246d2
-7be9a9a570c1140048f8781ced1111e1d930e517
-2bac3e484114c30548e286972525dd799dbd0a5b
-df529dcc65e8037c5a3a3ad74545be294a770f07
-6acd8700bc0ee1d10207a362c1e07372ba274041
-ffc6e48b2983189dc0ce7de0a038e5329bc07b1b
-252ae7111cbff09a4cbc5caee9e02b6ed3580476
-b3ecb7bab6074377d87c700bf0c5d351e5d3174f
-d9fdac130a5ed1d96fcac6bb87c10bec9d596b17
-a07e8caa5d5000286604458e6887f57fec7fdcbb
-8b262eb2d80bfa27ae8501078ce47bc1407e9c55
-5df84de583c900e00fef63bedaef32786f205a33
-4ba6da55743a55189164e29e45ac9e73a074d808
-5bea05bc1d17aa43cbdf3a3413241f8132790d93
-c17f11f7b43ad3bd9e242c67db1f3679558a0581
-5ea932a51083837cdd27715e10a3a0d5d553af24
-033c78671b91b12d589ebff6c5ede8d94d7500f8
-ef8a634358848847e006c43ce621bc17a612fd1f
-ba216b5fa63e7e6cae847d1e3621f5c54840f898
-26fee4f6bd9aec62c6caa60683ad66574cf16aa6
-6ab0e4cf49549640b903bf5fce0e6035b8116397
-326a5652e0d25fdb60c337ef4f1c98a63e0748f0
-424be03305143cbe5da5d5adb54d73d3dc3747b6
-38c201f47c0bc388a05cdb35d6137150fa90193e
-12ed800ab870e0fc527a84d6e4584b10c8d239f5
-aeed345c9bade5d52a3fbf0a943203f6c82e6344
-c6223b3daab0328ca742b1cc3c15e89e698630bb
-877678710800a4d78afc12519424f232f1a583d3
-6c4fecfaf7beefad0d1c3f8520bf50bb515a0716
-98212745c8acb5cc4e688bbb3979bfd46b25f98a
-b9bceaf1c081a84d9fcc680372614e797b168a9e
-1afc22a7667a7a5c66b4b5d7f50832356dd5ec12
-3255d6347b1f9eccbec3d6d93d4a424087a3b35b
-ec20f01ba0945a3113797ac98a6b3500e24603d4
-75b5643c47c3b382ed97a9f5e2bdc883a0f98709
-fee0d803fb55c8d85b5cd1ff69d799c5ad522e18
-565494619d809655fa94d274bb2202d25553e485
-ad6fce67b9bb6eee864c8431ad3291aebaa2e5d2
-99c7db8731cc77f143b52f544b3fdd93033ed20d
-b4d03be3cac04da8b5d5fa17e29c5220b75d970b
-ef37f2033c4ae104585cd980141262f95d33166e
-5cfdda2503c995cdd563b1a2a29162ac298d173d
-c5904e871479514b2e2e18b4fdbbe468c4e5ec8e
-10b22e3141a603ec891d2cfc7100c29c7409aabe
-afd2fca911c4a5e3a4d1f0993a226d40f250aff4
-505955052e60e0681865f3064e005ca0d3aa90bf
-8fdd23a224ba236874ef662c4ca311b002dbcab3
-1c011ff430106b5f727f2eaa0f7f4883cd2122a3
-ec8a50b8d786a8cd1192e692ab19b46979add582
-f90603ac6d24f5263649675d51233f1fce8b2ecd
-b7d6623c76e1468f2a93db5a3120580e2784d74a
-66270a416edb1610f276124483feceef9cba93ff
-e4fcbf797ed3b472d352ac3794ec82f581209c50
-479afa0f8486146a35f1fb96be1826061ecbcf23
-2a09a3891fde052a585dc019eea9fba26d42445d
-90a002ea647dcea57a2ed4294eab77897168ba1d
-30c21306c17165c3925fea4ac9d1a4763c6d2a99
-b3eb0d6485510f2bdf36d256ab60ce29b8213744
-efbcf2b1d5ff4ee7132eae9c9e203d2b875c545b
-b33ca14f594e2cf2a16ef27778169deb7cc9f4dc
-d636f3943d39ec893dab2d2546f77f3f2607769d
-cafe24f039e117d53288387c2720f44f27deecd0
-de8db47b7ff351f3287c5efb85102ba8836058d6
-d76e84a21416ef77e78138e326d4d249454e79dc
-7a74f88a26cf251ba36b26f604f1ac9940fd9c92
-1ad3d4e1261f4a444d982a1470c257c78233bda3
-8d9f45ea6a5e4220e44d34139438eea75a07530b
-c98ebf1bfb29a8203b5090412afeb333384213cd
-f18bb49547095020a30e81b648075bc7e707515c
-76f268b9bd1b69eb7784c5324abbb67f3e395b97
-e801084decf4542d57cf5ddb95820643766a172a
-be3e042c20e2f3449b7b55d1cab0a80b0c6f00af
-400fdd08cc95f1e85afafd07ddd9c0bed11483ea
-098b01dc58ff555c473ae58c92c34b03a77eda5f
-7cc2c670e3d7cf26454ac8547a94ec2c8ca90b34
-1088b02f0ccd7358d2b7076bb9e122d59d502d02
-f94b7d5bfa911ea7125920589723ee63a3eec9f0
-b4b057a3e0712dd16b50cbcfe7d613e4413ffa1c
-b40ceed98a112f4f0d07351ce07270d9ff2bf796
-4cb8757aae1ae31e5519d81e854f44ed062d9836
-f2f7e97e8cc24cf7a2b7954cb74ecfd0f91a95ad
-ae786098bc58b1ca92f596a698b23aeade9cd2cd
-c33652576ce21694b33a94832378f737dd6959fb
-e317c0d19201ff75fa7afedf93a9d1cd2c560af2
-bee35299716cc72cb7d5bd4daa9fddca05c58378
-318ea50a1c2f612e750a93e36620dd0c4531e9cf
-b6ee855b411ee9bc39f935d0da3298a773a2ed37
-daf3e7def7b9e5db7a32f5a20b5c4e09e3f0dd18
-bc64b5aa0fc543fe8fd3dbaec275f89df44dc409
-3f57c55dba6ef1fda2bdf6fd9abd8ca7eb6828e4
-431a548faaf51c7a5fc89b6e479187a1c0e29805
-e4bbd3d230f22401ba0a0a72c8ed41ee1bd098a0
-c45da32047cac54afc99cf9b8a539389c577ded1
-ab1f1d32469180b3d011e9625d67c86a22b55903
-a550f6e415fd8aec8c45d4704712a408c37ecd18
-c73af5416b66f09cec0eb106f5a10f9bb6ef9cb1
-a077a90da88f12d9f10c8b85840bdb847a98b0a0
-c5e9e428a9198c8c4076f239b5eaa8dc95e7985b
-b7365f0545b1a6862e3277b2b2139ee0d5aee1cf
-4bd0e9b90a39c5c6a016b83882ae44cb4d28f1f8
-7438ceac716fdfe6621728c05e718eaa89dd89aa
-4e3efd47e0d50c6cd1dc81ccc9669a5b2658f495
diff --git a/contrib/verify-commits/allow-unclean-merge-commits b/contrib/verify-commits/allow-unclean-merge-commits
index 7aab274b9a..e69de29bb2 100644
--- a/contrib/verify-commits/allow-unclean-merge-commits
+++ b/contrib/verify-commits/allow-unclean-merge-commits
@@ -1,4 +0,0 @@
-6052d509105790a26b3ad5df43dd61e7f1b24a12
-3798e5de334c3deb5f71302b782f6b8fbd5087f1
-326ffed09bfcc209a2efd6a2ebc69edf6bd200b5
-97d83739db0631be5d4ba86af3616014652c00ec
diff --git a/contrib/verify-commits/gpg.sh b/contrib/verify-commits/gpg.sh
index db5bfce208..cfd68e45b8 100755
--- a/contrib/verify-commits/gpg.sh
+++ b/contrib/verify-commits/gpg.sh
@@ -5,12 +5,9 @@
export LC_ALL=C
INPUT=$(cat /dev/stdin)
-VALID=false
-REVSIG=false
-IFS='
-'
if [ "$BITCOIN_VERIFY_COMMITS_ALLOW_SHA1" = 1 ]; then
- GPG_RES="$(printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null)"
+ printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null
+ exit $?
else
# Note how we've disabled SHA1 with the --weak-digest option, disabling
# signatures - including selfsigs - that use SHA1. While you might think that
@@ -20,12 +17,12 @@ else
# an attacker could construct a pull-req that results in a commit object that
# they've created a collision for. Not the most likely attack, but preventing
# it is pretty easy so we do so as a "belt-and-suspenders" measure.
- GPG_RES=""
for LINE in $(gpg --version); do
case "$LINE" in
"gpg (GnuPG) 1.4.1"*|"gpg (GnuPG) 2.0."*)
echo "Please upgrade to at least gpg 2.1.10 to check for weak signatures" > /dev/stderr
- GPG_RES="$(printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null)"
+ printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null
+ exit $?
;;
# We assume if you're running 2.1+, you're probably running 2.1.10+
# gpg will fail otherwise
@@ -33,33 +30,6 @@ else
# gpg will fail otherwise
esac
done
- [ "$GPG_RES" = "" ] && GPG_RES="$(printf '%s\n' "$INPUT" | gpg --trust-model always --weak-digest sha1 "$@" 2>/dev/null)"
-fi
-for LINE in $GPG_RES; do
- case "$LINE" in
- "[GNUPG:] VALIDSIG "*)
- while read KEY; do
- [ "${LINE#?GNUPG:? VALIDSIG * * * * * * * * * }" = "$KEY" ] && VALID=true
- done < ./contrib/verify-commits/trusted-keys
- ;;
- "[GNUPG:] REVKEYSIG "*)
- [ "$BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG" != 1 ] && exit 1
- REVSIG=true
- GOODREVSIG="[GNUPG:] GOODSIG ${LINE#* * *}"
- ;;
- "[GNUPG:] EXPKEYSIG "*)
- [ "$BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG" != 1 ] && exit 1
- REVSIG=true
- GOODREVSIG="[GNUPG:] GOODSIG ${LINE#* * *}"
- ;;
- esac
-done
-if ! $VALID; then
- exit 1
-fi
-if $VALID && $REVSIG; then
- printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null | grep "^\[GNUPG:\] \(NEWSIG\|SIG_ID\|VALIDSIG\)"
- echo "$GOODREVSIG"
-else
- printf '%s\n' "$INPUT" | gpg --trust-model always "$@" 2>/dev/null
+ printf '%s\n' "$INPUT" | gpg --trust-model always --weak-digest sha1 "$@" 2>/dev/null
+ exit $?
fi
diff --git a/contrib/verify-commits/trusted-git-root b/contrib/verify-commits/trusted-git-root
index 1c42195961..7ec318e1ea 100644
--- a/contrib/verify-commits/trusted-git-root
+++ b/contrib/verify-commits/trusted-git-root
@@ -1 +1 @@
-577bd51a4b8de066466a445192c1c653872657e2
+437dfe1c26e752c280014a30f809e62c684ad99e
diff --git a/contrib/verify-commits/trusted-keys b/contrib/verify-commits/trusted-keys
index 5ca65e7b0d..94daf28b15 100644
--- a/contrib/verify-commits/trusted-keys
+++ b/contrib/verify-commits/trusted-keys
@@ -1,5 +1,3 @@
-71A3B16735405025D447E8F274810B012346C9A6
-B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B
E777299FC265DD04793070EB944D35F9AC3DB76A
D1DBF2C4B96F2DEBF4C16654410108112E7EA81F
152812300785C96444D3334D17565732E08E5E41
diff --git a/contrib/verify-commits/verify-commits.py b/contrib/verify-commits/verify-commits.py
index 3825caf5de..a1fe78a643 100755
--- a/contrib/verify-commits/verify-commits.py
+++ b/contrib/verify-commits/verify-commits.py
@@ -92,8 +92,10 @@ def main():
unclean_merge_allowed = f.read().splitlines()
with open(dirname + "/allow-incorrect-sha512-commits", "r", encoding="utf8") as f:
incorrect_sha512_allowed = f.read().splitlines()
+ with open(dirname + "/trusted-keys", "r", encoding="utf8") as f:
+ trusted_keys = f.read().splitlines()
- # Set commit and branch and set variables
+ # Set commit and variables
current_commit = args.commit
if ' ' in current_commit:
print("Commit must not contain spaces", file=sys.stderr)
@@ -102,7 +104,6 @@ def main():
no_sha1 = True
prev_commit = ""
initial_commit = current_commit
- branch = subprocess.check_output([GIT, 'show', '-s', '--format=%H', initial_commit]).decode('utf8').splitlines()[0]
# Iterate through commits
while True:
@@ -113,17 +114,41 @@ def main():
if current_commit == verified_root:
print('There is a valid path from "{}" to {} where all commits are signed!'.format(initial_commit, verified_root))
sys.exit(0)
- if current_commit == verified_sha512_root:
- if verify_tree:
+ else:
+ # Make sure this commit isn't older than trusted roots
+ check_root_older_res = subprocess.run([GIT, "merge-base", "--is-ancestor", verified_root, current_commit])
+ if check_root_older_res.returncode != 0:
+ print(f"\"{current_commit}\" predates the trusted root, stopping!")
+ sys.exit(0)
+
+ if verify_tree:
+ if current_commit == verified_sha512_root:
print("All Tree-SHA512s matched up to {}".format(verified_sha512_root), file=sys.stderr)
- verify_tree = False
- no_sha1 = False
+ verify_tree = False
+ no_sha1 = False
+ else:
+ # Skip the tree check if we are older than the trusted root
+ check_root_older_res = subprocess.run([GIT, "merge-base", "--is-ancestor", verified_sha512_root, current_commit])
+ if check_root_older_res.returncode != 0:
+ print(f"\"{current_commit}\" predates the trusted SHA512 root, disabling tree verification.")
+ verify_tree = False
+ no_sha1 = False
+
os.environ['BITCOIN_VERIFY_COMMITS_ALLOW_SHA1'] = "0" if no_sha1 else "1"
- os.environ['BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG'] = "1" if current_commit in revsig_allowed else "0"
+ allow_revsig = current_commit in revsig_allowed
# Check that the commit (and parents) was signed with a trusted key
- if subprocess.call([GIT, '-c', 'gpg.program={}/gpg.sh'.format(dirname), 'verify-commit', current_commit], stdout=subprocess.DEVNULL):
+ valid_sig = False
+ verify_res = subprocess.run([GIT, '-c', 'gpg.program={}/gpg.sh'.format(dirname), 'verify-commit', "--raw", current_commit], capture_output=True)
+ for line in verify_res.stderr.decode().splitlines():
+ if line.startswith("[GNUPG:] VALIDSIG "):
+ key = line.split(" ")[-1]
+ valid_sig = key in trusted_keys
+ elif (line.startswith("[GNUPG:] REVKEYSIG ") or line.startswith("[GNUPG:] EXPKEYSIG ")) and not allow_revsig:
+ valid_sig = False
+ break
+ if not valid_sig:
if prev_commit != "":
print("No parent of {} was signed with a trusted key!".format(prev_commit), file=sys.stderr)
print("Parents are:", file=sys.stderr)
@@ -153,15 +178,24 @@ def main():
allow_unclean = current_commit in unclean_merge_allowed
if len(parents) == 2 and check_merge and not allow_unclean:
current_tree = subprocess.check_output([GIT, 'show', '--format=%T', current_commit]).decode('utf8').splitlines()[0]
- subprocess.call([GIT, 'checkout', '--force', '--quiet', parents[0]])
- subprocess.call([GIT, 'merge', '--no-ff', '--quiet', '--no-gpg-sign', parents[1]], stdout=subprocess.DEVNULL)
- recreated_tree = subprocess.check_output([GIT, 'show', '--format=format:%T', 'HEAD']).decode('utf8').splitlines()[0]
+
+ # This merge-tree functionality requires git >= 2.38. The
+ # --write-tree option was added in order to opt-in to the new
+ # behavior. Older versions of git will not recognize the option and
+ # will instead exit with code 128.
+ try:
+ recreated_tree = subprocess.check_output([GIT, "merge-tree", "--write-tree", parents[0], parents[1]]).decode('utf8').splitlines()[0]
+ except subprocess.CalledProcessError as e:
+ if e.returncode == 128:
+ print("git v2.38+ is required for this functionality.", file=sys.stderr)
+ sys.exit(1)
+ else:
+ raise e
+
if current_tree != recreated_tree:
print("Merge commit {} is not clean".format(current_commit), file=sys.stderr)
- subprocess.call([GIT, 'diff', current_commit])
- subprocess.call([GIT, 'checkout', '--force', '--quiet', branch])
+ subprocess.call([GIT, 'diff', recreated_tree, current_tree])
sys.exit(1)
- subprocess.call([GIT, 'checkout', '--force', '--quiet', branch])
prev_commit = current_commit
current_commit = parents[0]
diff --git a/contrib/verifybinaries/README.md b/contrib/verifybinaries/README.md
deleted file mode 100644
index c50d4bef71..0000000000
--- a/contrib/verifybinaries/README.md
+++ /dev/null
@@ -1,41 +0,0 @@
-### Verify Binaries
-
-#### Preparation:
-
-Make sure you obtain the proper release signing key and verify the fingerprint with several independent sources.
-
-```sh
-$ gpg --fingerprint "Bitcoin Core binary release signing key"
-pub 4096R/36C2E964 2015-06-24 [expires: YYYY-MM-DD]
- Key fingerprint = 01EA 5486 DE18 A882 D4C2 6845 90C8 019E 36C2 E964
-uid Wladimir J. van der Laan (Bitcoin Core binary release signing key) <laanwj@gmail.com>
-```
-
-#### Usage:
-
-This script attempts to download the signature file `SHA256SUMS.asc` from https://bitcoin.org.
-
-It first checks if the signature passes, and then downloads the files specified in the file, and checks if the hashes of these files match those that are specified in the signature file.
-
-The script returns 0 if everything passes the checks. It returns 1 if either the signature check or the hash check doesn't pass. If an error occurs the return value is 2.
-
-
-```sh
-./verify.py bitcoin-core-0.11.2
-./verify.py bitcoin-core-0.12.0
-./verify.py bitcoin-core-0.13.0-rc3
-```
-
-If you only want to download the binaries of certain platform, add the corresponding suffix, e.g.:
-
-```sh
-./verify.py bitcoin-core-0.11.2-osx
-./verify.py 0.12.0-linux
-./verify.py bitcoin-core-0.13.0-rc3-win64
-```
-
-If you do not want to keep the downloaded binaries, specify anything as the second parameter.
-
-```sh
-./verify.py bitcoin-core-0.13.0 delete
-```
diff --git a/contrib/verifybinaries/verify.py b/contrib/verifybinaries/verify.py
deleted file mode 100755
index b5e4f1318b..0000000000
--- a/contrib/verifybinaries/verify.py
+++ /dev/null
@@ -1,183 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2020-2021 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Script for verifying Bitcoin Core release binaries
-
-This script attempts to download the signature file SHA256SUMS.asc from
-bitcoincore.org and bitcoin.org and compares them.
-It first checks if the signature passes, and then downloads the files
-specified in the file, and checks if the hashes of these files match those
-that are specified in the signature file.
-The script returns 0 if everything passes the checks. It returns 1 if either
-the signature check or the hash check doesn't pass. If an error occurs the
-return value is >= 2.
-"""
-from hashlib import sha256
-import os
-import subprocess
-import sys
-from textwrap import indent
-
-WORKINGDIR = "/tmp/bitcoin_verify_binaries"
-HASHFILE = "hashes.tmp"
-HOST1 = "https://bitcoincore.org"
-HOST2 = "https://bitcoin.org"
-VERSIONPREFIX = "bitcoin-core-"
-SIGNATUREFILENAME = "SHA256SUMS.asc"
-
-
-def parse_version_string(version_str):
- if version_str.startswith(VERSIONPREFIX): # remove version prefix
- version_str = version_str[len(VERSIONPREFIX):]
-
- parts = version_str.split('-')
- version_base = parts[0]
- version_rc = ""
- version_os = ""
- if len(parts) == 2: # "<version>-rcN" or "version-platform"
- if "rc" in parts[1]:
- version_rc = parts[1]
- else:
- version_os = parts[1]
- elif len(parts) == 3: # "<version>-rcN-platform"
- version_rc = parts[1]
- version_os = parts[2]
-
- return version_base, version_rc, version_os
-
-
-def download_with_wget(remote_file, local_file=None):
- if local_file:
- wget_args = ['wget', '-O', local_file, remote_file]
- else:
- # use timestamping mechanism if local filename is not explicitly set
- wget_args = ['wget', '-N', remote_file]
-
- result = subprocess.run(wget_args,
- stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
- return result.returncode == 0, result.stdout.decode().rstrip()
-
-
-def files_are_equal(filename1, filename2):
- with open(filename1, 'rb') as file1:
- contents1 = file1.read()
- with open(filename2, 'rb') as file2:
- contents2 = file2.read()
- return contents1 == contents2
-
-
-def verify_with_gpg(signature_filename, output_filename):
- result = subprocess.run(['gpg', '--yes', '--decrypt', '--output',
- output_filename, signature_filename],
- stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
- return result.returncode, result.stdout.decode().rstrip()
-
-
-def remove_files(filenames):
- for filename in filenames:
- os.remove(filename)
-
-
-def main(args):
- # sanity check
- if len(args) < 1:
- print("Error: need to specify a version on the command line")
- return 3
-
- # determine remote dir dependent on provided version string
- version_base, version_rc, os_filter = parse_version_string(args[0])
- remote_dir = f"/bin/{VERSIONPREFIX}{version_base}/"
- if version_rc:
- remote_dir += f"test.{version_rc}/"
- remote_sigfile = remote_dir + SIGNATUREFILENAME
-
- # create working directory
- os.makedirs(WORKINGDIR, exist_ok=True)
- os.chdir(WORKINGDIR)
-
- # fetch first signature file
- sigfile1 = SIGNATUREFILENAME
- success, output = download_with_wget(HOST1 + remote_sigfile, sigfile1)
- if not success:
- print("Error: couldn't fetch signature file. "
- "Have you specified the version number in the following format?")
- print(f"[{VERSIONPREFIX}]<version>[-rc[0-9]][-platform] "
- f"(example: {VERSIONPREFIX}0.21.0-rc3-osx)")
- print("wget output:")
- print(indent(output, '\t'))
- return 4
-
- # fetch second signature file
- sigfile2 = SIGNATUREFILENAME + ".2"
- success, output = download_with_wget(HOST2 + remote_sigfile, sigfile2)
- if not success:
- print("bitcoin.org failed to provide signature file, "
- "but bitcoincore.org did?")
- print("wget output:")
- print(indent(output, '\t'))
- remove_files([sigfile1])
- return 5
-
- # ensure that both signature files are equal
- if not files_are_equal(sigfile1, sigfile2):
- print("bitcoin.org and bitcoincore.org signature files were not equal?")
- print(f"See files {WORKINGDIR}/{sigfile1} and {WORKINGDIR}/{sigfile2}")
- return 6
-
- # check signature and extract data into file
- retval, output = verify_with_gpg(sigfile1, HASHFILE)
- if retval != 0:
- if retval == 1:
- print("Bad signature.")
- elif retval == 2:
- print("gpg error. Do you have the Bitcoin Core binary release "
- "signing key installed?")
- print("gpg output:")
- print(indent(output, '\t'))
- remove_files([sigfile1, sigfile2, HASHFILE])
- return 1
-
- # extract hashes/filenames of binaries to verify from hash file;
- # each line has the following format: "<hash> <binary_filename>"
- with open(HASHFILE, 'r', encoding='utf8') as hash_file:
- hashes_to_verify = [
- line.split()[:2] for line in hash_file if os_filter in line]
- remove_files([HASHFILE])
- if not hashes_to_verify:
- print("error: no files matched the platform specified")
- return 7
-
- # download binaries
- for _, binary_filename in hashes_to_verify:
- print(f"Downloading {binary_filename}")
- download_with_wget(HOST1 + remote_dir + binary_filename)
-
- # verify hashes
- offending_files = []
- for hash_expected, binary_filename in hashes_to_verify:
- with open(binary_filename, 'rb') as binary_file:
- hash_calculated = sha256(binary_file.read()).hexdigest()
- if hash_calculated != hash_expected:
- offending_files.append(binary_filename)
- if offending_files:
- print("Hashes don't match.")
- print("Offending files:")
- print('\n'.join(offending_files))
- return 1
- verified_binaries = [entry[1] for entry in hashes_to_verify]
-
- # clean up files if desired
- if len(args) >= 2:
- print("Clean up the binaries")
- remove_files([sigfile1, sigfile2] + verified_binaries)
- else:
- print(f"Keep the binaries in {WORKINGDIR}")
-
- print("Verified hashes of")
- print('\n'.join(verified_binaries))
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))