replace tx.input, tx.output by methods, so that deserialize calls are encapsulated
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user