def list_purchases(obj): txs, heights = obj['txs'], obj['heights'] o = [] for h in txs: txhex = str(txs[h]) # print txhex txouts = b.deserialize(txhex)['outs'] if len(txouts) >= 2 and txouts[0]['value'] >= minimum - 30000: addr = b.script_to_address(txouts[0]['script']) if addr == exodus: v = txouts[0]['value'] + 30000 ht = heights[h] # We care about the timestamp of the previous # confirmed block before a transaction t = get_block_header_data(ht - 1)['timestamp'] o.append({ "tx": h, "addr": b.b58check_to_hex(b.script_to_address( txouts[1]['script'])), "value": v, "time": t }) if len(o) % 50 == 0: sys.stderr.write('Gathered outputs: %d\n' % len(o)) return o
def add_tx_notify(self, txd, unconfirmfun, confirmfun, notifyaddr, timeoutfun=None): if not self.notifythread: self.notifythread = BitcoinCoreNotifyThread(self) self.notifythread.start() one_addr_imported = False for outs in txd['outs']: addr = btc.script_to_address(outs['script'], get_p2pk_vbyte()) if self.rpc('getaccount', [addr]) != '': one_addr_imported = True break if not one_addr_imported: self.rpc('importaddress', [notifyaddr, 'joinmarket-notify', False]) tx_output_set = set([(sv['script'], sv['value']) for sv in txd['outs']]) self.txnotify_fun.append( (tx_output_set, unconfirmfun, confirmfun, timeoutfun, False)) #create unconfirm timeout here, create confirm timeout in the other thread if timeoutfun: threading.Timer(jm_single().config.getint('TIMEOUT', 'unconfirm_timeout_sec'), bitcoincore_timeout_callback, args=(False, tx_output_set, self.txnotify_fun, timeoutfun)).start()
def add_tx_notify(self, txd, unconfirmfun, confirmfun, notifyaddr, timeoutfun=None): if not self.notifythread: self.notifythread = BitcoinCoreNotifyThread(self) self.notifythread.start() one_addr_imported = False for outs in txd['outs']: addr = btc.script_to_address(outs['script'], get_p2pk_vbyte()) if self.rpc('getaccount', [addr]) != '': one_addr_imported = True break if not one_addr_imported: self.rpc('importaddress', [notifyaddr, 'joinmarket-notify', False]) tx_output_set = set([(sv['script'], sv['value']) for sv in txd['outs']]) self.txnotify_fun.append((tx_output_set, unconfirmfun, confirmfun, timeoutfun, False)) #create unconfirm timeout here, create confirm timeout in the other thread if timeoutfun: threading.Timer(jm_single().config.getint('TIMEOUT', 'unconfirm_timeout_sec'), bitcoincore_timeout_callback, args=(False, tx_output_set, self.txnotify_fun, timeoutfun)).start()
def on_tx_confirmed(self, cjorder, confirmations, txid): to_announce = [] for i, out in enumerate(cjorder.tx['outs']): addr = btc.script_to_address(out['script'], get_p2pk_vbyte()) if addr == cjorder.change_addr: neworder = { 'oid': self.get_next_oid(), 'ordertype': 'absorder', 'minsize': 12000, 'maxsize': out['value'], 'txfee': 10000, 'cjfee': 100000, 'utxo': txid + ':' + str(i) } to_announce.append(neworder) if addr == cjorder.cj_addr: neworder = { 'oid': self.get_next_oid(), 'ordertype': 'absorder', 'minsize': 12000, 'maxsize': out['value'], 'txfee': 10000, 'cjfee': 100000, 'utxo': txid + ':' + str(i) } to_announce.append(neworder) return [], to_announce
def takeUtxo(utxo, privs, bch_inputs, skip_if_blank=False): """ Take UTXO for spending and update the input arrays and private key set for later signing. """ intxhsh = utxo.txhash log.info("Looking at UTXO %s.", utxo) if "BCH_" + intxhsh not in tokenval.db: log.info("Input transaction missing for UTXO %s.", utxo) return None, None intx = tokenval.db["BCH_" + intxhsh] bch_prevout = intx.decoded["outs"][utxo.outnum] bch_prevout_addr = bitcoin.script_to_address(bch_prevout["script"]) priv = tokenval.privKey(bch_prevout_addr) if priv is None: log.info("Private key not available for unspent output %s.", utxo) return None, None log.info("Taking unspent output %s.", utxo) if not skip_if_blank or utxo.value is not None: privoutpoint = utxo.txhash + ":" + str(utxo.outnum) privs[privoutpoint] = priv bch_inputs.append({"output": privoutpoint, "amount": utxo.bch_value}) return utxo.value, utxo.bch_value
def getBalances(): """ Available (spendable) balances for all tokens. FIXME: super inefficient...""" addr2tokenid = {} for key in db: if key.startswith("TOKEN_"): rt = db[key] addr2tokenid[rt.addr] = rt.tokenid balances = {} outputs = allUnspentOutputs() for out in outputs: if out.token_addr not in addr2tokenid: continue tokenid = addr2tokenid[out.token_addr] if "BCH_" + out.txhash not in db: continue tx = db["BCH_" + out.txhash] spend_addr = bitcoin.script_to_address( tx.decoded["outs"][out.outnum]["script"]) if privKey(spend_addr) is None: if tokenid not in balances: balances[tokenid] = 0 continue value = 0 if out.value is None else out.value if tokenid in balances: balances[tokenid] += value else: balances[tokenid] = value return balances
def list_purchases(obj): txs, heights = obj['txs'], obj['heights'] o = [] for h in txs: txhex = str(txs[h]) # print txhex txouts = b.deserialize(txhex)['outs'] if len(txouts) >= 2: addr = b.script_to_address(txouts[0]['script']) if addr == exodus: v = txouts[0][ 'value'] + 10000 # add 0.1 millibit for the fees paid transfering from koinify wallet to Factom multisig ht = heights[h] # We care about the timestamp of the previous # confirmed block before a transaction t = get_block_header_data(ht - 1)['timestamp'] o.append({ "tx": h, "addr": extract_pubkey(txouts[1]['script']), "value": v, "time": t }) if len(o) % 50 == 0: sys.stderr.write('Gathered outputs: %d\n' % len(o)) return o
def list_purchases(obj): txs, heights = obj['txs'], obj['heights'] process_queue = [] for h in txs: txhex = str(txs[h]) txouts = b.deserialize(txhex)['outs'] if len(txouts) >= 2 and txouts[0]['value'] >= minimum - 30000: addr = b.script_to_address(txouts[0]['script']) if addr == exodus: v = txouts[0]['value'] + 30000 process_queue.append({ "tx": h, "addr": b.b58check_to_hex(b.script_to_address( txouts[1]['script'])), "value": v, "height": heights[h] }) else: sys.stderr.write( "Non-purchase tx found (not to exodus): %s\n" % h) elif len(txouts) == 1: sys.stderr.write("Non-purchase tx found (single output): %s\n" % h) else: sys.stderr.write( "Non-purchase tx found (insufficient value): %s\n" % h) sys.stderr.write('Gathered outputs, collecting block timestamps\n') # Determine the timestamp for every block height. We care about # the timestamp of the previous confirmed block before a transaction. # Save the results as a dictionary of transaction data o = [] for i in range(0, len(process_queue), 20): subpq = process_queue[i:i + 20] t = get_block_timestamp([x['height'] - 1 for x in subpq]) assert len(t) == len(subpq), [x['height'] - 1 for x in subpq] o.extend([{ "tx": _a["tx"], "addr": _a["addr"], "value": _a["value"], "time": _b } for _a, _b in zip(subpq, t)]) sys.stderr.write('Collected timestamps: %d\n' % len(o)) return o
def get_pubkey_derivation(self, x_pubkey): if x_pubkey[0:2] in ['02', '03', '04']: if x_pubkey in self.keypairs.keys(): return x_pubkey elif x_pubkey[0:2] == 'fd': addr = bitcoin.script_to_address(x_pubkey[2:]) if addr in self.addresses: return self.addresses[addr].get('pubkey')
def __init__(self, blockr_domain, txd, unconfirmfun, confirmfun): threading.Thread.__init__(self) self.daemon = True self.blockr_domain = blockr_domain self.unconfirmfun = unconfirmfun self.confirmfun = confirmfun self.tx_output_set = set([(sv['script'], sv['value']) for sv in txd['outs']]) self.output_addresses = [btc.script_to_address(scrval[0], common.get_p2pk_vbyte()) for scrval in self.tx_output_set] common.debug('txoutset=' + pprint.pformat(self.tx_output_set)) common.debug('outaddrs=' + ','.join(self.output_addresses))
def add_new_utxos(self, tx, txid): added_utxos = {} for index, outs in enumerate(tx["outs"]): addr = btc.script_to_address(outs["script"], get_addr_vbyte()) if addr not in self.addr_cache: continue addrdict = {"address": addr, "value": outs["value"]} utxo = txid + ":" + str(index) added_utxos[utxo] = addrdict self.unspent[utxo] = addrdict debug("added utxos, wallet now is \n" + pprint.pformat(self.get_utxos_by_mixdepth())) return added_utxos
def add_new_utxos(self, tx, txid): added_utxos = {} for index, outs in enumerate(tx['outs']): addr = btc.script_to_address(outs['script'], get_addr_vbyte()) if addr not in self.addr_cache: continue addrdict = {'address': addr, 'value': outs['value']} utxo = txid + ':' + str(index) added_utxos[utxo] = addrdict self.unspent[utxo] = addrdict debug('added utxos, wallet now is \n' + pprint.pformat(self.get_utxos_by_mixdepth())) return added_utxos
def add_new_utxos(self, tx, txid): added_utxos = {} for index, outs in enumerate(tx['outs']): addr = btc.script_to_address(outs['script'], get_p2pk_vbyte()) if addr not in self.addr_cache: continue addrdict = {'address': addr, 'value': outs['value']} utxo = txid + ':' + str(index) added_utxos[utxo] = addrdict self.unspent[utxo] = addrdict debug('added utxos, wallet now is \n' + pprint.pformat(self.get_utxos_by_mixdepth())) return added_utxos
def list_purchases(obj): txs, heights = obj['txs'], obj['heights'] process_queue = [] for h in txs: txhex = str(txs[h]) txouts = b.deserialize(txhex)['outs'] if len(txouts) >= 2 and txouts[0]['value'] >= minimum - 30000: addr = b.script_to_address(txouts[0]['script']) if addr == exodus: v = txouts[0]['value'] + 30000 process_queue.append({ "tx": h, "addr": b.b58check_to_hex(b.script_to_address( txouts[1]['script'])), "value": v, "height": heights[h] }) else: sys.stderr.write("Non-purchase tx found (not to exodus): %s\n" % h) elif len(txouts) == 1: sys.stderr.write("Non-purchase tx found (single output): %s\n" % h) else: sys.stderr.write("Non-purchase tx found (insufficient value): %s\n" % h) sys.stderr.write('Gathered outputs, collecting block timestamps\n') # Determine the timestamp for every block height. We care about # the timestamp of the previous confirmed block before a transaction. # Save the results as a dictionary of transaction data o = [] for i in range(0, len(process_queue), 20): subpq = process_queue[i:i+20] t = get_block_timestamp([x['height'] - 1 for x in subpq]) assert len(t) == len(subpq), [x['height'] - 1 for x in subpq] o.extend([{ "tx": _a["tx"], "addr": _a["addr"], "value": _a["value"], "time": _b } for _a, _b in zip(subpq, t)]) sys.stderr.write('Collected timestamps: %d\n' % len(o)) return o
def add_tx_notify(self, txd, unconfirmfun, confirmfun, notifyaddr): if not self.notifythread: self.notifythread = BitcoinCoreNotifyThread(self) self.notifythread.start() one_addr_imported = False for outs in txd['outs']: addr = btc.script_to_address(outs['script'], get_p2pk_vbyte()) if self.rpc('getaccount', [addr]) != '': one_addr_imported = True break if not one_addr_imported: self.rpc('importaddress', [notifyaddr, 'joinmarket-notify', False]) tx_output_set = set([(sv['script'], sv['value']) for sv in txd['outs']]) self.txnotify_fun.append((tx_output_set, unconfirmfun, confirmfun))
def add_tx_notify(self, txd, unconfirmfun, confirmfun, notifyaddr): if not self.notifythread: self.notifythread = BitcoinCoreNotifyThread(self) self.notifythread.start() one_addr_imported = False for outs in txd['outs']: addr = btc.script_to_address(outs['script'], common.get_p2pk_vbyte()) if self.rpc('getaccount', [addr]) != '': one_addr_imported = True break if not one_addr_imported: self.rpc('importaddress', [notifyaddr, 'joinmarket-notify', False]) tx_output_set = set([(sv['script'], sv['value']) for sv in txd['outs']]) self.txnotify_fun.append((tx_output_set, unconfirmfun, confirmfun))
def script_hex_to_address( script_hex ): """ Examine a scriptPubkey and extract an address. """ if script_hex.startswith("76a914") and script_hex.endswith("88ac") and len(script_hex) == 50: # p2pkh script return pybitcoin.script_hex_to_address( script_hex, version_byte=version_byte ) elif script_hex.startswith("a914") and script_hex.endswith("87") and len(script_hex) == 46: # p2sh script return bitcoin.script_to_address( script_hex, vbyte=multisig_version_byte ) else: raise ValueError("Nonstandard script %s" % script_hex)
def on_tx_confirmed(self, cjorder, confirmations, txid): to_announce = [] for i, out in enumerate(cjorder.tx['outs']): addr = btc.script_to_address(out['script'], get_addr_vbyte()) if addr == cjorder.change_addr: neworder = {'oid': self.get_next_oid(), 'ordertype': 'absorder', 'minsize': 12000, 'maxsize': out['value'], 'txfee': 10000, 'cjfee': 100000, 'utxo': txid + ':' + str(i)} to_announce.append(neworder) if addr == cjorder.cj_addr: neworder = {'oid': self.get_next_oid(), 'ordertype': 'absorder', 'minsize': 12000, 'maxsize': out['value'], 'txfee': 10000, 'cjfee': 100000, 'utxo': txid + ':' + str(i)} to_announce.append(neworder) return ([], to_announce)
def verify_unsigned_tx(self, txd): tx_utxo_set = set(ins['outpoint']['hash'] + ':' + str( ins['outpoint']['index']) for ins in txd['ins']) # complete authentication: check the tx input uses the authing pubkey input_utxo_data = jm_single().bc_interface.query_utxo_set( list(tx_utxo_set)) if None in input_utxo_data: return False, 'some utxos already spent or not confirmed yet' input_addresses = [u['address'] for u in input_utxo_data] if btc.pubtoaddr( self.i_utxo_pubkey, get_p2pk_vbyte()) not in input_addresses: return False, "authenticating bitcoin address is not contained" my_utxo_set = set(self.utxos.keys()) if not tx_utxo_set.issuperset(my_utxo_set): return False, 'my utxos are not contained' my_total_in = sum([va['value'] for va in self.utxos.values()]) self.real_cjfee = calc_cj_fee( self.ordertype, self.cjfee, self.cj_amount) expected_change_value = ( my_total_in - self.cj_amount - self.txfee + self.real_cjfee) log.debug('potentially earned = {}'.format( self.real_cjfee - self.txfee)) log.debug('mycjaddr, mychange = {}, {}'.format( self.cj_addr, self.change_addr)) times_seen_cj_addr = 0 times_seen_change_addr = 0 for outs in txd['outs']: addr = btc.script_to_address(outs['script'], get_p2pk_vbyte()) if addr == self.cj_addr: times_seen_cj_addr += 1 if outs['value'] != self.cj_amount: return False, 'Wrong cj_amount. I expect ' + str( self.cj_amount) if addr == self.change_addr: times_seen_change_addr += 1 if outs['value'] != expected_change_value: return False, 'wrong change, i expect ' + str( expected_change_value) if times_seen_cj_addr != 1 or times_seen_change_addr != 1: fmt = ('cj or change addr not in tx ' 'outputs once, #cjaddr={}, #chaddr={}').format return False, (fmt(times_seen_cj_addr, times_seen_change_addr)) return True, None
def verify_unsigned_tx(self, txd): tx_utxo_set = set(ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) for ins in txd['ins']) # complete authentication: check the tx input uses the authing pubkey input_utxo_data = jm_single().bc_interface.query_utxo_set( list(tx_utxo_set)) if None in input_utxo_data: return False, 'some utxos already spent or not confirmed yet' input_addresses = [u['address'] for u in input_utxo_data] if btc.pubtoaddr(self.i_utxo_pubkey, get_p2pk_vbyte()) not in input_addresses: return False, "authenticating bitcoin address is not contained" my_utxo_set = set(self.utxos.keys()) if not tx_utxo_set.issuperset(my_utxo_set): return False, 'my utxos are not contained' my_total_in = sum([va['value'] for va in self.utxos.values()]) self.real_cjfee = calc_cj_fee(self.ordertype, self.cjfee, self.cj_amount) expected_change_value = (my_total_in - self.cj_amount - self.txfee + self.real_cjfee) log.debug('potentially earned = {}'.format(self.real_cjfee - self.txfee)) log.debug('mycjaddr, mychange = {}, {}'.format(self.cj_addr, self.change_addr)) times_seen_cj_addr = 0 times_seen_change_addr = 0 for outs in txd['outs']: addr = btc.script_to_address(outs['script'], get_p2pk_vbyte()) if addr == self.cj_addr: times_seen_cj_addr += 1 if outs['value'] != self.cj_amount: return False, 'Wrong cj_amount. I expect ' + str( self.cj_amount) if addr == self.change_addr: times_seen_change_addr += 1 if outs['value'] != expected_change_value: return False, 'wrong change, i expect ' + str( expected_change_value) if times_seen_cj_addr != 1 or times_seen_change_addr != 1: fmt = ('cj or change addr not in tx ' 'outputs once, #cjaddr={}, #chaddr={}').format return False, (fmt(times_seen_cj_addr, times_seen_change_addr)) return True, None
def xpubkey_to_address(x_pubkey): if x_pubkey[0:2] == 'fd': address = bitcoin.script_to_address(x_pubkey[2:]) return x_pubkey, address if x_pubkey[0:2] in ['02', '03', '04']: pubkey = x_pubkey elif x_pubkey[0:2] == 'ff': xpub, s = BIP32_KeyStore.parse_xpubkey(x_pubkey) pubkey = BIP32_KeyStore.get_pubkey_from_xpub(xpub, s) elif x_pubkey[0:2] == 'fe': mpk, s = Old_KeyStore.parse_xpubkey(x_pubkey) pubkey = Old_KeyStore.get_pubkey_from_mpk(mpk, s[0], s[1]) else: raise BitcoinException("Cannot parse pubkey. prefix: {}".format( x_pubkey[0:2])) if pubkey: address = public_key_to_p2pkh(bfh(pubkey)) return pubkey, address
def script_hex_address(script_hex): """ Examine a scriptPubkey and extract an address """ if script_hex.startswith("76a914") and script_hex.endswith("88ac") and len( script_hex) == 50: # p2pkh script return pybitcoin.script_hex_to_address(script_hex, version_byte=version_byte) elif script_hex.startswith("a914") and script_hex.endswith("87") and len( script_hex) == 46: # p2sh script return bitcoin.script_to_address(script_hex, vbyte=multisig_version_byte) else: raise ValueError("Nonstandard script %s" % script_hex)
def verify_unsigned_tx(self, txd): tx_utxo_set = set([ins['outpoint']['hash'] + ':' \ + str(ins['outpoint']['index']) for ins in txd['ins']]) #complete authentication: check the tx input uses the authing pubkey input_utxo_data = common.bc_interface.query_utxo_set(list(tx_utxo_set)) input_addresses = [u['address'] for u in input_utxo_data] if btc.pubtoaddr(self.i_utxo_pubkey, get_addr_vbyte())\ not in input_addresses: return False, "authenticating bitcoin address is not contained" my_utxo_set = set(self.utxos.keys()) wallet_utxos = set(self.maker.wallet.unspent) if not tx_utxo_set.issuperset(my_utxo_set): return False, 'my utxos are not contained' if not wallet_utxos.issuperset(my_utxo_set): return False, 'my utxos already spent' my_total_in = sum([va['value'] for va in self.utxos.values()]) self.real_cjfee = calc_cj_fee(self.ordertype, self.cjfee, self.cj_amount) expected_change_value = (my_total_in - self.cj_amount - self.txfee + self.real_cjfee) debug('earned = ' + str(self.real_cjfee - self.txfee)) debug('mycjaddr, mychange = ' + self.cj_addr + ', ' + self.change_addr) times_seen_cj_addr = 0 times_seen_change_addr = 0 for outs in txd['outs']: addr = btc.script_to_address(outs['script'], get_addr_vbyte()) if addr == self.cj_addr: times_seen_cj_addr += 1 if outs['value'] != self.cj_amount: return False, 'Wrong cj_amount. I expect ' + str(cj_amount) if addr == self.change_addr: times_seen_change_addr += 1 if outs['value'] != expected_change_value: return False, 'wrong change, i expect ' + str( expected_change_value) if times_seen_cj_addr != 1 or times_seen_change_addr != 1: return False, ( 'cj or change addr not in tx outputs once, #cjaddr=' + str(times_seen_cj_addr) + ', #chaddr=' + str(times_seen_change_addr)) return True, None
def test_script_to_address(self): scripts = { '00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262': [ 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7', 196, False ], '00202a11fadf4a96c60669ae50b2ac7c0b3cae0b3d94483670504dc154a255826322': [ 'bcrt1q9ggl4h62jmrqv6dw2ze2clqt8jhqk0v5fqm8q5zdc922y4vzvv3qj3le86', 196, True ], '00142a3af484ba735f3de4535f0fd522d4666646ef3f': ['bcrt1q9ga0fp96wd0nmezntu8a2gk5venydmelf8ddtm', 111, True], '00143262354a6825b39de7f35534ddb04f45ea7a1f43': ['bc1qxf3r2jngykeemeln256dmvz0gh48586rfx4j2p', 0, False] } for s, a in scripts.items(): self.assertEqual(a[0], bitcoin.script_to_address(s, a[1], regtest=a[2]))
def main(): path = "blk0000" blockFilename = 'blk00001.dat' with open(blockFilename, 'rb') as blockFile: for block in range(0, 10): readBlock(blockFile) """len = os.stat(blockFilename).st_size print(len) with open(blockFilename, 'rb') as blockFile: while blockFile.tell() != len: readBlock(blockFile)""" for transaction in transactions: for input in inputs: if transaction.getHash() == input.getPreviousHash(): for output in transaction.getOutputs(): print( str(output.getIndex()) + " = " + str(input.getOutId())) if int(output.getIndex()) == int(input.getOutId()): print("TROVATO!") print(transaction.toString()) print(input.toString() + "\nhash della transazione dell'input: " + input.getHashTransaction() + "\n") print("\n ******** \n\n") print(output.toString()) print(input.toString()) input.setHashTransaction(output.getAddress()) with open("block01.json", "w") as outfile: transactionJSONData = json.dumps(transactions, indent=4, cls=TransactionEncoder) outfile.write(transactionJSONData) print( bitcoin.script_to_address( '4104c8f8fd8d4c0f56cc7b9e974c29875e893131144847ab56dcf0cb8c223f04a8e31e2ff7a7ac8626270077c2158bf0a898c2d595112e2c157b2e7177c136f7ae42ac' ))
def verify_unsigned_tx(self, txd): tx_utxo_set = set([ins['outpoint']['hash'] + ':' \ + str(ins['outpoint']['index']) for ins in txd['ins']]) #complete authentication: check the tx input uses the authing pubkey input_utxo_data = common.bc_interface.query_utxo_set(list(tx_utxo_set)) input_addresses = [u['address'] for u in input_utxo_data] if btc.pubtoaddr(self.i_utxo_pubkey, get_addr_vbyte())\ not in input_addresses: return False, "authenticating bitcoin address is not contained" my_utxo_set = set(self.utxos.keys()) wallet_utxos = set(self.maker.wallet.unspent) if not tx_utxo_set.issuperset(my_utxo_set): return False, 'my utxos are not contained' if not wallet_utxos.issuperset(my_utxo_set): return False, 'my utxos already spent' my_total_in = sum([va['value'] for va in self.utxos.values()]) self.real_cjfee = calc_cj_fee(self.ordertype, self.cjfee, self.cj_amount) expected_change_value = (my_total_in - self.cj_amount - self.txfee + self.real_cjfee) debug('earned = ' + str(self.real_cjfee - self.txfee)) debug('mycjaddr, mychange = ' + self.cj_addr + ', ' + self.change_addr) times_seen_cj_addr = 0 times_seen_change_addr = 0 for outs in txd['outs']: addr = btc.script_to_address(outs['script'], get_addr_vbyte()) if addr == self.cj_addr: times_seen_cj_addr += 1 if outs['value'] != self.cj_amount: return False, 'Wrong cj_amount. I expect ' + str(cj_amount) if addr == self.change_addr: times_seen_change_addr += 1 if outs['value'] != expected_change_value: return False, 'wrong change, i expect ' + str(expected_change_value) if times_seen_cj_addr != 1 or times_seen_change_addr != 1: return False, ('cj or change addr not in tx outputs once, #cjaddr=' + str(times_seen_cj_addr) + ', #chaddr=' + str(times_seen_change_addr)) return True, None
def verify_unsigned_tx(self, txd): tx_utxo_set = set(ins['outpoint']['hash'] + ':' + str( ins['outpoint']['index']) for ins in txd['ins']) my_utxo_set = set(self.utxos.keys()) if not tx_utxo_set.issuperset(my_utxo_set): return False, 'my utxos are not contained' my_total_in = sum([va['value'] for va in self.utxos.values()]) self.real_cjfee = calc_cj_fee( self.ordertype, self.cjfee, self.cj_amount) expected_change_value = ( my_total_in - self.cj_amount - self.txfee + self.real_cjfee) log.info('potentially earned = {}'.format( self.real_cjfee - self.txfee)) log.debug('mycjaddr, mychange = {}, {}'.format( self.cj_addr, self.change_addr)) times_seen_cj_addr = 0 times_seen_change_addr = 0 for outs in txd['outs']: addr = btc.script_to_address(outs['script'], get_p2pk_vbyte()) if addr == self.cj_addr: times_seen_cj_addr += 1 if outs['value'] != self.cj_amount: return False, 'Wrong cj_amount. I expect ' + str( self.cj_amount) if addr == self.change_addr: times_seen_change_addr += 1 if outs['value'] != expected_change_value: return False, 'wrong change, i expect ' + str( expected_change_value) if times_seen_cj_addr != 1 or times_seen_change_addr != 1: fmt = ('cj or change addr not in tx ' 'outputs once, #cjaddr={}, #chaddr={}').format return False, (fmt(times_seen_cj_addr, times_seen_change_addr)) return True, None
def verify_unsigned_tx(self, txd): tx_utxo_set = set(ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) for ins in txd['ins']) my_utxo_set = set(self.utxos.keys()) if not tx_utxo_set.issuperset(my_utxo_set): return False, 'my utxos are not contained' my_total_in = sum([va['value'] for va in self.utxos.values()]) self.real_cjfee = calc_cj_fee(self.ordertype, self.cjfee, self.cj_amount) expected_change_value = (my_total_in - self.cj_amount - self.txfee + self.real_cjfee) log.debug('potentially earned = {}'.format(self.real_cjfee - self.txfee)) log.debug('mycjaddr, mychange = {}, {}'.format(self.cj_addr, self.change_addr)) times_seen_cj_addr = 0 times_seen_change_addr = 0 for outs in txd['outs']: addr = btc.script_to_address(outs['script'], get_p2pk_vbyte()) if addr == self.cj_addr: times_seen_cj_addr += 1 if outs['value'] != self.cj_amount: return False, 'Wrong cj_amount. I expect ' + str( self.cj_amount) if addr == self.change_addr: times_seen_change_addr += 1 if outs['value'] != expected_change_value: return False, 'wrong change, i expect ' + str( expected_change_value) if times_seen_cj_addr != 1 or times_seen_change_addr != 1: fmt = ('cj or change addr not in tx ' 'outputs once, #cjaddr={}, #chaddr={}').format return False, (fmt(times_seen_cj_addr, times_seen_change_addr)) return True, None
def list_purchases(obj): txs, heights = obj['txs'], obj['heights'] o = [] for h in txs: txhex = str(txs[h]) # print txhex txouts = b.deserialize(txhex)['outs'] if len(txouts) >= 2: addr = b.script_to_address(txouts[0]['script']) if addr == exodus: v = txouts[0]['value'] + 10000 # add 0.1 millibit for the fees paid transfering from koinify wallet to Factom multisig ht = heights[h] # We care about the timestamp of the previous # confirmed block before a transaction t = get_block_header_data(ht - 1)['timestamp'] o.append({ "tx": h, "addr": extract_pubkey(txouts[1]['script']), "value": v, "time": t }) if len(o) % 50 == 0: sys.stderr.write('Gathered outputs: %d\n' % len(o)) return o
def validate(recovery_package): package_out = 0 total_out = 0 total_in = 0 total_fee = 0 raw_txs = recovery_package['txs'] print "Validating %d transactions" % len(raw_txs) for tx_index, tx_raw in enumerate(raw_txs): print "\nTransaction #", tx_index tx = bitcoin.transaction.deserialize(unhexlify(tx_raw['bytes'])) tx_out = 0 tx_in = 0 tx_fee = 0 for inp in tx['ins']: tx_hash = inp['outpoint']['hash'] vout = inp['outpoint']['index'] print "\tInput", hexlify(tx_hash) + ":" + str(vout) try: intx_hex = bitcoin.fetchtx(tx_hash) intx = bitcoin.transaction.deserialize(unhexlify(intx_hex)) prev_out = intx['outs'][vout] print "\t paying " + value_print( prev_out['value']), "to", bitcoin.script_to_address( prev_out['script']) tx_in += prev_out['value'] except: print "Exception in input retrieval - skipping online validation" pass for outp in tx['outs']: print "\tOutput paying " + value_print( outp['value']), "to", bitcoin.script_to_address(outp['script']) tx_out += outp['value'] print "\n-------------------------------" if tx_in > 0: print "- Total in " + value_print(tx_in) total_in += tx_in print "- Total out" + value_print(tx_out) total_out += tx_out if total_in > 0: tx_fee = tx_in - tx_out total_fee += tx_fee print "- Total fee" + value_print(tx_fee) tx_size = len(tx_raw['bytes']) / 4 feePerByte = tx_fee / tx_size print "- Tx size", tx_size, "bytes" print "- Fee per byte", feePerByte, "satoshi" if feePerByte > 100: print "WARNING - Excessive fee per byte", feePerByte if total_fee > 150000: print "WARNING - Unusually large fee", value_print(total_fee) if total_fee > (total_out / 100): raise Exception("ERROR - Fee exceeds 1% of Tx" + value_print(total_fee)) # check total outputs match expected amount print "\n\n==================================================" if total_in > 0: print "Total inputs for all transactions", value_print(total_in) print "Total outputs for all transactions", value_print(total_out) if total_in > 0: print "Total fees for all transactions", value_print(total_fee) if total_out == recovery_package['header']['total_out']: print "\n\nTotal outputs for all transactions match the recovery package header" else: raise Exception( "Total outputs for all transactions do not match the recovery package header" )
def processOnchain(txn): if txn.handle in db: log.warning("Have seen and processed on chain transaction %s already.", txn.handle) return # find and extract OP_RETURN data if available opreturn_data = None for output in txn.decoded["outs"]: assert ("script" in output) if output["script"].startswith("6a"): # OP_RETURN? opreturn_data = output["script"][4:] # skip length byte if opreturn_data is None: # transactions without OP_RETURN data are of interest for # their BCH outputs (to fill up miner fees) # and the potential tokens that can be created from these outputs. log.info( "Assuming transaction %s is generating transaction or meant for extra BCH fee input", txn.handle) for n, output in enumerate(txn.decoded["outs"]): script = output["script"] out_addr = bitcoin.script_to_address(script) log.info("Generating unspent blank output %s:%s:%d:%d", out_addr, txn.hsh, n, output["value"]) key = "UNSPENT_" + txn.hsh + ("_%d" % n) if key in db: log.error("Internal error, outpoint already in DB.") return db[key] = UnspentOutput(out_addr, txn.hsh, n, output["value"], None) # ok, transaction is coming in order, add to DB and be done db[txn.handle] = txn return if len(opreturn_data) != 64: # a single SHA256 hash is expected log.error("Transaction %s does not contain valid OP_RETURN data.", txn.handle) return tok_handle = "TOK_" + opreturn_data # handle to look for in DB if tok_handle not in db: log.error( "Transaction %s contains unknown OP_RETURN data. Please import token transaction first.", txn.handle) return toktxn = db[tok_handle] # check that the addresses for the signatures on the token transaction matching the signatures for the inputs of # the BCH transaction tok_addrs = set(toktxn.signed_addresses) bch_addrs = set() for inp in txn.decoded["ins"]: point = inp["outpoint"] txhsh, outnum = point["hash"], point["index"] if "BCH_" + txhsh not in db: log.error("Missing BCH transaction input %s:%d.", txhsh, outnum) return else: out = db["BCH_" + txhsh].decoded["outs"][outnum] addr = bitcoin.script_to_address(out["script"]) bch_addrs.add(addr) if tok_addrs != bch_addrs: log.error( "Signatures for BCH transaction %s mismatch those for the token transaction %s.", txn.handle, toktxn.handle) log.error("Signed addresses for token transaction: %s", repr(tok_addrs)) log.error("Signed addresses for BCH transaction: %s", repr(bch_addrs)) return if len(toktxn.outputs) != len(txn.decoded["outs"]) - 1: log.error( "Token transaction needs to have the same number of outputs as the BCH transaction minus one (for OP_RETURN)." ) log.error("Token outputs: %s", repr(toktxn.outputs)) log.error("BCH outputs: %s", repr(txn.decoded["outs"])) return # calculate input values, taking minted tokens with CREATE into account valuesum = 0 for mint in toktxn.mints: chainprevtxid, chainprevout, value = mint key = "UNSPENT_" + chainprevtxid + ("_%d" % chainprevout) if key not in db: log.error("Unspent output %s:%d referenced in create not in DB.\n", chainprevtxid, chainprevout) return utxo = db[key] if utxo.value is not None: log.error( "Trying to create a token from non-blank output %s:%d.\n", chainprevtxid, chainprevout) return if utxo.token_addr != toktxn.token_addr: log.error( "Trying to create a token from blank output with wrong address %s:%d\n", chainprevtxid, chainprevout) return if value < 0: log.error("Trying to create negative number of tokens.\n") return valuesum += value log.info("Adding mint value %d, total %d", value, valuesum) for inp in txn.decoded["ins"]: txid = inp["outpoint"]["hash"] outnum = inp["outpoint"]["index"] key = "UNSPENT_" + txid + ("_%d" % outnum) if key not in db: log.error("Missing unspent output %s:%d.", txid, outnum) return utxo = db[key] if utxo.value is not None: if utxo.token_addr != toktxn.token_addr: log.error("Input token address mismatch %s vs. %s.", utxo.token_addr, toktxn.token_addr) return valuesum += utxo.value log.info("Adding input value %d, total %d", utxo.value, valuesum) for value in toktxn.outputs: valuesum -= value log.info("Subtracting output value %d, total %d", value, valuesum) if valuesum < 0: log.error("Transaction %s trying to overspend.", toktxn.handle) return for value in toktxn.outputs: if value < 0: log.error("Trying to create negative output") return # consume inputs, for inp in txn.decoded["ins"]: txid = inp["outpoint"]["hash"] outnum = inp["outpoint"]["index"] key = "UNSPENT_" + txid + ("_%d" % outnum) del db[key] # create outputs for n, value in enumerate(toktxn.outputs): key = "UNSPENT_" + txn.hsh + ("_%d" % n) if key in db: log.error("Internal error, output exists.") return out = txn.decoded["outs"][n] script = out["script"] addr = bitcoin.script_to_address(script) if value > 0: db[key] = UnspentOutput(toktxn.token_addr, txn.hsh, n, out["value"], value) else: db[key] = UnspentOutput(addr, txn.hsh, n, out["value"], None) # and put onchain txn into DB db[txn.handle] = txn
def script_to_address(script): #TODO bech32 addresses #TODO testnet, although everything uses scripthash so the address vbyte doesnt matter return btc.script_to_address(script, 0x00)
field_names = ['tx#', 'timestamp', 'type', 'amount/btc', 'balance-change/btc', 'balance/btc', 'coinjoin-n', 'total-fees', 'utxo-count', 'mixdepth-from', 'mixdepth-to'] if options.csv: field_names += ['txid'] l = s().join(field_names) print(l) balance = 0 utxo_count = 0 deposits = [] deposit_times = [] for i, tx in enumerate(txes): rpctx = jm_single().bc_interface.rpc('gettransaction', [tx['txid']]) txhex = str(rpctx['hex']) txd = btc.deserialize(txhex) output_addr_values = dict(((btc.script_to_address(sv['script'], get_p2pk_vbyte()), sv['value']) for sv in txd['outs'])) our_output_addrs = wallet_addr_set.intersection( output_addr_values.keys()) from collections import Counter value_freq_list = sorted(Counter(output_addr_values.values()) .most_common(), key=lambda x: -x[1]) non_cj_freq = 0 if len(value_freq_list)==1 else sum(zip( *value_freq_list[1:])[1]) is_coinjoin = (value_freq_list[0][1] > 1 and value_freq_list[0][1] in [non_cj_freq, non_cj_freq+1]) cj_amount = value_freq_list[0][0] cj_n = value_freq_list[0][1] rpc_inputs = [] for ins in txd['ins']:
'mixdepth-from', 'mixdepth-to' ] if options.csv: field_names += ['txid'] l = s().join(field_names) print(l) balance = 0 utxo_count = 0 deposits = [] deposit_times = [] for i, tx in enumerate(txes): rpctx = jm_single().bc_interface.rpc('gettransaction', [tx['txid']]) txhex = str(rpctx['hex']) txd = btc.deserialize(txhex) output_addr_values = dict( ((btc.script_to_address(sv['script'], get_p2pk_vbyte()), sv['value']) for sv in txd['outs'])) our_output_addrs = wallet_addr_set.intersection( output_addr_values.keys()) from collections import Counter value_freq_list = sorted(Counter( output_addr_values.values()).most_common(), key=lambda x: -x[1]) non_cj_freq = 0 if len(value_freq_list) == 1 else sum( zip(*value_freq_list[1:])[1]) is_coinjoin = (value_freq_list[0][1] > 1 and value_freq_list[0][1] in [non_cj_freq, non_cj_freq + 1]) cj_amount = value_freq_list[0][0] cj_n = value_freq_list[0][1]