2 # Copyright (c) 2014-2017 Wladimir J. van der Laan
3 # Distributed under the MIT software license, see the accompanying
4 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 Script to generate list of seed nodes for chainparams.cpp.
8 This script expects two text files in the directory that is passed as an
14 These files must consist of lines in the format
21 0xDDBBCCAA (IPv4 little-endian old pnSeeds format)
23 The output will be two data structures with the peers in binary format:
25 static SeedSpec6 pnSeed6_main[]={
28 static SeedSpec6 pnSeed6_test[]={
32 These should be pasted into `src/chainparamsseeds.h`.
35 from base64
import b32decode
36 from binascii
import a2b_hex
41 pchIPv4
= bytearray([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff])
42 # tor-specific ipv6 prefix
43 pchOnionCat
= bytearray([0xFD,0x87,0xD8,0x7E,0xEB,0x43])
45 def name_to_ipv6(addr
):
46 if len(addr
)>6 and addr
.endswith('.onion'):
47 vchAddr
= b32decode(addr
[0:-6], True)
48 if len(vchAddr
) != 16-len(pchOnionCat
):
49 raise ValueError('Invalid onion %s' % s
)
50 return pchOnionCat
+ vchAddr
51 elif '.' in addr
: # IPv4
52 return pchIPv4
+ bytearray((int(x
) for x
in addr
.split('.')))
53 elif ':' in addr
: # IPv6
54 sub
= [[], []] # prefix, suffix
56 addr
= addr
.split(':')
57 for i
,comp
in enumerate(addr
):
59 if i
== 0 or i
== (len(addr
)-1): # skip empty component at beginning or end
61 x
+= 1 # :: skips to suffix
63 else: # two bytes per component
65 sub
[x
].append(val
>> 8)
66 sub
[x
].append(val
& 0xff)
67 nullbytes
= 16 - len(sub
[0]) - len(sub
[1])
68 assert((x
== 0 and nullbytes
== 0) or (x
== 1 and nullbytes
> 0))
69 return bytearray(sub
[0] + ([0] * nullbytes
) + sub
[1])
70 elif addr
.startswith('0x'): # IPv4-in-little-endian
71 return pchIPv4
+ bytearray(reversed(a2b_hex(addr
[2:])))
73 raise ValueError('Could not parse address %s' % addr
)
75 def parse_spec(s
, defaultport
):
76 match
= re
.match('\[([0-9a-fA-F:]+)\](?::([0-9]+))?$', s
)
80 elif s
.count(':') > 1: # ipv6, no port
84 (host
,_
,port
) = s
.partition(':')
91 host
= name_to_ipv6(host
)
95 def process_nodes(g
, f
, structname
, defaultport
):
96 g
.write('static SeedSpec6 %s[] = {\n' % structname
)
99 comment
= line
.find('#')
101 line
= line
[0:comment
]
109 (host
,port
) = parse_spec(line
, defaultport
)
110 hoststr
= ','.join(('0x%02x' % b
) for b
in host
)
111 g
.write(' {{%s}, %i}' % (hoststr
, port
))
116 print(('Usage: %s <path_to_nodes_txt>' % sys
.argv
[0]), file=sys
.stderr
)
120 g
.write('#ifndef BITCOIN_CHAINPARAMSSEEDS_H\n')
121 g
.write('#define BITCOIN_CHAINPARAMSSEEDS_H\n')
123 g
.write(' * List of fixed seed nodes for the bitcoin network\n')
124 g
.write(' * AUTOGENERATED by contrib/seeds/generate-seeds.py\n')
126 g
.write(' * Each line contains a 16-byte IPv6 address and a port.\n')
127 g
.write(' * IPv4 as well as onion addresses are wrapped inside a IPv6 address accordingly.\n')
129 with
open(os
.path
.join(indir
,'nodes_main.txt'),'r') as f
:
130 process_nodes(g
, f
, 'pnSeed6_main', 8333)
132 with
open(os
.path
.join(indir
,'nodes_test.txt'),'r') as f
:
133 process_nodes(g
, f
, 'pnSeed6_test', 18333)
134 g
.write('#endif // BITCOIN_CHAINPARAMSSEEDS_H\n')
136 if __name__
== '__main__':