URI: 
       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':