net: repair DragonX peer discovery, broken three separate ways

A DRAGONX node had no working peer discovery. Both mechanisms were broken, and a
third bug hid the fact.

1. DNS seeds were Hush's, and all three are dead. chainparams_commandline() sets an
   assetchain's port, magic, blocktime, upgrade heights and checkpoints but never
   touches vSeeds or vFixedSeeds, so DRAGONX silently inherited CMainParams':
   seed1.hush.is, seed2.hush.is and dns.leto.net. None of the three has an A record
   any more -- verified against 1.1.1.1 and 8.8.8.8, with google.com and
   node1..node5.dragonx.is resolving fine from the same host as a control. Replaced
   with the five DragonX node hostnames, which do resolve and do listen.

2. Every fixed seed carried port 0. contrib/seeds/generate-seeds.py documents its
   input as <ip>:<port>, but contrib/seeds/nodes_main.txt held bare IPs, so
   parse_spec() took the port as empty and emitted 0x00,0x00 for all five entries.
   The fixed-seed fallback -- which exists precisely for when DNS seeding yields
   nothing -- was therefore handing out unconnectable addresses. Added the port to
   nodes_main.txt and regenerated; entries now end 0x55,0x08 (21768).

3. ThreadDNSAddressSeed never incremented `found`, so "%d addresses found from DNS
   seeds" printed 0 unconditionally, whether seeding worked or not. That is almost
   certainly why nobody noticed the seeds had gone dead: the one diagnostic that
   would have shown it was hardcoded to say zero.

Verified on a fresh datadir (empty addrman, separate ports, real node untouched):
DNS seeding now reports "5 addresses found from DNS seeds" where it previously
reported 0, and the fixed-seed path adds 5 entries carrying the correct port.

Note on scope: the five hostnames are single-A-record hosts, so each contributes one
address rather than the spread a real seeder returns. A dedicated DNS seeder, or
simply a round-robin A record over the seed set, would be the proper fix and needs
only a DNS change rather than a release. This restores a working discovery path;
it does not make it a good one.

Also corrected the generated header's #endif comment, which said
HUSH_CHAINPARAMSSEEDS_H while the guard is DRAGONX_CHAINPARAMSSEEDS_H.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-26 00:11:55 +02:00
parent 4dc57e80b1
commit 499f02a905
5 changed files with 35 additions and 17 deletions

View File

@@ -177,7 +177,7 @@ def main():
g.write('\n')
with open(os.path.join(indir,'nodes_test.txt'), 'r', encoding="utf8") as f:
process_nodes(g, f, 'chainparams_seed_test')
g.write('#endif // HUSH_CHAINPARAMSSEEDS_H\n')
g.write('#endif // DRAGONX_CHAINPARAMSSEEDS_H\n')
if __name__ == '__main__':
main()

View File

@@ -1,14 +1,17 @@
# generate-seeds.py expects <ip>:<port> (see its docstring). Without the port it
# emits 0, and every fixed seed becomes unconnectable -- which is what shipped:
# the whole chainparams_seed_main array carried 0x00,0x00 as the port.
# node1.dragonx.is
212.56.41.63
212.56.41.63:21768
# node2.dragonx.is
194.140.198.176
194.140.198.176:21768
# node3.dragonx.is
212.56.41.47
212.56.41.47:21768
# node4.dragonx.is
144.126.147.165
144.126.147.165:21768
# node5.dragonx.is
176.126.87.241
176.126.87.241:21768

View File

@@ -181,11 +181,25 @@ public:
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
vFixedSeeds.clear();
vSeeds.clear();
// Hush Official DNS Seeds
vSeeds.push_back(CDNSSeedData("node1", "seed1.hush.is"));
vSeeds.push_back(CDNSSeedData("node2", "seed2.hush.is"));
// Community run DNS Seeds
vSeeds.push_back(CDNSSeedData("node3", "dns.leto.net"));
// DragonX DNS seeds. These must be names that actually resolve.
//
// An assetchain INHERITS these: chainparams_commandline() sets the port, magic,
// blocktime, upgrade heights and checkpoints, but never touches vSeeds or
// vFixedSeeds. DRAGONX therefore ran on Hush's seeds -- seed1.hush.is,
// seed2.hush.is and dns.leto.net -- and all three have no A records left, so DNS
// seeding silently returned zero addresses on every start. The only bootstrap
// path that worked was the node1..node5.dragonx.is -addnode injection in
// hush_utils.h, which is almost certainly why that injection exists.
//
// These are single-A-record hosts, so each contributes one address rather than
// the spread a real seeder returns. That is still strictly better than nothing;
// a dedicated seeder (or a round-robin A record over the seed set) would be the
// proper fix and needs only a DNS change, not a release.
vSeeds.push_back(CDNSSeedData("node1", "node1.dragonx.is"));
vSeeds.push_back(CDNSSeedData("node2", "node2.dragonx.is"));
vSeeds.push_back(CDNSSeedData("node3", "node3.dragonx.is"));
vSeeds.push_back(CDNSSeedData("node4", "node4.dragonx.is"));
vSeeds.push_back(CDNSSeedData("node5", "node5.dragonx.is"));
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,60);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,85);

View File

@@ -11,14 +11,14 @@
// Each line contains a BIP155 serialized address.
//
static const uint8_t chainparams_seed_main[] = {
0x01,0x04,0xd4,0x38,0x29,0x3f,0x00,0x00, // 212.56.41.63
0x01,0x04,0xc2,0x8c,0xc6,0xb0,0x00,0x00, // 194.140.198.176
0x01,0x04,0xd4,0x38,0x29,0x2f,0x00,0x00, // 212.56.41.47
0x01,0x04,0x90,0x7e,0x93,0xa5,0x00,0x00, // 144.126.147.165
0x01,0x04,0xb0,0x7e,0x57,0xf1,0x00,0x00, // 176.126.87.241
0x01,0x04,0xd4,0x38,0x29,0x3f,0x55,0x08, // 212.56.41.63:21768
0x01,0x04,0xc2,0x8c,0xc6,0xb0,0x55,0x08, // 194.140.198.176:21768
0x01,0x04,0xd4,0x38,0x29,0x2f,0x55,0x08, // 212.56.41.47:21768
0x01,0x04,0x90,0x7e,0x93,0xa5,0x55,0x08, // 144.126.147.165:21768
0x01,0x04,0xb0,0x7e,0x57,0xf1,0x55,0x08, // 176.126.87.241:21768
};
static const uint8_t chainparams_seed_test[] = {
0x01,0x04,0x01,0x02,0x03,0x04,0x00,0x00, // 1.2.3.4
};
#endif // HUSH_CHAINPARAMSSEEDS_H
#endif // DRAGONX_CHAINPARAMSSEEDS_H

View File

@@ -1581,6 +1581,7 @@ void ThreadDNSAddressSeed()
CAddress addr = CAddress(CService(ip, ASSETCHAINS_P2PPORT));
addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
vAdd.push_back(addr);
found++;
}
}
// TODO: The seed name resolve may fail, yielding an IP of [::], which results in