blockchain: swap a chain with its parent, if the parent branch is too short to be saved on disk
This commit is contained in:
parent
1316e4f70d
commit
50ad656c87
|
@ -65,8 +65,8 @@ blockchains = {}
|
||||||
|
|
||||||
def read_blockchains(config):
|
def read_blockchains(config):
|
||||||
blockchains[0] = Blockchain(config, 'blockchain_headers')
|
blockchains[0] = Blockchain(config, 'blockchain_headers')
|
||||||
# fixme: sort
|
l = filter(lambda x: x.startswith('fork_'), os.listdir(config.path))
|
||||||
l = sorted(filter(lambda x: x.startswith('fork_'), os.listdir(config.path)))
|
l = sorted(l, key = lambda x: int(x.split('_')[1]))
|
||||||
for x in l:
|
for x in l:
|
||||||
b = Blockchain(config, x)
|
b = Blockchain(config, x)
|
||||||
blockchains[b.checkpoint] = b
|
blockchains[b.checkpoint] = b
|
||||||
|
@ -106,6 +106,15 @@ class Blockchain(util.PrintError):
|
||||||
else:
|
else:
|
||||||
raise BaseException('')
|
raise BaseException('')
|
||||||
|
|
||||||
|
def get_max_child(self):
|
||||||
|
children = filter(lambda y: y.parent==self, blockchains.values())
|
||||||
|
return max([x.checkpoint for x in children]) if children else None
|
||||||
|
|
||||||
|
def get_branch_size(self):
|
||||||
|
mc = self.get_max_child()
|
||||||
|
checkpoint = mc if mc is not None else self.checkpoint
|
||||||
|
return self.height() - checkpoint
|
||||||
|
|
||||||
def check_header(self, header):
|
def check_header(self, header):
|
||||||
header_hash = hash_header(header)
|
header_hash = hash_header(header)
|
||||||
height = header.get('block_height')
|
height = header.get('block_height')
|
||||||
|
@ -187,12 +196,37 @@ class Blockchain(util.PrintError):
|
||||||
self.is_saved = True
|
self.is_saved = True
|
||||||
self.print_error("saved", self.filename)
|
self.print_error("saved", self.filename)
|
||||||
|
|
||||||
|
def swap_with_parent(self):
|
||||||
|
self.print_error("swap")
|
||||||
|
parent = self.parent
|
||||||
|
checkpoint = self.checkpoint
|
||||||
|
# copy headers
|
||||||
|
parent.headers = [parent.read_header(h) for h in range(checkpoint, checkpoint + parent.get_branch_size())]
|
||||||
|
# truncate parent file
|
||||||
|
with open(parent.path(), 'rb+') as f:
|
||||||
|
f.seek(checkpoint*80)
|
||||||
|
f.truncate()
|
||||||
|
parent.is_saved = False
|
||||||
|
# swap chains
|
||||||
|
fn = self.filename; self.filename = parent.filename; parent.filename = fn
|
||||||
|
self.parent = parent.parent; parent.parent = parent
|
||||||
|
self.checkpoint = parent.checkpoint; parent.checkpoint = checkpoint
|
||||||
|
# write my headers
|
||||||
|
for h in self.headers:
|
||||||
|
self.write_header(h)
|
||||||
|
self.headers = []
|
||||||
|
self.is_saved = True
|
||||||
|
|
||||||
def save_header(self, header):
|
def save_header(self, header):
|
||||||
|
N = 10
|
||||||
height = header.get('block_height')
|
height = header.get('block_height')
|
||||||
if not self.is_saved:
|
if not self.is_saved:
|
||||||
assert height == self.checkpoint + len(self.headers)
|
assert height == self.checkpoint + len(self.headers)
|
||||||
self.headers.append(header)
|
self.headers.append(header)
|
||||||
if len(self.headers) > 10 and self.parent.size() > 10:
|
if len(self.headers) > N:
|
||||||
|
if self.parent.get_branch_size() <= N:
|
||||||
|
self.swap_with_parent()
|
||||||
|
else:
|
||||||
self.save()
|
self.save()
|
||||||
return
|
return
|
||||||
self.write_header(header)
|
self.write_header(header)
|
||||||
|
|
|
@ -862,7 +862,6 @@ class Network(util.DaemonThread):
|
||||||
else:
|
else:
|
||||||
interface.print_error('already catching up')
|
interface.print_error('already catching up')
|
||||||
next_height = None
|
next_height = None
|
||||||
# todo: garbage collect blockchain objects
|
|
||||||
self.notify('updated')
|
self.notify('updated')
|
||||||
|
|
||||||
elif interface.mode == 'catch_up':
|
elif interface.mode == 'catch_up':
|
||||||
|
|
Loading…
Reference in New Issue