tblockchain: swap a chain with its parent, if the parent branch is too short to be saved on disk - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 50ad656c87fe59e5756a64a12ce31968bb3e1301 DIR parent 1316e4f70d3df951c804a9a82be0648b149756a6 HTML Author: ThomasV <thomasv@electrum.org> Date: Tue, 18 Jul 2017 18:10:22 +0200 blockchain: swap a chain with its parent, if the parent branch is too short to be saved on disk Diffstat: M lib/blockchain.py | 42 ++++++++++++++++++++++++++++--- M lib/network.py | 1 - 2 files changed, 38 insertions(+), 5 deletions(-) --- DIR diff --git a/lib/blockchain.py b/lib/blockchain.py t@@ -65,8 +65,8 @@ blockchains = {} def read_blockchains(config): blockchains[0] = Blockchain(config, 'blockchain_headers') - # fixme: sort - l = sorted(filter(lambda x: x.startswith('fork_'), os.listdir(config.path))) + l = filter(lambda x: x.startswith('fork_'), os.listdir(config.path)) + l = sorted(l, key = lambda x: int(x.split('_')[1])) for x in l: b = Blockchain(config, x) blockchains[b.checkpoint] = b t@@ -106,6 +106,15 @@ class Blockchain(util.PrintError): else: 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): header_hash = hash_header(header) height = header.get('block_height') t@@ -187,13 +196,38 @@ class Blockchain(util.PrintError): self.is_saved = True 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): + N = 10 height = header.get('block_height') if not self.is_saved: assert height == self.checkpoint + len(self.headers) self.headers.append(header) - if len(self.headers) > 10 and self.parent.size() > 10: - self.save() + if len(self.headers) > N: + if self.parent.get_branch_size() <= N: + self.swap_with_parent() + else: + self.save() return self.write_header(header) DIR diff --git a/lib/network.py b/lib/network.py t@@ -862,7 +862,6 @@ class Network(util.DaemonThread): else: interface.print_error('already catching up') next_height = None - # todo: garbage collect blockchain objects self.notify('updated') elif interface.mode == 'catch_up':