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