Extend transaction serialization, format to handle unsigned inputs where only the address is known, the public key is unknown.
This commit is contained in:
@@ -332,9 +332,16 @@ def parse_xpub(x_pubkey):
|
||||
from account import OldAccount
|
||||
mpk, s = OldAccount.parse_xpubkey(x_pubkey)
|
||||
pubkey = OldAccount.get_pubkey_from_mpk(mpk.decode('hex'), s[0], s[1])
|
||||
elif x_pubkey[0:2] == 'fd':
|
||||
addrtype = ord(x_pubkey[2:4].decode('hex'))
|
||||
hash160 = x_pubkey[4:].decode('hex')
|
||||
pubkey = None
|
||||
address = hash_160_to_bc_address(hash160, addrtype)
|
||||
else:
|
||||
raise BaseException("Cannnot parse pubkey")
|
||||
return pubkey
|
||||
if pubkey:
|
||||
address = public_key_to_bc_address(pubkey.decode('hex'))
|
||||
return pubkey, address
|
||||
|
||||
|
||||
def parse_scriptSig(d, bytes):
|
||||
@@ -365,7 +372,7 @@ def parse_scriptSig(d, bytes):
|
||||
x_pubkey = decoded[1][1].encode('hex')
|
||||
try:
|
||||
signatures = parse_sig([sig])
|
||||
pubkey = parse_xpub(x_pubkey)
|
||||
pubkey, address = parse_xpub(x_pubkey)
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
@@ -375,7 +382,7 @@ def parse_scriptSig(d, bytes):
|
||||
d['x_pubkeys'] = [x_pubkey]
|
||||
d['num_sig'] = 1
|
||||
d['pubkeys'] = [pubkey]
|
||||
d['address'] = public_key_to_bc_address(pubkey.decode('hex'))
|
||||
d['address'] = address
|
||||
return
|
||||
|
||||
# p2sh transaction, 2 of n
|
||||
@@ -639,7 +646,11 @@ class Transaction:
|
||||
sig_list = ''.join( map( lambda x: push_script(x), sig_list))
|
||||
if not p2sh:
|
||||
script = sig_list
|
||||
script += push_script(pubkeys[0])
|
||||
x_pubkey = pubkeys[0]
|
||||
if x_pubkey is None:
|
||||
addrtype, h160 = bc_address_to_hash_160(txin['address'])
|
||||
x_pubkey = 'fd' + (chr(addrtype) + h160).encode('hex')
|
||||
script += push_script(x_pubkey)
|
||||
else:
|
||||
script = '00' # op_0
|
||||
script += sig_list
|
||||
@@ -673,16 +684,6 @@ class Transaction:
|
||||
def hash(self):
|
||||
return Hash(self.raw.decode('hex') )[::-1].encode('hex')
|
||||
|
||||
def add_signature(self, i, pubkey, sig):
|
||||
print_error("adding signature for", pubkey)
|
||||
txin = self.inputs[i]
|
||||
pubkeys = txin['pubkeys']
|
||||
ii = pubkeys.index(pubkey)
|
||||
txin['signatures'][ii] = sig
|
||||
txin['x_pubkeys'][ii] = pubkey
|
||||
self.inputs[i] = txin
|
||||
self.raw = self.serialize()
|
||||
|
||||
def add_input(self, input):
|
||||
self.inputs.append(input)
|
||||
self.raw = None
|
||||
@@ -707,66 +708,56 @@ class Transaction:
|
||||
r += txin['num_sig']
|
||||
return s, r
|
||||
|
||||
|
||||
def is_complete(self):
|
||||
s, r = self.signature_count()
|
||||
return r == s
|
||||
|
||||
|
||||
def inputs_to_sign(self):
|
||||
from account import BIP32_Account, OldAccount
|
||||
xpub_list = []
|
||||
addr_list = set()
|
||||
out = set()
|
||||
for txin in self.inputs:
|
||||
x_signatures = txin['signatures']
|
||||
signatures = filter(lambda x: x is not None, x_signatures)
|
||||
|
||||
if len(signatures) == txin['num_sig']:
|
||||
# input is complete
|
||||
continue
|
||||
|
||||
for k, x_pubkey in enumerate(txin['x_pubkeys']):
|
||||
|
||||
if x_signatures[k] is not None:
|
||||
# this pubkey already signed
|
||||
continue
|
||||
|
||||
if x_pubkey[0:2] == 'ff':
|
||||
xpub, sequence = BIP32_Account.parse_xpubkey(x_pubkey)
|
||||
xpub_list.append((xpub,sequence))
|
||||
elif x_pubkey[0:2] == 'fe':
|
||||
xpub, sequence = OldAccount.parse_xpubkey(x_pubkey)
|
||||
xpub_list.append((xpub,sequence))
|
||||
else:
|
||||
addr_list.add(txin['address'])
|
||||
|
||||
return addr_list, xpub_list
|
||||
|
||||
out.add(x_pubkey)
|
||||
return out
|
||||
|
||||
def sign(self, keypairs):
|
||||
print_error("tx.sign(), keypairs:", keypairs)
|
||||
|
||||
for i, txin in enumerate(self.inputs):
|
||||
|
||||
# continue if this txin is complete
|
||||
signatures = filter(lambda x: x is not None, txin['signatures'])
|
||||
num = txin['num_sig']
|
||||
if len(signatures) == num:
|
||||
# continue if this txin is complete
|
||||
continue
|
||||
|
||||
redeem_pubkeys = txin['pubkeys']
|
||||
for_sig = Hash(self.tx_for_sig(i).decode('hex'))
|
||||
for pubkey in redeem_pubkeys:
|
||||
if pubkey in keypairs.keys():
|
||||
for x_pubkey in txin['x_pubkeys']:
|
||||
if x_pubkey in keypairs.keys():
|
||||
print_error("adding signature for", x_pubkey)
|
||||
# add pubkey to txin
|
||||
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
|
||||
# add signature
|
||||
sec = keypairs[pubkey]
|
||||
for_sig = Hash(self.tx_for_sig(i).decode('hex'))
|
||||
pkey = regenerate_key(sec)
|
||||
secexp = pkey.secret
|
||||
private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
|
||||
public_key = private_key.get_verifying_key()
|
||||
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)
|
||||
self.add_signature(i, pubkey, sig.encode('hex'))
|
||||
txin['signatures'][ii] = sig.encode('hex')
|
||||
self.inputs[i] = txin
|
||||
|
||||
print_error("is_complete", self.is_complete())
|
||||
self.raw = self.serialize()
|
||||
|
||||
Reference in New Issue
Block a user