halving-calculator.py 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. #!/usr/bin/env python3
  2. # Demonstrates use of the MMGen asyncio/aiohttp JSON-RPC interface
  3. # https://github.com/mmgen/mmgen
  4. import time
  5. from decimal import Decimal
  6. from mmgen.common import *
  7. opts.init({
  8. 'text': {
  9. 'desc': 'Estimate date of next block subsidy halving',
  10. 'usage':'[opts]',
  11. 'options': """
  12. -h, --help Print this help message
  13. --, --longhelp Print help message for long options (common options)
  14. -s, --sample-size=N Specify sample block range for block discovery time
  15. estimate
  16. """,
  17. 'notes': """
  18. Requires a running coin daemon
  19. Specify coin with --coin=btc (default)/--coin=bch/--coin=ltc
  20. If necessary, invoke with --rpc-host/--rpc-port/--rpc-user/--rpc-password
  21. Specify aiohttp backend with --rpc-backend=aiohttp (Linux only)
  22. """
  23. }
  24. })
  25. def date(t):
  26. return '{}-{:02}-{:02} {:02}:{:02}:{:02}'.format(*time.gmtime(t)[:6])
  27. def dhms(t):
  28. t,neg = (-t,'-') if t < 0 else (t,' ')
  29. return f'{neg}{t//60//60//24} days, {t//60//60%24:02}:{t//60%60:02}:{t%60:02} h/m/s'
  30. def time_diff_warning(t_diff):
  31. if abs(t_diff) > 60*60:
  32. print('Warning: block tip time is {} {} clock time!'.format(
  33. dhms(abs(t_diff)),
  34. ('behind','ahead of')[t_diff<0]))
  35. async def main():
  36. from mmgen.protocol import init_proto_from_opts
  37. proto = init_proto_from_opts()
  38. from mmgen.rpc import rpc_init
  39. c = await rpc_init(proto)
  40. tip = await c.call('getblockcount')
  41. assert tip > 1, 'block tip must be > 1'
  42. remaining = proto.halving_interval - tip % proto.halving_interval
  43. sample_size = int(opt.sample_size) if opt.sample_size else min(tip-1,max(remaining,144))
  44. # aiohttp backend will perform these two calls concurrently:
  45. cur,old = await c.gathered_call('getblockstats',((tip,),(tip - sample_size,)))
  46. clock_time = int(time.time())
  47. time_diff_warning(clock_time - cur['time'])
  48. bdr = (cur['time'] - old['time']) / sample_size
  49. t_rem = remaining * int(bdr)
  50. sub = cur['subsidy'] * Decimal('0.00000001')
  51. print(f'Current block: {tip}')
  52. print(f'Next halving block: {tip + remaining}')
  53. print(f'Blocks until halving: {remaining}')
  54. print('Current block subsidy: {} {}'.format(str(sub).rstrip('0'),proto.coin))
  55. print(f'Current block discovery rate (over last {sample_size} blocks): {bdr/60:0.1f} minutes')
  56. print(f'Current clock time (UTC): {date(clock_time)}')
  57. print(f'Est. halving date (UTC): {date(cur["time"] + t_rem)}')
  58. print(f'Est. time until halving: {dhms(cur["time"] + t_rem - clock_time)}')
  59. run_session(main())