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