URI: 
       tsimplification: do not request checkpoint, check headers against all known blockchains - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 702abf6581f8067b955295f30bf5a3ce2d09ba96
   DIR parent 3d4c64f9e0dca7d9aa07b165cd504d288317803f
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Mon, 17 Jul 2017 19:32:10 +0200
       
       simplification: do not request checkpoint, check headers against all known blockchains
       
       Diffstat:
         M lib/blockchain.py                   |       7 ++++++-
         M lib/network.py                      |     112 ++++++++++++++-----------------
       
       2 files changed, 57 insertions(+), 62 deletions(-)
       ---
   DIR diff --git a/lib/blockchain.py b/lib/blockchain.py
       t@@ -72,7 +72,7 @@ def read_blockchains(config):
                blockchains[b.checkpoint] = b
            return blockchains
        
       -def get_blockchain(header):
       +def check_header(header):
            if type(header) is not dict:
                return False
            for b in blockchains.values():
       t@@ -80,6 +80,11 @@ def get_blockchain(header):
                    return b
            return False
        
       +def can_connect(header):
       +    for b in blockchains.values():
       +        if b.can_connect(header):
       +            return b
       +    return False
        
        
        class Blockchain(util.PrintError):
   DIR diff --git a/lib/network.py b/lib/network.py
       t@@ -40,7 +40,7 @@ import util
        import bitcoin
        from bitcoin import *
        from interface import Connection, Interface
       -from blockchain import read_blockchains, get_blockchain
       +import blockchain
        from version import ELECTRUM_VERSION, PROTOCOL_VERSION
        
        DEFAULT_PORTS = {'t':'50001', 's':'50002'}
       t@@ -206,7 +206,7 @@ class Network(util.DaemonThread):
                util.DaemonThread.__init__(self)
                self.config = SimpleConfig(config) if type(config) == type({}) else config
                self.num_server = 10 if not self.config.get('oneserver') else 0
       -        self.blockchains = read_blockchains(self.config)
       +        self.blockchains = blockchain.read_blockchains(self.config)
                self.print_error("blockchains", self.blockchains.keys())
                self.blockchain_index = config.get('blockchain_index', 0)
                if self.blockchain_index not in self.blockchains.keys():
       t@@ -706,12 +706,13 @@ class Network(util.DaemonThread):
                interface.blockchain = None
                interface.tip_header = None
                interface.tip = 0
       -        interface.mode = 'checkpoint'
       +        interface.mode = 'default'
       +        interface.request = None
                self.interfaces[server] = interface
       -        self.request_header(interface, self.get_checkpoint())
       +        self.queue_request('blockchain.headers.subscribe', [], interface)
                if server == self.default_server:
                    self.switch_to_interface(server)
       -        self.notify('interfaces')
       +        #self.notify('interfaces')
        
            def maintain_sockets(self):
                '''Socket maintenance.'''
       t@@ -804,24 +805,14 @@ class Network(util.DaemonThread):
                    interface.print_error("unsolicited header",interface.request, height)
                    self.connection_down(interface.server)
                    return
       -        if interface.mode == 'checkpoint':
       -            b = get_blockchain(header)
       -            if b:
       -                interface.mode = 'default'
       -                interface.blockchain = b
       -                self.queue_request('blockchain.headers.subscribe', [], interface)
       -            else:
       -                interface.print_error("checkpoint failed")
       -                self.connection_down(interface.server)
       -            interface.request = None
       -            return
        
       -        ok = interface.blockchain.check_header(header)
       +        chain = blockchain.check_header(header)
                if interface.mode == 'backward':
       -            if ok:
       -                interface.good = height
       -                interface.mode = 'binary'
       +            if chain:
                        interface.print_error("binary search")
       +                interface.mode = 'binary'
       +                interface.blockchain = chain
       +                interface.good = height
                        next_height = (interface.bad + interface.good) // 2
                    else:
                        if height == 0:
       t@@ -832,35 +823,43 @@ class Network(util.DaemonThread):
                            delta = interface.tip - height
                            next_height = max(0, interface.tip - 2 * delta)
                elif interface.mode == 'binary':
       -            if ok:
       +            if chain:
                        interface.good = height
       +                interface.blockchain = chain
                    else:
                        interface.bad = height
                    if interface.bad != interface.good + 1:
                        next_height = (interface.bad + interface.good) // 2
                    else:
                        interface.print_error("can connect at %d"% interface.bad)
       -                b = self.blockchains.get(interface.bad)
       -                if b is not None:
       -                    if b.check_header(header):
       +                branch = self.blockchains.get(interface.bad)
       +                if branch is not None:
       +                    # should check bad_header. test doesnt work if header == good
       +                    if branch.check_header(header):
                                interface.print_error('joining chain', interface.bad)
       -                        interface.blockchain = b
       -                    elif b.parent.check_header(header):
       +                    elif branch.parent.check_header(header):
                                interface.print_error('reorg', interface.bad, interface.tip)
       -                        interface.blockchain = b.parent
       +                        interface.blockchain = branch.parent
                            else:
                                # should not happen
                                raise BaseException('error')
                            # todo: we should check the tip once catch up is nor
                            next_height = None
                        else:
       -                    b = interface.blockchain.fork(interface.bad)
       -                    self.blockchains[interface.bad] = b
       -                    interface.print_error("new chain", b.filename)
       -                    b.catch_up = interface.server
       -                    interface.blockchain = b
       -                    interface.mode = 'catch_up'
       -                    next_height = interface.bad
       +                    if interface.blockchain.height() > interface.good:
       +                        self.blockchains[interface.bad] = interface.blockchain.fork(interface.bad)
       +                        interface.blockchain = b
       +                        interface.print_error("new chain", b.filename)
       +                    else:
       +                        assert interface.blockchain.height() == interface.good
       +
       +                    if interface.blockchain.catch_up is None:
       +                        interface.mode = 'catch_up'
       +                        next_height = interface.bad
       +                        interface.blockchain.catch_up = interface.server
       +                    else:
       +                        interface.print_error('already catching up')
       +                        next_height = None
                        # todo: garbage collect blockchain objects
                        self.notify('updated')
        
       t@@ -902,6 +901,7 @@ class Network(util.DaemonThread):
                else:
                    interface.mode = 'default'
                    interface.request = None
       +            self.notify('updated')
                # refresh network dialog
                self.notify('interfaces')
        
       t@@ -973,35 +973,25 @@ class Network(util.DaemonThread):
                    return
                interface.tip_header = header
                interface.tip = height
       -        local_height = interface.blockchain.height()
                if interface.mode != 'default':
                    return
       -        if interface.tip > local_height + 1:
       -            if interface.blockchain.catch_up is None:
       -                interface.blockchain.catch_up = interface.server
       -                interface.mode = 'catch_up' # must transition to search if it does not connect
       -                self.request_header(interface, local_height + 1)
       -            else:
       -                # another interface is catching up
       -                pass
       -        elif interface.tip == local_height + 1:
       -            if interface.blockchain.can_connect(header):
       -                interface.blockchain.save_header(header)
       -                self.notify('updated')
       -            else:
       -                interface.mode = 'backward'
       -                interface.bad = height 
       -                self.request_header(interface, local_height)
       -        else:
       -            if not interface.blockchain.check_header(header):
       -                self.print_error("backward", height)
       -                interface.mode = 'backward'
       -                interface.bad = height
       -                self.request_header(interface, height - 1)
       -            else:
       -                pass
       -        self.switch_lagging_interface()
       -        self.notify('interfaces')
       +        b = blockchain.check_header(header)
       +        if b:
       +            interface.blockchain = b
       +            self.notify('interfaces')
       +            self.switch_lagging_interface()
       +            return
       +        b = blockchain.can_connect(header)
       +        if b:
       +            interface.blockchain = b
       +            b.save_header(header)
       +            self.notify('updated')
       +            self.notify('interfaces')
       +            self.switch_lagging_interface()
       +            return
       +        interface.mode = 'backward'
       +        interface.bad = height
       +        self.request_header(interface, height - 1) # should be max(heights)
        
            def blockchain(self):
                if self.interface and self.interface.blockchain is not None: