blockchain: size method, various fixes

This commit is contained in:
ThomasV 2017-07-17 08:44:09 +02:00
parent b2116d87ea
commit b0277d5426
2 changed files with 45 additions and 38 deletions

View File

@ -66,19 +66,17 @@ blockchains = {}
def read_blockchains(config):
blockchains[0] = Blockchain(config, 'blockchain_headers')
# fixme: sort
for x in os.listdir(config.path):
if x.startswith('fork_'):
b = Blockchain(config, x)
blockchains[b.checkpoint] = b
l = sorted(filter(lambda x: x.startswith('fork_'), os.listdir(config.path)))
for x in l:
b = Blockchain(config, x)
blockchains[b.checkpoint] = b
return blockchains
def get_blockchain(header):
if type(header) is not dict:
return False
header_hash = hash_header(header)
height = header.get('block_height')
for b in blockchains.values():
if header_hash == b.get_hash(height):
if b.check_header(header):
return b
return False
@ -102,19 +100,27 @@ class Blockchain(util.PrintError):
self.checkpoint = int(filename.split('_')[2])
else:
raise BaseException('')
self.set_local_height()
def check_header(self, header):
header_hash = hash_header(header)
height = header.get('block_height')
return header_hash == self.get_hash(height)
def fork(parent, checkpoint):
filename = 'fork_%d_%d'%(parent.checkpoint, checkpoint)
self = Blockchain(parent.config, filename)
self.is_saved = False
self.parent = parent
self.checkpoint = checkpoint
return self
def height(self):
local = self.local_height if self.is_saved else len(self.headers) - 1
return self.checkpoint + local
return self.checkpoint + self.size() - 1
def size(self):
if self.is_saved:
p = self.path()
return os.path.getsize(p)/80 if os.path.exists(p) else 0
else:
return len(self.headers)
def verify_header(self, header, prev_header, bits, target):
prev_hash = hash_header(prev_header)
@ -157,11 +163,13 @@ class Blockchain(util.PrintError):
if not self.is_saved:
self.save()
filename = self.path()
d = (index * 2016 - self.checkpoint) * 80
if d < 0:
chunk = chunk[-d:]
d = 0
with open(filename, 'rb+') as f:
f.seek(index * 2016 * 80)
f.truncate()
h = f.write(chunk)
self.set_local_height()
f.seek(d)
f.write(chunk)
def save(self):
# recursively save parents if they have not been saved
@ -179,28 +187,20 @@ class Blockchain(util.PrintError):
if not self.is_saved:
assert height == self.checkpoint + len(self.headers)
self.headers.append(header)
if len(self.headers) > 10:
if len(self.headers) > 10 and self.parent.size() > 10:
self.save()
return
self.write_header(header)
def write_header(self, header):
filename = self.path()
delta = header.get('block_height') - self.checkpoint
data = serialize_header(header).decode('hex')
assert delta * 80 == os.path.getsize(filename)
assert len(data) == 80
filename = self.path()
with open(filename, 'rb+') as f:
f.seek(delta * 80)
f.truncate()
h = f.write(data)
self.set_local_height()
def set_local_height(self):
self.local_height = 0
name = self.path()
if os.path.exists(name):
h = os.path.getsize(name)/80 - 1
self.local_height = h
f.write(data)
def read_header(self, height):
if height < self.checkpoint:
@ -219,7 +219,7 @@ class Blockchain(util.PrintError):
h = f.read(80)
f.close()
if len(h) == 80:
h = deserialize_header(h, delta)
h = deserialize_header(h, height)
return h
def get_hash(self, height):

View File

@ -851,14 +851,22 @@ class Network(util.DaemonThread):
else:
interface.print_error("can connect at %d"% interface.good)
b = self.blockchains.get(interface.good)
if b is None:
b = interface.blockchain.fork(interface.good)
b.catch_up = interface.server
interface.print_error("catching up with new chain")
self.blockchains[interface.good] = b
interface.mode = 'catch_up'
next_height = interface.good
interface.blockchain = b
# if there is a reorg we connect to the parent
if b is not None and interface.good == b.checkpoint:
interface.print_error('reorg', interface.good, interface.tip)
interface.blockchain = b.parent
interface.mode = 'default'
next_height = interface.tip
else:
if b is None:
b = interface.blockchain.fork(interface.good)
self.blockchains[interface.good] = b
interface.print_error("catching up on new blockchain", b.filename)
if b.catch_up is None:
b.catch_up = interface.server
interface.blockchain = b
interface.mode = 'catch_up'
next_height = interface.good
# todo: garbage collect blockchain objects
self.notify('updated')
@ -944,7 +952,6 @@ class Network(util.DaemonThread):
self.print_error("download failed. creating file", filename)
open(filename, 'wb+').close()
self.downloading_headers = False
self.blockchains[0].set_local_height()
self.downloading_headers = True
t = threading.Thread(target = download_thread)
t.daemon = True