URI: 
       tmake blockchain.size() threadsafe - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit d71c9d5be3034bd41d5538284d7b79a495ff2bbb
   DIR parent 622f459c416cb825af8bac9bddb663647a33445f
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Mon, 24 Jul 2017 15:54:42 +0200
       
       make blockchain.size() threadsafe
       
       Diffstat:
         M lib/blockchain.py                   |      56 ++++++++++++++++++++-----------
         M lib/network.py                      |       3 +--
       
       2 files changed, 38 insertions(+), 21 deletions(-)
       ---
   DIR diff --git a/lib/blockchain.py b/lib/blockchain.py
       t@@ -27,6 +27,8 @@
        
        import os
        import util
       +import threading
       +
        import bitcoin
        from bitcoin import *
        
       t@@ -101,6 +103,9 @@ class Blockchain(util.PrintError):
                self.catch_up = None # interface catching up
                self.checkpoint = checkpoint
                self.parent_id = parent_id
       +        self.lock = threading.Lock()
       +        with self.lock:
       +            self.update_size()
        
            def parent(self):
                return blockchains[self.parent_id]
       t@@ -124,18 +129,23 @@ class Blockchain(util.PrintError):
                height = header.get('block_height')
                return header_hash == self.get_hash(height)
        
       -    def fork(parent, checkpoint):
       +    def fork(parent, header):
       +        checkpoint = header.get('block_height')
                self = Blockchain(parent.config, checkpoint, parent.checkpoint)
       -        # create file
                open(self.path(), 'w+').close()
       +        self.save_header(header)
                return self
        
            def height(self):
                return self.checkpoint + self.size() - 1
        
            def size(self):
       +        with self.lock:
       +            return self._size
       +
       +    def update_size(self):
                p = self.path()
       -        return os.path.getsize(p)/80 if os.path.exists(p) else 0
       +        self._size = os.path.getsize(p)/80 if os.path.exists(p) else 0
        
            def verify_header(self, header, prev_header, bits, target):
                prev_hash = hash_header(prev_header)
       t@@ -181,9 +191,11 @@ class Blockchain(util.PrintError):
                if d < 0:
                    chunk = chunk[-d:]
                    d = 0
       -        with open(filename, 'rb+') as f:
       -            f.seek(d)
       -            f.write(chunk)
       +        with self.lock:
       +            with open(filename, 'rb+') as f:
       +                f.seek(d)
       +                f.write(chunk)
       +            self.update_size()
                self.swap_with_parent()
        
            def swap_with_parent(self):
       t@@ -199,16 +211,20 @@ class Blockchain(util.PrintError):
                with open(parent.path(), 'rb+') as f:
                    f.seek((checkpoint - parent.checkpoint)*80)
                    parent_data = f.read(parent_branch_size*80)
       -            f.seek((checkpoint - parent.checkpoint)*80)
       -            f.truncate()
       -        with open(self.path(), 'rb+') as f:
       -            my_data = f.read()
       -            f.seek(0)
       -            f.truncate()
       -            f.write(parent_data)
       -        with open(parent.path(), 'rb+') as f:
       -            f.seek((checkpoint - parent.checkpoint)*80)
       -            f.write(my_data)
       +        with self.lock:
       +            with open(self.path(), 'rb+') as f:
       +                my_data = f.read()
       +                f.seek(0)
       +                f.truncate()
       +                f.write(parent_data)
       +            self.update_size()
       +        with parent.lock:
       +            with open(parent.path(), 'rb+') as f:
       +                f.seek((checkpoint - parent.checkpoint)*80)
       +                f.truncate()
       +                f.seek((checkpoint - parent.checkpoint)*80)
       +                f.write(my_data)
       +            parent.update_size()
                # store file path
                for b in blockchains.values():
                    b.old_path = b.path()
       t@@ -231,9 +247,11 @@ class Blockchain(util.PrintError):
                data = serialize_header(header).decode('hex')
                assert delta == self.size()
                assert len(data) == 80
       -        with open(filename, 'rb+') as f:
       -            f.seek(delta * 80)
       -            f.write(data)
       +        with self.lock:
       +            with open(filename, 'rb+') as f:
       +                f.seek(delta * 80)
       +                f.write(data)
       +            self.update_size()
                # order files
                self.swap_with_parent()
        
   DIR diff --git a/lib/network.py b/lib/network.py
       t@@ -854,8 +854,7 @@ class Network(util.DaemonThread):
                            if bh > interface.good:
                                if not interface.blockchain.check_header(interface.bad_header):
                                    if interface.blockchain.can_connect(interface.bad_header, check_height=False):
       -                                b = interface.blockchain.fork(interface.bad)
       -                                b.save_header(interface.bad_header)
       +                                b = interface.blockchain.fork(interface.bad_header)
                                        self.blockchains[interface.bad] = b
                                        interface.blockchain = b
                                        interface.print_error("new chain", b.checkpoint)