add checkpoint dialog to the kivy gui

This commit is contained in:
ThomasV 2017-03-27 12:48:10 +02:00
parent e6560b8d7f
commit 2fcdd458b3
4 changed files with 124 additions and 6 deletions

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()