예제 #1
0
 def on_notify_header(self, interface, header):
     height = header.get('block_height')
     if not height:
         return
     interface.tip_header = header
     interface.tip = height
     if interface.mode != 'default':
         return
     b = blockchain.check_header(header)
     if b:
         interface.blockchain = b
         self.switch_lagging_interface()
         self.notify('interfaces')
         return
     b = blockchain.can_connect(header)
     if b:
         interface.blockchain = b
         b.save_header(header)
         self.switch_lagging_interface()
         self.notify('updated')
         self.notify('interfaces')
         return
     tip = max([x.height() for x in self.blockchains.values()])
     if tip >=0:
         interface.mode = 'backward'
         interface.bad = height
         interface.bad_header = header
         self.request_header(interface, min(tip, height - 1))
     else:
         chain = self.blockchains[0]
         if chain.catch_up is None:
             chain.catch_up = interface
             interface.mode = 'catch_up'
             interface.blockchain = chain
             self.request_header(interface, 0)
예제 #2
0
파일: network.py 프로젝트: flatfly/electrum
 def on_notify_header(self, interface, header):
     height = header.get('block_height')
     if not height:
         return
     interface.tip_header = header
     interface.tip = height
     if interface.mode != 'default':
         return
     b = blockchain.check_header(header)
     if b:
         interface.blockchain = b
         self.switch_lagging_interface()
         self.notify('interfaces')
         return
     b = blockchain.can_connect(header)
     if b:
         interface.blockchain = b
         b.save_header(header)
         self.switch_lagging_interface()
         self.notify('updated')
         self.notify('interfaces')
         return
     tip = max([x.height() for x in self.blockchains.values()])
     if tip >=0:
         interface.mode = 'backward'
         interface.bad = height
         interface.bad_header = header
         self.request_header(interface, min(tip, height - 1))
     else:
         chain = self.blockchains[0]
         if chain.catch_up is None:
             chain.catch_up = interface
             interface.mode = 'catch_up'
             interface.blockchain = chain
             self.request_header(interface, 0)
예제 #3
0
 def on_notify_header(self, interface, header):
     height = header.get('block_height')
     if not height:
         return
     interface.tip_header = header
     interface.tip = height
     if interface.mode != 'default':
         return
     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
     interface.bad_header = header
     self.request_header(interface, height - 1) # should be max(heights)
