1
0

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
BTChip
2014-08-27 07:49:01 +02:00
13 changed files with 135 additions and 129 deletions

View File

@@ -45,42 +45,36 @@ class Listener(threading.Thread):
threading.Thread.__init__(self)
self.daemon = True
self.parent = parent
self.key = None
self.keyname = None
self.keyhash = None
self.is_running = False
self.message = None
self.delete = False
def set_key(self, key):
self.key = key
def set_key(self, keyname, keyhash):
self.keyname = keyname
self.keyhash = keyhash
def clear(self):
self.delete = True
server.delete(self.keyhash)
self.message = None
def run(self):
self.is_running = True
while self.is_running:
if not self.key:
if not self.keyhash:
time.sleep(2)
continue
if not self.message:
try:
self.message = server.get(self.key)
self.message = server.get(self.keyhash)
except Exception as e:
util.print_error("cannot contact cosigner pool")
time.sleep(30)
continue
if self.message:
self.parent.win.emit(SIGNAL("cosigner:receive"))
else:
if self.delete:
# save it to disk
server.delete(self.key)
self.message = None
self.delete = False
# poll every 30 seconds
time.sleep(30)
@@ -109,21 +103,25 @@ class Plugin(BasePlugin):
self.load_wallet(self.win.wallet)
return True
def is_available(self):
if self.wallet is None:
return True
return self.wallet.wallet_type in ['2of2', '2of3']
def load_wallet(self, wallet):
self.wallet = wallet
if not self.is_available():
return
mpk = self.wallet.get_master_public_keys()
self.cold = mpk.get('x2')
if self.cold:
self.cold_K = bitcoin.deserialize_xkey(self.cold)[-1].encode('hex')
self.cold_hash = bitcoin.Hash(self.cold_K).encode('hex')
self.hot = mpk.get('x1')
if self.hot:
self.hot_K = bitcoin.deserialize_xkey(self.hot)[-1].encode('hex')
self.hot_hash = bitcoin.Hash(self.hot_K).encode('hex')
self.listener.set_key(self.hot_hash)
self.cosigner_list = []
for key, xpub in mpk.items():
keyname = key + '/' # fixme
K = bitcoin.deserialize_xkey(xpub)[-1].encode('hex')
_hash = bitcoin.Hash(K).encode('hex')
if self.wallet.master_private_keys.get(keyname):
self.listener.set_key(keyname, _hash)
else:
self.cosigner_list.append((xpub, K, _hash))
def transaction_dialog(self, d):
self.send_button = b = QPushButton(_("Send to cosigner"))
@@ -131,18 +129,18 @@ class Plugin(BasePlugin):
d.buttons.insertWidget(2, b)
self.transaction_dialog_update(d)
def transaction_dialog_update(self, d):
if d.tx.is_complete():
self.send_button.hide()
return
if self.cosigner_can_sign(d.tx):
self.send_button.show()
for xpub, K, _hash in self.cosigner_list:
if self.cosigner_can_sign(d.tx, xpub):
self.send_button.show()
break
else:
self.send_button.hide()
def cosigner_can_sign(self, tx):
def cosigner_can_sign(self, tx, cosigner_xpub):
from electrum.transaction import x_to_xpub
xpub_set = set([])
for txin in tx.inputs:
@@ -151,24 +149,21 @@ class Plugin(BasePlugin):
if xpub:
xpub_set.add(xpub)
return self.cold in xpub_set
return cosigner_xpub in xpub_set
def do_send(self, tx):
if not self.cosigner_can_sign(tx):
return
message = bitcoin.encrypt_message(tx.raw, self.cold_K)
try:
server.put(self.cold_hash, message)
self.win.show_message("Your transaction was sent to the cosigning pool.\nOpen your cosigner wallet to retrieve it.")
except Exception as e:
self.win.show_message(str(e))
for xpub, K, _hash in self.cosigner_list:
if not self.cosigner_can_sign(tx, xpub):
continue
message = bitcoin.encrypt_message(tx.raw, K)
try:
server.put(_hash, message)
except Exception as e:
self.win.show_message(str(e))
return
self.win.show_message("Your transaction was sent to the cosigning pool.\nOpen your cosigner wallet to retrieve it.")
def on_receive(self):
if self.wallet.use_encryption:
password = self.win.password_dialog('An encrypted transaction was retrieved from cosigning pool.\nPlease enter your password to decrypt it.')
if not password:
@@ -177,11 +172,12 @@ class Plugin(BasePlugin):
password = None
message = self.listener.message
xpriv = self.wallet.get_master_private_key('x1/', password)
if not xpriv:
key = self.listener.keyname
xprv = self.wallet.get_master_private_key(key, password)
if not xprv:
return
try:
k = bitcoin.deserialize_xkey(xpriv)[-1].encode('hex')
k = bitcoin.deserialize_xkey(xprv)[-1].encode('hex')
EC = bitcoin.EC_KEY(k.decode('hex'))
message = EC.decrypt_message(message)
except Exception as e:
@@ -190,7 +186,6 @@ class Plugin(BasePlugin):
return
self.listener.clear()
tx = transaction.Transaction.deserialize(message)
self.win.show_transaction(tx)

