electrum

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

commit 88fc62e8f788b9e610f5c2e1850009f701e904fe
parent 5f3408dd70f39db363abe7296df814e2cb100332
Author: SomberNight <somber.night@protonmail.com>
Date:   Tue, 14 Aug 2018 19:38:19 +0200

fix #4626

Diffstat:
Melectrum/plugins/safe_t/safe_t.py | 72+++++++++++++++++++++++++++++-------------------------------------------
Melectrum/plugins/trezor/trezor.py | 72+++++++++++++++++++++++++++++-------------------------------------------
Melectrum/transaction.py | 3++-
Melectrum/wallet.py | 2+-
4 files changed, 61 insertions(+), 88 deletions(-)

diff --git a/electrum/plugins/safe_t/safe_t.py b/electrum/plugins/safe_t/safe_t.py @@ -9,7 +9,7 @@ from electrum import constants from electrum.i18n import _ from electrum.plugin import BasePlugin, Device from electrum.transaction import deserialize, Transaction -from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey, xtype_from_derivation +from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey from electrum.base_wizard import ScriptTypeNotSupported from ..hw_wallet import HW_PluginBase @@ -19,9 +19,6 @@ from ..hw_wallet.plugin import is_any_tx_output_on_change_branch, trezor_validat # Safe-T mini initialization methods TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4) -# script "generation" -SCRIPT_GEN_LEGACY, SCRIPT_GEN_P2SH_SEGWIT, SCRIPT_GEN_NATIVE_SEGWIT = range(0, 3) - class SafeTKeyStore(Hardware_KeyStore): hw_type = 'safe_t' @@ -30,15 +27,6 @@ class SafeTKeyStore(Hardware_KeyStore): def get_derivation(self): return self.derivation - def get_script_gen(self): - xtype = xtype_from_derivation(self.derivation) - if xtype in ('p2wpkh', 'p2wsh'): - return SCRIPT_GEN_NATIVE_SEGWIT - elif xtype in ('p2wpkh-p2sh', 'p2wsh-p2sh'): - return SCRIPT_GEN_P2SH_SEGWIT - else: - return SCRIPT_GEN_LEGACY - def get_client(self, force_pair=True): return self.plugin.get_client(self, force_pair) @@ -294,23 +282,34 @@ class SafeTPlugin(HW_PluginBase): client.used() return xpub - def get_safet_input_script_type(self, script_gen, is_multisig): - if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: + def get_safet_input_script_type(self, electrum_txin_type: str): + if electrum_txin_type in ('p2wpkh', 'p2wsh'): return self.types.InputScriptType.SPENDWITNESS - elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: + if electrum_txin_type in ('p2wpkh-p2sh', 'p2wsh-p2sh'): return self.types.InputScriptType.SPENDP2SHWITNESS - else: - if is_multisig: - return self.types.InputScriptType.SPENDMULTISIG - else: - return self.types.InputScriptType.SPENDADDRESS + if electrum_txin_type in ('p2pkh', ): + return self.types.InputScriptType.SPENDADDRESS + if electrum_txin_type in ('p2sh', ): + return self.types.InputScriptType.SPENDMULTISIG + raise ValueError('unexpected txin type: {}'.format(electrum_txin_type)) + + def get_safet_output_script_type(self, electrum_txin_type: str): + if electrum_txin_type in ('p2wpkh', 'p2wsh'): + return self.types.OutputScriptType.PAYTOWITNESS + if electrum_txin_type in ('p2wpkh-p2sh', 'p2wsh-p2sh'): + return self.types.OutputScriptType.PAYTOP2SHWITNESS + if electrum_txin_type in ('p2pkh', ): + return self.types.OutputScriptType.PAYTOADDRESS + if electrum_txin_type in ('p2sh', ): + return self.types.OutputScriptType.PAYTOMULTISIG + raise ValueError('unexpected txin type: {}'.format(electrum_txin_type)) def sign_transaction(self, keystore, tx, prev_tx, xpub_path): self.prev_tx = prev_tx self.xpub_path = xpub_path client = self.get_client(keystore) - inputs = self.tx_inputs(tx, True, keystore.get_script_gen()) - outputs = self.tx_outputs(keystore.get_derivation(), tx, keystore.get_script_gen()) + inputs = self.tx_inputs(tx, True) + outputs = self.tx_outputs(keystore.get_derivation(), tx) signatures = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[0] signatures = [(bh2u(x) + '01') for x in signatures] tx.update_signatures(signatures) @@ -330,8 +329,7 @@ class SafeTPlugin(HW_PluginBase): address_n = client.expand_path(address_path) xpubs = wallet.get_master_public_keys() if len(xpubs) == 1: - script_gen = keystore.get_script_gen() - script_type = self.get_safet_input_script_type(script_gen, is_multisig=False) + script_type = self.get_safet_input_script_type(wallet.txin_type) client.get_address(self.get_coin_name(), address_n, True, script_type=script_type) else: def f(xpub): @@ -345,11 +343,10 @@ class SafeTPlugin(HW_PluginBase): signatures=[b''] * wallet.n, m=wallet.m, ) - script_gen = keystore.get_script_gen() - script_type = self.get_safet_input_script_type(script_gen, is_multisig=True) + script_type = self.get_safet_input_script_type(wallet.txin_type) client.get_address(self.get_coin_name(), address_n, True, multisig=multisig, script_type=script_type) - def tx_inputs(self, tx, for_sig=False, script_gen=SCRIPT_GEN_LEGACY): + def tx_inputs(self, tx, for_sig=False): inputs = [] for txin in tx.inputs(): txinputtype = self.types.TxInputType() @@ -364,7 +361,7 @@ class SafeTPlugin(HW_PluginBase): xpub, s = parse_xpubkey(x_pubkey) xpub_n = self.client_class.expand_path(self.xpub_path[xpub]) txinputtype._extend_address_n(xpub_n + s) - txinputtype.script_type = self.get_safet_input_script_type(script_gen, is_multisig=False) + txinputtype.script_type = self.get_safet_input_script_type(txin['type']) else: def f(x_pubkey): if is_xpubkey(x_pubkey): @@ -379,7 +376,7 @@ class SafeTPlugin(HW_PluginBase): signatures=list(map(lambda x: bfh(x)[:-1] if x else b'', txin.get('signatures'))), m=txin.get('num_sig'), ) - script_type = self.get_safet_input_script_type(script_gen, is_multisig=True) + script_type = self.get_safet_input_script_type(txin['type']) txinputtype = self.types.TxInputType( script_type=script_type, multisig=multisig @@ -411,16 +408,11 @@ class SafeTPlugin(HW_PluginBase): return inputs - def tx_outputs(self, derivation, tx, script_gen=SCRIPT_GEN_LEGACY): + def tx_outputs(self, derivation, tx): def create_output_by_derivation(): + script_type = self.get_trezor_output_script_type(info.script_type) if len(xpubs) == 1: - if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: - script_type = self.types.OutputScriptType.PAYTOWITNESS - elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: - script_type = self.types.OutputScriptType.PAYTOP2SHWITNESS - else: - script_type = self.types.OutputScriptType.PAYTOADDRESS address_n = self.client_class.expand_path(derivation + "/%d/%d" % index) txoutputtype = self.types.TxOutputType( amount=amount, @@ -428,12 +420,6 @@ class SafeTPlugin(HW_PluginBase): address_n=address_n, ) else: - if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: - script_type = self.types.OutputScriptType.PAYTOWITNESS - elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: - script_type = self.types.OutputScriptType.PAYTOP2SHWITNESS - else: - script_type = self.types.OutputScriptType.PAYTOMULTISIG address_n = self.client_class.expand_path("/%d/%d" % index) pubkeys = [self._make_node_path(xpub, address_n) for xpub in xpubs] multisig = self.types.MultisigRedeemScriptType( diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py @@ -9,7 +9,7 @@ from electrum import constants from electrum.i18n import _ from electrum.plugin import BasePlugin, Device from electrum.transaction import deserialize, Transaction -from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey, xtype_from_derivation +from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey from electrum.base_wizard import ScriptTypeNotSupported from ..hw_wallet import HW_PluginBase @@ -20,9 +20,6 @@ from ..hw_wallet.plugin import is_any_tx_output_on_change_branch, trezor_validat TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4) RECOVERY_TYPE_SCRAMBLED_WORDS, RECOVERY_TYPE_MATRIX = range(0, 2) -# script "generation" -SCRIPT_GEN_LEGACY, SCRIPT_GEN_P2SH_SEGWIT, SCRIPT_GEN_NATIVE_SEGWIT = range(0, 3) - class TrezorKeyStore(Hardware_KeyStore): hw_type = 'trezor' @@ -31,15 +28,6 @@ class TrezorKeyStore(Hardware_KeyStore): def get_derivation(self): return self.derivation - def get_script_gen(self): - xtype = xtype_from_derivation(self.derivation) - if xtype in ('p2wpkh', 'p2wsh'): - return SCRIPT_GEN_NATIVE_SEGWIT - elif xtype in ('p2wpkh-p2sh', 'p2wsh-p2sh'): - return SCRIPT_GEN_P2SH_SEGWIT - else: - return SCRIPT_GEN_LEGACY - def get_client(self, force_pair=True): return self.plugin.get_client(self, force_pair) @@ -305,23 +293,34 @@ class TrezorPlugin(HW_PluginBase): client.used() return xpub - def get_trezor_input_script_type(self, script_gen, is_multisig): - if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: + def get_trezor_input_script_type(self, electrum_txin_type: str): + if electrum_txin_type in ('p2wpkh', 'p2wsh'): return self.types.InputScriptType.SPENDWITNESS - elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: + if electrum_txin_type in ('p2wpkh-p2sh', 'p2wsh-p2sh'): return self.types.InputScriptType.SPENDP2SHWITNESS - else: - if is_multisig: - return self.types.InputScriptType.SPENDMULTISIG - else: - return self.types.InputScriptType.SPENDADDRESS + if electrum_txin_type in ('p2pkh', ): + return self.types.InputScriptType.SPENDADDRESS + if electrum_txin_type in ('p2sh', ): + return self.types.InputScriptType.SPENDMULTISIG + raise ValueError('unexpected txin type: {}'.format(electrum_txin_type)) + + def get_trezor_output_script_type(self, electrum_txin_type: str): + if electrum_txin_type in ('p2wpkh', 'p2wsh'): + return self.types.OutputScriptType.PAYTOWITNESS + if electrum_txin_type in ('p2wpkh-p2sh', 'p2wsh-p2sh'): + return self.types.OutputScriptType.PAYTOP2SHWITNESS + if electrum_txin_type in ('p2pkh', ): + return self.types.OutputScriptType.PAYTOADDRESS + if electrum_txin_type in ('p2sh', ): + return self.types.OutputScriptType.PAYTOMULTISIG + raise ValueError('unexpected txin type: {}'.format(electrum_txin_type)) def sign_transaction(self, keystore, tx, prev_tx, xpub_path): self.prev_tx = prev_tx self.xpub_path = xpub_path client = self.get_client(keystore) - inputs = self.tx_inputs(tx, True, keystore.get_script_gen()) - outputs = self.tx_outputs(keystore.get_derivation(), tx, keystore.get_script_gen()) + inputs = self.tx_inputs(tx, True) + outputs = self.tx_outputs(keystore.get_derivation(), tx) signatures = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[0] signatures = [(bh2u(x) + '01') for x in signatures] tx.update_signatures(signatures) @@ -341,8 +340,7 @@ class TrezorPlugin(HW_PluginBase): address_n = client.expand_path(address_path) xpubs = wallet.get_master_public_keys() if len(xpubs) == 1: - script_gen = keystore.get_script_gen() - script_type = self.get_trezor_input_script_type(script_gen, is_multisig=False) + script_type = self.get_trezor_input_script_type(wallet.txin_type) client.get_address(self.get_coin_name(), address_n, True, script_type=script_type) else: def f(xpub): @@ -356,11 +354,10 @@ class TrezorPlugin(HW_PluginBase): signatures=[b''] * wallet.n, m=wallet.m, ) - script_gen = keystore.get_script_gen() - script_type = self.get_trezor_input_script_type(script_gen, is_multisig=True) + script_type = self.get_trezor_input_script_type(wallet.txin_type) client.get_address(self.get_coin_name(), address_n, True, multisig=multisig, script_type=script_type) - def tx_inputs(self, tx, for_sig=False, script_gen=SCRIPT_GEN_LEGACY): + def tx_inputs(self, tx, for_sig=False): inputs = [] for txin in tx.inputs(): txinputtype = self.types.TxInputType() @@ -375,7 +372,7 @@ class TrezorPlugin(HW_PluginBase): xpub, s = parse_xpubkey(x_pubkey) xpub_n = self.client_class.expand_path(self.xpub_path[xpub]) txinputtype._extend_address_n(xpub_n + s) - txinputtype.script_type = self.get_trezor_input_script_type(script_gen, is_multisig=False) + txinputtype.script_type = self.get_trezor_input_script_type(txin['type']) else: def f(x_pubkey): if is_xpubkey(x_pubkey): @@ -390,7 +387,7 @@ class TrezorPlugin(HW_PluginBase): signatures=list(map(lambda x: bfh(x)[:-1] if x else b'', txin.get('signatures'))), m=txin.get('num_sig'), ) - script_type = self.get_trezor_input_script_type(script_gen, is_multisig=True) + script_type = self.get_trezor_input_script_type(txin['type']) txinputtype = self.types.TxInputType( script_type=script_type, multisig=multisig @@ -422,16 +419,11 @@ class TrezorPlugin(HW_PluginBase): return inputs - def tx_outputs(self, derivation, tx, script_gen=SCRIPT_GEN_LEGACY): + def tx_outputs(self, derivation, tx): def create_output_by_derivation(): + script_type = self.get_trezor_output_script_type(info.script_type) if len(xpubs) == 1: - if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: - script_type = self.types.OutputScriptType.PAYTOWITNESS - elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: - script_type = self.types.OutputScriptType.PAYTOP2SHWITNESS - else: - script_type = self.types.OutputScriptType.PAYTOADDRESS address_n = self.client_class.expand_path(derivation + "/%d/%d" % index) txoutputtype = self.types.TxOutputType( amount=amount, @@ -439,12 +431,6 @@ class TrezorPlugin(HW_PluginBase): address_n=address_n, ) else: - if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: - script_type = self.types.OutputScriptType.PAYTOWITNESS - elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: - script_type = self.types.OutputScriptType.PAYTOP2SHWITNESS - else: - script_type = self.types.OutputScriptType.PAYTOMULTISIG address_n = self.client_class.expand_path("/%d/%d" % index) pubkeys = [self._make_node_path(xpub, address_n) for xpub in xpubs] multisig = self.types.MultisigRedeemScriptType( diff --git a/electrum/transaction.py b/electrum/transaction.py @@ -65,7 +65,8 @@ TxOutput = NamedTuple("TxOutput", [('type', int), ('address', str), ('value', Un TxOutputHwInfo = NamedTuple("TxOutputHwInfo", [('address_index', Tuple), ('sorted_xpubs', Iterable[str]), - ('num_sig', Optional[int])]) + ('num_sig', Optional[int]), + ('script_type', str)]) class BCDataStream(object): diff --git a/electrum/wallet.py b/electrum/wallet.py @@ -787,7 +787,7 @@ class Abstract_Wallet(AddressSynchronizer): # sort xpubs using the order of pubkeys sorted_pubkeys, sorted_xpubs = zip(*sorted(zip(pubkeys, xpubs))) num_sig = self.m if isinstance(self, Multisig_Wallet) else None - info[addr] = TxOutputHwInfo(index, sorted_xpubs, num_sig) + info[addr] = TxOutputHwInfo(index, sorted_xpubs, num_sig, self.txin_type) tx.output_info = info def sign_transaction(self, tx, password):