Last active
October 14, 2018 13:52
-
-
Save gdassori/78b591721bacc46d2a21bfc88399510a to your computer and use it in GitHub Desktop.
Verify the Bitcoin Blockchain with DNS queries using Public DNS around the world.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests # requests | |
import bitcoin # pybitcointools | |
from dns import resolver # dnspython | |
def get_resolvers(): | |
dns = "https://public-dns.info/nameservers.txt" | |
lista_dns = requests.get(dns).content.decode() | |
resolvers = [] | |
for line in lista_dns.split('\n'): | |
l = line.strip() | |
resolvers.append(l) | |
return resolvers | |
def verify_pow(header, blockhash): | |
bits = header[72:76][::-1] | |
target = int.from_bytes(bits[1:], 'big') * 2 ** (8 * (bits[0] - 3)) | |
if target < int.from_bytes(blockhash, 'little'): | |
return True | |
raise ValueError | |
def deserialize_header(header: (str, bytes)): | |
if isinstance(header, bytes): | |
h, fmt = header, 'bin' | |
else: | |
h, fmt = bitcoin.binascii.unhexlify(header.encode()), 'hex' | |
blockhash = bitcoin.bin_sha256(bitcoin.bin_sha256(h))[::-1] | |
data = { | |
"version": bitcoin.decode(h[:4][::-1], 256), | |
"prev_block_hash": h[4:36][::-1], | |
"merkle_root": h[36:68][::-1], | |
"timestamp": bitcoin.decode(h[68:72][::-1], 256), | |
"bits": bitcoin.decode(h[72:76][::-1], 256), | |
"nonce": bitcoin.decode(h[76:80][::-1], 256), | |
"hash": blockhash | |
} | |
if fmt == 'hex': | |
data['prev_block_hash'] = bitcoin.binascii.hexlify(data['prev_block_hash']).decode() | |
data['merkle_root'] = bitcoin.binascii.hexlify(data['merkle_root']).decode() | |
data['hash'] = bitcoin.binascii.hexlify(data['hash']).decode() | |
verify_pow(h, blockhash) | |
return data | |
def get_block_hash(height, dns=None): | |
record_height = '{}.height.btc.mempool.co'.format(int(height)) | |
if dns: | |
my_resolver = resolver.Resolver() | |
my_resolver.nameservers = [dns] | |
my_resolver.timeout = 2 | |
my_resolver.lifetime = 6 | |
r = my_resolver | |
else: | |
r = resolver | |
x = r.query(record_height, 'CNAME') | |
return '0'*8 + x.rrset.items[0].target.labels[0].decode() | |
def get_block_header(hash, dns=None): | |
query_hash = '{}.block.btc.mempool.co'.format(hash[8:]) | |
if dns: | |
my_resolver = resolver.Resolver() | |
my_resolver.nameservers = [dns] | |
my_resolver.timeout = 2 | |
my_resolver.lifetime = 6 | |
r = my_resolver | |
else: | |
r = resolver | |
x = r.query(query_hash, 'TXT') | |
return bitcoin.binascii.hexlify( | |
bitcoin.base64.b64decode(x.rrset.items[0].strings[0].decode()) | |
).decode() | |
def get_header(block_hash, dns=None, deserialize=True): | |
block_header = get_block_header(block_hash, dns=dns) | |
header = deserialize and deserialize_header(block_header) or block_header | |
return header | |
if __name__ == '__main__': | |
block_hash = None | |
resolvers = get_resolvers() | |
i = 530000 | |
downloaded_at = bitcoin.time.time() | |
while not block_hash: | |
try: | |
rrr = bitcoin.random.choice(resolvers) | |
block_hash = get_block_hash(i, dns=rrr) | |
downloaded_at = bitcoin.time.time() | |
except Exception as e: | |
print('Removing %s' % rrr) | |
resolvers.remove(rrr) | |
prev_block_hash = block_hash | |
while 1: | |
try: | |
rrr = '38.122.24.30' | |
header = get_header(prev_block_hash, dns=rrr) | |
prev_block_hash = header['prev_block_hash'] | |
if not i: | |
assert '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f' == header['hash'], header | |
print('The blockchain has been verified') | |
break | |
else: | |
print('Downloaded header for block %s (%s) in %s over DNS %s' % ( | |
i - 1, header['hash'], (bitcoin.time.time() - downloaded_at), rrr | |
) | |
) | |
downloaded_at = bitcoin.time.time() | |
i -= 1 | |
except (resolver.NoNameservers, resolver.Timeout) as e: | |
rrr = bitcoin.random.choice(resolvers) | |
downloaded_at = bitcoin.time.time() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment