Skip to content
Snippets Groups Projects
Commit 2777208d authored by inso's avatar inso
Browse files

Detect blockchain rollback

parent 21219463
No related branches found
No related tags found
No related merge requests found
...@@ -12,7 +12,7 @@ import asyncio ...@@ -12,7 +12,7 @@ import asyncio
from ucoinpy.documents.peer import Peer from ucoinpy.documents.peer import Peer
from ucoinpy.documents.block import Block from ucoinpy.documents.block import Block
from ucoinpy.api import bma from ...tools.decorators import asyncify
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QTimer from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QTimer
from collections import Counter from collections import Counter
...@@ -25,6 +25,7 @@ class Network(QObject): ...@@ -25,6 +25,7 @@ class Network(QObject):
""" """
nodes_changed = pyqtSignal() nodes_changed = pyqtSignal()
new_block_mined = pyqtSignal(int) new_block_mined = pyqtSignal(int)
blockchain_rollback = pyqtSignal(int)
def __init__(self, currency, nodes): def __init__(self, currency, nodes):
""" """
...@@ -40,7 +41,7 @@ class Network(QObject): ...@@ -40,7 +41,7 @@ class Network(QObject):
self.add_node(n) self.add_node(n)
self.currency = currency self.currency = currency
self._must_crawl = False self._must_crawl = False
self._block_found = self.latest_block_hash self._refresh_block_found()
self._timer = QTimer() self._timer = QTimer()
@classmethod @classmethod
...@@ -189,6 +190,10 @@ class Network(QObject): ...@@ -189,6 +190,10 @@ class Network(QObject):
else: else:
return Block.Empty_Hash return Block.Empty_Hash
def _refresh_block_found(self):
self._block_found = {'hash': self.latest_block_hash,
'number': self.latest_block_number}
def check_nodes_sync(self): def check_nodes_sync(self):
""" """
Check nodes sync with the following rules : Check nodes sync with the following rules :
...@@ -334,10 +339,19 @@ class Network(QObject): ...@@ -334,10 +339,19 @@ class Network(QObject):
self.nodes.remove(node) self.nodes.remove(node)
self.nodes_changed.emit() self.nodes_changed.emit()
if node.state == Node.ONLINE:
logging.debug("{0} -> {1}".format(self._block_found[:10], self.latest_block_hash[:10])) logging.debug("{0} -> {1}".format(self._block_found['hash'][:10], self.latest_block_hash[:10]))
if self._block_found != self.latest_block_hash and node.state == Node.ONLINE: if self._block_found['hash'] != self.latest_block_hash:
logging.debug("Latest block changed : {0}".format(self.latest_block_number)) logging.debug("Latest block changed : {0}".format(self.latest_block_number))
self._block_found = self.latest_block_hash # If new latest block is lower than the previously found one
# Do not emit block change for empty block # or if the previously found block is different locally
# than in the main chain, we declare a rollback
if self._block_found['number'] and \
self.latest_block_number <= self._block_found['number'] \
or node.main_chain_previous_block and \
node.main_chain_previous_block['hash'] != self._block_found['hash']:
self._refresh_block_found()
self.blockchain_rollback.emit(self.latest_block_number)
else:
self._refresh_block_found()
self.new_block_mined.emit(self.latest_block_number) self.new_block_mined.emit(self.latest_block_number)
...@@ -5,7 +5,6 @@ Created on 21 févr. 2015 ...@@ -5,7 +5,6 @@ Created on 21 févr. 2015
""" """
from ucoinpy.documents.peer import Peer, Endpoint, BMAEndpoint from ucoinpy.documents.peer import Peer, Endpoint, BMAEndpoint
from ucoinpy.documents.block import Block
from ...tools.exceptions import InvalidNodeCurrency from ...tools.exceptions import InvalidNodeCurrency
from ...tools.decorators import asyncify from ...tools.decorators import asyncify
from ucoinpy.api import bma as bma from ucoinpy.api import bma as bma
...@@ -49,6 +48,7 @@ class Node(QObject): ...@@ -49,6 +48,7 @@ class Node(QObject):
self._uid = uid self._uid = uid
self._pubkey = pubkey self._pubkey = pubkey
self._block = block self._block = block
self.main_chain_previous_block = None
self._state = state self._state = state
self._neighbours = [] self._neighbours = []
self._currency = currency self._currency = currency
...@@ -295,12 +295,29 @@ class Node(QObject): ...@@ -295,12 +295,29 @@ class Node(QObject):
self.state = Node.ONLINE self.state = Node.ONLINE
if not self.block or block_hash != self.block['hash']: if not self.block or block_hash != self.block['hash']:
try:
#TODO: Check previous block
self.main_chain_previous_block = yield from bma.blockchain.Block(conn_handler,
self.block['number']).get()
except ValueError as e:
if '404' in str(e):
self.main_chain_previous_block = None
logging.debug("Error in block reply")
self.changed.emit()
except ClientError:
logging.debug("Client error : {0}".format(self.pubkey))
self.state = Node.OFFLINE
except asyncio.TimeoutError:
logging.debug("Timeout error : {0}".format(self.pubkey))
self.state = Node.OFFLINE
finally:
self.set_block(block_data) self.set_block(block_data)
logging.debug("Changed block {0} -> {1}".format(self.block['number'], logging.debug("Changed block {0} -> {1}".format(self.block['number'],
block_data['number'])) block_data['number']))
self.changed.emit() self.changed.emit()
except ValueError as e: except ValueError as e:
if '404' in str(e): if '404' in str(e):
self.main_chain_previous_block = None
self.set_block(None) self.set_block(None)
logging.debug("Error in block reply") logging.debug("Error in block reply")
self.changed.emit() self.changed.emit()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment