electrum

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

commit 811d05a1c2aaa70e295f508a1ee49416db200714
parent 961b81ba4a68e96183e3f8935540ac04c8ac131c
Author: ThomasV <thomasv@gitorious>
Date:   Sat, 23 Feb 2013 17:18:22 +0100

move methods into Transaction class

Diffstat:
Melectrum | 5+----
Mlib/bitcoin.py | 201++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mlib/deserialize.py | 7+++----
3 files changed, 106 insertions(+), 107 deletions(-)

diff --git a/electrum b/electrum @@ -717,13 +717,10 @@ if __name__ == '__main__': elif cmd == 'createmultisig': - 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) + print_json( Transaction.multisig_script(pubkeys, num) ) elif cmd == 'createrawtransaction': diff --git a/lib/bitcoin.py b/lib/bitcoin.py @@ -454,105 +454,10 @@ class DeterministicSequence: -def raw_tx( inputs, outputs, for_sig = None ): - - s = int_to_hex(1,4) # version - 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 - - if for_sig is None: - pubkeysig = txin.get('pubkeysig') - if pubkeysig: - pubkey, sig = pubkeysig[0] - sig = sig + chr(1) # hashtype - script = op_push( len(sig)) - script += sig.encode('hex') - script += op_push( len(pubkey)) - script += pubkey.encode('hex') - else: - signatures = txin['signatures'] - pubkeys = txin['pubkeys'] - script = '00' # op_0 - for sig in signatures: - sig = sig + '01' - script += op_push(len(sig)/2) - script += sig - - redeem_script = multisig_script(pubkeys,2) - script += op_push(len(redeem_script)/2) - script += redeem_script - - elif for_sig==i: - if txin.get('redeemScript'): - script = txin['redeemScript'] # p2sh uses the inner script - else: - script = txin['raw_output_script'] # scriptsig - else: - script='' - s += var_int( len(script)/2 ) # script length - s += script - s += "ffffffff" # sequence - - s += var_int( len(outputs) ) # number of outputs - for output in outputs: - addr, amount = output - s += int_to_hex( amount, 8) # amount - addrtype, hash_160 = bc_address_to_hash_160(addr) - if addrtype == 0: - script = '76a9' # op_dup, op_hash_160 - script += '14' # push 0x14 bytes - script += hash_160.encode('hex') - script += '88ac' # op_equalverify, op_checksig - elif addrtype == 5: - script = 'a9' # op_hash_160 - script += '14' # push 0x14 bytes - script += hash_160.encode('hex') - script += '87' # op_equal - else: - raise - - s += var_int( len(script)/2 ) # script length - s += script # script - s += int_to_hex(0,4) # lock time - if for_sig is not None and for_sig != -1: - s += int_to_hex(1, 4) # hash type - return s -def multisig_script(public_keys, num=None): - # supports only "2 of 2", and "2 of 3" transactions - n = len(public_keys) - - 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 - if n==2: - s += '52' - elif n==3: - s += '53' - else: - raise - s += 'ae' - return s - - class Transaction: @@ -565,7 +470,7 @@ class Transaction: @classmethod def from_io(klass, inputs, outputs): - raw = raw_tx(inputs, outputs, for_sig = -1) # for_sig=-1 means do not sign + raw = klass.serialize(inputs, outputs, for_sig = -1) # for_sig=-1 means do not sign self = klass(raw) self.inputs = inputs self.outputs = outputs @@ -574,8 +479,106 @@ class Transaction: def __str__(self): return self.raw + @classmethod + def multisig_script(klass, public_keys, num=None): + n = len(public_keys) + if num is None: num = n + # supports only "2 of 2", and "2 of 3" transactions + assert num <= n and n in [2,3] + + 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 + if n==2: + s += '52' + elif n==3: + s += '53' + else: + raise + s += 'ae' + + out = { "address": hash_160_to_bc_address(hash_160(s.decode('hex')), 5), "redeemScript":s } + return out + + @classmethod + def serialize( klass, inputs, outputs, for_sig = None ): + + s = int_to_hex(1,4) # version + 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 + + if for_sig is None: + pubkeysig = txin.get('pubkeysig') + if pubkeysig: + pubkey, sig = pubkeysig[0] + sig = sig + chr(1) # hashtype + script = op_push( len(sig)) + script += sig.encode('hex') + script += op_push( len(pubkey)) + script += pubkey.encode('hex') + else: + signatures = txin['signatures'] + pubkeys = txin['pubkeys'] + script = '00' # op_0 + for sig in signatures: + sig = sig + '01' + script += op_push(len(sig)/2) + script += sig + + redeem_script = klass.multisig_script(pubkeys,2) + script += op_push(len(redeem_script)/2) + script += redeem_script + + elif for_sig==i: + if txin.get('redeemScript'): + script = txin['redeemScript'] # p2sh uses the inner script + else: + script = txin['raw_output_script'] # scriptsig + else: + script='' + s += var_int( len(script)/2 ) # script length + s += script + s += "ffffffff" # sequence + + s += var_int( len(outputs) ) # number of outputs + for output in outputs: + addr, amount = output + s += int_to_hex( amount, 8) # amount + addrtype, hash_160 = bc_address_to_hash_160(addr) + if addrtype == 0: + script = '76a9' # op_dup, op_hash_160 + script += '14' # push 0x14 bytes + script += hash_160.encode('hex') + script += '88ac' # op_equalverify, op_checksig + elif addrtype == 5: + script = 'a9' # op_hash_160 + script += '14' # push 0x14 bytes + script += hash_160.encode('hex') + script += '87' # op_equal + else: + raise + + s += var_int( len(script)/2 ) # script length + s += script # script + s += int_to_hex(0,4) # lock time + if for_sig is not None and for_sig != -1: + s += int_to_hex(1, 4) # hash type + return s + + def for_sig(self,i): - return raw_tx(self.inputs, self.outputs, for_sig = i) + return self.serialize(self.inputs, self.outputs, for_sig = i) + def hash(self): return Hash(self.raw.decode('hex') )[::-1].encode('hex') @@ -585,7 +588,7 @@ class Transaction: for i in range(len(self.inputs)): txin = self.inputs[i] - tx_for_sig = raw_tx( self.inputs, self.outputs, for_sig = i ) + tx_for_sig = self.serialize( self.inputs, self.outputs, for_sig = i ) if txin.get('redeemScript'): # 1 parse the redeem script @@ -654,7 +657,7 @@ class Transaction: self.inputs[i]["pubkeysig"] = [(pubkey, sig)] self.is_complete = True - self.raw = raw_tx( self.inputs, self.outputs ) + self.raw = self.serialize( self.inputs, self.outputs ) def deserialize(self): diff --git a/lib/deserialize.py b/lib/deserialize.py @@ -2,7 +2,7 @@ # # -from bitcoin import public_key_to_bc_address, hash_160_to_bc_address, hash_encode, multisig_script, hash_160 +from bitcoin import public_key_to_bc_address, hash_160_to_bc_address, hash_encode, hash_160 #import socket import time import struct @@ -348,15 +348,14 @@ def get_address_from_input_script(bytes): match2 = [ opcodes.OP_2, opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4, opcodes.OP_2, opcodes.OP_CHECKMULTISIG ] if match_decoded(dec2, match2): pubkeys = [ dec2[1][1].encode('hex'), dec2[2][1].encode('hex') ] - s = multisig_script(pubkeys) - return pubkeys, signatures, hash_160_to_bc_address(hash_160(s.decode('hex')), 5) + return pubkeys, signatures, hash_160_to_bc_address(hash_160(redeemScript), 5) # 2 of 3 match2 = [ opcodes.OP_2, opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4, opcodes.OP_3, opcodes.OP_CHECKMULTISIG ] if match_decoded(dec2, match2): pubkeys = [ dec2[1][1].encode('hex'), dec2[2][1].encode('hex'), dec2[3][1].encode('hex') ] s = multisig_script(pubkeys) - return pubkeys, signatures, hash_160_to_bc_address(hash_160(s.decode('hex')), 5) + return pubkeys, signatures, hash_160_to_bc_address(hash_160(redeemScript), 5) raise BaseException("no match for scriptsig")