URI: 
       tcleanup signrawtrasaction and input_info - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 3480cb9ef47c0cbfabeaec5b24e6f171e85dc251
   DIR parent a9b05ad1884752181c45f17126fcb85dbc82bc4b
  HTML Author: ThomasV <thomasv@gitorious>
       Date:   Sun, 29 Sep 2013 15:16:22 +0200
       
       cleanup signrawtrasaction and input_info
       
       Diffstat:
         M gui/qt/main_window.py               |       4 +++-
         M lib/transaction.py                  |      74 ++++++++++++++++----------------
         M lib/wallet.py                       |     124 +++++++++++++------------------
       
       3 files changed, 93 insertions(+), 109 deletions(-)
       ---
   DIR diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
       t@@ -1658,9 +1658,11 @@ class ElectrumWindow(QMainWindow):
                    tx_dict = json.loads(str(txt))
                    assert "hex" in tx_dict.keys()
                    assert "complete" in tx_dict.keys()
       +            tx = Transaction(tx_dict["hex"])
                    if not tx_dict["complete"]:
                        assert "input_info" in tx_dict.keys()
       -            tx = Transaction(tx_dict["hex"])
       +                input_info = json.loads(tx_dict['input_info'])
       +                tx.add_input_info(input_info)
                    return tx
                except:
                    pass
   DIR diff --git a/lib/transaction.py b/lib/transaction.py
       t@@ -376,8 +376,7 @@ class Transaction:
                self.inputs = self.d['inputs']
                self.outputs = self.d['outputs']
                self.outputs = map(lambda x: (x['address'],x['value']), self.outputs)
       -        self.input_info = None
       -        self.is_complete = True
       +        self.is_complete = False
                
            def __str__(self):
                return self.raw
       t@@ -389,22 +388,6 @@ class Transaction:
                self.is_complete = False
                self.inputs = inputs
                self.outputs = outputs
       -        extras = []
       -        for i in self.inputs:
       -            
       -            e = { 'txid':i['tx_hash'],
       -                  'vout':i['index'],
       -                  'scriptPubKey':i.get('raw_output_script'),
       -                  'KeyID':i['KeyID'],
       -                  'redeemScript':i.get('redeemScript'),
       -                  'redeemPubkey':i.get('redeemPubkey')
       -                  }
       -            extras.append(e)
       -            # fixme: simplify this
       -            i['prevout_hash'] = i['tx_hash']
       -            i['prevout_n'] = i['index']
       -
       -        self.input_info = extras
                return self
        
            @classmethod
       t@@ -441,8 +424,8 @@ class Transaction:
                s += var_int( len(inputs) )                                  # number of inputs
                for i in range(len(inputs)):
                    txin = inputs[i]
       -            s += txin['tx_hash'].decode('hex')[::-1].encode('hex')   # prev hash
       -            s += int_to_hex(txin['index'],4)                         # prev index
       +            s += txin['prevout_hash'].decode('hex')[::-1].encode('hex')   # prev hash
       +            s += int_to_hex(txin['prevout_n'],4)                          # prev index
        
                    if for_sig is None:
                        signatures = txin['signatures']
       t@@ -470,7 +453,7 @@ class Transaction:
                        if txin.get('redeemScript'):
                            script = txin['redeemScript']                    # p2sh uses the inner script
                        else:
       -                    script = txin['raw_output_script']               # scriptsig
       +                    script = txin['scriptPubKey']                    # scriptsig
                    else:
                        script=''
                    s += var_int( len(script)/2 )                            # script length
       t@@ -598,8 +581,8 @@ class Transaction:
                is_pubkey, address = get_address_from_output_script(scriptPubKey)
                d['is_pubkey'] = is_pubkey
                d['address'] = address
       -        d['raw_output_script'] = scriptPubKey.encode('hex')
       -        d['index'] = i
       +        d['scriptPubKey'] = scriptPubKey.encode('hex')
       +        d['prevout_n'] = i
                return d
        
        
       t@@ -679,27 +662,36 @@ class Transaction:
        
                return is_relevant, is_send, v, fee
        
       +
       +    def get_input_info(self):
       +        info = []
       +        for i in self.inputs:
       +            print len(i)
       +            item = { 
       +                'prevout_hash':i['prevout_hash'], 
       +                'prevout_n':i['prevout_n'],
       +                'address':i['address'],
       +                'KeyID':i.get('KeyID'),
       +                'scriptPubKey':i.get('scriptPubKey'),
       +                'redeemScript':i.get('redeemScript'),
       +                'redeemPubkey':i.get('redeemPubkey'),
       +                'pubkeys':i.get('pubkeys'),
       +                'signatures':i.get('signatures'),
       +                }
       +            info.append(item)
       +        return info
       +
       +
            def as_dict(self):
                import json
                out = {
                    "hex":self.raw,
                    "complete":self.is_complete
                    }
       +
                if not self.is_complete:
       -            extras = []
       -            for i in self.inputs:
       -                e = { 'txid':i['tx_hash'], 'vout':i['index'],
       -                      'scriptPubKey':i.get('raw_output_script'),
       -                      'KeyID':i.get('KeyID'),
       -                      'redeemScript':i.get('redeemScript'),
       -                      'signatures':i.get('signatures'),
       -                      'pubkeys':i.get('pubkeys'),
       -                      }
       -                extras.append(e)
       -            self.input_info = extras
       -
       -            if self.input_info:
       -                out['input_info'] = json.dumps(self.input_info).replace(' ','')
       +            input_info = self.get_input_info()
       +            out['input_info'] = json.dumps(input_info).replace(' ','')
        
                return out
        
       t@@ -724,3 +716,11 @@ class Transaction:
                return priority < threshold 
        
        
       +
       +    def add_input_info(self, input_info):
       +        for i, txin in enumerate(self.inputs):
       +            item = input_info[i]
       +            txin['address'] = item['address']
       +            txin['scriptPubKey'] = item['scriptPubKey']
       +            txin['redeemScript'] = item.get('redeemScript')
       +            txin['KeyID'] = item.get('KeyID')
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -585,44 +585,17 @@ class Wallet:
                return out
        
        
       +    def add_keypairs_from_wallet(self, tx, keypairs, password):
       +        for txin in tx.inputs:
       +            address = txin['address']
       +            private_keys = self.get_private_key(address, password)
       +            for sec in private_keys:
       +                pubkey = public_key_from_private_key(sec)
       +                keypairs[ pubkey ] = sec
        
        
       -    def signrawtransaction(self, tx, input_info, private_keys, password):
       -
       -        unspent_coins = self.get_unspent_coins()
       -        seed = self.decode_seed(password)
       -
       -        # build a list of public/private keys
       -        keypairs = {}
       -        for sec in private_keys:
       -            pubkey = public_key_from_private_key(sec)
       -            keypairs[ pubkey ] = sec
       -
       -
       +    def add_keypairs_from_KeyID(self, tx, keypairs, password):
                for txin in tx.inputs:
       -            # convert to own format
       -            txin['tx_hash'] = txin['prevout_hash']
       -            txin['index'] = txin['prevout_n']
       -
       -            for item in input_info:
       -                if item.get('txid') == txin['tx_hash'] and item.get('vout') == txin['index']:
       -                    txin['raw_output_script'] = item['scriptPubKey']
       -                    txin['redeemScript'] = item.get('redeemScript')
       -                    txin['KeyID'] = item.get('KeyID')
       -                    break
       -            else:
       -                for item in unspent_coins:
       -                    if txin['tx_hash'] == item['tx_hash'] and txin['index'] == item['index']:
       -                        print_error( "tx input is in unspent coins" )
       -                        txin['raw_output_script'] = item['raw_output_script']
       -                        account, sequence = self.get_address_index(item['address'])
       -                        if account != -1:
       -                            txin['redeemScript'] = self.accounts[account].redeem_script(sequence)
       -                        break
       -                else:
       -                    raise BaseException("Unknown transaction input. Please provide the 'input_info' parameter, or synchronize this wallet")
       -
       -            # if available, derive private_keys from KeyID
                    keyid = txin.get('KeyID')
                    if keyid:
                        roots = []
       t@@ -643,32 +616,51 @@ class Wallet:
                        account = self.accounts.get(account_id)
                        if not account: continue
                        addr = account.get_address(*sequence)
       -                txin['address'] = addr
       +                txin['address'] = addr # fixme: side effect
                        pk = self.get_private_key(addr, password)
                        for sec in pk:
                            pubkey = public_key_from_private_key(sec)
                            keypairs[pubkey] = sec
        
       -            redeem_script = txin.get("redeemScript")
       -            print_error( "p2sh:", "yes" if redeem_script else "no")
       -            if redeem_script:
       -                addr = hash_160_to_bc_address(hash_160(redeem_script.decode('hex')), 5)
       -            else:
       -                import transaction
       -                _, addr = transaction.get_address_from_output_script(txin["raw_output_script"].decode('hex'))
       -            txin['address'] = addr
        
       -            # add private keys that are in the wallet
       -            pk = self.get_private_key(addr, password)
       -            for sec in pk:
       -                pubkey = public_key_from_private_key(sec)
       -                keypairs[pubkey] = sec
       -                if not redeem_script:
       -                    txin['redeemPubkey'] = pubkey
        
       -            print txin
       +    def signrawtransaction(self, tx, input_info, private_keys, password):
       +
       +        # check that the password is correct
       +        seed = self.decode_seed(password)
       +
       +        # add input info
       +        tx.add_input_info(input_info)
       +
       +        # add redeem script for coins that are in the wallet
       +        # FIXME: add redeemPubkey too!
       +        unspent_coins = self.get_unspent_coins()
       +        for txin in tx.inputs:
       +            for item in unspent_coins:
       +                if txin['prevout_hash'] == item['prevout_hash'] and txin['prevout_n'] == item['prevout_n']:
       +                    print_error( "tx input is in unspent coins" )
       +                    txin['scriptPubKey'] = item['scriptPubKey']
       +                    account, sequence = self.get_address_index(item['address'])
       +                    if account != -1:
       +                        txin['redeemScript'] = self.accounts[account].redeem_script(sequence)
       +                        print_error("added redeemScript", txin['redeemScript'])
       +                    break
       +
       +
       +        # build a list of public/private keys
       +        keypairs = {}
       +
       +        # add private keys from parameter
       +        for sec in private_keys:
       +            pubkey = public_key_from_private_key(sec)
       +            keypairs[ pubkey ] = sec
       +
       +        # add private_keys from KeyID
       +        self.add_keypairs_from_KeyID(tx, keypairs, password)
        
       -        self.sign_tx(tx, keypairs)
       +        # add private keys from wallet
       +        self.add_keypairs_from_wallet(tx, keypairs, password)
       +        self.sign_transaction(tx, keypairs)
        
        
            def sign_message(self, address, message, password):
       t@@ -979,9 +971,9 @@ class Wallet:
                        if tx is None: raise BaseException("Wallet not synchronized")
                        for output in tx.d.get('outputs'):
                            if output.get('address') != addr: continue
       -                    key = tx_hash + ":%d" % output.get('index')
       +                    key = tx_hash + ":%d" % output.get('prevout_n')
                            if key in self.spent_outputs: continue
       -                    output['tx_hash'] = tx_hash
       +                    output['prevout_hash'] = tx_hash
                            output['height'] = tx_height
                            coins.append((tx_height, output))
        
       t@@ -1021,7 +1013,7 @@ class Wallet:
                    addr = item.get('address')
                    v = item.get('value')
                    total += v
       -            inputs.append( item )
       +            inputs.append(item)
                    fee = self.estimated_fee(inputs) if fixed_fee is None else fixed_fee
                    if total >= amount + fee: break
                else:
       t@@ -1210,7 +1202,9 @@ class Wallet:
        
            def mktx(self, outputs, password, fee=None, change_addr=None, domain= None ):
                tx = self.make_unsigned_transaction(outputs, fee, change_addr, domain)
       -        self.sign_transaction(tx, password)
       +        keypairs = {}
       +        self.add_keypairs_from_wallet(tx, keypairs, password)
       +        self.sign_transaction(tx, keypairs)
                return tx
        
        
       t@@ -1226,21 +1220,9 @@ class Wallet:
                        txin['redeemPubkey'] = self.accounts[account].get_pubkey(*sequence)
        
        
       -    def sign_transaction(self, tx, password):
       -        keypairs = {}
       -        for i, txin in enumerate(tx.inputs):
       -            address = txin['address']
       -            private_keys = self.get_private_key(address, password)
       -            for sec in private_keys:
       -                pubkey = public_key_from_private_key(sec)
       -                keypairs[ pubkey ] = sec
       -
       -        self.sign_tx(tx, keypairs)
       -
       -
       -    def sign_tx(self, tx, keypairs):
       +    def sign_transaction(self, tx, keypairs):
                tx.sign(keypairs)
       -        run_hook('sign_tx', tx)
       +        run_hook('sign_transaction', tx)
        
        
            def sendtx(self, tx):