py3
This commit is contained in:
parent
f70408cef5
commit
5be78950ca
37
electrum
37
electrum
|
@ -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,7 +308,7 @@ 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':
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -427,7 +438,7 @@ if __name__ == '__main__':
|
||||||
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'))
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,})\>'
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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 *
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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...
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 _
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
||||||
|
|
236
lib/bitcoin.py
236
lib/bitcoin.py
|
@ -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)
|
||||||
|
assert base in (58, 43)
|
||||||
chars = __b58chars
|
chars = __b58chars
|
||||||
elif base == 43:
|
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)
|
||||||
|
v = to_bytes(v, 'ascii')
|
||||||
|
assert base in (58, 43)
|
||||||
chars = __b58chars
|
chars = __b58chars
|
||||||
elif base == 43:
|
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
12
lib/i18n.py
12
lib/i18n.py
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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,14 +589,17 @@ 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']:
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
if six.PY2:
|
||||||
seed = unicodedata.normalize('NFKD', unicode(seed))
|
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)
|
||||||
|
|
||||||
|
|
16
lib/msqr.py
16
lib/msqr.py
|
@ -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
|
||||||
|
|
|
@ -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,6 +441,7 @@ 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:
|
||||||
|
if six.PY2:
|
||||||
socket.socket = socket._socketobject
|
socket.socket = socket._socketobject
|
||||||
socket.getaddrinfo = socket._socket.getaddrinfo
|
socket.getaddrinfo = socket._socket.getaddrinfo
|
||||||
|
|
||||||
|
@ -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'))
|
||||||
|
|
|
@ -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
|
||||||
|
@ -1689,8 +1695,8 @@ 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:]))
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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':
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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')
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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):
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
237
lib/util.py
237
lib/util.py
|
@ -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,6 +636,9 @@ 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:
|
||||||
|
if six.PY3:
|
||||||
|
out['message'] = out['message']
|
||||||
|
else:
|
||||||
out['message'] = out['message'].decode('utf8')
|
out['message'] = out['message'].decode('utf8')
|
||||||
out['memo'] = out['message']
|
out['memo'] = out['message']
|
||||||
if 'time' in out:
|
if 'time' in out:
|
||||||
|
@ -450,14 +646,14 @@ def parse_URI(uri, on_pr=None):
|
||||||
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()
|
||||||
|
|
||||||
|
if six.PY2:
|
||||||
import __builtin__
|
import __builtin__
|
||||||
builtin_raw_input = __builtin__.raw_input
|
builtin_raw_input = __builtin__.raw_input
|
||||||
__builtin__.raw_input = 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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
continue
|
for addr in mine_addrs:
|
||||||
|
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]
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
||||||
|
|
55
lib/x509.py
55
lib/x509.py
|
@ -22,16 +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 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'
|
||||||
|
@ -40,9 +43,12 @@ 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 = {
|
||||||
|
@ -59,19 +65,20 @@ ASN1_TYPES = {
|
||||||
'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 = []
|
||||||
|
@ -100,16 +108,13 @@ def encode_OID(oid):
|
||||||
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])
|
||||||
|
@ -122,31 +127,37 @@ class ASN1_Node(str):
|
||||||
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):
|
def root(self):
|
||||||
return self.get_node(0)
|
return self.get_node(0)
|
||||||
|
|
||||||
|
|
||||||
def next_node(self, node):
|
def next_node(self, node):
|
||||||
ixs, ixf, ixl = node
|
ixs, ixf, ixl = node
|
||||||
return self.get_node(ixl + 1)
|
return self.get_node(ixl + 1)
|
||||||
|
|
||||||
|
|
||||||
def first_child(self, node):
|
def first_child(self, node):
|
||||||
ixs, ixf, ixl = node
|
ixs, ixf, ixl = node
|
||||||
if ord(self[ixs]) & 0x20 != 0x20:
|
if ord(self[ixs]) & 0x20 != 0x20:
|
||||||
raise BaseException('Can only open constructed types.', hex(ord(self[ixs])))
|
raise BaseException('Can only open constructed types.', hex(ord(self[ixs])))
|
||||||
return self.get_node(ixf)
|
return self.get_node(ixf)
|
||||||
|
|
||||||
|
|
||||||
def is_child_of(node1, node2):
|
def is_child_of(node1, node2):
|
||||||
ixs, ixf, ixl = node1
|
ixs, ixf, ixl = node1
|
||||||
jxs, jxf, jxl = node2
|
jxs, jxf, jxl = node2
|
||||||
return ((ixf <= jxs) and (jxl <= ixl)) or ((jxf <= ixs) and (ixl <= jxl))
|
return ((ixf <= jxs) and (jxl <= ixl)) or ((jxf <= ixs) and (ixl <= jxl))
|
||||||
|
|
||||||
|
|
||||||
def get_all(self, node):
|
def get_all(self, node):
|
||||||
# return type + length + value
|
# return type + length + value
|
||||||
ixs, ixf, ixl = node
|
ixs, ixf, ixl = node
|
||||||
return self[ixs:ixl + 1]
|
return self[ixs:ixl + 1]
|
||||||
|
|
||||||
|
|
||||||
def get_value_of_type(self, node, asn1_type):
|
def get_value_of_type(self, node, asn1_type):
|
||||||
# verify type byte and return content
|
# verify type byte and return content
|
||||||
ixs, ixf, ixl = node
|
ixs, ixf, ixl = node
|
||||||
|
@ -154,10 +165,12 @@ class ASN1_Node(str):
|
||||||
raise BaseException('Wrong type:', hex(ord(self[ixs])), hex(ASN1_TYPES[asn1_type]))
|
raise BaseException('Wrong type:', hex(ord(self[ixs])), hex(ASN1_TYPES[asn1_type]))
|
||||||
return self[ixf:ixl + 1]
|
return self[ixf:ixl + 1]
|
||||||
|
|
||||||
|
|
||||||
def get_value(self, node):
|
def get_value(self, node):
|
||||||
ixs, ixf, ixl = node
|
ixs, ixf, ixl = node
|
||||||
return self[ixf:ixl + 1]
|
return self[ixf:ixl + 1]
|
||||||
|
|
||||||
|
|
||||||
def get_children(self, node):
|
def get_children(self, node):
|
||||||
nodes = []
|
nodes = []
|
||||||
ii = self.first_child(node)
|
ii = self.first_child(node)
|
||||||
|
@ -167,9 +180,11 @@ class ASN1_Node(str):
|
||||||
nodes.append(ii)
|
nodes.append(ii)
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
|
|
||||||
def get_sequence(self):
|
def get_sequence(self):
|
||||||
return map(lambda j: self.get_value(j), self.get_children(self.root()))
|
return map(lambda j: self.get_value(j), self.get_children(self.root()))
|
||||||
|
|
||||||
|
|
||||||
def get_dict(self, node):
|
def get_dict(self, node):
|
||||||
p = {}
|
p = {}
|
||||||
for ii in self.get_children(node):
|
for ii in self.get_children(node):
|
||||||
|
@ -183,7 +198,6 @@ class ASN1_Node(str):
|
||||||
|
|
||||||
|
|
||||||
class X509(object):
|
class X509(object):
|
||||||
|
|
||||||
def __init__(self, b):
|
def __init__(self, b):
|
||||||
|
|
||||||
self.bytes = bytearray(b)
|
self.bytes = bytearray(b)
|
||||||
|
@ -300,16 +314,13 @@ class X509(object):
|
||||||
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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue