Browse Source

cleanup signrawtrasaction and input_info

283
ThomasV 11 years ago
parent
commit
3480cb9ef4
  1. 4
      gui/qt/main_window.py
  2. 74
      lib/transaction.py
  3. 124
      lib/wallet.py

4
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

74
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')

124
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):

Loading…
Cancel
Save