Skip to content

net: Regenerate the mainnet fixed seeds for the BLAKE2b network - #394

Open
jasonsopko wants to merge 5 commits into
bitcoinknots:29.x-knotsfrom
jasonsopko:seeds-blake2b
Open

jasonsopko wants to merge 5 commits into
bitcoinknots:29.x-knotsfrom
jasonsopko:seeds-blake2b

Conversation

@jasonsopko

@jasonsopko jasonsopko commented Sep 6, 2026 •

Copy link
Copy Markdown

What

Regenerates the compiled-in mainnet seeds from the current seeder dumps so that nodes_main.txt and chainparamsseeds.h agree again, adds -u/--uptime-window to makeseeds.py so a network younger than 30 days can be seeded at all, and lets -s take several dump files directly.

Why

A fresh node that gets no DNS answer within 60 seconds falls back to the compiled-in list, and two of the DNS seeds serve x10000009 answers today (Luke's and Leo Haf's; #437 adds a third), so the fallback matters more than it used to. In 29.4.1 that list was the one crawled before the proof-of-work change: of its 1,306 entries, 1,188 have no BLAKE2B bit in the seeder dumps, and only a peer with that bit can serve the header chain past the fork. The header was regenerated on 2026-09-20 and 29.4.2 ships that one, 394 entries with 386 BLAKE2b Knots nodes among them in the 2026-10-04 dumps, but nodes_main.txt was not: it is still the list of 2025 with 2,031 entries, and generate-seeds.py run on the tree does not produce the header in the tree.

makeseeds.py requires 50% uptime over 30 days. A node first probed at the change needs about three weeks to reach that on the seeders' 30-day column, so the first list here used the 7-day column of the same dumps; the option stays for the next network younger than its filter. The current list uses the default.

-s took one concatenated file. LionThunderFingers hit a dump without a trailing newline, whose last line merged into the next dump's first; -s now takes the files one by one.

How I tested

The list is LionThunderFingers' regeneration of 2026-10-03: the README pipeline with the default window over the dumps of Luke Dashjr, Leo Haf, sipa, 21.ninja, achow101 and seed.thelionpool.org. 240 entries: 61 IPv4, 12 IPv6, 97 onion, 70 I2P, plus the 2 cjdns seeds carried over from the 29.4.2 header, which none of the dumps list, 242 in all. I checked every entry against the same six dumps fetched 2026-10-04: all 240 advertise the BLAKE2B bit at a height past 961640 with a Knots agent string, 215 seen within the last day and the other 25 between 47 hours and 21 days before. The header in 29.4.2, decoded and checked the same way: 394 entries, 85 IPv4, 12 IPv6, 175 onion, 120 I2P, 2 CJDNS; 386 pass, 2 have no bit, 3 are not Knots, 1 is behind, 2 are in no dump; 320 seen within the last day, the oldest 25 days before. The new list is smaller, two weeks fresher, and reproducible from the tree: generate-seeds.py reproduces chainparamsseeds.h from it byte for byte. 2rdzy's handshake test and my 2026-09-11 check cover the first list (127 entries, 2026-09-06) and are in the comments.

Risk and rollback

Only affects the fixed-seed fallback, which a node loads when its addrman is empty for a reachable network. Rollback is reverting the last commit and then the regeneration commit.

Edit: the list is now the 2026-10-03 regeneration (240 entries) with the -s change. What, Why, How I tested and Risk are rewritten to match; the earlier Edit line and the "Still unsure about" section are gone, since makeseeds.py has required the BLAKE2B service bit since 418f6ae and that settles the MIN_BLOCKS question. The text before this edit covered the 127-entry list of 2026-09-06 that the first comments refer to.

Edit 2: one commit added on top. The regeneration had put the testnet4 fixed seeds of 2025 back and dropped the two cjdns seeds; nodes_testnet4.txt now holds the 48 entries the 29.4.2 header ships and the cjdns addresses are in nodes_main.txt, so the whole header reproduces from the tree. How I tested now counts the 2 cjdns seeds, 242 entries. Risk no longer says a dead entry costs at most three failed attempts before addrman drops it, which was wrong, and the rollback now takes two reverts. Details in the comment posted with this edit.

@2rdzy

2rdzy commented Sep 9, 2026

Copy link
Copy Markdown

Tested bca354c.

Built on Linux/gcc, daemon-only:

cmake -B build -DENABLE_WALLET=OFF -DBUILD_GUI=OFF
cmake --build build -j$(nproc) --target bitcoind bitcoin-cli

Clearnet — fresh datadir, DNS and inbound off:

bitcoind -datadir=<fresh> -dnsseed=0 -listen=0 -debug=net

59 of the 127 entries loaded (clearnet only). 5 dialed, all 5 completed a
handshake; 2 (165.173.19.136, 162.229.22.126) were closed by the remote
within a second, no error given; 3 held (135.180.233.81, 207.81.196.105,
188.27.84.62), all reporting blocks=970318 (past the 961640 change) and
the BLAKE2B service bit.

Onion / I2P — same isolation, via a local Tor 0.4.9.11 + i2pd 2.59.0:

bitcoind -datadir=<fresh> -dnsseed=0 -listen=0 -onlynet=i2p -i2psam=127.0.0.1:7656
bitcoind -datadir=<fresh> -dnsseed=0 -listen=0 -onlynet=onion -onion=127.0.0.1:9050

I2P: 31 entries loaded, 3 dialed, 2 held, both genuinely on this chain
(Knots:20260508, blocks=970332, BLAKE2B).

Onion: 37 entries loaded, 9 dialed, 5 completed a handshake before I
stopped the node. Of the other 4: 3 were still mid-connect when I stopped
testing, 1 failed outright about 30s earlier (host unreachable). Of the 5
that completed, only 2 are actually running Knots:

habnl624ma73ppxpw5urkp3drjiry2criaolabrujp27laqgczxbqfyd.onion  Knots:20260508rc4   blocks=970332  BLAKE2B
vuvdmgbjtujzr74hfeee4aik72wcs6z5jxx4doj5r2xapbv2i6zw3wyd.onion  Knots:20260508      blocks=970332  BLAKE2B
mvzi3o46ldq4r5kzurcnn7o4gprwqsxc7o4dvgjm4agyhrv2hoyf5rid.onion  Satoshi:31.1.0      blocks=966267  (no BLAKE2B)
v7izfunvqpm754jda6xjwupegwsl36roeeokhe3uxf43uzmgjnggmiad.onion  Satoshi:28.1.0      blocks=966267  (no BLAKE2B)
p2ysyflsxjygwtr46u66sh56baajfpjnie2ayygicw4jzsbdyone7yyd.onion  Satoshi:29.1.0      blocks=966267

3 of 5 are plain Bitcoin Core, confirmed from their version message, not
Knots. Not necessarily a defect in this PR — the service bit is only as
fresh as the crawl, and fixed seeds are a "probably still there" list by
nature — but worth flagging: most of this (small) onion sample no longer
points at a fork node.

Separately, contrib/seeds/generate-seeds.py contrib/seeds reproduces
src/chainparamsseeds.h byte-for-byte from the nodes_main.txt in this
commit, and the list composition (52 IPv4 / 7 IPv6 / 37 onion / 31 I2P)
matches the PR description.

Unit tests (693 cases), p2p_dns_seeds.py, and p2p_seednode.py all pass on
this branch.

@jasonsopko

Copy link
Copy Markdown
Author

The three Core nodes are not in this list. mvzi3o46…, v7izfunv… and p2ysyflsx… do not appear in nodes_main.txt, and the seeders have had all three on file as Core (28.1.0, 29.1.0, 30.2.0 then 31.1.0) without the BLAKE2B bit since at least April, so no crawl with the 0x10000009 filter could have picked them up. Your node got them from addr gossip: the fixed-seed peers you handshaked first relay addresses out of their own addrman, which is still mostly pre-change nodes, and once those land in yours they are dialed like any other entry. The two Knots onions you held, habnl624… and vuvdmgbj…, are both in the list. #398 is the change that stops a node from dialing peers it would drop at the handshake.

The two clearnet peers that closed on you, 165.173.19.136 and 162.229.22.126, are in the list too, and the seeders saw both as Knots 29.4.1 with the bit tonight, so that was not a chain mismatch either. Why they closed I do not know; I did not look at their side.

I checked the whole list against tonight's seeder dumps (fetched 2026-09-11 00:37Z). All 127 entries still advertise the bit at BLAKE2b heights. Of the 59 clearnet entries, 47 were reached within the last day, 4 within the week, 8 not in the last week. The onion and I2P rows cannot be re-checked that way: the seeder they come from last reached each of the 68 between 08-30 and 09-06, and most of its onion rows look like that, so your two handshakes are the freshest data on that set.

The list ages from the day it is cut. It should be regenerated from that day's dumps when this merges, with the pipeline in the description, rather than patched one entry at a time.

@LionThunderFingers

LionThunderFingers commented Oct 3, 2026 •

Copy link
Copy Markdown

Regenerated the mainnet fixed seeds using this PR's method
Dumps from Luke, Léo Haf, sipa, 21.ninja, achow101, and my own seed.
The fork is past 30 days old now so I dropped the -u 7 workaround from Jason's tests and used the plain default window.

240 entries (61 IPv4, 12 IPv6, 97 onion, 70 I2P), mainnet only.

Also fixed makeseeds.py -s to take multiple source files directly instead of requiring them pre-concatenated in the shell
One raw dump had no trailing newline, which silently merged into the next file's first line and crashed the script with an unrelated looking error.
Parsing each file separately before concatenation avoids that regardless of what a source ends with.

I Don't have push access to the branch so here's the files... Hope it's helpful:

jasonsopko and others added 4 commits October 4, 2026 15:00
makeseeds.py judges every node on its 30-day uptime. A node that
joined the network at the BLAKE2b hardfork on 2026-08-30 cannot pass
a 50% 30-day threshold until the end of September no matter how
reliable it is, so a regeneration today keeps only nodes that were
already running before the fork and drops the rest.

Add -u/--uptime-window with choices 7 and 30 (default 30, unchanged
behavior). With -u 7 the 7-day column from the same seeder dumps is
used for the threshold and the sort. Checked that the default output
is unchanged and that -u 7 admits the post-fork nodes.
Regenerated nodes_main.txt and chainparamsseeds.h on 2026-10-03 with
the README pipeline and the tool's default 30-day uptime window, from
the dumps of Luke Dashjr, Léo Haf, sipa, 21.ninja, achow101 and
seed.thelionpool.org.

240 entries: 61 IPv4, 12 IPv6, 97 onion, 70 I2P. Only the mainnet
section changes; testnet, testnet4 and signet are byte-identical.
The documented pipeline concatenates several seeders' raw dumps in the
shell before handing them to makeseeds.py. If any source file is
missing a trailing newline, that file's last line silently merges
into the next file's first line when concatenated, corrupting both:
hit this firsthand when doing the regen above (Luke Dashjr's dump had
no trailing newline), and it produced a confusing crash
(ValueError: invalid literal for int() with base 10: 'address') three
steps removed from the actual cause.

-s now takes one or more files and parses each separately before
combining, so this failure mode can't happen regardless of what a
source file ends with. README's documented commands are updated to
write each source to its own file rather than relying on shell
>/>> concatenation.
The 2026-10-03 regeneration read it alongside the other five, so the
README should list it for the next run.
@jasonsopko

Copy link
Copy Markdown
Author

Pulled in, thank you. The branch is now your regeneration and your -s change on the current 29.x-knots tip, with you as author and the two regeneration commits squashed into one, my -u commit ahead of them, and two lines from me adding your dump to the README pipeline. Previous head bca354c.

I checked all 240 entries against the six dumps fetched 2026-10-04 17:43Z: every one advertises the BLAKE2B bit at a height past 961640 with a Knots agent string, 215 seen within the last day and the other 25 between 47 hours and 21 days before. generate-seeds.py reproduces chainparamsseeds.h from your nodes_main.txt byte for byte. For comparison, the header in 29.4.2, regenerated 2026-09-20 and not reproducible from the nodes_main.txt in the tree, has 394 entries, 386 of them passing the same check and 320 seen within the last day; yours is smaller and fresher, and the body has the split.

On sources: achow101's dump carries onion and I2P BLAKE2b nodes as well, 902 of the 1,082 distinct ones across the six dumps today against 961 in yours, so the README lists yours with the other five.

The 2026-10-03 regeneration ran generate-seeds.py over the whole tree,
and nodes_testnet4.txt was still Core's list of 2025-03-06. The header
Luke regenerated on 2026-09-20 (ae8cbd9) replaced the testnet4 array
with 48 entries without updating that file, so the generator put the
151 old entries back. The two mainnet cjdns seeds Leo Haf added by hand
in 3ca6d37 were never in nodes_main.txt and dropped out the same way.
The regeneration commit's claim that testnet4 is byte-identical was
wrong.

Write the 48 shipped testnet4 entries to nodes_testnet4.txt and append
the two cjdns addresses to nodes_main.txt. generate-seeds.py reproduces
the header from the tree, and the testnet, testnet4 and signet arrays
are byte-identical to the 29.x-knots tip. Found by kwsantiago while
assembling the 29.4.3rc1 spec (luke-jr/tmp#4).
@jasonsopko

Copy link
Copy Markdown
Author

kwsantiago found two problems with the 2026-10-03 regeneration while assembling the 29.4.3rc1 spec (luke-jr/tmp#4), and both are real. It put Core's testnet4 fixed seeds of 2025-03-06 back, because nodes_testnet4.txt was never updated when the header was regenerated on 2026-09-20, and it dropped the two mainnet cjdns seeds that were only ever in the header. The regeneration commit says testnet4 is byte-identical. It is not. I checked the mainnet array and should have checked the others.

The new head adds one commit on top of the four: nodes_testnet4.txt is now the 48 entries the 29.4.2 header ships, the two cjdns addresses are appended to nodes_main.txt, and generate-seeds.py reproduces the whole header from the tree. The testnet, testnet4 and signet arrays are byte-identical to the 29.x-knots tip, and mainnet is the same 240 entries plus the 2 cjdns, 242 in all.

@kwsantiago the spec's extra commit restores the header but leaves nodes_testnet4.txt behind it, so generate-seeds.py does not reproduce that tree's header. This head does both, so if k394 is rebased from this head that commit can go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants