This commit is contained in:
Dmitry Sorokin 2017-01-22 21:25:24 +03:00 committed by ThomasV
parent f70408cef5
commit 5be78950ca
64 changed files with 1232 additions and 657 deletions

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python
# -*- mode: python -*- # -*- mode: python -*-
# #
# Electrum - lightweight Bitcoin client # Electrum - lightweight Bitcoin client
@ -23,9 +23,14 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import os import os
import sys import sys
import six
# from https://gist.github.com/tito/09c42fb4767721dc323d # from https://gist.github.com/tito/09c42fb4767721dc323d
import threading import threading
@ -42,6 +47,12 @@ if jnius:
jnius.detach() jnius.detach()
threading.Thread.run = thread_check_run 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
script_dir = os.path.dirname(os.path.realpath(__file__)) script_dir = os.path.dirname(os.path.realpath(__file__))
is_bundle = getattr(sys, 'frozen', False) is_bundle = getattr(sys, 'frozen', False)
@ -54,6 +65,7 @@ os.environ['KIVY_DATA_DIR'] = os.path.abspath(os.path.dirname(__file__)) + '/gui
if is_local or is_android: if is_local or is_android:
sys.path.insert(0, os.path.join(script_dir, 'packages')) sys.path.insert(0, os.path.join(script_dir, 'packages'))
elif is_bundle and sys.platform=='darwin': elif is_bundle and sys.platform=='darwin':
# TODO: py3
sys.path.insert(0, os.getcwd() + "/lib/python2.7/packages") sys.path.insert(0, os.getcwd() + "/lib/python2.7/packages")
@ -68,7 +80,7 @@ def check_imports():
import qrcode import qrcode
import pbkdf2 import pbkdf2
import google.protobuf import google.protobuf
import jsonrpclib # import jsonrpclib
except ImportError as e: except ImportError as e:
sys.exit("Error: %s. Try 'sudo pip install <module-name>'"%e.message) sys.exit("Error: %s. Try 'sudo pip install <module-name>'"%e.message)
# the following imports are for pyinstaller # the following imports are for pyinstaller
@ -76,7 +88,7 @@ def check_imports():
from google.protobuf import message from google.protobuf import message
from google.protobuf import reflection from google.protobuf import reflection
from google.protobuf import descriptor_pb2 from google.protobuf import descriptor_pb2
from jsonrpclib import SimpleJSONRPCServer # from jsonrpclib import SimpleJSONRPCServer
# check that we have the correct version of ecdsa # check that we have the correct version of ecdsa
try: try:
from ecdsa.ecdsa import curve_secp256k1, generator_secp256k1 from ecdsa.ecdsa import curve_secp256k1, generator_secp256k1
@ -276,11 +288,11 @@ def run_offline_command(config, config_options):
if cmd.requires_network: if cmd.requires_network:
print_msg("Warning: running command offline") print_msg("Warning: running command offline")
# arguments passed to function # arguments passed to function
args = map(lambda x: config.get(x), cmd.params) args = [config.get(x) for x in cmd.params]
# decode json arguments # decode json arguments
args = map(json_decode, args) args = list(map(json_decode, args))
# options # options
args += map(lambda x: (config_options.get(x) if x in ['password', 'new_password'] else config.get(x)), cmd.options) args += [(config_options.get(x) if x in ['password', 'new_password'] else config.get(x)) for x in cmd.options]
cmd_runner = Commands(config, wallet, None) cmd_runner = Commands(config, wallet, None)
func = getattr(cmd_runner, cmd.name) func = getattr(cmd_runner, cmd.name)
result = func(*args) result = func(*args)
@ -296,10 +308,10 @@ def init_plugins(config, gui_name):
if __name__ == '__main__': if __name__ == '__main__':
# on osx, delete Process Serial Number arg generated for apps launched in Finder # on osx, delete Process Serial Number arg generated for apps launched in Finder
sys.argv = filter(lambda x: not x.startswith('-psn'), sys.argv) sys.argv = list(filter(lambda x: not x.startswith('-psn'), sys.argv))
# old 'help' syntax # old 'help' syntax
if len(sys.argv)>1 and sys.argv[1] == 'help': if len(sys.argv) > 1 and sys.argv[1] == 'help':
sys.argv.remove('help') sys.argv.remove('help')
sys.argv.append('-h') sys.argv.append('-h')
@ -312,9 +324,9 @@ if __name__ == '__main__':
else: else:
raise BaseException('Cannot get argument from stdin') raise BaseException('Cannot get argument from stdin')
elif arg == '?': elif arg == '?':
sys.argv[i] = raw_input("Enter argument:") sys.argv[i] = input("Enter argument:")
elif arg == ':': elif arg == ':':
sys.argv[i] = prompt_password('Enter argument (will not echo):', False) sys.argv[i] = prompt_password('Enter argument (will noot echo):', False)
# parse command line # parse command line
parser = get_parser() parser = get_parser()
@ -329,9 +341,8 @@ if __name__ == '__main__':
} }
else: else:
config_options = args.__dict__ config_options = args.__dict__
for k, v in config_options.items(): f = lambda key: config_options[key] is not None and key not in config_variables.get(args.cmd, {}).keys()
if v is None or (k in config_variables.get(args.cmd, {}).keys()): config_options = {key: config_options[key] for key in filter(f, config_options.keys())}
config_options.pop(k)
if config_options.get('server'): if config_options.get('server'):
config_options['auto_connect'] = False config_options['auto_connect'] = False
@ -426,8 +437,8 @@ if __name__ == '__main__':
init_plugins(config, 'cmdline') init_plugins(config, 'cmdline')
result = run_offline_command(config, config_options) result = run_offline_command(config, config_options)
# print result # print result
if type(result) in [str, unicode]: if isinstance(result, six.text_type):
print_msg(result) print_msg(result)
elif type(result) is dict and result.get('error'): elif type(result) is dict and result.get('error'):
print_stderr(result.get('error')) print_stderr(result.get('error'))

View File

@ -43,18 +43,20 @@ from electrum.synchronizer import Synchronizer
from electrum.verifier import SPV from electrum.verifier import SPV
from electrum.util import DebugMem, UserCancelled, InvalidPassword from electrum.util import DebugMem, UserCancelled, InvalidPassword
from electrum.wallet import Abstract_Wallet from electrum.wallet import Abstract_Wallet
from installwizard import InstallWizard, GoBack
from .installwizard import InstallWizard, GoBack
try: try:
import icons_rc from . import icons_rc
except Exception: except Exception as e:
print "Error: Could not find icons file." print(e)
print "Please run 'pyrcc4 icons.qrc -o gui/qt/icons_rc.py', and reinstall Electrum" print("Error: Could not find icons file.")
print("Please run 'pyrcc4 icons.qrc -o gui/qt/icons_rc.py', and reinstall Electrum")
sys.exit(1) sys.exit(1)
from util import * # * needed for plugins from .util import * # * needed for plugins
from main_window import ElectrumWindow from .main_window import ElectrumWindow
class OpenFileEventFilter(QObject): class OpenFileEventFilter(QObject):

View File

@ -22,16 +22,22 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from electrum.i18n import _ from electrum.i18n import _
import PyQt4 import PyQt4
from PyQt4.QtGui import * from PyQt4.QtGui import *
from PyQt4.QtCore import * from PyQt4.QtCore import *
from util import * from .util import *
from history_list import HistoryList from .history_list import HistoryList
from qrtextedit import ShowQRTextEdit from .qrtextedit import ShowQRTextEdit
class AddressDialog(WindowModalDialog): class AddressDialog(WindowModalDialog):

View File

@ -22,11 +22,16 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import webbrowser import webbrowser
from util import * from .util import *
from electrum.i18n import _ from electrum.i18n import _
from electrum.util import block_explorer_URL, format_satoshis, format_time from electrum.util import block_explorer_URL, format_satoshis, format_time
from electrum.plugins import run_hook from electrum.plugins import run_hook

View File

@ -1,11 +1,17 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from PyQt4.QtCore import * from PyQt4.QtCore import *
from PyQt4.QtGui import * from PyQt4.QtGui import *
from decimal import Decimal from decimal import Decimal
from electrum.util import format_satoshis_plain from electrum.util import format_satoshis_plain
class MyLineEdit(QLineEdit): class MyLineEdit(QLineEdit):
frozen = pyqtSignal() frozen = pyqtSignal()

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
# source: http://stackoverflow.com/questions/2758159/how-to-embed-a-python-interpreter-in-a-pyqt-widget # source: http://stackoverflow.com/questions/2758159/how-to-embed-a-python-interpreter-in-a-pyqt-widget
import sys, os, re import sys, os, re
@ -220,7 +226,7 @@ class Console(QtGui.QPlainTextEdit):
self.appendPlainText(repr(result)) self.appendPlainText(repr(result))
except SyntaxError: except SyntaxError:
# exec is generally considered bad practice. use it wisely! # exec is generally considered bad practice. use it wisely!
exec command in self.namespace exec(command) in self.namespace
except SystemExit: except SystemExit:
self.close() self.close()
except Exception: except Exception:

View File

@ -22,8 +22,13 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import webbrowser import webbrowser
import six
from electrum.i18n import _ from electrum.i18n import _
from electrum.bitcoin import is_address from electrum.bitcoin import is_address
@ -32,7 +37,7 @@ from electrum.plugins import run_hook
from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
from PyQt4.QtGui import * from PyQt4.QtGui import *
from PyQt4.QtCore import * from PyQt4.QtCore import *
from util import MyTreeWidget, pr_tooltips, pr_icons from .util import MyTreeWidget, pr_tooltips, pr_icons
class ContactList(MyTreeWidget): class ContactList(MyTreeWidget):

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from electrum.i18n import _ from electrum.i18n import _
import PyQt4 import PyQt4

View File

@ -22,11 +22,16 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import webbrowser import webbrowser
from util import * from .util import *
from electrum.i18n import _ from electrum.i18n import _
from electrum.util import block_explorer_URL, format_satoshis, format_time from electrum.util import block_explorer_URL, format_satoshis, format_time
from electrum.plugins import run_hook from electrum.plugins import run_hook

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import sys import sys
import os import os
@ -11,10 +17,10 @@ from electrum.util import UserCancelled, InvalidPassword
from electrum.base_wizard import BaseWizard from electrum.base_wizard import BaseWizard
from electrum.i18n import _ from electrum.i18n import _
from seed_dialog import SeedLayout, KeysLayout from .seed_dialog import SeedLayout, KeysLayout
from network_dialog import NetworkChoiceLayout from .network_dialog import NetworkChoiceLayout
from util import * from .util import *
from password_dialog import PasswordLayout, PW_NEW from .password_dialog import PasswordLayout, PW_NEW
class GoBack(Exception): class GoBack(Exception):

View File

@ -22,9 +22,14 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from util import * from .util import *
from electrum.i18n import _ from electrum.i18n import _
from electrum.util import block_explorer_URL, format_satoshis, format_time from electrum.util import block_explorer_URL, format_satoshis, format_time
from electrum.plugins import run_hook from electrum.plugins import run_hook

View File

