URI: 
       tMerge pull request #3354 from benma/dbb_segwit - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 8a200aaf33711c728665b6cfb0c519d05c419848
   DIR parent b97402b796497626812b9fdf1106ed2d61ac9171
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Thu, 23 Nov 2017 09:27:16 +0100
       
       Merge pull request #3354 from benma/dbb_segwit
       
       digitalbitbox: add support for segwit
       Diffstat:
         M plugins/digitalbitbox/digitalbitbo… |      67 ++++++++++++++++++++-----------
         M plugins/digitalbitbox/qt.py         |       3 +++
       
       2 files changed, 46 insertions(+), 24 deletions(-)
       ---
   DIR diff --git a/plugins/digitalbitbox/digitalbitbox.py b/plugins/digitalbitbox/digitalbitbox.py
       t@@ -6,6 +6,7 @@
        try:
            import electrum
            from electrum.bitcoin import TYPE_ADDRESS, push_script, var_int, msg_magic, Hash, verify_message, pubkey_from_signature, point_to_ser, public_key_to_p2pkh, EncodeAES, DecodeAES, MyVerifyingKey
       +    from electrum.bitcoin import serialize_xpub, deserialize_xpub
            from electrum.transaction import Transaction
            from electrum.i18n import _
            from electrum.keystore import Hardware_KeyStore
       t@@ -85,10 +86,17 @@ class DigitalBitbox_Client():
        
        
            def get_xpub(self, bip32_path, xtype):
       -        assert xtype == 'standard'
       +        assert xtype in ('standard', 'p2wpkh-p2sh')
                reply = self._get_xpub(bip32_path)
                if reply:
       -            return reply['xpub']
       +            xpub = reply['xpub']
       +            # Change type of xpub to the requested type. The firmware
       +            # only ever returns the standard type, but it is agnostic
       +            # to the type when signing.
       +            if xtype != 'standard':
       +                _, depth, fingerprint, child_number, c, cK = deserialize_xpub(xpub)
       +                xpub = serialize_xpub(xtype, c, cK, depth, fingerprint, child_number)
       +            return xpub
                else:
                    raise BaseException('no reply')
        
       t@@ -399,6 +407,10 @@ class DigitalBitbox_KeyStore(Hardware_KeyStore):
                return str(self.derivation)
        
        
       +    def is_p2pkh(self):
       +        return self.derivation.startswith("m/44'/")
       +
       +
            def give_error(self, message, clear_client = False):
                if clear_client:
                    self.client = None
       t@@ -472,7 +484,7 @@ class DigitalBitbox_KeyStore(Hardware_KeyStore):
                    return
        
                try:
       -            p2shTransaction = False
       +            p2pkhTransaction = True
                    derivations = self.get_tx_derivations(tx)
                    inputhasharray = []
                    hasharray = []
       t@@ -483,8 +495,8 @@ class DigitalBitbox_KeyStore(Hardware_KeyStore):
                        if txin['type'] == 'coinbase':
                            self.give_error("Coinbase not supported") # should never happen
        
       -                if txin['type'] in ['p2sh']:
       -                    p2shTransaction = True
       +                if txin['type'] != 'p2pkh':
       +                    p2pkhTransaction = False
        
                        for x_pubkey in txin['x_pubkeys']:
                            if x_pubkey in derivations:
       t@@ -498,12 +510,6 @@ class DigitalBitbox_KeyStore(Hardware_KeyStore):
                        else:
                            self.give_error("No matching x_key for sign_transaction") # should never happen
        
       -            # Sanity check
       -            if p2shTransaction:
       -                for txinput in tx.inputs():
       -                    if txinput['type'] != 'p2sh':
       -                        self.give_error("P2SH / regular input mixed in same transaction not supported") # should never happen
       -
                    # Build pubkeyarray from outputs
                    for _type, address, amount in tx.outputs():
                        assert _type == TYPE_ADDRESS
       t@@ -517,15 +523,22 @@ class DigitalBitbox_KeyStore(Hardware_KeyStore):
        
                    # Special serialization of the unsigned transaction for
                    # the mobile verification app.
       -            class CustomTXSerialization(Transaction):
       -                @classmethod
       -                def input_script(self, txin, estimate_size=False):
       -                    if txin['type'] == 'p2pkh':
       -                        return Transaction.get_preimage_script(txin)
       -                    if txin['type'] == 'p2sh':
       -                        return '00' + push_script(Transaction.get_preimage_script(txin))
       -                    raise Exception("unsupported type %s" % txin['type'])
       -            tx_dbb_serialized = CustomTXSerialization(tx.serialize()).serialize()
       +            # At the moment, verification only works for p2pkh transactions.
       +            if p2pkhTransaction:
       +                class CustomTXSerialization(Transaction):
       +                    @classmethod
       +                    def input_script(self, txin, estimate_size=False):
       +                        if txin['type'] == 'p2pkh':
       +                            return Transaction.get_preimage_script(txin)
       +                        if txin['type'] == 'p2sh':
       +                            # Multisig verification has partial support, but is disabled. This is the
       +                            # expected serialization though, so we leave it here until we activate it.
       +                            return '00' + push_script(Transaction.get_preimage_script(txin))
       +                        raise Exception("unsupported type %s" % txin['type'])
       +                tx_dbb_serialized = CustomTXSerialization(tx.serialize()).serialize()
       +            else:
       +                # We only need this for the signing echo / verification.
       +                tx_dbb_serialized = None
        
                    # Build sign command
                    dbb_signatures = []
       t@@ -533,8 +546,15 @@ class DigitalBitbox_KeyStore(Hardware_KeyStore):
                    for step in range(int(steps)):
                        hashes = hasharray[step * self.maxInputs : (step + 1) * self.maxInputs]
        
       -                msg = ('{"sign": {"meta":"%s", "data":%s, "checkpub":%s} }' % \
       -                       (to_hexstr(Hash(tx_dbb_serialized)), json.dumps(hashes), json.dumps(pubkeyarray))).encode('utf8')
       +                msg = {
       +                    "sign": {
       +                        "data": hashes,
       +                        "checkpub": pubkeyarray,
       +                    },
       +                }
       +                if tx_dbb_serialized is not None:
       +                    msg["sign"]["meta"] = to_hexstr(Hash(tx_dbb_serialized))
       +                msg = json.dumps(msg).encode('ascii')
                        dbb_client = self.plugin.get_client(self)
        
                        if not dbb_client.is_paired():
       t@@ -547,8 +567,7 @@ class DigitalBitbox_KeyStore(Hardware_KeyStore):
                        if 'echo' not in reply:
                            raise Exception("Could not sign transaction.")
        
       -                # multisig verification not working correctly yet
       -                if self.plugin.is_mobile_paired() and not p2shTransaction:
       +                if self.plugin.is_mobile_paired() and tx_dbb_serialized is not None:
                            reply['tx'] = tx_dbb_serialized
                            self.plugin.comserver_post_notification(reply)
        
   DIR diff --git a/plugins/digitalbitbox/qt.py b/plugins/digitalbitbox/qt.py
       t@@ -25,6 +25,9 @@ class Plugin(DigitalBitboxPlugin, QtPluginBase):
                if not self.is_mobile_paired():
                    return
        
       +        if not keystore.is_p2pkh():
       +            return
       +
                if len(addrs) == 1:
                    def show_address():
                        change, index = wallet.get_address_index(addrs[0])