commit 3480cb9ef47c0cbfabeaec5b24e6f171e85dc251
parent a9b05ad1884752181c45f17126fcb85dbc82bc4b
Author: ThomasV <thomasv@gitorious>
Date: Sun, 29 Sep 2013 15:16:22 +0200
cleanup signrawtrasaction and input_info
Diffstat:
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):