1
0

wallet: put Sync and Verifier in their own TaskGroup, and that into interface.group

This commit is contained in:
SomberNight
2018-09-11 20:24:01 +02:00
parent 09dfb0fd1d
commit e829d6bbcf
12 changed files with 73 additions and 65 deletions

View File

@@ -26,11 +26,9 @@ import asyncio
import itertools
from collections import defaultdict
from aiorpcx import TaskGroup
from . import bitcoin
from .bitcoin import COINBASE_MATURITY, TYPE_ADDRESS, TYPE_PUBKEY
from .util import PrintError, profiler, bfh, VerifiedTxInfo, TxMinedStatus
from .util import PrintError, profiler, bfh, VerifiedTxInfo, TxMinedStatus, aiosafe, CustomTaskGroup
from .transaction import Transaction, TxOutput
from .synchronizer import Synchronizer
from .verifier import SPV
@@ -62,6 +60,7 @@ class AddressSynchronizer(PrintError):
self.synchronizer = None
self.verifier = None
self.sync_restart_lock = asyncio.Lock()
self.group = None
# locks: if you need to take multiple ones, acquire them in the order they are defined here!
self.lock = threading.RLock()
self.transaction_lock = threading.RLock()
@@ -138,34 +137,45 @@ class AddressSynchronizer(PrintError):
# add it in case it was previously unconfirmed
self.add_unverified_tx(tx_hash, tx_height)
async def on_default_server_changed(self, evt):
@aiosafe
async def on_default_server_changed(self, event):
async with self.sync_restart_lock:
interface = self.network.interface
if interface is None:
return # we should get called again soon
self.verifier = SPV(self.network, self)
self.synchronizer = Synchronizer(self)
await interface.group.spawn(self.verifier.main(interface))
await interface.group.spawn(self.synchronizer.send_subscriptions(interface))
await interface.group.spawn(self.synchronizer.handle_status(interface))
await interface.group.spawn(self.synchronizer.main())
self.stop_threads()
await self._start_threads()
def start_threads(self, network):
def start_network(self, network):
self.network = network
if self.network is not None:
self.network.register_callback(self.on_default_server_changed, ['default_server_changed'])
self.network.trigger_callback('default_server_changed')
else:
self.verifier = None
self.synchronizer = None
asyncio.run_coroutine_threadsafe(self._start_threads(), network.asyncio_loop)
async def _start_threads(self):
interface = self.network.interface
if interface is None:
return # we should get called again soon
self.verifier = SPV(self.network, self)
self.synchronizer = synchronizer = Synchronizer(self)
assert self.group is None, 'group already exists'
self.group = CustomTaskGroup()
async def job():
async with self.group as group:
await group.spawn(self.verifier.main(group))
await group.spawn(self.synchronizer.send_subscriptions(group))
await group.spawn(self.synchronizer.handle_status(group))
await group.spawn(self.synchronizer.main())
# we are being cancelled now
interface.session.unsubscribe(synchronizer.status_queue)
await interface.group.spawn(job)
def stop_threads(self):
if self.network:
#self.network.remove_jobs([self.verifier])
self.synchronizer = None
self.verifier = None
# Now no references to the synchronizer or verifier
# remain so they will be GC-ed
if self.group:
asyncio.run_coroutine_threadsafe(self.group.cancel_remaining(), self.network.asyncio_loop)
self.group = None
self.storage.put('stored_height', self.get_local_height())
self.save_transactions()
self.save_verified_tx()