URI: 
       tadd checkpoint dialog to the kivy gui - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 2fcdd458b3af68b46fd9e7b2f42921c924b9ba9a
   DIR parent e6560b8d7f9977bd1b97fdfbd505890faaa20932
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Mon, 27 Mar 2017 12:48:10 +0200
       
       add checkpoint dialog to the kivy gui
       
       Diffstat:
         A gui/kivy/uix/dialogs/checkpoint_di… |      86 ++++++++++++++++++++++++++++++
         M gui/kivy/uix/dialogs/settings.py    |      22 ++++++++++++++++++++++
         M gui/qt/network_dialog.py            |       6 ++----
         M lib/blockchain.py                   |      16 ++++++++++++++--
       
       4 files changed, 124 insertions(+), 6 deletions(-)
       ---
   DIR diff --git a/gui/kivy/uix/dialogs/checkpoint_dialog.py b/gui/kivy/uix/dialogs/checkpoint_dialog.py
       t@@ -0,0 +1,86 @@
       +from kivy.app import App
       +from kivy.factory import Factory
       +from kivy.properties import ObjectProperty
       +from kivy.lang import Builder
       +
       +
       +
       +Builder.load_string('''
       +#:import _ electrum_gui.kivy.i18n._
       +
       +<CheckpointDialog@Popup>
       +    id: popup
       +    cp_height: 0
       +    cp_value: ''
       +    title: _('Checkpoint')
       +    size_hint: 0.8, 0.8
       +    pos_hint: {'top':0.9}
       +    BoxLayout:
       +        orientation: 'vertical'
       +        Label:
       +            id: description
       +            text: 'In the event of a blockchain fork, a checkpoint can be used to ensure that you are on the correct blockchain.'
       +            halign: 'left'
       +            text_size: self.width, None
       +            size: self.texture_size
       +        BoxLayout:
       +            orientation: 'horizontal'
       +            size_hint: 1, 0.2
       +            Label:
       +                text: _('Height')
       +                height: '48dp'
       +            TextInput:
       +                id: height_input
       +                text: '%d'%root.cp_height
       +                on_focus: root.on_height_str()
       +        TopLabel:
       +            text: _('Block hash') + ':'
       +        TxHashLabel:
       +            data: root.cp_value
       +        Label:
       +            text: 'Edit the height to fetch a checkpoint from your main server, and check its value from independent sources.'
       +            halign: 'left'
       +            text_size: self.width, None
       +            size: self.texture_size
       +        Widget:
       +            size_hint: 1, 0.3
       +        BoxLayout:
       +            orientation: 'horizontal'
       +            size_hint: 1, 0.2
       +            Button:
       +                text: _('Cancel')
       +                size_hint: 0.5, None
       +                height: '48dp'
       +                on_release: popup.dismiss()
       +            Button:
       +                text: _('OK')
       +                size_hint: 0.5, None
       +                height: '48dp'
       +                on_release:
       +                    root.callback(root.cp_height, root.cp_value)
       +                    popup.dismiss()
       +''')
       +
       +class CheckpointDialog(Factory.Popup):
       +    def __init__(self, network, callback):
       +        Factory.Popup.__init__(self)
       +        self.network = network
       +        self.cp_height, self.cp_value = self.network.blockchain.get_checkpoint()
       +        self.callback = callback
       +
       +    def on_height_str(self):
       +        try:
       +            new_height = int(self.ids.height_input.text)
       +        except:
       +            new_height = 0
       +        if new_height == self.cp_height:
       +            return
       +        try:
       +            header = self.network.synchronous_get(('blockchain.block.get_header', [new_height]), 5)
       +            new_value = self.network.blockchain.hash_header(header)
       +        except BaseException as e:
       +            self.network.print_error(str(e))
       +            new_value = ''
       +        if new_value:
       +            self.cp_height = new_height
       +            self.cp_value = new_value
   DIR diff --git a/gui/kivy/uix/dialogs/settings.py b/gui/kivy/uix/dialogs/settings.py
       t@@ -113,6 +113,12 @@ Builder.load_string('''
                            title: _('Coin selection') + ': ' + self.status
                            description: "Coin selection method"
                            action: partial(root.coinselect_dialog, self)
       +                CardSeparator
       +                SettingsItem:
       +                    status: root.checkpoint_status()
       +                    title: _('Checkpoint') + ': ' + self.status
       +                    description: _("Configure blockchain checkpoint")
       +                    action: partial(root.checkpoint_dialog, self)
        ''')
        
        
       t@@ -134,6 +140,7 @@ class SettingsDialog(Factory.Popup):
                self._language_dialog = None
                self._unit_dialog = None
                self._coinselect_dialog = None
       +        self._checkpoint_dialog = None
        
            def update(self):
                self.wallet = self.app.wallet
       t@@ -177,6 +184,21 @@ class SettingsDialog(Factory.Popup):
                    self._coinselect_dialog = ChoiceDialog(_('Coin selection'), choosers, chooser_name, cb)
                self._coinselect_dialog.open()
        
       +    def checkpoint_status(self):
       +        height, value = self.app.network.blockchain.get_checkpoint()
       +        return "Block %d"% height if height else _("Genesis block")
       +
       +    def checkpoint_dialog(self, item, dt):
       +        from checkpoint_dialog import CheckpointDialog
       +        if self._checkpoint_dialog is None:
       +            def callback(height, value):
       +                if value:
       +                    self.app.network.blockchain.set_checkpoint(height, value)
       +                    item.status = self.checkpoint_status()
       +
       +            self._checkpoint_dialog = CheckpointDialog(self.app.network, callback)
       +        self._checkpoint_dialog.open()
       +
            def network_dialog(self, item, dt):
                if self._network_dialog is None:
                    server, port, protocol, proxy, auto_connect = self.app.network.get_parameters()
   DIR diff --git a/gui/qt/network_dialog.py b/gui/qt/network_dialog.py
       t@@ -192,8 +192,7 @@ class NetworkChoiceLayout(object):
                n = len(network.get_interfaces())
                status = _("Connected to %d nodes.")%n if n else _("Not connected")
                height_str = "%d "%(network.get_local_height()) + _("blocks")
       -        self.checkpoint_height = self.config.get('checkpoint_height', 0)
       -        self.checkpoint_value = self.config.get('checkpoint_value', bitcoin.GENESIS)
       +        self.checkpoint_height, self.checkpoint_value = network.blockchain.get_checkpoint()
                self.cph_label = QLabel(_('Height'))
                self.cph = QLineEdit("%d"%self.checkpoint_height)
                self.cph.setFixedWidth(80)
       t@@ -337,8 +336,7 @@ class NetworkChoiceLayout(object):
                auto_connect = self.autoconnect_cb.isChecked()
        
                self.network.set_parameters(host, port, protocol, proxy, auto_connect)
       -        self.config.set_key('checkpoint_height', self.checkpoint_height)
       -        self.config.set_key('checkpoint_value', self.checkpoint_value)
       +        self.network.blockchain.set_checkpoint(self.checkpoint_height, self.checkpoint_value)
        
            def suggest_proxy(self, found_proxy):
                self.tor_proxy = found_proxy
   DIR diff --git a/lib/blockchain.py b/lib/blockchain.py
       t@@ -37,8 +37,7 @@ class Blockchain(util.PrintError):
            def __init__(self, config, network):
                self.config = config
                self.network = network
       -        self.checkpoint_height = self.config.get('checkpoint_height', 0)
       -        self.checkpoint_hash = self.config.get('checkpoint_value', bitcoin.GENESIS)
       +        self.checkpoint_height, self.checkpoint_hash = self.get_checkpoint()
                self.check_truncate_headers()
                self.set_local_height()
        
       t@@ -189,6 +188,7 @@ class Blockchain(util.PrintError):
                    return
                if self.hash_header(checkpoint) == self.checkpoint_hash:
                    return
       +        self.print_error('checkpoint mismatch:', self.hash_header(checkpoint), self.checkpoint_hash)
                self.print_error('Truncating headers file at height %d'%self.checkpoint_height)
                name = self.path()
                f = open(name, 'rb+')
       t@@ -274,3 +274,15 @@ class Blockchain(util.PrintError):
                except BaseException as e:
                    self.print_error('verify_chunk failed', str(e))
                    return idx - 1
       +
       +    def get_checkpoint(self):
       +        height = self.config.get('checkpoint_height', 0)
       +        value = self.config.get('checkpoint_value', bitcoin.GENESIS)
       +        return (height, value)
       +
       +    def set_checkpoint(self, height, value):
       +        self.checkpoint_height = height
       +        self.checkpoint_hash = value
       +        self.config.set_key('checkpoint_height', height)
       +        self.config.set_key('checkpoint_value', value)
       +        self.check_truncate_headers()