3 # linearize-hashes.py: List blocks in a linear, no-fork version of the chain.
5 # Copyright (c) 2013-2016 The Bitcoin Core developers
6 # Distributed under the MIT software license, see the accompanying
7 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
10 from __future__
import print_function
12 import http
.client
as httplib
13 except ImportError: # Python 2
24 ##### Switch endian-ness #####
25 def hex_switchEndian(s
):
26 """ Switches the endianness of a hex string (in pairs of hex chars) """
27 pairList
= [s
[i
:i
+2].encode() for i
in range(0, len(s
), 2)]
28 return b
''.join(pairList
[::-1]).decode()
31 def __init__(self
, host
, port
, username
, password
):
32 authpair
= "%s:%s" % (username
, password
)
33 authpair
= authpair
.encode('utf-8')
34 self
.authhdr
= b
"Basic " + base64
.b64encode(authpair
)
35 self
.conn
= httplib
.HTTPConnection(host
, port
=port
, timeout
=30)
37 def execute(self
, obj
):
39 self
.conn
.request('POST', '/', json
.dumps(obj
),
40 { 'Authorization' : self
.authhdr
,
41 'Content-type' : 'application/json' })
42 except ConnectionRefusedError
:
43 print('RPC connection refused. Check RPC settings and the server status.',
47 resp
= self
.conn
.getresponse()
49 print("JSON-RPC: no response", file=sys
.stderr
)
52 body
= resp
.read().decode('utf-8')
53 resp_obj
= json
.loads(body
)
57 def build_request(idx
, method
, params
):
58 obj
= { 'version' : '1.1',
64 obj
['params'] = params
68 def response_is_error(resp_obj
):
69 return 'error' in resp_obj
and resp_obj
['error'] is not None
71 def get_block_hashes(settings
, max_blocks_per_call
=10000):
72 rpc
= BitcoinRPC(settings
['host'], settings
['port'],
73 settings
['rpcuser'], settings
['rpcpassword'])
75 height
= settings
['min_height']
76 while height
< settings
['max_height']+1:
77 num_blocks
= min(settings
['max_height']+1-height
, max_blocks_per_call
)
79 for x
in range(num_blocks
):
80 batch
.append(rpc
.build_request(x
, 'getblockhash', [height
+ x
]))
82 reply
= rpc
.execute(batch
)
84 print('Cannot continue. Program will halt.')
87 for x
,resp_obj
in enumerate(reply
):
88 if rpc
.response_is_error(resp_obj
):
89 print('JSON-RPC: error at height', height
+x
, ': ', resp_obj
['error'], file=sys
.stderr
)
91 assert(resp_obj
['id'] == x
) # assume replies are in-sequence
92 if settings
['rev_hash_bytes'] == 'true':
93 resp_obj
['result'] = hex_switchEndian(resp_obj
['result'])
94 print(resp_obj
['result'])
99 # Open the cookie file
100 with
open(os
.path
.join(os
.path
.expanduser(settings
['datadir']), '.cookie'), 'r') as f
:
101 combined
= f
.readline()
102 combined_split
= combined
.split(":")
103 settings
['rpcuser'] = combined_split
[0]
104 settings
['rpcpassword'] = combined_split
[1]
106 if __name__
== '__main__':
107 if len(sys
.argv
) != 2:
108 print("Usage: linearize-hashes.py CONFIG-FILE")
111 f
= open(sys
.argv
[1])
114 m
= re
.search('^\s*#', line
)
118 # parse key=value lines
119 m
= re
.search('^(\w+)\s*=\s*(\S.*)$', line
)
122 settings
[m
.group(1)] = m
.group(2)
125 if 'host' not in settings
:
126 settings
['host'] = '127.0.0.1'
127 if 'port' not in settings
:
128 settings
['port'] = 8332
129 if 'min_height' not in settings
:
130 settings
['min_height'] = 0
131 if 'max_height' not in settings
:
132 settings
['max_height'] = 313000
133 if 'rev_hash_bytes' not in settings
:
134 settings
['rev_hash_bytes'] = 'false'
138 if 'rpcuser' not in settings
or 'rpcpassword' not in settings
:
140 if 'datadir' in settings
and not use_userpass
:
142 if not use_userpass
and not use_datadir
:
143 print("Missing datadir or username and/or password in cfg file", file=stderr
)
146 settings
['port'] = int(settings
['port'])
147 settings
['min_height'] = int(settings
['min_height'])
148 settings
['max_height'] = int(settings
['max_height'])
150 # Force hash byte format setting to be lowercase to make comparisons easier.
151 settings
['rev_hash_bytes'] = settings
['rev_hash_bytes'].lower()
153 # Get the rpc user and pass from the cookie if the datadir is set
157 get_block_hashes(settings
)