commit 811d05a1c2aaa70e295f508a1ee49416db200714
parent 961b81ba4a68e96183e3f8935540ac04c8ac131c
Author: ThomasV <thomasv@gitorious>
Date: Sat, 23 Feb 2013 17:18:22 +0100
move methods into Transaction class
Diffstat:
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")