Updates current tests to work with chain_monitor instead of zmq_sub

This commit is contained in:
Sergi Delgado Segura
2020-01-03 13:36:52 +01:00
parent 3889d30e31
commit 069e15fdba
3 changed files with 81 additions and 96 deletions

View File

@@ -10,6 +10,7 @@ from pisa.watcher import Watcher
from pisa.tools import bitcoin_cli from pisa.tools import bitcoin_cli
from pisa import HOST, PORT from pisa import HOST, PORT
from pisa.conf import MAX_APPOINTMENTS from pisa.conf import MAX_APPOINTMENTS
from pisa.chain_monitor import ChainMonitor
from test.pisa.unit.conftest import ( from test.pisa.unit.conftest import (
generate_block, generate_block,
@@ -37,7 +38,13 @@ def run_api(db_manager):
format=serialization.PrivateFormat.TraditionalOpenSSL, format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(), encryption_algorithm=serialization.NoEncryption(),
) )
watcher = Watcher(db_manager, sk_der)
chain_monitor = ChainMonitor()
chain_monitor.monitor_chain()
watcher = Watcher(db_manager, chain_monitor, sk_der)
chain_monitor.attach_watcher(watcher.block_queue, watcher.asleep)
chain_monitor.attach_responder(watcher.responder.block_queue, watcher.responder.asleep)
api_thread = Thread(target=API(watcher).start) api_thread = Thread(target=API(watcher).start)
api_thread.daemon = True api_thread.daemon = True

View File

