1
0

replace tx.input, tx.output by methods, so that deserialize calls are encapsulated

This commit is contained in:
ThomasV
2016-01-17 14:12:57 +01:00
parent 321ab10742
commit d200b236ae
7 changed files with 63 additions and 55 deletions

View File

@@ -479,17 +479,27 @@ class Transaction:
self.raw = raw['hex']
else:
raise BaseException("cannot initialize transaction", raw)
self.inputs = None
self._inputs = None
def update(self, raw):
self.raw = raw
self.inputs = None
self._inputs = None
self.deserialize()
def inputs(self):
if self._inputs is None:
self.deserialize()
return self._inputs
def outputs(self):
if self._outputs is None:
self.deserialize()
return self._outputs
def update_signatures(self, raw):
"""Add new signatures to a transaction"""
d = deserialize(raw)
for i, txin in enumerate(self.inputs):
for i, txin in enumerate(self.inputs()):
sigs1 = txin.get('signatures')
sigs2 = d['inputs'][i].get('signatures')
for sig in sigs2:
@@ -509,8 +519,8 @@ class Transaction:
public_key.verify_digest(sig_string, for_sig, sigdecode = ecdsa.util.sigdecode_string)
j = pubkeys.index(pubkey)
print_error("adding sig", i, j, pubkey, sig)
self.inputs[i]['signatures'][j] = sig
self.inputs[i]['x_pubkeys'][j] = pubkey
self._inputs[i]['signatures'][j] = sig
self._inputs[i]['x_pubkeys'][j] = pubkey
break
# redo raw
self.raw = self.serialize()
@@ -519,19 +529,19 @@ class Transaction:
def deserialize(self):
if self.raw is None:
self.raw = self.serialize()
if self.inputs is not None:
if self._inputs is not None:
return
d = deserialize(self.raw)
self.inputs = d['inputs']
self.outputs = [(x['type'], x['address'], x['value']) for x in d['outputs']]
self._inputs = d['inputs']
self._outputs = [(x['type'], x['address'], x['value']) for x in d['outputs']]
self.locktime = d['lockTime']
return d
@classmethod
def from_io(klass, inputs, outputs, locktime=0):
self = klass(None)
self.inputs = inputs
self.outputs = outputs
self._inputs = inputs
self._outputs = outputs
self.locktime = locktime
return self
@@ -657,12 +667,12 @@ class Transaction:
def BIP_LI01_sort(self):
# See https://github.com/kristovatlas/rfc/blob/master/bips/bip-li01.mediawiki
self.inputs.sort(key = lambda i: (i['prevout_hash'], i['prevout_n']))
self.outputs.sort(key = lambda o: (o[2], self.pay_script(o[0], o[1])))
self._inputs.sort(key = lambda i: (i['prevout_hash'], i['prevout_n']))
self._outputs.sort(key = lambda o: (o[2], self.pay_script(o[0], o[1])))
def serialize(self, for_sig=None):
inputs = self.inputs
outputs = self.outputs
inputs = self.inputs()
outputs = self.outputs()
s = int_to_hex(1,4) # version
s += var_int( len(inputs) ) # number of inputs
for i, txin in enumerate(inputs):
@@ -685,21 +695,25 @@ class Transaction:
def hash(self):
return Hash(self.raw.decode('hex') )[::-1].encode('hex')
def add_input(self, input):
self.inputs.append(input)
def add_inputs(self, inputs):
self._inputs.extend(inputs)
self.raw = None
def add_outputs(self, outputs):
self._outputs.extend(outputs)
self.raw = None
def input_value(self):
return sum(x['value'] for x in self.inputs)
return sum(x['value'] for x in self.inputs())
def output_value(self):
return sum( val for tp,addr,val in self.outputs)
return sum( val for tp,addr,val in self.outputs())
def get_fee(self):
return self.input_value() - self.output_value()
def is_final(self):
return not any([x.get('sequence') < 0xffffffff - 1 for x in self.inputs])
return not any([x.get('sequence') < 0xffffffff - 1 for x in self.inputs()])
@classmethod
def fee_for_size(self, relay_fee, fee_per_kb, size):
@@ -727,7 +741,7 @@ class Transaction:
def signature_count(self):
r = 0
s = 0
for txin in self.inputs:
for txin in self.inputs():
if txin.get('is_coinbase'):
continue
signatures = filter(None, txin.get('signatures',[]))
@@ -741,14 +755,14 @@ class Transaction:
def inputs_without_script(self):
out = set()
for i, txin in enumerate(self.inputs):
for i, txin in enumerate(self.inputs()):
if txin.get('scriptSig') == '':
out.add(i)
return out
def inputs_to_sign(self):
out = set()
for txin in self.inputs:
for txin in self.inputs():
num_sig = txin.get('num_sig')
if num_sig is None:
continue
@@ -765,7 +779,7 @@ class Transaction:
return out
def sign(self, keypairs):
for i, txin in enumerate(self.inputs):
for i, txin in enumerate(self.inputs()):
num = txin['num_sig']
for x_pubkey in txin['x_pubkeys']:
signatures = filter(None, txin['signatures'])
@@ -775,14 +789,14 @@ class Transaction:
if x_pubkey in keypairs.keys():
print_error("adding signature for", x_pubkey)
# add pubkey to txin
txin = self.inputs[i]
txin = self._inputs[i]
x_pubkeys = txin['x_pubkeys']
ii = x_pubkeys.index(x_pubkey)
sec = keypairs[x_pubkey]
pubkey = public_key_from_private_key(sec)
txin['x_pubkeys'][ii] = pubkey
txin['pubkeys'][ii] = pubkey
self.inputs[i] = txin
self._inputs[i] = txin
# add signature
for_sig = Hash(self.tx_for_sig(i).decode('hex'))
pkey = regenerate_key(sec)
@@ -792,7 +806,7 @@ class Transaction:
sig = private_key.sign_digest_deterministic( for_sig, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der )
assert public_key.verify_digest( sig, for_sig, sigdecode = ecdsa.util.sigdecode_der)
txin['signatures'][ii] = sig.encode('hex')
self.inputs[i] = txin
self._inputs[i] = txin
print_error("is_complete", self.is_complete())
self.raw = self.serialize()
@@ -800,7 +814,7 @@ class Transaction:
def get_outputs(self):
"""convert pubkeys to addresses"""
o = []
for type, x, v in self.outputs:
for type, x, v in self.outputs():
if type == TYPE_ADDRESS:
addr = x
elif type == TYPE_PUBKEY:
@@ -815,7 +829,7 @@ class Transaction:
def has_address(self, addr):
return (addr in self.get_output_addresses()) or (addr in (tx.get("address") for tx in self.inputs))
return (addr in self.get_output_addresses()) or (addr in (tx.get("address") for tx in self.inputs()))
def as_dict(self):
if self.raw is None:
@@ -842,7 +856,7 @@ class Transaction:
# priority must be large enough for free tx
threshold = 57600000
weight = 0
for txin in self.inputs:
for txin in self.inputs():
age = wallet.get_confirmations(txin["prevout_hash"])[0]
weight += txin["value"] * age
priority = weight / size