Browse Source

simplification: do not request checkpoint, check headers against all known blockchains

2.9.x
ThomasV 8 years ago
parent
commit
702abf6581
  1. 7
      lib/blockchain.py
  2. 112
      lib/network.py

7
lib/blockchain.py

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

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

Loading…
Cancel
Save