예제 #4
0
    def on_get_header(self, interface, response):
        '''Handle receiving a single block header'''
        header = response.get('result')
        if not header:
            interface.print_error(response)
            self.connection_down(interface.server)
            return
        height = header.get('block_height')
        if interface.request != height:
            interface.print_error("unsolicited header",interface.request, height)
            self.connection_down(interface.server)
            return

        chain = blockchain.check_header(header)
        if interface.mode == 'backward':
            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:
                    self.connection_down(interface.server)
                    next_height = None
                else:
                    interface.bad = height
                    interface.bad_header = header
                    delta = interface.tip - height
                    next_height = max(0, interface.tip - 2 * delta)

        elif interface.mode == 'binary':
            if chain:
                interface.good = height
                interface.blockchain = chain
            else:
                interface.bad = height
                interface.bad_header = header
            if interface.bad != interface.good + 1:
                next_height = (interface.bad + interface.good) // 2
            elif not interface.blockchain.can_connect(interface.bad_header, check_height=False):
                self.connection_down(interface.server)
                next_height = None
            else:
                branch = self.blockchains.get(interface.bad)
                if branch is not None:
                    if branch.check_header(interface.bad_header):
                        interface.print_error('joining chain', interface.bad)
                        next_height = None
                    elif branch.parent().check_header(header):
                        interface.print_error('reorg', interface.bad, interface.tip)
                        interface.blockchain = branch.parent()
                        next_height = None
                    else:
                        interface.print_error('checkpoint conflicts with existing fork', branch.path())
                        branch.write('', 0)
                        branch.save_header(interface.bad_header)
                        interface.mode = 'catch_up'
                        interface.blockchain = branch
                        next_height = interface.bad + 1
                        interface.blockchain.catch_up = interface.server
                else:
                    bh = interface.blockchain.height()
                    next_height = None
                    if bh > interface.good:
                        if not interface.blockchain.check_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)
                            interface.mode = 'catch_up'
                            next_height = interface.bad + 1
                            interface.blockchain.catch_up = interface.server
                    else:
                        assert bh == interface.good
                        if interface.blockchain.catch_up is None and bh < interface.tip:
                            interface.print_error("catching up from %d"% (bh + 1))
                            interface.mode = 'catch_up'
                            next_height = bh + 1
                            interface.blockchain.catch_up = interface.server

                self.notify('updated')

        elif interface.mode == 'catch_up':
            can_connect = interface.blockchain.can_connect(header)
            if can_connect:
                interface.blockchain.save_header(header)
                next_height = height + 1 if height < interface.tip else None
            else:
                # go back
                interface.print_error("cannot connect", height)
                interface.mode = 'backward'
                interface.bad = height
                interface.bad_header = header
                next_height = height - 1

            if next_height is None:
                # exit catch_up state
                interface.print_error('catch up done', interface.blockchain.height())
                interface.blockchain.catch_up = None
                self.switch_lagging_interface()
                self.notify('updated')

        elif interface.mode == 'default':
            if not ok:
                interface.print_error("default: cannot connect %d"% height)
                interface.mode = 'backward'
                interface.bad = height
                interface.bad_header = header
                next_height = height - 1
            else:
                interface.print_error("we are ok", height, interface.request)
                next_height = None
        else:
            raise BaseException(interface.mode)
        # If not finished, get the next header
        if next_height:
            if interface.mode == 'catch_up' and interface.tip > next_height + 50:
                self.request_chunk(interface, next_height // 2016)
            else:
                self.request_header(interface, next_height)
        else:
            interface.mode = 'default'
            interface.request = None
            self.notify('updated')
        # refresh network dialog
        self.notify('interfaces')
예제 #5
0
파일: network.py 프로젝트: flatfly/electrum
    def on_get_header(self, interface, response):
        '''Handle receiving a single block header'''
        header = response.get('result')
        if not header:
            interface.print_error(response)
            self.connection_down(interface.server)
            return
        height = header.get('block_height')
        if interface.request != height:
            interface.print_error("unsolicited header",interface.request, height)
            self.connection_down(interface.server)
            return

        chain = blockchain.check_header(header)
        if interface.mode == 'backward':
            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:
                    self.connection_down(interface.server)
                    next_height = None
                else:
                    interface.bad = height
                    interface.bad_header = header
                    delta = interface.tip - height
                    next_height = max(0, interface.tip - 2 * delta)

        elif interface.mode == 'binary':
            if chain:
                interface.good = height
                interface.blockchain = chain
            else:
                interface.bad = height
                interface.bad_header = header
            if interface.bad != interface.good + 1:
                next_height = (interface.bad + interface.good) // 2
            else:
                branch = self.blockchains.get(interface.bad)
                if branch is not None:
                    if branch.check_header(interface.bad_header):
                        interface.print_error('joining chain', interface.bad)
                    elif branch.parent().check_header(header):
                        interface.print_error('reorg', interface.bad, interface.tip)
                        interface.blockchain = branch.parent()
                    else:
                        # should not happen
                        raise BaseException('error')
                    next_height = None
                else:
                    bh = interface.blockchain.height()
                    next_height = None
                    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)
                                self.blockchains[interface.bad] = b
                                interface.blockchain = b
                                interface.print_error("new chain", b.checkpoint)
                                interface.mode = 'catch_up'
                                next_height = interface.bad + 1
                                interface.blockchain.catch_up = interface.server
                    else:
                        assert bh == interface.good
                        if interface.blockchain.catch_up is None and bh < interface.tip:
                            interface.print_error("catching up from %d"% (bh + 1))
                            interface.mode = 'catch_up'
                            next_height = bh + 1
                            interface.blockchain.catch_up = interface.server

                self.notify('updated')

        elif interface.mode == 'catch_up':
            can_connect = interface.blockchain.can_connect(header)
            if can_connect:
                interface.blockchain.save_header(header)
                next_height = height + 1 if height < interface.tip else None
            else:
                # go back
                interface.print_error("cannot connect", height)
                interface.mode = 'backward'
                interface.bad = height
                interface.bad_header = header
                next_height = height - 1

            if next_height is None:
                # exit catch_up state
                interface.print_error('catch up done', interface.blockchain.height())
                interface.blockchain.catch_up = None
                self.switch_lagging_interface()
                self.notify('updated')

        elif interface.mode == 'default':
            if not ok:
                interface.print_error("default: cannot connect %d"% height)
                interface.mode = 'backward'
                interface.bad = height
                interface.bad_header = header
                next_height = height - 1
            else:
                interface.print_error("we are ok", height, interface.request)
                next_height = None
        else:
            raise BaseException(interface.mode)
        # If not finished, get the next header
        if next_height:
            if interface.mode == 'catch_up' and interface.tip > next_height + 50:
                self.request_chunk(interface, next_height // 2016)
            else:
                self.request_header(interface, next_height)
        else:
            interface.mode = 'default'
            interface.request = None
            self.notify('updated')
        # refresh network dialog
        self.notify('interfaces')