您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

linearize-hashes.py 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #!/usr/bin/env python3
  2. #
  3. # linearize-hashes.py: List blocks in a linear, no-fork version of the chain.
  4. #
  5. # Copyright (c) 2013-2017 The Starwels developers
  6. # Distributed under the MIT software license, see the accompanying
  7. # file COPYING or http://www.opensource.org/licenses/mit-license.php.
  8. #
  9. from __future__ import print_function
  10. try: # Python 3
  11. import http.client as httplib
  12. except ImportError: # Python 2
  13. import httplib
  14. import json
  15. import re
  16. import base64
  17. import sys
  18. import os
  19. import os.path
  20. settings = {}
  21. ##### Switch endian-ness #####
  22. def hex_switchEndian(s):
  23. """ Switches the endianness of a hex string (in pairs of hex chars) """
  24. pairList = [s[i:i+2].encode() for i in range(0, len(s), 2)]
  25. return b''.join(pairList[::-1]).decode()
  26. class StarwelsRPC:
  27. def __init__(self, host, port, username, password):
  28. authpair = "%s:%s" % (username, password)
  29. authpair = authpair.encode('utf-8')
  30. self.authhdr = b"Basic " + base64.b64encode(authpair)
  31. self.conn = httplib.HTTPConnection(host, port=port, timeout=30)
  32. def execute(self, obj):
  33. try:
  34. self.conn.request('POST', '/', json.dumps(obj),
  35. { 'Authorization' : self.authhdr,
  36. 'Content-type' : 'application/json' })
  37. except ConnectionRefusedError:
  38. print('RPC connection refused. Check RPC settings and the server status.',
  39. file=sys.stderr)
  40. return None
  41. resp = self.conn.getresponse()
  42. if resp is None:
  43. print("JSON-RPC: no response", file=sys.stderr)
  44. return None
  45. body = resp.read().decode('utf-8')
  46. resp_obj = json.loads(body)
  47. return resp_obj
  48. @staticmethod
  49. def build_request(idx, method, params):
  50. obj = { 'version' : '1.1',
  51. 'method' : method,
  52. 'id' : idx }
  53. if params is None:
  54. obj['params'] = []
  55. else:
  56. obj['params'] = params
  57. return obj
  58. @staticmethod
  59. def response_is_error(resp_obj):
  60. return 'error' in resp_obj and resp_obj['error'] is not None
  61. def get_block_hashes(settings, max_blocks_per_call=10000):
  62. rpc = StarwelsRPC(settings['host'], settings['port'],
  63. settings['rpcuser'], settings['rpcpassword'])
  64. height = settings['min_height']
  65. while height < settings['max_height']+1:
  66. num_blocks = min(settings['max_height']+1-height, max_blocks_per_call)
  67. batch = []
  68. for x in range(num_blocks):
  69. batch.append(rpc.build_request(x, 'getblockhash', [height + x]))
  70. reply = rpc.execute(batch)
  71. if reply is None:
  72. print('Cannot continue. Program will halt.')
  73. return None
  74. for x,resp_obj in enumerate(reply):
  75. if rpc.response_is_error(resp_obj):
  76. print('JSON-RPC: error at height', height+x, ': ', resp_obj['error'], file=sys.stderr)
  77. sys.exit(1)
  78. assert(resp_obj['id'] == x) # assume replies are in-sequence
  79. if settings['rev_hash_bytes'] == 'true':
  80. resp_obj['result'] = hex_switchEndian(resp_obj['result'])
  81. print(resp_obj['result'])
  82. height += num_blocks
  83. def get_rpc_cookie():
  84. # Open the cookie file
  85. with open(os.path.join(os.path.expanduser(settings['datadir']), '.cookie'), 'r') as f:
  86. combined = f.readline()
  87. combined_split = combined.split(":")
  88. settings['rpcuser'] = combined_split[0]
  89. settings['rpcpassword'] = combined_split[1]
  90. if __name__ == '__main__':
  91. if len(sys.argv) != 2:
  92. print("Usage: linearize-hashes.py CONFIG-FILE")
  93. sys.exit(1)
  94. f = open(sys.argv[1])
  95. for line in f:
  96. # skip comment lines
  97. m = re.search('^\s*#', line)
  98. if m:
  99. continue
  100. # parse key=value lines
  101. m = re.search('^(\w+)\s*=\s*(\S.*)$', line)
  102. if m is None:
  103. continue
  104. settings[m.group(1)] = m.group(2)
  105. f.close()
  106. if 'host' not in settings:
  107. settings['host'] = '127.0.0.1'
  108. if 'port' not in settings:
  109. settings['port'] = 8342
  110. if 'min_height' not in settings:
  111. settings['min_height'] = 0
  112. if 'max_height' not in settings:
  113. settings['max_height'] = 313000
  114. if 'rev_hash_bytes' not in settings:
  115. settings['rev_hash_bytes'] = 'false'
  116. use_userpass = True
  117. use_datadir = False
  118. if 'rpcuser' not in settings or 'rpcpassword' not in settings:
  119. use_userpass = False
  120. if 'datadir' in settings and not use_userpass:
  121. use_datadir = True
  122. if not use_userpass and not use_datadir:
  123. print("Missing datadir or username and/or password in cfg file", file=sys.stderr)
  124. sys.exit(1)
  125. settings['port'] = int(settings['port'])
  126. settings['min_height'] = int(settings['min_height'])
  127. settings['max_height'] = int(settings['max_height'])
  128. # Force hash byte format setting to be lowercase to make comparisons easier.
  129. settings['rev_hash_bytes'] = settings['rev_hash_bytes'].lower()
  130. # Get the rpc user and pass from the cookie if the datadir is set
  131. if use_datadir:
  132. get_rpc_cookie()
  133. get_block_hashes(settings)