electrum

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

commit 3480cb9ef47c0cbfabeaec5b24e6f171e85dc251
parent a9b05ad1884752181c45f17126fcb85dbc82bc4b
Author: ThomasV <thomasv@gitorious>
Date:   Sun, 29 Sep 2013 15:16:22 +0200

cleanup signrawtrasaction and input_info

Diffstat:
Mgui/qt/main_window.py | 4+++-
Mlib/transaction.py | 74+++++++++++++++++++++++++++++++++++++-------------------------------------
Mlib/wallet.py | 124++++++++++++++++++++++++++++++++++---------------------------------------------
3 files changed, 93 insertions(+), 109 deletions(-)

diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py @@ -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 diff --git a/lib/transaction.py b/lib/transaction.py @@ -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 @@ -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 @@ -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'] @@ -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 @@ -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 @@ -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 @@ -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') diff --git a/lib/wallet.py b/lib/wallet.py @@ -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 = [] @@ -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): @@ -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)) @@ -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: @@ -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 @@ -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):