Browse Source

async block headers: remove BlockHeaderInterface and Conn classes, make self.height a local

3.3.3.1
Janus 6 years ago
committed by SomberNight
parent
commit
d367199553
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 208
      electrum/interface.py
  2. 132
      electrum/tests/test_network.py

208
electrum/interface.py

@ -171,6 +171,13 @@ class Interface(PrintError):
except ValueError: except ValueError:
return None return None
async def get_block_header(self, height, assert_mode):
res = await asyncio.wait_for(self.session.send_request('blockchain.block.header', [height]), 1)
return blockchain.deserialize_header(bytes.fromhex(res), height)
async def request_chunk(self, idx, tip):
return await self.network.request_chunk(idx, tip, self.session)
async def open_session(self, sslc, exit_early): async def open_session(self, sslc, exit_early):
header_queue = asyncio.Queue() header_queue = asyncio.Queue()
async with NotificationSession(None, header_queue, self.host, self.port, ssl=sslc, proxy=self.proxy) as session: async with NotificationSession(None, header_queue, self.host, self.port, ssl=sslc, proxy=self.proxy) as session:
@ -184,8 +191,7 @@ class Interface(PrintError):
self.mark_ready() self.mark_ready()
self.session = session self.session = session
copy_header_queue = asyncio.Queue() copy_header_queue = asyncio.Queue()
conniface = Conn(self.server, session, lambda idx, tip: self.network.request_chunk(idx, tip, session)) block_retriever = asyncio.get_event_loop().create_task(self.run_fetch_blocks(subscription_res, copy_header_queue))
block_retriever = asyncio.get_event_loop().create_task(self.run_fetch_blocks(subscription_res, copy_header_queue, conniface))
while True: while True:
try: try:
new_header = await asyncio.wait_for(header_queue.get(), 300) new_header = await asyncio.wait_for(header_queue.get(), 300)
@ -195,121 +201,109 @@ class Interface(PrintError):
except concurrent.futures.TimeoutError: except concurrent.futures.TimeoutError:
await asyncio.wait_for(session.send_request('server.ping'), 5) await asyncio.wait_for(session.send_request('server.ping'), 5)
def queue_request(self, method, params, msg_id):
pass
def close(self): def close(self):
self.fut.cancel() self.fut.cancel()
@aiosafe @aiosafe
async def run_fetch_blocks(self, sub_reply, replies, conniface): async def run_fetch_blocks(self, sub_reply, replies):
async with self.network.bhi_lock: async with self.network.bhi_lock:
bhi = BlockHeaderInterface(conniface, self.blockchain.height()+1, self) height = self.blockchain.height()+1
await replies.put(blockchain.deserialize_header(bfh(sub_reply['hex']), sub_reply['height'])) await replies.put(blockchain.deserialize_header(bfh(sub_reply['hex']), sub_reply['height']))
while True: while True:
self.network.notify('updated') self.network.notify('updated')
item = await replies.get() item = await replies.get()
async with self.network.bhi_lock: async with self.network.bhi_lock:
if self.blockchain.height()-1 < item['block_height']: if self.blockchain.height() < item['block_height']-1:
await bhi.sync_until() _, height = await self.sync_until(height, None)
if self.blockchain.height() >= bhi.height and self.blockchain.check_header(item): if self.blockchain.height() >= height and self.blockchain.check_header(item):
# another interface amended the blockchain # another interface amended the blockchain
self.print_error("SKIPPING HEADER", bhi.height) self.print_error("SKIPPING HEADER", height)
continue continue
if self.tip < bhi.height: if self.tip < height:
bhi.height = self.tip height = self.tip
await bhi.step(item) _, height = await self.step(height, item)
self.tip = max(bhi.height, self.tip) self.tip = max(height, self.tip)
class BlockHeaderInterface(PrintError):
def __init__(self, conn, height, iface):
self.height = height
self.conn = conn
self.iface = iface
def diagnostic_name(self):
return self.conn.server
async def sync_until(self, next_height=None): async def sync_until(self, height, next_height=None):
if next_height is None: if next_height is None:
next_height = self.iface.tip next_height = self.tip
last = None last = None
while last is None or self.height < next_height: while last is None or height < next_height:
if next_height > self.height + 10: if next_height > height + 10:
could_connect, num_headers = await self.conn.request_chunk(self.height, next_height) could_connect, num_headers = await self.request_chunk(height, next_height)
self.iface.tip = max(self.height + num_headers, self.iface.tip) self.tip = max(height + num_headers, self.tip)
if not could_connect: if not could_connect:
if self.height <= self.iface.network.max_checkpoint(): if height <= self.network.max_checkpoint():
raise Exception('server chain conflicts with checkpoints or genesis') raise Exception('server chain conflicts with checkpoints or genesis')
last = await self.step() last, height = await self.step(height)
self.iface.tip = max(self.height, self.iface.tip) self.tip = max(height, self.tip)
continue continue
self.height = (self.height // 2016 * 2016) + num_headers height = (height // 2016 * 2016) + num_headers
if self.height > next_height: if height > next_height:
assert False, (self.height, self.iface.tip) assert False, (height, self.tip)
last = 'catchup' last = 'catchup'
else: else:
last = await self.step() last, height = await self.step(height)
self.iface.tip = max(self.height, self.iface.tip) self.tip = max(height, self.tip)
return last return last, height
async def step(self, header=None): async def step(self, height, header=None):
assert self.height != 0 assert height != 0
if header is None: if header is None:
header = await self.conn.get_block_header(self.height, 'catchup') header = await self.get_block_header(height, 'catchup')
chain = self.iface.blockchain.check_header(header) if 'mock' not in header else header['mock']['check'](header) chain = self.blockchain.check_header(header) if 'mock' not in header else header['mock']['check'](header)
if chain: return 'catchup' if chain: return 'catchup', height
can_connect = blockchain.can_connect(header) if 'mock' not in header else header['mock']['connect'](self) can_connect = blockchain.can_connect(header) if 'mock' not in header else header['mock']['connect'](height)
bad_header = None bad_header = None
if not can_connect: if not can_connect:
self.print_error("can't connect", self.height) self.print_error("can't connect", height)
#backward #backward
bad = self.height bad = height
bad_header = header bad_header = header
self.height -= 1 height -= 1
checkp = False checkp = False
if self.height <= self.iface.network.max_checkpoint(): if height <= self.network.max_checkpoint():
self.height = self.iface.network.max_checkpoint() + 1 height = self.network.max_checkpoint() + 1
checkp = True checkp = True
header = await self.conn.get_block_header(self.height, 'backward') header = await self.get_block_header(height, 'backward')
chain = blockchain.check_header(header) if 'mock' not in header else header['mock']['check'](header) chain = blockchain.check_header(header) if 'mock' not in header else header['mock']['check'](header)
can_connect = blockchain.can_connect(header) if 'mock' not in header else header['mock']['connect'](self) can_connect = blockchain.can_connect(header) if 'mock' not in header else header['mock']['connect'](height)
if checkp: if checkp:
assert can_connect or chain, (can_connect, chain) assert can_connect or chain, (can_connect, chain)
while not chain and not can_connect: while not chain and not can_connect:
bad = self.height bad = height
bad_header = header bad_header = header
delta = self.iface.tip - self.height delta = self.tip - height
next_height = self.iface.tip - 2 * delta next_height = self.tip - 2 * delta
checkp = False checkp = False
if next_height <= self.iface.network.max_checkpoint(): if next_height <= self.network.max_checkpoint():
next_height = self.iface.network.max_checkpoint() + 1 next_height = self.network.max_checkpoint() + 1
checkp = True checkp = True
self.height = next_height height = next_height
header = await self.conn.get_block_header(self.height, 'backward') header = await self.get_block_header(height, 'backward')
chain = blockchain.check_header(header) if 'mock' not in header else header['mock']['check'](header) chain = blockchain.check_header(header) if 'mock' not in header else header['mock']['check'](header)
can_connect = blockchain.can_connect(header) if 'mock' not in header else header['mock']['connect'](self) can_connect = blockchain.can_connect(header) if 'mock' not in header else header['mock']['connect'](height)
if checkp: if checkp:
assert can_connect or chain, (can_connect, chain) assert can_connect or chain, (can_connect, chain)
self.print_error("exiting backward mode at", self.height) self.print_error("exiting backward mode at", height)
if can_connect: if can_connect:
self.print_error("could connect", self.height) self.print_error("could connect", height)
chain = blockchain.check_header(header) if 'mock' not in header else header['mock']['check'](header) chain = blockchain.check_header(header) if 'mock' not in header else header['mock']['check'](header)
if type(can_connect) is bool: if type(can_connect) is bool:
# mock # mock
self.height += 1 height += 1
if self.height > self.iface.tip: if height > self.tip:
assert False assert False
return 'catchup' return 'catchup', height
self.iface.blockchain = can_connect self.blockchain = can_connect
self.height += 1 height += 1
self.iface.blockchain.save_header(header) self.blockchain.save_header(header)
return 'catchup' return 'catchup', height
if not chain: if not chain:
raise Exception("not chain") # line 931 in 8e69174374aee87d73cd2f8005fbbe87c93eee9c's network.py raise Exception("not chain") # line 931 in 8e69174374aee87d73cd2f8005fbbe87c93eee9c's network.py
@ -318,27 +312,27 @@ class BlockHeaderInterface(PrintError):
if type(chain) in [int, bool]: if type(chain) in [int, bool]:
pass # mock pass # mock
else: else:
self.iface.blockchain = chain self.blockchain = chain
good = self.height good = height
self.height = (bad + good) // 2 height = (bad + good) // 2
header = await self.conn.get_block_header(self.height, 'binary') header = await self.get_block_header(height, 'binary')
while True: while True:
self.print_error("binary step") self.print_error("binary step")
chain = blockchain.check_header(header) if 'mock' not in header else header['mock']['check'](header) chain = blockchain.check_header(header) if 'mock' not in header else header['mock']['check'](header)
if chain: if chain:
assert bad != self.height, (bad, self.height) assert bad != height, (bad, height)
good = self.height good = height
self.iface.blockchain = self.iface.blockchain if type(chain) in [bool, int] else chain self.blockchain = self.blockchain if type(chain) in [bool, int] else chain
else: else:
bad = self.height bad = height
assert good != self.height assert good != height
bad_header = header bad_header = header
if bad != good + 1: if bad != good + 1:
self.height = (bad + good) // 2 height = (bad + good) // 2
header = await self.conn.get_block_header(self.height, 'binary') header = await self.get_block_header(height, 'binary')
continue continue
mock = bad_header and 'mock' in bad_header and bad_header['mock']['connect'](self) mock = bad_header and 'mock' in bad_header and bad_header['mock']['connect'](height)
real = not mock and self.iface.blockchain.can_connect(bad_header, check_height=False) real = not mock and self.blockchain.can_connect(bad_header, check_height=False)
if not real and not mock: if not real and not mock:
raise Exception('unexpected bad header during binary' + str(bad_header)) # line 948 in 8e69174374aee87d73cd2f8005fbbe87c93eee9c's network.py raise Exception('unexpected bad header during binary' + str(bad_header)) # line 948 in 8e69174374aee87d73cd2f8005fbbe87c93eee9c's network.py
branch = blockchain.blockchains.get(bad) branch = blockchain.blockchains.get(bad)
@ -354,58 +348,48 @@ class BlockHeaderInterface(PrintError):
# electrum runtime # electrum runtime
if ismocking and branch['check'](bad_header) or not ismocking and branch.check_header(bad_header): if ismocking and branch['check'](bad_header) or not ismocking and branch.check_header(bad_header):
self.print_error('joining chain', bad) self.print_error('joining chain', bad)
self.height += 1 height += 1
return 'join' return 'join', height
else: else:
if ismocking and branch['parent']['check'](header) or not ismocking and branch.parent().check_header(header): if ismocking and branch['parent']['check'](header) or not ismocking and branch.parent().check_header(header):
self.print_error('reorg', bad, self.iface.tip) self.print_error('reorg', bad, self.tip)
self.iface.blockchain = branch.parent() if not ismocking else branch['parent'] self.blockchain = branch.parent() if not ismocking else branch['parent']
self.height = bad height = bad
header = await self.conn.get_block_header(self.height, 'binary') header = await self.get_block_header(height, 'binary')
else: else:
if ismocking: if ismocking:
self.height = bad + 1 height = bad + 1
self.print_error("TODO replace blockchain") self.print_error("TODO replace blockchain")
return 'conflict' return 'conflict', height
self.print_error('forkpoint conflicts with existing fork', branch.path()) self.print_error('forkpoint conflicts with existing fork', branch.path())
branch.write(b'', 0) branch.write(b'', 0)
branch.save_header(bad_header) branch.save_header(bad_header)
self.iface.blockchain = branch self.blockchain = branch
self.height = bad + 1 height = bad + 1
return 'conflict' return 'conflict', height
else: else:
bh = self.iface.blockchain.height() bh = self.blockchain.height()
if bh > good: if bh > good:
forkfun = self.iface.blockchain.fork forkfun = self.blockchain.fork
if 'mock' in bad_header: if 'mock' in bad_header:
chain = bad_header['mock']['check'](bad_header) chain = bad_header['mock']['check'](bad_header)
forkfun = bad_header['mock']['fork'] if 'fork' in bad_header['mock'] else forkfun forkfun = bad_header['mock']['fork'] if 'fork' in bad_header['mock'] else forkfun
else: else:
chain = self.iface.blockchain.check_header(bad_header) chain = self.blockchain.check_header(bad_header)
if not chain: if not chain:
b = forkfun(bad_header) b = forkfun(bad_header)
assert bad not in blockchain.blockchains, (bad, list(blockchain.blockchains.keys())) assert bad not in blockchain.blockchains, (bad, list(blockchain.blockchains.keys()))
blockchain.blockchains[bad] = b blockchain.blockchains[bad] = b
self.iface.blockchain = b self.blockchain = b
self.height = b.forkpoint + 1 height = b.forkpoint + 1
assert b.forkpoint == bad assert b.forkpoint == bad
return 'fork' return 'fork', height
else: else:
assert bh == good assert bh == good
if bh < self.iface.tip: if bh < self.tip:
self.print_error("catching up from %d"% (bh + 1)) self.print_error("catching up from %d"% (bh + 1))
self.height = bh + 1 height = bh + 1
return 'no_fork' return 'no_fork', height
class Conn:
def __init__(self, server, session, get_chunk):
self.server = server
self.session = session # type: aiorpcx.ClientSession
self.request_chunk = get_chunk
async def get_block_header(self, height, assert_mode):
res = await asyncio.wait_for(self.session.send_request('blockchain.block.header', [height]), 1)
return blockchain.deserialize_header(bytes.fromhex(res), height)
def check_cert(host, cert): def check_cert(host, cert):
try: try:

132
electrum/tests/test_network.py

@ -5,12 +5,18 @@ import unittest
from electrum.constants import set_regtest from electrum.constants import set_regtest
from electrum.simple_config import SimpleConfig from electrum.simple_config import SimpleConfig
from electrum import blockchain from electrum import blockchain
from electrum.interface import BlockHeaderInterface from electrum.interface import Interface
class MockConnection: class MockInterface(Interface):
def __init__(self): def __init__(self, config):
self.config = config
super().__init__(None, 'mock-server:50000:t', self.config.electrum_path(), None)
class FakeNetwork:
max_checkpoint = lambda: 0
self.network = FakeNetwork
self.q = asyncio.Queue() self.q = asyncio.Queue()
self.server = 'mock-server' self.blockchain = blockchain.Blockchain(self.config, 2002, None)
self.tip = 12
async def get_block_header(self, height, assert_mode): async def get_block_header(self, height, assert_mode):
assert self.q.qsize() > 0, (height, assert_mode) assert self.q.qsize() > 0, (height, assert_mode)
item = await self.q.get() item = await self.q.get()
@ -22,76 +28,63 @@ class MockConnection:
class TestNetwork(unittest.TestCase): class TestNetwork(unittest.TestCase):
def setUp(self): def setUp(self):
self.config = SimpleConfig({'electrum_path': tempfile.mkdtemp(prefix="test_network")}) self.config = SimpleConfig({'electrum_path': tempfile.mkdtemp(prefix="test_network")})
self.interface = MockInterface(self.config)
def blockchain_iface_pair(self, forkpoint=2002):
b = blockchain.Blockchain(self.config, forkpoint, None)
class FakeNetwork:
max_checkpoint = lambda: 0
class FakeIface:
blockchain = b
network = FakeNetwork
tip = 12
return FakeIface
def test_new_fork(self): def test_new_fork(self):
blockchain.blockchains = {} blockchain.blockchains = {}
conn = MockConnection() self.interface.q.put_nowait({'block_height': 8, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: False}})
conn.q.put_nowait({'block_height': 8, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: False}}) def mock_connect(height):
def mock_connect(block_header_iface): return height == 6
return block_header_iface.height == 6 self.interface.q.put_nowait({'block_height': 7, 'mock': {'backward':1,'check': lambda x: False, 'connect': mock_connect, 'fork': self.mock_fork}})
conn.q.put_nowait({'block_height': 7, 'mock': {'backward':1,'check': lambda x: False, 'connect': mock_connect, 'fork': self.mock_fork}}) self.interface.q.put_nowait({'block_height': 2, 'mock': {'backward':1,'check':lambda x: True, 'connect': lambda x: False}})
conn.q.put_nowait({'block_height': 2, 'mock': {'backward':1,'check':lambda x: True, 'connect': lambda x: False}}) self.interface.q.put_nowait({'block_height': 4, 'mock': {'binary':1,'check':lambda x: True, 'connect': lambda x: True}})
conn.q.put_nowait({'block_height': 4, 'mock': {'binary':1,'check':lambda x: True, 'connect': lambda x: True}}) self.interface.q.put_nowait({'block_height': 5, 'mock': {'binary':1,'check':lambda x: True, 'connect': lambda x: True}})
conn.q.put_nowait({'block_height': 5, 'mock': {'binary':1,'check':lambda x: True, 'connect': lambda x: True}}) self.interface.q.put_nowait({'block_height': 6, 'mock': {'binary':1,'check':lambda x: True, 'connect': lambda x: True}})
conn.q.put_nowait({'block_height': 6, 'mock': {'binary':1,'check':lambda x: True, 'connect': lambda x: True}}) ifa = self.interface
ifa = BlockHeaderInterface(conn, 8, self.blockchain_iface_pair()) self.assertEqual(('fork', 8), asyncio.get_event_loop().run_until_complete(ifa.sync_until(8, next_height=8)))
self.assertEqual('fork', asyncio.get_event_loop().run_until_complete(ifa.sync_until(next_height=8))) self.assertEqual(self.interface.q.qsize(), 0)
self.assertEqual(conn.q.qsize(), 0)
def test_new_can_connect_during_backward(self): def test_new_can_connect_during_backward(self):
blockchain.blockchains = {} blockchain.blockchains = {}
conn = MockConnection() self.interface.q.put_nowait({'block_height': 8, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: False}})
conn.q.put_nowait({'block_height': 8, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: False}}) def mock_connect(height):
def mock_connect(block_header_iface): return height == 2
return block_header_iface.height == 2 self.interface.q.put_nowait({'block_height': 7, 'mock': {'backward':1, 'check': lambda x: False, 'connect': mock_connect, 'fork': self.mock_fork}})
conn.q.put_nowait({'block_height': 7, 'mock': {'backward':1, 'check': lambda x: False, 'connect': mock_connect, 'fork': self.mock_fork}}) self.interface.q.put_nowait({'block_height': 2, 'mock': {'backward':1, 'check': lambda x: False, 'connect': mock_connect, 'fork': self.mock_fork}})
conn.q.put_nowait({'block_height': 2, 'mock': {'backward':1, 'check': lambda x: False, 'connect': mock_connect, 'fork': self.mock_fork}}) self.interface.q.put_nowait({'block_height': 3, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: True}})
conn.q.put_nowait({'block_height': 3, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: True}}) self.interface.q.put_nowait({'block_height': 4, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: True}})
conn.q.put_nowait({'block_height': 4, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: True}}) ifa = self.interface
ifa = BlockHeaderInterface(conn, 8, self.blockchain_iface_pair()) self.assertEqual(('catchup', 5), asyncio.get_event_loop().run_until_complete(ifa.sync_until(8, next_height=5)))
self.assertEqual('catchup', asyncio.get_event_loop().run_until_complete(ifa.sync_until(next_height=5))) self.assertEqual(self.interface.q.qsize(), 0)
self.assertEqual(conn.q.qsize(), 0)
def mock_fork(self, bad_header): def mock_fork(self, bad_header):
return blockchain.Blockchain(self.config, bad_header['block_height'], None) return blockchain.Blockchain(self.config, bad_header['block_height'], None)
def test_new_chain_false_during_binary(self): def test_new_chain_false_during_binary(self):
blockchain.blockchains = {} blockchain.blockchains = {}
conn = MockConnection() self.interface.q.put_nowait({'block_height': 8, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: False}})
conn.q.put_nowait({'block_height': 8, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: False}}) mock_connect = lambda height: height == 3
mock_connect = lambda bhi: bhi.height == 3 self.interface.q.put_nowait({'block_height': 7, 'mock': {'backward':1, 'check': lambda x: False, 'connect': mock_connect}})
conn.q.put_nowait({'block_height': 7, 'mock': {'backward':1, 'check': lambda x: False, 'connect': mock_connect}}) self.interface.q.put_nowait({'block_height': 2, 'mock': {'backward':1, 'check': lambda x: True, 'connect': mock_connect}})
conn.q.put_nowait({'block_height': 2, 'mock': {'backward':1, 'check': lambda x: True, 'connect': mock_connect}}) self.interface.q.put_nowait({'block_height': 4, 'mock': {'binary':1, 'check': lambda x: False, 'fork': self.mock_fork, 'connect': mock_connect}})
conn.q.put_nowait({'block_height': 4, 'mock': {'binary':1, 'check': lambda x: False, 'fork': self.mock_fork, 'connect': mock_connect}}) self.interface.q.put_nowait({'block_height': 3, 'mock': {'binary':1, 'check': lambda x: True, 'connect': lambda x: True}})
conn.q.put_nowait({'block_height': 3, 'mock': {'binary':1, 'check': lambda x: True, 'connect': lambda x: True}}) self.interface.q.put_nowait({'block_height': 5, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: True}})
conn.q.put_nowait({'block_height': 5, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: True}}) self.interface.q.put_nowait({'block_height': 6, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: True}})
conn.q.put_nowait({'block_height': 6, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: True}}) ifa = self.interface
ifa = BlockHeaderInterface(conn, 8, self.blockchain_iface_pair(1000)) self.assertEqual(('catchup', 7), asyncio.get_event_loop().run_until_complete(ifa.sync_until(8, next_height=7)))
self.assertEqual('catchup', asyncio.get_event_loop().run_until_complete(ifa.sync_until(next_height=7))) self.assertEqual(self.interface.q.qsize(), 0)
self.assertEqual(conn.q.qsize(), 0)
def test_new_join(self): def test_new_join(self):
blockchain.blockchains = {7: {'check': lambda bad_header: True}} blockchain.blockchains = {7: {'check': lambda bad_header: True}}
conn = MockConnection() self.interface.q.put_nowait({'block_height': 8, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: False}})
conn.q.put_nowait({'block_height': 8, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: False}}) self.interface.q.put_nowait({'block_height': 7, 'mock': {'backward':1, 'check': lambda x: False, 'connect': lambda height: height == 6}})
conn.q.put_nowait({'block_height': 7, 'mock': {'backward':1, 'check': lambda x: False, 'connect': lambda x: x.height == 6}}) self.interface.q.put_nowait({'block_height': 2, 'mock': {'backward':1, 'check': lambda x: True, 'connect': lambda x: False}})
conn.q.put_nowait({'block_height': 2, 'mock': {'backward':1, 'check': lambda x: True, 'connect': lambda x: False}}) self.interface.q.put_nowait({'block_height': 4, 'mock': {'binary':1, 'check': lambda x: True, 'connect': lambda x: False}})
conn.q.put_nowait({'block_height': 4, 'mock': {'binary':1, 'check': lambda x: True, 'connect': lambda x: False}}) self.interface.q.put_nowait({'block_height': 5, 'mock': {'binary':1, 'check': lambda x: True, 'connect': lambda x: False}})
conn.q.put_nowait({'block_height': 5, 'mock': {'binary':1, 'check': lambda x: True, 'connect': lambda x: False}}) self.interface.q.put_nowait({'block_height': 6, 'mock': {'binary':1, 'check': lambda x: True, 'connect': lambda x: True}})
conn.q.put_nowait({'block_height': 6, 'mock': {'binary':1, 'check': lambda x: True, 'connect': lambda x: True}}) ifa = self.interface
ifa = BlockHeaderInterface(conn, 8, self.blockchain_iface_pair()) self.assertEqual(('join', 7), asyncio.get_event_loop().run_until_complete(ifa.sync_until(8, next_height=7)))
self.assertEqual('join', asyncio.get_event_loop().run_until_complete(ifa.sync_until(next_height=7))) self.assertEqual(self.interface.q.qsize(), 0)
self.assertEqual(conn.q.qsize(), 0)
def test_new_reorg(self): def test_new_reorg(self):
times = 0 times = 0
@ -101,17 +94,16 @@ class TestNetwork(unittest.TestCase):
times += 1 times += 1
return times != 1 return times != 1
blockchain.blockchains = {7: {'check': check, 'parent': {'check': lambda x: True}}} blockchain.blockchains = {7: {'check': check, 'parent': {'check': lambda x: True}}}
conn = MockConnection() self.interface.q.put_nowait({'block_height': 8, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: False}})
conn.q.put_nowait({'block_height': 8, 'mock': {'catchup':1, 'check': lambda x: False, 'connect': lambda x: False}}) self.interface.q.put_nowait({'block_height': 7, 'mock': {'backward':1, 'check': lambda x: False, 'connect': lambda height: height == 6}})
conn.q.put_nowait({'block_height': 7, 'mock': {'backward':1, 'check': lambda x: False, 'connect': lambda x: x.height == 6}}) self.interface.q.put_nowait({'block_height': 2, 'mock': {'backward':1, 'check': lambda x: 1, 'connect': lambda x: False}})
conn.q.put_nowait({'block_height': 2, 'mock': {'backward':1, 'check': lambda x: 1, 'connect': lambda x: False}}) self.interface.q.put_nowait({'block_height': 4, 'mock': {'binary':1, 'check': lambda x: 1, 'connect': lambda x: False}})
conn.q.put_nowait({'block_height': 4, 'mock': {'binary':1, 'check': lambda x: 1, 'connect': lambda x: False}}) self.interface.q.put_nowait({'block_height': 5, 'mock': {'binary':1, 'check': lambda x: 1, 'connect': lambda x: False}})
conn.q.put_nowait({'block_height': 5, 'mock': {'binary':1, 'check': lambda x: 1, 'connect': lambda x: False}}) self.interface.q.put_nowait({'block_height': 6, 'mock': {'binary':1, 'check': lambda x: 1, 'connect': lambda x: True}})
conn.q.put_nowait({'block_height': 6, 'mock': {'binary':1, 'check': lambda x: 1, 'connect': lambda x: True}}) self.interface.q.put_nowait({'block_height': 7, 'mock': {'binary':1, 'check': lambda x: False, 'connect': lambda x: True}})
conn.q.put_nowait({'block_height': 7, 'mock': {'binary':1, 'check': lambda x: False, 'connect': lambda x: True}}) ifa = self.interface
ifa = BlockHeaderInterface(conn, 8, self.blockchain_iface_pair()) self.assertEqual(('join', 8), asyncio.get_event_loop().run_until_complete(ifa.sync_until(8, next_height=8)))
self.assertEqual('join', asyncio.get_event_loop().run_until_complete(ifa.sync_until(next_height=8))) self.assertEqual(self.interface.q.qsize(), 0)
self.assertEqual(conn.q.qsize(), 0)
self.assertEqual(times, 2) self.assertEqual(times, 2)
if __name__=="__main__": if __name__=="__main__":

Loading…
Cancel
Save