d['pubkeys'] = pubkeys
redeemScript = Transaction.multisig_script(pubkeys,2)
d['redeemScript'] = redeemScript
- d['address'] = hash_160_to_bc_address(hash_160(redeemScript.decode('hex')), 5)
+ d['address'] = hash_160_to_bc_address(hash_160(redeemScript.decode('hex')), 20)
# 65 BYTES:... CHECKSIG
match = [ opcodes.OP_PUSHDATA4, opcodes.OP_CHECKSIG ]
if match_decoded(decoded, match):
- return "pubkey:" + decoded[0][1].encode('hex')
+ return 'pubkey', decoded[0][1].encode('hex')
# Pay-by-Bitcoin-address TxOuts look like:
# DUP HASH160 20 BYTES:... EQUALVERIFY CHECKSIG
match = [ opcodes.OP_DUP, opcodes.OP_HASH160, opcodes.OP_PUSHDATA4, opcodes.OP_EQUALVERIFY, opcodes.OP_CHECKSIG ]
if match_decoded(decoded, match):
- return hash_160_to_bc_address(decoded[2][1])
+ return 'address', hash_160_to_bc_address(decoded[2][1])
# p2sh
match = [ opcodes.OP_HASH160, opcodes.OP_PUSHDATA4, opcodes.OP_EQUAL ]
if match_decoded(decoded, match):
- return hash_160_to_bc_address(decoded[1][1],5)
+ return 'address', hash_160_to_bc_address(decoded[1][1],20)
- return "(None)"
+ return "(None)", "(None)"
d = {}
d['value'] = vds.read_int64()
scriptPubKey = vds.read_bytes(vds.read_compact_size())
- address = get_address_from_output_script(scriptPubKey)
+ type, address = get_address_from_output_script(scriptPubKey)
+ d['type'] = type
d['address'] = address
d['scriptPubKey'] = scriptPubKey.encode('hex')
d['prevout_n'] = i
d = {}
start = vds.read_cursor
d['version'] = vds.read_int32()
+ d['timestamp'] = vds.read_int32()
n_vin = vds.read_compact_size()
d['inputs'] = []
for i in xrange(n_vin):
def __str__(self):
if self.raw is None:
- self.raw = self.serialize(self.inputs, self.outputs, for_sig = None) # for_sig=-1 means do not sign
+ self.raw = self.serialize(self.timestamp, self.inputs, self.outputs, for_sig = None) # for_sig=-1 means do not sign
return self.raw
- def __init__(self, inputs, outputs, locktime=0):
+ def __init__(self, timestamp, inputs, outputs, locktime=0):
+ self.timestamp = timestamp
self.inputs = inputs
self.outputs = outputs
self.locktime = locktime
@classmethod
def deserialize(klass, raw):
- self = klass([],[])
+ self = klass(0, [],[])
self.update(raw)
return self
def update(self, raw):
d = deserialize(raw)
self.raw = raw
+ self.timestamp = d['timestamp']
self.inputs = d['inputs']
- self.outputs = map(lambda x: (x['address'], x['value']), d['outputs'])
+ self.outputs = map(lambda x: (x['type'], x['address'], x['value']), d['outputs'])
self.locktime = d['lockTime']
-
@classmethod
def sweep(klass, privkeys, network, to_address, fee):
inputs = []
pubkey = public_key_from_private_key(privkey)
address = address_from_private_key(privkey)
u = network.synchronous_get([ ('blockchain.address.listunspent',[address])])[0]
- pay_script = klass.pay_script(address)
+ pay_script = klass.pay_script('address', address)
for item in u:
item['scriptPubKey'] = pay_script
item['redeemPubkey'] = pubkey
return
total = sum( map(lambda x:int(x.get('value')), inputs) ) - fee
- outputs = [(to_address, total)]
+ outputs = [('address', to_address, total)]
self = klass(inputs, outputs)
self.sign({ pubkey:privkey })
return self
@classmethod
- def pay_script(self, addr):
- if addr.startswith('OP_RETURN:'):
- h = addr[10:].encode('hex')
+ def pay_script(self, type, payto):
+ assert type == 'address' or type == 'pubkey' or type == 'op_return'
+
+ if type == 'op_return':
+ h = payto.encode('hex')
return '6a' + push_script(h)
- addrtype, hash_160 = bc_address_to_hash_160(addr)
- if addrtype == 0:
- script = '76a9' # op_dup, op_hash_160
- script += push_script(hash_160.encode('hex'))
- script += '88ac' # op_equalverify, op_checksig
- elif addrtype == 5:
- script = 'a9' # op_hash_160
- script += push_script(hash_160.encode('hex'))
- script += '87' # op_equal
+ elif type == 'pubkey':
+ script = push_script(payto)
+ script += 'ac' # op_checksig
+ return script
else:
- raise
- return script
+ addrtype, hash_160 = bc_address_to_hash_160(payto)
+ if addrtype == 8:
+ script = '76a9' # op_dup, op_hash_160
+ script += push_script(hash_160.encode('hex'))
+ script += '88ac' # op_equalverify, op_checksig
+ elif addrtype == 20:
+ script = 'a9' # op_hash_160
+ script += push_script(hash_160.encode('hex'))
+ script += '87' # op_equal
+ else:
+ raise
+ return script
@classmethod
- def serialize(klass, inputs, outputs, for_sig = None ):
-
+ def serialize(klass, timestamp, inputs, outputs, for_sig = None ):
s = int_to_hex(1,4) # version
+ s += int_to_hex(timestamp, 4) # timestamp
s += var_int( len(inputs) ) # number of inputs
for i in range(len(inputs)):
txin = inputs[i]
p2sh = txin.get('redeemScript') is not None
num_sig = txin['num_sig']
- address = txin['address']
+ payto = txin['address'] if txin["type"] == 'address' else txin['pubkeys'][0]
x_signatures = txin['signatures']
signatures = filter(lambda x: x is not None, x_signatures)
sig_list = ''.join( map( lambda x: push_script(x), sig_list))
if not p2sh:
script = sig_list
- script += push_script(pubkeys[0])
+ if txin["type"] != 'pubkey':
+ script += push_script(pubkeys[0])
else:
script = '00' # op_0
script += sig_list
script += push_script(redeem_script)
elif for_sig==i:
- script = txin['redeemScript'] if p2sh else klass.pay_script(address)
+ script = txin['redeemScript'] if p2sh else klass.pay_script(txin["type"], payto)
+ print script
else:
script = ''
s += var_int( len(script)/2 ) # script length
s += var_int( len(outputs) ) # number of outputs
for output in outputs:
- addr, amount = output
+ type, addr, amount = output
s += int_to_hex( amount, 8) # amount
- script = klass.pay_script(addr)
+ script = klass.pay_script(type, addr)
s += var_int( len(script)/2 ) # script length
s += script # script
s += int_to_hex(0,4) # lock time
def tx_for_sig(self,i):
- return self.serialize(self.inputs, self.outputs, for_sig = i)
+ return self.serialize(self.timestamp, self.inputs, self.outputs, for_sig = i)
def hash(self):
txin['signatures'][ii] = sig
txin['x_pubkeys'][ii] = pubkey
self.inputs[i] = txin
- self.raw = self.serialize(self.inputs, self.outputs)
+ self.raw = self.serialize(self.timestamp, self.inputs, self.outputs)
def signature_count(self):
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 )
+ sig = private_key.sign_digest_deterministic( for_sig, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der_canonize )
+
assert public_key.verify_digest( sig, for_sig, sigdecode = ecdsa.util.sigdecode_der)
self.add_signature(i, pubkey, sig.encode('hex'))
-
print_error("is_complete", self.is_complete())
- self.raw = self.serialize( self.inputs, self.outputs )
+ self.raw = self.serialize( self.timestamp, self.inputs, self.outputs )
def add_pubkey_addresses(self, txlist):
for i in self.inputs:
+ i["pubkey"] = False
if i.get("address") == "(pubkey)":
prev_tx = txlist.get(i.get('prevout_hash'))
if prev_tx:
- address, value = prev_tx.get_outputs()[i.get('prevout_n')]
+ type, address, value = prev_tx.get_outputs()[i.get('prevout_n')]
print_error("found pay-to-pubkey address:", address)
i["address"] = address
+ i["type"] = type
def get_outputs(self):
"""convert pubkeys to addresses"""
o = []
- for x, v in self.outputs:
- if bitcoin.is_address(x):
+ for type, x, v in self.outputs:
+ if type == 'address':
addr = x
- elif x.startswith('pubkey:'):
- addr = public_key_to_bc_address(x[7:].decode('hex'))
+ elif type == 'pubkey':
+ addr = public_key_to_bc_address(x.decode('hex'))
else:
addr = "(None)"
- o.append((addr,v))
+ o.append((type,addr,v))
+# print o
return o
def get_output_addresses(self):
- return map(lambda x:x[0], self.get_outputs())
+ return map(lambda x:x[1], self.get_outputs())
def has_address(self, addr):
if not is_send: is_partial = False
- for addr, value in self.get_outputs():
+ for type, addr, value in self.get_outputs():
v_out += value
if addr in addresses:
v_out_mine += value
def requires_fee(self, verifier):
- # see https://en.bitcoin.it/wiki/Transaction_fees
threshold = 57600000
size = len(self.raw)/2
- if size >= 10000:
+ if size >= 1000:
return True
- for o in self.outputs:
- value = o[1]
- if value < 1000000:
+ for o in self.get_outputs():
+ value = o[2]
+ if value < 10000:
return True
sum = 0
for i in self.inputs: