electrum

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

commit 972ba397d1eca79a3f6eddd4550480a198a6ae60
parent f971c80d5812b629d00bdd5760a93889a4f6e0ab
Author: thomasv <thomasv@gitorious>
Date:   Wed, 20 Feb 2013 13:10:32 +0100

support for multisig functions

Diffstat:
Melectrum | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mlib/__init__.py | 2+-
Mlib/bitcoin.py | 25++++++++++++++++++++++---
Mlib/util.py | 6++++++
4 files changed, 85 insertions(+), 6 deletions(-)

diff --git a/electrum b/electrum @@ -91,6 +91,10 @@ options:\n --fee, -f: set transaction fee\n --fromaddr, -s: send from address 'unfreeze':'', 'prioritize':'', 'unprioritize':'', + 'createmultisig':'similar to bitcoind\'s command', + 'createrawtransaction':'similar to bitcoind\'s command', + 'decoderawtransaction':'similar to bitcoind\'s command', + 'signrawtransaction':'similar to bitcoind\'s command', } @@ -103,10 +107,12 @@ offline_commands = [ 'password', 'mktx', 'signtx', 'importprivkey', 'seed', 'deseed','reseed', 'freeze','unfreeze', - 'prioritize','unprioritize'] + 'prioritize','unprioritize', + 'createmultisig', 'createrawtransaction', 'decoderawtransaction', 'signrawtransaction' + ] -protected_commands = ['payto', 'password', 'mktx', 'signtx', 'seed', 'importprivkey','signmessage' ] +protected_commands = ['payto', 'password', 'mktx', 'signtx', 'seed', 'importprivkey','signmessage', 'signrawtransaction' ] # get password routine def prompt_password(prompt, confirm=True): @@ -690,5 +696,53 @@ if __name__ == '__main__': print_msg(wallet.unprioritize(addr)) + elif cmd == 'createmultisig': + import ast + from lib.bitcoin import * + num = int(args[1]) + pubkeys = ast.literal_eval(args[2]) + assert isinstance(pubkeys,list) + s = multisig_script(pubkeys, num) + out = { "address": hash_160_to_bc_address(hash_160(s.decode('hex')), 5), "redeemScript":s } + print_json(out) + + + elif cmd == 'createrawtransaction': + import ast + inputs = ast.literal_eval(args[1]) + outputs = ast.literal_eval(args[2]) + inputs = map(lambda x: (None, None, x["txid"], x["vout"], None, None), inputs) + outputs = map(lambda x: (x[0],int(x[1]*1e8)), outputs.items()) + tx = raw_tx(inputs, outputs, for_sig = -1) # for_sig=-1 means do not sign + print_msg( tx ) + + + elif cmd == 'decoderawtransaction': + print_json( bitcoin.deserialize(args[1]) ) + + + elif cmd == 'signrawtransaction': + d = bitcoin.deserialize(args[1]) + txouts = args[2] if len(args)>2 else [] + private_keys = args[3] if len(args)>3 else [] + + inputs = [] + for x in d['inputs']: + txid = x["prevout_hash"] + nout = x["prevout_n"] + tx = wallet.transactions.get(txid) + txout = tx['outputs'][nout] + addr = txout['address'] + v = txout['value'] + inputs.append( (addr, v, txid, nout, txout['raw_output_script'], [(None,None)] ) ) + + outputs = map(lambda x: (x['address'],x['value']), d['outputs']) + print_error("inputs", inputs) + print_error("outputs", outputs) + + tx = wallet.signed_tx( inputs, outputs, password ) + print_msg(tx) + + if cmd not in offline_commands and not options.offline: synchronizer.stop() diff --git a/lib/__init__.py b/lib/__init__.py @@ -1,5 +1,5 @@ from version import ELECTRUM_VERSION -from util import format_satoshis, print_msg, print_error, set_verbosity +from util import format_satoshis, print_msg, print_json, print_error, set_verbosity from i18n import set_language from wallet import WalletSynchronizer from wallet_factory import WalletFactory as Wallet diff --git a/lib/bitcoin.py b/lib/bitcoin.py @@ -378,14 +378,33 @@ def raw_tx( inputs, outputs, for_sig = None ): s += var_int( len(tx_filter(script))/2 ) # script length s += script # script s += int_to_hex(0,4) # lock time - if for_sig is not None: s += int_to_hex(1, 4) # hash type + if for_sig is not None and for_sig != 1: s += int_to_hex(1, 4) # hash type return tx_filter(s) -def multisig_script(public_keys): +def deserialize(raw_tx): + import deserialize + vds = deserialize.BCDataStream() + vds.write(raw_tx.decode('hex')) + return deserialize.parse_Transaction(vds) + + +def multisig_script(public_keys, num=None): # supports only "2 of 2", and "2 of 3" transactions n = len(public_keys) - s = '52' + + if num is None: + num = n + + assert num <= n and n <= 3 and n >= 2 + + if num==2: + s = '52' + elif num == 3: + s = '53' + else: + raise + for k in public_keys: s += var_int(len(k)/2) s += k diff --git a/lib/util.py b/lib/util.py @@ -22,6 +22,12 @@ def print_msg(*args): sys.stdout.write(" ".join(args) + "\n") sys.stdout.flush() +def print_json(obj): + import json + s = json.dumps(obj,sort_keys = True, indent = 4) + sys.stdout.write(s + "\n") + sys.stdout.flush() + def check_windows_wallet_migration(): if os.path.exists(os.path.join(os.environ["LOCALAPPDATA"], "Electrum")):