class BitcoinCandyQuery(object): def __init__(self, vdb, settings): self.vdb = vdb self.coin = self.vdb.get_coin_info('bitcoin-candy') self.addrs = [{'addr': a, 'p2sh_p2wpkh': a[:1] == "3", 'bech32': a[:3] == "bc1"} for a in settings.addresses] self.tails = not settings.not_tails self.cache = settings.cache_requests self.wd = WebData(tails=self.tails, cache=self.cache) self.explorer = self.coin['explorer'].strip('/') self._add_nuggets() def _add_nuggets(self): for a in self.addrs: converted_addr = str(ConvertedAddress(a['addr'], "bitcoin-candy")) aapi = "%s/insight-api/addr/%s" % (self.explorer, converted_addr) addr_info = self.wd.fetch_web_url_json_info(aapi) for t in addr_info['transactions']: tapi = "%s/insight-api/tx/%s" % (self.explorer, t) tx_info = self.wd.fetch_web_url_json_info(tapi) for o in tx_info['vout']: if o['scriptPubKey']['addresses'][0] != converted_addr: continue n = o['n'] satoshis = int(float(o['value']) * 100000) self.vdb['nuggets'].append_direct_query(a, self.coin, t, o['n'], satoshis)
def __init__(self, settings, addr): super().__init__(settings, addr) self.wd = WebData(tails=self.tails, cache=self.cache) self.addr_info = self.wd.fetch_addr_info(self.addr) ins = list(self._get_addr_ins()) outs = list(self._get_addr_outs()) self._validate_outs(ins, outs) tx_block_map = self._get_tx_block_map(ins, outs) for i in ins: i['block'] = tx_block_map[i['hash']] for o in outs: o['block'] = tx_block_map[o['hash']] self['spans'] = self._calc_spans(ins, outs) print(self['spans'])
def __init__(self, vdb, settings): self.vdb = vdb self.coin = self.vdb.get_coin_info('bitcore') self.addrs = [{ 'addr': a, 'p2sh_p2wpkh': a[:1] == "3", 'bech32': a[:3] == "bc1" } for a in settings.addresses] self.tails = not settings.not_tails self.cache = settings.cache_requests self.wd = WebData(tails=self.tails, cache=self.cache) self._add_nuggets()
def __init__(self, settings): super().__init__() addrs = settings.addresses addrs.sort() self.forkdrop_info = ForkdropInfo() self.tails = not settings.not_tails self.cache = settings.cache_requests self.bfc_force = settings.bfc_force self.claim_save_file = settings.claim_save_file self.wd = WebData(tails=self.tails, cache=self.cache) self['addrs'] = [AddressInfo(self.wd, addr) for addr in addrs] self['basic_coins'] = [c for c in self.forkdrop_info['bitcoin'] if self._classify(c) == "basic"] self['basic_coins'].sort(key=lambda x: self._coin_sort(x)) self['tbd_coins'] = [c for c in self.forkdrop_info['bitcoin'] if self._classify(c) == "tbd"] self['tbd_coins'].sort(key=lambda x: self._coin_sort(x)) self['special_coins'] = [c for c in self.forkdrop_info['bitcoin'] if self._classify(c) == "special"] self['special_coins'].sort(key=lambda x: self._coin_sort(x)) self['registered_coins'] = [c for c in self.forkdrop_info['bitcoin'] if self._classify(c) == "registered"] self['registered_coins'].sort(key=lambda x: self._coin_sort(x)) self['exchanges'] = self.forkdrop_info['exchanges'] self['nuggets'] = NuggetList(self, tails=self.tails, bfc_force=self.bfc_force)
class BitcoreQuery(object): def __init__(self, vdb, settings): self.vdb = vdb self.coin = self.vdb.get_coin_info('bitcore') self.addrs = [{ 'addr': a, 'p2sh_p2wpkh': a[:1] == "3", 'bech32': a[:3] == "bc1" } for a in settings.addresses] self.tails = not settings.not_tails self.cache = settings.cache_requests self.wd = WebData(tails=self.tails, cache=self.cache) self._add_nuggets() def _add_nuggets(self): for a in self.addrs: addr = a['addr'] url = UNSPENT_URL % addr unspent_info = self.wd.fetch_web_url_json_info(url) for u in unspent_info['unspent_outputs']: self.vdb['nuggets'].append_direct_query( a, self.coin, u['tx_hash'], u['tx_ouput_n'], int(u['value']))
class BlockchainAddressInfo(AddressInfo): """ Info queried for a single address from blockchain.com block explorerer. Spans of blocks that that address held coins are calculeted """ def __init__(self, settings, addr): super().__init__(settings, addr) self.wd = WebData(tails=self.tails, cache=self.cache) self.addr_info = self.wd.fetch_addr_info(self.addr) ins = list(self._get_addr_ins()) outs = list(self._get_addr_outs()) self._validate_outs(ins, outs) tx_block_map = self._get_tx_block_map(ins, outs) for i in ins: i['block'] = tx_block_map[i['hash']] for o in outs: o['block'] = tx_block_map[o['hash']] self['spans'] = self._calc_spans(ins, outs) print(self['spans']) def _calc_spans(self, ins, outs): spans = {} out_lookup = {o['span_id']: o for o in outs} for i in ins: span_id = i['span_id'] o = out_lookup[span_id] if span_id in out_lookup.keys() else None spans[span_id] = {'funded': i, 'defunded': o} return spans def _span_id(self, tx_index, n, value): return "%s %s %s" % (tx_index, n, value) def _validate_outs(self, ins, outs): # make sure data is consistent by having every out correspond to # a previous in. i_set = set(t['span_id'] for t in ins) o_set = set(t['span_id'] for t in outs) #print(i_set) #print(o_set) for o in o_set: assert o in i_set def _iter_tx_blocks(self, txes): hashes = [t['hash'] for t in txes] for h in list(set(hashes)): d = self.wd.fetch_tx_info(h) yield h, d['block_height'] def _get_tx_block_map(self, ins, outs): return {h: height for h, height in self._iter_tx_blocks(ins + outs)} def _get_addr_ins(self): for tx in self.addr_info['txs']: outs = [o for o in tx['out'] if o['addr'] == self.addr] for o in outs: yield { 'n': o['n'], 'hash': tx['hash'], 'value': o['value'], 'tx_index': o['tx_index'], 'span_id': self._span_id(o['tx_index'], o['n'], o['value']) } def _get_addr_outs(self): for tx in self.addr_info['txs']: ins = [ i for i in tx['inputs'] if i['prev_out']['addr'] == self.addr ] for i in ins: n = i['prev_out']['n'] value = i['prev_out']['value'] tx_index = i['prev_out']["tx_index"] yield { 'tx_index': tx_index, 'n': n, 'value': value, 'hash': tx['hash'], 'span_id': self._span_id(tx_index, n, value) }
class BitcoinCbcQuery(object): def __init__(self, vdb, settings): self.vdb = vdb self.coin = self.vdb.get_coin_info('bitcoin-cbc') self.addrs = [{ 'addr': a, 'p2sh_p2wpkh': a[:1] == "3", 'bech32': a[:3] == "bc1" } for a in settings.addresses] self.tails = not settings.not_tails self.cache = settings.cache_requests self.bfc_force = settings.bfc_force self.wd = WebData(tails=self.tails, cache=self.cache) self._add_nuggets() def _slice_table(self, content): # kinda hacky - slices out the last html table in the content start = content.rfind("<table") end = content.rfind("</table>") return content[start:end] + "</table>" def _strip(self, td): # kinda hacky - gets at the internal text of a html <a> element if # there is one instead of just text if len(td.getchildren()) > 0: return td.getchildren()[0].text return td.text def _iter_txes(self, addr_html): table = self._slice_table(addr_html) t = ET.XML(table) rows = iter(t) headers = [col.text for col in next(rows)] for row in rows: values = [col for col in row] yield values[0].getchildren()[0].attrib['href'] def _iter_tx_outputs(self, tx_html): table = self._slice_table(tx_html) t = ET.XML(table) rows = iter(t) headers = [col.text for col in next(rows)] for row in rows: values = [col for col in row] index = int(values[0].getchildren()[0].text) amount = int(float(values[2].text) * SATOSHIS_PER_BTC) addr = values[3].getchildren()[0].text yield index, amount, addr def _add_nuggets(self): for a in self.addrs: addr = a['addr'] addr_url = ADDR_URL % addr addr_html = self.wd.fetch_web_url_text_info(addr_url) for tx_path in self._iter_txes(addr_html): txid = tx_path.split('/')[-1].split("#")[0] tx_url = ADDR_URL % tx_path tx_html = self.wd.fetch_web_url_text_info(tx_url) for index, satoshis, to_addr in self._iter_tx_outputs(tx_html): if to_addr != addr: continue self.vdb['nuggets'].append_direct_query( a, self.coin, txid, index, satoshis)