|
|
@ -454,7 +454,61 @@ class DeterministicSequence: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def raw_tx( inputs, outputs, for_sig = None ): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Transaction: |
|
|
|
|
|
|
|
def __init__(self, raw): |
|
|
|
self.raw = raw |
|
|
|
self.deserialize() |
|
|
|
self.inputs = self.d['inputs'] |
|
|
|
self.outputs = self.d['outputs'] |
|
|
|
self.outputs = map(lambda x: (x['address'],x['value']), self.outputs) |
|
|
|
|
|
|
|
@classmethod |
|
|
|
def from_io(klass, inputs, outputs): |
|
|
|
raw = klass.serialize(inputs, outputs, for_sig = -1) # for_sig=-1 means do not sign |
|
|
|
self = klass(raw) |
|
|
|
self.inputs = inputs |
|
|
|
self.outputs = outputs |
|
|
|
return self |
|
|
|
|
|
|
|
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 |
|
|
@ -481,7 +535,7 @@ def raw_tx( inputs, outputs, for_sig = None ): |
|
|
|
script += op_push(len(sig)/2) |
|
|
|
script += sig |
|
|
|
|
|
|
|
redeem_script = multisig_script(pubkeys,2) |
|
|
|
redeem_script = klass.multisig_script(pubkeys,2) |
|
|
|
script += op_push(len(redeem_script)/2) |
|
|
|
script += redeem_script |
|
|
|
|
|
|
@ -522,60 +576,9 @@ def raw_tx( inputs, outputs, for_sig = None ): |
|
|
|
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: |
|
|
|
|
|
|
|
def __init__(self, raw): |
|
|
|
self.raw = raw |
|
|
|
self.deserialize() |
|
|
|
self.inputs = self.d['inputs'] |
|
|
|
self.outputs = self.d['outputs'] |
|
|
|
self.outputs = map(lambda x: (x['address'],x['value']), self.outputs) |
|
|
|
|
|
|
|
@classmethod |
|
|
|
def from_io(klass, inputs, outputs): |
|
|
|
raw = raw_tx(inputs, outputs, for_sig = -1) # for_sig=-1 means do not sign |
|
|
|
self = klass(raw) |
|
|
|
self.inputs = inputs |
|
|
|
self.outputs = outputs |
|
|
|
return self |
|
|
|
|
|
|
|
def __str__(self): |
|
|
|
return self.raw |
|
|
|
|
|
|
|
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): |
|
|
|