URI: 
       tfix bug with the order of signatures in tx input - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit b32d0c77a3afcfbfa3b551610cab3cba4ddd84c9
   DIR parent 84b8b6d73d6ca2a793db0505022b2510428b4fce
  HTML Author: ThomasV <thomasv@gitorious>
       Date:   Mon, 23 Jun 2014 09:42:07 +0200
       
       fix bug with the order of signatures in tx input
       
       Diffstat:
         M gui/qt/transaction_dialog.py        |       3 ++-
         M lib/transaction.py                  |      82 ++++++++++++++++---------------
         M lib/wallet.py                       |       4 +++-
       
       3 files changed, 47 insertions(+), 42 deletions(-)
       ---
   DIR diff --git a/gui/qt/transaction_dialog.py b/gui/qt/transaction_dialog.py
       t@@ -96,7 +96,8 @@ class TxDialog(QDialog):
                buttons.addWidget(cancelButton)
                cancelButton.setDefault(True)
        
       -        b = QPushButton(_("Show QR code"))
       +        b = QPushButton()
       +        b.setIcon(QIcon(":icons/qrcode.png"))
                b.clicked.connect(self.show_qr)
                buttons.insertWidget(1,b)
                self.update()
   DIR diff --git a/lib/transaction.py b/lib/transaction.py
       t@@ -33,6 +33,8 @@ import struct
        import StringIO
        import mmap
        
       +NO_SIGNATURE = 'ff'
       +
        class SerializationError(Exception):
            """ Thrown when there's a problem deserializing or serializing """
        
       t@@ -303,12 +305,21 @@ def parse_sig(x_sig):
                if sig[-2:] == '01':
                    s.append(sig[:-2])
                else:
       -            assert sig == 'ff'
       +            assert sig == NO_SIGNATURE
       +            s.append(None)
            return s
        
        def is_extended_pubkey(x_pubkey):
            return x_pubkey[0:2] in ['fe', 'ff']
        
       +def x_to_xpub(x_pubkey):
       +    if x_pubkey[0:2] == 'ff':
       +        from account import BIP32_Account
       +        xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       +        return xpub
       +
       +        
       +
        def parse_xpub(x_pubkey):
            if x_pubkey[0:2] == 'ff':
                from account import BIP32_Account
       t@@ -385,6 +396,7 @@ def parse_scriptSig(d, bytes):
            d['x_pubkeys'] = x_pubkeys
            pubkeys = map(parse_xpub, x_pubkeys)
            d['pubkeys'] = pubkeys
       +
            redeemScript = Transaction.multisig_script(pubkeys,2)
            d['redeemScript'] = redeemScript
            d['address'] = hash_160_to_bc_address(hash_160(redeemScript.decode('hex')), 5)
       t@@ -415,6 +427,8 @@ def get_address_from_output_script(bytes):
            return False, "(None)"
        
        
       +
       +
        class Transaction:
            
            def __init__(self, raw):
       t@@ -510,8 +524,6 @@ class Transaction:
            @classmethod
            def serialize( klass, inputs, outputs, for_sig = None ):
        
       -        NO_SIGNATURE = 'ff'
       -
                push_script = lambda x: op_push(len(x)/2) + x
                s  = int_to_hex(1,4)                                         # version
                s += var_int( len(inputs) )                                  # number of inputs
       t@@ -522,38 +534,34 @@ class Transaction:
                    s += int_to_hex(txin['prevout_n'],4)                          # prev index
        
                    p2sh = txin.get('redeemScript') is not None
       -            n_sig = 2 if p2sh else 1
       -
       -            pubkeys = txin['pubkeys'] # pubkeys should always be known
       +            num_sig = txin['num_sig']
                    address = txin['address']
        
       -            if for_sig is None:
       +            x_signatures = txin['signatures']
       +            signatures = filter(lambda x: x is not None, x_signatures)
       +            is_complete = len(signatures) == num_sig
        
       -                # list of signatures
       -                signatures = txin.get('signatures',[])
       +            if for_sig is None:
       +                # if we have enough signatures, we use the actual pubkeys
       +                # use extended pubkeys (with bip32 derivation)
                        sig_list = []
       -                for signature in signatures:
       -                    sig_list.append(signature + '01')
       -                if len(sig_list) > n_sig:
       -                    sig_list = sig_list[:n_sig]
       -                while len(sig_list) < n_sig:
       -                    sig_list.append(NO_SIGNATURE)
       -                sig_list = ''.join( map( lambda x: push_script(x), sig_list))
       -
       -                if len(signatures) < n_sig:
       -                    # extended pubkeys (with bip32 derivation)
       -                    x_pubkeys = txin['x_pubkeys']
       +                if is_complete:
       +                    pubkeys = txin['pubkeys']
       +                    for signature in signatures:
       +                        sig_list.append(signature + '01')
                        else:
       -                    # if we have enough signatures, we use the actual pubkeys
       -                    x_pubkeys = txin['pubkeys']
       +                    pubkeys = txin['x_pubkeys']
       +                    for signature in x_signatures:
       +                        sig_list.append((signature + '01') if signature is not None else NO_SIGNATURE)
        
       +                sig_list = ''.join( map( lambda x: push_script(x), sig_list))
                        if not p2sh:
                            script = sig_list
       -                    script += push_script(x_pubkeys[0])
       +                    script += push_script(pubkeys[0])
                        else:
                            script = '00'                                    # op_0
                            script += sig_list
       -                    redeem_script = klass.multisig_script(x_pubkeys,2)
       +                    redeem_script = klass.multisig_script(pubkeys,2)
                            script += push_script(redeem_script)
        
                    elif for_sig==i:
       t@@ -585,25 +593,21 @@ class Transaction:
                return Hash(self.raw.decode('hex') )[::-1].encode('hex')
        
            def add_signature(self, i, pubkey, sig):
       +        print_error("adding signature for", pubkey)
                txin = self.inputs[i]
       -        signatures = txin.get("signatures",[])
       -        if sig not in signatures:
       -            signatures.append(sig)
       -        txin["signatures"] = signatures
       +        pubkeys = txin['pubkeys']
       +        ii = pubkeys.index(pubkey)
       +        txin['signatures'][ii] = sig
       +        txin['x_pubkeys'][ii] = pubkey
                self.inputs[i] = txin
       -        print_error("adding signature for", pubkey)
       -        # replace x_pubkey
       -        i = txin['pubkeys'].index(pubkey)
       -        txin['x_pubkeys'][i] = pubkey
       -
       -        self.raw = self.serialize( self.inputs, self.outputs )
       +        self.raw = self.serialize(self.inputs, self.outputs)
        
        
            def signature_count(self):
                r = 0
                s = 0
                for txin in self.inputs:
       -            signatures = txin.get("signatures",[])
       +            signatures = filter(lambda x: x is not None, txin['signatures'])
                    s += len(signatures)
                    r += txin['num_sig']
                return s, r
       t@@ -619,15 +623,13 @@ class Transaction:
        
                for i, txin in enumerate(self.inputs):
        
       -            redeem_pubkeys = txin['pubkeys']
       -            num = len(redeem_pubkeys)
       -
       -            # get list of already existing signatures
       -            signatures = txin.get("signatures",{})
                    # continue if this txin is complete
       +            signatures = filter(lambda x: x is not None, txin['signatures'])
       +            num = txin['num_sig']
                    if len(signatures) == num:
                        continue
        
       +            redeem_pubkeys = txin['pubkeys']
                    for_sig = Hash(self.tx_for_sig(i).decode('hex'))
                    for pubkey in redeem_pubkeys:
                        if pubkey in keypairs.keys():
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -861,7 +861,9 @@ class Abstract_Wallet:
                account = self.accounts[account_id]
                redeemScript = account.redeem_script(sequence)
                txin['x_pubkeys'] = account.get_xpubkeys(sequence)
       -        txin['pubkeys'] = account.get_pubkeys(sequence) 
       +        txin['pubkeys'] = pubkeys = account.get_pubkeys(sequence)
       +        txin['signatures'] = [None] * len(pubkeys)
       +
                if redeemScript: 
                    txin['redeemScript'] = redeemScript
                    txin['num_sig'] = 2