tx-v1-to-v3.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #!/usr/bin/env python3
  2. # Convert MMGen 'v1' transaction file (extension '.raw' or '.sig')
  3. # to MMGen 'v3' ('.rawtx' or '.sigtx' + amounts as strings)
  4. import sys,os
  5. repo_root = os.path.split(os.path.abspath(os.path.dirname(sys.argv[0])))[0]
  6. sys.path = [repo_root] + sys.path
  7. from mmgen.common import *
  8. opts_data = lambda: {
  9. 'desc': "Convert MMGen transaction file from v1 format to v3 format",
  10. 'usage': "<tx file>",
  11. 'options': """
  12. -h, --help Print this help message
  13. -d, --outdir=d Output files to directory 'd' instead of working dir
  14. -q, --quiet Write (and overwrite) files without prompting
  15. -S, --stdout Write data to STDOUT instead of file
  16. """
  17. }
  18. cmd_args = opts.init(opts_data)
  19. from mmgen.tx import *
  20. if len(cmd_args) != 1: opts.usage()
  21. def parse_tx_file(infile):
  22. from ast import literal_eval
  23. def eval_io_data(raw_data,desc):
  24. import re
  25. d = literal_eval(re.sub(r"[A-Za-z]+?\(('.+?')\)",r'\1',raw_data))
  26. assert type(d) == list,'{} data not a list!'.format(desc)
  27. assert len(d),'no {}!'.format(desc)
  28. for e in d: e['amount'] = g.proto.coin_amt(e['amount'])
  29. return d
  30. err_fmt = 'Invalid {} in transaction file'
  31. tx_data = get_lines_from_file(infile)
  32. try:
  33. err_str = 'number of lines'
  34. assert len(tx_data) in (4,5)
  35. if len(tx_data) == 5:
  36. metadata,tx_hex,inputs,outputs,comment = tx_data
  37. elif len(tx_data) == 4:
  38. metadata,tx_hex,inputs,outputs = tx_data
  39. comment = ''
  40. err_str = 'metadata'
  41. assert len(metadata.split()) == 3
  42. err_str = 'hex data'
  43. unhexlify(tx_hex)
  44. err_str = 'inputs data'
  45. inputs = eval_io_data(inputs,'inputs')
  46. err_str = 'btc-to-mmgen address map data'
  47. outputs = literal_eval(outputs)
  48. if comment:
  49. from mmgen.bitcoin import b58decode
  50. comment = b58decode(comment)
  51. if comment == False:
  52. err_str = 'encoded comment (not base58)'
  53. else:
  54. err_str = 'comment'
  55. comment = MMGenTXLabel(comment)
  56. except:
  57. die(2,err_fmt.format(err_str))
  58. else:
  59. return metadata.split(),tx_hex,inputs,outputs,comment
  60. def find_block_by_time(timestamp):
  61. secs = decode_timestamp(timestamp)
  62. block_num = g.rpch.getblockcount()
  63. # print 'secs:',secs, 'last block:',last_block
  64. top,bot = block_num,0
  65. m = 'Searching for block'
  66. msg_r(m)
  67. for i in range(40):
  68. msg_r('.')
  69. bhash = g.rpch.getblockhash(block_num)
  70. block = g.rpch.getblock(bhash)
  71. # print 'block_num:',block_num, 'mediantime:',block['mediantime'], 'target:',secs
  72. cur_secs = block['mediantime']
  73. if cur_secs > secs:
  74. top = block_num
  75. else:
  76. bot = block_num
  77. block_num = (top + bot) / 2
  78. if top - bot < 2:
  79. msg('\nFound: {} '.format(block_num))
  80. break
  81. return block_num
  82. tx = MMGenTX()
  83. metadata,tx.hex,inputs,outputs,tx.label = parse_tx_file(cmd_args[0])
  84. tx.txid,send_amt,tx.timestamp = metadata
  85. tx.send_amt = Decimal(send_amt)
  86. g.testnet = False
  87. g.rpc_host = 'localhost'
  88. rpc_init()
  89. for i in inputs:
  90. if not 'mmid' in i and 'account' in i:
  91. lbl = TwLabel(i['account'])
  92. i['mmid'] = lbl.mmid
  93. i['comment'] = lbl.comment
  94. tx.inputs = tx.MMGenTxInputList(tx.decode_io_oldfmt(inputs))
  95. if tx.marked_signed():
  96. msg('Transaction is signed')
  97. dec_tx = g.rpch.decoderawtransaction(tx.hex)
  98. tx.outputs = tx.MMGenTxOutputList(
  99. MMGenTX.MMGenTxOutput(addr=i['scriptPubKey']['addresses'][0],
  100. amt=g.proto.coin_amt(i['value']))
  101. for i in dec_tx['vout'])
  102. for e in tx.outputs:
  103. if e.addr in outputs:
  104. f = outputs[e.addr]
  105. e.mmid = f[0]
  106. if f[1]: e.label = f[1].decode('utf8')
  107. else:
  108. for f in tx.inputs:
  109. if e.addr == f.addr and f.mmid:
  110. e.mmid = f.mmid
  111. if f.label: e.label = f.label.decode('utf8')
  112. tx.blockcount = find_block_by_time(tx.timestamp)
  113. tx.write_to_file(ask_tty=False,ask_overwrite=not opt.quiet,ask_write=not opt.quiet)