electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit b86619ee301cf6e2528439064328f2734adeee46
parent ad15c6a80e619d418c10b50d3fa8f3b583f8eecf
Author: ThomasV <thomasv@electrum.org>
Date:   Wed, 30 Aug 2017 11:48:55 +0200

Merge pull request #2760 from jhoenicke/trezorsegwit

[TREZOR] Added Segwit support.
Diffstat:
Mlib/base_wizard.py | 2+-
Mlib/keystore.py | 9++++-----
Mlib/transaction.py | 10+++++++---
Mplugins/trezor/plugin.py | 31+++++++++++++++++++++----------
4 files changed, 33 insertions(+), 19 deletions(-)

diff --git a/lib/base_wizard.py b/lib/base_wizard.py @@ -227,7 +227,7 @@ class BaseWizard(object): self.derivation_dialog(f) def derivation_dialog(self, f): - default = bip44_derivation(0) + default = bip44_derivation(0, self.config.get('segwit')) message = '\n'.join([ _('Enter your wallet derivation here.'), _('If you are not sure what this is, leave this field unchanged.') diff --git a/lib/keystore.py b/lib/keystore.py @@ -684,11 +684,10 @@ 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) -def bip44_derivation(account_id): - if bitcoin.TESTNET: - return "m/44'/1'/%d'"% int(account_id) - else: - return "m/44'/0'/%d'"% int(account_id) +def bip44_derivation(account_id, segwit=False): + bip = 49 if segwit else 44 + coin = 1 if bitcoin.TESTNET else 0 + return "m/%d'/%d'/%d'" % (bip, coin, int(account_id)) def from_seed(seed, passphrase): t = seed_type(seed) diff --git a/lib/transaction.py b/lib/transaction.py @@ -421,8 +421,7 @@ def parse_input(vds): def parse_witness(vds): n = vds.read_compact_size() - for i in range(n): - x = vds.read_bytes(vds.read_compact_size()) + return list(vds.read_bytes(vds.read_compact_size()).encode('hex') for i in xrange(n)) def parse_output(vds, i): d = {} @@ -548,7 +547,12 @@ class Transaction: for i, txin in enumerate(self.inputs()): pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin) sigs1 = txin.get('signatures') - sigs2 = d['inputs'][i].get('signatures') + if d.get('witness') is None: + sigs2 = d['inputs'][i].get('signatures') + else: + # signatures are in the witnesses. But the last item is + # the pubkey or the multisig script, so skip that. + sigs2 = d['witness'][i][:-1] for sig in sigs2: if sig in sigs1: continue diff --git a/plugins/trezor/plugin.py b/plugins/trezor/plugin.py @@ -26,6 +26,9 @@ class TrezorCompatibleKeyStore(Hardware_KeyStore): def get_derivation(self): return self.derivation + def is_segwit(self): + return self.derivation.startswith("m/49'/") + def get_client(self, force_pair=True): return self.plugin.get_client(self, force_pair) @@ -241,8 +244,8 @@ class TrezorCompatiblePlugin(HW_PluginBase): self.prev_tx = prev_tx self.xpub_path = xpub_path client = self.get_client(keystore) - inputs = self.tx_inputs(tx, True) - outputs = self.tx_outputs(keystore.get_derivation(), tx) + inputs = self.tx_inputs(tx, True, keystore.is_segwit()) + outputs = self.tx_outputs(keystore.get_derivation(), tx, keystore.is_segwit()) signed_tx = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[1] raw = bh2u(signed_tx) tx.update_signatures(raw) @@ -256,9 +259,11 @@ class TrezorCompatiblePlugin(HW_PluginBase): derivation = wallet.keystore.derivation address_path = "%s/%d/%d"%(derivation, change, index) address_n = client.expand_path(address_path) - client.get_address(self.get_coin_name(), address_n, True) + segwit = wallet.keystore.is_segwit() + script_type = self.types.SPENDP2SHWITNESS if segwit else self.types.SPENDADDRESS + client.get_address(self.get_coin_name(), address_n, True, script_type=script_type) - def tx_inputs(self, tx, for_sig=False): + def tx_inputs(self, tx, for_sig=False, segwit=False): inputs = [] for txin in tx.inputs(): txinputtype = self.types.TxInputType() @@ -273,6 +278,7 @@ class TrezorCompatiblePlugin(HW_PluginBase): xpub, s = parse_xpubkey(x_pubkey) xpub_n = self.client_class.expand_path(self.xpub_path[xpub]) txinputtype.address_n.extend(xpub_n + s) + txinputtype.script_type = self.types.SPENDP2SHWITNESS if segwit else self.types.SPENDADDRESS else: def f(x_pubkey): if is_xpubkey(x_pubkey): @@ -288,8 +294,9 @@ class TrezorCompatiblePlugin(HW_PluginBase): signatures=map(lambda x: bfh(x)[:-1] if x else b'', txin.get('signatures')), m=txin.get('num_sig'), ) + script_type = self.types.SPENDP2SHWITNESS if segwit else self.types.SPENDMULTISIG txinputtype = self.types.TxInputType( - script_type=self.types.SPENDMULTISIG, + script_type=script_type, multisig=multisig ) # find which key is mine @@ -304,6 +311,8 @@ class TrezorCompatiblePlugin(HW_PluginBase): prev_hash = unhexlify(txin['prevout_hash']) prev_index = txin['prevout_n'] + if 'value' in txin: + txinputtype.amount = txin['value'] txinputtype.prev_hash = prev_hash txinputtype.prev_index = prev_index @@ -317,7 +326,7 @@ class TrezorCompatiblePlugin(HW_PluginBase): return inputs - def tx_outputs(self, derivation, tx): + def tx_outputs(self, derivation, tx, segwit=False): outputs = [] has_change = False @@ -327,14 +336,16 @@ class TrezorCompatiblePlugin(HW_PluginBase): has_change = True # no more than one change address addrtype, hash_160 = bc_address_to_hash_160(address) index, xpubs, m = info - if addrtype == ADDRTYPE_P2PKH: + if len(xpubs) == 1: + script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOADDRESS address_n = self.client_class.expand_path(derivation + "/%d/%d"%index) txoutputtype = self.types.TxOutputType( amount = amount, - script_type = self.types.PAYTOADDRESS, + script_type = script_type, address_n = address_n, ) - elif addrtype == ADDRTYPE_P2SH: + else: + script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOMULTISIG address_n = self.client_class.expand_path("/%d/%d"%index) nodes = map(self.ckd_public.deserialize, xpubs) pubkeys = [ self.types.HDNodePathType(node=node, address_n=address_n) for node in nodes] @@ -346,7 +357,7 @@ class TrezorCompatiblePlugin(HW_PluginBase): multisig = multisig, amount = amount, address_n = self.client_class.expand_path(derivation + "/%d/%d"%index), - script_type = self.types.PAYTOMULTISIG) + script_type = script_type) else: txoutputtype = self.types.TxOutputType() txoutputtype.amount = amount