mmnode-blocks-info 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2017 Philemon <mmgen-py@yandex.com>
  5. #
  6. # This program is free software: you can redistribute it and/or modify it under
  7. # the terms of the GNU General Public License as published by the Free Software
  8. # Foundation, either version 3 of the License, or (at your option) any later
  9. # version.
  10. #
  11. # This program is distributed in the hope that it will be useful, but WITHOUT
  12. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  13. # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  14. # details.
  15. #
  16. # You should have received a copy of the GNU General Public License along with
  17. # this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. mmgen-blocks-info: Display information about a block or range of blocks
  20. """
  21. import time,re
  22. from mmgen.common import *
  23. opts_data = lambda: {
  24. 'desc': 'Display information about or find a transaction within a range of blocks',
  25. 'usage': '[opts] +<last n blocks>|<block num>|<block num range>',
  26. 'options': """
  27. -h, --help Print this help message
  28. --, --longhelp Print help message for long options (common options)
  29. -H, --hashes Display only block numbers and hashes
  30. -m, --miner-info Display miner info in coinbase transaction
  31. -n, --nya Display NYA (New York Agreement) support
  32. -M, --raw-miner-info Display miner info in uninterpreted form
  33. -s, --summary Print the summary only
  34. -t, --transaction=t Search for transaction 't' in specified block range
  35. If no block number is specified, the current block is assumed
  36. """
  37. }
  38. cmd_args = opts.init(opts_data)
  39. if len(cmd_args) not in (0,1): opts.usage()
  40. if opt.raw_miner_info: opt.miner_info = True
  41. c = rpc_init()
  42. cur_blk = c.getblockcount()
  43. arg = cmd_args[0] if cmd_args else None
  44. if not arg:
  45. first = last = cur_blk
  46. elif arg[0] == '+' and is_int(arg[1:]):
  47. last = cur_blk
  48. first = last - int(arg[1:]) + 1
  49. elif is_int(arg):
  50. first = last = int(arg)
  51. else:
  52. try:
  53. a,b = arg.split('-')
  54. assert is_int(a) and is_int(b)
  55. first,last = int(a),int(b)
  56. except:
  57. opts.usage()
  58. if first > last:
  59. die(2,'{}: invalid block range'.format(arg))
  60. if last > cur_blk:
  61. die(2,'Requested block number ({}) greater than current block height'.format(last))
  62. if opt.summary:
  63. pass
  64. elif opt.transaction:
  65. if len(opt.transaction) != 64 or not is_hex_str(opt.transaction):
  66. die(2,'{}: invalid transaction id'.format(opt.transaction))
  67. elif opt.hashes:
  68. Msg('{:<7} {}'.format('BLOCK','HASH'))
  69. else:
  70. if opt.miner_info:
  71. fs='{:<6} {:<19}{:>9} {:>6} {:>7} {:8} {}'
  72. Msg(fs.format('BLOCK','DATE','INTERVAL','CONFS','SIZE','VERSION','MINER'))
  73. else:
  74. fs='{:<6} {:<19}{:>9} {:>6} {:>7} {}'
  75. Msg(fs.format('BLOCK','DATE','INTERVAL','CONFS','SIZE','VERSION'))
  76. miner_strings = {
  77. 'Bixin':'Bixin',
  78. 'AntPool':'AntPool',
  79. 'Bitfury':'Bitfury',
  80. 'BTCC':'BTCC',
  81. 'BTC.COM':'BTC.COM',
  82. 'BTPOOL':'BTPOOL',
  83. 'ViaBTC':'ViaBTC',
  84. 'slush':'Slush',
  85. 'BitMinter':'BitMinter',
  86. 'BW.COM':'BW.COM',
  87. 'gbminers':'GBMiners',
  88. 'BitClub Network':'BitClub Network',
  89. 'bitcoin.com':'bitcoin.com',
  90. 'KanoPool':'KanoPool',
  91. 'BTC.TOP':'BTC.TOP',
  92. }
  93. total,prev_time = 0,None
  94. for i in range(first,last+1):
  95. b = c.getblock(c.getblockhash(i))
  96. total += b['size']
  97. if opt.transaction:
  98. if opt.transaction in b['tx']:
  99. Msg('Requested transaction is in block {}'.format(i))
  100. sys.exit(0)
  101. msg('Checking block {}'.format(i))
  102. else:
  103. gmt = time.gmtime(b['mediantime'])
  104. date = '{}-{:02}-{:02} {:02}:{:02}:{:02}'.format(*gmt[:6])
  105. if prev_time == None:
  106. b_prev = b if i == 0 else c.getblock(c.getblockhash(i-1))
  107. first_time = prev_time = b_prev['mediantime']
  108. et = b['mediantime'] - prev_time
  109. prev_time = b['mediantime']
  110. if opt.summary:
  111. continue
  112. if opt.hashes:
  113. Msg('{:<7} {}'.format(i,b['hash']))
  114. else:
  115. d = (i,date,'{}:{:02}'.format(et//60,et%60),b['confirmations'],b['size'],b['versionHex'])
  116. if opt.miner_info:
  117. bd = c.getrawtransaction(b['tx'][0],1,on_fail='silent')
  118. if type(bd) == tuple:
  119. Msg(fs.format(*(d+('---',))))
  120. else:
  121. cb = unhexlify(bd['vin'][0]['coinbase'])
  122. scb = re.sub(b'[^\w /-:,;.]',b'',cb)[1:]
  123. if opt.raw_miner_info:
  124. Msg(fs.format(*(d+(scb.decode(),))))
  125. else:
  126. for ms in miner_strings:
  127. if ms.encode() in scb:
  128. s = miner_strings[ms]
  129. break
  130. else:
  131. try: s = scb.split('ined by')[1].strip()
  132. except: s = '??'
  133. nya_str = (b' ',b'NYA ')[b'NYA' in scb] if opt.nya else b''
  134. Msg(fs.format(*(d+(nya_str.decode()+s,))))
  135. else:
  136. Msg(fs.format(*d))
  137. if opt.transaction:
  138. from mmgen.rpc import rpc_error
  139. if rpc_error(c.getmempoolentry(opt.transaction,on_fail='silent')):
  140. Msg('\rTransaction not found in block range {}-{} or in mempool'.format(first,last))
  141. else:
  142. Msg('\rTransaction is in mempool')
  143. else:
  144. blocks = last - first + 1
  145. if blocks > 1:
  146. fs2 = '{:<15} {}\n'
  147. et = b['mediantime'] - first_time
  148. ac = int(et / blocks)
  149. if not opt.summary: Msg('')
  150. Msg_r( fs2.format('Range:','{}-{} ({} blocks)'.format(first,last,blocks)) +
  151. fs2.format('Avg size:','{} bytes'.format(total//blocks)) +
  152. fs2.format('MB/hr:','{:0.5f}'.format(float(total)*36/10000/et)) +
  153. fs2.format('Avg conf time:','{}:{:02}'.format(ac//60,ac%60)))