@ -22,7 +22,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import sys, time, threading import sys, time, threading
import os, json, traceback import os, json, traceback
import shutil import shutil
@ -39,7 +44,7 @@ from PyQt4.QtGui import *
from PyQt4.QtCore import * from PyQt4.QtCore import *
import PyQt4.QtCore as QtCore import PyQt4.QtCore as QtCore
import icons_rc from . import icons_rc
from electrum import keystore from electrum import keystore
from electrum.bitcoin import COIN, is_valid, TYPE_ADDRESS from electrum.bitcoin import COIN, is_valid, TYPE_ADDRESS
@ -57,17 +62,17 @@ try:
except: except:
plot_history = None plot_history = None
from amountedit import AmountEdit, BTCAmountEdit, MyLineEdit, BTCkBEdit from .amountedit import AmountEdit, BTCAmountEdit, MyLineEdit, BTCkBEdit
from qrcodewidget import QRCodeWidget, QRDialog from .qrcodewidget import QRCodeWidget, QRDialog
from qrtextedit import ShowQRTextEdit from .qrtextedit import ShowQRTextEdit
from transaction_dialog import show_transaction from .transaction_dialog import show_transaction
from fee_slider import FeeSlider from .fee_slider import FeeSlider
from electrum import ELECTRUM_VERSION from electrum import ELECTRUM_VERSION
import re import re
from util import * from .util import *
class StatusBarButton(QPushButton): class StatusBarButton(QPushButton):
@ -397,7 +402,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
try: try:
shutil.copy2(path, new_path) shutil.copy2(path, new_path)
self.show_message(_("A copy of your wallet file was created in")+" '%s'" % str(new_path), title=_("Wallet backup created")) self.show_message(_("A copy of your wallet file was created in")+" '%s'" % str(new_path), title=_("Wallet backup created"))
except (IOError, os.error), reason: except (IOError, os.error) as reason:
self.show_critical(_("Electrum was unable to copy your wallet file to the specified location.") + "\n" + str(reason), title=_("Unable to create backup")) self.show_critical(_("Electrum was unable to copy your wallet file to the specified location.") + "\n" + str(reason), title=_("Unable to create backup"))
def update_recently_visited(self, filename): def update_recently_visited(self, filename):
@ -722,13 +727,13 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
self.update_completions() self.update_completions()
def create_history_tab(self): def create_history_tab(self):
from history_list import HistoryList from .history_list import HistoryList
self.history_list = l = HistoryList(self) self.history_list = l = HistoryList(self)
l.searchable_list = l l.searchable_list = l
return l return l
def show_address(self, addr): def show_address(self, addr):
import address_dialog from . import address_dialog
d = address_dialog.AddressDialog(self, addr) d = address_dialog.AddressDialog(self, addr)
d.exec_() d.exec_()
@ -770,7 +775,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
self.connect_fields(self, self.receive_amount_e, self.fiat_receive_e, None) self.connect_fields(self, self.receive_amount_e, self.fiat_receive_e, None)
self.expires_combo = QComboBox() self.expires_combo = QComboBox()
self.expires_combo.addItems(map(lambda x:x[0], expiration_values)) self.expires_combo.addItems([i[0] for i in expiration_values])
self.expires_combo.setCurrentIndex(3) self.expires_combo.setCurrentIndex(3)
self.expires_combo.setFixedWidth(self.receive_amount_e.width()) self.expires_combo.setFixedWidth(self.receive_amount_e.width())
msg = ' '.join([ msg = ' '.join([
@ -806,7 +811,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
self.receive_requests_label = QLabel(_('Requests')) self.receive_requests_label = QLabel(_('Requests'))
from request_list import RequestList from .request_list import RequestList
self.request_list = RequestList(self) self.request_list = RequestList(self)
# layout # layout
@ -991,7 +996,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
grid.setSpacing(8) grid.setSpacing(8)
grid.setColumnStretch(3, 1) grid.setColumnStretch(3, 1)
from paytoedit import PayToEdit from .paytoedit import PayToEdit
self.amount_e = BTCAmountEdit(self.get_decimal_point) self.amount_e = BTCAmountEdit(self.get_decimal_point)
self.payto_e = PayToEdit(self) self.payto_e = PayToEdit(self)
msg = _('Recipient of the funds.') + '\n\n'\ msg = _('Recipient of the funds.') + '\n\n'\
@ -1123,7 +1128,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
self.fee_e.textChanged.connect(entry_changed) self.fee_e.textChanged.connect(entry_changed)
self.invoices_label = QLabel(_('Invoices')) self.invoices_label = QLabel(_('Invoices'))
from invoice_list import InvoiceList from .invoice_list import InvoiceList
self.invoice_list = InvoiceList(self) self.invoice_list = InvoiceList(self)
vbox0 = QVBoxLayout() vbox0 = QVBoxLayout()
@ -1567,17 +1572,17 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
return w return w
def create_addresses_tab(self): def create_addresses_tab(self):
from address_list import AddressList from .address_list import AddressList
self.address_list = l = AddressList(self) self.address_list = l = AddressList(self)
return self.create_list_tab(l) return self.create_list_tab(l)
def create_utxo_tab(self): def create_utxo_tab(self):
from utxo_list import UTXOList from .utxo_list import UTXOList
self.utxo_list = l = UTXOList(self) self.utxo_list = l = UTXOList(self)
return self.create_list_tab(l) return self.create_list_tab(l)
def create_contacts_tab(self): def create_contacts_tab(self):
from contact_list import ContactList from .contact_list import ContactList
self.contact_list = l = ContactList(self) self.contact_list = l = ContactList(self)
return self.create_list_tab(l) return self.create_list_tab(l)
@ -1693,11 +1698,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
self.payment_request_error() self.payment_request_error()
def create_console_tab(self): def create_console_tab(self):
from console import Console from .console import Console
self.console = console = Console() self.console = console = Console()
return console return console
def update_console(self): def update_console(self):
console = self.console console = self.console
console.history = self.config.get("console-history",[]) console.history = self.config.get("console-history",[])
@ -2202,7 +2206,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
with open(fileName, 'w+') as f: with open(fileName, 'w+') as f:
json.dump(labels, f, indent=4, sort_keys=True) json.dump(labels, f, indent=4, sort_keys=True)
self.show_message(_("Your labels were exported to") + " '%s'" % str(fileName)) self.show_message(_("Your labels were exported to") + " '%s'" % str(fileName))
except (IOError, os.error), reason: except (IOError, os.error) as reason:
self.show_critical(_("Electrum was unable to export your labels.") + "\n" + str(reason)) self.show_critical(_("Electrum was unable to export your labels.") + "\n" + str(reason))
@ -2226,7 +2230,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
return return
try: try:
self.do_export_history(self.wallet, filename, csv_button.isChecked()) self.do_export_history(self.wallet, filename, csv_button.isChecked())
except (IOError, os.error), reason: except (IOError, os.error) as reason:
export_error_label = _("Electrum was unable to produce a transaction export.") export_error_label = _("Electrum was unable to produce a transaction export.")
self.show_critical(export_error_label + "\n" + str(reason), title=_("Unable to export history")) self.show_critical(export_error_label + "\n" + str(reason), title=_("Unable to export history"))
return return

View File

@ -22,8 +22,15 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
import socket
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import socket
import six
from PyQt4.QtGui import * from PyQt4.QtGui import *
from PyQt4.QtCore import * from PyQt4.QtCore import *
import PyQt4.QtCore as QtCore import PyQt4.QtCore as QtCore
@ -32,7 +39,7 @@ from electrum.i18n import _
from electrum.network import DEFAULT_PORTS from electrum.network import DEFAULT_PORTS
from electrum.network import serialize_server, deserialize_server from electrum.network import serialize_server, deserialize_server
from util import * from .util import *
protocol_names = ['TCP', 'SSL'] protocol_names = ['TCP', 'SSL']
protocol_letters = 'ts' protocol_letters = 'ts'

View File

@ -22,11 +22,16 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from PyQt4.QtGui import * from PyQt4.QtGui import *
from PyQt4.QtCore import * from PyQt4.QtCore import *
from electrum.i18n import _ from electrum.i18n import _
from util import * from .util import *
import re import re
import math import math

View File

@ -22,16 +22,21 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from PyQt4.QtCore import * from PyQt4.QtCore import *
from PyQt4.QtGui import * from PyQt4.QtGui import *
from qrtextedit import ScanQRTextEdit from .qrtextedit import ScanQRTextEdit
import re import re
from decimal import Decimal from decimal import Decimal
from electrum import bitcoin from electrum import bitcoin
import util from . import util
RE_ADDRESS = '[1-9A-HJ-NP-Za-km-z]{26,}' RE_ADDRESS = '[1-9A-HJ-NP-Za-km-z]{26,}'
RE_ALIAS = '(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>' RE_ALIAS = '(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>'

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from PyQt4.QtGui import * from PyQt4.QtGui import *
from PyQt4.QtCore import * from PyQt4.QtCore import *
import PyQt4.QtGui as QtGui import PyQt4.QtGui as QtGui
@ -7,7 +13,7 @@ import qrcode
import electrum import electrum
from electrum.i18n import _ from electrum.i18n import _
from util import WindowModalDialog from .util import WindowModalDialog
class QRCodeWidget(QWidget): class QRCodeWidget(QWidget):

View File

@ -1,9 +1,15 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from electrum.i18n import _ from electrum.i18n import _
from electrum.plugins import run_hook from electrum.plugins import run_hook
from PyQt4.QtGui import * from PyQt4.QtGui import *
from PyQt4.QtCore import * from PyQt4.QtCore import *
from util import ButtonsTextEdit, MessageBoxMixin from .util import ButtonsTextEdit, MessageBoxMixin
class ShowQRTextEdit(ButtonsTextEdit): class ShowQRTextEdit(ButtonsTextEdit):

View File

@ -22,11 +22,15 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import re import re
import platform import platform
from decimal import Decimal from decimal import Decimal
from urllib import quote
from PyQt4.QtGui import * from PyQt4.QtGui import *
from PyQt4.QtCore import * from PyQt4.QtCore import *

View File

@ -22,7 +22,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from electrum.i18n import _ from electrum.i18n import _
from electrum.util import block_explorer_URL, format_satoshis, format_time, age from electrum.util import block_explorer_URL, format_satoshis, format_time, age
@ -30,7 +35,7 @@ from electrum.plugins import run_hook
from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
from PyQt4.QtGui import * from PyQt4.QtGui import *
from PyQt4.QtCore import * from PyQt4.QtCore import *
from util import MyTreeWidget, pr_tooltips, pr_icons from .util import MyTreeWidget, pr_tooltips, pr_icons
class RequestList(MyTreeWidget): class RequestList(MyTreeWidget):

View File

@ -22,13 +22,18 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from PyQt4.QtGui import * from PyQt4.QtGui import *
from PyQt4.QtCore import * from PyQt4.QtCore import *
from electrum.i18n import _ from electrum.i18n import _
from util import * from .util import *
from qrtextedit import ShowQRTextEdit, ScanQRTextEdit from .qrtextedit import ShowQRTextEdit, ScanQRTextEdit
def seed_warning_msg(seed): def seed_warning_msg(seed):

View File

@ -22,7 +22,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import copy import copy
import datetime import datetime
import json import json
@ -37,7 +42,7 @@ from electrum.bitcoin import base_encode
from electrum.i18n import _ from electrum.i18n import _
from electrum.plugins import run_hook from electrum.plugins import run_hook
from util import * from .util import *
dialogs = [] # Otherwise python randomly garbage collects the dialogs... dialogs = [] # Otherwise python randomly garbage collects the dialogs...

View File

@ -1,10 +1,16 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import os.path import os.path
import time import time
import traceback import traceback
import sys import sys
import threading import threading
import platform import platform
import Queue from six.moves import queue
from collections import namedtuple from collections import namedtuple
from functools import partial from functools import partial
@ -565,7 +571,7 @@ class TaskThread(QThread):
def __init__(self, parent, on_error=None): def __init__(self, parent, on_error=None):
super(TaskThread, self).__init__(parent) super(TaskThread, self).__init__(parent)
self.on_error = on_error self.on_error = on_error
self.tasks = Queue.Queue() self.tasks = queue.Queue()
self.doneSig.connect(self.on_done) self.doneSig.connect(self.on_done)
self.start() self.start()

View File

@ -22,8 +22,13 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from util import * import six
from .util import *
from electrum.i18n import _ from electrum.i18n import _
from electrum.bitcoin import is_address from electrum.bitcoin import is_address

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from decimal import Decimal from decimal import Decimal
_ = lambda x:x _ = lambda x:x
#from i18n import _ #from i18n import _

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import tty, sys import tty, sys
import curses, datetime, locale import curses, datetime, locale
from decimal import Decimal from decimal import Decimal

View File

@ -1,14 +1,14 @@
from version import ELECTRUM_VERSION from .version import ELECTRUM_VERSION
from util import format_satoshis, print_msg, print_error, set_verbosity from .util import format_satoshis, print_msg, print_error, set_verbosity
from wallet import Synchronizer, Wallet, Imported_Wallet from .wallet import Synchronizer, Wallet, Imported_Wallet
from storage import WalletStorage from .storage import WalletStorage
from coinchooser import COIN_CHOOSERS from .coinchooser import COIN_CHOOSERS
from network import Network, pick_random_server from .network import Network, pick_random_server
from interface import Connection, Interface from .interface import Connection, Interface
from simple_config import SimpleConfig, get_config, set_config from .simple_config import SimpleConfig, get_config, set_config
import bitcoin from . import bitcoin
import transaction from . import transaction
import daemon from . import daemon
from transaction import Transaction from .transaction import Transaction
from plugins import BasePlugin from .plugins import BasePlugin
from commands import Commands, known_commands from .commands import Commands, known_commands

0
lib/account.py Normal file
View File

View File

@ -22,14 +22,19 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import os import os
import bitcoin from . import bitcoin
import keystore from . import keystore
from keystore import bip44_derivation from .keystore import bip44_derivation
from wallet import Wallet, Imported_Wallet, Standard_Wallet, Multisig_Wallet, wallet_types from .wallet import Wallet, Imported_Wallet, Standard_Wallet, Multisig_Wallet, wallet_types
from i18n import _ from .i18n import _
from plugins import run_hook from .plugins import run_hook
class BaseWizard(object): class BaseWizard(object):

View File

@ -26,12 +26,12 @@
import hashlib import hashlib
import base64 import base64
import os
import re import re
import hmac import hmac
import version from lib.util import bfh, bh2u
from util import print_error, InvalidPassword from . import version
from .util import print_error, InvalidPassword, assert_bytes, _bytes, to_bytes
import ecdsa import ecdsa
import pyaes import pyaes
@ -98,6 +98,9 @@ except:
AES = None AES = None
def aes_encrypt_with_iv(key, iv, data): def aes_encrypt_with_iv(key, iv, data):
assert_bytes(key, iv, data)
if six.PY2:
key, iv, data = map(str, (key, iv, data))
if AES: if AES:
padlen = 16 - (len(data) % 16) padlen = 16 - (len(data) % 16)
if padlen == 0: if padlen == 0:
@ -112,6 +115,9 @@ def aes_encrypt_with_iv(key, iv, data):
return e return e
def aes_decrypt_with_iv(key, iv, data): def aes_decrypt_with_iv(key, iv, data):
assert_bytes(key, iv, data)
if six.PY2:
key, iv, data = map(str, (key, iv, data))
if AES: if AES:
cipher = AES.new(key, AES.MODE_CBC, iv) cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.decrypt(data) data = cipher.decrypt(data)
@ -127,14 +133,21 @@ def aes_decrypt_with_iv(key, iv, data):
return s return s
def EncodeAES(secret, s): def EncodeAES(secret, s):
iv = bytes(os.urandom(16)) assert_bytes(s)
iv = _bytes(os.urandom(16))
# aes_cbc = pyaes.AESModeOfOperationCBC(secret, iv=iv)
# aes = pyaes.Encrypter(aes_cbc)
# e = iv + aes.feed(s) + aes.feed()
ct = aes_encrypt_with_iv(secret, iv, s) ct = aes_encrypt_with_iv(secret, iv, s)
e = iv + ct e = iv + ct
return base64.b64encode(e) return base64.b64encode(e)
def DecodeAES(secret, e): def DecodeAES(secret, e):
e = bytes(base64.b64decode(e)) e = _bytes(base64.b64decode(e))
iv, e = e[:16], e[16:] iv, e = e[:16], e[16:]
# aes_cbc = pyaes.AESModeOfOperationCBC(secret, iv=iv)
# aes = pyaes.Decrypter(aes_cbc)
# s = aes.feed(e) + aes.feed()
s = aes_decrypt_with_iv(secret, iv, e) s = aes_decrypt_with_iv(secret, iv, e)
return s return s
@ -158,10 +171,11 @@ def pw_decode(s, password):
def rev_hex(s): def rev_hex(s):
return s.decode('hex')[::-1].encode('hex') return bh2u(bfh(s)[::-1])
def int_to_hex(i, length=1): def int_to_hex(i, length=1):
assert isinstance(i, int)
s = hex(i)[2:].rstrip('L') s = hex(i)[2:].rstrip('L')
s = "0"*(2*length - len(s)) + s s = "0"*(2*length - len(s)) + s
return rev_hex(s) return rev_hex(s)
@ -191,26 +205,30 @@ def op_push(i):
def sha256(x): def sha256(x):
return hashlib.sha256(x).digest() x = to_bytes(x, 'utf8')
return _bytes(hashlib.sha256(x).digest())
def Hash(x): def Hash(x):
if type(x) is unicode: x=x.encode('utf-8') x = to_bytes(x, 'utf8')
return sha256(sha256(x)) out = _bytes(sha256(sha256(x)))
return out
hash_encode = lambda x: bh2u(x[::-1])
hash_decode = lambda x: bfh(x)[::-1]
hmac_sha_512 = lambda x, y: _bytes(hmac.new(x, y, hashlib.sha512).digest())
hash_encode = lambda x: x[::-1].encode('hex')
hash_decode = lambda x: x.decode('hex')[::-1]
hmac_sha_512 = lambda x,y: hmac.new(x, y, hashlib.sha512).digest()
def is_new_seed(x, prefix=version.SEED_PREFIX): def is_new_seed(x, prefix=version.SEED_PREFIX):
import mnemonic from . import mnemonic
x = mnemonic.normalize_text(x) x = mnemonic.normalize_text(x)
s = hmac_sha_512("Seed version", x.encode('utf8')).encode('hex') s = bh2u(hmac_sha_512(b"Seed version", x.encode('utf8')))
return s.startswith(prefix) return s.startswith(prefix)
def is_old_seed(seed): def is_old_seed(seed):
import old_mnemonic from . import old_mnemonic
words = seed.strip().split() words = seed.strip().split()
try: try:
old_mnemonic.mn_decode(words) old_mnemonic.mn_decode(words)
@ -218,8 +236,8 @@ def is_old_seed(seed):
except Exception: except Exception:
uses_electrum_words = False uses_electrum_words = False
try: try:
seed.decode('hex') seed = bfh(seed)
is_hex = (len(seed) == 32 or len(seed) == 64) is_hex = (len(seed) == 16 or len(seed) == 32)
except Exception: except Exception:
is_hex = False is_hex = False
return is_hex or (uses_electrum_words and (len(words) == 12 or len(words) == 24)) return is_hex or (uses_electrum_words and (len(words) == 12 or len(words) == 24))
@ -255,37 +273,38 @@ def i2o_ECPublicKey(pubkey, compressed=False):
'%064x' % pubkey.point.x() + \ '%064x' % pubkey.point.x() + \
'%064x' % pubkey.point.y() '%064x' % pubkey.point.y()
return key.decode('hex') return bfh(key)
# end pywallet openssl private key implementation # end pywallet openssl private key implementation
############ functions from pywallet ##################### ############ functions from pywallet #####################
def hash_160(public_key): def hash_160(public_key):
if 'ANDROID_DATA' in os.environ: if 'ANDROID_DATA' in os.environ:
from Crypto.Hash import RIPEMD from Crypto.Hash import RIPEMD
md = RIPEMD.new() md = RIPEMD.new()
else: else:
md = hashlib.new('ripemd') md = hashlib.new('ripemd')
public_key = to_bytes(public_key, 'ascii')
md.update(sha256(public_key)) md.update(sha256(public_key))
return md.digest() return md.digest()
def hash_160_to_bc_address(h160, addrtype, witness_program_version=1): def hash_160_to_bc_address(h160, addrtype, witness_program_version=1):
s = chr(addrtype) s = bytes([addrtype])
if addrtype == ADDRTYPE_P2WPKH: if addrtype == ADDRTYPE_P2WPKH:
s += chr(witness_program_version) + chr(0) s += bytes([witness_program_version]) + b'\x00'
s += h160 s += h160
return base_encode(s+Hash(s)[0:4], base=58) return base_encode(s+Hash(s)[0:4], base=58)
def bc_address_to_hash_160(addr): def bc_address_to_hash_160(addr):
bytes = base_decode(addr, 25, base=58) addr = to_bytes(addr, 'ascii')
return ord(bytes[0]), bytes[1:21] _bytes = base_decode(addr, 25, base=58)
return _bytes[0], _bytes[1:21]
def hash160_to_p2pkh(h160): def hash160_to_p2pkh(h160):
return hash_160_to_bc_address(h160, ADDRTYPE_P2PKH) return hash_160_to_bc_address(h160, ADDRTYPE_P2PKH)
def hash160_to_p2sh(h160): def hash160_to_p2sh(h160):
return hash_160_to_bc_address(h160, ADDRTYPE_P2SH) return hash_160_to_bc_address(h160, ADDRTYPE_P2SH)
@ -298,60 +317,70 @@ def public_key_to_p2wpkh(public_key):
__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' __b58chars = b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
assert len(__b58chars) == 58 assert len(__b58chars) == 58
__b43chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ$*+-./:' __b43chars = b'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ$*+-./:'
assert len(__b43chars) == 43 assert len(__b43chars) == 43
def base_encode(v, base): def base_encode(v, base):
""" encode v, which is a string of bytes, to base58.""" """ encode v, which is a string of bytes, to base58."""
if base == 58: assert_bytes(v)
chars = __b58chars assert base in (58, 43)
elif base == 43: chars = __b58chars
if base == 43:
chars = __b43chars chars = __b43chars
long_value = 0L long_value = 0
for (i, c) in enumerate(v[::-1]): for (i, c) in enumerate(v[::-1]):
long_value += (256**i) * ord(c) long_value += (256**i) * c
result = '' result = bytearray()
while long_value >= base: while long_value >= base:
div, mod = divmod(long_value, base) div, mod = divmod(long_value, base)
result = chars[mod] + result result.append(chars[mod])
long_value = div long_value = div
result = chars[long_value] + result result.append(chars[long_value])
# Bitcoin does a little leading-zero-compression: # Bitcoin does a little leading-zero-compression:
# leading 0-bytes in the input become leading-1s # leading 0-bytes in the input become leading-1s
nPad = 0 nPad = 0
for c in v: for c in v:
if c == '\0': nPad += 1 if c == 0x00:
else: break nPad += 1
return (chars[0]*nPad) + result else:
break
result.extend([chars[0]] * nPad)
result.reverse()
return result.decode('ascii')
def base_decode(v, length, base): def base_decode(v, length, base):
""" decode v into a string of len bytes.""" """ decode v into a string of len bytes."""
if base == 58: # assert_bytes(v)
chars = __b58chars v = to_bytes(v, 'ascii')
elif base == 43: assert base in (58, 43)
chars = __b58chars
if base == 43:
chars = __b43chars chars = __b43chars
long_value = 0L long_value = 0
for (i, c) in enumerate(v[::-1]): for (i, c) in enumerate(v[::-1]):
long_value += chars.find(c) * (base**i) long_value += chars.find(_bytes([c])) * (base**i)
result = '' result = bytearray()
while long_value >= 256: while long_value >= 256:
div, mod = divmod(long_value, 256) div, mod = divmod(long_value, 256)
result = chr(mod) + result result.append(mod)
long_value = div long_value = div
result = chr(long_value) + result result.append(long_value)
nPad = 0 nPad = 0
for c in v: for c in v:
if c == chars[0]: nPad += 1 if c == chars[0]:
else: break nPad += 1
result = chr(0)*nPad + result else:
break
result.extend(b'\x00' * nPad)
if length is not None and len(result) != length: if length is not None and len(result) != length:
return None return None
return result result.reverse()
return bytes(result)
def EncodeBase58Check(vchIn): def EncodeBase58Check(vchIn):
@ -377,14 +406,15 @@ def PrivKeyToSecret(privkey):
def SecretToASecret(secret, compressed=False): def SecretToASecret(secret, compressed=False):
addrtype = ADDRTYPE_P2PKH addrtype = ADDRTYPE_P2PKH
vchIn = chr((addrtype+128)&255) + secret vchIn = bytes([(addrtype+128)&255]) + secret
if compressed: vchIn += '\01' if compressed: vchIn += b'\01'
return EncodeBase58Check(vchIn) return EncodeBase58Check(vchIn)
def ASecretToSecret(key): def ASecretToSecret(key):
addrtype = ADDRTYPE_P2PKH addrtype = ADDRTYPE_P2PKH
vch = DecodeBase58Check(key) vch = DecodeBase58Check(key)
if vch and vch[0] == chr((addrtype+128)&255): if vch and vch[0] == ((addrtype+128)&255):
return vch[1:] return vch[1:]
elif is_minikey(key): elif is_minikey(key):
return minikey_to_private_key(key) return minikey_to_private_key(key)
@ -404,7 +434,7 @@ def GetPubKey(pubkey, compressed=False):
def GetSecret(pkey): def GetSecret(pkey):
return ('%064x' % pkey.secret).decode('hex') return bfh('%064x' % pkey.secret)
def is_compressed(sec): def is_compressed(sec):
@ -418,12 +448,12 @@ def public_key_from_private_key(sec):
assert pkey assert pkey
compressed = is_compressed(sec) compressed = is_compressed(sec)
public_key = GetPubKey(pkey.pubkey, compressed) public_key = GetPubKey(pkey.pubkey, compressed)
return public_key.encode('hex') return bh2u(public_key)
def address_from_private_key(sec): def address_from_private_key(sec):
public_key = public_key_from_private_key(sec) public_key = public_key_from_private_key(sec)
address = public_key_to_p2pkh(public_key.decode('hex')) address = public_key_to_p2pkh(bfh(public_key))
return address return address
@ -434,7 +464,7 @@ def is_valid(addr):
def is_address(addr): def is_address(addr):
try: try:
addrtype, h = bc_address_to_hash_160(addr) addrtype, h = bc_address_to_hash_160(addr)
except Exception: except Exception as e:
return False return False
if addrtype not in [ADDRTYPE_P2PKH, ADDRTYPE_P2SH]: if addrtype not in [ADDRTYPE_P2PKH, ADDRTYPE_P2SH]:
return False return False
@ -478,10 +508,14 @@ from ecdsa.curves import SECP256k1
from ecdsa.ellipticcurve import Point from ecdsa.ellipticcurve import Point
from ecdsa.util import string_to_number, number_to_string from ecdsa.util import string_to_number, number_to_string
def msg_magic(message): def msg_magic(message):
varint = var_int(len(message)) varint = var_int(len(message))
encoded_varint = "".join([chr(int(varint[i:i+2], 16)) for i in xrange(0, len(varint), 2)]) if six.PY3:
return "\x18Bitcoin Signed Message:\n" + encoded_varint + message encoded_varint = varint.encode('ascii')
else:
encoded_varint = b"".join([chr(int(varint[i:i+2], 16)) for i in range(0, len(varint), 2)])
return b"\x18Bitcoin Signed Message:\n" + encoded_varint + message
def verify_message(address, sig, message): def verify_message(address, sig, message):
@ -502,11 +536,11 @@ def verify_message(address, sig, message):
def encrypt_message(message, pubkey): def encrypt_message(message, pubkey):
return EC_KEY.encrypt_message(message, pubkey.decode('hex')) return EC_KEY.encrypt_message(message, bfh(pubkey))
def chunks(l, n): def chunks(l, n):
return [l[i:i+n] for i in xrange(0, len(l), n)] return [l[i:i+n] for i in range(0, len(l), n)]
def ECC_YfromX(x,curved=curve_secp256k1, odd=True): def ECC_YfromX(x,curved=curve_secp256k1, odd=True):
@ -516,7 +550,7 @@ def ECC_YfromX(x,curved=curve_secp256k1, odd=True):
for offset in range(128): for offset in range(128):
Mx = x + offset Mx = x + offset
My2 = pow(Mx, 3, _p) + _a * pow(Mx, 2, _p) + _b % _p My2 = pow(Mx, 3, _p) + _a * pow(Mx, 2, _p) + _b % _p
My = pow(My2, (_p+1)/4, _p ) My = pow(My2, (_p+1)//4, _p )
if curved.contains_point(Mx,My): if curved.contains_point(Mx,My):
if odd == bool(My&1): if odd == bool(My&1):
@ -531,20 +565,19 @@ def negative_point(P):
def point_to_ser(P, comp=True ): def point_to_ser(P, comp=True ):
if comp: if comp:
return ( ('%02x'%(2+(P.y()&1)))+('%064x'%P.x()) ).decode('hex') return bfh( ('%02x'%(2+(P.y()&1)))+('%064x'%P.x()) )
return ( '04'+('%064x'%P.x())+('%064x'%P.y()) ).decode('hex') return bfh( '04'+('%064x'%P.x())+('%064x'%P.y()) )
def ser_to_point(Aser): def ser_to_point(Aser):
curve = curve_secp256k1 curve = curve_secp256k1
generator = generator_secp256k1 generator = generator_secp256k1
_r = generator.order() _r = generator.order()
assert Aser[0] in ['\x02','\x03','\x04'] assert Aser[0] in [0x02, 0x03, 0x04]
if Aser[0] == '\x04': if Aser[0] == 0x04:
return Point( curve, string_to_number(Aser[1:33]), string_to_number(Aser[33:]), _r ) return Point( curve, string_to_number(Aser[1:33]), string_to_number(Aser[33:]), _r )
Mx = string_to_number(Aser[1:]) Mx = string_to_number(Aser[1:])
return Point( curve, Mx, ECC_YfromX(Mx, curve, Aser[0]=='\x03')[0], _r ) return Point( curve, Mx, ECC_YfromX(Mx, curve, Aser[0] == 0x03)[0], _r )
class MyVerifyingKey(ecdsa.VerifyingKey): class MyVerifyingKey(ecdsa.VerifyingKey):
@ -552,14 +585,14 @@ class MyVerifyingKey(ecdsa.VerifyingKey):
def from_signature(klass, sig, recid, h, curve): def from_signature(klass, sig, recid, h, curve):
""" See http://www.secg.org/download/aid-780/sec1-v2.pdf, chapter 4.1.6 """ """ See http://www.secg.org/download/aid-780/sec1-v2.pdf, chapter 4.1.6 """
from ecdsa import util, numbertheory from ecdsa import util, numbertheory
import msqr from . import msqr
curveFp = curve.curve curveFp = curve.curve
G = curve.generator G = curve.generator
order = G.order() order = G.order()
# extract r,s from signature # extract r,s from signature
r, s = util.sigdecode_string(sig, order) r, s = util.sigdecode_string(sig, order)
# 1.1 # 1.1
x = r + (recid/2) * order x = r + (recid//2) * order
# 1.3 # 1.3
alpha = ( x * x * x + curveFp.a() * x + curveFp.b() ) % curveFp.p() alpha = ( x * x * x + curveFp.a() * x + curveFp.b() ) % curveFp.p()
beta = msqr.modular_sqrt(alpha, curveFp.p()) beta = msqr.modular_sqrt(alpha, curveFp.p())
@ -578,7 +611,7 @@ class MyVerifyingKey(ecdsa.VerifyingKey):
def pubkey_from_signature(sig, h): def pubkey_from_signature(sig, h):
if len(sig) != 65: if len(sig) != 65:
raise Exception("Wrong encoding") raise Exception("Wrong encoding")
nV = ord(sig[0]) nV = sig[0]
if nV < 27 or nV >= 35: if nV < 27 or nV >= 35:
raise Exception("Bad encoding") raise Exception("Bad encoding")
if nV >= 31: if nV >= 31:
@ -598,7 +631,7 @@ class MySigningKey(ecdsa.SigningKey):
G = curve.generator G = curve.generator
order = G.order() order = G.order()
r, s = ecdsa.SigningKey.sign_number(self, number, entropy, k) r, s = ecdsa.SigningKey.sign_number(self, number, entropy, k)
if s > order/2: if s > order//2:
s = order - s s = order - s
return r, s return r, s
@ -612,7 +645,7 @@ class EC_KEY(object):
self.secret = secret self.secret = secret
def get_public_key(self, compressed=True): def get_public_key(self, compressed=True):
return point_to_ser(self.pubkey.point, compressed).encode('hex') return bh2u(point_to_ser(self.pubkey.point, compressed))
def sign(self, msg_hash): def sign(self, msg_hash):
private_key = MySigningKey.from_secret_exponent(self.secret, curve = SECP256k1) private_key = MySigningKey.from_secret_exponent(self.secret, curve = SECP256k1)
@ -622,19 +655,20 @@ class EC_KEY(object):
return signature return signature
def sign_message(self, message, is_compressed): def sign_message(self, message, is_compressed):
message = to_bytes(message, 'utf8')
signature = self.sign(Hash(msg_magic(message))) signature = self.sign(Hash(msg_magic(message)))
for i in range(4): for i in range(4):
sig = chr(27 + i + (4 if is_compressed else 0)) + signature sig = bytes([27 + i + (4 if is_compressed else 0)]) + signature
try: try:
self.verify_message(sig, message) self.verify_message(sig, message)
return sig return sig
except Exception: except Exception as e:
continue continue
else: else:
raise Exception("error: cannot sign message") raise Exception("error: cannot sign message")
def verify_message(self, sig, message): def verify_message(self, sig, message):
assert_bytes(message)
h = Hash(msg_magic(message)) h = Hash(msg_magic(message))
public_key, compressed = pubkey_from_signature(sig, h) public_key, compressed = pubkey_from_signature(sig, h)
# check public key # check public key
@ -648,6 +682,7 @@ class EC_KEY(object):
@classmethod @classmethod
def encrypt_message(self, message, pubkey): def encrypt_message(self, message, pubkey):
assert_bytes(message)
pk = ser_to_point(pubkey) pk = ser_to_point(pubkey)
if not ecdsa.ecdsa.point_is_valid(generator_secp256k1, pk.x(), pk.y()): if not ecdsa.ecdsa.point_is_valid(generator_secp256k1, pk.x(), pk.y()):
@ -659,13 +694,12 @@ class EC_KEY(object):
key = hashlib.sha512(ecdh_key).digest() key = hashlib.sha512(ecdh_key).digest()
iv, key_e, key_m = key[0:16], key[16:32], key[32:] iv, key_e, key_m = key[0:16], key[16:32], key[32:]
ciphertext = aes_encrypt_with_iv(key_e, iv, message) ciphertext = aes_encrypt_with_iv(key_e, iv, message)
ephemeral_pubkey = ephemeral.get_public_key(compressed=True).decode('hex') ephemeral_pubkey = bfh(ephemeral.get_public_key(compressed=True))
encrypted = 'BIE1' + ephemeral_pubkey + ciphertext encrypted = b'BIE1' + ephemeral_pubkey + ciphertext
mac = hmac.new(key_m, encrypted, hashlib.sha256).digest() mac = hmac.new(key_m, encrypted, hashlib.sha256).digest()
return base64.b64encode(encrypted + mac) return base64.b64encode(encrypted + mac)
def decrypt_message(self, encrypted): def decrypt_message(self, encrypted):
encrypted = base64.b64decode(encrypted) encrypted = base64.b64decode(encrypted)
if len(encrypted) < 85: if len(encrypted) < 85:
@ -674,11 +708,11 @@ class EC_KEY(object):
ephemeral_pubkey = encrypted[4:37] ephemeral_pubkey = encrypted[4:37]
ciphertext = encrypted[37:-32] ciphertext = encrypted[37:-32]
mac = encrypted[-32:] mac = encrypted[-32:]
if magic != 'BIE1': if magic != b'BIE1':
raise Exception('invalid ciphertext: invalid magic bytes') raise Exception('invalid ciphertext: invalid magic bytes')
try: try:
ephemeral_pubkey = ser_to_point(ephemeral_pubkey) ephemeral_pubkey = ser_to_point(ephemeral_pubkey)
except AssertionError, e: except AssertionError as e:
raise Exception('invalid ciphertext: invalid ephemeral pubkey') raise Exception('invalid ciphertext: invalid ephemeral pubkey')
if not ecdsa.ecdsa.point_is_valid(generator_secp256k1, ephemeral_pubkey.x(), ephemeral_pubkey.y()): if not ecdsa.ecdsa.point_is_valid(generator_secp256k1, ephemeral_pubkey.x(), ephemeral_pubkey.y()):
raise Exception('invalid ciphertext: invalid ephemeral pubkey') raise Exception('invalid ciphertext: invalid ephemeral pubkey')
@ -715,13 +749,14 @@ def get_pubkeys_from_secret(secret):
# public key can be determined without the master private key. # public key can be determined without the master private key.
def CKD_priv(k, c, n): def CKD_priv(k, c, n):
is_prime = n & BIP32_PRIME is_prime = n & BIP32_PRIME
return _CKD_priv(k, c, rev_hex(int_to_hex(n,4)).decode('hex'), is_prime) return _CKD_priv(k, c, bfh(rev_hex(int_to_hex(n,4))), is_prime)
def _CKD_priv(k, c, s, is_prime): def _CKD_priv(k, c, s, is_prime):
order = generator_secp256k1.order() order = generator_secp256k1.order()
keypair = EC_KEY(k) keypair = EC_KEY(k)
cK = GetPubKey(keypair.pubkey,True) cK = GetPubKey(keypair.pubkey,True)
data = chr(0) + k + s if is_prime else cK + s data = bytes([0]) + k + s if is_prime else cK + s
I = hmac.new(c, data, hashlib.sha512).digest() I = hmac.new(c, data, hashlib.sha512).digest()
k_n = number_to_string( (string_to_number(I[0:32]) + string_to_number(k)) % order , order ) k_n = number_to_string( (string_to_number(I[0:32]) + string_to_number(k)) % order , order )
c_n = I[32:] c_n = I[32:]
@ -735,7 +770,7 @@ def _CKD_priv(k, c, s, is_prime):
# non-negative. If n is negative, we need the master private key to find it. # non-negative. If n is negative, we need the master private key to find it.
def CKD_pub(cK, c, n): def CKD_pub(cK, c, n):
if n & BIP32_PRIME: raise if n & BIP32_PRIME: raise
return _CKD_pub(cK, c, rev_hex(int_to_hex(n,4)).decode('hex')) return _CKD_pub(cK, c, bfh(rev_hex(int_to_hex(n,4))))
# helper function, callable with arbitrary string # helper function, callable with arbitrary string
def _CKD_pub(cK, c, s): def _CKD_pub(cK, c, s):
@ -750,41 +785,48 @@ def _CKD_pub(cK, c, s):
def xprv_header(xtype): def xprv_header(xtype):
return ("%08x"%(XPRV_HEADER + xtype)).decode('hex') return bfh("%08x" % (XPRV_HEADER + xtype))
def xpub_header(xtype): def xpub_header(xtype):
return ("%08x"%(XPUB_HEADER + xtype)).decode('hex') return bfh("%08x" % (XPUB_HEADER + xtype))
def serialize_xprv(xtype, c, k, depth=0, fingerprint=chr(0)*4, child_number=chr(0)*4):
xprv = xprv_header(xtype) + chr(depth) + fingerprint + child_number + c + chr(0) + k def serialize_xprv(xtype, c, k, depth=0, fingerprint=b'\x00'*4, child_number=b'\x00'*4):
xprv = xprv_header(xtype) + bytes([depth]) + fingerprint + child_number + c + bytes([0]) + k
return EncodeBase58Check(xprv) return EncodeBase58Check(xprv)
def serialize_xpub(xtype, c, cK, depth=0, fingerprint=chr(0)*4, child_number=chr(0)*4):
xpub = xpub_header(xtype) + chr(depth) + fingerprint + child_number + c + cK def serialize_xpub(xtype, c, cK, depth=0, fingerprint=b'\x00'*4, child_number=b'\x00'*4):
xpub = xpub_header(xtype) + bytes([depth]) + fingerprint + child_number + c + cK
return EncodeBase58Check(xpub) return EncodeBase58Check(xpub)
def deserialize_xkey(xkey, prv): def deserialize_xkey(xkey, prv):
xkey = DecodeBase58Check(xkey) xkey = DecodeBase58Check(xkey)
if len(xkey) != 78: if len(xkey) != 78:
raise BaseException('Invalid length') raise BaseException('Invalid length')
depth = ord(xkey[4]) depth = xkey[4]
fingerprint = xkey[5:9] fingerprint = xkey[5:9]
child_number = xkey[9:13] child_number = xkey[9:13]
c = xkey[13:13+32] c = xkey[13:13+32]
header = XPRV_HEADER if prv else XPUB_HEADER header = XPRV_HEADER if prv else XPUB_HEADER
xtype = int('0x' + xkey[0:4].encode('hex'), 16) - header xtype = int('0x' + bh2u(xkey[0:4]), 16) - header
if xtype not in ([0, 1] if TESTNET else [0]): if xtype not in ([0, 1] if TESTNET else [0]):
raise BaseException('Invalid header') raise BaseException('Invalid header')
n = 33 if prv else 32 n = 33 if prv else 32
K_or_k = xkey[13+n:] K_or_k = xkey[13+n:]
return xtype, depth, fingerprint, child_number, c, K_or_k return xtype, depth, fingerprint, child_number, c, K_or_k
def deserialize_xpub(xkey): def deserialize_xpub(xkey):
return deserialize_xkey(xkey, False) return deserialize_xkey(xkey, False)
def deserialize_xprv(xkey): def deserialize_xprv(xkey):
return deserialize_xkey(xkey, True) return deserialize_xkey(xkey, True)
def is_xpub(text): def is_xpub(text):
try: try:
deserialize_xpub(text) deserialize_xpub(text)
@ -792,6 +834,7 @@ def is_xpub(text):
except: except:
return False return False
def is_xprv(text): def is_xprv(text):
try: try:
deserialize_xprv(text) deserialize_xprv(text)
@ -807,7 +850,7 @@ def xpub_from_xprv(xprv):
def bip32_root(seed, xtype): def bip32_root(seed, xtype):
I = hmac.new("Bitcoin seed", seed, hashlib.sha512).digest() I = hmac.new(b"Bitcoin seed", seed, hashlib.sha512).digest()
master_k = I[0:32] master_k = I[0:32]
master_c = I[32:] master_c = I[32:]
K, cK = get_pubkeys_from_secret(master_k) K, cK = get_pubkeys_from_secret(master_k)
@ -815,9 +858,10 @@ def bip32_root(seed, xtype):
xpub = serialize_xpub(xtype, master_c, cK) xpub = serialize_xpub(xtype, master_c, cK)
return xprv, xpub return xprv, xpub
def xpub_from_pubkey(xtype, cK): def xpub_from_pubkey(xtype, cK):
assert cK[0] in ['\x02','\x03'] assert cK[0] in [0x02, 0x03]
return serialize_xpub(xtype, chr(0)*32, cK) return serialize_xpub(xtype, b'\x00'*32, cK)
def bip32_derivation(s): def bip32_derivation(s):
@ -849,7 +893,7 @@ def bip32_private_derivation(xprv, branch, sequence):
depth += 1 depth += 1
_, parent_cK = get_pubkeys_from_secret(parent_k) _, parent_cK = get_pubkeys_from_secret(parent_k)
fingerprint = hash_160(parent_cK)[0:4] fingerprint = hash_160(parent_cK)[0:4]
child_number = ("%08X"%i).decode('hex') child_number = bfh("%08X"%i)
K, cK = get_pubkeys_from_secret(k) K, cK = get_pubkeys_from_secret(k)
xpub = serialize_xpub(xtype, c, cK, depth, fingerprint, child_number) xpub = serialize_xpub(xtype, c, cK, depth, fingerprint, child_number)
xprv = serialize_xprv(xtype, c, k, depth, fingerprint, child_number) xprv = serialize_xprv(xtype, c, k, depth, fingerprint, child_number)
@ -867,7 +911,7 @@ def bip32_public_derivation(xpub, branch, sequence):
cK, c = CKD_pub(cK, c, i) cK, c = CKD_pub(cK, c, i)
depth += 1 depth += 1
fingerprint = hash_160(parent_cK)[0:4] fingerprint = hash_160(parent_cK)[0:4]
child_number = ("%08X"%i).decode('hex') child_number = bfh("%08X"%i)
return serialize_xpub(xtype, c, cK, depth, fingerprint, child_number) return serialize_xpub(xtype, c, cK, depth, fingerprint, child_number)
@ -878,7 +922,7 @@ def bip32_private_key(sequence, k, chain):
def xkeys_from_seed(seed, passphrase, derivation): def xkeys_from_seed(seed, passphrase, derivation):
from mnemonic import Mnemonic from .mnemonic import Mnemonic
xprv, xpub = bip32_root(Mnemonic.mnemonic_to_seed(seed, passphrase), 0) xprv, xpub = bip32_root(Mnemonic.mnemonic_to_seed(seed, passphrase), 0)
xprv, xpub = bip32_private_derivation(xprv, "m/", derivation) xprv, xpub = bip32_private_derivation(xprv, "m/", derivation)
return xprv, xpub return xprv, xpub

View File

@ -22,15 +22,20 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import os import os
import util
import threading import threading
import bitcoin from . import util
from bitcoin import * from . import bitcoin
from .bitcoin import *
MAX_TARGET = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 MAX_TARGET = 0x00000000FFFF0000000000000000000000000000000000000000000000000000

View File

@ -22,13 +22,19 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from collections import defaultdict, namedtuple from collections import defaultdict, namedtuple
from math import floor, log10 from math import floor, log10
from bitcoin import sha256, COIN, TYPE_ADDRESS from .bitcoin import sha256, COIN, TYPE_ADDRESS
from transaction import Transaction from .transaction import Transaction
from util import NotEnoughFunds, PrintError, profiler from .util import NotEnoughFunds, PrintError, profiler
# A simple deterministic PRNG. Used to deterministically shuffle a # A simple deterministic PRNG. Used to deterministically shuffle a
# set of coins - the same set of coins should produce the same output. # set of coins - the same set of coins should produce the same output.
@ -36,7 +42,6 @@ from util import NotEnoughFunds, PrintError, profiler
# so if sending twice from the same UTXO set we choose the same UTXOs # so if sending twice from the same UTXO set we choose the same UTXOs
# to spend. This prevents attacks on users by malicious or stale # to spend. This prevents attacks on users by malicious or stale
# servers. # servers.
class PRNG: class PRNG:
def __init__(self, seed): def __init__(self, seed):
self.sha = sha256(seed) self.sha = sha256(seed)

View File

@ -22,7 +22,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import os import os
import sys import sys
import datetime import datetime
@ -35,15 +40,16 @@ import base64
from functools import wraps from functools import wraps
from decimal import Decimal from decimal import Decimal
import util from .import util
from util import print_msg, format_satoshis, print_stderr from .util import print_msg, format_satoshis, print_stderr
import bitcoin from .import bitcoin
from bitcoin import is_address, hash_160, COIN, TYPE_ADDRESS from .bitcoin import is_address, hash_160, COIN, TYPE_ADDRESS
import transaction from .transaction import Transaction
from transaction import Transaction from .import paymentrequest
import paymentrequest from .paymentrequest import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED
from paymentrequest import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED from .import contacts
import contacts if six.PY3:
long = int
known_commands = {} known_commands = {}
@ -53,7 +59,6 @@ def satoshis(amount):
class Command: class Command:
def __init__(self, func, s): def __init__(self, func, s):
self.name = func.__name__ self.name = func.__name__
self.requires_network = 'n' in s self.requires_network = 'n' in s
@ -61,8 +66,8 @@ class Command:
self.requires_password = 'p' in s self.requires_password = 'p' in s
self.description = func.__doc__ self.description = func.__doc__
self.help = self.description.split('.')[0] if self.description else None self.help = self.description.split('.')[0] if self.description else None
varnames = func.func_code.co_varnames[1:func.func_code.co_argcount] varnames = func.__code__.co_varnames[1:func.__code__.co_argcount]
self.defaults = func.func_defaults self.defaults = func.__defaults__
if self.defaults: if self.defaults:
n = len(self.defaults) n = len(self.defaults)
self.params = list(varnames[:-n]) self.params = list(varnames[:-n])
@ -728,7 +733,7 @@ command_options = {
# don't use floats because of rounding errors # don't use floats because of rounding errors
from transaction import tx_from_str from .transaction import tx_from_str
json_loads = lambda x: json.loads(x, parse_float=lambda x: str(Decimal(x))) json_loads = lambda x: json.loads(x, parse_float=lambda x: str(Decimal(x)))
arg_types = { arg_types = {
'num': int, 'num': int,

View File

@ -20,6 +20,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import sys import sys
import re import re
@ -27,10 +33,10 @@ import dns
import os import os
import json import json
import bitcoin from . import bitcoin
import dnssec from . import dnssec
from util import print_error from .util import print_error
from i18n import _ from .i18n import _
class Contacts(dict): class Contacts(dict):

View File

@ -22,25 +22,30 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import ast import ast
import os import os
import sys import sys
import time import time
import jsonrpclib # import jsonrpclib
from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer, SimpleJSONRPCRequestHandler # from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer, SimpleJSONRPCRequestHandler
from version import ELECTRUM_VERSION from .version import ELECTRUM_VERSION
from network import Network from .network import Network
from util import json_decode, DaemonThread from .util import json_decode, DaemonThread
from util import print_msg, print_error, print_stderr, UserCancelled from .util import print_msg, print_error, print_stderr, UserCancelled
from wallet import Wallet from .wallet import Wallet
from storage import WalletStorage from .storage import WalletStorage
from commands import known_commands, Commands from .commands import known_commands, Commands
from simple_config import SimpleConfig from .simple_config import SimpleConfig
from plugins import run_hook from .plugins import run_hook
from exchange_rate import FxThread from .exchange_rate import FxThread
def get_lockfile(config): def get_lockfile(config):
return os.path.join(config.path, 'daemon') return os.path.join(config.path, 'daemon')
@ -85,18 +90,17 @@ def get_server(config):
time.sleep(1.0) time.sleep(1.0)
# class RequestHandler(SimpleJSONRPCRequestHandler):
class RequestHandler(SimpleJSONRPCRequestHandler): #
# def do_OPTIONS(self):
def do_OPTIONS(self): # self.send_response(200)
self.send_response(200) # self.end_headers()
self.end_headers() #
# def end_headers(self):
def end_headers(self): # self.send_header("Access-Control-Allow-Headers",
self.send_header("Access-Control-Allow-Headers", # "Origin, X-Requested-With, Content-Type, Accept")
"Origin, X-Requested-With, Content-Type, Accept") # self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Access-Control-Allow-Origin", "*") # SimpleJSONRPCRequestHandler.end_headers(self)
SimpleJSONRPCRequestHandler.end_headers(self)
class Daemon(DaemonThread): class Daemon(DaemonThread):

View File

@ -22,7 +22,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
# Check DNSSEC trust chain. # Check DNSSEC trust chain.
@ -61,25 +66,21 @@ import dns.rdtypes.IN.AAAA
from dns.exception import DNSException from dns.exception import DNSException
# Pure-Python version of dns.dnssec._validate_rsig
"""
Pure-Python version of dns.dnssec._validate_rsig
"""
import ecdsa import ecdsa
import rsakey from . import rsakey
def python_validate_rrsig(rrset, rrsig, keys, origin=None, now=None): def python_validate_rrsig(rrset, rrsig, keys, origin=None, now=None):
from dns.dnssec import ValidationFailure, ECDSAP256SHA256, ECDSAP384SHA384 from dns.dnssec import ValidationFailure, ECDSAP256SHA256, ECDSAP384SHA384
from dns.dnssec import _find_candidate_keys, _make_hash, _is_ecdsa, _is_rsa, _to_rdata, _make_algorithm_id from dns.dnssec import _find_candidate_keys, _make_hash, _is_ecdsa, _is_rsa, _to_rdata, _make_algorithm_id
if isinstance(origin, (str, unicode)): if isinstance(origin, six.text_type):
origin = dns.name.from_text(origin, dns.name.root) origin = dns.name.from_text(origin, dns.name.root)
for candidate_key in _find_candidate_keys(keys, rrsig): for candidate_key in _find_candidate_keys(keys, rrsig):
if not candidate_key: if not candidate_key:
raise ValidationFailure, 'unknown key' raise ValidationFailure('unknown key')
# For convenience, allow the rrset to be specified as a (name, rdataset) # For convenience, allow the rrset to be specified as a (name, rdataset)
# tuple as well as a proper rrset # tuple as well as a proper rrset
@ -93,9 +94,9 @@ def python_validate_rrsig(rrset, rrsig, keys, origin=None, now=None):
if now is None: if now is None:
now = time.time() now = time.time()
if rrsig.expiration < now: if rrsig.expiration < now:
raise ValidationFailure, 'expired' raise ValidationFailure('expired')
if rrsig.inception > now: if rrsig.inception > now:
raise ValidationFailure, 'not yet valid' raise ValidationFailure('not yet valid')
hash = _make_hash(rrsig.algorithm) hash = _make_hash(rrsig.algorithm)
@ -124,7 +125,7 @@ def python_validate_rrsig(rrset, rrsig, keys, origin=None, now=None):
digest_len = 48 digest_len = 48
else: else:
# shouldn't happen # shouldn't happen
raise ValidationFailure, 'unknown ECDSA curve' raise ValidationFailure('unknown ECDSA curve')
keyptr = candidate_key.key keyptr = candidate_key.key
x = ecdsa.util.string_to_number(keyptr[0:key_len]) x = ecdsa.util.string_to_number(keyptr[0:key_len])
y = ecdsa.util.string_to_number(keyptr[key_len:key_len * 2]) y = ecdsa.util.string_to_number(keyptr[key_len:key_len * 2])
@ -137,7 +138,7 @@ def python_validate_rrsig(rrset, rrsig, keys, origin=None, now=None):
ecdsa.util.string_to_number(s)) ecdsa.util.string_to_number(s))
else: else:
raise ValidationFailure, 'unknown algorithm %u' % rrsig.algorithm raise ValidationFailure('unknown algorithm %u' % rrsig.algorithm)
hash.update(_to_rdata(rrsig, origin)[:18]) hash.update(_to_rdata(rrsig, origin)[:18])
hash.update(rrsig.signer.to_digestable(origin)) hash.update(rrsig.signer.to_digestable(origin))
@ -170,9 +171,9 @@ def python_validate_rrsig(rrset, rrsig, keys, origin=None, now=None):
return return
else: else:
raise ValidationFailure, 'unknown algorithm %u' % rrsig.algorithm raise ValidationFailure('unknown algorithm %s' % rrsig.algorithm)
raise ValidationFailure, 'verify failure' raise ValidationFailure('verify failure')
# replace validate_rrsig # replace validate_rrsig
@ -182,7 +183,7 @@ dns.dnssec.validate = dns.dnssec._validate
from util import print_error from .util import print_error
# hard-coded trust anchors (root KSKs) # hard-coded trust anchors (root KSKs)

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from datetime import datetime from datetime import datetime
import inspect import inspect
import requests import requests
@ -8,10 +14,10 @@ import traceback
import csv import csv
from decimal import Decimal from decimal import Decimal
from bitcoin import COIN from .bitcoin import COIN
from i18n import _ from .i18n import _
from util import PrintError, ThreadJob from .util import PrintError, ThreadJob
from util import format_satoshis from .util import format_satoshis
# See https://en.wikipedia.org/wiki/ISO_4217 # See https://en.wikipedia.org/wiki/ISO_4217
@ -22,6 +28,7 @@ CCY_PRECISIONS = {'BHD': 3, 'BIF': 0, 'BYR': 0, 'CLF': 4, 'CLP': 0,
'RWF': 0, 'TND': 3, 'UGX': 0, 'UYI': 0, 'VND': 0, 'RWF': 0, 'TND': 3, 'UGX': 0, 'UYI': 0, 'VND': 0,
'VUV': 0, 'XAF': 0, 'XAU': 4, 'XOF': 0, 'XPF': 0} 'VUV': 0, 'XAF': 0, 'XAU': 4, 'XOF': 0, 'XPF': 0}
class ExchangeBase(PrintError): class ExchangeBase(PrintError):
def __init__(self, on_quotes, on_history): def __init__(self, on_quotes, on_history):
@ -323,7 +330,7 @@ class Winkdex(ExchangeBase):
def dictinvert(d): def dictinvert(d):
inv = {} inv = {}
for k, vlist in d.iteritems(): for k, vlist in d.items():
for v in vlist: for v in vlist:
keys = inv.setdefault(v, []) keys = inv.setdefault(v, [])
keys.append(k) keys.append(k)

View File

@ -22,16 +22,24 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import gettext, os import gettext, os, six
LOCALE_DIR = os.path.join(os.path.dirname(__file__), 'locale') LOCALE_DIR = os.path.join(os.path.dirname(__file__), 'locale')
language = gettext.translation('electrum', LOCALE_DIR, fallback = True) language = gettext.translation('electrum', LOCALE_DIR, fallback = True)
if six.PY2:
def _(x): def _(x):
global language global language
return language.ugettext(x) return language.ugettext(x)
else:
def _(x):
global language
return language.gettext(x)
def set_language(x): def set_language(x):
global language global language

View File

@ -22,8 +22,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import os import os
import re import re
import socket import socket
@ -36,9 +40,9 @@ import traceback
import requests import requests
ca_path = requests.certs.where() ca_path = requests.certs.where()
import util from . import util
import x509 from . import x509
import pem from . import pem
def Connection(server, queue, config_path): def Connection(server, queue, config_path):
@ -80,7 +84,7 @@ class TcpConnection(threading.Thread, util.PrintError):
# None/{} is not acceptable. # None/{} is not acceptable.
if not peercert: if not peercert:
return False return False
if peercert.has_key("subjectAltName"): if 'subjectAltName' in peercert:
for typ, val in peercert["subjectAltName"]: for typ, val in peercert["subjectAltName"]:
if typ == "DNS" and val == name: if typ == "DNS" and val == name:
return True return True
@ -102,6 +106,7 @@ class TcpConnection(threading.Thread, util.PrintError):
except socket.gaierror: except socket.gaierror:
self.print_error("cannot resolve hostname") self.print_error("cannot resolve hostname")
return return
e = None
for res in l: for res in l:
try: try:
s = socket.socket(res[0], socket.SOCK_STREAM) s = socket.socket(res[0], socket.SOCK_STREAM)
@ -110,7 +115,8 @@ class TcpConnection(threading.Thread, util.PrintError):
s.settimeout(2) s.settimeout(2)
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
return s return s
except BaseException as e: except BaseException as _e:
e = _e
continue continue
else: else:
self.print_error("failed to connect", str(e)) self.print_error("failed to connect", str(e))
@ -126,7 +132,7 @@ class TcpConnection(threading.Thread, util.PrintError):
# try with CA first # try with CA first
try: 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_SSLv23, cert_reqs=ssl.CERT_REQUIRED, ca_certs=ca_path, do_handshake_on_connect=True)
except ssl.SSLError, e: except ssl.SSLError as e:
s = None s = None
if s and self.check_host_name(s.getpeercert(), self.host): if s and self.check_host_name(s.getpeercert(), self.host):
self.print_error("SSL certificate signed by CA") self.print_error("SSL certificate signed by CA")
@ -138,7 +144,7 @@ class TcpConnection(threading.Thread, util.PrintError):
return return
try: 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_SSLv23, cert_reqs=ssl.CERT_NONE, ca_certs=None)
except ssl.SSLError, e: except ssl.SSLError as e:
self.print_error("SSL error retrieving SSL certificate:", e) self.print_error("SSL error retrieving SSL certificate:", e)
return return
@ -164,7 +170,7 @@ class TcpConnection(threading.Thread, util.PrintError):
cert_reqs=ssl.CERT_REQUIRED, 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) do_handshake_on_connect=True)
except ssl.SSLError, e: except ssl.SSLError as e:
self.print_error("SSL error:", e) self.print_error("SSL error:", e)
if e.errno != 1: if e.errno != 1:
return return
@ -191,7 +197,7 @@ class TcpConnection(threading.Thread, util.PrintError):
return return
self.print_error("wrong certificate") self.print_error("wrong certificate")
return return
except BaseException, e: except BaseException as e:
self.print_error(e) self.print_error(e)
if e.errno == 104: if e.errno == 104:
return return
@ -264,12 +270,12 @@ class Interface(util.PrintError):
def send_requests(self): def send_requests(self):
'''Sends queued requests. Returns False on failure.''' '''Sends queued requests. Returns False on failure.'''
make_dict = lambda (m, p, i): {'method': m, 'params': p, 'id': i} make_dict = lambda m, p, i: {'method': m, 'params': p, 'id': i}
n = self.num_requests() n = self.num_requests()
wire_requests = self.unsent_requests[0:n] wire_requests = self.unsent_requests[0:n]
try: try:
self.pipe.send_all(map(make_dict, wire_requests)) self.pipe.send_all(map(make_dict, wire_requests))
except socket.error, e: except socket.error as e:
self.print_error("socket error:", e) self.print_error("socket error:", e)
return False return False
self.unsent_requests = self.unsent_requests[n:] self.unsent_requests = self.unsent_requests[n:]
@ -363,12 +369,12 @@ def _match_hostname(name, val):
return val.startswith('*.') and name.endswith(val[1:]) return val.startswith('*.') and name.endswith(val[1:])
def test_certificates(): def test_certificates():
from simple_config import SimpleConfig from .simple_config import SimpleConfig
config = SimpleConfig() config = SimpleConfig()
mydir = os.path.join(config.path, "certs") mydir = os.path.join(config.path, "certs")
certs = os.listdir(mydir) certs = os.listdir(mydir)
for c in certs: for c in certs:
print c print(c)
p = os.path.join(mydir,c) p = os.path.join(mydir,c)
with open(p) as f: with open(p) as f:
cert = f.read() cert = f.read()

View File

@ -28,15 +28,15 @@ import struct
from unicodedata import normalize from unicodedata import normalize
from version import * from .version import *
import bitcoin from . import bitcoin
from bitcoin import pw_encode, pw_decode, bip32_root, bip32_private_derivation, bip32_public_derivation, bip32_private_key, deserialize_xprv, deserialize_xpub from .bitcoin import pw_encode, pw_decode, bip32_root, bip32_private_derivation, bip32_public_derivation, bip32_private_key, deserialize_xprv, deserialize_xpub
from bitcoin import public_key_from_private_key, public_key_to_p2pkh from .bitcoin import public_key_from_private_key, public_key_to_p2pkh
from bitcoin import * from .bitcoin import *
from bitcoin import is_old_seed, is_new_seed, is_seed from .bitcoin import is_old_seed, is_new_seed, is_seed
from util import PrintError, InvalidPassword from .util import PrintError, InvalidPassword
from mnemonic import Mnemonic, load_wordlist from .mnemonic import Mnemonic, load_wordlist
class KeyStore(PrintError): class KeyStore(PrintError):
@ -170,7 +170,7 @@ class Imported_KeyStore(Software_KeyStore):
# fixme: this assumes p2pkh # fixme: this assumes p2pkh
_, addr = xpubkey_to_address(x_pubkey) _, addr = xpubkey_to_address(x_pubkey)
for pubkey in self.keypairs.keys(): for pubkey in self.keypairs.keys():
if public_key_to_p2pkh(pubkey.decode('hex')) == addr: if public_key_to_p2pkh(bfh(pubkey)) == addr:
return pubkey return pubkey
def update_password(self, old_password, new_password): def update_password(self, old_password, new_password):
@ -247,22 +247,22 @@ class Xpub:
_, _, _, _, c, cK = deserialize_xpub(xpub) _, _, _, _, c, cK = deserialize_xpub(xpub)
for i in sequence: for i in sequence:
cK, c = CKD_pub(cK, c, i) cK, c = CKD_pub(cK, c, i)
return cK.encode('hex') return bh2u(cK)
def get_xpubkey(self, c, i): def get_xpubkey(self, c, i):
s = ''.join(map(lambda x: bitcoin.int_to_hex(x,2), (c, i))) s = ''.join(map(lambda x: bitcoin.int_to_hex(x,2), (c, i)))
return 'ff' + bitcoin.DecodeBase58Check(self.xpub).encode('hex') + s return 'ff' + bh2u(bitcoin.DecodeBase58Check(self.xpub)) + s
@classmethod @classmethod
def parse_xpubkey(self, pubkey): def parse_xpubkey(self, pubkey):
assert pubkey[0:2] == 'ff' assert pubkey[0:2] == 'ff'
pk = pubkey.decode('hex') pk = bfh(pubkey)
pk = pk[1:] pk = pk[1:]
xkey = bitcoin.EncodeBase58Check(pk[0:78]) xkey = bitcoin.EncodeBase58Check(pk[0:78])
dd = pk[78:] dd = pk[78:]
s = [] s = []
while dd: while dd:
n = int(bitcoin.rev_hex(dd[0:2].encode('hex')), 16) n = int(bitcoin.rev_hex(bh2u(dd[0:2])), 16)
dd = dd[2:] dd = dd[2:]
s.append(n) s.append(n)
assert len(s) == 2 assert len(s) == 2
@ -277,7 +277,6 @@ class Xpub:
return derivation return derivation
class BIP32_KeyStore(Deterministic_KeyStore, Xpub): class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
def __init__(self, d): def __init__(self, d):
@ -363,12 +362,12 @@ class Old_KeyStore(Deterministic_KeyStore):
self.mpk = mpk self.mpk = mpk
def format_seed(self, seed): def format_seed(self, seed):
import old_mnemonic from . import old_mnemonic
# see if seed was entered as hex # see if seed was entered as hex
seed = seed.strip() seed = seed.strip()
if seed: if seed:
try: try:
seed.decode('hex') bfh(seed)
return str(seed) return str(seed)
except Exception: except Exception:
pass pass
@ -379,7 +378,7 @@ class Old_KeyStore(Deterministic_KeyStore):
return seed return seed
def get_seed(self, password): def get_seed(self, password):
import old_mnemonic from . import old_mnemonic
s = self.get_hex_seed(password) s = self.get_hex_seed(password)
return ' '.join(old_mnemonic.mn_encode(s)) return ' '.join(old_mnemonic.mn_encode(s))
@ -388,7 +387,7 @@ class Old_KeyStore(Deterministic_KeyStore):
secexp = klass.stretch_key(seed) secexp = klass.stretch_key(seed)
master_private_key = ecdsa.SigningKey.from_secret_exponent(secexp, curve = SECP256k1) master_private_key = ecdsa.SigningKey.from_secret_exponent(secexp, curve = SECP256k1)
master_public_key = master_private_key.get_verifying_key().to_string() master_public_key = master_private_key.get_verifying_key().to_string()
return master_public_key.encode('hex') return bh2u(master_public_key)
@classmethod @classmethod
def stretch_key(self, seed): def stretch_key(self, seed):
@ -399,20 +398,20 @@ class Old_KeyStore(Deterministic_KeyStore):
@classmethod @classmethod
def get_sequence(self, mpk, for_change, n): def get_sequence(self, mpk, for_change, n):
return string_to_number(Hash("%d:%d:"%(n, for_change) + mpk.decode('hex'))) return string_to_number(Hash(("%d:%d:"%(n, for_change)).encode('ascii') + bfh(mpk)))
def get_address(self, for_change, n): def get_address(self, for_change, n):
pubkey = self.get_pubkey(for_change, n) pubkey = self.get_pubkey(for_change, n)
address = public_key_to_p2pkh(pubkey.decode('hex')) address = public_key_to_p2pkh(bfh(pubkey))
return address return address
@classmethod @classmethod
def get_pubkey_from_mpk(self, mpk, for_change, n): def get_pubkey_from_mpk(self, mpk, for_change, n):
z = self.get_sequence(mpk, for_change, n) z = self.get_sequence(mpk, for_change, n)
master_public_key = ecdsa.VerifyingKey.from_string(mpk.decode('hex'), curve = SECP256k1) master_public_key = ecdsa.VerifyingKey.from_string(bfh(mpk), curve = SECP256k1)
pubkey_point = master_public_key.pubkey.point + z*SECP256k1.generator pubkey_point = master_public_key.pubkey.point + z*SECP256k1.generator
public_key2 = ecdsa.VerifyingKey.from_public_point(pubkey_point, curve = SECP256k1) public_key2 = ecdsa.VerifyingKey.from_public_point(pubkey_point, curve = SECP256k1)
return '04' + public_key2.to_string().encode('hex') return '04' + bh2u(public_key2.to_string())
def derive_pubkey(self, for_change, n): def derive_pubkey(self, for_change, n):
return self.get_pubkey_from_mpk(self.mpk, for_change, n) return self.get_pubkey_from_mpk(self.mpk, for_change, n)
@ -436,8 +435,8 @@ class Old_KeyStore(Deterministic_KeyStore):
secexp = self.stretch_key(seed) secexp = self.stretch_key(seed)
master_private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 ) master_private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
master_public_key = master_private_key.get_verifying_key().to_string() master_public_key = master_private_key.get_verifying_key().to_string()
if master_public_key != self.mpk.decode('hex'): if master_public_key != bfh(self.mpk):
print_error('invalid password (mpk)', self.mpk, master_public_key.encode('hex')) print_error('invalid password (mpk)', self.mpk, bh2u(master_public_key))
raise InvalidPassword() raise InvalidPassword()
def check_password(self, password): def check_password(self, password):
@ -590,17 +589,20 @@ def bip39_is_checksum_valid(mnemonic):
def is_xpubkey(x_pubkey): def is_xpubkey(x_pubkey):
return x_pubkey[0:2] == 'ff' return x_pubkey[0:2] == 'ff'
def parse_xpubkey(x_pubkey): def parse_xpubkey(x_pubkey):
assert x_pubkey[0:2] == 'ff' assert x_pubkey[0:2] == 'ff'
return BIP32_KeyStore.parse_xpubkey(x_pubkey) return BIP32_KeyStore.parse_xpubkey(x_pubkey)
def xpubkey_to_address(x_pubkey): def xpubkey_to_address(x_pubkey):
if x_pubkey[0:2] == 'fd': if x_pubkey[0:2] == 'fd':
addrtype = ord(x_pubkey[2:4].decode('hex')) # TODO: check that ord() is OK here
hash160 = x_pubkey[4:].decode('hex') addrtype = ord(bfh(x_pubkey[2:4]))
hash160 = bfh(x_pubkey[4:])
address = bitcoin.hash_160_to_bc_address(hash160, addrtype) address = bitcoin.hash_160_to_bc_address(hash160, addrtype)
return x_pubkey, address return x_pubkey, address
if x_pubkey[0:2] in ['02','03','04']: if x_pubkey[0:2] in ['02', '03', '04']:
pubkey = x_pubkey pubkey = x_pubkey
elif x_pubkey[0:2] == 'ff': elif x_pubkey[0:2] == 'ff':
xpub, s = BIP32_KeyStore.parse_xpubkey(x_pubkey) xpub, s = BIP32_KeyStore.parse_xpubkey(x_pubkey)
@ -611,7 +613,7 @@ def xpubkey_to_address(x_pubkey):
else: else:
raise BaseException("Cannot parse pubkey") raise BaseException("Cannot parse pubkey")
if pubkey: if pubkey:
address = public_key_to_p2pkh(pubkey.decode('hex')) address = public_key_to_p2pkh(bfh(pubkey))
return pubkey, address return pubkey, address
def xpubkey_to_pubkey(x_pubkey): def xpubkey_to_pubkey(x_pubkey):
@ -649,7 +651,6 @@ def load_keystore(storage, name):
return k return k
def is_old_mpk(mpk): def is_old_mpk(mpk):
try: try:
int(mpk, 16) int(mpk, 16)
@ -657,10 +658,12 @@ def is_old_mpk(mpk):
return False return False
return len(mpk) == 128 return len(mpk) == 128
def is_address_list(text): def is_address_list(text):
parts = text.split() parts = text.split()
return bool(parts) and all(bitcoin.is_address(x) for x in parts) return bool(parts) and all(bitcoin.is_address(x) for x in parts)
def get_private_keys(text): def get_private_keys(text):
parts = text.split('\n') parts = text.split('\n')
parts = map(lambda x: ''.join(x.split()), parts) parts = map(lambda x: ''.join(x.split()), parts)
@ -668,15 +671,18 @@ def get_private_keys(text):
if bool(parts) and all(bitcoin.is_private_key(x) for x in parts): if bool(parts) and all(bitcoin.is_private_key(x) for x in parts):
return parts return parts
def is_private_key_list(text): def is_private_key_list(text):
return bool(get_private_keys(text)) return bool(get_private_keys(text))
is_mpk = lambda x: is_old_mpk(x) or is_xpub(x) is_mpk = lambda x: is_old_mpk(x) or is_xpub(x)
is_private = lambda x: is_seed(x) or is_xprv(x) or is_private_key_list(x) is_private = lambda x: is_seed(x) or is_xprv(x) or is_private_key_list(x)
is_any_key = lambda x: is_old_mpk(x) or is_xprv(x) or is_xpub(x) or is_private_key_list(x) is_any_key = lambda x: is_old_mpk(x) or is_xprv(x) or is_xpub(x) or is_private_key_list(x)
is_private_key = lambda x: is_xprv(x) or is_private_key_list(x) is_private_key = lambda x: is_xprv(x) or is_private_key_list(x)
is_bip32_key = lambda x: is_xprv(x) or is_xpub(x) is_bip32_key = lambda x: is_xprv(x) or is_xpub(x)
def bip44_derivation(account_id): def bip44_derivation(account_id):
if bitcoin.TESTNET: if bitcoin.TESTNET:
return "m/44'/1'/%d'"% int(account_id) return "m/44'/1'/%d'"% int(account_id)

View File

@ -22,6 +22,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import os import os
import hmac import hmac
@ -33,10 +39,10 @@ import string
import ecdsa import ecdsa
import pbkdf2 import pbkdf2
from util import print_error from .util import print_error
from bitcoin import is_old_seed, is_new_seed from .bitcoin import is_old_seed, is_new_seed
import version from . import version
import i18n from . import i18n
# http://www.asahi-net.or.jp/~ax2s-kmtn/ref/unicode/e_asia.html # http://www.asahi-net.or.jp/~ax2s-kmtn/ref/unicode/e_asia.html
CJK_INTERVALS = [ CJK_INTERVALS = [
@ -80,7 +86,10 @@ def is_CJK(c):
def normalize_text(seed): def normalize_text(seed):
# normalize # normalize
seed = unicodedata.normalize('NFKD', unicode(seed)) if six.PY2:
seed = unicodedata.normalize('NFKD', unicode(seed))
else:
seed = unicodedata.normalize('NFKD', str(seed))
# lower # lower
seed = seed.lower() seed = seed.lower()
# remove accents # remove accents
@ -139,7 +148,7 @@ class Mnemonic(object):
words = [] words = []
while i: while i:
x = i%n x = i%n
i = i/n i = i//n
words.append(self.wordlist[x]) words.append(self.wordlist[x])
return ' '.join(words) return ' '.join(words)

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
# from http://eli.thegreenplace.net/2009/03/07/computing-modular-square-roots-in-python/ # from http://eli.thegreenplace.net/2009/03/07/computing-modular-square-roots-in-python/
def modular_sqrt(a, p): def modular_sqrt(a, p):
@ -26,7 +32,7 @@ def modular_sqrt(a, p):
elif p == 2: elif p == 2:
return p return p
elif p % 4 == 3: elif p % 4 == 3:
return pow(a, (p + 1) / 4, p) return pow(a, (p + 1) // 4, p)
# Partition p-1 to s * 2^e for an odd s (i.e. # Partition p-1 to s * 2^e for an odd s (i.e.
# reduce all the powers of 2 from p-1) # reduce all the powers of 2 from p-1)
@ -34,7 +40,7 @@ def modular_sqrt(a, p):
s = p - 1 s = p - 1
e = 0 e = 0
while s % 2 == 0: while s % 2 == 0:
s /= 2 s //= 2
e += 1 e += 1
# Find some 'n' with a legendre symbol n|p = -1. # Find some 'n' with a legendre symbol n|p = -1.
@ -59,7 +65,7 @@ def modular_sqrt(a, p):
# both a and b # both a and b
# r is the exponent - decreases with each update # r is the exponent - decreases with each update
# #
x = pow(a, (s + 1) / 2, p) x = pow(a, (s + 1) // 2, p)
b = pow(a, s, p) b = pow(a, s, p)
g = pow(n, s, p) g = pow(n, s, p)
r = e r = e
@ -67,7 +73,7 @@ def modular_sqrt(a, p):
while True: while True:
t = b t = b
m = 0 m = 0
for m in xrange(r): for m in range(r):
if t == 1: if t == 1:
break break
t = pow(t, 2, p) t = pow(t, 2, p)
@ -90,5 +96,5 @@ def legendre_symbol(a, p):
Returns 1 if a has a square root modulo Returns 1 if a has a square root modulo
p, -1 otherwise. p, -1 otherwise.
""" """
ls = pow(a, (p - 1) / 2, p) ls = pow(a, (p - 1) // 2, p)
return -1 if ls == p - 1 else ls return -1 if ls == p - 1 else ls

View File

@ -20,9 +20,14 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import time import time
import Queue from six.moves import queue
import os import os
import errno import errno
import sys import sys
@ -32,16 +37,16 @@ import traceback
from collections import defaultdict, deque from collections import defaultdict, deque
import threading import threading
import socks
import socket import socket
import json import json
import util from . import socks
import bitcoin from . import util
from bitcoin import * from . import bitcoin
from interface import Connection, Interface from .bitcoin import *
import blockchain from .interface import Connection, Interface
from version import ELECTRUM_VERSION, PROTOCOL_VERSION from . import blockchain
from .version import ELECTRUM_VERSION, PROTOCOL_VERSION
DEFAULT_PORTS = {'t':'50001', 's':'50002'} DEFAULT_PORTS = {'t':'50001', 's':'50002'}
@ -143,7 +148,7 @@ def pick_random_server(hostmap = None, protocol = 's', exclude_set = set()):
eligible = list(set(filter_protocol(hostmap, protocol)) - exclude_set) eligible = list(set(filter_protocol(hostmap, protocol)) - exclude_set)
return random.choice(eligible) if eligible else None return random.choice(eligible) if eligible else None
from simple_config import SimpleConfig from .simple_config import SimpleConfig
proxy_modes = ['socks4', 'socks5', 'http'] proxy_modes = ['socks4', 'socks5', 'http']
@ -255,7 +260,7 @@ class Network(util.DaemonThread):
self.interfaces = {} self.interfaces = {}
self.auto_connect = self.config.get('auto_connect', True) self.auto_connect = self.config.get('auto_connect', True)
self.connecting = set() self.connecting = set()
self.socket_queue = Queue.Queue() self.socket_queue = queue.Queue()
self.start_network(deserialize_server(self.default_server)[2], self.start_network(deserialize_server(self.default_server)[2],
deserialize_proxy(self.config.get('proxy'))) deserialize_proxy(self.config.get('proxy')))
@ -436,8 +441,9 @@ class Network(util.DaemonThread):
# prevent dns leaks, see http://stackoverflow.com/questions/13184205/dns-over-proxy # prevent dns leaks, see http://stackoverflow.com/questions/13184205/dns-over-proxy
socket.getaddrinfo = lambda *args: [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (args[0], args[1]))] socket.getaddrinfo = lambda *args: [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (args[0], args[1]))]
else: else:
socket.socket = socket._socketobject if six.PY2:
socket.getaddrinfo = socket._socket.getaddrinfo socket.socket = socket._socketobject
socket.getaddrinfo = socket._socket.getaddrinfo
def start_network(self, protocol, proxy): def start_network(self, protocol, proxy):
assert not self.interface and not self.interfaces assert not self.interface and not self.interfaces
@ -458,7 +464,7 @@ class Network(util.DaemonThread):
assert not self.interfaces assert not self.interfaces
self.connecting = set() self.connecting = set()
# Get a new queue - no old pending connections thanks! # Get a new queue - no old pending connections thanks!
self.socket_queue = Queue.Queue() self.socket_queue = queue.Queue()
def set_parameters(self, host, port, protocol, proxy, auto_connect): def set_parameters(self, host, port, protocol, proxy, auto_connect):
proxy_str = serialize_proxy(proxy) proxy_str = serialize_proxy(proxy)
@ -936,7 +942,9 @@ class Network(util.DaemonThread):
win = [i for i in self.interfaces.values() if i.num_requests()] win = [i for i in self.interfaces.values() if i.num_requests()]
try: try:
rout, wout, xout = select.select(rin, win, [], 0.1) rout, wout, xout = select.select(rin, win, [], 0.1)
except socket.error as (code, msg): except socket.error as e:
# TODO: py3, get code from e
code = None
if code == errno.EINTR: if code == errno.EINTR:
return return
raise raise
@ -1056,11 +1064,11 @@ class Network(util.DaemonThread):
return self.blockchain().height() return self.blockchain().height()
def synchronous_get(self, request, timeout=30): def synchronous_get(self, request, timeout=30):
queue = Queue.Queue() queue = queue.Queue()
self.send([request], queue.put) self.send([request], queue.put)
try: try:
r = queue.get(True, timeout) r = queue.get(True, timeout)
except Queue.Empty: except queue.Empty:
raise BaseException('Server did not answer') raise BaseException('Server did not answer')
if r.get('error'): if r.get('error'):
raise BaseException(r.get('error')) raise BaseException(r.get('error'))

View File

@ -22,7 +22,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
# list of words from http://en.wiktionary.org/wiki/Wiktionary:Frequency_lists/Contemporary_poetry # list of words from http://en.wiktionary.org/wiki/Wiktionary:Frequency_lists/Contemporary_poetry
@ -1665,18 +1670,19 @@ n = 1626
def mn_encode( message ): def mn_encode( message ):
assert len(message) % 8 == 0 assert len(message) % 8 == 0
out = [] out = []
for i in range(len(message)/8): for i in range(len(message)//8):
word = message[8*i:8*i+8] word = message[8*i:8*i+8]
x = int(word, 16) x = int(word, 16)
w1 = (x%n) w1 = (x%n)
w2 = ((x/n) + w1)%n w2 = ((x//n) + w1)%n
w3 = ((x/n/n) + w2)%n w3 = ((x//n//n) + w2)%n
out += [ words[w1], words[w2], words[w3] ] out += [ words[w1], words[w2], words[w3] ]
return out return out
def mn_decode( wlist ): def mn_decode( wlist ):
out = '' out = ''
for i in range(len(wlist)/3): for i in range(len(wlist)//3):
word1, word2, word3 = wlist[3*i:3*i+3] word1, word2, word3 = wlist[3*i:3*i+3]
w1 = words.index(word1) w1 = words.index(word1)
w2 = (words.index(word2))%n w2 = (words.index(word2))%n
@ -1688,9 +1694,9 @@ def mn_decode( wlist ):
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
if len( sys.argv ) == 1: if len(sys.argv) == 1:
print 'I need arguments: a hex string to encode, or a list of words to decode' print('I need arguments: a hex string to encode, or a list of words to decode')
elif len( sys.argv ) == 2: elif len(sys.argv) == 2:
print ' '.join(mn_encode(sys.argv[1])) print(' '.join(mn_encode(sys.argv[1])))
else: else:
print mn_decode(sys.argv[1:]) print(mn_decode(sys.argv[1:]))

View File

@ -22,8 +22,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import hashlib import hashlib
import os.path import os.path
import re import re
@ -31,23 +35,28 @@ import sys
import threading import threading
import time import time
import traceback import traceback
import urlparse
import json import json
import requests import requests
from six.moves import urllib_parse
try: try:
import paymentrequest_pb2 as pb2 if six.PY3:
from . import paymentrequest_pb2_py3 as pb2
else:
from . import paymentrequest_pb2 as pb2
except ImportError: except ImportError:
sys.exit("Error: could not find paymentrequest_pb2.py. Create it with 'protoc --proto_path=lib/ --python_out=lib/ lib/paymentrequest.proto'") sys.exit("Error: could not find paymentrequest_pb2.py. Create it with 'protoc --proto_path=lib/ --python_out=lib/ lib/paymentrequest.proto'")
import bitcoin from . import bitcoin
import util from . import util
from util import print_error from .util import print_error
import transaction from . import transaction
import x509 from . import x509
import rsakey from . import rsakey
from bitcoin import TYPE_ADDRESS from .bitcoin import TYPE_ADDRESS
REQUEST_HEADERS = {'Accept': 'application/bitcoin-paymentrequest', 'User-Agent': 'Electrum'} REQUEST_HEADERS = {'Accept': 'application/bitcoin-paymentrequest', 'User-Agent': 'Electrum'}
ACK_HEADERS = {'Content-Type':'application/bitcoin-payment','Accept':'application/bitcoin-paymentack','User-Agent':'Electrum'} ACK_HEADERS = {'Content-Type':'application/bitcoin-payment','Accept':'application/bitcoin-paymentack','User-Agent':'Electrum'}
@ -72,7 +81,7 @@ PR_PAID = 3 # send and propagated
def get_payment_request(url): def get_payment_request(url):
u = urlparse.urlparse(url) u = urllib_parse.urlparse(url)
error = None error = None
if u.scheme in ['http', 'https']: if u.scheme in ['http', 'https']:
try: try:
@ -275,15 +284,15 @@ class PaymentRequest:
paymnt.memo = "Paid using Electrum" paymnt.memo = "Paid using Electrum"
pm = paymnt.SerializeToString() pm = paymnt.SerializeToString()
payurl = urlparse.urlparse(pay_det.payment_url) payurl = urllib_parse.urlparse(pay_det.payment_url)
try: try:
r = requests.post(payurl.geturl(), data=pm, headers=ACK_HEADERS, verify=ca_path) r = requests.post(payurl.geturl(), data=pm, headers=ACK_HEADERS, verify=ca_path)
except requests.exceptions.SSLError: except requests.exceptions.SSLError:
print "Payment Message/PaymentACK verify Failed" print("Payment Message/PaymentACK verify Failed")
try: try:
r = requests.post(payurl.geturl(), data=pm, headers=ACK_HEADERS, verify=False) r = requests.post(payurl.geturl(), data=pm, headers=ACK_HEADERS, verify=False)
except Exception as e: except Exception as e:
print e print(e)
return False, "Payment Message/PaymentACK Failed" return False, "Payment Message/PaymentACK Failed"
if r.status_code >= 500: if r.status_code >= 500:
@ -295,12 +304,12 @@ class PaymentRequest:
except Exception: except Exception:
return False, "PaymentACK could not be processed. Payment was sent; please manually verify that payment was received." return False, "PaymentACK could not be processed. Payment was sent; please manually verify that payment was received."
print "PaymentACK message received: %s" % paymntack.memo print("PaymentACK message received: %s" % paymntack.memo)
return True, paymntack.memo return True, paymntack.memo
def make_unsigned_request(req): def make_unsigned_request(req):
from transaction import Transaction from .transaction import Transaction
addr = req['address'] addr = req['address']
time = req.get('time', 0) time = req.get('time', 0)
exp = req.get('exp', 0) exp = req.get('exp', 0)
@ -392,7 +401,7 @@ def verify_cert_chain(chain):
def check_ssl_config(config): def check_ssl_config(config):
import pem from . import pem
key_path = config.get('ssl_privkey') key_path = config.get('ssl_privkey')
cert_path = config.get('ssl_chain') cert_path = config.get('ssl_chain')
with open(key_path, 'r') as f: with open(key_path, 'r') as f:
@ -414,7 +423,7 @@ def check_ssl_config(config):
return requestor return requestor
def sign_request_with_x509(pr, key_path, cert_path): def sign_request_with_x509(pr, key_path, cert_path):
import pem from . import pem
with open(key_path, 'r') as f: with open(key_path, 'r') as f:
params = pem.parse_private_key(f.read()) params = pem.parse_private_key(f.read())
privkey = rsakey.RSAKey(*params) privkey = rsakey.RSAKey(*params)

View File

@ -22,7 +22,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
# This module uses code from TLSLlite # This module uses code from TLSLlite
# TLSLite Author: Trevor Perrin) # TLSLite Author: Trevor Perrin)
@ -30,7 +35,7 @@
import binascii import binascii
from x509 import ASN1_Node, bytestr_to_int, decode_OID from .x509 import ASN1_Node, bytestr_to_int, decode_OID
def a2b_base64(s): def a2b_base64(s):

View File

@ -22,7 +22,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from collections import namedtuple from collections import namedtuple
import traceback import traceback
import sys import sys
@ -30,10 +35,11 @@ import os
import imp import imp
import pkgutil import pkgutil
import time import time
import threading
from util import * from .util import *
from i18n import _ from .i18n import _
from util import profiler, PrintError, DaemonThread, UserCancelled from .util import profiler, PrintError, DaemonThread, UserCancelled, ThreadJob
plugin_loaders = {} plugin_loaders = {}
hook_names = set() hook_names = set()
@ -156,7 +162,7 @@ class Plugins(DaemonThread):
return out return out
def register_wallet_type(self, name, gui_good, wallet_type): def register_wallet_type(self, name, gui_good, wallet_type):
from wallet import register_wallet_type, register_constructor from .wallet import register_wallet_type, register_constructor
self.print_error("registering wallet type", (wallet_type, name)) self.print_error("registering wallet type", (wallet_type, name))
def loader(): def loader():
plugin = self.get_plugin(name) plugin = self.get_plugin(name)
@ -165,7 +171,7 @@ class Plugins(DaemonThread):
plugin_loaders[wallet_type] = loader plugin_loaders[wallet_type] = loader
def register_keystore(self, name, gui_good, details): def register_keystore(self, name, gui_good, details):
from keystore import register_keystore from .keystore import register_keystore
def dynamic_constructor(d): def dynamic_constructor(d):
return self.get_plugin(name).keystore_class(d) return self.get_plugin(name).keystore_class(d)
if details[0] == 'hardware': if details[0] == 'hardware':
@ -299,7 +305,7 @@ class DeviceMgr(ThreadJob, PrintError):
def __init__(self, config): def __init__(self, config):
super(DeviceMgr, self).__init__() super(DeviceMgr, self).__init__()
# Keyed by xpub. The value is the device id # Keyed by xpub. The value is the device id
# has been paired, and None otherwise. # has been paired, and None otherwise.
self.xpub_ids = {} self.xpub_ids = {}
# A list of clients. The key is the client, the value is # A list of clients. The key is the client, the value is

View File

@ -33,15 +33,19 @@
"""Pure-Python RSA implementation.""" """Pure-Python RSA implementation."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function from __future__ import print_function
from __future__ import unicode_literals
import six
import os import os
import math import math
import base64 import base64
import binascii import binascii
import hashlib import hashlib
from pem import * from .pem import *
def SHA1(x): def SHA1(x):

View File

@ -1,12 +1,18 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import ast import ast
import json import json
import threading import threading
import os import os
from copy import deepcopy from copy import deepcopy
from util import user_dir, print_error, print_msg, print_stderr, PrintError from .util import user_dir, print_error, print_msg, print_stderr, PrintError
from bitcoin import MAX_FEE_RATE, FEE_TARGETS from .bitcoin import MAX_FEE_RATE, FEE_TARGETS
SYSTEM_CONFIG_PATH = "/etc/electrum.conf" SYSTEM_CONFIG_PATH = "/etc/electrum.conf"
@ -96,7 +102,7 @@ class SimpleConfig(PrintError):
def fixup_config_keys(self, config, keypairs): def fixup_config_keys(self, config, keypairs):
updated = False updated = False
for old_key, new_key in keypairs.iteritems(): for old_key, new_key in keypairs.items():
if old_key in config: if old_key in config:
if not new_key in config: if not new_key in config:
config[new_key] = config[old_key] config[new_key] = config[old_key]
@ -252,17 +258,18 @@ def read_system_config(path=SYSTEM_CONFIG_PATH):
result = {} result = {}
if os.path.exists(path): if os.path.exists(path):
try: try:
import ConfigParser from six.moves import configparser
# import ConfigParser
except ImportError: except ImportError:
print "cannot parse electrum.conf. please install ConfigParser" print("cannot parse electrum.conf. please install ConfigParser")
return return
p = ConfigParser.ConfigParser() p = configparser.ConfigParser()
try: try:
p.read(path) p.read(path)
for k, v in p.items('client'): for k, v in p.items('client'):
result[k] = v result[k] = v
except (ConfigParser.NoSectionError, ConfigParser.MissingSectionHeaderError): except (configparser.NoSectionError, configparser.MissingSectionHeaderError):
pass pass
return result return result

View File

@ -22,7 +22,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import os import os
import ast import ast
import threading import threading
@ -36,11 +41,11 @@ import pbkdf2, hmac, hashlib
import base64 import base64
import zlib import zlib
from i18n import _ from .i18n import _
from util import NotEnoughFunds, PrintError, profiler from .util import NotEnoughFunds, PrintError, profiler
from plugins import run_hook, plugin_loaders from .plugins import run_hook, plugin_loaders
from keystore import bip44_derivation from .keystore import bip44_derivation
import bitcoin import .bitcoin
# seed_version is now used for the version of the wallet file # seed_version is now used for the version of the wallet file

View File

@ -22,14 +22,18 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from threading import Lock from threading import Lock
import hashlib import hashlib
from bitcoin import Hash, hash_encode from .bitcoin import Hash, hash_encode
from transaction import Transaction from .transaction import Transaction
from util import print_error, print_msg, ThreadJob from .util import print_error, print_msg, ThreadJob
class Synchronizer(ThreadJob): class Synchronizer(ThreadJob):

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import unittest import unittest
class Test_Account(unittest.TestCase): class Test_Account(unittest.TestCase):

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import unittest import unittest
import sys import sys
from ecdsa.util import number_to_string from ecdsa.util import number_to_string
@ -8,6 +14,7 @@ from lib.bitcoin import (
pw_decode, Hash, public_key_from_private_key, address_from_private_key, pw_decode, Hash, public_key_from_private_key, address_from_private_key,
is_valid, is_private_key, xpub_from_xprv, is_new_seed, is_old_seed, is_valid, is_private_key, xpub_from_xprv, is_new_seed, is_old_seed,
var_int, op_push) var_int, op_push)
from lib.util import bfh
try: try:
import ecdsa import ecdsa
@ -18,7 +25,7 @@ except ImportError:
class Test_bitcoin(unittest.TestCase): class Test_bitcoin(unittest.TestCase):
def test_crypto(self): def test_crypto(self):
for message in ["Chancellor on brink of second bailout for banks", chr(255)*512]: for message in [b"Chancellor on brink of second bailout for banks", b'\xff'*512]:
self._do_test_crypto(message) self._do_test_crypto(message)
def _do_test_crypto(self, message): def _do_test_crypto(self, message):
@ -60,7 +67,7 @@ class Test_bitcoin(unittest.TestCase):
assert xprv == "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j" assert xprv == "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"
def _do_test_bip32(self, seed, sequence): def _do_test_bip32(self, seed, sequence):
xprv, xpub = bip32_root(seed.decode('hex'), 0) xprv, xpub = bip32_root(bfh(seed), 0)
assert sequence[0:2] == "m/" assert sequence[0:2] == "m/"
path = 'm' path = 'm'
sequence = sequence[2:] sequence = sequence[2:]
@ -106,7 +113,7 @@ class Test_bitcoin(unittest.TestCase):
def test_hash(self): def test_hash(self):
"""Make sure the Hash function does sha256 twice""" """Make sure the Hash function does sha256 twice"""
payload = u"test" payload = u"test"
expected = '\x95MZI\xfdp\xd9\xb8\xbc\xdb5\xd2R&x)\x95\x7f~\xf7\xfalt\xf8\x84\x19\xbd\xc5\xe8"\t\xf4' expected = b'\x95MZI\xfdp\xd9\xb8\xbc\xdb5\xd2R&x)\x95\x7f~\xf7\xfalt\xf8\x84\x19\xbd\xc5\xe8"\t\xf4'
result = Hash(payload) result = Hash(payload)
self.assertEqual(expected, result) self.assertEqual(expected, result)

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import unittest import unittest
from lib import interface from lib import interface

View File

@ -1,13 +1,21 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import unittest import unittest
from lib import keystore from lib import keystore
from lib import mnemonic from lib import mnemonic
from lib import old_mnemonic from lib import old_mnemonic
from lib.util import bh2u
class Test_NewMnemonic(unittest.TestCase): class Test_NewMnemonic(unittest.TestCase):
def test_to_seed(self): def test_to_seed(self):
seed = mnemonic.Mnemonic.mnemonic_to_seed(mnemonic='foobar', passphrase='none') seed = mnemonic.Mnemonic.mnemonic_to_seed(mnemonic='foobar', passphrase='none')
self.assertEquals(seed.encode('hex'), self.assertEquals(bh2u(seed),
'741b72fd15effece6bfe5a26a52184f66811bd2be363190e07a42cca442b1a5b' '741b72fd15effece6bfe5a26a52184f66811bd2be363190e07a42cca442b1a5b'
'b22b3ad0eb338197287e6d314866c7fba863ac65d3f156087a5052ebc7157fce') 'b22b3ad0eb338197287e6d314866c7fba863ac65d3f156087a5052ebc7157fce')

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import ast import ast
import sys import sys
import os import os
@ -6,7 +12,7 @@ import tempfile
import shutil import shutil
import json import json
from StringIO import StringIO from six.moves import StringIO
from lib.simple_config import (SimpleConfig, read_system_config, from lib.simple_config import (SimpleConfig, read_system_config,
read_user_config) read_user_config)
@ -230,15 +236,6 @@ class TestUserConfig(unittest.TestCase):
result = read_user_config(None) result = read_user_config(None)
self.assertEqual({}, result) self.assertEqual({}, result)
def test_path_with_reprd_dict(self):
thefile = os.path.join(self.user_dir, "config")
payload = {"gap_limit": 5}
with open(thefile, "w") as f:
f.write(json.dumps(payload))
result = read_user_config(self.user_dir)
self.assertEqual(payload, result)
def test_path_without_config_file(self): def test_path_without_config_file(self):
"""We pass a path but if does not contain a "config" file.""" """We pass a path but if does not contain a "config" file."""
result = read_user_config(self.user_dir) result = read_user_config(self.user_dir)

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import unittest import unittest
from lib import transaction from lib import transaction
from lib.bitcoin import TYPE_ADDRESS from lib.bitcoin import TYPE_ADDRESS
@ -5,6 +11,10 @@ from lib.bitcoin import TYPE_ADDRESS
import pprint import pprint
from lib.keystore import xpubkey_to_address from lib.keystore import xpubkey_to_address
from lib.util import bh2u
from lib.util import bh2u
unsigned_blob = '01000000012a5c9a94fcde98f5581cd00162c60a13936ceb75389ea65bf38633b424eb4031000000005701ff4c53ff0488b21e03ef2afea18000000089689bff23e1e7fb2f161daa37270a97a3d8c2e537584b2d304ecb47b86d21fc021b010d3bd425f8cf2e04824bfdf1f1f5ff1d51fadd9a41f9e3fb8dd3403b1bfe00000000ffffffff0140420f00000000001976a914230ac37834073a42146f11ef8414ae929feaafc388ac00000000' unsigned_blob = '01000000012a5c9a94fcde98f5581cd00162c60a13936ceb75389ea65bf38633b424eb4031000000005701ff4c53ff0488b21e03ef2afea18000000089689bff23e1e7fb2f161daa37270a97a3d8c2e537584b2d304ecb47b86d21fc021b010d3bd425f8cf2e04824bfdf1f1f5ff1d51fadd9a41f9e3fb8dd3403b1bfe00000000ffffffff0140420f00000000001976a914230ac37834073a42146f11ef8414ae929feaafc388ac00000000'
signed_blob = '01000000012a5c9a94fcde98f5581cd00162c60a13936ceb75389ea65bf38633b424eb4031000000006c493046022100a82bbc57a0136751e5433f41cf000b3f1a99c6744775e76ec764fb78c54ee100022100f9e80b7de89de861dc6fb0c1429d5da72c2b6b2ee2406bc9bfb1beedd729d985012102e61d176da16edd1d258a200ad9759ef63adf8e14cd97f53227bae35cdb84d2f6ffffffff0140420f00000000001976a914230ac37834073a42146f11ef8414ae929feaafc388ac00000000' signed_blob = '01000000012a5c9a94fcde98f5581cd00162c60a13936ceb75389ea65bf38633b424eb4031000000006c493046022100a82bbc57a0136751e5433f41cf000b3f1a99c6744775e76ec764fb78c54ee100022100f9e80b7de89de861dc6fb0c1429d5da72c2b6b2ee2406bc9bfb1beedd729d985012102e61d176da16edd1d258a200ad9759ef63adf8e14cd97f53227bae35cdb84d2f6ffffffff0140420f00000000001976a914230ac37834073a42146f11ef8414ae929feaafc388ac00000000'
v2_blob = "0200000001191601a44a81e061502b7bfbc6eaa1cef6d1e6af5308ef96c9342f71dbf4b9b5000000006b483045022100a6d44d0a651790a477e75334adfb8aae94d6612d01187b2c02526e340a7fd6c8022028bdf7a64a54906b13b145cd5dab21a26bd4b85d6044e9b97bceab5be44c2a9201210253e8e0254b0c95776786e40984c1aa32a7d03efa6bdacdea5f421b774917d346feffffff026b20fa04000000001976a914024db2e87dd7cfd0e5f266c5f212e21a31d805a588aca0860100000000001976a91421919b94ae5cefcdf0271191459157cdb41c4cbf88aca6240700" v2_blob = "0200000001191601a44a81e061502b7bfbc6eaa1cef6d1e6af5308ef96c9342f71dbf4b9b5000000006b483045022100a6d44d0a651790a477e75334adfb8aae94d6612d01187b2c02526e340a7fd6c8022028bdf7a64a54906b13b145cd5dab21a26bd4b85d6044e9b97bceab5be44c2a9201210253e8e0254b0c95776786e40984c1aa32a7d03efa6bdacdea5f421b774917d346feffffff026b20fa04000000001976a914024db2e87dd7cfd0e5f266c5f212e21a31d805a588aca0860100000000001976a91421919b94ae5cefcdf0271191459157cdb41c4cbf88aca6240700"
@ -20,7 +30,7 @@ class TestBCDataStream(unittest.TestCase):
with self.assertRaises(transaction.SerializationError): with self.assertRaises(transaction.SerializationError):
s.write_compact_size(-1) s.write_compact_size(-1)
self.assertEquals(s.input.encode('hex'), self.assertEquals(bh2u(s.input),
'0001fcfdfd00fdfffffe00000100feffffffffff0000000001000000ffffffffffffffffff') '0001fcfdfd00fdfffffe00000100feffffffffff0000000001000000ffffffffffffffffff')
for v in values: for v in values:
self.assertEquals(s.read_compact_size(), v) self.assertEquals(s.read_compact_size(), v)
@ -44,11 +54,11 @@ class TestBCDataStream(unittest.TestCase):
def test_bytes(self): def test_bytes(self):
s = transaction.BCDataStream() s = transaction.BCDataStream()
s.write('foobar') s.write(b'foobar')
self.assertEquals(s.read_bytes(3), 'foo') self.assertEquals(s.read_bytes(3), b'foo')
self.assertEquals(s.read_bytes(2), 'ba') self.assertEquals(s.read_bytes(2), b'ba')
self.assertEquals(s.read_bytes(4), 'r') self.assertEquals(s.read_bytes(4), b'r')
self.assertEquals(s.read_bytes(1), '') self.assertEquals(s.read_bytes(1), b'')
class TestTransaction(unittest.TestCase): class TestTransaction(unittest.TestCase):

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import unittest import unittest
from lib.util import format_satoshis, parse_URI from lib.util import format_satoshis, parse_URI

View File

@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import shutil import shutil
import tempfile import tempfile
import sys import sys
@ -5,8 +11,8 @@ import unittest
import os import os
import json import json
from StringIO import StringIO from six.moves import StringIO
from electrum.storage import WalletStorage, FINAL_SEED_VERSION from lib.storage import WalletStorage, FINAL_SEED_VERSION
class FakeSynchronizer(object): class FakeSynchronizer(object):

View File

@ -27,11 +27,12 @@
# Note: The deserialization code originally comes from ABE. # Note: The deserialization code originally comes from ABE.
from . import bitcoin
from .bitcoin import *
from .util import print_error, profiler, to_string
import bitcoin from . import bitcoin
from bitcoin import * from .bitcoin import *
from bitcoin import hash160_to_p2sh, hash160_to_p2pkh
from util import print_error, profiler
import time import time
import sys import sys
import struct import struct
@ -40,9 +41,9 @@ import struct
# Workalike python implementation of Bitcoin's CDataStream class. # Workalike python implementation of Bitcoin's CDataStream class.
# #
import struct import struct
import StringIO from six import StringIO
import random import random
from keystore import xpubkey_to_address, xpubkey_to_pubkey from .keystore import xpubkey_to_address, xpubkey_to_pubkey
NO_SIGNATURE = 'ff' NO_SIGNATURE = 'ff'
@ -50,6 +51,7 @@ NO_SIGNATURE = 'ff'
class SerializationError(Exception): class SerializationError(Exception):
""" Thrown when there's a problem deserializing or serializing """ """ Thrown when there's a problem deserializing or serializing """
class BCDataStream(object): class BCDataStream(object):
def __init__(self): def __init__(self):
self.input = None self.input = None
@ -59,13 +61,13 @@ class BCDataStream(object):
self.input = None self.input = None
self.read_cursor = 0 self.read_cursor = 0
def write(self, bytes): # Initialize with string of bytes def write(self, _bytes): # Initialize with string of _bytes
if self.input is None: if self.input is None:
self.input = bytes self.input = bytearray(_bytes)
else: else:
self.input += bytes self.input += bytearray(_bytes)
def read_string(self): def read_string(self, encoding='ascii'):
# Strings are encoded depending on length: # Strings are encoded depending on length:
# 0 to 252 : 1-byte-length followed by bytes (if any) # 0 to 252 : 1-byte-length followed by bytes (if any)
# 253 to 65,535 : byte'253' 2-byte-length followed by bytes # 253 to 65,535 : byte'253' 2-byte-length followed by bytes
@ -81,9 +83,10 @@ class BCDataStream(object):
except IndexError: except IndexError:
raise SerializationError("attempt to read past end of buffer") raise SerializationError("attempt to read past end of buffer")
return self.read_bytes(length) return self.read_bytes(length).decode(encoding)
def write_string(self, string): def write_string(self, string, encoding='ascii'):
string = to_bytes(string, encoding)
# Length-encoded as with read-string # Length-encoded as with read-string
self.write_compact_size(len(string)) self.write_compact_size(len(string))
self.write(string) self.write(string)
@ -115,7 +118,7 @@ class BCDataStream(object):
def write_uint64(self, val): return self._write_num('<Q', val) def write_uint64(self, val): return self._write_num('<Q', val)
def read_compact_size(self): def read_compact_size(self):
size = ord(self.input[self.read_cursor]) size = self.input[self.read_cursor]
self.read_cursor += 1 self.read_cursor += 1
if size == 253: if size == 253:
size = self._read_num('<H') size = self._read_num('<H')
@ -129,15 +132,15 @@ class BCDataStream(object):
if size < 0: if size < 0:
raise SerializationError("attempt to write size < 0") raise SerializationError("attempt to write size < 0")
elif size < 253: elif size < 253:
self.write(chr(size)) self.write(bytes([size]))
elif size < 2**16: elif size < 2**16:
self.write('\xfd') self.write(b'\xfd')
self._write_num('<H', size) self._write_num('<H', size)
elif size < 2**32: elif size < 2**32:
self.write('\xfe') self.write(b'\xfe')
self._write_num('<I', size) self._write_num('<I', size)
elif size < 2**64: elif size < 2**64:
self.write('\xff') self.write(b'\xff')
self._write_num('<Q', size) self._write_num('<Q', size)
def _read_num(self, format): def _read_num(self, format):
@ -149,15 +152,13 @@ class BCDataStream(object):
s = struct.pack(format, num) s = struct.pack(format, num)
self.write(s) self.write(s)
#
# enum-like type # enum-like type
# From the Python Cookbook, downloaded from http://code.activestate.com/recipes/67107/ # From the Python Cookbook, downloaded from http://code.activestate.com/recipes/67107/
# class EnumException(Exception):
import types, string, exceptions
class EnumException(exceptions.Exception):
pass pass
class Enumeration: class Enumeration:
def __init__(self, name, enumList): def __init__(self, name, enumList):
self.__doc__ = name self.__doc__ = name
@ -167,16 +168,16 @@ class Enumeration:
uniqueNames = [ ] uniqueNames = [ ]
uniqueValues = [ ] uniqueValues = [ ]
for x in enumList: for x in enumList:
if type(x) == types.TupleType: if isinstance(x, tuple):
x, i = x x, i = x
if type(x) != types.StringType: if not isinstance(x, six.text_type):
raise EnumException, "enum name is not a string: " + x raise EnumException("enum name is not a string: " + x)
if type(i) != types.IntType: if not isinstance(i, six.integer_types):
raise EnumException, "enum value is not an integer: " + i raise EnumException("enum value is not an integer: " + i)
if x in uniqueNames: if x in uniqueNames:
raise EnumException, "enum name is not unique: " + x raise EnumException("enum name is not unique: " + x)
if i in uniqueValues: if i in uniqueValues:
raise EnumException, "enum value is not unique for " + x raise EnumException("enum value is not unique for " + x)
uniqueNames.append(x) uniqueNames.append(x)
uniqueValues.append(i) uniqueValues.append(i)
lookup[x] = i lookup[x] = i
@ -184,8 +185,9 @@ class Enumeration:
i = i + 1 i = i + 1
self.lookup = lookup self.lookup = lookup
self.reverseLookup = reverseLookup self.reverseLookup = reverseLookup
def __getattr__(self, attr): def __getattr__(self, attr):
if not self.lookup.has_key(attr): if attr not in self.lookup:
raise AttributeError raise AttributeError
return self.lookup[attr] return self.lookup[attr]
def whatis(self, value): def whatis(self, value):
@ -228,32 +230,32 @@ opcodes = Enumeration("Opcodes", [
]) ])
def script_GetOp(bytes): def script_GetOp(_bytes):
i = 0 i = 0
while i < len(bytes): while i < len(_bytes):
vch = None vch = None
opcode = ord(bytes[i]) opcode = _bytes[i]
i += 1 i += 1
if opcode >= opcodes.OP_SINGLEBYTE_END: if opcode >= opcodes.OP_SINGLEBYTE_END:
opcode <<= 8 opcode <<= 8
opcode |= ord(bytes[i]) opcode |= _bytes[i]
i += 1 i += 1
if opcode <= opcodes.OP_PUSHDATA4: if opcode <= opcodes.OP_PUSHDATA4:
nSize = opcode nSize = opcode
if opcode == opcodes.OP_PUSHDATA1: if opcode == opcodes.OP_PUSHDATA1:
nSize = ord(bytes[i]) nSize = _bytes[i]
i += 1 i += 1
elif opcode == opcodes.OP_PUSHDATA2: elif opcode == opcodes.OP_PUSHDATA2:
(nSize,) = struct.unpack_from('<H', bytes, i) (nSize,) = struct.unpack_from('<H', _bytes, i)
i += 2 i += 2
elif opcode == opcodes.OP_PUSHDATA4: elif opcode == opcodes.OP_PUSHDATA4:
(nSize,) = struct.unpack_from('<I', bytes, i) (nSize,) = struct.unpack_from('<I', _bytes, i)
i += 4 i += 4
vch = bytes[i:i+nSize] vch = _bytes[i:i + nSize]
i += nSize i += nSize
yield (opcode, vch, i) yield opcode, vch, i
def script_GetOpName(opcode): def script_GetOpName(opcode):
@ -292,21 +294,20 @@ def safe_parse_pubkey(x):
except: except:
return x return x
def parse_scriptSig(d, _bytes):
def parse_scriptSig(d, bytes):
try: try:
decoded = [ x for x in script_GetOp(bytes) ] decoded = [ x for x in script_GetOp(_bytes) ]
except Exception: except Exception as e:
# coinbase transactions raise an exception # coinbase transactions raise an exception
print_error("cannot find address in input script", bytes.encode('hex')) print_error("cannot find address in input script", bh2u(_bytes))
return return
match = [ opcodes.OP_PUSHDATA4 ] match = [ opcodes.OP_PUSHDATA4 ]
if match_decoded(decoded, match): if match_decoded(decoded, match):
item = decoded[0][1] item = decoded[0][1]
if item[0] == chr(0): if item[0] == 0:
redeemScript = item.encode('hex') redeemScript = bh2u(item)
d['address'] = bitcoin.hash160_to_p2sh(bitcoin.hash_160(redeemScript.decode('hex'))) d['address'] = bitcoin.hash160_to_p2sh(bitcoin.hash_160(item))
d['type'] = 'p2wpkh-p2sh' d['type'] = 'p2wpkh-p2sh'
d['redeemScript'] = redeemScript d['redeemScript'] = redeemScript
d['x_pubkeys'] = ["(witness)"] d['x_pubkeys'] = ["(witness)"]
@ -317,7 +318,7 @@ def parse_scriptSig(d, bytes):
# payto_pubkey # payto_pubkey
d['type'] = 'p2pk' d['type'] = 'p2pk'
d['address'] = "(pubkey)" d['address'] = "(pubkey)"
d['signatures'] = [item.encode('hex')] d['signatures'] = [bh2u(item)]
d['num_sig'] = 1 d['num_sig'] = 1
d['x_pubkeys'] = ["(pubkey)"] d['x_pubkeys'] = ["(pubkey)"]
d['pubkeys'] = ["(pubkey)"] d['pubkeys'] = ["(pubkey)"]
@ -328,13 +329,13 @@ def parse_scriptSig(d, bytes):
# (65 bytes) onto the stack: # (65 bytes) onto the stack:
match = [ opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4 ] match = [ opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4 ]
if match_decoded(decoded, match): if match_decoded(decoded, match):
sig = decoded[0][1].encode('hex') sig = bh2u(decoded[0][1])
x_pubkey = decoded[1][1].encode('hex') x_pubkey = bh2u(decoded[1][1])
try: try:
signatures = parse_sig([sig]) signatures = parse_sig([sig])
pubkey, address = xpubkey_to_address(x_pubkey) pubkey, address = xpubkey_to_address(x_pubkey)
except BaseException: except:
print_error("cannot find address in input script", bytes.encode('hex')) print_error("cannot find address in input script", bh2u(_bytes))
return return
d['type'] = 'p2pkh' d['type'] = 'p2pkh'
d['signatures'] = signatures d['signatures'] = signatures
@ -347,9 +348,9 @@ def parse_scriptSig(d, bytes):
# p2sh transaction, m of n # p2sh transaction, m of n
match = [ opcodes.OP_0 ] + [ opcodes.OP_PUSHDATA4 ] * (len(decoded) - 1) match = [ opcodes.OP_0 ] + [ opcodes.OP_PUSHDATA4 ] * (len(decoded) - 1)
if not match_decoded(decoded, match): if not match_decoded(decoded, match):
print_error("cannot find address in input script", bytes.encode('hex')) print_error("cannot find address in input script", bh2u(_bytes))
return return
x_sig = [x[1].encode('hex') for x in decoded[1:-1]] x_sig = [bh2u(x[1]) for x in decoded[1:-1]]
dec2 = [ x for x in script_GetOp(decoded[-1][1]) ] dec2 = [ x for x in script_GetOp(decoded[-1][1]) ]
m = dec2[0][0] - opcodes.OP_1 + 1 m = dec2[0][0] - opcodes.OP_1 + 1
n = dec2[-2][0] - opcodes.OP_1 + 1 n = dec2[-2][0] - opcodes.OP_1 + 1
@ -357,9 +358,9 @@ def parse_scriptSig(d, bytes):
op_n = opcodes.OP_1 + n - 1 op_n = opcodes.OP_1 + n - 1
match_multisig = [ op_m ] + [opcodes.OP_PUSHDATA4]*n + [ op_n, opcodes.OP_CHECKMULTISIG ] match_multisig = [ op_m ] + [opcodes.OP_PUSHDATA4]*n + [ op_n, opcodes.OP_CHECKMULTISIG ]
if not match_decoded(dec2, match_multisig): if not match_decoded(dec2, match_multisig):
print_error("cannot find address in input script", bytes.encode('hex')) print_error("cannot find address in input script", bh2u(_bytes))
return return
x_pubkeys = map(lambda x: x[1].encode('hex'), dec2[1:-2]) x_pubkeys = [bh2u(x[1]) for x in dec2[1:-2]]
pubkeys = [safe_parse_pubkey(x) for x in x_pubkeys] pubkeys = [safe_parse_pubkey(x) for x in x_pubkeys]
redeemScript = multisig_script(pubkeys, m) redeemScript = multisig_script(pubkeys, m)
# write result in d # write result in d
@ -369,19 +370,17 @@ def parse_scriptSig(d, bytes):
d['x_pubkeys'] = x_pubkeys d['x_pubkeys'] = x_pubkeys
d['pubkeys'] = pubkeys d['pubkeys'] = pubkeys
d['redeemScript'] = redeemScript d['redeemScript'] = redeemScript
d['address'] = hash160_to_p2sh(hash_160(redeemScript.decode('hex'))) d['address'] = hash160_to_p2sh(hash_160(bfh(redeemScript)))
def get_address_from_output_script(_bytes):
decoded = [x for x in script_GetOp(_bytes)]
def get_address_from_output_script(bytes):
decoded = [ x for x in script_GetOp(bytes) ]
# The Genesis Block, self-payments, and pay-by-IP-address payments look like: # The Genesis Block, self-payments, and pay-by-IP-address payments look like:
# 65 BYTES:... CHECKSIG # 65 BYTES:... CHECKSIG
match = [ opcodes.OP_PUSHDATA4, opcodes.OP_CHECKSIG ] match = [ opcodes.OP_PUSHDATA4, opcodes.OP_CHECKSIG ]
if match_decoded(decoded, match): if match_decoded(decoded, match):
return TYPE_PUBKEY, decoded[0][1].encode('hex') return TYPE_PUBKEY, bh2u(decoded[0][1])
# Pay-by-Bitcoin-address TxOuts look like: # Pay-by-Bitcoin-address TxOuts look like:
# DUP HASH160 20 BYTES:... EQUALVERIFY CHECKSIG # DUP HASH160 20 BYTES:... EQUALVERIFY CHECKSIG
@ -394,10 +393,7 @@ def get_address_from_output_script(bytes):
if match_decoded(decoded, match): if match_decoded(decoded, match):
return TYPE_ADDRESS, hash160_to_p2sh(decoded[1][1]) return TYPE_ADDRESS, hash160_to_p2sh(decoded[1][1])
return TYPE_SCRIPT, bytes return TYPE_SCRIPT, _bytes
def parse_input(vds): def parse_input(vds):
@ -406,7 +402,7 @@ def parse_input(vds):
prevout_n = vds.read_uint32() prevout_n = vds.read_uint32()
scriptSig = vds.read_bytes(vds.read_compact_size()) scriptSig = vds.read_bytes(vds.read_compact_size())
sequence = vds.read_uint32() sequence = vds.read_uint32()
d['scriptSig'] = scriptSig.encode('hex') d['scriptSig'] = bh2u(scriptSig)
d['prevout_hash'] = prevout_hash d['prevout_hash'] = prevout_hash
d['prevout_n'] = prevout_n d['prevout_n'] = prevout_n
d['sequence'] = sequence d['sequence'] = sequence
@ -433,14 +429,14 @@ def parse_output(vds, i):
d['value'] = vds.read_int64() d['value'] = vds.read_int64()
scriptPubKey = vds.read_bytes(vds.read_compact_size()) scriptPubKey = vds.read_bytes(vds.read_compact_size())
d['type'], d['address'] = get_address_from_output_script(scriptPubKey) d['type'], d['address'] = get_address_from_output_script(scriptPubKey)
d['scriptPubKey'] = scriptPubKey.encode('hex') d['scriptPubKey'] = bh2u(scriptPubKey)
d['prevout_n'] = i d['prevout_n'] = i
return d return d
def deserialize(raw): def deserialize(raw):
vds = BCDataStream() vds = BCDataStream()
vds.write(raw.decode('hex')) vds.write(bfh(raw))
d = {} d = {}
start = vds.read_cursor start = vds.read_cursor
d['version'] = vds.read_int32() d['version'] = vds.read_int32()
@ -448,13 +444,13 @@ def deserialize(raw):
is_segwit = (n_vin == 0) is_segwit = (n_vin == 0)
if is_segwit: if is_segwit:
marker = vds.read_bytes(1) marker = vds.read_bytes(1)
assert marker == chr(1) assert marker == 1
n_vin = vds.read_compact_size() n_vin = vds.read_compact_size()
d['inputs'] = list(parse_input(vds) for i in xrange(n_vin)) d['inputs'] = [parse_input(vds) for i in range(n_vin)]
n_vout = vds.read_compact_size() n_vout = vds.read_compact_size()
d['outputs'] = list(parse_output(vds,i) for i in xrange(n_vout)) d['outputs'] = [parse_output(vds,i) for i in range(n_vout)]
if is_segwit: if is_segwit:
d['witness'] = list(parse_witness(vds) for i in xrange(n_vin)) d['witness'] = [parse_witness(vds) for i in range(n_vin)]
d['lockTime'] = vds.read_uint32() d['lockTime'] = vds.read_uint32()
return d return d
@ -462,27 +458,30 @@ def deserialize(raw):
# pay & redeem scripts # pay & redeem scripts
def push_script(x): def push_script(x):
return op_push(len(x)/2) + x return op_push(len(x)//2) + x
def get_scriptPubKey(addr): def get_scriptPubKey(addr):
addrtype, hash_160 = bc_address_to_hash_160(addr) addrtype, hash_160 = bc_address_to_hash_160(addr)
if addrtype == bitcoin.ADDRTYPE_P2PKH: if addrtype == bitcoin.ADDRTYPE_P2PKH:
script = '76a9' # op_dup, op_hash_160 script = '76a9' # op_dup, op_hash_160
script += push_script(hash_160.encode('hex')) script += push_script(bh2u(hash_160))
script += '88ac' # op_equalverify, op_checksig script += '88ac' # op_equalverify, op_checksig
elif addrtype == bitcoin.ADDRTYPE_P2SH: elif addrtype == bitcoin.ADDRTYPE_P2SH:
script = 'a9' # op_hash_160 script = 'a9' # op_hash_160
script += push_script(hash_160.encode('hex')) script += push_script(bh2u(hash_160))
script += '87' # op_equal script += '87' # op_equal
else: else:
raise BaseException('unknown address type') raise BaseException('unknown address type')
return script return script
def segwit_script(pubkey): def segwit_script(pubkey):
pubkey = safe_parse_pubkey(pubkey) pubkey = safe_parse_pubkey(pubkey)
pkh = hash_160(pubkey.decode('hex')).encode('hex') pkh = bh2u(hash_160(bfh(pubkey)))
return '00' + push_script(pkh) return '00' + push_script(pkh)
def multisig_script(public_keys, m): def multisig_script(public_keys, m):
n = len(public_keys) n = len(public_keys)
assert n <= 15 assert n <= 15
@ -505,9 +504,9 @@ class Transaction:
def __init__(self, raw): def __init__(self, raw):
if raw is None: if raw is None:
self.raw = None self.raw = None
elif type(raw) in [str, unicode]: elif isinstance(raw, str):
self.raw = raw.strip() if raw else None self.raw = raw.strip() if raw else None
elif type(raw) is dict: elif isinstance(raw, dict):
self.raw = raw['hex'] self.raw = raw['hex']
else: else:
raise BaseException("cannot initialize transaction", raw) raise BaseException("cannot initialize transaction", raw)
@ -553,15 +552,15 @@ class Transaction:
for sig in sigs2: for sig in sigs2:
if sig in sigs1: if sig in sigs1:
continue continue
pre_hash = Hash(self.serialize_preimage(i).decode('hex')) pre_hash = Hash(bfh(self.serialize_preimage(i)))
# der to string # der to string
order = ecdsa.ecdsa.generator_secp256k1.order() order = ecdsa.ecdsa.generator_secp256k1.order()
r, s = ecdsa.util.sigdecode_der(sig.decode('hex')[:-1], order) r, s = ecdsa.util.sigdecode_der(bfh(sig[:-2]), order)
sig_string = ecdsa.util.sigencode_string(r, s, order) sig_string = ecdsa.util.sigencode_string(r, s, order)
compressed = True compressed = True
for recid in range(4): for recid in range(4):
public_key = MyVerifyingKey.from_signature(sig_string, recid, pre_hash, curve = SECP256k1) public_key = MyVerifyingKey.from_signature(sig_string, recid, pre_hash, curve = SECP256k1)
pubkey = point_to_ser(public_key.pubkey.point, compressed).encode('hex') pubkey = bh2u(point_to_ser(public_key.pubkey.point, compressed))
if pubkey in pubkeys: if pubkey in pubkeys:
public_key.verify_digest(sig_string, pre_hash, sigdecode = ecdsa.util.sigdecode_string) public_key.verify_digest(sig_string, pre_hash, sigdecode = ecdsa.util.sigdecode_string)
j = pubkeys.index(pubkey) j = pubkeys.index(pubkey)
@ -572,7 +571,6 @@ class Transaction:
# redo raw # redo raw
self.raw = self.serialize() self.raw = self.serialize()
def deserialize(self): def deserialize(self):
if self.raw is None: if self.raw is None:
return return
@ -597,7 +595,7 @@ class Transaction:
@classmethod @classmethod
def pay_script(self, output_type, addr): def pay_script(self, output_type, addr):
if output_type == TYPE_SCRIPT: if output_type == TYPE_SCRIPT:
return addr.encode('hex') return bh2u(addr)
elif output_type == TYPE_ADDRESS: elif output_type == TYPE_ADDRESS:
return get_scriptPubKey(addr) return get_scriptPubKey(addr)
else: else:
@ -616,7 +614,7 @@ class Transaction:
else: else:
pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin) pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin)
x_signatures = txin['signatures'] x_signatures = txin['signatures']
signatures = filter(None, x_signatures) signatures = list(filter(None, x_signatures))
is_complete = len(signatures) == num_sig is_complete = len(signatures) == num_sig
if is_complete: if is_complete:
pk_list = pubkeys pk_list = pubkeys
@ -671,21 +669,21 @@ class Transaction:
return multisig_script(pubkeys, txin['num_sig']) return multisig_script(pubkeys, txin['num_sig'])
elif txin['type'] == 'p2wpkh-p2sh': elif txin['type'] == 'p2wpkh-p2sh':
pubkey = txin['pubkeys'][0] pubkey = txin['pubkeys'][0]
pkh = bitcoin.hash_160(pubkey.decode('hex')).encode('hex') pkh = bh2u(bitcoin.hash_160(bfh(pubkey)))
return '76a9' + push_script(pkh) + '88ac' return '76a9' + push_script(pkh) + '88ac'
else: else:
raise TypeError('Unknown txin type', _type) raise TypeError('Unknown txin type', _type)
@classmethod @classmethod
def serialize_outpoint(self, txin): def serialize_outpoint(self, txin):
return txin['prevout_hash'].decode('hex')[::-1].encode('hex') + int_to_hex(txin['prevout_n'], 4) return bh2u(bfh(txin['prevout_hash'])[::-1]) + int_to_hex(txin['prevout_n'], 4)
@classmethod @classmethod
def serialize_input(self, txin, script): def serialize_input(self, txin, script):
# Prev hash and index # Prev hash and index
s = self.serialize_outpoint(txin) s = self.serialize_outpoint(txin)
# Script length, script, sequence # Script length, script, sequence
s += var_int(len(script)/2) s += var_int(len(script)//2)
s += script s += script
s += int_to_hex(txin.get('sequence', 0xffffffff - 1), 4) s += int_to_hex(txin.get('sequence', 0xffffffff - 1), 4)
return s return s
@ -704,7 +702,7 @@ class Transaction:
output_type, addr, amount = output output_type, addr, amount = output
s = int_to_hex(amount, 8) s = int_to_hex(amount, 8)
script = self.pay_script(output_type, addr) script = self.pay_script(output_type, addr)
s += var_int(len(script)/2) s += var_int(len(script)//2)
s += script s += script
return s return s
@ -715,6 +713,7 @@ class Transaction:
inputs = self.inputs() inputs = self.inputs()
outputs = self.outputs() outputs = self.outputs()
txin = inputs[i] txin = inputs[i]
# TODO: py3 hex
if self.is_segwit_input(txin): if self.is_segwit_input(txin):
hashPrevouts = Hash(''.join(self.serialize_outpoint(txin) for txin in inputs).decode('hex')).encode('hex') 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') hashSequence = Hash(''.join(int_to_hex(txin.get('sequence', 0xffffffff - 1), 4) for txin in inputs).decode('hex')).encode('hex')
@ -750,7 +749,7 @@ class Transaction:
return nVersion + txins + txouts + nLocktime return nVersion + txins + txouts + nLocktime
def hash(self): def hash(self):
print "warning: deprecated tx.hash()" print("warning: deprecated tx.hash()")
return self.txid() return self.txid()
def txid(self): def txid(self):
@ -758,11 +757,11 @@ class Transaction:
if not all_segwit and not self.is_complete(): if not all_segwit and not self.is_complete():
return None return None
ser = self.serialize(witness=False) ser = self.serialize(witness=False)
return Hash(ser.decode('hex'))[::-1].encode('hex') return bh2u(Hash(bfh(ser))[::-1])
def wtxid(self): def wtxid(self):
ser = self.serialize(witness=True) ser = self.serialize(witness=True)
return Hash(ser.decode('hex'))[::-1].encode('hex') return bh2u(Hash(bfh(ser))[::-1])
def add_inputs(self, inputs): def add_inputs(self, inputs):
self._inputs.extend(inputs) self._inputs.extend(inputs)
@ -787,13 +786,13 @@ class Transaction:
@profiler @profiler
def estimated_size(self): def estimated_size(self):
'''Return an estimated tx size in bytes.''' '''Return an estimated tx size in bytes.'''
return len(self.serialize(True)) / 2 if not self.is_complete() or self.raw is None else len(self.raw) / 2 # ASCII hex string return len(self.serialize(True)) // 2 if not self.is_complete() or self.raw is None else len(self.raw) / 2 # ASCII hex string
@classmethod @classmethod
def estimated_input_size(self, txin): def estimated_input_size(self, txin):
'''Return an estimated of serialized input size in bytes.''' '''Return an estimated of serialized input size in bytes.'''
script = self.input_script(txin, True) script = self.input_script(txin, True)
return len(self.serialize_input(txin, script)) / 2 return len(self.serialize_input(txin, script)) // 2
def signature_count(self): def signature_count(self):
r = 0 r = 0
@ -801,7 +800,7 @@ class Transaction:
for txin in self.inputs(): for txin in self.inputs():
if txin['type'] == 'coinbase': if txin['type'] == 'coinbase':
continue continue
signatures = filter(None, txin.get('signatures',[])) signatures = list(filter(None, txin.get('signatures',[])))
s += len(signatures) s += len(signatures)
r += txin.get('num_sig',-1) r += txin.get('num_sig',-1)
return s, r return s, r
@ -824,14 +823,14 @@ class Transaction:
sec = keypairs.get(x_pubkey) sec = keypairs.get(x_pubkey)
pubkey = public_key_from_private_key(sec) pubkey = public_key_from_private_key(sec)
# add signature # add signature
pre_hash = Hash(self.serialize_preimage(i).decode('hex')) pre_hash = Hash(bfh(self.serialize_preimage(i)))
pkey = regenerate_key(sec) pkey = regenerate_key(sec)
secexp = pkey.secret secexp = pkey.secret
private_key = bitcoin.MySigningKey.from_secret_exponent(secexp, curve = SECP256k1) private_key = bitcoin.MySigningKey.from_secret_exponent(secexp, curve = SECP256k1)
public_key = private_key.get_verifying_key() public_key = private_key.get_verifying_key()
sig = private_key.sign_digest_deterministic(pre_hash, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der) sig = private_key.sign_digest_deterministic(pre_hash, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der)
assert public_key.verify_digest(sig, pre_hash, sigdecode = ecdsa.util.sigdecode_der) assert public_key.verify_digest(sig, pre_hash, sigdecode = ecdsa.util.sigdecode_der)
txin['signatures'][j] = sig.encode('hex') + '01' txin['signatures'][j] = bh2u(sig) + '01'
txin['x_pubkeys'][j] = pubkey txin['x_pubkeys'][j] = pubkey
txin['pubkeys'][j] = pubkey # needed for fd keys txin['pubkeys'][j] = pubkey # needed for fd keys
self._inputs[i] = txin self._inputs[i] = txin
@ -845,9 +844,9 @@ class Transaction:
if type == TYPE_ADDRESS: if type == TYPE_ADDRESS:
addr = x addr = x
elif type == TYPE_PUBKEY: elif type == TYPE_PUBKEY:
addr = bitcoin.public_key_to_p2pkh(x.decode('hex')) addr = bitcoin.public_key_to_p2pkh(bfh(x))
else: else:
addr = 'SCRIPT ' + x.encode('hex') addr = 'SCRIPT ' + bh2u(x)
o.append((addr,v)) # consider using yield (addr, v) o.append((addr,v)) # consider using yield (addr, v)
return o return o
@ -869,7 +868,6 @@ class Transaction:
} }
return out return out
def requires_fee(self, wallet): def requires_fee(self, wallet):
# see https://en.bitcoin.it/wiki/Transaction_fees # see https://en.bitcoin.it/wiki/Transaction_fees
# #
@ -899,7 +897,7 @@ def tx_from_str(txt):
import json import json
txt = txt.strip() txt = txt.strip()
try: try:
txt.decode('hex') bfh(txt)
is_hex = True is_hex = True
except: except:
is_hex = False is_hex = False

View File

@ -22,7 +22,12 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import binascii
import os, sys, re, json import os, sys, re, json
import platform import platform
import shutil import shutil
@ -30,10 +35,18 @@ from collections import defaultdict
from datetime import datetime from datetime import datetime
from decimal import Decimal from decimal import Decimal
import traceback import traceback
import urlparse
import urllib import urllib
import threading import threading
from i18n import _ from .i18n import _
import six
from six.moves import queue, urllib_parse
try:
import urllib.parse
import urllib.request, urllib.parse, urllib.error
except ImportError:
pass
base_units = {'BTC':8, 'mBTC':5, 'uBTC':2} base_units = {'BTC':8, 'mBTC':5, 'uBTC':2}
fee_levels = [_('Within 25 blocks'), _('Within 10 blocks'), _('Within 5 blocks'), _('Within 2 blocks'), _('In the next block')] fee_levels = [_('Within 25 blocks'), _('Within 10 blocks'), _('Within 5 blocks'), _('Within 2 blocks'), _('In the next block')]
@ -194,7 +207,7 @@ def json_decode(x):
# decorator that prints execution time # decorator that prints execution time
def profiler(func): def profiler(func):
def do_profile(func, args, kw_args): def do_profile(func, args, kw_args):
n = func.func_name n = func.__name__
t0 = time.time() t0 = time.time()
o = func(*args, **kw_args) o = func(*args, **kw_args)
t = time.time() - t0 t = time.time() - t0
@ -238,6 +251,182 @@ def android_check_data_dir():
def get_headers_dir(config): def get_headers_dir(config):
return android_headers_dir() if 'ANDROID_DATA' in os.environ else config.path return android_headers_dir() if 'ANDROID_DATA' in os.environ else config.path
def assert_bytes(*args):
"""
porting helper, assert args type
"""
if six.PY2:
for x in args:
assert isinstance(x, (bytes, bytearray, str))
return
try:
if six.PY3:
for x in args:
assert isinstance(x, (bytes, bytearray))
else:
for x in args:
assert isinstance(x, bytearray)
except:
print('assert bytes failed', list(map(type, args)))
raise
def assert_str(*args):
"""
porting helper, assert args type
"""
for x in 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):
if isinstance(x, (bytes, bytearray)):
return x.decode(enc)
if isinstance(x, str):
return x
else:
raise TypeError("Not a string or bytes like object")
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))
# def ufh(x):
# """
# py2-py3 aware wrapper for str.decode('hex')
# :param x: str
# :return: str
# """
# if
# return binascii.unhexlify(x)
def hfu(x):
"""
py2-py3 aware wrapper for str.encode('hex')
:param x: str
:return: str
"""
if six.PY3:
assert_bytes(x)
return binascii.hexlify(x)
else:
return x.encode('hex')
def bfh(x):
"""
py2-py3 aware wrapper to "bytes.fromhex()" func
:param x: str
:rtype: bytes
"""
if isinstance(x, six.string_types):
return bfh_builder(x)
# TODO: check for iterator interface
elif isinstance(x, (list, tuple, map)):
return [bfh(sub) for sub in x]
else:
raise TypeError('Unexpected type: ' + type(x))
def bh2u(x):
"""
unicode with hex representation of bytes()
e.g. x = bytes([1, 2, 10])
bh2u(x) -> '01020A'
:param x: bytes
:rtype: str
"""
if six.PY3:
assert_bytes(x)
# x = to_bytes(x, 'ascii')
return binascii.hexlify(x).decode('ascii')
else:
if isinstance(x, bytearray):
return binascii.hexlify(x)
else:
return x.encode('hex')
def user_dir(): def user_dir():
if 'ANDROID_DATA' in os.environ: if 'ANDROID_DATA' in os.environ:
return android_check_data_dir() return android_check_data_dir()
@ -251,12 +440,14 @@ def user_dir():
#raise Exception("No home directory found in environment variables.") #raise Exception("No home directory found in environment variables.")
return return
def format_satoshis_plain(x, decimal_point = 8): def format_satoshis_plain(x, decimal_point = 8):
'''Display a satoshi amount scaled. Always uses a '.' as a decimal """Display a satoshi amount scaled. Always uses a '.' as a decimal
point and has no thousands separator''' point and has no thousands separator"""
scale_factor = pow(10, decimal_point) scale_factor = pow(10, decimal_point)
return "{:.8f}".format(Decimal(x) / scale_factor).rstrip('0').rstrip('.') return "{:.8f}".format(Decimal(x) / scale_factor).rstrip('0').rstrip('.')
def format_satoshis(x, is_diff=False, num_zeros = 0, decimal_point = 8, whitespaces=False): def format_satoshis(x, is_diff=False, num_zeros = 0, decimal_point = 8, whitespaces=False):
from locale import localeconv from locale import localeconv
if x is None: if x is None:
@ -277,7 +468,9 @@ def format_satoshis(x, is_diff=False, num_zeros = 0, decimal_point = 8, whitespa
if whitespaces: if whitespaces:
result += " " * (decimal_point - len(fract_part)) result += " " * (decimal_point - len(fract_part))
result = " " * (15 - len(result)) + result result = " " * (15 - len(result)) + result
return result.decode('utf8') if six.PY2:
result = result.decode('utf8')
return result
def timestamp_to_datetime(timestamp): def timestamp_to_datetime(timestamp):
try: try:
@ -404,15 +597,15 @@ def block_explorer_URL(config, kind, item):
#urldecode = lambda x: _ud.sub(lambda m: chr(int(m.group(1), 16)), x) #urldecode = lambda x: _ud.sub(lambda m: chr(int(m.group(1), 16)), x)
def parse_URI(uri, on_pr=None): def parse_URI(uri, on_pr=None):
import bitcoin from . import bitcoin
from bitcoin import COIN from .bitcoin import COIN
if ':' not in uri: if ':' not in uri:
if not bitcoin.is_address(uri): if not bitcoin.is_address(uri):
raise BaseException("Not a bitcoin address") raise BaseException("Not a bitcoin address")
return {'address': uri} return {'address': uri}
u = urlparse.urlparse(uri) u = urllib_parse.urlparse(uri)
if u.scheme != 'bitcoin': if u.scheme != 'bitcoin':
raise BaseException("Not a bitcoin URI") raise BaseException("Not a bitcoin URI")
address = u.path address = u.path
@ -420,9 +613,9 @@ def parse_URI(uri, on_pr=None):
# python for android fails to parse query # python for android fails to parse query
if address.find('?') > 0: if address.find('?') > 0:
address, query = u.path.split('?') address, query = u.path.split('?')
pq = urlparse.parse_qs(query) pq = urllib_parse.parse_qs(query)
else: else:
pq = urlparse.parse_qs(u.query) pq = urllib_parse.parse_qs(u.query)
for k, v in pq.items(): for k, v in pq.items():
if len(v)!=1: if len(v)!=1:
@ -443,21 +636,24 @@ def parse_URI(uri, on_pr=None):
amount = Decimal(am) * COIN amount = Decimal(am) * COIN
out['amount'] = int(amount) out['amount'] = int(amount)
if 'message' in out: if 'message' in out:
out['message'] = out['message'].decode('utf8') if six.PY3:
out['message'] = out['message']
else:
out['message'] = out['message'].decode('utf8')
out['memo'] = out['message'] out['memo'] = out['message']
if 'time' in out: if 'time' in out:
out['time'] = int(out['time']) out['time'] = int(out['time'])
if 'exp' in out: if 'exp' in out:
out['exp'] = int(out['exp']) out['exp'] = int(out['exp'])
if 'sig' in out: if 'sig' in out:
out['sig'] = bitcoin.base_decode(out['sig'], None, base=58).encode('hex') out['sig'] = bh2u(bitcoin.base_decode(out['sig'], None, base=58))
r = out.get('r') r = out.get('r')
sig = out.get('sig') sig = out.get('sig')
name = out.get('name') name = out.get('name')
if on_pr and (r or (name and sig)): if on_pr and (r or (name and sig)):
def get_payment_request_thread(): def get_payment_request_thread():
import paymentrequest as pr from . import paymentrequest as pr
if name and sig: if name and sig:
s = pr.serialize_request(out).SerializeToString() s = pr.serialize_request(out).SerializeToString()
request = pr.PaymentRequest(s) request = pr.PaymentRequest(s)
@ -472,7 +668,7 @@ def parse_URI(uri, on_pr=None):
def create_URI(addr, amount, message): def create_URI(addr, amount, message):
import bitcoin from . import bitcoin
if not bitcoin.is_address(addr): if not bitcoin.is_address(addr):
return "" return ""
query = [] query = []
@ -482,19 +678,26 @@ def create_URI(addr, amount, message):
if type(message) == unicode: if type(message) == unicode:
message = message.encode('utf8') message = message.encode('utf8')
query.append('message=%s'%urllib.quote(message)) query.append('message=%s'%urllib.quote(message))
p = urlparse.ParseResult(scheme='bitcoin', netloc='', path=addr, params='', query='&'.join(query), fragment='') p = urllib_parse.ParseResult(scheme='bitcoin', netloc='', path=addr, params='', query='&'.join(query), fragment='')
return urlparse.urlunparse(p) return urllib_parse.urlunparse(p)
# Python bug (http://bugs.python.org/issue1927) causes raw_input # Python bug (http://bugs.python.org/issue1927) causes raw_input
# to be redirected improperly between stdin/stderr on Unix systems # to be redirected improperly between stdin/stderr on Unix systems
#TODO: py3
def raw_input(prompt=None): def raw_input(prompt=None):
if prompt: if prompt:
sys.stdout.write(prompt) sys.stdout.write(prompt)
return builtin_raw_input() return builtin_raw_input()
import __builtin__
builtin_raw_input = __builtin__.raw_input if six.PY2:
__builtin__.raw_input = raw_input import __builtin__
builtin_raw_input = __builtin__.raw_input
__builtin__.raw_input = raw_input
else:
import builtins
builtin_raw_input = builtins.input
builtins.input = raw_input
@ -596,8 +799,6 @@ class SocketPipe:
import Queue
class QueuePipe: class QueuePipe:
def __init__(self, send_queue=None, get_queue=None): def __init__(self, send_queue=None, get_queue=None):

View File

@ -22,10 +22,14 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from util import ThreadJob from .util import ThreadJob
from bitcoin import * from .bitcoin import *
class SPV(ThreadJob): class SPV(ThreadJob):

View File

@ -23,13 +23,11 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
""" # Wallet classes:
Wallet classes: # - Imported_Wallet: imported address, no keystore
- Imported_Wallet: imported address, no keystore # - Standard_Wallet: one keystore, P2PKH
- Standard_Wallet: one keystore, P2PKH # - Multisig_Wallet: several keystores, P2SH
- Multisig_Wallet: several keystores, P2SH
"""
import os import os
import hashlib import hashlib
@ -45,27 +43,26 @@ import errno
from functools import partial from functools import partial
from collections import namedtuple, defaultdict from collections import namedtuple, defaultdict
from i18n import _ from .i18n import _
from util import NotEnoughFunds, PrintError, UserCancelled, profiler from .util import NotEnoughFunds, PrintError, UserCancelled, profiler
from bitcoin import * from .bitcoin import *
from version import * from .version import *
from keystore import load_keystore, Hardware_KeyStore from .keystore import load_keystore, Hardware_KeyStore
from storage import multisig_type from .storage import multisig_type
import transaction import transaction
from transaction import Transaction from .transaction import Transaction
from plugins import run_hook from .plugins import run_hook
import bitcoin from . import bitcoin
import coinchooser from . import coinchooser
from synchronizer import Synchronizer from .synchronizer import Synchronizer
from verifier import SPV from .verifier import SPV
from mnemonic import Mnemonic from .mnemonic import Mnemonic
import paymentrequest from . import paymentrequest
from paymentrequest import InvoiceStore
from contacts import Contacts
from .storage import WalletStorage
TX_STATUS = [ TX_STATUS = [
_('Replaceable'), _('Replaceable'),
@ -197,11 +194,11 @@ class Abstract_Wallet(PrintError):
@profiler @profiler
def check_history(self): def check_history(self):
save = False save = False
for addr, hist in self.history.items(): mine_addrs = list(filter(lambda k: self.is_mine(self.history[k]), self.history.keys()))
if not self.is_mine(addr): if len(mine_addrs) != len(self.history.keys()):
self.history.pop(addr) save = True
save = True for addr in mine_addrs:
continue hist = self.history[addr]
for tx_hash, tx_height in hist: for tx_hash, tx_height in hist:
if tx_hash in self.pruned_txo.values() or self.txi.get(tx_hash) or self.txo.get(tx_hash): if tx_hash in self.pruned_txo.values() or self.txi.get(tx_hash) or self.txo.get(tx_hash):
@ -625,7 +622,7 @@ class Abstract_Wallet(PrintError):
if _type == TYPE_ADDRESS: if _type == TYPE_ADDRESS:
addr = x addr = x
elif _type == TYPE_PUBKEY: elif _type == TYPE_PUBKEY:
addr = bitcoin.public_key_to_p2pkh(x.decode('hex')) addr = bitcoin.public_key_to_p2pkh(bfh(x))
else: else:
addr = None addr = None
if addr and self.is_mine(addr): if addr and self.is_mine(addr):
@ -947,7 +944,7 @@ class Abstract_Wallet(PrintError):
# if we are on a pruning server, remove unverified transactions # if we are on a pruning server, remove unverified transactions
with self.lock: with self.lock:
vr = self.verified_tx.keys() + self.unverified_tx.keys() vr = list(self.verified_tx.keys()) + list(self.unverified_tx.keys())
for tx_hash in self.transactions.keys(): for tx_hash in self.transactions.keys():
if tx_hash not in vr: if tx_hash not in vr:
self.print_error("removing transaction", tx_hash) self.print_error("removing transaction", tx_hash)
@ -1253,7 +1250,7 @@ class Abstract_Wallet(PrintError):
def make_payment_request(self, addr, amount, message, expiration): def make_payment_request(self, addr, amount, message, expiration):
timestamp = int(time.time()) timestamp = int(time.time())
_id = Hash(addr + "%d"%timestamp).encode('hex')[0:10] _id = bh2u(Hash(addr + "%d"%timestamp))[0:10]
r = {'time':timestamp, 'amount':amount, 'exp':expiration, 'address':addr, 'memo':message, 'id':_id} r = {'time':timestamp, 'amount':amount, 'exp':expiration, 'address':addr, 'memo':message, 'id':_id}
return r return r
@ -1263,7 +1260,7 @@ class Abstract_Wallet(PrintError):
pr = paymentrequest.make_unsigned_request(req) pr = paymentrequest.make_unsigned_request(req)
paymentrequest.sign_request_with_alias(pr, alias, alias_privkey) paymentrequest.sign_request_with_alias(pr, alias, alias_privkey)
req['name'] = pr.pki_data req['name'] = pr.pki_data
req['sig'] = pr.signature.encode('hex') req['sig'] = bh2u(pr.signature)
self.receive_requests[key] = req self.receive_requests[key] = req
self.storage.put('payment_requests', self.receive_requests) self.storage.put('payment_requests', self.receive_requests)
@ -1420,7 +1417,10 @@ class Imported_Wallet(Abstract_Wallet):
def add_input_sig_info(self, txin, address): def add_input_sig_info(self, txin, address):
addrtype, hash160 = bc_address_to_hash_160(address) addrtype, hash160 = bc_address_to_hash_160(address)
x_pubkey = 'fd' + (chr(addrtype) + hash160).encode('hex') if six.PY3:
x_pubkey = 'fd' + bh2u(bytes([addrtype]) + hash160)
else:
x_pubkey = 'fd' + bh2u(chr(addrtype) + hash160)
txin['x_pubkeys'] = [x_pubkey] txin['x_pubkeys'] = [x_pubkey]
txin['signatures'] = [None] txin['signatures'] = [None]

View File

@ -22,8 +22,14 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import threading, Queue, os, json, time import six
from six.moves import queue
import threading, os, json, time
from collections import defaultdict from collections import defaultdict
try: try:
from SimpleWebSocketServer import WebSocket, SimpleSSLWebSocketServer from SimpleWebSocketServer import WebSocket, SimpleSSLWebSocketServer
@ -31,9 +37,9 @@ except ImportError:
import sys import sys
sys.exit("install SimpleWebSocketServer") sys.exit("install SimpleWebSocketServer")
import util from . import util
request_queue = Queue.Queue() request_queue = queue.Queue()
class ElectrumWebSocket(WebSocket): class ElectrumWebSocket(WebSocket):

View File

@ -22,56 +22,63 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from datetime import datetime from datetime import datetime
import sys import sys
import util from . import util
from util import profiler, print_error from .util import profiler, print_error
import ecdsa import ecdsa
import hashlib import hashlib
# algo OIDs # algo OIDs
ALGO_RSA_SHA1 = '1.2.840.113549.1.1.5' ALGO_RSA_SHA1 = '1.2.840.113549.1.1.5'
ALGO_RSA_SHA256 = '1.2.840.113549.1.1.11' ALGO_RSA_SHA256 = '1.2.840.113549.1.1.11'
ALGO_RSA_SHA384 = '1.2.840.113549.1.1.12' ALGO_RSA_SHA384 = '1.2.840.113549.1.1.12'
ALGO_RSA_SHA512 = '1.2.840.113549.1.1.13' ALGO_RSA_SHA512 = '1.2.840.113549.1.1.13'
ALGO_ECDSA_SHA256 = '1.2.840.10045.4.3.2' ALGO_ECDSA_SHA256 = '1.2.840.10045.4.3.2'
# prefixes, see http://stackoverflow.com/questions/3713774/c-sharp-how-to-calculate-asn-1-der-encoding-of-a-particular-hash-algorithm # prefixes, see http://stackoverflow.com/questions/3713774/c-sharp-how-to-calculate-asn-1-der-encoding-of-a-particular-hash-algorithm
PREFIX_RSA_SHA256 = bytearray([0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20]) PREFIX_RSA_SHA256 = bytearray(
PREFIX_RSA_SHA384 = bytearray([0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30]) [0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20])
PREFIX_RSA_SHA512 = bytearray([0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40]) PREFIX_RSA_SHA384 = bytearray(
[0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30])
PREFIX_RSA_SHA512 = bytearray(
[0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40])
# types used in ASN1 structured data # types used in ASN1 structured data
ASN1_TYPES = { ASN1_TYPES = {
'BOOLEAN': 0x01, 'BOOLEAN' : 0x01,
'INTEGER': 0x02, 'INTEGER' : 0x02,
'BIT STRING': 0x03, 'BIT STRING' : 0x03,
'OCTET STRING': 0x04, 'OCTET STRING' : 0x04,
'NULL': 0x05, 'NULL' : 0x05,
'OBJECT IDENTIFIER': 0x06, 'OBJECT IDENTIFIER': 0x06,
'SEQUENCE': 0x70, 'SEQUENCE' : 0x70,
'SET': 0x71, 'SET' : 0x71,
'PrintableString': 0x13, 'PrintableString' : 0x13,
'IA5String': 0x16, 'IA5String' : 0x16,
'UTCTime': 0x17, 'UTCTime' : 0x17,
'ENUMERATED': 0x0A, 'ENUMERATED' : 0x0A,
'UTF8String': 0x0C, 'UTF8String' : 0x0C,
'PrintableString': 0x13,
} }
class CertificateError(Exception): class CertificateError(Exception):
pass pass
# helper functions
# helper functions
def bitstr_to_bytestr(s): def bitstr_to_bytestr(s):
if s[0] != '\x00': if s[0] != '\x00':
raise BaseException('no padding') raise BaseException('no padding')
return s[1:] return s[1:]
def bytestr_to_int(s): def bytestr_to_int(s):
i = 0 i = 0
for char in s: for char in s:
@ -79,6 +86,7 @@ def bytestr_to_int(s):
i |= ord(char) i |= ord(char)
return i return i
def decode_OID(s): def decode_OID(s):
s = map(ord, s) s = map(ord, s)
r = [] r = []
@ -87,103 +95,109 @@ def decode_OID(s):
k = 0 k = 0
for i in s[1:]: for i in s[1:]:
if i < 128: if i < 128:
r.append(i + 128*k) r.append(i + 128 * k)
k = 0 k = 0
else: else:
k = (i - 128) + 128*k k = (i - 128) + 128 * k
return '.'.join(map(str, r)) return '.'.join(map(str, r))
def encode_OID(oid): def encode_OID(oid):
x = map(int, oid.split('.')) x = map(int, oid.split('.'))
s = chr(x[0]*40 + x[1]) s = chr(x[0] * 40 + x[1])
for i in x[2:]: for i in x[2:]:
ss = chr(i % 128) ss = chr(i % 128)
while i > 128: while i > 128:
i = i / 128 i //= 128
ss = chr(128 + i % 128) + ss ss = chr(128 + i % 128) + ss
s += ss s += ss
return s return s
class ASN1_Node(str): class ASN1_Node(str):
def get_node(self, ix): def get_node(self, ix):
# return index of first byte, first content byte and last byte. # return index of first byte, first content byte and last byte.
first = ord(self[ix+1]) first = ord(self[ix + 1])
if (ord(self[ix+1]) & 0x80) == 0: if (ord(self[ix + 1]) & 0x80) == 0:
length = first length = first
ixf = ix + 2 ixf = ix + 2
ixl = ixf + length - 1 ixl = ixf + length - 1
else: else:
lengthbytes = first & 0x7F lengthbytes = first & 0x7F
length = bytestr_to_int(self[ix+2:ix+2+lengthbytes]) length = bytestr_to_int(self[ix + 2:ix + 2 + lengthbytes])
ixf = ix + 2 + lengthbytes ixf = ix + 2 + lengthbytes
ixl = ixf + length -1 ixl = ixf + length - 1
return (ix, ixf, ixl) return ix, ixf, ixl
def root(self):
return self.get_node(0)
def next_node(self, node): def root(self):
ixs, ixf, ixl = node return self.get_node(0)
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): def next_node(self, node):
ixs, ixf, ixl = node1 ixs, ixf, ixl = node
jxs, jxf, jxl = node2 return self.get_node(ixl + 1)
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): def first_child(self, node):
# verify type byte and return content ixs, ixf, ixl = node
ixs, ixf, ixl = node if ord(self[ixs]) & 0x20 != 0x20:
if ASN1_TYPES[asn1_type] != ord(self[ixs]): raise BaseException('Can only open constructed types.', hex(ord(self[ixs])))
raise BaseException('Wrong type:', hex(ord(self[ixs])), hex(ASN1_TYPES[asn1_type]) ) return self.get_node(ixf)
return self[ixf:ixl+1]
def get_value(self, node):
ixs, ixf, ixl = node
return self[ixf:ixl+1]
def get_children(self, node): def is_child_of(node1, node2):
nodes = [] ixs, ixf, ixl = node1
ii = self.first_child(node) 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)
nodes.append(ii) nodes.append(ii)
while ii[2] < node[2]: return nodes
ii = self.next_node(ii)
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): def get_sequence(self):
p = {} return map(lambda j: self.get_value(j), self.get_children(self.root()))
for ii in self.get_children(node):
for iii in self.get_children(ii):
iiii = self.first_child(iii) def get_dict(self, node):
oid = decode_OID(self.get_value_of_type(iiii, 'OBJECT IDENTIFIER')) p = {}
iiii = self.next_node(iiii) for ii in self.get_children(node):
value = self.get_value(iiii) for iii in self.get_children(ii):
p[oid] = value iiii = self.first_child(iii)
return p 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): class X509(object):
def __init__(self, b): def __init__(self, b):
self.bytes = bytearray(b) self.bytes = bytearray(b)
@ -292,24 +306,21 @@ class X509(object):
not_before = time.mktime(time.strptime(self.notBefore, TIMESTAMP_FMT)) not_before = time.mktime(time.strptime(self.notBefore, TIMESTAMP_FMT))
not_after = time.mktime(time.strptime(self.notAfter, TIMESTAMP_FMT)) not_after = time.mktime(time.strptime(self.notAfter, TIMESTAMP_FMT))
if not_before > now: if not_before > now:
raise CertificateError('Certificate has not entered its valid date range. (%s)'%self.get_common_name()) raise CertificateError('Certificate has not entered its valid date range. (%s)' % self.get_common_name())
if not_after <= now: if not_after <= now:
raise CertificateError('Certificate has expired. (%s)'%self.get_common_name()) raise CertificateError('Certificate has expired. (%s)' % self.get_common_name())
def getFingerprint(self): def getFingerprint(self):
return hashlib.sha1(self.bytes).digest() return hashlib.sha1(self.bytes).digest()
@profiler @profiler
def load_certificates(ca_path): def load_certificates(ca_path):
import pem from . import pem
ca_list = {} ca_list = {}
ca_keyID = {} ca_keyID = {}
with open(ca_path, 'r') as f: with open(ca_path, 'rb') as f:
s = f.read() s = f.read().decode('utf8')
bList = pem.dePemList(s, "CERTIFICATE") bList = pem.dePemList(s, "CERTIFICATE")
for b in bList: for b in bList:
try: try:
@ -328,7 +339,7 @@ def load_certificates(ca_path):
if __name__ == "__main__": if __name__ == "__main__":
import requests import requests
util.set_verbosity(True) util.set_verbosity(True)
ca_path = requests.certs.where() ca_path = requests.certs.where()
ca_list, ca_keyID = load_certificates(ca_path) ca_list, ca_keyID = load_certificates(ca_path)