commit 2fcdd458b3af68b46fd9e7b2f42921c924b9ba9a
parent e6560b8d7f9977bd1b97fdfbd505890faaa20932
Author: ThomasV <thomasv@electrum.org>
Date: Mon, 27 Mar 2017 12:48:10 +0200
add checkpoint dialog to the kivy gui
Diffstat:
4 files changed, 124 insertions(+), 6 deletions(-)
diff --git a/gui/kivy/uix/dialogs/checkpoint_dialog.py b/gui/kivy/uix/dialogs/checkpoint_dialog.py
@@ -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
diff --git a/gui/kivy/uix/dialogs/settings.py b/gui/kivy/uix/dialogs/settings.py
@@ -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)
''')
@@ -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
@@ -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()
diff --git a/gui/qt/network_dialog.py b/gui/qt/network_dialog.py
@@ -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)
@@ -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
diff --git a/lib/blockchain.py b/lib/blockchain.py
@@ -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()
@@ -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+')
@@ -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()