@@ -5,15 +5,14 @@ from uuid import uuid4
from shutil import rmtree from shutil import rmtree
from copy import deepcopy from copy import deepcopy
from threading import Thread from threading import Thread
from queue import Queue, Empty
from pisa.db_manager import DBManager from pisa.db_manager import DBManager
from pisa.responder import Responder, TransactionTracker from pisa.responder import Responder, TransactionTracker
from pisa.block_processor import BlockProcessor from pisa.block_processor import BlockProcessor
from pisa.chain_monitor import ChainMonitor
from pisa.tools import bitcoin_cli from pisa.tools import bitcoin_cli
from common.constants import LOCATOR_LEN_HEX from common.constants import LOCATOR_LEN_HEX
from common.tools import check_sha256_hex_format
from bitcoind_mock.utils import sha256d from bitcoind_mock.utils import sha256d
from bitcoind_mock.transaction import TX from bitcoind_mock.transaction import TX
@@ -21,8 +20,19 @@ from test.pisa.unit.conftest import generate_block, generate_blocks, get_random_
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def responder(db_manager): def chain_monitor():
return Responder(db_manager) chain_monitor = ChainMonitor()
chain_monitor.monitor_chain()
return chain_monitor
@pytest.fixture(scope="module")
def responder(db_manager, chain_monitor):
responder = Responder(db_manager, chain_monitor)
chain_monitor.attach_responder(responder.block_queue, responder.asleep)
return responder
@pytest.fixture() @pytest.fixture()
@@ -145,17 +155,19 @@ def test_tracker_from_dict_invalid_data():
def test_init_responder(responder): def test_init_responder(responder):
assert type(responder.trackers) is dict and len(responder.trackers) == 0 assert isinstance(responder.trackers, dict) and len(responder.trackers) == 0
assert type(responder.tx_tracker_map) is dict and len(responder.tx_tracker_map) == 0 assert isinstance(responder.tx_tracker_map, dict) and len(responder.tx_tracker_map) == 0
assert type(responder.unconfirmed_txs) is list and len(responder.unconfirmed_txs) == 0 assert isinstance(responder.unconfirmed_txs, list) and len(responder.unconfirmed_txs) == 0
assert type(responder.missed_confirmations) is dict and len(responder.missed_confirmations) == 0 assert isinstance(responder.missed_confirmations, dict) and len(responder.missed_confirmations) == 0
assert isinstance(responder.chain_monitor, ChainMonitor)
assert responder.block_queue.empty() assert responder.block_queue.empty()
assert responder.asleep is True assert responder.asleep is True
assert responder.zmq_subscriber is None
def test_handle_breach(db_manager): def test_handle_breach(db_manager, chain_monitor):
responder = Responder(db_manager) responder = Responder(db_manager, chain_monitor)
chain_monitor.attach_responder(responder.block_queue, responder.asleep)
uuid = uuid4().hex uuid = uuid4().hex
tracker = create_dummy_tracker() tracker = create_dummy_tracker()
@@ -172,11 +184,10 @@ def test_handle_breach(db_manager):
assert receipt.delivered is True assert receipt.delivered is True
# The responder automatically fires add_tracker on adding a tracker if it is asleep. We need to stop the processes now. # The responder automatically fires add_tracker on adding a tracker if it is asleep. We need to stop the processes
# To do so we delete all the trackers, stop the zmq and create a new fake block to unblock the queue.get method # now. To do so we delete all the trackers, and generate a new block.
responder.trackers = dict() responder.trackers = dict()
responder.zmq_subscriber.terminate = True generate_block()
responder.block_queue.put(get_random_value_hex(32))
def test_add_bad_response(responder): def test_add_bad_response(responder):
@@ -205,7 +216,7 @@ def test_add_bad_response(responder):
def test_add_tracker(responder): def test_add_tracker(responder):
responder.asleep = False # Responder is asleep
for _ in range(20): for _ in range(20):
uuid = uuid4().hex uuid = uuid4().hex
@@ -237,7 +248,8 @@ def test_add_tracker(responder):
def test_add_tracker_same_penalty_txid(responder): def test_add_tracker_same_penalty_txid(responder):
# Create the same tracker using two different uuids # Responder is asleep
confirmations = 0 confirmations = 0
locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end = create_dummy_tracker_data(random_txid=True) locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end = create_dummy_tracker_data(random_txid=True)
uuid_1 = uuid4().hex uuid_1 = uuid4().hex
@@ -264,7 +276,7 @@ def test_add_tracker_same_penalty_txid(responder):
def test_add_tracker_already_confirmed(responder): def test_add_tracker_already_confirmed(responder):
responder.asleep = False # Responder is asleep
for i in range(20): for i in range(20):
uuid = uuid4().hex uuid = uuid4().hex
@@ -278,29 +290,10 @@ def test_add_tracker_already_confirmed(responder):
assert penalty_txid not in responder.unconfirmed_txs assert penalty_txid not in responder.unconfirmed_txs
def test_do_subscribe(responder): def test_do_watch(temp_db_manager, chain_monitor):
responder.block_queue = Queue() # Create a fresh responder to simplify the test
responder = Responder(temp_db_manager, chain_monitor)
zmq_thread = Thread(target=responder.do_subscribe) chain_monitor.attach_responder(responder.block_queue, False)
zmq_thread.daemon = True
zmq_thread.start()
try:
generate_block()
block_hash = responder.block_queue.get()
assert check_sha256_hex_format(block_hash)
except Empty:
assert False
def test_do_watch(temp_db_manager):
responder = Responder(temp_db_manager)
responder.block_queue = Queue()
zmq_thread = Thread(target=responder.do_subscribe)
zmq_thread.daemon = True
zmq_thread.start()
trackers = [create_dummy_tracker(penalty_rawtx=TX.create_dummy_transaction()) for _ in range(20)] trackers = [create_dummy_tracker(penalty_rawtx=TX.create_dummy_transaction()) for _ in range(20)]
@@ -314,9 +307,7 @@ def test_do_watch(temp_db_manager):
responder.unconfirmed_txs.append(tracker.penalty_txid) responder.unconfirmed_txs.append(tracker.penalty_txid)
# Let's start to watch # Let's start to watch
watch_thread = Thread(target=responder.do_watch) Thread(target=responder.do_watch, daemon=True).start()
watch_thread.daemon = True
watch_thread.start()
# And broadcast some of the transactions # And broadcast some of the transactions
broadcast_txs = [] broadcast_txs = []
@@ -324,8 +315,10 @@ def test_do_watch(temp_db_manager):
bitcoin_cli().sendrawtransaction(tracker.penalty_rawtx) bitcoin_cli().sendrawtransaction(tracker.penalty_rawtx)
broadcast_txs.append(tracker.penalty_txid) broadcast_txs.append(tracker.penalty_txid)
print(responder.unconfirmed_txs)
# Mine a block # Mine a block
generate_block() generate_block()
print(responder.unconfirmed_txs)
# The transactions we sent shouldn't be in the unconfirmed transaction list anymore # The transactions we sent shouldn't be in the unconfirmed transaction list anymore
assert not set(broadcast_txs).issubset(responder.unconfirmed_txs) assert not set(broadcast_txs).issubset(responder.unconfirmed_txs)
@@ -350,13 +343,9 @@ def test_do_watch(temp_db_manager):
assert responder.asleep is True assert responder.asleep is True
def test_check_confirmations(temp_db_manager): def test_check_confirmations(temp_db_manager, chain_monitor):
responder = Responder(temp_db_manager) responder = Responder(temp_db_manager, chain_monitor)
responder.block_queue = Queue() chain_monitor.attach_responder(responder.block_queue, responder.asleep)
zmq_thread = Thread(target=responder.do_subscribe)
zmq_thread.daemon = True
zmq_thread.start()
# check_confirmations checks, given a list of transaction for a block, what of the known penalty transaction have # check_confirmations checks, given a list of transaction for a block, what of the known penalty transaction have
# been confirmed. To test this we need to create a list of transactions and the state of the responder # been confirmed. To test this we need to create a list of transactions and the state of the responder
@@ -386,7 +375,7 @@ def test_check_confirmations(temp_db_manager):
assert responder.missed_confirmations[tx] == 1 assert responder.missed_confirmations[tx] == 1
# WIP: Check this properly, a bug pass unnoticed! # TODO: Check this properly, a bug pass unnoticed!
def test_get_txs_to_rebroadcast(responder): def test_get_txs_to_rebroadcast(responder):
# Let's create a few fake txids and assign at least 6 missing confirmations to each # Let's create a few fake txids and assign at least 6 missing confirmations to each
txs_missing_too_many_conf = {get_random_value_hex(32): 6 + i for i in range(10)} txs_missing_too_many_conf = {get_random_value_hex(32): 6 + i for i in range(10)}
@@ -410,13 +399,13 @@ def test_get_txs_to_rebroadcast(responder):
assert txs_to_rebroadcast == list(txs_missing_too_many_conf.keys()) assert txs_to_rebroadcast == list(txs_missing_too_many_conf.keys())
def test_get_completed_trackers(db_manager): def test_get_completed_trackers(db_manager, chain_monitor):
initial_height = bitcoin_cli().getblockcount() initial_height = bitcoin_cli().getblockcount()
# Let's use a fresh responder for this to make it easier to compare the results responder = Responder(db_manager, chain_monitor)
responder = Responder(db_manager) chain_monitor.attach_responder(responder.block_queue, responder.asleep)
# A complete tracker is a tracker that has reached the appointment end with enough confirmations (> MIN_CONFIRMATIONS) # A complete tracker is a tracker that has reached the appointment end with enough confs (> MIN_CONFIRMATIONS)
# We'll create three type of transactions: end reached + enough conf, end reached + no enough conf, end not reached # We'll create three type of transactions: end reached + enough conf, end reached + no enough conf, end not reached
trackers_end_conf = { trackers_end_conf = {
uuid4().hex: create_dummy_tracker(penalty_rawtx=TX.create_dummy_transaction()) for _ in range(10) uuid4().hex: create_dummy_tracker(penalty_rawtx=TX.create_dummy_transaction()) for _ in range(10)
@@ -461,9 +450,10 @@ def test_get_completed_trackers(db_manager):
assert set(completed_trackers_ids) == set(ended_trackers_keys) assert set(completed_trackers_ids) == set(ended_trackers_keys)
def test_rebroadcast(db_manager): def test_rebroadcast(db_manager, chain_monitor):
responder = Responder(db_manager) responder = Responder(db_manager, chain_monitor)
responder.asleep = False responder.asleep = False
chain_monitor.attach_responder(responder.block_queue, responder.asleep)
txs_to_rebroadcast = [] txs_to_rebroadcast = []

View File

@@ -1,22 +1,15 @@
import pytest import pytest
from uuid import uuid4 from uuid import uuid4
from threading import Thread from threading import Thread
from queue import Queue, Empty
from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives import serialization
from pisa.watcher import Watcher from pisa.watcher import Watcher
from pisa.responder import Responder from pisa.responder import Responder
from pisa.tools import bitcoin_cli from pisa.tools import bitcoin_cli
from test.pisa.unit.conftest import ( from test.pisa.unit.conftest import generate_blocks, generate_dummy_appointment, get_random_value_hex, generate_keypair
generate_block, from pisa.chain_monitor import ChainMonitor
generate_blocks,
generate_dummy_appointment,
get_random_value_hex,
generate_keypair,
)
from pisa.conf import EXPIRY_DELTA, MAX_APPOINTMENTS from pisa.conf import EXPIRY_DELTA, MAX_APPOINTMENTS
from common.tools import check_sha256_hex_format
from common.cryptographer import Cryptographer from common.cryptographer import Cryptographer
@@ -35,8 +28,20 @@ sk_der = signing_key.private_bytes(
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def watcher(db_manager): def chain_monitor():
return Watcher(db_manager, sk_der) chain_monitor = ChainMonitor()
chain_monitor.monitor_chain()
return chain_monitor
@pytest.fixture(scope="module")
def watcher(db_manager, chain_monitor):
watcher = Watcher(db_manager, chain_monitor, sk_der)
chain_monitor.attach_watcher(watcher.block_queue, watcher.asleep)
chain_monitor.attach_responder(watcher.responder.block_queue, watcher.responder.asleep)
return watcher
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
@@ -67,17 +72,18 @@ def create_appointments(n):
return appointments, locator_uuid_map, dispute_txs return appointments, locator_uuid_map, dispute_txs
def test_init(watcher): def test_init(run_bitcoind, watcher):
assert type(watcher.appointments) is dict and len(watcher.appointments) == 0 assert isinstance(watcher.appointments, dict) and len(watcher.appointments) == 0
assert type(watcher.locator_uuid_map) is dict and len(watcher.locator_uuid_map) == 0 assert isinstance(watcher.locator_uuid_map, dict) and len(watcher.locator_uuid_map) == 0
assert isinstance(watcher.chain_monitor, ChainMonitor)
assert watcher.block_queue.empty() assert watcher.block_queue.empty()
assert watcher.asleep is True assert watcher.asleep is True
assert watcher.max_appointments == MAX_APPOINTMENTS assert watcher.max_appointments == MAX_APPOINTMENTS
assert watcher.zmq_subscriber is None
assert type(watcher.responder) is Responder assert type(watcher.responder) is Responder
def test_add_appointment(run_bitcoind, watcher): def test_add_appointment(watcher):
# The watcher automatically fires do_watch and do_subscribe on adding an appointment if it is asleep (initial state) # The watcher automatically fires do_watch and do_subscribe on adding an appointment if it is asleep (initial state)
# Avoid this by setting the state to awake. # Avoid this by setting the state to awake.
watcher.asleep = False watcher.asleep = False
@@ -121,36 +127,18 @@ def test_add_too_many_appointments(watcher):
assert sig is None assert sig is None
def test_do_subscribe(watcher):
watcher.block_queue = Queue()
zmq_thread = Thread(target=watcher.do_subscribe)
zmq_thread.daemon = True
zmq_thread.start()
try:
generate_block()
block_hash = watcher.block_queue.get()
assert check_sha256_hex_format(block_hash)
except Empty:
assert False
def test_do_watch(watcher): def test_do_watch(watcher):
# We will wipe all the previous data and add 5 appointments # We will wipe all the previous data and add 5 appointments
watcher.appointments, watcher.locator_uuid_map, dispute_txs = create_appointments(APPOINTMENTS) watcher.appointments, watcher.locator_uuid_map, dispute_txs = create_appointments(APPOINTMENTS)
watcher.chain_monitor.watcher_asleep = False
watch_thread = Thread(target=watcher.do_watch) Thread(target=watcher.do_watch, daemon=True).start()
watch_thread.daemon = True
watch_thread.start()
# Broadcast the first two # Broadcast the first two
for dispute_tx in dispute_txs[:2]: for dispute_tx in dispute_txs[:2]:
bitcoin_cli().sendrawtransaction(dispute_tx) bitcoin_cli().sendrawtransaction(dispute_tx)
# After leaving some time for the block to be mined and processed, the number of appointments should have reduced # After generating enough blocks, the number of appointments should have reduced by two
# by two
generate_blocks(START_TIME_OFFSET + END_TIME_OFFSET) generate_blocks(START_TIME_OFFSET + END_TIME_OFFSET)
assert len(watcher.appointments) == APPOINTMENTS - 2 assert len(watcher.appointments) == APPOINTMENTS - 2