event generator and better ZMQ handling

This commit is contained in:
Lex Berezhny 2020-07-27 10:58:57 -04:00
parent 412ace1c6f
commit dbc0da2817
9 changed files with 385 additions and 290 deletions

View file

@ -15,6 +15,7 @@ import zmq.asyncio
from lbry.conf import Config
from lbry.event import EventController
from lbry.error import LbrycrdEventSubscriptionError
from .database import BlockchainDB
from .ledger import Ledger, RegTestLedger
@ -57,10 +58,13 @@ class Process(asyncio.SubprocessProtocol):
self.ready.set()
ZMQ_BLOCK_EVENT = 'pubhashblock'
class Lbrycrd:
def __init__(self, ledger: Ledger):
self.ledger = ledger
self.ledger, self.conf = ledger, ledger.conf
self.data_dir = self.actual_data_dir = ledger.conf.lbrycrd_dir
if self.is_regtest:
self.actual_data_dir = os.path.join(self.data_dir, 'regtest')
@ -70,14 +74,8 @@ class Lbrycrd:
self.cli_bin = os.path.join(self.bin_dir, 'lbrycrd-cli')
self.protocol = None
self.transport = None
self.hostname = 'localhost'
self.peerport = 9246 + 2 # avoid conflict with default peer port
self.rpcport = 9245 + 2 # avoid conflict with default rpc port
self.rpcuser = 'rpcuser'
self.rpcpassword = 'rpcpassword'
self.subscribed = False
self.subscription: Optional[asyncio.Task] = None
self.subscription_url = 'tcp://127.0.0.1:29000'
self.default_generate_address = None
self._on_block_controller = EventController()
self.on_block = self._on_block_controller.stream
@ -88,7 +86,13 @@ class Lbrycrd:
@classmethod
def temp_regtest(cls):
return cls(RegTestLedger(Config.with_same_dir(tempfile.mkdtemp())))
return cls(RegTestLedger(
Config.with_same_dir(tempfile.mkdtemp()).set(
lbrycrd_rpc_port=9245 + 2, # avoid conflict with default rpc port
lbrycrd_peer_port=9246 + 2, # avoid conflict with default peer port
lbrycrd_zmq_blocks="tcp://127.0.0.1:29000"
)
))
@staticmethod
def get_block_file_name(block_file_number):
@ -106,7 +110,10 @@ class Lbrycrd:
@property
def rpc_url(self):
return f'http://{self.rpcuser}:{self.rpcpassword}@{self.hostname}:{self.rpcport}/'
return (
f'http://{self.conf.lbrycrd_rpc_user}:{self.conf.lbrycrd_rpc_pass}'
f'@{self.conf.lbrycrd_rpc_host}:{self.conf.lbrycrd_rpc_port}/'
)
@property
def exists(self):
@ -153,14 +160,15 @@ class Lbrycrd:
def get_start_command(self, *args):
if self.is_regtest:
args += ('-regtest',)
if self.conf.lbrycrd_zmq_blocks:
args += (f'-zmqpubhashblock={self.conf.lbrycrd_zmq_blocks}',)
return (
self.daemon_bin,
f'-datadir={self.data_dir}',
f'-port={self.peerport}',
f'-rpcport={self.rpcport}',
f'-rpcuser={self.rpcuser}',
f'-rpcpassword={self.rpcpassword}',
f'-zmqpubhashblock={self.subscription_url}',
f'-port={self.conf.lbrycrd_peer_port}',
f'-rpcport={self.conf.lbrycrd_rpc_port}',
f'-rpcuser={self.conf.lbrycrd_rpc_user}',
f'-rpcpassword={self.conf.lbrycrd_rpc_pass}',
'-server', '-printtoconsole',
*args
)
@ -197,12 +205,20 @@ class Lbrycrd:
None, shutil.rmtree, self.data_dir, True
)
def subscribe(self):
async def ensure_subscribable(self):
zmq_notifications = await self.get_zmq_notifications()
subs = {e['type']: e['address'] for e in zmq_notifications}
if ZMQ_BLOCK_EVENT not in subs:
raise LbrycrdEventSubscriptionError(ZMQ_BLOCK_EVENT)
if not self.conf.lbrycrd_zmq_blocks:
self.conf.lbrycrd_zmq_blocks = subs[ZMQ_BLOCK_EVENT]
async def subscribe(self):
if not self.subscribed:
self.subscribed = True
ctx = zmq.asyncio.Context.instance()
sock = ctx.socket(zmq.SUB) # pylint: disable=no-member
sock.connect(self.subscription_url)
sock.connect(self.conf.lbrycrd_zmq_blocks)
sock.subscribe("hashblock")
self.subscription = asyncio.create_task(self.subscription_handler(sock))
@ -242,6 +258,9 @@ class Lbrycrd:
result['error'].update(method=method, params=params)
raise Exception(result['error'])
async def get_zmq_notifications(self):
return await self.rpc("getzmqnotifications")
async def generate(self, blocks):
if self.default_generate_address is None:
self.default_generate_address = await self.get_new_address()

