commit 702abf6581f8067b955295f30bf5a3ce2d09ba96
parent 3d4c64f9e0dca7d9aa07b165cd504d288317803f
Author: ThomasV <thomasv@electrum.org>
Date: Mon, 17 Jul 2017 19:32:10 +0200
simplification: do not request checkpoint, check headers against all known blockchains
Diffstat:
2 files changed, 57 insertions(+), 62 deletions(-)
diff --git a/lib/blockchain.py b/lib/blockchain.py
@@ -72,7 +72,7 @@ def read_blockchains(config):
blockchains[b.checkpoint] = b
return blockchains
-def get_blockchain(header):
+def check_header(header):
if type(header) is not dict:
return False
for b in blockchains.values():
@@ -80,6 +80,11 @@ def get_blockchain(header):
return b
return False
+def can_connect(header):
+ for b in blockchains.values():
+ if b.can_connect(header):
+ return b
+ return False
class Blockchain(util.PrintError):
diff --git a/lib/network.py b/lib/network.py
@@ -40,7 +40,7 @@ import util
import bitcoin
from bitcoin import *
from interface import Connection, Interface
-from blockchain import read_blockchains, get_blockchain
+import blockchain
from version import ELECTRUM_VERSION, PROTOCOL_VERSION
DEFAULT_PORTS = {'t':'50001', 's':'50002'}
@@ -206,7 +206,7 @@ class Network(util.DaemonThread):
util.DaemonThread.__init__(self)
self.config = SimpleConfig(config) if type(config) == type({}) else config
self.num_server = 10 if not self.config.get('oneserver') else 0
- self.blockchains = read_blockchains(self.config)
+ self.blockchains = blockchain.read_blockchains(self.config)
self.print_error("blockchains", self.blockchains.keys())
self.blockchain_index = config.get('blockchain_index', 0)
if self.blockchain_index not in self.blockchains.keys():
@@ -706,12 +706,13 @@ class Network(util.DaemonThread):
interface.blockchain = None
interface.tip_header = None
interface.tip = 0
- interface.mode = 'checkpoint'
+ interface.mode = 'default'
+ interface.request = None
self.interfaces[server] = interface
- self.request_header(interface, self.get_checkpoint())
+ self.queue_request('blockchain.headers.subscribe', [], interface)
if server == self.default_server:
self.switch_to_interface(server)
- self.notify('interfaces')
+ #self.notify('interfaces')
def maintain_sockets(self):
'''Socket maintenance.'''
@@ -804,24 +805,14 @@ class Network(util.DaemonThread):
interface.print_error("unsolicited header",interface.request, height)
self.connection_down(interface.server)
return
- if interface.mode == 'checkpoint':
- b = get_blockchain(header)
- if b:
- interface.mode = 'default'
- interface.blockchain = b
- self.queue_request('blockchain.headers.subscribe', [], interface)
- else:
- interface.print_error("checkpoint failed")
- self.connection_down(interface.server)
- interface.request = None
- return
- ok = interface.blockchain.check_header(header)
+ chain = blockchain.check_header(header)
if interface.mode == 'backward':
- if ok:
- interface.good = height
- interface.mode = 'binary'
+ 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:
@@ -832,35 +823,43 @@ class Network(util.DaemonThread):
delta = interface.tip - height
next_height = max(0, interface.tip - 2 * delta)
elif interface.mode == 'binary':
- if ok:
+ if chain:
interface.good = height
+ interface.blockchain = chain
else:
interface.bad = height
if interface.bad != interface.good + 1:
next_height = (interface.bad + interface.good) // 2
else:
interface.print_error("can connect at %d"% interface.bad)
- b = self.blockchains.get(interface.bad)
- if b is not None:
- if b.check_header(header):
+ branch = self.blockchains.get(interface.bad)
+ if branch is not None:
+ # should check bad_header. test doesnt work if header == good
+ if branch.check_header(header):
interface.print_error('joining chain', interface.bad)
- interface.blockchain = b
- elif b.parent.check_header(header):
+ elif branch.parent.check_header(header):
interface.print_error('reorg', interface.bad, interface.tip)
- interface.blockchain = b.parent
+ interface.blockchain = branch.parent
else:
# should not happen
raise BaseException('error')
# todo: we should check the tip once catch up is nor
next_height = None
else:
- b = interface.blockchain.fork(interface.bad)
- self.blockchains[interface.bad] = b
- interface.print_error("new chain", b.filename)
- b.catch_up = interface.server
- interface.blockchain = b
- interface.mode = 'catch_up'
- next_height = interface.bad
+ if interface.blockchain.height() > interface.good:
+ self.blockchains[interface.bad] = interface.blockchain.fork(interface.bad)
+ interface.blockchain = b
+ interface.print_error("new chain", b.filename)
+ else:
+ assert interface.blockchain.height() == interface.good
+
+ if interface.blockchain.catch_up is None:
+ interface.mode = 'catch_up'
+ next_height = interface.bad
+ interface.blockchain.catch_up = interface.server
+ else:
+ interface.print_error('already catching up')
+ next_height = None
# todo: garbage collect blockchain objects
self.notify('updated')
@@ -902,6 +901,7 @@ class Network(util.DaemonThread):
else:
interface.mode = 'default'
interface.request = None
+ self.notify('updated')
# refresh network dialog
self.notify('interfaces')
@@ -973,35 +973,25 @@ class Network(util.DaemonThread):
return
interface.tip_header = header
interface.tip = height
- local_height = interface.blockchain.height()
if interface.mode != 'default':
return
- if interface.tip > local_height + 1:
- if interface.blockchain.catch_up is None:
- interface.blockchain.catch_up = interface.server
- interface.mode = 'catch_up' # must transition to search if it does not connect
- self.request_header(interface, local_height + 1)
- else:
- # another interface is catching up
- pass
- elif interface.tip == local_height + 1:
- if interface.blockchain.can_connect(header):
- interface.blockchain.save_header(header)
- self.notify('updated')
- else:
- interface.mode = 'backward'
- interface.bad = height
- self.request_header(interface, local_height)
- else:
- if not interface.blockchain.check_header(header):
- self.print_error("backward", height)
- interface.mode = 'backward'
- interface.bad = height
- self.request_header(interface, height - 1)
- else:
- pass
- self.switch_lagging_interface()
- self.notify('interfaces')
+ 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
+ self.request_header(interface, height - 1) # should be max(heights)
def blockchain(self):
if self.interface and self.interface.blockchain is not None: