From b8a71ff00cdf025eefea637f4c1b23516dccb76e Mon Sep 17 00:00:00 2001 From: ThomasV Date: Mon, 25 Feb 2013 09:05:45 +0100 Subject: [PATCH] offline wallets sign transactions using KeyID --- electrum | 52 +++++++++++++++++++++++++++++++++----------------- lib/bitcoin.py | 6 ++++++ lib/wallet.py | 10 +++++++++- 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/electrum b/electrum index 12cf2ed98..4fc1b21dd 100755 --- a/electrum +++ b/electrum @@ -636,7 +636,11 @@ if __name__ == '__main__': r, h = wallet.sendtx( tx ) print_msg(h) else: - print_json({"hex":str(tx), "complete":tx.is_complete}) + out = {"hex":str(tx), "complete":tx.is_complete} + if not tx.is_complete: + import json + out['input_info'] = repr(tx.inputs_info).replace(' ','') + print_json(out) if is_temporary: wallet.imported_keys.pop(from_addr) @@ -732,41 +736,55 @@ if __name__ == '__main__': elif cmd == 'signrawtransaction': tx = Transaction(args[1]) - txouts = ast.literal_eval(args[2]) if len(args)>2 else [] + inputs_info = ast.literal_eval(args[2]) if len(args)>2 else [] private_keys = ast.literal_eval(args[3]) if len(args)>3 else {} unspent_coins = wallet.get_unspent_coins() + # convert private_keys to dict + pk = {} + for sec in private_keys: + address = bitcoin.address_from_private_key(sec) + pk[address] = sec + private_keys = pk + for txin in tx.inputs: # convert to own format txin['tx_hash'] = txin['prevout_hash'] txin['index'] = txin['prevout_n'] - for txout in txouts: - if txout.get('txid') == txin['tx_hash'] and txout.get('vout') == txin['index']: - txin['raw_output_script'] = txout['scriptPubKey'] - txin['redeemScript'] = txout['redeemScript'] + for item in inputs_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['electrumKeyID'] = item.get('electrumKeyID') break - else: for item in unspent_coins: if txin['tx_hash'] == item['tx_hash'] and txin['index'] == item['index']: - txin['address'] = item['address'] txin['raw_output_script'] = item['raw_output_script'] break else: # if neither, we might want to get it from the server.. raise - if not private_keys: - for txin in tx.inputs: - addr = txin['address'] - private_keys[addr] = wallet.get_private_key(addr, password) - else: - pk = {} - for sec in private_keys: + # find the address: + from lib import deserialize + if txin.get('electrumKeyID'): + n, for_change = txin.get('electrumKeyID') + sec = wallet.sequence.get_private_key(n, for_change, seed) address = bitcoin.address_from_private_key(sec) - pk[address] = sec - private_keys = pk + txin['address'] = address + private_keys[address] = sec + + elif txin.get("redeemScript"): + txin['address'] = hash_160_to_bc_address(hash_160(txin.get("redeemScript").decode('hex')), 5) + + elif txin.get("raw_output_script"): + addr = deserialize.get_address_from_output_script(txin.get("raw_output_script").decode('hex')) + sec = wallet.get_private_key(addr, password) + if sec: + private_keys[addr] = sec + txin['address'] = addr tx.sign( private_keys ) print_json({ "hex":str(tx),"complete":tx.is_complete}) diff --git a/lib/bitcoin.py b/lib/bitcoin.py index a00b88d90..a7b6a02eb 100644 --- a/lib/bitcoin.py +++ b/lib/bitcoin.py @@ -479,6 +479,12 @@ class Transaction: self.is_complete = False self.inputs = inputs self.outputs = outputs + extras = [] + for i in self.inputs: + print i + e = { 'txid':i['tx_hash'], 'vout':i['index'],'scriptPubKey':i['raw_output_script'] } + extras.append(e) + self.inputs_info = extras return self def __str__(self): diff --git a/lib/wallet.py b/lib/wallet.py index 6da01bb6f..b3599ae1e 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -190,7 +190,7 @@ class Wallet: def get_master_public_key(self): return self.sequence.master_public_key - def get_public_key(self, address): + def get_address_index(self, address): if address in self.imported_keys.keys(): raise BaseException("imported key") @@ -200,7 +200,10 @@ class Wallet: elif address in self.change_addresses: n = self.change_addresses.index(address) for_change = True + return n,for_change + def get_public_key(self, address): + n, for_change = self.get_address_index(address) return self.sequence.get_pubkey(n, for_change) @@ -666,6 +669,11 @@ class Wallet: outputs = self.add_tx_change(outputs, amount, fee, total, change_addr) tx = Transaction.from_io(inputs, outputs) + for i in range(len(tx.inputs)): + addr = tx.inputs[i]['address'] + n, is_change = self.get_address_index(addr) + tx.inputs_info[i]['electrumKeyID'] = (n, is_change) + if not self.seed: return tx