tfix #4626 - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit 88fc62e8f788b9e610f5c2e1850009f701e904fe
 (DIR) parent 5f3408dd70f39db363abe7296df814e2cb100332
 (HTM) Author: SomberNight <somber.night@protonmail.com>
       Date:   Tue, 14 Aug 2018 19:38:19 +0200
       
       fix #4626
       
       Diffstat:
         M electrum/plugins/safe_t/safe_t.py   |      72 +++++++++++++------------------
         M electrum/plugins/trezor/trezor.py   |      72 +++++++++++++------------------
         M electrum/transaction.py             |       3 ++-
         M electrum/wallet.py                  |       2 +-
       
       4 files changed, 61 insertions(+), 88 deletions(-)
       ---
 (DIR) diff --git a/electrum/plugins/safe_t/safe_t.py b/electrum/plugins/safe_t/safe_t.py
       t@@ -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
       t@@ -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'
       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)
        
       t@@ -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)
       t@@ -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):
       t@@ -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()
       t@@ -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):
       t@@ -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
       t@@ -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,
       t@@ -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(
 (DIR) diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py
       t@@ -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
       t@@ -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'
       t@@ -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)
        
       t@@ -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)
       t@@ -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):
       t@@ -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()
       t@@ -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):
       t@@ -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
       t@@ -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,
       t@@ -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(
 (DIR) diff --git a/electrum/transaction.py b/electrum/transaction.py
       t@@ -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):
 (DIR) diff --git a/electrum/wallet.py b/electrum/wallet.py
       t@@ -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):