View File

@@ -1,4 +1,4 @@
from PyQt4.Qt import QMessageBox, QDialog, QVBoxLayout, QLabel, QThread, SIGNAL
from PyQt4.Qt import QMessageBox, QDialog, QVBoxLayout, QLabel, QThread, SIGNAL, QGridLayout, QInputDialog, QPushButton
import PyQt4.QtCore as QtCore
from binascii import unhexlify
from struct import pack
@@ -7,7 +7,7 @@ from time import sleep
from base64 import b64encode, b64decode
from electrum_gui.qt.password_dialog import make_password_dialog, run_password_dialog
from electrum_gui.qt.util import ok_cancel_buttons
from electrum_gui.qt.util import ok_cancel_buttons, EnterButton
from electrum.account import BIP32_Account
from electrum.bitcoin import EncodeBase58Check, public_key_to_bc_address, bc_address_to_hash_160
from electrum.i18n import _
@@ -43,6 +43,7 @@ class Plugin(BasePlugin):
def __init__(self, gui, name):
BasePlugin.__init__(self, gui, name)
self._is_available = self._init()
self._requires_settings = True
self.wallet = None
def _init(self):
@@ -55,6 +56,9 @@ class Plugin(BasePlugin):
return True
return False
def requires_settings(self):
return self._requires_settings
def set_enabled(self, enabled):
self.wallet.storage.put('use_' + self.name, enabled)
@@ -77,6 +81,8 @@ class Plugin(BasePlugin):
wallet_types.append(('trezor', _("Trezor wallet"), TrezorWallet))
def installwizard_restore(self, wizard, storage):
if storage.get('wallet_type') != 'trezor':
return
wallet = TrezorWallet(storage)
try:
wallet.create_main_account(None)
@@ -91,6 +97,41 @@ class Plugin(BasePlugin):
except Exception as e:
tx.error = str(e)
def settings_widget(self, window):
return EnterButton(_('Settings'), self.settings_dialog)
def settings_dialog(self):
get_label = lambda: self.wallet.get_client().features.label
update_label = lambda: current_label_label.setText("Label: %s" % get_label())
d = QDialog()
layout = QGridLayout(d)
layout.addWidget(QLabel("Trezor Options"),0,0)
layout.addWidget(QLabel("ID:"),1,0)
layout.addWidget(QLabel(" %s" % self.wallet.get_client().get_device_id()),1,1)
def modify_label():
response = QInputDialog().getText(None, "Set New Trezor Label", "New Trezor Label: (upon submission confirm on Trezor)")
if not response[1]:
return
new_label = str(response[0])
twd.start("Please confirm label change on Trezor")
status = self.wallet.get_client().apply_settings(label=new_label)
twd.stop()
update_label()
current_label_label = QLabel()
update_label()
change_label_button = QPushButton("Modify")
change_label_button.clicked.connect(modify_label)
layout.addWidget(current_label_label,3,0)
layout.addWidget(change_label_button,3,1)
if d.exec_():
return True
else:
return False
class TrezorWallet(NewWallet):
wallet_type = 'trezor'
@@ -138,7 +179,7 @@ class TrezorWallet(NewWallet):
def address_id(self, address):
account_id, (change, address_index) = self.get_address_index(address)
return "%s/%d/%d" % (account_id, change, address_index)
return "44'/0'/%s'/%d/%d" % (account_id, change, address_index)
def create_main_account(self, password):
self.create_account('Main account', None) #name, empty password
@@ -167,12 +208,9 @@ class TrezorWallet(NewWallet):
pass
def decrypt_message(self, pubkey, message, password):
try:
address = public_key_to_bc_address(pubkey.decode('hex'))
address_path = self.address_id(address)
address_n = self.get_client().expand_path(address_path)
except Exception, e:
raise e
address = public_key_to_bc_address(pubkey.decode('hex'))
address_path = self.address_id(address)
address_n = self.get_client().expand_path(address_path)
try:
decrypted_msg = self.get_client().decrypt_message(address_n, b64decode(message))
except Exception, e:
@@ -182,6 +220,8 @@ class TrezorWallet(NewWallet):
return str(decrypted_msg)
def sign_message(self, address, message, password):
if not self.check_proper_device():
give_error('Wrong device or password')
try:
address_path = self.address_id(address)
address_n = self.get_client().expand_path(address_path)