electrum-bitcoinprivate/contrib/zclassic/btc2zclassic.py

127 lines
3.5 KiB
Python
Executable File

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Search and replaces BTC addresses and private keys in WIF to bitcoinprivate variant"""
import click
import imp
import re
imp.load_module('lib', *imp.find_module('../../lib'))
from lib.bitcoin import (b58_address_to_hash160, hash160_to_b58_address,
base_decode, serialize_privkey, DecodeBase58Check,
SCRIPT_TYPES)
from lib.util import inv_dict, to_bytes
from lib.constants import net
ADDR_PATTERN = re.compile(
'([123456789ABCDEFGHJKLMNPQRSTUVWXYZ'
'abcdefghijkmnopqrstuvwxyz]{20,180})')
def b58_address_to_hash160_btc(addr):
addr = to_bytes(addr, 'ascii')
_bytes = base_decode(addr, 25, base=58)
return _bytes[0], _bytes[1:21]
def deserialize_btc_priv(val):
try:
vch = DecodeBase58Check(val)
except:
return None, None, None
if vch[0] != 0x80:
return None, None, None
if len(vch) not in [33, 34]:
return None, None, None
txin_type = inv_dict(SCRIPT_TYPES)[vch[0] - 0x80]
compressed = len(vch) == 34
return txin_type, vch[1:33], compressed
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
@click.command(context_settings=CONTEXT_SETTINGS)
@click.option('-i', '--input-file', required=True,
help='Input file')
@click.option('-n', '--dry-run', is_flag=True,
help='Only show what will be changed')
@click.option('-o', '--output-file',
help='Output file')
@click.option('-p', '--inplace', is_flag=True,
help='Replace data inplace')
def main(**kwargs):
input_file = kwargs.pop('input_file')
output_file = kwargs.pop('output_file', None)
inplace = kwargs.pop('inplace', False)
dry_run = kwargs.pop('dry_run', False)
if inplace:
output_file = input_file
olines = []
total_sub = 0
for ln, l in enumerate(open(input_file, 'r').read().splitlines()):
pos = 0
ol = ''
while pos < len(l):
m = ADDR_PATTERN.search(l, pos)
if not m:
ol += l[pos:]
break
ol += l[pos:m.start()]
val = m.group()
try:
addrtype, h = b58_address_to_hash160_btc(val)
except:
h = None
if h and addrtype == 0:
new_val = hash160_to_b58_address(h, net.ADDRTYPE_P2PKH)
total_sub +=1
elif h and addrtype == 5:
new_val = hash160_to_b58_address(h, net.ADDRTYPE_P2SH)
total_sub +=1
else:
new_val = None
if not new_val:
try:
txin_type, privkey, compressed = deserialize_btc_priv(val)
except Exception as e:
privkey = None
if privkey:
new_val = serialize_privkey(privkey, compressed, txin_type,
internal_use=True)
if dry_run and new_val:
print('line %s, col %s: %s => %s' % (
ln, m.start(), val, new_val
))
ol += new_val if new_val else val
pos = m.end()
olines.append(ol)
out = '\n'.join(olines)
if not output_file:
print(out)
elif not dry_run:
with open(output_file, 'w') as wfd:
wfd.write('%s\n' % out)
else:
print('Total sub count:', total_sub)
if __name__ == '__main__':
main()