View file

@ -48,9 +48,10 @@ class BlockchainSync(Sync):
async def start(self):
self.db.stop_event.clear()
await self.chain.ensure_subscribable()
self.advance_loop_task = asyncio.create_task(self.advance())
await self.advance_loop_task
self.chain.subscribe()
await self.chain.subscribe()
self.advance_loop_task = asyncio.create_task(self.advance_loop())
self.on_block_subscription = self.chain.on_block.listen(
lambda e: self.advance_loop_event.set()

View file

@ -505,8 +505,8 @@ class CLIConfig(TranscodeConfig):
class Config(CLIConfig):
db_url = String("Database connection URL, uses a local file based SQLite by default.")
processes = Integer(
"Multiprocessing, specify number of processes lbrynet can start (including main process)."
workers = Integer(
"Multiprocessing, specify number of worker processes lbrynet can start (including main process)."
" (-1: threads only, 0: equal to number of CPUs, >1: specific number of processes)", -1
)
console = StringChoice(
@ -615,6 +615,12 @@ class Config(CLIConfig):
comment_server = String("Comment server API URL", "https://comments.lbry.com/api")
# blockchain
lbrycrd_rpc_user = String("Username for connecting to lbrycrd.", "rpcuser")
lbrycrd_rpc_pass = String("Password for connecting to lbrycrd.", "rpcpassword")
lbrycrd_rpc_host = String("Hostname for connecting to lbrycrd.", "localhost")
lbrycrd_rpc_port = Integer("Port for connecting to lbrycrd.", 9245)
lbrycrd_peer_port = Integer("Port for connecting to lbrycrd.", 9246)
lbrycrd_zmq_blocks = String("ZMQ block events address.")
lbrycrd_dir = Path("Directory containing lbrycrd data.", metavar='DIR')
blockchain_name = String("Blockchain name - lbrycrd_main, lbrycrd_regtest, or lbrycrd_testnet", 'lbrycrd_main')
spv_address_filters = Toggle(

View file

@ -88,13 +88,12 @@ class Basic(Console):
s.append('Full Node')
elif isinstance(self.service, LightClient):
s.append('Light Client')
if conf.processes in (-1, 99):
if conf.workers == -1:
s.append('Threads Only')
elif conf.processes == 0:
s.append(f'{os.cpu_count()} Process(es)')
else:
s.append(f'{conf.processes} Process(es)')
s.append(f'({os.cpu_count()} CPU(s) available)')
workers = os.cpu_count() if conf.workers == 0 else conf.workers
s.append(f'{workers} Worker' if workers == 1 else f'{workers} Workers')
s.append(f'({os.cpu_count()} CPUs available)')
print(' '.join(s))
def stopping(self):

View file

@ -81,7 +81,7 @@ class Database:
def __init__(self, ledger: 'Ledger'):
self.url = ledger.conf.db_url_or_default
self.ledger = ledger
self.processes = self._normalize_processes(ledger.conf.processes)
self.workers = self._normalize_worker_processes(ledger.conf.workers)
self.executor: Optional[Executor] = None
self.message_queue = mp.Queue()
self.stop_event = mp.Event()
@ -92,11 +92,11 @@ class Database:
)
@staticmethod
def _normalize_processes(processes):
if processes == 0:
def _normalize_worker_processes(workers):
if workers == 0:
return os.cpu_count()
elif processes > 0:
return processes
elif workers > 0:
return workers
return 1
@classmethod
@ -162,8 +162,8 @@ class Database:
self.message_queue, self.stop_event
)
}
if self.processes > 1 and self.processes != 99:
self.executor = ProcessPoolExecutor(max_workers=self.processes, **kwargs)
if self.workers > 1:
self.executor = ProcessPoolExecutor(max_workers=self.workers, **kwargs)
else:
self.executor = ThreadPoolExecutor(max_workers=1, **kwargs)
return await self.run(q.check_version_and_create_tables)

View file

@ -81,3 +81,5 @@ Code | Name | Message
701 | InvalidExchangeRateResponse | Failed to get exchange rate from {source}: {reason}
702 | CurrencyConversion | {message}
703 | InvalidCurrency | Invalid currency: {currency} is not a supported currency.
**8xx** | Lbrycrd | **Lbrycrd**
811 | LbrycrdEventSubscription | Lbrycrd is not publishing '{event}' events.

View file

@ -398,3 +398,16 @@ class InvalidCurrencyError(CurrencyExchangeError):
def __init__(self, currency):
self.currency = currency
super().__init__(f"Invalid currency: {currency} is not a supported currency.")
class LbrycrdError(BaseError):
"""
**Lbrycrd**
"""
class LbrycrdEventSubscriptionError(LbrycrdError):
def __init__(self, event):
self.event = event
super().__init__(f"Lbrycrd is not publishing '{event}' events.")

View file

@ -742,3 +742,211 @@ class CommandTestCase(IntegrationTestCase):
@staticmethod
def get_address(tx):
return tx['outputs'][0]['address']
class EventGenerator:
def __init__(
self, initial_sync=False, start=None, end=None, block_files=None, claims=None,
takeovers=None, stakes=0, supports=None
):
self.initial_sync = initial_sync
self.block_files = block_files or []
self.claims = claims or []
self.takeovers = takeovers or []
self.stakes = stakes
self.supports = supports or []
self.start_height = start
self.end_height = end
@property
def events(self):
yield from self.blocks_init()
if self.block_files:
yield from self.blocks_main_start()
for block_file in self.block_files:
yield from self.blocks_file(*block_file)
yield from self.blocks_main_finish()
yield from self.spends_steps()
if self.claims:
if not self.initial_sync:
yield from self.claims_init()
yield from self.claims_main_start()
yield from self.claims_insert(self.claims)
if self.initial_sync:
yield from self.generate("blockchain.sync.claims.indexes", ("steps",), 0, None, (8,), (1,))
else:
yield from self.claims_takeovers(self.takeovers)
yield from self.claims_stakes()
yield from self.claims_vacuum()
yield from self.claims_main_finish()
if self.supports:
if not self.initial_sync:
yield from self.supports_init()
yield from self.supports_main_start()
yield from self.supports_insert(self.supports)
if self.initial_sync:
yield from self.generate("blockchain.sync.supports.indexes", ("steps",), 0, None, (3,), (1,))
else:
yield from self.supports_vacuum()
yield from self.supports_main_finish()
def blocks_init(self):
yield from self.generate("blockchain.sync.blocks.init", ("steps",), 0, None, (3,), (1,))
def blocks_main_start(self):
files = len(self.block_files)
blocks = sum([bf[1] for bf in self.block_files])
txs = sum([bf[2] for bf in self.block_files])
claims = sum([c[2] for c in self.claims])
supports = sum([c[2] for c in self.supports])
yield {
"event": "blockchain.sync.blocks.main",
"data": {
"id": 0, "done": (0, 0), "total": (blocks, txs), "units": ("blocks", "txs"),
"starting_height": self.start_height, "ending_height": self.end_height,
"files": files, "claims": claims, "supports": supports
}
}
def blocks_main_finish(self):
yield {
"event": "blockchain.sync.blocks.main",
"data": {"id": 0, "done": (-1, -1)}
}
def blocks_files(self, files):
for file in files:
yield from self.blocks_file(*file)
def blocks_file(self, file, blocks, txs, steps):
for i, step in enumerate(steps):
if i == 0:
yield {
"event": "blockchain.sync.blocks.file",
"data": {
"id": file,
"done": (0, 0),
"total": (blocks, txs),
"units": ("blocks", "txs"),
"label": f"blk0000{file}.dat",
}
}
yield {
"event": "blockchain.sync.blocks.file",
"data": {"id": file, "done": step}
}
def spends_steps(self):
yield from self.generate(
"blockchain.sync.spends.main", ("steps",), 0, None,
(15 if self.initial_sync else 5,),
(1,)
)
def claims_init(self):
yield from self.generate("blockchain.sync.claims.init", ("steps",), 0, None, (4,), (1,))
def claims_main_start(self):
total = (
sum([c[2] for c in self.claims]) +
sum([c[2] for c in self.takeovers]) +
self.stakes
)
yield {
"event": "blockchain.sync.claims.main",
"data": {
"id": 0, "done": (0,),
"total": (total,),
"units": ("claims",)}
}
def claims_main_finish(self):
yield {
"event": "blockchain.sync.claims.main",
"data": {"id": 0, "done": (-1,)}
}
def claims_insert(self, heights):
for start, end, total, count in heights:
yield from self.generate(
"blockchain.sync.claims.insert", ("claims",), start,
f"add claims {start}- {end}", (total,), (count,)
)
def claims_takeovers(self, heights):
for start, end, total, count in heights:
yield from self.generate(
"blockchain.sync.claims.takeovers", ("claims",), 0,
f"mod winner {start}- {end}", (total,), (count,)
)
def claims_stakes(self):
yield from self.generate(
"blockchain.sync.claims.stakes", ("claims",), 0, None, (self.stakes,), (1,)
)
def claims_vacuum(self):
yield from self.generate(
"blockchain.sync.claims.vacuum", ("steps",), 0, None, (2,), (1,)
)
def supports_init(self):
yield from self.generate("blockchain.sync.supports.init", ("steps",), 0, None, (2,), (1,))
def supports_main_start(self):
yield {
"event": "blockchain.sync.supports.main",
"data": {
"id": 0, "done": (0,),
"total": (sum([c[2] for c in self.supports]),),
"units": ("supports",)
}
}
def supports_main_finish(self):
yield {
"event": "blockchain.sync.supports.main",
"data": {"id": 0, "done": (-1,)}
}
def supports_insert(self, heights):
for start, end, total, count in heights:
yield from self.generate(
"blockchain.sync.supports.insert", ("supports",), start,
f"add supprt {start}" if start==end else f"add supprt {start}- {end}",
(total,), (count,)
)
def supports_vacuum(self):
yield from self.generate(
"blockchain.sync.supports.vacuum", ("steps",), 0, None, (1,), (1,)
)
def generate(self, name, units, eid, label, total, steps):
done = (0,)*len(total)
while not all(d >= t for d, t in zip(done, total)):
if done[0] == 0:
first_event = {
"event": name,
"data": {
"id": eid,
"done": done,
"total": total,
"units": units,
}
}
if label is not None:
first_event["data"]["label"] = label
yield first_event
done = tuple(min(d+s, t) for d, s, t in zip(done, steps, total))
yield {
"event": name,
"data": {
"id": eid,
"done": done,
}
}

View file

@ -4,19 +4,19 @@ import asyncio
import tempfile
from unittest import skip
from binascii import hexlify, unhexlify
from typing import List, Optional
from typing import List, Optional, Iterable
from distutils.dir_util import copy_tree, remove_tree
from lbry import Config, Database, RegTestLedger, Transaction, Output, Input
from lbry.crypto.base58 import Base58
from lbry.schema.claim import Stream, Channel
from lbry.schema.support import Support
from lbry.blockchain.script import OutputScript
from lbry.error import LbrycrdEventSubscriptionError
from lbry.blockchain.lbrycrd import Lbrycrd
from lbry.blockchain.sync import BlockchainSync
from lbry.blockchain.dewies import dewies_to_lbc, lbc_to_dewies
from lbry.constants import CENT, COIN
from lbry.testcase import AsyncioTestCase
from lbry.testcase import AsyncioTestCase, EventGenerator
#logging.getLogger('lbry.blockchain').setLevel(logging.DEBUG)
@ -284,26 +284,58 @@ class SyncingBlockchainTestCase(BasicBlockchainTestCase):
self.assertEqual(accepted or [], await self.get_accepted())
class TestLbrycrdEvents(BasicBlockchainTestCase):
class TestLbrycrdEvents(AsyncioTestCase):
async def test_zmq(self):
chain = Lbrycrd.temp_regtest()
chain.ledger.conf.set(lbrycrd_zmq_blocks='')
await chain.ensure()
self.addCleanup(chain.stop)
# lbrycrdr started without zmq
await chain.start()
with self.assertRaises(LbrycrdEventSubscriptionError):
await chain.ensure_subscribable()
await chain.stop()
# lbrycrdr started with zmq, ensure_subscribable updates lbrycrd_zmq_blocks config
await chain.start('-zmqpubhashblock=tcp://127.0.0.1:29000')
self.assertEqual(chain.ledger.conf.lbrycrd_zmq_blocks, '')
await chain.ensure_subscribable()
self.assertEqual(chain.ledger.conf.lbrycrd_zmq_blocks, 'tcp://127.0.0.1:29000')
await chain.stop()
# lbrycrdr started with zmq, ensure_subscribable does not override lbrycrd_zmq_blocks config
chain.ledger.conf.set(lbrycrd_zmq_blocks='')
await chain.start('-zmqpubhashblock=tcp://127.0.0.1:29000')
self.assertEqual(chain.ledger.conf.lbrycrd_zmq_blocks, '')
chain.ledger.conf.set(lbrycrd_zmq_blocks='tcp://external-ip:29000')
await chain.ensure_subscribable()
self.assertEqual(chain.ledger.conf.lbrycrd_zmq_blocks, 'tcp://external-ip:29000')
async def test_block_event(self):
chain = Lbrycrd.temp_regtest()
await chain.ensure()
self.addCleanup(chain.stop)
await chain.start()
msgs = []
self.chain.subscribe()
self.chain.on_block.listen(lambda e: msgs.append(e['msg']))
res = await self.chain.generate(5)
await self.chain.on_block.where(lambda e: e['msg'] == 4)
await chain.subscribe()
chain.on_block.listen(lambda e: msgs.append(e['msg']))
res = await chain.generate(5)
await chain.on_block.where(lambda e: e['msg'] == 4)
self.assertEqual([0, 1, 2, 3, 4], msgs)
self.assertEqual(5, len(res))
self.chain.unsubscribe()
res = await self.chain.generate(2)
chain.unsubscribe()
res = await chain.generate(2)
self.assertEqual(2, len(res))
await asyncio.sleep(0.1) # give some time to "miss" the new block events
self.chain.subscribe()
res = await self.chain.generate(3)
await self.chain.on_block.where(lambda e: e['msg'] == 9)
await chain.subscribe()
res = await chain.generate(3)
await chain.on_block.where(lambda e: e['msg'] == 9)
self.assertEqual(3, len(res))
self.assertEqual([
0, 1, 2, 3, 4,
@ -381,32 +413,6 @@ class TestMultiBlockFileSyncing(BasicBlockchainTestCase):
await self.chain.start(*self.LBRYCRD_ARGS)
@staticmethod
def extract_block_events(name, events):
return sorted([[
p['data']['block_file'],
p['data']['step'],
p['data']['total'],
p['data']['txs_done'],
p['data']['txs_total'],
] for p in events if p['event'] == name])
@staticmethod
def extract_events(name, events):
return sorted([
[p['data']['step'], p['data']['total']]
for p in events if p['event'] == name
])
def assertEventsAlmostEqual(self, actual, expected):
# this is needed because the sample tx data created
# by lbrycrd does not have deterministic number of TXIs,
# which throws off the progress reporting steps.
# adjust the 'actual' to match 'expected' if it's only off by 1:
for e, a in zip(expected, actual):
if a[1] != e[1] and abs(a[1]-e[1]) <= 1:
a[1] = e[1]
self.assertEqual(expected, actual)
async def test_lbrycrd_database_queries(self):
db = self.chain.db
@ -461,148 +467,65 @@ class TestMultiBlockFileSyncing(BasicBlockchainTestCase):
for c in await db.get_support_metadata(0, 500)]
)
def assertConsumingEvents(self, events: list, name, units, expectation_generator):
expected_count = 0
for expectation in expectation_generator:
expected_count += len(expectation[2:])
self.assertGreaterEqual(len(events), expected_count)
extracted = []
for _ in range(expected_count):
extracted.append(events.pop(0))
actual = sorted(extracted, key=lambda e: (e["event"], e["data"]["id"], e["data"]["done"]))
expected = []
for expectation in expectation_generator:
for i, done in enumerate(expectation[2:]):
if i == 0:
first_event = {
"event": name,
"data": {
"id": expectation[0],
"done": (0,) * len(units),
"total": expectation[2],
"units": units,
}
}
if expectation[1] is not None:
first_event["data"]["label"] = expectation[1]
expected.append(first_event)
else:
expected.append({
"event": name,
"data": {
"id": expectation[0],
"done": done,
}
})
self.assertEqual(expected, actual)
@staticmethod
def sorted_events(events):
sorted_events = []
buffer = []
sort_key = lambda e: (e["event"], e["data"]["id"], e["data"]["done"])
for event in events:
if buffer and event['event'] != buffer[-1]['event']:
buffer.sort(key=sort_key)
sorted_events.extend(buffer)
buffer.clear()
buffer.append(event)
buffer.sort(key=sort_key)
sorted_events.extend(buffer)
return sorted_events
async def test_multi_block_file_sync(self):
events = []
self.sync.on_progress.listen(events.append)
# initial sync
await self.sync.advance()
await asyncio.sleep(1) # give it time to collect events
self.assertConsumingEvents(
events, "blockchain.sync.blocks.init", ("steps",), [
(0, None, (3,), (1,), (2,), (3,))
]
)
self.assertEqual(
events.pop(0), {
"event": "blockchain.sync.blocks.main",
"data": {
"id": 0, "done": (0, 0), "total": (353, 544), "units": ("blocks", "txs"),
"starting_height": 0, "ending_height": 352,
"files": 3, "claims": 3610, "supports": 2
}
}
)
self.assertConsumingEvents(
events, "blockchain.sync.blocks.file", ("blocks", "txs"), [
(0, "blk00000.dat", (191, 280), (100, 0), (191, 280)),
(1, "blk00001.dat", (89, 178), (89, 178)),
(2, "blk00002.dat", (73, 86), (73, 86)),
self.sorted_events(events),
list(EventGenerator(
initial_sync=True,
start=0, end=352,
block_files=[
(0, 191, 280, ((100, 0), (191, 280))),
(1, 89, 178, ((89, 178),)),
(2, 73, 86, ((73, 86),)),
],
claims=[
(102, 120, 361, 361),
(121, 139, 361, 361),
(140, 158, 361, 361),
(159, 177, 361, 361),
(178, 196, 361, 361),
(197, 215, 361, 361),
(216, 234, 361, 361),
(235, 253, 361, 361),
(254, 272, 361, 361),
(273, 291, 361, 361),
],
supports=[
(352, 352, 2, 2),
]
).events)
)
self.assertEqual(
events.pop(0), {
"event": "blockchain.sync.blocks.main",
"data": {"id": 0, "done": (-1, -1)}
}
)
self.assertConsumingEvents(
events, "blockchain.sync.spends.main", ("steps",), [
(0, None, (15,), (1,), (2,), (3,), (4,), (5,), (6,), (7,),
(8,), (9,), (10,), (11,), (12,), (13,), (14,), (15,))
]
)
self.assertEqual(
events.pop(0), {
"event": "blockchain.sync.claims.main",
"data": {"id": 0, "done": (0,), "total": (3610,), "units": ("claims",)}
}
)
self.assertConsumingEvents(
events, "blockchain.sync.claims.insert", ("claims",), [
(102, "add claims 102- 120", (361,), (361,)),
(121, "add claims 121- 139", (361,), (361,)),
(140, "add claims 140- 158", (361,), (361,)),
(159, "add claims 159- 177", (361,), (361,)),
(178, "add claims 178- 196", (361,), (361,)),
(197, "add claims 197- 215", (361,), (361,)),
(216, "add claims 216- 234", (361,), (361,)),
(235, "add claims 235- 253", (361,), (361,)),
(254, "add claims 254- 272", (361,), (361,)),
(273, "add claims 273- 291", (361,), (361,)),
]
)
self.assertConsumingEvents(
events, "blockchain.sync.claims.indexes", ("steps",), [
(0, None, (8,), (1,), (2,), (3,), (4,), (5,), (6,), (7,), (8,))
]
)
self.assertEqual(
events.pop(0), {
"event": "blockchain.sync.claims.main",
"data": {"id": 0, "done": (-1,)}
}
)
self.assertEqual(
events.pop(0), {
"event": "blockchain.sync.supports.main",
"data": {"id": 0, "done": (0,), "total": (2,), "units": ("supports",)}
}
)
self.assertConsumingEvents(
events, "blockchain.sync.supports.insert", ("supports",), [
(352, "add supprt 352", (2,), (2,)),
]
)
self.assertConsumingEvents(
events, "blockchain.sync.supports.indexes", ("steps",), [
(0, None, (3,), (1,), (2,), (3,))
]
)
self.assertEqual(
events.pop(0), {
"event": "blockchain.sync.supports.main",
"data": {"id": 0, "done": (-1,)}
}
)
self.assertEqual(events, [])
# initial_sync = False & no new blocks
events.clear()
await self.sync.advance() # should be no-op
await asyncio.sleep(1) # give it time to collect events
self.assertConsumingEvents(
events, "blockchain.sync.blocks.init", ("steps",), [
(0, None, (3,), (1,), (2,), (3,))
]
)
self.assertEqual(events, [])
self.assertEqual(self.sorted_events(events), list(EventGenerator().events))
# initial_sync = False
events.clear()
txid = await self.chain.claim_name('foo', 'beef', '0.01')
await self.chain.generate(1)
tx = Transaction(unhexlify(await self.chain.get_raw_transaction(txid)))
@ -611,102 +534,26 @@ class TestMultiBlockFileSyncing(BasicBlockchainTestCase):
await self.chain.generate(1)
await self.sync.advance()
await asyncio.sleep(1) # give it time to collect events
self.assertConsumingEvents(
events, "blockchain.sync.blocks.init", ("steps",), [
(0, None, (3,), (1,), (2,), (3,))
]
)
self.assertEqual(
events.pop(0), {
"event": "blockchain.sync.blocks.main",
"data": {
"id": 0, "done": (0, 0), "total": (2, 4), "units": ("blocks", "txs"),
"starting_height": 353, "ending_height": 354,
"files": 1, "claims": 1, "supports": 1
}
}
)
self.assertConsumingEvents(
events, "blockchain.sync.blocks.file", ("blocks", "txs"), [
(2, "blk00002.dat", (2, 4), (2, 4)),
self.sorted_events(events),
list(EventGenerator(
initial_sync=False,
start=353, end=354,
block_files=[
(2, 2, 4, ((2, 4),)),
],
claims=[
(353, 354, 1, 1),
],
takeovers=[
(353, 354, 1, 1),
],
stakes=1,
supports=[
(353, 354, 1, 1),
]
).events)
)
self.assertEqual(
events.pop(0), {
"event": "blockchain.sync.blocks.main",
"data": {"id": 0, "done": (-1, -1)}
}
)
self.assertConsumingEvents(
events, "blockchain.sync.spends.main", ("steps",), [
(0, None, (5,), (1,), (2,), (3,), (4,), (5,))
]
)
self.assertConsumingEvents(
events, "blockchain.sync.claims.init", ("steps",), [
(0, None, (4,), (1,), (2,), (3,), (4,))
]
)
self.assertEqual(
events.pop(0), {
"event": "blockchain.sync.claims.main",
"data": {"id": 0, "done": (0,), "total": (3,), "units": ("claims",)}
}
)
self.assertConsumingEvents(
events, "blockchain.sync.claims.insert", ("claims",), [
(353, "add claims 353- 354", (1,), (1,)),
]
)
self.assertConsumingEvents(
events, "blockchain.sync.claims.takeovers", ("claims",), [
(0, "mod winner 353- 354", (1,), (1,)),
]
)
self.assertConsumingEvents(
events, "blockchain.sync.claims.stakes", ("claims",), [
(0, None, (1,), (1,)),
]
)
self.assertConsumingEvents(
events, "blockchain.sync.claims.vacuum", ("steps",), [
(0, None, (2,), (1,), (2,))
]
)
self.assertEqual(
events.pop(0), {
"event": "blockchain.sync.claims.main",
"data": {"id": 0, "done": (-1,)}
}
)
self.assertConsumingEvents(
events, "blockchain.sync.supports.init", ("steps",), [
(0, None, (2,), (1,), (2,))
]
)
self.assertEqual(
events.pop(0), {
"event": "blockchain.sync.supports.main",
"data": {"id": 0, "done": (0,), "total": (1,), "units": ("supports",)}
}
)
self.assertConsumingEvents(
events, "blockchain.sync.supports.insert", ("supports",), [
(353, "add supprt 353- 354", (1,), (1,)),
]
)
self.assertConsumingEvents(
events, "blockchain.sync.supports.vacuum", ("steps",), [
(0, None, (1,), (1,))
]
)
self.assertEqual(
events.pop(0), {
"event": "blockchain.sync.supports.main",
"data": {"id": 0, "done": (-1,)}
}
)
self.assertEqual(events, [])
class TestGeneralBlockchainSync(SyncingBlockchainTestCase):