commit d304ccdf17be860b2828c1b6b31a6ba7aaa32020
parent 5be78950ca31ba903b4bd0f575511eeb732e114c
Author: Dmitry Sorokin <asfins@gmail.com>
Date: Mon, 30 Jan 2017 12:36:56 +0300
py3 in qtgui
Diffstat:
28 files changed, 255 insertions(+), 332 deletions(-)
diff --git a/electrum b/electrum
@@ -48,11 +48,11 @@ if jnius:
threading.Thread.run = thread_check_run
# monkeypatch unicode constructor for py3
-if six.PY3:
- import builtins
- builtins.unicode = str
- builtins.QString = str
- builtins.long = int
+# if six.PY3:
+# import builtins
+ # builtins.unicode = str
+ # builtins.QString = str
+ # builtins.long = int
script_dir = os.path.dirname(os.path.realpath(__file__))
is_bundle = getattr(sys, 'frozen', False)
diff --git a/gui/qt/address_list.py b/gui/qt/address_list.py
@@ -48,7 +48,7 @@ class AddressList(MyTreeWidget):
def on_update(self):
self.wallet = self.parent.wallet
item = self.currentItem()
- current_address = item.data(0, Qt.UserRole).toString() if item else None
+ current_address = item.data(0, Qt.UserRole) if item else None
self.clear()
receiving_addresses = self.wallet.get_receiving_addresses()
change_addresses = self.wallet.get_change_addresses()
@@ -97,7 +97,7 @@ class AddressList(MyTreeWidget):
can_delete = self.wallet.can_delete_address()
selected = self.selectedItems()
multi_select = len(selected) > 1
- addrs = [unicode(item.text(0)) for item in selected]
+ addrs = [item.text(0) for item in selected]
if not addrs:
return
if not multi_select:
diff --git a/gui/qt/amountedit.py b/gui/qt/amountedit.py
@@ -37,7 +37,7 @@ class AmountEdit(MyLineEdit):
return 8
def numbify(self):
- text = unicode(self.text()).strip()
+ text = self.text().strip()
if text == '!':
self.shortcut.emit()
return
diff --git a/gui/qt/console.py b/gui/qt/console.py
@@ -76,7 +76,7 @@ class Console(QtGui.QPlainTextEdit):
def getCommand(self):
doc = self.document()
- curr_line = unicode(doc.findBlockByLineNumber(doc.lineCount() - 1).text())
+ curr_line = doc.findBlockByLineNumber(doc.lineCount() - 1).text()
curr_line = curr_line.rstrip()
curr_line = curr_line[len(self.prompt):]
return curr_line
@@ -86,7 +86,7 @@ class Console(QtGui.QPlainTextEdit):
return
doc = self.document()
- curr_line = unicode(doc.findBlockByLineNumber(doc.lineCount() - 1).text())
+ curr_line = doc.findBlockByLineNumber(doc.lineCount() - 1).text()
self.moveCursor(QtGui.QTextCursor.End)
for i in range(len(curr_line) - len(self.prompt)):
self.moveCursor(QtGui.QTextCursor.Left, QtGui.QTextCursor.KeepAnchor)
@@ -95,7 +95,6 @@ class Console(QtGui.QPlainTextEdit):
self.textCursor().insertText(command)
self.moveCursor(QtGui.QTextCursor.End)
-
def show_completions(self, completions):
if self.completions_visible:
self.hide_completions()
@@ -113,7 +112,6 @@ class Console(QtGui.QPlainTextEdit):
self.moveCursor(QtGui.QTextCursor.End)
self.completions_visible = True
-
def hide_completions(self):
if not self.completions_visible:
return
@@ -125,7 +123,6 @@ class Console(QtGui.QPlainTextEdit):
self.moveCursor(QtGui.QTextCursor.End)
self.completions_visible = False
-
def getConstruct(self, command):
if self.construct:
prev_command = self.construct[-1]
diff --git a/gui/qt/contact_list.py b/gui/qt/contact_list.py
@@ -55,7 +55,7 @@ class ContactList(MyTreeWidget):
def on_edited(self, item, column, prior):
if column == 0: # Remove old contact if renamed
self.parent.contacts.pop(prior)
- self.parent.set_contact(unicode(item.text(0)), unicode(item.text(1)))
+ self.parent.set_contact(item.text(0), item.text(1))
def import_contacts(self):
wallet_folder = self.parent.get_wallet_folder()
@@ -72,11 +72,11 @@ class ContactList(MyTreeWidget):
menu.addAction(_("New contact"), lambda: self.parent.new_contact_dialog())
menu.addAction(_("Import file"), lambda: self.parent.import_contacts())
else:
- names = [unicode(item.text(0)) for item in selected]
- keys = [unicode(item.text(1)) for item in selected]
+ names = [item.text(0) for item in selected]
+ keys = [item.text(1) for item in selected]
column = self.currentColumn()
column_title = self.headerItem().text(column)
- column_data = '\n'.join([unicode(item.text(column)) for item in selected])
+ column_data = '\n'.join([item.text(column) for item in selected])
menu.addAction(_("Copy %s")%column_title, lambda: self.parent.app.clipboard().setText(column_data))
if column in self.editable_columns:
menu.addAction(_("Edit %s")%column_title, lambda: self.editItem(item, column))
@@ -91,7 +91,7 @@ class ContactList(MyTreeWidget):
def on_update(self):
item = self.currentItem()
- current_key = item.data(0, Qt.UserRole).toString() if item else None
+ current_key = item.data(0, Qt.UserRole) if item else None
self.clear()
for key in sorted(self.parent.contacts.keys()):
_type, name = self.parent.contacts[key]
diff --git a/gui/qt/history_list.py b/gui/qt/history_list.py
@@ -77,7 +77,7 @@ class HistoryList(MyTreeWidget):
self.wallet = self.parent.wallet
h = self.wallet.get_history(self.get_domain())
item = self.currentItem()
- current_tx = item.data(0, Qt.UserRole).toString() if item else None
+ current_tx = item.data(0, Qt.UserRole) if item else None
self.clear()
fx = self.parent.fx
if fx: fx.history_used_spot = False
@@ -128,7 +128,7 @@ class HistoryList(MyTreeWidget):
child_count = root.childCount()
for i in range(child_count):
item = root.child(i)
- txid = str(item.data(0, Qt.UserRole).toString())
+ txid = item.data(0, Qt.UserRole)
label = self.wallet.get_label(txid)
item.setText(3, label)
@@ -147,7 +147,7 @@ class HistoryList(MyTreeWidget):
if not item:
return
column = self.currentColumn()
- tx_hash = str(item.data(0, Qt.UserRole).toString())
+ tx_hash = item.data(0, Qt.UserRole)
if not tx_hash:
return
if column is 0:
diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py
@@ -444,8 +444,8 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
@wizard_dialog
def choice_dialog(self, title, message, choices, run_next):
- c_values = map(lambda x: x[0], choices)
- c_titles = map(lambda x: x[1], choices)
+ c_values = [x[0] for x in choices]
+ c_titles = [x[1] for x in choices]
clayout = ChoicesLayout(message, c_titles)
vbox = QVBoxLayout()
vbox.addLayout(clayout.layout())
@@ -473,7 +473,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
vbox.addWidget(line)
vbox.addWidget(WWLabel(warning))
self.exec_layout(vbox, title, next_enabled=test(default))
- return ' '.join(unicode(line.text()).split())
+ return ' '.join(line.text().split())
@wizard_dialog
def show_xpub_dialog(self, xpub, run_next):
diff --git a/gui/qt/invoice_list.py b/gui/qt/invoice_list.py
@@ -73,8 +73,10 @@ class InvoiceList(MyTreeWidget):
def create_menu(self, position):
menu = QMenu()
item = self.itemAt(position)
- key = str(item.data(0, 32).toString())
- column = self.currentColumn()
+ if not item:
+ return
+ key = item.data(0, 32)
+ column = self.currentColumn()
column_title = self.headerItem().text(column)
column_data = item.text(column)
pr = self.parent.invoices.get(key)
diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
@@ -384,7 +384,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def open_wallet(self):
wallet_folder = self.get_wallet_folder()
- filename = unicode(QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder))
+ filename = QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder)
if not filename:
return
self.gui_object.new_window(filename)
@@ -393,7 +393,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def backup_wallet(self):
path = self.wallet.storage.path
wallet_folder = os.path.dirname(path)
- filename = unicode( QFileDialog.getSaveFileName(self, _('Enter a filename for the copy of your wallet'), wallet_folder) )
+ filename = QFileDialog.getSaveFileName(self, _('Enter a filename for the copy of your wallet'), wallet_folder)
if not filename:
return
@@ -578,16 +578,16 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
# custom wrappers for getOpenFileName and getSaveFileName, that remember the path selected by the user
def getOpenFileName(self, title, filter = ""):
- directory = self.config.get('io_dir', unicode(os.path.expanduser('~')))
- fileName = unicode( QFileDialog.getOpenFileName(self, title, directory, filter) )
+ directory = self.config.get('io_dir', os.path.expanduser('~'))
+ fileName = QFileDialog.getOpenFileName(self, title, directory, filter)
if fileName and directory != os.path.dirname(fileName):
self.config.set_key('io_dir', os.path.dirname(fileName), True)
return fileName
def getSaveFileName(self, title, filename, filter = ""):
- directory = self.config.get('io_dir', unicode(os.path.expanduser('~')))
+ directory = self.config.get('io_dir', os.path.expanduser('~'))
path = os.path.join( directory, filename )
- fileName = unicode( QFileDialog.getSaveFileName(self, title, path, filter) )
+ fileName = QFileDialog.getSaveFileName(self, title, path, filter)
if fileName and directory != os.path.dirname(fileName):
self.config.set_key('io_dir', os.path.dirname(fileName), True)
return fileName
@@ -880,7 +880,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def save_payment_request(self):
addr = str(self.receive_address_e.text())
amount = self.receive_amount_e.get_amount()
- message = unicode(self.receive_message_e.text())
+ message = self.receive_message_e.text()
if not message and not amount:
self.show_error(_('No message or amount'))
return False
@@ -982,7 +982,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def update_receive_qr(self):
addr = str(self.receive_address_e.text())
amount = self.receive_amount_e.get_amount()
- message = unicode(self.receive_message_e.text()).encode('utf8')
+ message = self.receive_message_e.text()
self.save_request_button.setEnabled((amount is not None) or (message != ""))
uri = util.create_URI(addr, amount, message)
self.receive_qr.setData(uri)
@@ -1281,7 +1281,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
if self.payment_request and self.payment_request.has_expired():
self.show_error(_('Payment request has expired'))
return
- label = unicode( self.message_e.text() )
+ label = self.message_e.text()
if self.payment_request:
outputs = self.payment_request.get_outputs()
@@ -1513,7 +1513,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
if not URI:
return
try:
- out = util.parse_URI(unicode(URI), self.on_pr)
+ out = util.parse_URI(URI, self.on_pr)
except BaseException as e:
self.show_error(_('Invalid bitcoin URI:') + '\n' + str(e))
return
@@ -1807,7 +1807,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
vbox.addLayout(grid)
vbox.addLayout(Buttons(CancelButton(d), OkButton(d)))
if d.exec_():
- self.set_contact(unicode(line2.text()), str(line1.text()))
+ self.set_contact(line2.text(), line1.text())
def show_master_public_keys(self):
dialog = WindowModalDialog(self, "Master Public Keys")
@@ -1848,7 +1848,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
except BaseException as e:
self.show_error(str(e))
return
- from seed_dialog import SeedDialog
+ from .seed_dialog import SeedDialog
d = SeedDialog(self, seed, passphrase)
d.exec_()
@@ -1889,7 +1889,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
@protected
def do_sign(self, address, message, signature, password):
address = str(address.text()).strip()
- message = unicode(message.toPlainText()).encode('utf-8').strip()
+ message = message.toPlainText().strip()
if not bitcoin.is_address(address):
self.show_message('Invalid Bitcoin address.')
return
@@ -1906,7 +1906,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def do_verify(self, address, message, signature):
address = str(address.text()).strip()
- message = unicode(message.toPlainText()).encode('utf-8').strip()
+ message = message.toPlainText().strip()
if not bitcoin.is_address(address):
self.show_message('Invalid Bitcoin address.')
return
@@ -1970,10 +1970,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
self.wallet.thread.add(task, on_success=message_e.setText)
def do_encrypt(self, message_e, pubkey_e, encrypted_e):
- message = unicode(message_e.toPlainText())
+ message = message_e.toPlainText()
message = message.encode('utf-8')
try:
- encrypted = bitcoin.encrypt_message(message, str(pubkey_e.text()))
+ encrypted = bitcoin.encrypt_message(message, pubkey_e.text())
encrypted_e.setText(encrypted)
except BaseException as e:
traceback.print_exc(file=sys.stdout)
@@ -2386,7 +2386,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
lang_label = HelpLabel(_('Language') + ':', lang_help)
lang_combo = QComboBox()
from electrum.i18n import languages
- lang_combo.addItems(languages.values())
+ lang_combo.addItems(list(languages.values()))
try:
index = languages.keys().index(self.config.get("language",''))
except Exception:
@@ -2570,7 +2570,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
msg = _("Install the zbar package to enable this.")
qr_label = HelpLabel(_('Video Device') + ':', msg)
qr_combo.setEnabled(qrscanner.libzbar is not None)
- on_video_device = lambda x: self.config.set_key("video_device", str(qr_combo.itemData(x).toString()), True)
+ on_video_device = lambda x: self.config.set_key("video_device", qr_combo.itemData(x), True)
qr_combo.currentIndexChanged.connect(on_video_device)
gui_widgets.append((qr_label, qr_combo))
diff --git a/gui/qt/network_dialog.py b/gui/qt/network_dialog.py
@@ -386,7 +386,7 @@ class NetworkChoiceLayout(object):
def change_protocol(self, use_ssl):
p = 's' if use_ssl else 't'
- host = unicode(self.server_host.text())
+ host = self.server_host.text()
pp = self.servers.get(host, DEFAULT_PORTS)
if p not in pp.keys():
p = pp.keys()[0]
diff --git a/gui/qt/password_dialog.py b/gui/qt/password_dialog.py
@@ -44,7 +44,7 @@ def check_password_strength(password):
:param password: password entered by user in New Password
:return: password strength Weak or Medium or Strong
'''
- password = unicode(password)
+ password = password
n = math.log(len(set(password)))
num = re.search("[0-9]", password) is not None and re.match("^[0-9]*$", password) is None
caps = password != password.upper() and password != password.lower()
@@ -156,11 +156,11 @@ class PasswordLayout(object):
def old_password(self):
if self.kind == PW_CHANGE:
- return unicode(self.pw.text()) or None
+ return self.pw.text() or None
return None
def new_password(self):
- pw = unicode(self.new_pw.text())
+ pw = self.new_pw.text()
# Empty passphrases are fine and returned empty.
if pw == "" and self.kind != PW_PASSPHRASE:
pw = None
diff --git a/gui/qt/paytoedit.py b/gui/qt/paytoedit.py
@@ -120,7 +120,7 @@ class PayToEdit(ScanQRTextEdit):
if self.is_pr:
return
# filter out empty lines
- lines = filter(lambda x: x, self.lines())
+ lines = [i for i in self.lines() if i]
outputs = []
total = 0
self.payto_address = None
@@ -180,7 +180,7 @@ class PayToEdit(ScanQRTextEdit):
return self.outputs[:]
def lines(self):
- return unicode(self.toPlainText()).split('\n')
+ return self.toPlainText().split('\n')
def is_multiline(self):
return len(self.lines()) > 1
@@ -242,14 +242,14 @@ class PayToEdit(ScanQRTextEdit):
QPlainTextEdit.keyPressEvent(self, e)
ctrlOrShift = e.modifiers() and (Qt.ControlModifier or Qt.ShiftModifier)
- if self.c is None or (ctrlOrShift and e.text().isEmpty()):
+ if self.c is None or (ctrlOrShift and not e.text()):
return
- eow = QString("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-=")
- hasModifier = (e.modifiers() != Qt.NoModifier) and not ctrlOrShift;
+ eow = "~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="
+ hasModifier = (e.modifiers() != Qt.NoModifier) and not ctrlOrShift
completionPrefix = self.textUnderCursor()
- if hasModifier or e.text().isEmpty() or completionPrefix.length() < 1 or eow.contains(e.text().right(1)):
+ if hasModifier or not e.text() or completionPrefix.length() < 1 or eow.contains(e.text().right(1)):
self.c.popup().hide()
return
diff --git a/gui/qt/qrtextedit.py b/gui/qt/qrtextedit.py
@@ -22,11 +22,11 @@ class ShowQRTextEdit(ButtonsTextEdit):
run_hook('show_text_edit', self)
def qr_show(self):
- from qrcodewidget import QRDialog
+ from .qrcodewidget import QRDialog
try:
s = str(self.toPlainText())
except:
- s = unicode(self.toPlainText())
+ s = self.toPlainText()
QRDialog(s).exec_()
def contextMenuEvent(self, e):
@@ -45,7 +45,7 @@ class ScanQRTextEdit(ButtonsTextEdit, MessageBoxMixin):
run_hook('scan_text_edit', self)
def file_input(self):
- fileName = unicode(QFileDialog.getOpenFileName(self, 'select file'))
+ fileName = QFileDialog.getOpenFileName(self, 'select file')
if not fileName:
return
with open(fileName, "r") as f:
diff --git a/gui/qt/seed_dialog.py b/gui/qt/seed_dialog.py
@@ -52,7 +52,6 @@ def seed_warning_msg(seed):
]) % len(seed.split())
-
class SeedLayout(QVBoxLayout):
#options
is_bip39 = False
@@ -92,7 +91,6 @@ class SeedLayout(QVBoxLayout):
self.is_ext = cb_ext.isChecked() if 'ext' in self.options else False
self.is_bip39 = cb_bip39.isChecked() if 'bip39' in self.options else False
-
def __init__(self, seed=None, title=None, icon=True, msg=None, options=None, is_seed=None, passphrase=None, parent=None):
QVBoxLayout.__init__(self)
self.parent = parent
@@ -140,7 +138,7 @@ class SeedLayout(QVBoxLayout):
self.addWidget(self.seed_warning)
def get_seed(self):
- text = unicode(self.seed_e.text())
+ text = self.seed_e.text()
return ' '.join(text.split())
def on_edit(self):
@@ -159,7 +157,6 @@ class SeedLayout(QVBoxLayout):
self.parent.next_button.setEnabled(b)
-
class KeysLayout(QVBoxLayout):
def __init__(self, parent=None, title=None, is_valid=None):
QVBoxLayout.__init__(self)
@@ -171,7 +168,7 @@ class KeysLayout(QVBoxLayout):
self.addWidget(self.text_e)
def get_text(self):
- return unicode(self.text_e.text())
+ return self.text_e.text()
def on_edit(self):
b = self.is_valid(self.get_text())
diff --git a/gui/qt/util.py b/gui/qt/util.py
@@ -260,7 +260,7 @@ def line_dialog(parent, title, label, ok_label, default=None):
l.addWidget(txt)
l.addLayout(Buttons(CancelButton(dialog), OkButton(dialog, ok_label)))
if dialog.exec_():
- return unicode(txt.text())
+ return txt.text()
def text_dialog(parent, title, label, ok_label, default=None):
from qrtextedit import ScanQRTextEdit
@@ -275,7 +275,7 @@ def text_dialog(parent, title, label, ok_label, default=None):
l.addWidget(txt)
l.addLayout(Buttons(CancelButton(dialog), OkButton(dialog, ok_label)))
if dialog.exec_():
- return unicode(txt.toPlainText())
+ return txt.toPlainText()
class ChoicesLayout(object):
def __init__(self, msg, choices, on_clicked=None, checked_index=0):
@@ -341,15 +341,15 @@ def filename_field(parent, config, defaultname, select_msg):
hbox = QHBoxLayout()
- directory = config.get('io_dir', unicode(os.path.expanduser('~')))
+ directory = config.get('io_dir', os.path.expanduser('~'))
path = os.path.join( directory, defaultname )
filename_e = QLineEdit()
filename_e.setText(path)
def func():
- text = unicode(filename_e.text())
+ text = filename_e.text()
_filter = "*.csv" if text.endswith(".csv") else "*.json" if text.endswith(".json") else None
- p = unicode( QFileDialog.getSaveFileName(None, select_msg, text, _filter))
+ p = QFileDialog.getSaveFileName(None, select_msg, text, _filter)
if p:
filename_e.setText(p)
@@ -360,7 +360,7 @@ def filename_field(parent, config, defaultname, select_msg):
vbox.addLayout(hbox)
def set_csv(v):
- text = unicode(filename_e.text())
+ text = filename_e.text()
text = text.replace(".json",".csv") if v else text.replace(".csv",".json")
filename_e.setText(text)
@@ -409,7 +409,7 @@ class MyTreeWidget(QTreeWidget):
def editItem(self, item, column):
if column in self.editable_columns:
- self.editing_itemcol = (item, column, unicode(item.text(column)))
+ self.editing_itemcol = (item, column, item.text(column))
# Calling setFlags causes on_changed events for some reason
item.setFlags(item.flags() | Qt.ItemIsEditable)
QTreeWidget.editItem(self, item, column)
@@ -471,7 +471,7 @@ class MyTreeWidget(QTreeWidget):
def on_edited(self, item, column, prior):
'''Called only when the text actually changes'''
key = str(item.data(0, Qt.UserRole).toString())
- text = unicode(item.text(column))
+ text = item.text(column)
self.parent.wallet.set_label(key, text)
self.parent.history_list.update_labels()
self.parent.update_completions()
@@ -501,10 +501,10 @@ class MyTreeWidget(QTreeWidget):
def filter(self, p):
columns = self.__class__.filter_columns
- p = unicode(p).lower()
+ p = p.lower()
self.current_filter = p
for item in self.get_leaves(self.invisibleRootItem()):
- item.setHidden(all([unicode(item.text(column)).lower().find(p) == -1
+ item.setHidden(all([item.text(column).lower().find(p) == -1
for column in columns]))
diff --git a/gui/qt/utxo_list.py b/gui/qt/utxo_list.py
@@ -63,7 +63,7 @@ class UTXOList(MyTreeWidget):
self.addChild(utxo_item)
def create_menu(self, position):
- selected = [str(x.data(0, Qt.UserRole).toString()) for x in self.selectedItems()]
+ selected = [x.data(0, Qt.UserRole) for x in self.selectedItems()]
if not selected:
return
menu = QMenu()
diff --git a/lib/bitcoin.py b/lib/bitcoin.py
@@ -28,10 +28,11 @@ import hashlib
import base64
import re
import hmac
+import os
from lib.util import bfh, bh2u
from . import version
-from .util import print_error, InvalidPassword, assert_bytes, _bytes, to_bytes
+from .util import print_error, InvalidPassword, assert_bytes, to_bytes
import ecdsa
import pyaes
@@ -206,12 +207,12 @@ def op_push(i):
def sha256(x):
x = to_bytes(x, 'utf8')
- return _bytes(hashlib.sha256(x).digest())
+ return bytes(hashlib.sha256(x).digest())
def Hash(x):
x = to_bytes(x, 'utf8')
- out = _bytes(sha256(sha256(x)))
+ out = bytes(sha256(sha256(x)))
return out
@@ -363,7 +364,7 @@ def base_decode(v, length, base):
chars = __b43chars
long_value = 0
for (i, c) in enumerate(v[::-1]):
- long_value += chars.find(_bytes([c])) * (base**i)
+ long_value += chars.find(bytes([c])) * (base**i)
result = bytearray()
while long_value >= 256:
div, mod = divmod(long_value, 256)
diff --git a/lib/commands.py b/lib/commands.py
@@ -243,8 +243,8 @@ class Commands:
tx = Transaction(tx)
if privkey:
pubkey = bitcoin.public_key_from_private_key(privkey)
- h160 = bitcoin.hash_160(pubkey.decode('hex'))
- x_pubkey = 'fd' + (chr(0) + h160).encode('hex')
+ h160 = bitcoin.hash_160(bfh(pubkey))
+ x_pubkey = 'fd' + bh2u(b'\x00' + h160)
tx.sign({x_pubkey:privkey})
else:
self.wallet.sign_transaction(tx, password)
@@ -266,8 +266,8 @@ class Commands:
def createmultisig(self, num, pubkeys):
"""Create multisig address"""
assert isinstance(pubkeys, list), (type(num), type(pubkeys))
- redeem_script = transaction.multisig_script(pubkeys, num)
- address = bitcoin.hash160_to_p2sh(hash_160(redeem_script.decode('hex')))
+ redeem_script = Transaction.multisig_script(pubkeys, num)
+ address = bitcoin.hash160_to_p2sh(hash_160(bfh(redeem_script)))
return {'address':address, 'redeemScript':redeem_script}
@command('w')
diff --git a/lib/daemon.py b/lib/daemon.py
@@ -33,8 +33,9 @@ import os
import sys
import time
-# import jsonrpclib
-# from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer, SimpleJSONRPCRequestHandler
+# from jsonrpc import JSONRPCResponseManager
+import jsonrpclib
+from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer, SimpleJSONRPCRequestHandler
from .version import ELECTRUM_VERSION
from .network import Network
@@ -47,12 +48,15 @@ from .simple_config import SimpleConfig
from .plugins import run_hook
from .exchange_rate import FxThread
+
def get_lockfile(config):
return os.path.join(config.path, 'daemon')
+
def remove_lockfile(lockfile):
os.unlink(lockfile)
+
def get_fd_or_server(config):
'''Tries to create the lockfile, using O_EXCL to
prevent races. If it succeeds it returns the FD.
@@ -71,6 +75,7 @@ def get_fd_or_server(config):
# Couldn't connect; remove lockfile and try again.
remove_lockfile(lockfile)
+
def get_server(config):
lockfile = get_lockfile(config)
while True:
@@ -82,7 +87,8 @@ def get_server(config):
# Test daemon is running
server.ping()
return server
- except:
+ except Exception as e:
+ print_error(e)
pass
if not create_time or create_time < time.time() - 1.0:
return None
@@ -90,17 +96,17 @@ def get_server(config):
time.sleep(1.0)
-# class RequestHandler(SimpleJSONRPCRequestHandler):
-#
-# def do_OPTIONS(self):
-# self.send_response(200)
-# self.end_headers()
-#
-# def end_headers(self):
-# self.send_header("Access-Control-Allow-Headers",
-# "Origin, X-Requested-With, Content-Type, Accept")
-# self.send_header("Access-Control-Allow-Origin", "*")
-# SimpleJSONRPCRequestHandler.end_headers(self)
+class RequestHandler(SimpleJSONRPCRequestHandler):
+
+ def do_OPTIONS(self):
+ self.send_response(200)
+ self.end_headers()
+
+ def end_headers(self):
+ self.send_header("Access-Control-Allow-Headers",
+ "Origin, X-Requested-With, Content-Type, Accept")
+ self.send_header("Access-Control-Allow-Origin", "*")
+ SimpleJSONRPCRequestHandler.end_headers(self)
class Daemon(DaemonThread):
@@ -129,12 +135,12 @@ class Daemon(DaemonThread):
try:
server = SimpleJSONRPCServer((host, port), logRequests=False,
requestHandler=RequestHandler)
- except:
- self.print_error('Warning: cannot initialize RPC server on host', host)
+ except Exception as e:
+ self.print_error('Warning: cannot initialize RPC server on host', host, e)
self.server = None
os.close(fd)
return
- os.write(fd, repr((server.socket.getsockname(), time.time())))
+ os.write(fd, bytes(repr((server.socket.getsockname(), time.time())), 'utf8'))
os.close(fd)
server.timeout = 0.1
for cmdname in known_commands:
diff --git a/lib/exchange_rate.py b/lib/exchange_rate.py
@@ -290,7 +290,7 @@ class LocalBitcoins(ExchangeBase):
class MercadoBitcoin(ExchangeBase):
def get_rates(self, ccy):
- json = self.get_json('api.bitvalor.com', '/v1/ticker.json')
+ json = self.get_json('api.bitvalor.com', '/v1/ticker.json')
return {'BRL': Decimal(json['ticker_1h']['exchanges']['MBT']['last'])}
diff --git a/lib/interface.py b/lib/interface.py
@@ -38,6 +38,9 @@ import time
import traceback
import requests
+
+from lib import print_error
+
ca_path = requests.certs.where()
from . import util
@@ -60,6 +63,7 @@ def Connection(server, queue, config_path):
c.start()
return c
+
class TcpConnection(threading.Thread, util.PrintError):
def __init__(self, server, queue, config_path):
@@ -131,8 +135,9 @@ class TcpConnection(threading.Thread, util.PrintError):
return
# try with CA first
try:
- s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv23, cert_reqs=ssl.CERT_REQUIRED, ca_certs=ca_path, do_handshake_on_connect=True)
+ s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1_1, cert_reqs=ssl.CERT_REQUIRED, ca_certs=ca_path, do_handshake_on_connect=True)
except ssl.SSLError as e:
+ print_error(e)
s = None
if s and self.check_host_name(s.getpeercert(), self.host):
self.print_error("SSL certificate signed by CA")
@@ -143,7 +148,7 @@ class TcpConnection(threading.Thread, util.PrintError):
if s is None:
return
try:
- s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv23, cert_reqs=ssl.CERT_NONE, ca_certs=None)
+ s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1_1, cert_reqs=ssl.CERT_NONE, ca_certs=None)
except ssl.SSLError as e:
self.print_error("SSL error retrieving SSL certificate:", e)
return
@@ -166,9 +171,9 @@ class TcpConnection(threading.Thread, util.PrintError):
if self.use_ssl:
try:
s = ssl.wrap_socket(s,
- ssl_version=ssl.PROTOCOL_SSLv23,
+ ssl_version=ssl.PROTOCOL_TLSv1_1,
cert_reqs=ssl.CERT_REQUIRED,
- ca_certs= (temporary_path if is_new else cert_path),
+ ca_certs=(temporary_path if is_new else cert_path),
do_handshake_on_connect=True)
except ssl.SSLError as e:
self.print_error("SSL error:", e)
@@ -196,11 +201,11 @@ class TcpConnection(threading.Thread, util.PrintError):
os.unlink(cert_path)
return
self.print_error("wrong certificate")
+ if e.errno == 104:
+ return
return
except BaseException as e:
self.print_error(e)
- if e.errno == 104:
- return
traceback.print_exc(file=sys.stderr)
return
@@ -216,6 +221,7 @@ class TcpConnection(threading.Thread, util.PrintError):
self.print_error("connected")
self.queue.put((self.server, socket))
+
class Interface(util.PrintError):
"""The Interface class handles a socket connected to a single remote
electrum server. It's exposed API is:
@@ -274,7 +280,7 @@ class Interface(util.PrintError):
n = self.num_requests()
wire_requests = self.unsent_requests[0:n]
try:
- self.pipe.send_all(map(make_dict, wire_requests))
+ self.pipe.send_all([make_dict(*r) for r in wire_requests])
except socket.error as e:
self.print_error("socket error:", e)
return False
@@ -368,13 +374,13 @@ def _match_hostname(name, val):
return val.startswith('*.') and name.endswith(val[1:])
+
def test_certificates():
from .simple_config import SimpleConfig
config = SimpleConfig()
mydir = os.path.join(config.path, "certs")
certs = os.listdir(mydir)
for c in certs:
- print(c)
p = os.path.join(mydir,c)
with open(p) as f:
cert = f.read()
diff --git a/lib/network.py b/lib/network.py
@@ -103,7 +103,7 @@ SERVER_RETRY_INTERVAL = 10
def parse_servers(result):
""" parse servers list into dict format"""
- from version import PROTOCOL_VERSION
+ from .version import PROTOCOL_VERSION
servers = {}
for item in result:
host = item[1]
@@ -123,7 +123,8 @@ def parse_servers(result):
if pruning_level == '': pruning_level = '0'
try:
is_recent = cmp(util.normalize_version(version), util.normalize_version(PROTOCOL_VERSION)) >= 0
- except Exception:
+ except Exception as e:
+ print_error(e)
is_recent = False
if out and is_recent:
@@ -152,13 +153,15 @@ from .simple_config import SimpleConfig
proxy_modes = ['socks4', 'socks5', 'http']
+
def serialize_proxy(p):
- if type(p) != dict:
+ if not isinstance(p, dict):
return None
return ':'.join([p.get('mode'),p.get('host'), p.get('port'), p.get('user'), p.get('password')])
+
def deserialize_proxy(s):
- if type(s) not in [str, unicode]:
+ if not isinstance(s, str):
return None
if s.lower() == 'none':
return None
@@ -183,15 +186,18 @@ def deserialize_proxy(s):
proxy["password"] = args[n]
return proxy
+
def deserialize_server(server_str):
host, port, protocol = str(server_str).split(':')
assert protocol in 'st'
int(port) # Throw if cannot be converted to int
return host, port, protocol
+
def serialize_server(host, port, protocol):
return str(':'.join([host, port, protocol]))
+
class Network(util.DaemonThread):
"""The Network class manages a set of connections to remote electrum
servers, each connected socket is handled by an Interface() object.
@@ -209,7 +215,7 @@ class Network(util.DaemonThread):
if config is None:
config = {} # Do not use mutables as default values!
util.DaemonThread.__init__(self)
- self.config = SimpleConfig(config) if type(config) == type({}) else config
+ self.config = SimpleConfig(config) if isinstance(config, dict) else config
self.num_server = 10 if not self.config.get('oneserver') else 0
self.blockchains = blockchain.read_blockchains(self.config)
self.print_error("blockchains", self.blockchains.keys())
@@ -390,7 +396,7 @@ class Network(util.DaemonThread):
def get_interfaces(self):
'''The interfaces that are in connected state'''
- return self.interfaces.keys()
+ return list(self.interfaces.keys())
def get_servers(self):
if self.irc_servers:
@@ -456,7 +462,7 @@ class Network(util.DaemonThread):
def stop_network(self):
self.print_error("stopping network")
- for interface in self.interfaces.values():
+ for interface in list(self.interfaces.values()):
self.close_interface(interface)
if self.interface:
self.close_interface(self.interface)
@@ -596,7 +602,7 @@ class Network(util.DaemonThread):
def get_index(self, method, params):
""" hashable index for subscriptions and cache"""
- return str(method) + (':' + str(params[0]) if params else '')
+ return str(method) + (':' + str(params[0]) if params else '')
def process_responses(self, interface):
responses = interface.get_responses()
@@ -647,6 +653,7 @@ class Network(util.DaemonThread):
def send(self, messages, callback):
'''Messages is a list of (method, params) tuples'''
+ messages = list(messages)
with self.lock:
self.pending_sends.append((messages, callback))
@@ -730,7 +737,8 @@ class Network(util.DaemonThread):
self.connection_down(server)
# Send pings and shut down stale interfaces
- for interface in self.interfaces.values():
+ # must use copy of values
+ for interface in list(self.interfaces.values()):
if interface.has_timed_out():
self.connection_down(interface.server)
elif interface.ping_required():
@@ -1059,15 +1067,14 @@ class Network(util.DaemonThread):
host, port, protocol = server.split(':')
self.set_parameters(host, port, protocol, proxy, auto_connect)
-
def get_local_height(self):
return self.blockchain().height()
def synchronous_get(self, request, timeout=30):
- queue = queue.Queue()
- self.send([request], queue.put)
+ q = queue.Queue()
+ self.send([request], q.put)
try:
- r = queue.get(True, timeout)
+ r = q.get(True, timeout)
except queue.Empty:
raise BaseException('Server did not answer')
if r.get('error'):
diff --git a/lib/paymentrequest.py b/lib/paymentrequest.py
@@ -51,7 +51,7 @@ except ImportError:
from . import bitcoin
from . import util
-from .util import print_error
+from .util import print_error, bh2u, bfh
from . import transaction
from . import x509
from . import rsakey
@@ -126,7 +126,7 @@ class PaymentRequest:
def parse(self, r):
if self.error:
return
- self.id = bitcoin.sha256(r)[0:16].encode('hex')
+ self.id = bh2u(bitcoin.sha256(r)[0:16])
try:
self.data = pb2.PaymentRequest()
self.data.ParseFromString(r)
@@ -321,7 +321,7 @@ def make_unsigned_request(req):
if amount is None:
amount = 0
memo = req['memo']
- script = Transaction.pay_script(TYPE_ADDRESS, addr).decode('hex')
+ script = bfh(Transaction.pay_script(TYPE_ADDRESS, addr))
outputs = [(script, amount)]
pd = pb2.PaymentDetails()
for script, amount in outputs:
@@ -445,7 +445,7 @@ def serialize_request(req):
signature = req.get('sig')
requestor = req.get('name')
if requestor and signature:
- pr.signature = signature.decode('hex')
+ pr.signature = bfh(signature)
pr.pki_type = 'dnssec+btc'
pr.pki_data = str(requestor)
return pr
@@ -477,7 +477,7 @@ class InvoiceStore(object):
def load(self, d):
for k, v in d.items():
try:
- pr = PaymentRequest(v.get('hex').decode('hex'))
+ pr = bfh(PaymentRequest(v.get('hex')))
pr.tx = v.get('txid')
pr.requestor = v.get('requestor')
self.invoices[k] = pr
@@ -499,7 +499,7 @@ class InvoiceStore(object):
l = {}
for k, pr in self.invoices.items():
l[k] = {
- 'hex': str(pr).encode('hex'),
+ 'hex': bh2u(pr),
'requestor': pr.requestor,
'txid': pr.tx
}
diff --git a/lib/synchronizer.py b/lib/synchronizer.py
@@ -33,7 +33,7 @@ import hashlib
from .bitcoin import Hash, hash_encode
from .transaction import Transaction
-from .util import print_error, print_msg, ThreadJob
+from .util import print_error, print_msg, ThreadJob, bh2u
class Synchronizer(ThreadJob):
@@ -89,7 +89,7 @@ class Synchronizer(ThreadJob):
status = ''
for tx_hash, height in h:
status += tx_hash + ':%d:' % height
- return hashlib.sha256(status).digest().encode('hex')
+ return bh2u(hashlib.sha256(status.encode('ascii')).digest())
def addr_subscription_response(self, response):
params, result = self.parse_response(response)
@@ -114,7 +114,7 @@ class Synchronizer(ThreadJob):
self.print_error("receiving history", addr, len(result))
server_status = self.requested_histories[addr]
hashes = set(map(lambda item: item['tx_hash'], result))
- hist = map(lambda item: (item['tx_hash'], item['height']), result)
+ hist = list(map(lambda item: (item['tx_hash'], item['height']), result))
# tx_fees
tx_fees = [(item['tx_hash'], item.get('fee')) for item in result]
tx_fees = dict(filter(lambda x:x[1] is not None, tx_fees))
@@ -140,7 +140,7 @@ class Synchronizer(ThreadJob):
if not params:
return
tx_hash, tx_height = params
- #assert tx_hash == hash_encode(Hash(result.decode('hex')))
+ #assert tx_hash == hash_encode(Hash(bytes.fromhex(result)))
tx = Transaction(result)
try:
tx.deserialize()
diff --git a/lib/transaction.py b/lib/transaction.py
@@ -170,9 +170,9 @@ class Enumeration:
for x in enumList:
if isinstance(x, tuple):
x, i = x
- if not isinstance(x, six.text_type):
+ if not isinstance(x, str):
raise EnumException("enum name is not a string: " + x)
- if not isinstance(i, six.integer_types):
+ if not isinstance(i, int):
raise EnumException("enum value is not an integer: " + i)
if x in uniqueNames:
raise EnumException("enum name is not unique: " + x)
@@ -715,9 +715,9 @@ class Transaction:
txin = inputs[i]
# TODO: py3 hex
if self.is_segwit_input(txin):
- hashPrevouts = Hash(''.join(self.serialize_outpoint(txin) for txin in inputs).decode('hex')).encode('hex')
- hashSequence = Hash(''.join(int_to_hex(txin.get('sequence', 0xffffffff - 1), 4) for txin in inputs).decode('hex')).encode('hex')
- hashOutputs = Hash(''.join(self.serialize_output(o) for o in outputs).decode('hex')).encode('hex')
+ hashPrevouts = bh2u(Hash(bfh(''.join(self.serialize_outpoint(txin) for txin in inputs))))
+ hashSequence = bh2u(Hash(bfh(''.join(int_to_hex(txin.get('sequence', 0xffffffff - 1), 4) for txin in inputs))))
+ hashOutputs = bh2u(Hash(bfh(''.join(self.serialize_output(o) for o in outputs))))
outpoint = self.serialize_outpoint(txin)
preimage_script = self.get_preimage_script(txin)
scriptCode = var_int(len(preimage_script)/2) + preimage_script
diff --git a/lib/util.py b/lib/util.py
@@ -141,7 +141,7 @@ class DaemonThread(threading.Thread, PrintError):
for job in self.jobs:
try:
job.run()
- except:
+ except Exception as e:
traceback.print_exc(file=sys.stderr)
def remove_jobs(self, jobs):
@@ -170,7 +170,8 @@ class DaemonThread(threading.Thread, PrintError):
self.print_error("stopped")
-is_verbose = False
+# TODO: disable
+is_verbose = True
def set_verbosity(b):
global is_verbose
is_verbose = b
@@ -281,63 +282,8 @@ def assert_str(*args):
assert isinstance(x, six.string_types)
-def __str(x, encoding='utf8'):
- if six.PY3:
- return x.decode(encoding)
-
-
-def _bytes(x=None, encoding=None, **kw):
- """
- py2-py3 aware wrapper to "bytes()" like constructor
- :param x:
- :return:
- """
- if encoding is not None:
- kw['encoding'] = encoding
- if x is None:
- x = []
- if six.PY3:
- if isinstance(x, bytes):
- return x
- return bytes(x, **kw)
- else:
- return bytearray(x, **kw)
-
-
-def _to_bytes2(x, enc):
- if isinstance(x, bytearray):
- return bytearray(x)
- if isinstance(x, six.text_type):
- return bytearray(x.encode(enc))
- elif isinstance(x, six.binary_type):
- return bytearray(x)
- else:
- raise TypeError("Not a string or bytes like object")
-
-def _to_bytes3(x, enc):
- if isinstance(x, bytes):
- return x
- if isinstance(x, str):
- return x.encode(enc)
- elif isinstance(x, bytearray):
- return bytes(x)
- else:
- raise TypeError("Not a string or bytes like object")
-
-
-def _to_string2(x, enc):
- if isinstance(x, (str, bytes)):
- return x
- if isinstance(x, unicode):
- return x.encode(enc)
- if isinstance(x, bytearray):
- return x.decode(enc)
- else:
- raise TypeError("Not a string or bytes like object")
-
-
-def _to_string3(x, enc):
+def to_string(x, enc):
if isinstance(x, (bytes, bytearray)):
return x.decode(enc)
if isinstance(x, str):
@@ -349,35 +295,16 @@ def to_bytes(something, encoding='utf8'):
"""
cast string to bytes() like object, but for python2 support it's bytearray copy
"""
- raise NotImplementedError("This call should be redefined")
-
-def to_bytes(something, encoding='utf8'):
- """
- cast string to str object
- """
- raise NotImplementedError("This call should be redefined")
-
-if six.PY3:
- to_bytes = _to_bytes3
- to_string = _to_string3
-else:
- to_bytes = _to_bytes2
- to_string = _to_string2
-
-if six.PY3:
- bfh_builder = lambda x: bytes.fromhex(x)
-else:
- bfh_builder = lambda x: x.decode('hex') # str(bytearray.fromhex(x))
-
+ if isinstance(something, bytes):
+ return something
+ if isinstance(something, str):
+ return something.encode(encoding)
+ elif isinstance(something, bytearray):
+ return bytes(something)
+ else:
+ raise TypeError("Not a string or bytes like object")
-# def ufh(x):
-# """
-# py2-py3 aware wrapper for str.decode('hex')
-# :param x: str
-# :return: str
-# """
-# if
-# return binascii.unhexlify(x)
+bfh_builder = lambda x: bytes.fromhex(x)
def hfu(x):
@@ -700,20 +627,18 @@ else:
builtins.input = raw_input
-
def parse_json(message):
- n = message.find('\n')
+ # TODO: check \r\n pattern
+ n = message.find(b'\n')
if n==-1:
return None, message
try:
- j = json.loads( message[0:n] )
+ j = json.loads(message[0:n].decode('utf8'))
except:
j = None
return j, message[n+1:]
-
-
class timeout(Exception):
pass
@@ -723,11 +648,11 @@ import json
import ssl
import time
-class SocketPipe:
+class SocketPipe:
def __init__(self, socket):
self.socket = socket
- self.message = ''
+ self.message = b''
self.set_timeout(0.1)
self.recv_time = time.time()
@@ -757,10 +682,10 @@ class SocketPipe:
raise timeout
else:
print_error("pipe: socket error", err)
- data = ''
+ data = b''
except:
traceback.print_exc(file=sys.stderr)
- data = ''
+ data = b''
if not data: # Connection closed remotely
return None
@@ -769,10 +694,12 @@ class SocketPipe:
def send(self, request):
out = json.dumps(request) + '\n'
+ out = out.encode('utf8')
self._send(out)
def send_all(self, requests):
- out = ''.join(map(lambda x: json.dumps(x) + '\n', requests))
+ print(requests)
+ out = b''.join(map(lambda x: (json.dumps(x) + '\n').encode('utf8'), requests))
self._send(out)
def _send(self, out):
@@ -798,7 +725,6 @@ class SocketPipe:
raise e
-
class QueuePipe:
def __init__(self, send_queue=None, get_queue=None):
@@ -833,9 +759,8 @@ class QueuePipe:
self.send(request)
-
def check_www_dir(rdir):
- import urllib, urlparse, shutil, os
+ import urllib, shutil, os
if not os.path.exists(rdir):
os.mkdir(rdir)
index = os.path.join(rdir, 'index.html')
@@ -850,7 +775,7 @@ def check_www_dir(rdir):
"https://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css"
]
for URL in files:
- path = urlparse.urlsplit(URL).path
+ path = urllib_parse.urlsplit(URL).path
filename = os.path.basename(path)
path = os.path.join(rdir, filename)
if not os.path.exists(path):
diff --git a/lib/wallet.py b/lib/wallet.py
@@ -51,7 +51,7 @@ from .version import *
from .keystore import load_keystore, Hardware_KeyStore
from .storage import multisig_type
-import transaction
+from . import transaction
from .transaction import Transaction
from .plugins import run_hook
from . import bitcoin
@@ -297,6 +297,7 @@ class Abstract_Wallet(PrintError):
self.verifier.merkle_roots.pop(tx_hash, None)
# tx will be verified only if height > 0
+ print('unverif', tx_hash, tx_height)
if tx_hash not in self.verified_tx:
self.unverified_tx[tx_hash] = tx_height
@@ -759,7 +760,7 @@ class Abstract_Wallet(PrintError):
return ''
def get_tx_status(self, tx_hash, height, conf, timestamp):
- from util import format_time
+ from .util import format_time
if conf == 0:
tx = self.transactions.get(tx_hash)
if not tx:
@@ -1417,16 +1418,11 @@ class Imported_Wallet(Abstract_Wallet):
def add_input_sig_info(self, txin, address):
addrtype, hash160 = bc_address_to_hash_160(address)
- if six.PY3:
- x_pubkey = 'fd' + bh2u(bytes([addrtype]) + hash160)
- else:
- x_pubkey = 'fd' + bh2u(chr(addrtype) + hash160)
+ x_pubkey = 'fd' + bh2u(bytes([addrtype]) + hash160)
txin['x_pubkeys'] = [x_pubkey]
txin['signatures'] = [None]
-
-
class Deterministic_Wallet(Abstract_Wallet):
def __init__(self, storage):
@@ -1508,7 +1504,7 @@ class Deterministic_Wallet(Abstract_Wallet):
if len(addresses) < limit:
self.create_new_address(for_change)
continue
- if map(lambda a: self.address_is_old(a), addresses[-limit:] ) == limit*[False]:
+ if list(map(lambda a: self.address_is_old(a), addresses[-limit:] )) == limit*[False]:
break
else:
self.create_new_address(for_change)
@@ -1521,7 +1517,7 @@ class Deterministic_Wallet(Abstract_Wallet):
else:
if len(self.receiving_addresses) != len(self.keystore.keypairs):
pubkeys = self.keystore.keypairs.keys()
- self.receiving_addresses = map(self.pubkeys_to_address, pubkeys)
+ self.receiving_addresses = [self.pubkeys_to_address(i) for i in pubkeys]
self.save_addresses()
for addr in self.receiving_addresses:
self.add_address(addr)
@@ -1652,7 +1648,7 @@ class P2SH:
def pubkeys_to_address(self, pubkey):
redeem_script = self.pubkeys_to_redeem_script(pubkey)
- return bitcoin.hash160_to_p2sh(hash_160(redeem_script.decode('hex')))
+ return bitcoin.hash160_to_p2sh(hash_160(bfh(redeem_script)))
class Standard_Wallet(Simple_Deterministic_Wallet):
@@ -1664,17 +1660,14 @@ class Standard_Wallet(Simple_Deterministic_Wallet):
def pubkeys_to_address(self, pubkey):
if not self.is_segwit:
- return bitcoin.public_key_to_p2pkh(pubkey.decode('hex'))
+ return bitcoin.public_key_to_p2pkh(bfh(pubkey))
elif bitcoin.TESTNET:
redeem_script = self.pubkeys_to_redeem_script(pubkey)
- return bitcoin.hash160_to_p2sh(hash_160(redeem_script.decode('hex')))
+ return bitcoin.hash160_to_p2sh(hash_160(bfh(redeem_script)))
else:
raise NotImplementedError()
-
-
-
class Multisig_Wallet(Deterministic_Wallet, P2SH):
# generic m of n
gap_limit = 20
diff --git a/lib/x509.py b/lib/x509.py
@@ -31,7 +31,7 @@ import six
from datetime import datetime
import sys
from . import util
-from .util import profiler, print_error
+from .util import profiler, print_error, bh2u
import ecdsa
import hashlib
@@ -74,7 +74,7 @@ class CertificateError(Exception):
# helper functions
def bitstr_to_bytestr(s):
- if s[0] != '\x00':
+ if s[0] != 0x00:
raise BaseException('no padding')
return s[1:]
@@ -83,14 +83,13 @@ def bytestr_to_int(s):
i = 0
for char in s:
i <<= 8
- i |= ord(char)
+ i |= char
return i
def decode_OID(s):
- s = map(ord, s)
r = []
- r.append(s[0] / 40)
+ r.append(s[0] // 40)
r.append(s[0] % 40)
k = 0
for i in s[1:]:
@@ -103,7 +102,7 @@ def decode_OID(s):
def encode_OID(oid):
- x = map(int, oid.split('.'))
+ x = [int(i) for i in oid.split('.')]
s = chr(x[0] * 40 + x[1])
for i in x[2:]:
ss = chr(i % 128)
@@ -114,11 +113,11 @@ def encode_OID(oid):
return s
-class ASN1_Node(str):
+class ASN1_Node(bytes):
def get_node(self, ix):
# return index of first byte, first content byte and last byte.
- first = ord(self[ix + 1])
- if (ord(self[ix + 1]) & 0x80) == 0:
+ first = self[ix + 1]
+ if (self[ix + 1] & 0x80) == 0:
length = first
ixf = ix + 2
ixl = ixf + length - 1
@@ -129,72 +128,62 @@ class ASN1_Node(str):
ixl = ixf + length - 1
return ix, ixf, ixl
-
-def root(self):
- return self.get_node(0)
-
-
-def next_node(self, node):
- ixs, ixf, ixl = node
- return self.get_node(ixl + 1)
-
-
-def first_child(self, node):
- ixs, ixf, ixl = node
- if ord(self[ixs]) & 0x20 != 0x20:
- raise BaseException('Can only open constructed types.', hex(ord(self[ixs])))
- return self.get_node(ixf)
-
-
-def is_child_of(node1, node2):
- ixs, ixf, ixl = node1
- jxs, jxf, jxl = node2
- return ((ixf <= jxs) and (jxl <= ixl)) or ((jxf <= ixs) and (ixl <= jxl))
-
-
-def get_all(self, node):
- # return type + length + value
- ixs, ixf, ixl = node
- return self[ixs:ixl + 1]
-
-
-def get_value_of_type(self, node, asn1_type):
- # verify type byte and return content
- ixs, ixf, ixl = node
- if ASN1_TYPES[asn1_type] != ord(self[ixs]):
- raise BaseException('Wrong type:', hex(ord(self[ixs])), hex(ASN1_TYPES[asn1_type]))
- return self[ixf:ixl + 1]
-
-
-def get_value(self, node):
- ixs, ixf, ixl = node
- return self[ixf:ixl + 1]
-
-
-def get_children(self, node):
- nodes = []
- ii = self.first_child(node)
- nodes.append(ii)
- while ii[2] < node[2]:
- ii = self.next_node(ii)
+ def root(self):
+ return self.get_node(0)
+
+ def next_node(self, node):
+ ixs, ixf, ixl = node
+ return self.get_node(ixl + 1)
+
+ def first_child(self, node):
+ ixs, ixf, ixl = node
+ if self[ixs] & 0x20 != 0x20:
+ raise BaseException('Can only open constructed types.', hex(self[ixs]))
+ return self.get_node(ixf)
+
+ def is_child_of(node1, node2):
+ ixs, ixf, ixl = node1
+ jxs, jxf, jxl = node2
+ return ((ixf <= jxs) and (jxl <= ixl)) or ((jxf <= ixs) and (ixl <= jxl))
+
+ def get_all(self, node):
+ # return type + length + value
+ ixs, ixf, ixl = node
+ return self[ixs:ixl + 1]
+
+ def get_value_of_type(self, node, asn1_type):
+ # verify type byte and return content
+ ixs, ixf, ixl = node
+ if ASN1_TYPES[asn1_type] != self[ixs]:
+ raise BaseException('Wrong type:', hex(self[ixs]), hex(ASN1_TYPES[asn1_type]))
+ return self[ixf:ixl + 1]
+
+ def get_value(self, node):
+ ixs, ixf, ixl = node
+ return self[ixf:ixl + 1]
+
+ def get_children(self, node):
+ nodes = []
+ ii = self.first_child(node)
nodes.append(ii)
- return nodes
-
-
-def get_sequence(self):
- return map(lambda j: self.get_value(j), self.get_children(self.root()))
-
-
-def get_dict(self, node):
- p = {}
- for ii in self.get_children(node):
- for iii in self.get_children(ii):
- iiii = self.first_child(iii)
- oid = decode_OID(self.get_value_of_type(iiii, 'OBJECT IDENTIFIER'))
- iiii = self.next_node(iiii)
- value = self.get_value(iiii)
- p[oid] = value
- return p
+ while ii[2] < node[2]:
+ ii = self.next_node(ii)
+ nodes.append(ii)
+ return nodes
+
+ def get_sequence(self):
+ return list(map(lambda j: self.get_value(j), self.get_children(self.root())))
+
+ def get_dict(self, node):
+ p = {}
+ for ii in self.get_children(node):
+ for iii in self.get_children(ii):
+ iiii = self.first_child(iii)
+ oid = decode_OID(self.get_value_of_type(iiii, 'OBJECT IDENTIFIER'))
+ iiii = self.next_node(iiii)
+ value = self.get_value(iiii)
+ p[oid] = value
+ return p
class X509(object):
@@ -202,14 +191,14 @@ class X509(object):
self.bytes = bytearray(b)
- der = ASN1_Node(str(b))
+ der = ASN1_Node(b)
root = der.root()
cert = der.first_child(root)
# data for signature
self.data = der.get_all(cert)
# optional version field
- if der.get_value(cert)[0] == chr(0xa0):
+ if der.get_value(cert)[0] == 0xa0:
version = der.first_child(cert)
serial_number = der.next_node(version)
else:
@@ -269,10 +258,10 @@ class X509(object):
# Subject Key Identifier
r = value.root()
value = value.get_value_of_type(r, 'OCTET STRING')
- self.SKI = value.encode('hex')
+ self.SKI = bh2u(value)
elif oid == '2.5.29.35':
# Authority Key Identifier
- self.AKI = value.get_sequence()[0].encode('hex')
+ self.AKI = bh2u(value.get_sequence()[0])
else:
pass
@@ -303,8 +292,8 @@ class X509(object):
import time
now = time.time()
TIMESTAMP_FMT = '%y%m%d%H%M%SZ'
- not_before = time.mktime(time.strptime(self.notBefore, TIMESTAMP_FMT))
- not_after = time.mktime(time.strptime(self.notAfter, TIMESTAMP_FMT))
+ not_before = time.mktime(time.strptime(self.notBefore.decode('ascii'), TIMESTAMP_FMT))
+ not_after = time.mktime(time.strptime(self.notAfter.decode('ascii'), TIMESTAMP_FMT))
if not_before > now:
raise CertificateError('Certificate has not entered its valid date range. (%s)' % self.get_common_name())
if not_after <= now:
@@ -320,7 +309,7 @@ def load_certificates(ca_path):
ca_list = {}
ca_keyID = {}
with open(ca_path, 'rb') as f:
- s = f.read().decode('utf8')
+ s = f.read().decode('ascii')
bList = pem.dePemList(s, "CERTIFICATE")
for b in bList:
try: