Skip to content

Instantly share code, notes, and snippets.

@gdassori
Last active October 14, 2018 13:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gdassori/78b591721bacc46d2a21bfc88399510a to your computer and use it in GitHub Desktop.
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.
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