mirror of
https://github.com/aljazceru/python-teos.git
synced 2025-12-17 14:14:22 +01:00
Adaps unit tests. Speeds up tests by removing unnecesary sleeps
This commit is contained in:
@@ -31,17 +31,11 @@ def test_init_appointment(appointment_data):
|
|||||||
# The appointment has no checks whatsoever, since the inspector is the one taking care or that, and the only one
|
# The appointment has no checks whatsoever, since the inspector is the one taking care or that, and the only one
|
||||||
# creating appointments.
|
# creating appointments.
|
||||||
appointment = Appointment(
|
appointment = Appointment(
|
||||||
appointment_data["locator"],
|
appointment_data["locator"], appointment_data["to_self_delay"], appointment_data["encrypted_blob"]
|
||||||
appointment_data["start_time"],
|
|
||||||
appointment_data["end_time"],
|
|
||||||
appointment_data["to_self_delay"],
|
|
||||||
appointment_data["encrypted_blob"],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
appointment_data["locator"] == appointment.locator
|
appointment_data["locator"] == appointment.locator
|
||||||
and appointment_data["start_time"] == appointment.start_time
|
|
||||||
and appointment_data["end_time"] == appointment.end_time
|
|
||||||
and appointment_data["to_self_delay"] == appointment.to_self_delay
|
and appointment_data["to_self_delay"] == appointment.to_self_delay
|
||||||
and appointment_data["encrypted_blob"] == appointment.encrypted_blob
|
and appointment_data["encrypted_blob"] == appointment.encrypted_blob
|
||||||
)
|
)
|
||||||
@@ -49,19 +43,13 @@ def test_init_appointment(appointment_data):
|
|||||||
|
|
||||||
def test_to_dict(appointment_data):
|
def test_to_dict(appointment_data):
|
||||||
appointment = Appointment(
|
appointment = Appointment(
|
||||||
appointment_data["locator"],
|
appointment_data["locator"], appointment_data["to_self_delay"], appointment_data["encrypted_blob"]
|
||||||
appointment_data["start_time"],
|
|
||||||
appointment_data["end_time"],
|
|
||||||
appointment_data["to_self_delay"],
|
|
||||||
appointment_data["encrypted_blob"],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
dict_appointment = appointment.to_dict()
|
dict_appointment = appointment.to_dict()
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
appointment_data["locator"] == dict_appointment["locator"]
|
appointment_data["locator"] == dict_appointment["locator"]
|
||||||
and appointment_data["start_time"] == dict_appointment["start_time"]
|
|
||||||
and appointment_data["end_time"] == dict_appointment["end_time"]
|
|
||||||
and appointment_data["to_self_delay"] == dict_appointment["to_self_delay"]
|
and appointment_data["to_self_delay"] == dict_appointment["to_self_delay"]
|
||||||
and appointment_data["encrypted_blob"] == dict_appointment["encrypted_blob"]
|
and appointment_data["encrypted_blob"] == dict_appointment["encrypted_blob"]
|
||||||
)
|
)
|
||||||
@@ -94,13 +82,9 @@ def test_serialize(appointment_data):
|
|||||||
assert isinstance(serialized_appointment, bytes)
|
assert isinstance(serialized_appointment, bytes)
|
||||||
|
|
||||||
locator = serialized_appointment[:16]
|
locator = serialized_appointment[:16]
|
||||||
start_time = serialized_appointment[16:20]
|
to_self_delay = serialized_appointment[16:20]
|
||||||
end_time = serialized_appointment[20:24]
|
encrypted_blob = serialized_appointment[20:]
|
||||||
to_self_delay = serialized_appointment[24:28]
|
|
||||||
encrypted_blob = serialized_appointment[28:]
|
|
||||||
|
|
||||||
assert binascii.hexlify(locator).decode() == appointment.locator
|
assert binascii.hexlify(locator).decode() == appointment.locator
|
||||||
assert struct.unpack(">I", start_time)[0] == appointment.start_time
|
|
||||||
assert struct.unpack(">I", end_time)[0] == appointment.end_time
|
|
||||||
assert struct.unpack(">I", to_self_delay)[0] == appointment.to_self_delay
|
assert struct.unpack(">I", to_self_delay)[0] == appointment.to_self_delay
|
||||||
assert binascii.hexlify(encrypted_blob).decode() == appointment.encrypted_blob
|
assert binascii.hexlify(encrypted_blob).decode() == appointment.encrypted_blob
|
||||||
|
|||||||
@@ -12,15 +12,14 @@ from bitcoind_mock.transaction import create_dummy_transaction
|
|||||||
|
|
||||||
from teos import DEFAULT_CONF
|
from teos import DEFAULT_CONF
|
||||||
from teos.carrier import Carrier
|
from teos.carrier import Carrier
|
||||||
from teos.tools import bitcoin_cli
|
|
||||||
from teos.users_dbm import UsersDBM
|
from teos.users_dbm import UsersDBM
|
||||||
from teos.gatekeeper import Gatekeeper
|
from teos.gatekeeper import Gatekeeper
|
||||||
from teos.responder import TransactionTracker
|
from teos.responder import TransactionTracker
|
||||||
from teos.block_processor import BlockProcessor
|
from teos.block_processor import BlockProcessor
|
||||||
from teos.appointments_dbm import AppointmentsDBM
|
from teos.appointments_dbm import AppointmentsDBM
|
||||||
|
from teos.extended_appointment import ExtendedAppointment
|
||||||
|
|
||||||
from common.tools import compute_locator
|
from common.tools import compute_locator
|
||||||
from common.appointment import Appointment
|
|
||||||
from common.constants import LOCATOR_LEN_HEX
|
from common.constants import LOCATOR_LEN_HEX
|
||||||
from common.config_loader import ConfigLoader
|
from common.config_loader import ConfigLoader
|
||||||
from common.cryptographer import Cryptographer
|
from common.cryptographer import Cryptographer
|
||||||
@@ -81,8 +80,14 @@ def block_processor():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def gatekeeper(user_db_manager):
|
def gatekeeper(user_db_manager, block_processor):
|
||||||
return Gatekeeper(user_db_manager, get_config().get("DEFAULT_SLOTS"))
|
return Gatekeeper(
|
||||||
|
user_db_manager,
|
||||||
|
block_processor,
|
||||||
|
get_config().get("DEFAULT_SLOTS"),
|
||||||
|
get_config().get("DEFAULT_SUBSCRIPTION_DURATION"),
|
||||||
|
get_config().get("EXPIRY_DELTA"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def generate_keypair():
|
def generate_keypair():
|
||||||
@@ -98,11 +103,21 @@ def get_random_value_hex(nbytes):
|
|||||||
return prv_hex.zfill(2 * nbytes)
|
return prv_hex.zfill(2 * nbytes)
|
||||||
|
|
||||||
|
|
||||||
def generate_block():
|
def generate_block_w_delay():
|
||||||
requests.post(url="http://{}:{}/generate".format(BTC_RPC_HOST, BTC_RPC_PORT), timeout=5)
|
requests.post(url="http://{}:{}/generate".format(BTC_RPC_HOST, BTC_RPC_PORT), timeout=5)
|
||||||
sleep(0.5)
|
sleep(0.5)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_blocks_w_delay(n):
|
||||||
|
for _ in range(n):
|
||||||
|
generate_block()
|
||||||
|
sleep(0.2)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_block():
|
||||||
|
requests.post(url="http://{}:{}/generate".format(BTC_RPC_HOST, BTC_RPC_PORT), timeout=5)
|
||||||
|
|
||||||
|
|
||||||
def generate_blocks(n):
|
def generate_blocks(n):
|
||||||
for _ in range(n):
|
for _ in range(n):
|
||||||
generate_block()
|
generate_block()
|
||||||
@@ -113,38 +128,23 @@ def fork(block_hash):
|
|||||||
requests.post(fork_endpoint, json={"parent": block_hash})
|
requests.post(fork_endpoint, json={"parent": block_hash})
|
||||||
|
|
||||||
|
|
||||||
def generate_dummy_appointment(real_height=True, start_time_offset=5, end_time_offset=30):
|
def generate_dummy_appointment():
|
||||||
if real_height:
|
|
||||||
current_height = bitcoin_cli(bitcoind_connect_params).getblockcount()
|
|
||||||
|
|
||||||
else:
|
|
||||||
current_height = 10
|
|
||||||
|
|
||||||
dispute_tx = create_dummy_transaction()
|
dispute_tx = create_dummy_transaction()
|
||||||
dispute_txid = dispute_tx.tx_id.hex()
|
dispute_txid = dispute_tx.tx_id.hex()
|
||||||
penalty_tx = create_dummy_transaction(dispute_txid)
|
penalty_tx = create_dummy_transaction(dispute_txid)
|
||||||
|
|
||||||
dummy_appointment_data = {
|
|
||||||
"tx": penalty_tx.hex(),
|
|
||||||
"tx_id": dispute_txid,
|
|
||||||
"start_time": current_height + start_time_offset,
|
|
||||||
"end_time": current_height + end_time_offset,
|
|
||||||
"to_self_delay": 20,
|
|
||||||
}
|
|
||||||
|
|
||||||
locator = compute_locator(dispute_txid)
|
locator = compute_locator(dispute_txid)
|
||||||
|
dummy_appointment_data = {"tx": penalty_tx.hex(), "tx_id": dispute_txid, "to_self_delay": 20}
|
||||||
encrypted_blob = Cryptographer.encrypt(dummy_appointment_data.get("tx"), dummy_appointment_data.get("tx_id"))
|
encrypted_blob = Cryptographer.encrypt(dummy_appointment_data.get("tx"), dummy_appointment_data.get("tx_id"))
|
||||||
|
|
||||||
appointment_data = {
|
appointment_data = {
|
||||||
"locator": locator,
|
"locator": locator,
|
||||||
"start_time": dummy_appointment_data.get("start_time"),
|
|
||||||
"end_time": dummy_appointment_data.get("end_time"),
|
|
||||||
"to_self_delay": dummy_appointment_data.get("to_self_delay"),
|
"to_self_delay": dummy_appointment_data.get("to_self_delay"),
|
||||||
"encrypted_blob": encrypted_blob,
|
"encrypted_blob": encrypted_blob,
|
||||||
|
"user_id": get_random_value_hex(16),
|
||||||
}
|
}
|
||||||
|
|
||||||
return Appointment.from_dict(appointment_data), dispute_tx.hex()
|
return ExtendedAppointment.from_dict(appointment_data), dispute_tx.hex()
|
||||||
|
|
||||||
|
|
||||||
def generate_dummy_tracker():
|
def generate_dummy_tracker():
|
||||||
@@ -158,7 +158,7 @@ def generate_dummy_tracker():
|
|||||||
dispute_txid=dispute_txid,
|
dispute_txid=dispute_txid,
|
||||||
penalty_txid=penalty_txid,
|
penalty_txid=penalty_txid,
|
||||||
penalty_rawtx=penalty_rawtx,
|
penalty_rawtx=penalty_rawtx,
|
||||||
appointment_end=100,
|
user_id=get_random_value_hex(16),
|
||||||
)
|
)
|
||||||
|
|
||||||
return TransactionTracker.from_dict(tracker_data)
|
return TransactionTracker.from_dict(tracker_data)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from teos.api import API
|
|||||||
import teos.errors as errors
|
import teos.errors as errors
|
||||||
from teos.watcher import Watcher
|
from teos.watcher import Watcher
|
||||||
from teos.inspector import Inspector
|
from teos.inspector import Inspector
|
||||||
|
from teos.gatekeeper import UserInfo
|
||||||
from teos.appointments_dbm import AppointmentsDBM
|
from teos.appointments_dbm import AppointmentsDBM
|
||||||
from teos.responder import Responder, TransactionTracker
|
from teos.responder import Responder, TransactionTracker
|
||||||
|
|
||||||
@@ -58,10 +59,10 @@ def get_all_db_manager():
|
|||||||
def api(db_manager, carrier, block_processor, gatekeeper, run_bitcoind):
|
def api(db_manager, carrier, block_processor, gatekeeper, run_bitcoind):
|
||||||
sk, pk = generate_keypair()
|
sk, pk = generate_keypair()
|
||||||
|
|
||||||
responder = Responder(db_manager, carrier, block_processor)
|
responder = Responder(db_manager, gatekeeper, carrier, block_processor)
|
||||||
watcher = Watcher(db_manager, block_processor, responder, sk.to_der(), MAX_APPOINTMENTS, config.get("EXPIRY_DELTA"))
|
watcher = Watcher(db_manager, gatekeeper, block_processor, responder, sk.to_der(), MAX_APPOINTMENTS)
|
||||||
inspector = Inspector(block_processor, config.get("MIN_TO_SELF_DELAY"))
|
inspector = Inspector(block_processor, config.get("MIN_TO_SELF_DELAY"))
|
||||||
api = API(config.get("API_HOST"), config.get("API_PORT"), inspector, watcher, gatekeeper)
|
api = API(config.get("API_HOST"), config.get("API_PORT"), inspector, watcher)
|
||||||
|
|
||||||
return api
|
return api
|
||||||
|
|
||||||
@@ -141,8 +142,8 @@ def test_register_json_no_inner_dict(client):
|
|||||||
|
|
||||||
|
|
||||||
def test_add_appointment(api, client, appointment):
|
def test_add_appointment(api, client, appointment):
|
||||||
# Simulate the user registration
|
# Simulate the user registration (end time does not matter here)
|
||||||
api.gatekeeper.registered_users[compressed_client_pk] = {"available_slots": 1}
|
api.watcher.gatekeeper.registered_users[compressed_client_pk] = UserInfo(available_slots=1, subscription_expiry=0)
|
||||||
|
|
||||||
# Properly formatted appointment
|
# Properly formatted appointment
|
||||||
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
||||||
@@ -154,8 +155,8 @@ def test_add_appointment(api, client, appointment):
|
|||||||
|
|
||||||
|
|
||||||
def test_add_appointment_no_json(api, client, appointment):
|
def test_add_appointment_no_json(api, client, appointment):
|
||||||
# Simulate the user registration
|
# Simulate the user registration (end time does not matter here)
|
||||||
api.gatekeeper.registered_users[compressed_client_pk] = {"available_slots": 1}
|
api.watcher.gatekeeper.registered_users[compressed_client_pk] = UserInfo(available_slots=1, subscription_expiry=0)
|
||||||
|
|
||||||
# Properly formatted appointment
|
# Properly formatted appointment
|
||||||
r = client.post(add_appointment_endpoint, data="random_message")
|
r = client.post(add_appointment_endpoint, data="random_message")
|
||||||
@@ -163,8 +164,8 @@ def test_add_appointment_no_json(api, client, appointment):
|
|||||||
|
|
||||||
|
|
||||||
def test_add_appointment_json_no_inner_dict(api, client, appointment):
|
def test_add_appointment_json_no_inner_dict(api, client, appointment):
|
||||||
# Simulate the user registration
|
# Simulate the user registration (end time does not matter here)
|
||||||
api.gatekeeper.registered_users[compressed_client_pk] = {"available_slots": 1}
|
api.watcher.gatekeeper.registered_users[compressed_client_pk] = UserInfo(available_slots=1, subscription_expiry=0)
|
||||||
|
|
||||||
# Properly formatted appointment
|
# Properly formatted appointment
|
||||||
r = client.post(add_appointment_endpoint, json="random_message")
|
r = client.post(add_appointment_endpoint, json="random_message")
|
||||||
@@ -172,8 +173,8 @@ def test_add_appointment_json_no_inner_dict(api, client, appointment):
|
|||||||
|
|
||||||
|
|
||||||
def test_add_appointment_wrong(api, client, appointment):
|
def test_add_appointment_wrong(api, client, appointment):
|
||||||
# Simulate the user registration
|
# Simulate the user registration (end time does not matter here)
|
||||||
api.gatekeeper.registered_users[compressed_client_pk] = 1
|
api.watcher.gatekeeper.registered_users[compressed_client_pk] = UserInfo(available_slots=1, subscription_expiry=0)
|
||||||
|
|
||||||
# Incorrect appointment
|
# Incorrect appointment
|
||||||
appointment.to_self_delay = 0
|
appointment.to_self_delay = 0
|
||||||
@@ -199,8 +200,8 @@ def test_add_appointment_not_registered(api, client, appointment):
|
|||||||
|
|
||||||
|
|
||||||
def test_add_appointment_registered_no_free_slots(api, client, appointment):
|
def test_add_appointment_registered_no_free_slots(api, client, appointment):
|
||||||
# Empty the user slots
|
# Empty the user slots (end time does not matter here)
|
||||||
api.gatekeeper.registered_users[compressed_client_pk] = {"available_slots": 0}
|
api.watcher.gatekeeper.registered_users[compressed_client_pk] = UserInfo(available_slots=0, subscription_expiry=0)
|
||||||
|
|
||||||
# Properly formatted appointment
|
# Properly formatted appointment
|
||||||
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
||||||
@@ -212,8 +213,8 @@ def test_add_appointment_registered_no_free_slots(api, client, appointment):
|
|||||||
|
|
||||||
|
|
||||||
def test_add_appointment_registered_not_enough_free_slots(api, client, appointment):
|
def test_add_appointment_registered_not_enough_free_slots(api, client, appointment):
|
||||||
# Give some slots to the user
|
# Give some slots to the user (end time does not matter here)
|
||||||
api.gatekeeper.registered_users[compressed_client_pk] = 1
|
api.watcher.gatekeeper.registered_users[compressed_client_pk] = UserInfo(available_slots=1, subscription_expiry=0)
|
||||||
|
|
||||||
# Properly formatted appointment
|
# Properly formatted appointment
|
||||||
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
||||||
@@ -232,8 +233,8 @@ def test_add_appointment_multiple_times_same_user(api, client, appointment, n=MU
|
|||||||
# Multiple appointments with the same locator should be valid and counted as updates
|
# Multiple appointments with the same locator should be valid and counted as updates
|
||||||
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
||||||
|
|
||||||
# Simulate registering enough slots
|
# Simulate registering enough slots (end time does not matter here)
|
||||||
api.gatekeeper.registered_users[compressed_client_pk] = {"available_slots": n}
|
api.watcher.gatekeeper.registered_users[compressed_client_pk] = UserInfo(available_slots=n, subscription_expiry=0)
|
||||||
for _ in range(n):
|
for _ in range(n):
|
||||||
r = add_appointment(
|
r = add_appointment(
|
||||||
client, {"appointment": appointment.to_dict(), "signature": appointment_signature}, compressed_client_pk
|
client, {"appointment": appointment.to_dict(), "signature": appointment_signature}, compressed_client_pk
|
||||||
@@ -254,7 +255,7 @@ def test_add_appointment_multiple_times_different_users(api, client, appointment
|
|||||||
# Add one slot per public key
|
# Add one slot per public key
|
||||||
for pair in user_keys:
|
for pair in user_keys:
|
||||||
tmp_compressed_pk = hexlify(pair[1].format(compressed=True)).decode("utf-8")
|
tmp_compressed_pk = hexlify(pair[1].format(compressed=True)).decode("utf-8")
|
||||||
api.gatekeeper.registered_users[tmp_compressed_pk] = {"available_slots": 2}
|
api.watcher.gatekeeper.registered_users[tmp_compressed_pk] = UserInfo(available_slots=2, subscription_expiry=0)
|
||||||
|
|
||||||
# Send the appointments
|
# Send the appointments
|
||||||
for compressed_pk, signature in zip(compressed_pks, signatures):
|
for compressed_pk, signature in zip(compressed_pks, signatures):
|
||||||
@@ -268,10 +269,10 @@ def test_add_appointment_multiple_times_different_users(api, client, appointment
|
|||||||
|
|
||||||
def test_add_appointment_update_same_size(api, client, appointment):
|
def test_add_appointment_update_same_size(api, client, appointment):
|
||||||
# Update an appointment by one of the same size and check that no additional slots are filled
|
# Update an appointment by one of the same size and check that no additional slots are filled
|
||||||
api.gatekeeper.registered_users[compressed_client_pk] = {"available_slots": 1}
|
api.watcher.gatekeeper.registered_users[compressed_client_pk] = UserInfo(available_slots=1, subscription_expiry=0)
|
||||||
|
|
||||||
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
||||||
# # Since we will replace the appointment, we won't added to appointments
|
# Since we will replace the appointment, we won't added to appointments
|
||||||
r = add_appointment(
|
r = add_appointment(
|
||||||
client, {"appointment": appointment.to_dict(), "signature": appointment_signature}, compressed_client_pk
|
client, {"appointment": appointment.to_dict(), "signature": appointment_signature}, compressed_client_pk
|
||||||
)
|
)
|
||||||
@@ -289,7 +290,7 @@ def test_add_appointment_update_same_size(api, client, appointment):
|
|||||||
|
|
||||||
def test_add_appointment_update_bigger(api, client, appointment):
|
def test_add_appointment_update_bigger(api, client, appointment):
|
||||||
# Update an appointment by one bigger, and check additional slots are filled
|
# Update an appointment by one bigger, and check additional slots are filled
|
||||||
api.gatekeeper.registered_users[compressed_client_pk] = {"available_slots": 2}
|
api.watcher.gatekeeper.registered_users[compressed_client_pk] = UserInfo(available_slots=2, subscription_expiry=0)
|
||||||
|
|
||||||
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
||||||
r = add_appointment(
|
r = add_appointment(
|
||||||
@@ -317,8 +318,7 @@ def test_add_appointment_update_bigger(api, client, appointment):
|
|||||||
|
|
||||||
def test_add_appointment_update_smaller(api, client, appointment):
|
def test_add_appointment_update_smaller(api, client, appointment):
|
||||||
# Update an appointment by one bigger, and check slots are freed
|
# Update an appointment by one bigger, and check slots are freed
|
||||||
api.gatekeeper.registered_users[compressed_client_pk] = {"available_slots": 2}
|
api.watcher.gatekeeper.registered_users[compressed_client_pk] = UserInfo(available_slots=2, subscription_expiry=0)
|
||||||
|
|
||||||
# This should take 2 slots
|
# This should take 2 slots
|
||||||
appointment.encrypted_blob = TWO_SLOTS_BLOTS
|
appointment.encrypted_blob = TWO_SLOTS_BLOTS
|
||||||
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
appointment_signature = Cryptographer.sign(appointment.serialize(), client_sk)
|
||||||
@@ -338,7 +338,7 @@ def test_add_appointment_update_smaller(api, client, appointment):
|
|||||||
|
|
||||||
def test_add_too_many_appointment(api, client):
|
def test_add_too_many_appointment(api, client):
|
||||||
# Give slots to the user
|
# Give slots to the user
|
||||||
api.gatekeeper.registered_users[compressed_client_pk] = {"available_slots": 200}
|
api.watcher.gatekeeper.registered_users[compressed_client_pk] = UserInfo(available_slots=200, subscription_expiry=0)
|
||||||
|
|
||||||
free_appointment_slots = MAX_APPOINTMENTS - len(api.watcher.appointments)
|
free_appointment_slots = MAX_APPOINTMENTS - len(api.watcher.appointments)
|
||||||
|
|
||||||
@@ -406,6 +406,8 @@ def test_request_appointment_in_watcher(api, client, appointment):
|
|||||||
assert r.json.get("status") == "being_watched"
|
assert r.json.get("status") == "being_watched"
|
||||||
|
|
||||||
# Check the the sent appointment matches the received one
|
# Check the the sent appointment matches the received one
|
||||||
|
appointment_dict = appointment.to_dict()
|
||||||
|
appointment_dict.pop("user_id")
|
||||||
assert r.json.get("locator") == appointment.locator
|
assert r.json.get("locator") == appointment.locator
|
||||||
assert appointment.to_dict() == r.json.get("appointment")
|
assert appointment.to_dict() == r.json.get("appointment")
|
||||||
|
|
||||||
@@ -417,7 +419,7 @@ def test_request_appointment_in_responder(api, client, appointment):
|
|||||||
"dispute_txid": get_random_value_hex(32),
|
"dispute_txid": get_random_value_hex(32),
|
||||||
"penalty_txid": get_random_value_hex(32),
|
"penalty_txid": get_random_value_hex(32),
|
||||||
"penalty_rawtx": get_random_value_hex(250),
|
"penalty_rawtx": get_random_value_hex(250),
|
||||||
"appointment_end": appointment.end_time,
|
"user_id": get_random_value_hex(16),
|
||||||
}
|
}
|
||||||
tx_tracker = TransactionTracker.from_dict(tracker_data)
|
tx_tracker = TransactionTracker.from_dict(tracker_data)
|
||||||
|
|
||||||
@@ -442,10 +444,9 @@ def test_request_appointment_in_responder(api, client, appointment):
|
|||||||
assert tx_tracker.dispute_txid == r.json.get("appointment").get("dispute_txid")
|
assert tx_tracker.dispute_txid == r.json.get("appointment").get("dispute_txid")
|
||||||
assert tx_tracker.penalty_txid == r.json.get("appointment").get("penalty_txid")
|
assert tx_tracker.penalty_txid == r.json.get("appointment").get("penalty_txid")
|
||||||
assert tx_tracker.penalty_rawtx == r.json.get("appointment").get("penalty_rawtx")
|
assert tx_tracker.penalty_rawtx == r.json.get("appointment").get("penalty_rawtx")
|
||||||
assert tx_tracker.appointment_end == r.json.get("appointment").get("appointment_end")
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_all_appointments_watcher(api, client, get_all_db_manager, appointment):
|
def test_get_all_appointments_watcher(api, client, get_all_db_manager):
|
||||||
# Let's reset the dbs so we can test this clean
|
# Let's reset the dbs so we can test this clean
|
||||||
api.watcher.db_manager = get_all_db_manager
|
api.watcher.db_manager = get_all_db_manager
|
||||||
api.watcher.responder.db_manager = get_all_db_manager
|
api.watcher.responder.db_manager = get_all_db_manager
|
||||||
@@ -459,6 +460,7 @@ def test_get_all_appointments_watcher(api, client, get_all_db_manager, appointme
|
|||||||
non_triggered_appointments = {}
|
non_triggered_appointments = {}
|
||||||
for _ in range(10):
|
for _ in range(10):
|
||||||
uuid = get_random_value_hex(16)
|
uuid = get_random_value_hex(16)
|
||||||
|
appointment, _ = generate_dummy_appointment()
|
||||||
appointment.locator = get_random_value_hex(16)
|
appointment.locator = get_random_value_hex(16)
|
||||||
non_triggered_appointments[uuid] = appointment.to_dict()
|
non_triggered_appointments[uuid] = appointment.to_dict()
|
||||||
api.watcher.db_manager.store_watcher_appointment(uuid, appointment.to_dict())
|
api.watcher.db_manager.store_watcher_appointment(uuid, appointment.to_dict())
|
||||||
@@ -466,6 +468,7 @@ def test_get_all_appointments_watcher(api, client, get_all_db_manager, appointme
|
|||||||
triggered_appointments = {}
|
triggered_appointments = {}
|
||||||
for _ in range(10):
|
for _ in range(10):
|
||||||
uuid = get_random_value_hex(16)
|
uuid = get_random_value_hex(16)
|
||||||
|
appointment, _ = generate_dummy_appointment()
|
||||||
appointment.locator = get_random_value_hex(16)
|
appointment.locator = get_random_value_hex(16)
|
||||||
triggered_appointments[uuid] = appointment.to_dict()
|
triggered_appointments[uuid] = appointment.to_dict()
|
||||||
api.watcher.db_manager.store_watcher_appointment(uuid, appointment.to_dict())
|
api.watcher.db_manager.store_watcher_appointment(uuid, appointment.to_dict())
|
||||||
@@ -501,7 +504,7 @@ def test_get_all_appointments_responder(api, client, get_all_db_manager):
|
|||||||
"dispute_txid": get_random_value_hex(32),
|
"dispute_txid": get_random_value_hex(32),
|
||||||
"penalty_txid": get_random_value_hex(32),
|
"penalty_txid": get_random_value_hex(32),
|
||||||
"penalty_rawtx": get_random_value_hex(250),
|
"penalty_rawtx": get_random_value_hex(250),
|
||||||
"appointment_end": 20,
|
"user_id": get_random_value_hex(16),
|
||||||
}
|
}
|
||||||
tracker = TransactionTracker.from_dict(tracker_data)
|
tracker = TransactionTracker.from_dict(tracker_data)
|
||||||
tx_trackers[uuid] = tracker.to_dict()
|
tx_trackers[uuid] = tracker.to_dict()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from test.teos.unit.conftest import get_random_value_hex, generate_dummy_appoint
|
|||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def watcher_appointments():
|
def watcher_appointments():
|
||||||
return {uuid4().hex: generate_dummy_appointment(real_height=False)[0] for _ in range(10)}
|
return {uuid4().hex: generate_dummy_appointment()[0] for _ in range(10)}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
@@ -215,7 +215,7 @@ def test_store_load_triggered_appointment(db_manager):
|
|||||||
assert db_watcher_appointments == db_watcher_appointments_with_triggered
|
assert db_watcher_appointments == db_watcher_appointments_with_triggered
|
||||||
|
|
||||||
# Create an appointment flagged as triggered
|
# Create an appointment flagged as triggered
|
||||||
triggered_appointment, _ = generate_dummy_appointment(real_height=False)
|
triggered_appointment, _ = generate_dummy_appointment()
|
||||||
uuid = uuid4().hex
|
uuid = uuid4().hex
|
||||||
assert db_manager.store_watcher_appointment(uuid, triggered_appointment.to_dict()) is True
|
assert db_manager.store_watcher_appointment(uuid, triggered_appointment.to_dict()) is True
|
||||||
db_manager.create_triggered_appointment_flag(uuid)
|
db_manager.create_triggered_appointment_flag(uuid)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from queue import Queue
|
|||||||
|
|
||||||
from teos.builder import Builder
|
from teos.builder import Builder
|
||||||
from teos.watcher import Watcher
|
from teos.watcher import Watcher
|
||||||
|
from teos.tools import bitcoin_cli
|
||||||
from teos.responder import Responder
|
from teos.responder import Responder
|
||||||
|
|
||||||
from test.teos.unit.conftest import (
|
from test.teos.unit.conftest import (
|
||||||
@@ -11,7 +12,6 @@ from test.teos.unit.conftest import (
|
|||||||
generate_dummy_appointment,
|
generate_dummy_appointment,
|
||||||
generate_dummy_tracker,
|
generate_dummy_tracker,
|
||||||
generate_block,
|
generate_block,
|
||||||
bitcoin_cli,
|
|
||||||
get_config,
|
get_config,
|
||||||
bitcoind_connect_params,
|
bitcoind_connect_params,
|
||||||
generate_keypair,
|
generate_keypair,
|
||||||
@@ -25,7 +25,7 @@ def test_build_appointments():
|
|||||||
|
|
||||||
# Create some appointment data
|
# Create some appointment data
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
appointment, _ = generate_dummy_appointment(real_height=False)
|
appointment, _ = generate_dummy_appointment()
|
||||||
uuid = uuid4().hex
|
uuid = uuid4().hex
|
||||||
|
|
||||||
appointments_data[uuid] = appointment.to_dict()
|
appointments_data[uuid] = appointment.to_dict()
|
||||||
@@ -33,7 +33,7 @@ def test_build_appointments():
|
|||||||
# Add some additional appointments that share the same locator to test all the builder's cases
|
# Add some additional appointments that share the same locator to test all the builder's cases
|
||||||
if i % 2 == 0:
|
if i % 2 == 0:
|
||||||
locator = appointment.locator
|
locator = appointment.locator
|
||||||
appointment, _ = generate_dummy_appointment(real_height=False)
|
appointment, _ = generate_dummy_appointment()
|
||||||
uuid = uuid4().hex
|
uuid = uuid4().hex
|
||||||
appointment.locator = locator
|
appointment.locator = locator
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ def test_build_appointments():
|
|||||||
for uuid, appointment in appointments.items():
|
for uuid, appointment in appointments.items():
|
||||||
assert uuid in appointments_data.keys()
|
assert uuid in appointments_data.keys()
|
||||||
assert appointments_data[uuid].get("locator") == appointment.get("locator")
|
assert appointments_data[uuid].get("locator") == appointment.get("locator")
|
||||||
assert appointments_data[uuid].get("end_time") == appointment.get("end_time")
|
assert appointments_data[uuid].get("user_id") == appointment.get("user_id")
|
||||||
assert len(appointments_data[uuid].get("encrypted_blob")) == appointment.get("size")
|
assert len(appointments_data[uuid].get("encrypted_blob")) == appointment.get("size")
|
||||||
assert uuid in locator_uuid_map[appointment.get("locator")]
|
assert uuid in locator_uuid_map[appointment.get("locator")]
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ def test_build_trackers():
|
|||||||
|
|
||||||
assert tracker.get("penalty_txid") == trackers_data[uuid].get("penalty_txid")
|
assert tracker.get("penalty_txid") == trackers_data[uuid].get("penalty_txid")
|
||||||
assert tracker.get("locator") == trackers_data[uuid].get("locator")
|
assert tracker.get("locator") == trackers_data[uuid].get("locator")
|
||||||
assert tracker.get("appointment_end") == trackers_data[uuid].get("appointment_end")
|
assert tracker.get("user_id") == trackers_data[uuid].get("user_id")
|
||||||
assert uuid in tx_tracker_map[tracker.get("penalty_txid")]
|
assert uuid in tx_tracker_map[tracker.get("penalty_txid")]
|
||||||
|
|
||||||
|
|
||||||
@@ -95,14 +95,14 @@ def test_populate_block_queue():
|
|||||||
assert len(blocks) == 0
|
assert len(blocks) == 0
|
||||||
|
|
||||||
|
|
||||||
def test_update_states_empty_list(db_manager, carrier, block_processor):
|
def test_update_states_empty_list(db_manager, gatekeeper, carrier, block_processor):
|
||||||
w = Watcher(
|
w = Watcher(
|
||||||
db_manager=db_manager,
|
db_manager=db_manager,
|
||||||
|
gatekeeper=gatekeeper,
|
||||||
block_processor=block_processor,
|
block_processor=block_processor,
|
||||||
responder=Responder(db_manager, carrier, block_processor),
|
responder=Responder(db_manager, gatekeeper, carrier, block_processor),
|
||||||
sk_der=generate_keypair()[0].to_der(),
|
sk_der=generate_keypair()[0].to_der(),
|
||||||
max_appointments=config.get("MAX_APPOINTMENTS"),
|
max_appointments=config.get("MAX_APPOINTMENTS"),
|
||||||
expiry_delta=config.get("EXPIRY_DELTA"),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
missed_blocks_watcher = []
|
missed_blocks_watcher = []
|
||||||
@@ -116,14 +116,14 @@ def test_update_states_empty_list(db_manager, carrier, block_processor):
|
|||||||
Builder.update_states(w, missed_blocks_responder, missed_blocks_watcher)
|
Builder.update_states(w, missed_blocks_responder, missed_blocks_watcher)
|
||||||
|
|
||||||
|
|
||||||
def test_update_states_responder_misses_more(run_bitcoind, db_manager, carrier, block_processor):
|
def test_update_states_responder_misses_more(run_bitcoind, db_manager, gatekeeper, carrier, block_processor):
|
||||||
w = Watcher(
|
w = Watcher(
|
||||||
db_manager=db_manager,
|
db_manager=db_manager,
|
||||||
|
gatekeeper=gatekeeper,
|
||||||
block_processor=block_processor,
|
block_processor=block_processor,
|
||||||
responder=Responder(db_manager, carrier, block_processor),
|
responder=Responder(db_manager, gatekeeper, carrier, block_processor),
|
||||||
sk_der=generate_keypair()[0].to_der(),
|
sk_der=generate_keypair()[0].to_der(),
|
||||||
max_appointments=config.get("MAX_APPOINTMENTS"),
|
max_appointments=config.get("MAX_APPOINTMENTS"),
|
||||||
expiry_delta=config.get("EXPIRY_DELTA"),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
blocks = []
|
blocks = []
|
||||||
@@ -140,15 +140,15 @@ def test_update_states_responder_misses_more(run_bitcoind, db_manager, carrier,
|
|||||||
assert w.responder.last_known_block == blocks[-1]
|
assert w.responder.last_known_block == blocks[-1]
|
||||||
|
|
||||||
|
|
||||||
def test_update_states_watcher_misses_more(db_manager, carrier, block_processor):
|
def test_update_states_watcher_misses_more(db_manager, gatekeeper, carrier, block_processor):
|
||||||
# Same as before, but data is now in the Responder
|
# Same as before, but data is now in the Responder
|
||||||
w = Watcher(
|
w = Watcher(
|
||||||
db_manager=db_manager,
|
db_manager=db_manager,
|
||||||
|
gatekeeper=gatekeeper,
|
||||||
block_processor=block_processor,
|
block_processor=block_processor,
|
||||||
responder=Responder(db_manager, carrier, block_processor),
|
responder=Responder(db_manager, gatekeeper, carrier, block_processor),
|
||||||
sk_der=generate_keypair()[0].to_der(),
|
sk_der=generate_keypair()[0].to_der(),
|
||||||
max_appointments=config.get("MAX_APPOINTMENTS"),
|
max_appointments=config.get("MAX_APPOINTMENTS"),
|
||||||
expiry_delta=config.get("EXPIRY_DELTA"),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
blocks = []
|
blocks = []
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ def set_up_appointments(db_manager, total_appointments):
|
|||||||
uuid = uuid4().hex
|
uuid = uuid4().hex
|
||||||
locator = get_random_value_hex(LOCATOR_LEN_BYTES)
|
locator = get_random_value_hex(LOCATOR_LEN_BYTES)
|
||||||
|
|
||||||
appointment = Appointment(locator, None, None, None, None)
|
appointment = Appointment(locator, None, None)
|
||||||
appointments[uuid] = {"locator": appointment.locator}
|
appointments[uuid] = {"locator": appointment.locator}
|
||||||
locator_uuid_map[locator] = [uuid]
|
locator_uuid_map[locator] = [uuid]
|
||||||
|
|
||||||
@@ -156,7 +156,8 @@ def test_flag_triggered_appointments(db_manager):
|
|||||||
assert set(triggered_appointments).issubset(db_appointments)
|
assert set(triggered_appointments).issubset(db_appointments)
|
||||||
|
|
||||||
|
|
||||||
def test_delete_completed_trackers_db_match(db_manager):
|
def test_delete_trackers_db_match(db_manager):
|
||||||
|
# Completed and expired trackers are deleted using the same method. The only difference is the logging message
|
||||||
height = 0
|
height = 0
|
||||||
|
|
||||||
for _ in range(ITERATIONS):
|
for _ in range(ITERATIONS):
|
||||||
@@ -165,12 +166,12 @@ def test_delete_completed_trackers_db_match(db_manager):
|
|||||||
|
|
||||||
completed_trackers = {tracker: 6 for tracker in selected_trackers}
|
completed_trackers = {tracker: 6 for tracker in selected_trackers}
|
||||||
|
|
||||||
Cleaner.delete_completed_trackers(completed_trackers, height, trackers, tx_tracker_map, db_manager)
|
Cleaner.delete_trackers(completed_trackers, height, trackers, tx_tracker_map, db_manager)
|
||||||
|
|
||||||
assert not set(completed_trackers).issubset(trackers.keys())
|
assert not set(completed_trackers).issubset(trackers.keys())
|
||||||
|
|
||||||
|
|
||||||
def test_delete_completed_trackers_no_db_match(db_manager):
|
def test_delete_trackers_no_db_match(db_manager):
|
||||||
height = 0
|
height = 0
|
||||||
|
|
||||||
for _ in range(ITERATIONS):
|
for _ in range(ITERATIONS):
|
||||||
@@ -203,5 +204,5 @@ def test_delete_completed_trackers_no_db_match(db_manager):
|
|||||||
completed_trackers = {tracker: 6 for tracker in selected_trackers}
|
completed_trackers = {tracker: 6 for tracker in selected_trackers}
|
||||||
|
|
||||||
# We should be able to delete the correct ones and not fail in the others
|
# We should be able to delete the correct ones and not fail in the others
|
||||||
Cleaner.delete_completed_trackers(completed_trackers, height, trackers, tx_tracker_map, db_manager)
|
Cleaner.delete_trackers(completed_trackers, height, trackers, tx_tracker_map, db_manager)
|
||||||
assert not set(completed_trackers).issubset(trackers.keys())
|
assert not set(completed_trackers).issubset(trackers.keys())
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from teos.gatekeeper import IdentificationFailure, NotEnoughSlots
|
from teos.gatekeeper import AuthenticationFailure, NotEnoughSlots
|
||||||
|
|
||||||
from common.cryptographer import Cryptographer
|
from common.cryptographer import Cryptographer
|
||||||
|
from common.exceptions import InvalidParameter
|
||||||
|
|
||||||
from test.teos.unit.conftest import get_random_value_hex, generate_keypair, get_config
|
from test.teos.unit.conftest import get_random_value_hex, generate_keypair, get_config
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ from test.teos.unit.conftest import get_random_value_hex, generate_keypair, get_
|
|||||||
config = get_config()
|
config = get_config()
|
||||||
|
|
||||||
|
|
||||||
def test_init(gatekeeper):
|
def test_init(gatekeeper, run_bitcoind):
|
||||||
assert isinstance(gatekeeper.default_slots, int) and gatekeeper.default_slots == config.get("DEFAULT_SLOTS")
|
assert isinstance(gatekeeper.default_slots, int) and gatekeeper.default_slots == config.get("DEFAULT_SLOTS")
|
||||||
assert isinstance(gatekeeper.registered_users, dict) and len(gatekeeper.registered_users) == 0
|
assert isinstance(gatekeeper.registered_users, dict) and len(gatekeeper.registered_users) == 0
|
||||||
|
|
||||||
@@ -20,14 +21,12 @@ def test_add_update_user(gatekeeper):
|
|||||||
user_pk = "02" + get_random_value_hex(32)
|
user_pk = "02" + get_random_value_hex(32)
|
||||||
|
|
||||||
for _ in range(10):
|
for _ in range(10):
|
||||||
current_slots = gatekeeper.registered_users.get(user_pk)
|
user = gatekeeper.registered_users.get(user_pk)
|
||||||
current_slots = current_slots.get("available_slots") if current_slots is not None else 0
|
current_slots = user.available_slots if user is not None else 0
|
||||||
|
|
||||||
gatekeeper.add_update_user(user_pk)
|
gatekeeper.add_update_user(user_pk)
|
||||||
|
|
||||||
assert gatekeeper.registered_users.get(user_pk).get("available_slots") == current_slots + config.get(
|
assert gatekeeper.registered_users.get(user_pk).available_slots == current_slots + config.get("DEFAULT_SLOTS")
|
||||||
"DEFAULT_SLOTS"
|
|
||||||
)
|
|
||||||
|
|
||||||
# The same can be checked for multiple users
|
# The same can be checked for multiple users
|
||||||
for _ in range(10):
|
for _ in range(10):
|
||||||
@@ -35,14 +34,14 @@ def test_add_update_user(gatekeeper):
|
|||||||
user_pk = "03" + get_random_value_hex(32)
|
user_pk = "03" + get_random_value_hex(32)
|
||||||
|
|
||||||
gatekeeper.add_update_user(user_pk)
|
gatekeeper.add_update_user(user_pk)
|
||||||
assert gatekeeper.registered_users.get(user_pk).get("available_slots") == config.get("DEFAULT_SLOTS")
|
assert gatekeeper.registered_users.get(user_pk).available_slots == config.get("DEFAULT_SLOTS")
|
||||||
|
|
||||||
|
|
||||||
def test_add_update_user_wrong_pk(gatekeeper):
|
def test_add_update_user_wrong_pk(gatekeeper):
|
||||||
# Passing a wrong pk defaults to the errors in check_user_pk. We can try with one.
|
# Passing a wrong pk defaults to the errors in check_user_pk. We can try with one.
|
||||||
wrong_pk = get_random_value_hex(32)
|
wrong_pk = get_random_value_hex(32)
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(InvalidParameter):
|
||||||
gatekeeper.add_update_user(wrong_pk)
|
gatekeeper.add_update_user(wrong_pk)
|
||||||
|
|
||||||
|
|
||||||
@@ -50,7 +49,7 @@ def test_add_update_user_wrong_pk_prefix(gatekeeper):
|
|||||||
# Prefixes must be 02 or 03, anything else should fail
|
# Prefixes must be 02 or 03, anything else should fail
|
||||||
wrong_pk = "04" + get_random_value_hex(32)
|
wrong_pk = "04" + get_random_value_hex(32)
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(InvalidParameter):
|
||||||
gatekeeper.add_update_user(wrong_pk)
|
gatekeeper.add_update_user(wrong_pk)
|
||||||
|
|
||||||
|
|
||||||
@@ -66,7 +65,7 @@ def test_identify_user(gatekeeper):
|
|||||||
message = "Hey, it's me"
|
message = "Hey, it's me"
|
||||||
signature = Cryptographer.sign(message.encode(), sk)
|
signature = Cryptographer.sign(message.encode(), sk)
|
||||||
|
|
||||||
assert gatekeeper.identify_user(message.encode(), signature) == compressed_pk
|
assert gatekeeper.authenticate_user(message.encode(), signature) == compressed_pk
|
||||||
|
|
||||||
|
|
||||||
def test_identify_user_non_registered(gatekeeper):
|
def test_identify_user_non_registered(gatekeeper):
|
||||||
@@ -76,8 +75,8 @@ def test_identify_user_non_registered(gatekeeper):
|
|||||||
message = "Hey, it's me"
|
message = "Hey, it's me"
|
||||||
signature = Cryptographer.sign(message.encode(), sk)
|
signature = Cryptographer.sign(message.encode(), sk)
|
||||||
|
|
||||||
with pytest.raises(IdentificationFailure):
|
with pytest.raises(AuthenticationFailure):
|
||||||
gatekeeper.identify_user(message.encode(), signature)
|
gatekeeper.authenticate_user(message.encode(), signature)
|
||||||
|
|
||||||
|
|
||||||
def test_identify_user_invalid_signature(gatekeeper):
|
def test_identify_user_invalid_signature(gatekeeper):
|
||||||
@@ -85,8 +84,8 @@ def test_identify_user_invalid_signature(gatekeeper):
|
|||||||
message = "Hey, it's me"
|
message = "Hey, it's me"
|
||||||
signature = get_random_value_hex(72)
|
signature = get_random_value_hex(72)
|
||||||
|
|
||||||
with pytest.raises(IdentificationFailure):
|
with pytest.raises(AuthenticationFailure):
|
||||||
gatekeeper.identify_user(message.encode(), signature)
|
gatekeeper.authenticate_user(message.encode(), signature)
|
||||||
|
|
||||||
|
|
||||||
def test_identify_user_wrong(gatekeeper):
|
def test_identify_user_wrong(gatekeeper):
|
||||||
@@ -97,41 +96,16 @@ def test_identify_user_wrong(gatekeeper):
|
|||||||
signature = Cryptographer.sign(message.encode(), sk)
|
signature = Cryptographer.sign(message.encode(), sk)
|
||||||
|
|
||||||
# Non-byte message and str sig
|
# Non-byte message and str sig
|
||||||
with pytest.raises(IdentificationFailure):
|
with pytest.raises(AuthenticationFailure):
|
||||||
gatekeeper.identify_user(message, signature)
|
gatekeeper.authenticate_user(message, signature)
|
||||||
|
|
||||||
# byte message and non-str sig
|
# byte message and non-str sig
|
||||||
with pytest.raises(IdentificationFailure):
|
with pytest.raises(AuthenticationFailure):
|
||||||
gatekeeper.identify_user(message.encode(), signature.encode())
|
gatekeeper.authenticate_user(message.encode(), signature.encode())
|
||||||
|
|
||||||
# non-byte message and non-str sig
|
# non-byte message and non-str sig
|
||||||
with pytest.raises(IdentificationFailure):
|
with pytest.raises(AuthenticationFailure):
|
||||||
gatekeeper.identify_user(message, signature.encode())
|
gatekeeper.authenticate_user(message, signature.encode())
|
||||||
|
|
||||||
|
|
||||||
def test_fill_slots(gatekeeper):
|
# FIXME: MISSING TESTS
|
||||||
# Free slots will decrease the slot count of a user as long as he has enough slots, otherwise raise NotEnoughSlots
|
|
||||||
user_pk = "02" + get_random_value_hex(32)
|
|
||||||
gatekeeper.add_update_user(user_pk)
|
|
||||||
|
|
||||||
gatekeeper.fill_slots(user_pk, config.get("DEFAULT_SLOTS") - 1)
|
|
||||||
assert gatekeeper.registered_users.get(user_pk).get("available_slots") == 1
|
|
||||||
|
|
||||||
with pytest.raises(NotEnoughSlots):
|
|
||||||
gatekeeper.fill_slots(user_pk, 2)
|
|
||||||
|
|
||||||
# NotEnoughSlots is also raised if the user does not exist
|
|
||||||
with pytest.raises(NotEnoughSlots):
|
|
||||||
gatekeeper.fill_slots(get_random_value_hex(33), 2)
|
|
||||||
|
|
||||||
|
|
||||||
def test_free_slots(gatekeeper):
|
|
||||||
# Free slots simply adds slots to the user as long as it exists.
|
|
||||||
user_pk = "03" + get_random_value_hex(32)
|
|
||||||
gatekeeper.add_update_user(user_pk)
|
|
||||||
gatekeeper.free_slots(user_pk, 42)
|
|
||||||
|
|
||||||
assert gatekeeper.registered_users.get(user_pk).get("available_slots") == config.get("DEFAULT_SLOTS") + 42
|
|
||||||
|
|
||||||
# Just making sure it does not crash for non-registered user
|
|
||||||
assert gatekeeper.free_slots(get_random_value_hex(33), 10) is None
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ from binascii import unhexlify
|
|||||||
import teos.errors as errors
|
import teos.errors as errors
|
||||||
from teos.block_processor import BlockProcessor
|
from teos.block_processor import BlockProcessor
|
||||||
from teos.inspector import Inspector, InspectionFailed
|
from teos.inspector import Inspector, InspectionFailed
|
||||||
|
from teos.extended_appointment import ExtendedAppointment
|
||||||
|
|
||||||
from common.appointment import Appointment
|
|
||||||
from common.constants import LOCATOR_LEN_BYTES, LOCATOR_LEN_HEX
|
from common.constants import LOCATOR_LEN_BYTES, LOCATOR_LEN_HEX
|
||||||
|
|
||||||
from test.teos.unit.conftest import get_random_value_hex, bitcoind_connect_params, get_config
|
from test.teos.unit.conftest import get_random_value_hex, bitcoind_connect_params, get_config
|
||||||
@@ -95,101 +95,6 @@ def test_check_locator():
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
|
||||||
def test_check_start_time():
|
|
||||||
# Time is defined in block height
|
|
||||||
current_time = 100
|
|
||||||
|
|
||||||
# Right format and right value (start time in the future)
|
|
||||||
start_time = 101
|
|
||||||
assert inspector.check_start_time(start_time, current_time) is None
|
|
||||||
|
|
||||||
# Start time too small (either same block or block in the past)
|
|
||||||
start_times = [100, 99, 98, -1]
|
|
||||||
for start_time in start_times:
|
|
||||||
with pytest.raises(InspectionFailed):
|
|
||||||
try:
|
|
||||||
inspector.check_start_time(start_time, current_time)
|
|
||||||
|
|
||||||
except InspectionFailed as e:
|
|
||||||
assert e.erno == errors.APPOINTMENT_FIELD_TOO_SMALL
|
|
||||||
raise e
|
|
||||||
|
|
||||||
# Empty field
|
|
||||||
start_time = None
|
|
||||||
with pytest.raises(InspectionFailed):
|
|
||||||
try:
|
|
||||||
inspector.check_start_time(start_time, current_time)
|
|
||||||
|
|
||||||
except InspectionFailed as e:
|
|
||||||
assert e.erno == errors.APPOINTMENT_EMPTY_FIELD
|
|
||||||
raise e
|
|
||||||
|
|
||||||
# Wrong data type
|
|
||||||
start_times = WRONG_TYPES
|
|
||||||
for start_time in start_times:
|
|
||||||
with pytest.raises(InspectionFailed):
|
|
||||||
try:
|
|
||||||
inspector.check_start_time(start_time, current_time)
|
|
||||||
|
|
||||||
except InspectionFailed as e:
|
|
||||||
assert e.erno == errors.APPOINTMENT_WRONG_FIELD_TYPE
|
|
||||||
raise e
|
|
||||||
|
|
||||||
|
|
||||||
def test_check_end_time():
|
|
||||||
# Time is defined in block height
|
|
||||||
current_time = 100
|
|
||||||
start_time = 120
|
|
||||||
|
|
||||||
# Right format and right value (start time before end and end in the future)
|
|
||||||
end_time = 121
|
|
||||||
assert inspector.check_end_time(end_time, start_time, current_time) is None
|
|
||||||
|
|
||||||
# End time too small (start time after end time)
|
|
||||||
end_times = [120, 119, 118, -1]
|
|
||||||
for end_time in end_times:
|
|
||||||
with pytest.raises(InspectionFailed):
|
|
||||||
try:
|
|
||||||
inspector.check_end_time(end_time, start_time, current_time)
|
|
||||||
|
|
||||||
except InspectionFailed as e:
|
|
||||||
assert e.erno == errors.APPOINTMENT_FIELD_TOO_SMALL
|
|
||||||
raise e
|
|
||||||
|
|
||||||
# End time too small (either same height as current block or in the past)
|
|
||||||
current_time = 130
|
|
||||||
end_times = [130, 129, 128, -1]
|
|
||||||
for end_time in end_times:
|
|
||||||
with pytest.raises(InspectionFailed):
|
|
||||||
try:
|
|
||||||
inspector.check_end_time(end_time, start_time, current_time)
|
|
||||||
|
|
||||||
except InspectionFailed as e:
|
|
||||||
assert e.erno == errors.APPOINTMENT_FIELD_TOO_SMALL
|
|
||||||
raise e
|
|
||||||
|
|
||||||
# Empty field
|
|
||||||
end_time = None
|
|
||||||
with pytest.raises(InspectionFailed):
|
|
||||||
try:
|
|
||||||
inspector.check_end_time(end_time, start_time, current_time)
|
|
||||||
|
|
||||||
except InspectionFailed as e:
|
|
||||||
assert e.erno == errors.APPOINTMENT_EMPTY_FIELD
|
|
||||||
raise e
|
|
||||||
|
|
||||||
# Wrong data type
|
|
||||||
end_times = WRONG_TYPES
|
|
||||||
for end_time in end_times:
|
|
||||||
with pytest.raises(InspectionFailed):
|
|
||||||
try:
|
|
||||||
inspector.check_end_time(end_time, start_time, current_time)
|
|
||||||
|
|
||||||
except InspectionFailed as e:
|
|
||||||
assert e.erno == errors.APPOINTMENT_WRONG_FIELD_TYPE
|
|
||||||
raise e
|
|
||||||
|
|
||||||
|
|
||||||
def test_check_to_self_delay():
|
def test_check_to_self_delay():
|
||||||
# Right value, right format
|
# Right value, right format
|
||||||
to_self_delays = [MIN_TO_SELF_DELAY, MIN_TO_SELF_DELAY + 1, MIN_TO_SELF_DELAY + 1000]
|
to_self_delays = [MIN_TO_SELF_DELAY, MIN_TO_SELF_DELAY + 1, MIN_TO_SELF_DELAY + 1000]
|
||||||
@@ -234,10 +139,6 @@ def test_check_blob():
|
|||||||
encrypted_blob = get_random_value_hex(120)
|
encrypted_blob = get_random_value_hex(120)
|
||||||
assert inspector.check_blob(encrypted_blob) is None
|
assert inspector.check_blob(encrypted_blob) is None
|
||||||
|
|
||||||
# # Wrong content
|
|
||||||
# # FIXME: There is not proper defined format for this yet. It should be restricted by size at least, and check it
|
|
||||||
# # is multiple of the block size defined by the encryption function.
|
|
||||||
|
|
||||||
# Wrong type
|
# Wrong type
|
||||||
encrypted_blobs = WRONG_TYPES_NO_STR
|
encrypted_blobs = WRONG_TYPES_NO_STR
|
||||||
for encrypted_blob in encrypted_blobs:
|
for encrypted_blob in encrypted_blobs:
|
||||||
@@ -279,21 +180,13 @@ def test_inspect(run_bitcoind):
|
|||||||
to_self_delay = MIN_TO_SELF_DELAY
|
to_self_delay = MIN_TO_SELF_DELAY
|
||||||
encrypted_blob = get_random_value_hex(64)
|
encrypted_blob = get_random_value_hex(64)
|
||||||
|
|
||||||
appointment_data = {
|
appointment_data = {"locator": locator, "to_self_delay": to_self_delay, "encrypted_blob": encrypted_blob}
|
||||||
"locator": locator,
|
|
||||||
"start_time": start_time,
|
|
||||||
"end_time": end_time,
|
|
||||||
"to_self_delay": to_self_delay,
|
|
||||||
"encrypted_blob": encrypted_blob,
|
|
||||||
}
|
|
||||||
|
|
||||||
appointment = inspector.inspect(appointment_data)
|
appointment = inspector.inspect(appointment_data)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
type(appointment) == Appointment
|
type(appointment) == ExtendedAppointment
|
||||||
and appointment.locator == locator
|
and appointment.locator == locator
|
||||||
and appointment.start_time == start_time
|
|
||||||
and appointment.end_time == end_time
|
|
||||||
and appointment.to_self_delay == to_self_delay
|
and appointment.to_self_delay == to_self_delay
|
||||||
and appointment.encrypted_blob == encrypted_blob
|
and appointment.encrypted_blob == encrypted_blob
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,23 +9,31 @@ from threading import Thread
|
|||||||
from teos.carrier import Carrier
|
from teos.carrier import Carrier
|
||||||
from teos.tools import bitcoin_cli
|
from teos.tools import bitcoin_cli
|
||||||
from teos.chain_monitor import ChainMonitor
|
from teos.chain_monitor import ChainMonitor
|
||||||
|
from teos.block_processor import BlockProcessor
|
||||||
|
from teos.gatekeeper import Gatekeeper, UserInfo
|
||||||
from teos.appointments_dbm import AppointmentsDBM
|
from teos.appointments_dbm import AppointmentsDBM
|
||||||
from teos.responder import Responder, TransactionTracker
|
from teos.responder import Responder, TransactionTracker, CONFIRMATIONS_BEFORE_RETRY
|
||||||
|
|
||||||
from common.constants import LOCATOR_LEN_HEX
|
from common.constants import LOCATOR_LEN_HEX
|
||||||
from bitcoind_mock.transaction import create_dummy_transaction, create_tx_from_hex
|
from bitcoind_mock.transaction import create_dummy_transaction, create_tx_from_hex
|
||||||
from test.teos.unit.conftest import (
|
from test.teos.unit.conftest import (
|
||||||
generate_block,
|
generate_block,
|
||||||
generate_blocks,
|
generate_blocks,
|
||||||
|
generate_block_w_delay,
|
||||||
|
generate_blocks_w_delay,
|
||||||
get_random_value_hex,
|
get_random_value_hex,
|
||||||
bitcoind_connect_params,
|
bitcoind_connect_params,
|
||||||
bitcoind_feed_params,
|
bitcoind_feed_params,
|
||||||
|
get_config,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
config = get_config()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def responder(db_manager, carrier, block_processor):
|
def responder(db_manager, gatekeeper, carrier, block_processor):
|
||||||
responder = Responder(db_manager, carrier, block_processor)
|
responder = Responder(db_manager, gatekeeper, carrier, block_processor)
|
||||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||||
chain_monitor.monitor_chain()
|
chain_monitor.monitor_chain()
|
||||||
|
|
||||||
@@ -66,28 +74,26 @@ def create_dummy_tracker_data(random_txid=False, penalty_rawtx=None):
|
|||||||
if random_txid is True:
|
if random_txid is True:
|
||||||
penalty_txid = get_random_value_hex(32)
|
penalty_txid = get_random_value_hex(32)
|
||||||
|
|
||||||
appointment_end = bitcoin_cli(bitcoind_connect_params).getblockcount() + 2
|
|
||||||
locator = dispute_txid[:LOCATOR_LEN_HEX]
|
locator = dispute_txid[:LOCATOR_LEN_HEX]
|
||||||
|
user_id = get_random_value_hex(16)
|
||||||
|
|
||||||
return locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end
|
return locator, dispute_txid, penalty_txid, penalty_rawtx, user_id
|
||||||
|
|
||||||
|
|
||||||
def create_dummy_tracker(random_txid=False, penalty_rawtx=None):
|
def create_dummy_tracker(random_txid=False, penalty_rawtx=None):
|
||||||
locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end = create_dummy_tracker_data(
|
locator, dispute_txid, penalty_txid, penalty_rawtx, expiry = create_dummy_tracker_data(random_txid, penalty_rawtx)
|
||||||
random_txid, penalty_rawtx
|
return TransactionTracker(locator, dispute_txid, penalty_txid, penalty_rawtx, expiry)
|
||||||
)
|
|
||||||
return TransactionTracker(locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end)
|
|
||||||
|
|
||||||
|
|
||||||
def test_tracker_init(run_bitcoind):
|
def test_tracker_init(run_bitcoind):
|
||||||
locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end = create_dummy_tracker_data()
|
locator, dispute_txid, penalty_txid, penalty_rawtx, user_id = create_dummy_tracker_data()
|
||||||
tracker = TransactionTracker(locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end)
|
tracker = TransactionTracker(locator, dispute_txid, penalty_txid, penalty_rawtx, user_id)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
tracker.dispute_txid == dispute_txid
|
tracker.dispute_txid == dispute_txid
|
||||||
and tracker.penalty_txid == penalty_txid
|
and tracker.penalty_txid == penalty_txid
|
||||||
and tracker.penalty_rawtx == penalty_rawtx
|
and tracker.penalty_rawtx == penalty_rawtx
|
||||||
and tracker.appointment_end == appointment_end
|
and tracker.user_id == user_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -115,7 +121,7 @@ def test_tracker_to_dict():
|
|||||||
assert (
|
assert (
|
||||||
tracker.locator == tracker_dict["locator"]
|
tracker.locator == tracker_dict["locator"]
|
||||||
and tracker.penalty_rawtx == tracker_dict["penalty_rawtx"]
|
and tracker.penalty_rawtx == tracker_dict["penalty_rawtx"]
|
||||||
and tracker.appointment_end == tracker_dict["appointment_end"]
|
and tracker.user_id == tracker_dict["user_id"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -129,7 +135,7 @@ def test_tracker_from_dict():
|
|||||||
def test_tracker_from_dict_invalid_data():
|
def test_tracker_from_dict_invalid_data():
|
||||||
tracker_dict = create_dummy_tracker().to_dict()
|
tracker_dict = create_dummy_tracker().to_dict()
|
||||||
|
|
||||||
for value in ["dispute_txid", "penalty_txid", "penalty_rawtx", "appointment_end"]:
|
for value in ["dispute_txid", "penalty_txid", "penalty_rawtx", "user_id"]:
|
||||||
tracker_dict_copy = deepcopy(tracker_dict)
|
tracker_dict_copy = deepcopy(tracker_dict)
|
||||||
tracker_dict_copy[value] = None
|
tracker_dict_copy[value] = None
|
||||||
|
|
||||||
@@ -141,17 +147,22 @@ def test_tracker_from_dict_invalid_data():
|
|||||||
assert True
|
assert True
|
||||||
|
|
||||||
|
|
||||||
def test_init_responder(temp_db_manager, carrier, block_processor):
|
def test_init_responder(temp_db_manager, gatekeeper, carrier, block_processor):
|
||||||
responder = Responder(temp_db_manager, carrier, block_processor)
|
responder = Responder(temp_db_manager, gatekeeper, carrier, block_processor)
|
||||||
assert isinstance(responder.trackers, dict) and len(responder.trackers) == 0
|
assert isinstance(responder.trackers, dict) and len(responder.trackers) == 0
|
||||||
assert isinstance(responder.tx_tracker_map, dict) and len(responder.tx_tracker_map) == 0
|
assert isinstance(responder.tx_tracker_map, dict) and len(responder.tx_tracker_map) == 0
|
||||||
assert isinstance(responder.unconfirmed_txs, list) and len(responder.unconfirmed_txs) == 0
|
assert isinstance(responder.unconfirmed_txs, list) and len(responder.unconfirmed_txs) == 0
|
||||||
assert isinstance(responder.missed_confirmations, dict) and len(responder.missed_confirmations) == 0
|
assert isinstance(responder.missed_confirmations, dict) and len(responder.missed_confirmations) == 0
|
||||||
assert responder.block_queue.empty()
|
assert isinstance(responder.block_queue, Queue) and responder.block_queue.empty()
|
||||||
|
assert isinstance(responder.db_manager, AppointmentsDBM)
|
||||||
|
assert isinstance(responder.gatekeeper, Gatekeeper)
|
||||||
|
assert isinstance(responder.carrier, Carrier)
|
||||||
|
assert isinstance(responder.block_processor, BlockProcessor)
|
||||||
|
assert responder.last_known_block is None or isinstance(responder.last_known_block, str)
|
||||||
|
|
||||||
|
|
||||||
def test_handle_breach(db_manager, carrier, block_processor):
|
def test_handle_breach(db_manager, gatekeeper, carrier, block_processor):
|
||||||
responder = Responder(db_manager, carrier, block_processor)
|
responder = Responder(db_manager, gatekeeper, carrier, block_processor)
|
||||||
|
|
||||||
uuid = uuid4().hex
|
uuid = uuid4().hex
|
||||||
tracker = create_dummy_tracker()
|
tracker = create_dummy_tracker()
|
||||||
@@ -163,17 +174,17 @@ def test_handle_breach(db_manager, carrier, block_processor):
|
|||||||
tracker.dispute_txid,
|
tracker.dispute_txid,
|
||||||
tracker.penalty_txid,
|
tracker.penalty_txid,
|
||||||
tracker.penalty_rawtx,
|
tracker.penalty_rawtx,
|
||||||
tracker.appointment_end,
|
tracker.user_id,
|
||||||
block_hash=get_random_value_hex(32),
|
block_hash=get_random_value_hex(32),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert receipt.delivered is True
|
assert receipt.delivered is True
|
||||||
|
|
||||||
|
|
||||||
def test_handle_breach_bad_response(db_manager, block_processor):
|
def test_handle_breach_bad_response(db_manager, gatekeeper, block_processor):
|
||||||
# We need a new carrier here, otherwise the transaction will be flagged as previously sent and receipt.delivered
|
# We need a new carrier here, otherwise the transaction will be flagged as previously sent and receipt.delivered
|
||||||
# will be True
|
# will be True
|
||||||
responder = Responder(db_manager, Carrier(bitcoind_connect_params), block_processor)
|
responder = Responder(db_manager, gatekeeper, Carrier(bitcoind_connect_params), block_processor)
|
||||||
|
|
||||||
uuid = uuid4().hex
|
uuid = uuid4().hex
|
||||||
tracker = create_dummy_tracker()
|
tracker = create_dummy_tracker()
|
||||||
@@ -188,7 +199,7 @@ def test_handle_breach_bad_response(db_manager, block_processor):
|
|||||||
tracker.dispute_txid,
|
tracker.dispute_txid,
|
||||||
tracker.penalty_txid,
|
tracker.penalty_txid,
|
||||||
tracker.penalty_rawtx,
|
tracker.penalty_rawtx,
|
||||||
tracker.appointment_end,
|
tracker.user_id,
|
||||||
block_hash=get_random_value_hex(32),
|
block_hash=get_random_value_hex(32),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -199,9 +210,7 @@ def test_add_tracker(responder):
|
|||||||
for _ in range(20):
|
for _ in range(20):
|
||||||
uuid = uuid4().hex
|
uuid = uuid4().hex
|
||||||
confirmations = 0
|
confirmations = 0
|
||||||
locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end = create_dummy_tracker_data(
|
locator, dispute_txid, penalty_txid, penalty_rawtx, user_id = create_dummy_tracker_data(random_txid=True)
|
||||||
random_txid=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check the tracker is not within the responder trackers before adding it
|
# Check the tracker is not within the responder trackers before adding it
|
||||||
assert uuid not in responder.trackers
|
assert uuid not in responder.trackers
|
||||||
@@ -209,7 +218,7 @@ def test_add_tracker(responder):
|
|||||||
assert penalty_txid not in responder.unconfirmed_txs
|
assert penalty_txid not in responder.unconfirmed_txs
|
||||||
|
|
||||||
# And that it is afterwards
|
# And that it is afterwards
|
||||||
responder.add_tracker(uuid, locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end, confirmations)
|
responder.add_tracker(uuid, locator, dispute_txid, penalty_txid, penalty_rawtx, user_id, confirmations)
|
||||||
assert uuid in responder.trackers
|
assert uuid in responder.trackers
|
||||||
assert penalty_txid in responder.tx_tracker_map
|
assert penalty_txid in responder.tx_tracker_map
|
||||||
assert penalty_txid in responder.unconfirmed_txs
|
assert penalty_txid in responder.unconfirmed_txs
|
||||||
@@ -219,18 +228,18 @@ def test_add_tracker(responder):
|
|||||||
assert (
|
assert (
|
||||||
tracker.get("penalty_txid") == penalty_txid
|
tracker.get("penalty_txid") == penalty_txid
|
||||||
and tracker.get("locator") == locator
|
and tracker.get("locator") == locator
|
||||||
and tracker.get("appointment_end") == appointment_end
|
and tracker.get("user_id") == user_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_add_tracker_same_penalty_txid(responder):
|
def test_add_tracker_same_penalty_txid(responder):
|
||||||
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, user_id = create_dummy_tracker_data(random_txid=True)
|
||||||
uuid_1 = uuid4().hex
|
uuid_1 = uuid4().hex
|
||||||
uuid_2 = uuid4().hex
|
uuid_2 = uuid4().hex
|
||||||
|
|
||||||
responder.add_tracker(uuid_1, locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end, confirmations)
|
responder.add_tracker(uuid_1, locator, dispute_txid, penalty_txid, penalty_rawtx, user_id, confirmations)
|
||||||
responder.add_tracker(uuid_2, locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end, confirmations)
|
responder.add_tracker(uuid_2, locator, dispute_txid, penalty_txid, penalty_rawtx, user_id, confirmations)
|
||||||
|
|
||||||
# Check that both trackers have been added
|
# Check that both trackers have been added
|
||||||
assert uuid_1 in responder.trackers and uuid_2 in responder.trackers
|
assert uuid_1 in responder.trackers and uuid_2 in responder.trackers
|
||||||
@@ -243,7 +252,7 @@ def test_add_tracker_same_penalty_txid(responder):
|
|||||||
assert (
|
assert (
|
||||||
tracker.get("penalty_txid") == penalty_txid
|
tracker.get("penalty_txid") == penalty_txid
|
||||||
and tracker.get("locator") == locator
|
and tracker.get("locator") == locator
|
||||||
and tracker.get("appointment_end") == appointment_end
|
and tracker.get("user_id") == user_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -251,35 +260,42 @@ def test_add_tracker_already_confirmed(responder):
|
|||||||
for i in range(20):
|
for i in range(20):
|
||||||
uuid = uuid4().hex
|
uuid = uuid4().hex
|
||||||
confirmations = i + 1
|
confirmations = i + 1
|
||||||
locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end = create_dummy_tracker_data(
|
locator, dispute_txid, penalty_txid, penalty_rawtx, user_id = create_dummy_tracker_data(
|
||||||
penalty_rawtx=create_dummy_transaction().hex()
|
penalty_rawtx=create_dummy_transaction().hex()
|
||||||
)
|
)
|
||||||
|
|
||||||
responder.add_tracker(uuid, locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end, confirmations)
|
responder.add_tracker(uuid, locator, dispute_txid, penalty_txid, penalty_rawtx, user_id, confirmations)
|
||||||
|
|
||||||
assert penalty_txid not in responder.unconfirmed_txs
|
assert penalty_txid not in responder.unconfirmed_txs
|
||||||
|
|
||||||
|
|
||||||
def test_do_watch(temp_db_manager, carrier, block_processor):
|
def test_do_watch(temp_db_manager, gatekeeper, carrier, block_processor):
|
||||||
# Create a fresh responder to simplify the test
|
# Create a fresh responder to simplify the test
|
||||||
responder = Responder(temp_db_manager, carrier, block_processor)
|
responder = Responder(temp_db_manager, gatekeeper, carrier, block_processor)
|
||||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||||
chain_monitor.monitor_chain()
|
chain_monitor.monitor_chain()
|
||||||
|
|
||||||
trackers = [create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex()) for _ in range(20)]
|
trackers = [create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex()) for _ in range(20)]
|
||||||
|
subscription_expiry = responder.block_processor.get_block_count() + 110
|
||||||
|
|
||||||
# Let's set up the trackers first
|
# Let's set up the trackers first
|
||||||
for tracker in trackers:
|
for tracker in trackers:
|
||||||
uuid = uuid4().hex
|
uuid = uuid4().hex
|
||||||
|
|
||||||
|
# Simulate user registration
|
||||||
|
responder.gatekeeper.registered_users[tracker.user_id] = UserInfo(
|
||||||
|
available_slots=10, subscription_expiry=subscription_expiry
|
||||||
|
)
|
||||||
|
|
||||||
responder.trackers[uuid] = {
|
responder.trackers[uuid] = {
|
||||||
"locator": tracker.locator,
|
"locator": tracker.locator,
|
||||||
"penalty_txid": tracker.penalty_txid,
|
"penalty_txid": tracker.penalty_txid,
|
||||||
"appointment_end": tracker.appointment_end,
|
"user_id": tracker.user_id,
|
||||||
}
|
}
|
||||||
responder.tx_tracker_map[tracker.penalty_txid] = [uuid]
|
responder.tx_tracker_map[tracker.penalty_txid] = [uuid]
|
||||||
responder.missed_confirmations[tracker.penalty_txid] = 0
|
responder.missed_confirmations[tracker.penalty_txid] = 0
|
||||||
responder.unconfirmed_txs.append(tracker.penalty_txid)
|
responder.unconfirmed_txs.append(tracker.penalty_txid)
|
||||||
|
responder.gatekeeper.registered_users[tracker.user_id].appointments.append(uuid)
|
||||||
|
|
||||||
# We also need to store the info in the db
|
# We also need to store the info in the db
|
||||||
responder.db_manager.create_triggered_appointment_flag(uuid)
|
responder.db_manager.create_triggered_appointment_flag(uuid)
|
||||||
@@ -295,32 +311,29 @@ def test_do_watch(temp_db_manager, carrier, block_processor):
|
|||||||
broadcast_txs.append(tracker.penalty_txid)
|
broadcast_txs.append(tracker.penalty_txid)
|
||||||
|
|
||||||
# Mine a block
|
# Mine a block
|
||||||
generate_block()
|
generate_block_w_delay()
|
||||||
|
|
||||||
# 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)
|
||||||
|
|
||||||
# TODO: test that reorgs can be detected once data persistence is merged (new version of the simulator)
|
# CONFIRMATIONS_BEFORE_RETRY+1 blocks after, the responder should rebroadcast the unconfirmed txs (15 remaining)
|
||||||
|
generate_blocks_w_delay(CONFIRMATIONS_BEFORE_RETRY + 1)
|
||||||
|
assert len(responder.unconfirmed_txs) == 0
|
||||||
|
assert len(responder.trackers) == 20
|
||||||
|
|
||||||
# Generating 5 additional blocks should complete the 5 trackers
|
# Generating 100 - CONFIRMATIONS_BEFORE_RETRY -2 additional blocks should complete the first 5 trackers
|
||||||
generate_blocks(5)
|
generate_blocks_w_delay(100 - CONFIRMATIONS_BEFORE_RETRY - 2)
|
||||||
|
assert len(responder.unconfirmed_txs) == 0
|
||||||
|
assert len(responder.trackers) == 15
|
||||||
|
|
||||||
assert not set(broadcast_txs).issubset(responder.tx_tracker_map)
|
# CONFIRMATIONS_BEFORE_RETRY additional blocks should complete the rest
|
||||||
|
generate_blocks_w_delay(CONFIRMATIONS_BEFORE_RETRY)
|
||||||
# Do the rest
|
assert len(responder.unconfirmed_txs) == 0
|
||||||
broadcast_txs = []
|
assert len(responder.trackers) == 0
|
||||||
for tracker in trackers[5:]:
|
|
||||||
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(tracker.penalty_rawtx)
|
|
||||||
broadcast_txs.append(tracker.penalty_txid)
|
|
||||||
|
|
||||||
# Mine a block
|
|
||||||
generate_blocks(6)
|
|
||||||
|
|
||||||
assert len(responder.tx_tracker_map) == 0
|
|
||||||
|
|
||||||
|
|
||||||
def test_check_confirmations(db_manager, carrier, block_processor):
|
def test_check_confirmations(db_manager, gatekeeper, carrier, block_processor):
|
||||||
responder = Responder(db_manager, carrier, block_processor)
|
responder = Responder(db_manager, gatekeeper, carrier, block_processor)
|
||||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||||
chain_monitor.monitor_chain()
|
chain_monitor.monitor_chain()
|
||||||
|
|
||||||
@@ -376,68 +389,69 @@ 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, carrier, block_processor):
|
def test_get_completed_trackers(db_manager, gatekeeper, carrier, block_processor):
|
||||||
initial_height = bitcoin_cli(bitcoind_connect_params).getblockcount()
|
initial_height = bitcoin_cli(bitcoind_connect_params).getblockcount()
|
||||||
|
|
||||||
responder = Responder(db_manager, carrier, block_processor)
|
responder = Responder(db_manager, gatekeeper, carrier, block_processor)
|
||||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||||
chain_monitor.monitor_chain()
|
chain_monitor.monitor_chain()
|
||||||
|
|
||||||
# A complete tracker is a tracker that has reached the appointment end with enough confs (> MIN_CONFIRMATIONS)
|
# A complete tracker is a tracker which penalty transaction has been irrevocably resolved (i.e. has reached 100
|
||||||
# We'll create three type of transactions: end reached + enough conf, end reached + no enough conf, end not reached
|
# confirmations)
|
||||||
trackers_end_conf = {
|
# We'll create 3 type of txs: irrevocably resolved, confirmed but not irrevocably resolved, and unconfirmed
|
||||||
|
trackers_ir_resolved = {
|
||||||
uuid4().hex: create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex()) for _ in range(10)
|
uuid4().hex: create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex()) for _ in range(10)
|
||||||
}
|
}
|
||||||
|
|
||||||
trackers_end_no_conf = {}
|
trackers_confirmed = {
|
||||||
|
uuid4().hex: create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex()) for _ in range(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
trackers_unconfirmed = {}
|
||||||
for _ in range(10):
|
for _ in range(10):
|
||||||
tracker = create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex())
|
tracker = create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex())
|
||||||
responder.unconfirmed_txs.append(tracker.penalty_txid)
|
responder.unconfirmed_txs.append(tracker.penalty_txid)
|
||||||
trackers_end_no_conf[uuid4().hex] = tracker
|
trackers_unconfirmed[uuid4().hex] = tracker
|
||||||
|
|
||||||
trackers_no_end = {}
|
|
||||||
for _ in range(10):
|
|
||||||
tracker = create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex())
|
|
||||||
tracker.appointment_end += 10
|
|
||||||
trackers_no_end[uuid4().hex] = tracker
|
|
||||||
|
|
||||||
all_trackers = {}
|
all_trackers = {}
|
||||||
all_trackers.update(trackers_end_conf)
|
all_trackers.update(trackers_ir_resolved)
|
||||||
all_trackers.update(trackers_end_no_conf)
|
all_trackers.update(trackers_confirmed)
|
||||||
all_trackers.update(trackers_no_end)
|
all_trackers.update(trackers_unconfirmed)
|
||||||
|
|
||||||
# Let's add all to the responder
|
# Let's add all to the responder
|
||||||
for uuid, tracker in all_trackers.items():
|
for uuid, tracker in all_trackers.items():
|
||||||
responder.trackers[uuid] = {
|
responder.trackers[uuid] = {
|
||||||
"locator": tracker.locator,
|
"locator": tracker.locator,
|
||||||
"penalty_txid": tracker.penalty_txid,
|
"penalty_txid": tracker.penalty_txid,
|
||||||
"appointment_end": tracker.appointment_end,
|
"user_id": tracker.user_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
for uuid, tracker in all_trackers.items():
|
for uuid, tracker in trackers_ir_resolved.items():
|
||||||
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(tracker.penalty_rawtx)
|
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(tracker.penalty_rawtx)
|
||||||
|
|
||||||
# The dummy appointments have a end_appointment time of current + 2, but trackers need at least 6 confs by default
|
generate_block_w_delay()
|
||||||
generate_blocks(6)
|
|
||||||
|
|
||||||
# And now let's check
|
for uuid, tracker in trackers_confirmed.items():
|
||||||
completed_trackers = responder.get_completed_trackers(initial_height + 6)
|
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(tracker.penalty_rawtx)
|
||||||
completed_trackers_ids = [tracker_id for tracker_id, confirmations in completed_trackers.items()]
|
|
||||||
ended_trackers_keys = list(trackers_end_conf.keys())
|
|
||||||
assert set(completed_trackers_ids) == set(ended_trackers_keys)
|
|
||||||
|
|
||||||
# Generating 6 additional blocks should also confirm trackers_no_end
|
# ir_resolved have 100 confs and confirmed have 99
|
||||||
generate_blocks(6)
|
generate_blocks_w_delay(99)
|
||||||
|
|
||||||
completed_trackers = responder.get_completed_trackers(initial_height + 12)
|
# Let's check
|
||||||
completed_trackers_ids = [tracker_id for tracker_id, confirmations in completed_trackers.items()]
|
completed_trackers = responder.get_completed_trackers()
|
||||||
ended_trackers_keys.extend(list(trackers_no_end.keys()))
|
ended_trackers_keys = list(trackers_ir_resolved.keys())
|
||||||
|
assert set(completed_trackers) == set(ended_trackers_keys)
|
||||||
|
|
||||||
assert set(completed_trackers_ids) == set(ended_trackers_keys)
|
# Generating 1 additional block should also include confirmed
|
||||||
|
generate_block_w_delay()
|
||||||
|
|
||||||
|
completed_trackers = responder.get_completed_trackers()
|
||||||
|
ended_trackers_keys.extend(list(trackers_confirmed.keys()))
|
||||||
|
assert set(completed_trackers) == set(ended_trackers_keys)
|
||||||
|
|
||||||
|
|
||||||
def test_rebroadcast(db_manager, carrier, block_processor):
|
def test_rebroadcast(db_manager, gatekeeper, carrier, block_processor):
|
||||||
responder = Responder(db_manager, carrier, block_processor)
|
responder = Responder(db_manager, gatekeeper, carrier, block_processor)
|
||||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||||
chain_monitor.monitor_chain()
|
chain_monitor.monitor_chain()
|
||||||
|
|
||||||
@@ -446,17 +460,13 @@ def test_rebroadcast(db_manager, carrier, block_processor):
|
|||||||
# Rebroadcast calls add_response with retry=True. The tracker data is already in trackers.
|
# Rebroadcast calls add_response with retry=True. The tracker data is already in trackers.
|
||||||
for i in range(20):
|
for i in range(20):
|
||||||
uuid = uuid4().hex
|
uuid = uuid4().hex
|
||||||
locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end = create_dummy_tracker_data(
|
locator, dispute_txid, penalty_txid, penalty_rawtx, user_id = create_dummy_tracker_data(
|
||||||
penalty_rawtx=create_dummy_transaction().hex()
|
penalty_rawtx=create_dummy_transaction().hex()
|
||||||
)
|
)
|
||||||
|
|
||||||
tracker = TransactionTracker(locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end)
|
tracker = TransactionTracker(locator, dispute_txid, penalty_txid, penalty_rawtx, user_id)
|
||||||
|
|
||||||
responder.trackers[uuid] = {
|
responder.trackers[uuid] = {"locator": locator, "penalty_txid": penalty_txid, "user_id": user_id}
|
||||||
"locator": locator,
|
|
||||||
"penalty_txid": penalty_txid,
|
|
||||||
"appointment_end": appointment_end,
|
|
||||||
}
|
|
||||||
|
|
||||||
# We need to add it to the db too
|
# We need to add it to the db too
|
||||||
responder.db_manager.create_triggered_appointment_flag(uuid)
|
responder.db_manager.create_triggered_appointment_flag(uuid)
|
||||||
|
|||||||
@@ -13,13 +13,7 @@ def test_can_connect_to_bitcoind():
|
|||||||
assert can_connect_to_bitcoind(bitcoind_connect_params) is True
|
assert can_connect_to_bitcoind(bitcoind_connect_params) is True
|
||||||
|
|
||||||
|
|
||||||
# def test_can_connect_to_bitcoind_bitcoin_not_running():
|
def test_bitcoin_cli(run_bitcoind):
|
||||||
# # Kill the simulator thread and test the check fails
|
|
||||||
# bitcoind_process.kill()
|
|
||||||
# assert can_connect_to_bitcoind() is False
|
|
||||||
|
|
||||||
|
|
||||||
def test_bitcoin_cli():
|
|
||||||
try:
|
try:
|
||||||
bitcoin_cli(bitcoind_connect_params).help()
|
bitcoin_cli(bitcoind_connect_params).help()
|
||||||
assert True
|
assert True
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
from teos.appointments_dbm import AppointmentsDBM
|
from teos.users_dbm import UsersDBM
|
||||||
|
from teos.gatekeeper import UserInfo
|
||||||
|
|
||||||
from test.teos.unit.conftest import get_random_value_hex
|
from test.teos.unit.conftest import get_random_value_hex
|
||||||
|
|
||||||
|
|
||||||
stored_users = {}
|
stored_users = {}
|
||||||
|
|
||||||
|
|
||||||
def open_create_db(db_path):
|
def open_create_db(db_path):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
db_manager = AppointmentsDBM(db_path)
|
db_manager = UsersDBM(db_path)
|
||||||
|
|
||||||
return db_manager
|
return db_manager
|
||||||
|
|
||||||
@@ -20,17 +20,17 @@ def open_create_db(db_path):
|
|||||||
def test_store_user(user_db_manager):
|
def test_store_user(user_db_manager):
|
||||||
# Store user should work as long as the user_pk is properly formatted and data is a dictionary
|
# Store user should work as long as the user_pk is properly formatted and data is a dictionary
|
||||||
user_pk = "02" + get_random_value_hex(32)
|
user_pk = "02" + get_random_value_hex(32)
|
||||||
user_data = {"available_slots": 42}
|
user_info = UserInfo(available_slots=42, subscription_expiry=100)
|
||||||
stored_users[user_pk] = user_data
|
stored_users[user_pk] = user_info.to_dict()
|
||||||
assert user_db_manager.store_user(user_pk, user_data) is True
|
assert user_db_manager.store_user(user_pk, user_info.to_dict()) is True
|
||||||
|
|
||||||
# Wrong pks should return False on adding
|
# Wrong pks should return False on adding
|
||||||
user_pk = "04" + get_random_value_hex(32)
|
user_pk = "04" + get_random_value_hex(32)
|
||||||
user_data = {"available_slots": 42}
|
user_info = UserInfo(available_slots=42, subscription_expiry=100)
|
||||||
assert user_db_manager.store_user(user_pk, user_data) is False
|
assert user_db_manager.store_user(user_pk, user_info.to_dict()) is False
|
||||||
|
|
||||||
# Same for wrong types
|
# Same for wrong types
|
||||||
assert user_db_manager.store_user(42, user_data) is False
|
assert user_db_manager.store_user(42, user_info.to_dict()) is False
|
||||||
|
|
||||||
# And for wrong type user data
|
# And for wrong type user data
|
||||||
assert user_db_manager.store_user(user_pk, 42) is False
|
assert user_db_manager.store_user(user_pk, 42) is False
|
||||||
@@ -71,9 +71,9 @@ def test_load_all_users(user_db_manager):
|
|||||||
# Adding some and checking we get them all
|
# Adding some and checking we get them all
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
user_pk = "02" + get_random_value_hex(32)
|
user_pk = "02" + get_random_value_hex(32)
|
||||||
user_data = {"available_slots": i}
|
user_info = UserInfo(available_slots=42, subscription_expiry=100)
|
||||||
user_db_manager.store_user(user_pk, user_data)
|
user_db_manager.store_user(user_pk, user_info.to_dict())
|
||||||
stored_users[user_pk] = user_data
|
stored_users[user_pk] = user_info.to_dict()
|
||||||
|
|
||||||
all_users = user_db_manager.load_all_users()
|
all_users = user_db_manager.load_all_users()
|
||||||
|
|
||||||
|
|||||||
@@ -4,20 +4,21 @@ from shutil import rmtree
|
|||||||
from threading import Thread
|
from threading import Thread
|
||||||
from coincurve import PrivateKey
|
from coincurve import PrivateKey
|
||||||
|
|
||||||
from teos import LOG_PREFIX
|
|
||||||
from teos.carrier import Carrier
|
from teos.carrier import Carrier
|
||||||
from teos.watcher import Watcher
|
|
||||||
from teos.tools import bitcoin_cli
|
from teos.tools import bitcoin_cli
|
||||||
from teos.responder import Responder
|
from teos.responder import Responder
|
||||||
|
from teos.gatekeeper import UserInfo
|
||||||
|
from teos.gatekeeper import Gatekeeper
|
||||||
from teos.chain_monitor import ChainMonitor
|
from teos.chain_monitor import ChainMonitor
|
||||||
from teos.appointments_dbm import AppointmentsDBM
|
from teos.appointments_dbm import AppointmentsDBM
|
||||||
from teos.block_processor import BlockProcessor
|
from teos.block_processor import BlockProcessor
|
||||||
|
from teos.watcher import Watcher, AppointmentLimitReached
|
||||||
|
|
||||||
from common.tools import compute_locator
|
from common.tools import compute_locator
|
||||||
from common.cryptographer import Cryptographer
|
from common.cryptographer import Cryptographer
|
||||||
|
|
||||||
from test.teos.unit.conftest import (
|
from test.teos.unit.conftest import (
|
||||||
generate_blocks,
|
generate_blocks_w_delay,
|
||||||
generate_dummy_appointment,
|
generate_dummy_appointment,
|
||||||
get_random_value_hex,
|
get_random_value_hex,
|
||||||
generate_keypair,
|
generate_keypair,
|
||||||
@@ -27,8 +28,6 @@ from test.teos.unit.conftest import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
APPOINTMENTS = 5
|
APPOINTMENTS = 5
|
||||||
START_TIME_OFFSET = 1
|
|
||||||
END_TIME_OFFSET = 1
|
|
||||||
TEST_SET_SIZE = 200
|
TEST_SET_SIZE = 200
|
||||||
|
|
||||||
config = get_config()
|
config = get_config()
|
||||||
@@ -51,14 +50,12 @@ def temp_db_manager():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def watcher(db_manager):
|
def watcher(db_manager, gatekeeper):
|
||||||
block_processor = BlockProcessor(bitcoind_connect_params)
|
block_processor = BlockProcessor(bitcoind_connect_params)
|
||||||
carrier = Carrier(bitcoind_connect_params)
|
carrier = Carrier(bitcoind_connect_params)
|
||||||
|
|
||||||
responder = Responder(db_manager, carrier, block_processor)
|
responder = Responder(db_manager, gatekeeper, carrier, block_processor)
|
||||||
watcher = Watcher(
|
watcher = Watcher(db_manager, gatekeeper, block_processor, responder, signing_key.to_der(), MAX_APPOINTMENTS)
|
||||||
db_manager, block_processor, responder, signing_key.to_der(), MAX_APPOINTMENTS, config.get("EXPIRY_DELTA")
|
|
||||||
)
|
|
||||||
|
|
||||||
chain_monitor = ChainMonitor(
|
chain_monitor = ChainMonitor(
|
||||||
watcher.block_queue, watcher.responder.block_queue, block_processor, bitcoind_feed_params
|
watcher.block_queue, watcher.responder.block_queue, block_processor, bitcoind_feed_params
|
||||||
@@ -84,9 +81,7 @@ def create_appointments(n):
|
|||||||
dispute_txs = []
|
dispute_txs = []
|
||||||
|
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
appointment, dispute_tx = generate_dummy_appointment(
|
appointment, dispute_tx = generate_dummy_appointment()
|
||||||
start_time_offset=START_TIME_OFFSET, end_time_offset=END_TIME_OFFSET
|
|
||||||
)
|
|
||||||
uuid = uuid4().hex
|
uuid = uuid4().hex
|
||||||
|
|
||||||
appointments[uuid] = appointment
|
appointments[uuid] = appointment
|
||||||
@@ -103,82 +98,79 @@ def test_init(run_bitcoind, watcher):
|
|||||||
assert isinstance(watcher.block_processor, BlockProcessor)
|
assert isinstance(watcher.block_processor, BlockProcessor)
|
||||||
assert isinstance(watcher.responder, Responder)
|
assert isinstance(watcher.responder, Responder)
|
||||||
assert isinstance(watcher.max_appointments, int)
|
assert isinstance(watcher.max_appointments, int)
|
||||||
assert isinstance(watcher.expiry_delta, int)
|
assert isinstance(watcher.gatekeeper, Gatekeeper)
|
||||||
assert isinstance(watcher.signing_key, PrivateKey)
|
assert isinstance(watcher.signing_key, PrivateKey)
|
||||||
|
|
||||||
|
|
||||||
def test_get_appointment_summary(watcher):
|
|
||||||
# get_appointment_summary returns an appointment summary if found, else None.
|
|
||||||
random_uuid = get_random_value_hex(16)
|
|
||||||
appointment_summary = {"locator": get_random_value_hex(16), "end_time": 10, "size": 200}
|
|
||||||
watcher.appointments[random_uuid] = appointment_summary
|
|
||||||
assert watcher.get_appointment_summary(random_uuid) == appointment_summary
|
|
||||||
|
|
||||||
# Requesting a non-existing appointment
|
|
||||||
assert watcher.get_appointment_summary(get_random_value_hex(16)) is None
|
|
||||||
|
|
||||||
|
|
||||||
def test_add_appointment(watcher):
|
def test_add_appointment(watcher):
|
||||||
# We should be able to add appointments up to the limit
|
# Simulate the user is registered
|
||||||
for _ in range(10):
|
user_sk, user_pk = generate_keypair()
|
||||||
appointment, dispute_tx = generate_dummy_appointment(
|
available_slots = 100
|
||||||
start_time_offset=START_TIME_OFFSET, end_time_offset=END_TIME_OFFSET
|
user_id = Cryptographer.get_compressed_pk(user_pk)
|
||||||
)
|
watcher.gatekeeper.registered_users[user_id] = UserInfo(available_slots=available_slots, subscription_expiry=10)
|
||||||
user_pk = get_random_value_hex(33)
|
|
||||||
|
|
||||||
added_appointment, sig = watcher.add_appointment(appointment, user_pk)
|
appointment, dispute_tx = generate_dummy_appointment()
|
||||||
|
appointment_signature = Cryptographer.sign(appointment.serialize(), user_sk)
|
||||||
|
|
||||||
assert added_appointment is True
|
response = watcher.add_appointment(appointment, appointment_signature)
|
||||||
assert Cryptographer.get_compressed_pk(watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
|
assert response.get("locator") == appointment.locator
|
||||||
Cryptographer.recover_pk(appointment.serialize(), sig)
|
assert Cryptographer.get_compressed_pk(watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
|
||||||
)
|
Cryptographer.recover_pk(appointment.serialize(), response.get("signature"))
|
||||||
|
)
|
||||||
|
assert response.get("available_slots") == available_slots - 1
|
||||||
|
|
||||||
# Check that we can also add an already added appointment (same locator)
|
# Check that we can also add an already added appointment (same locator)
|
||||||
added_appointment, sig = watcher.add_appointment(appointment, user_pk)
|
response = watcher.add_appointment(appointment, appointment_signature)
|
||||||
|
assert response.get("locator") == appointment.locator
|
||||||
|
assert Cryptographer.get_compressed_pk(watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
|
||||||
|
Cryptographer.recover_pk(appointment.serialize(), response.get("signature"))
|
||||||
|
)
|
||||||
|
# The slot count should not have been reduced and only one copy is kept.
|
||||||
|
assert response.get("available_slots") == available_slots - 1
|
||||||
|
assert len(watcher.locator_uuid_map[appointment.locator]) == 1
|
||||||
|
|
||||||
assert added_appointment is True
|
# If two appointments with the same locator come from different users, they are kept.
|
||||||
assert Cryptographer.get_compressed_pk(watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
|
another_user_sk, another_user_pk = generate_keypair()
|
||||||
Cryptographer.recover_pk(appointment.serialize(), sig)
|
another_user_id = Cryptographer.get_compressed_pk(another_user_pk)
|
||||||
)
|
watcher.gatekeeper.registered_users[another_user_id] = UserInfo(
|
||||||
|
available_slots=available_slots, subscription_expiry=10
|
||||||
|
)
|
||||||
|
|
||||||
# If two appointments with the same locator from the same user are added, they are overwritten, but if they come
|
appointment_signature = Cryptographer.sign(appointment.serialize(), another_user_sk)
|
||||||
# from different users, they are kept.
|
response = watcher.add_appointment(appointment, appointment_signature)
|
||||||
assert len(watcher.locator_uuid_map[appointment.locator]) == 1
|
assert response.get("locator") == appointment.locator
|
||||||
|
assert Cryptographer.get_compressed_pk(watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
|
||||||
different_user_pk = get_random_value_hex(33)
|
Cryptographer.recover_pk(appointment.serialize(), response.get("signature"))
|
||||||
added_appointment, sig = watcher.add_appointment(appointment, different_user_pk)
|
)
|
||||||
assert added_appointment is True
|
assert response.get("available_slots") == available_slots - 1
|
||||||
assert Cryptographer.get_compressed_pk(watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
|
assert len(watcher.locator_uuid_map[appointment.locator]) == 2
|
||||||
Cryptographer.recover_pk(appointment.serialize(), sig)
|
|
||||||
)
|
|
||||||
assert len(watcher.locator_uuid_map[appointment.locator]) == 2
|
|
||||||
|
|
||||||
|
|
||||||
def test_add_too_many_appointments(watcher):
|
def test_add_too_many_appointments(watcher):
|
||||||
# Any appointment on top of those should fail
|
# Simulate the user is registered
|
||||||
|
user_sk, user_pk = generate_keypair()
|
||||||
|
available_slots = 100
|
||||||
|
user_id = Cryptographer.get_compressed_pk(user_pk)
|
||||||
|
watcher.gatekeeper.registered_users[user_id] = UserInfo(available_slots=available_slots, subscription_expiry=10)
|
||||||
|
|
||||||
|
# Appointments on top of the limit should be rejected
|
||||||
watcher.appointments = dict()
|
watcher.appointments = dict()
|
||||||
|
|
||||||
for _ in range(MAX_APPOINTMENTS):
|
for i in range(MAX_APPOINTMENTS):
|
||||||
appointment, dispute_tx = generate_dummy_appointment(
|
appointment, dispute_tx = generate_dummy_appointment()
|
||||||
start_time_offset=START_TIME_OFFSET, end_time_offset=END_TIME_OFFSET
|
appointment_signature = Cryptographer.sign(appointment.serialize(), user_sk)
|
||||||
)
|
|
||||||
user_pk = get_random_value_hex(33)
|
|
||||||
|
|
||||||
added_appointment, sig = watcher.add_appointment(appointment, user_pk)
|
response = watcher.add_appointment(appointment, appointment_signature)
|
||||||
|
assert response.get("locator") == appointment.locator
|
||||||
assert added_appointment is True
|
|
||||||
assert Cryptographer.get_compressed_pk(watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
|
assert Cryptographer.get_compressed_pk(watcher.signing_key.public_key) == Cryptographer.get_compressed_pk(
|
||||||
Cryptographer.recover_pk(appointment.serialize(), sig)
|
Cryptographer.recover_pk(appointment.serialize(), response.get("signature"))
|
||||||
)
|
)
|
||||||
|
assert response.get("available_slots") == available_slots - (i + 1)
|
||||||
|
|
||||||
appointment, dispute_tx = generate_dummy_appointment(
|
with pytest.raises(AppointmentLimitReached):
|
||||||
start_time_offset=START_TIME_OFFSET, end_time_offset=END_TIME_OFFSET
|
appointment, dispute_tx = generate_dummy_appointment()
|
||||||
)
|
appointment_signature = Cryptographer.sign(appointment.serialize(), user_sk)
|
||||||
user_pk = get_random_value_hex(33)
|
watcher.add_appointment(appointment, appointment_signature)
|
||||||
added_appointment, sig = watcher.add_appointment(appointment, user_pk)
|
|
||||||
|
|
||||||
assert added_appointment is False
|
|
||||||
assert sig is None
|
|
||||||
|
|
||||||
|
|
||||||
def test_do_watch(watcher, temp_db_manager):
|
def test_do_watch(watcher, temp_db_manager):
|
||||||
@@ -190,9 +182,18 @@ def test_do_watch(watcher, temp_db_manager):
|
|||||||
# Set the data into the Watcher and in the db
|
# Set the data into the Watcher and in the db
|
||||||
watcher.locator_uuid_map = locator_uuid_map
|
watcher.locator_uuid_map = locator_uuid_map
|
||||||
watcher.appointments = {}
|
watcher.appointments = {}
|
||||||
|
watcher.gatekeeper.registered_users = {}
|
||||||
|
|
||||||
|
# Simulate a register
|
||||||
|
user_id = get_random_value_hex(16)
|
||||||
|
watcher.gatekeeper.registered_users[user_id] = UserInfo(
|
||||||
|
available_slots=100, subscription_expiry=watcher.block_processor.get_block_count() + 10
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add the appointments
|
||||||
for uuid, appointment in appointments.items():
|
for uuid, appointment in appointments.items():
|
||||||
watcher.appointments[uuid] = {"locator": appointment.locator, "end_time": appointment.end_time, "size": 200}
|
watcher.appointments[uuid] = {"locator": appointment.locator, "user_id": user_id, "size": 200}
|
||||||
|
watcher.gatekeeper.registered_users[user_id].appointments.append(uuid)
|
||||||
watcher.db_manager.store_watcher_appointment(uuid, appointment.to_dict())
|
watcher.db_manager.store_watcher_appointment(uuid, appointment.to_dict())
|
||||||
watcher.db_manager.create_append_locator_map(appointment.locator, uuid)
|
watcher.db_manager.create_append_locator_map(appointment.locator, uuid)
|
||||||
|
|
||||||
@@ -203,14 +204,14 @@ def test_do_watch(watcher, temp_db_manager):
|
|||||||
for dispute_tx in dispute_txs[:2]:
|
for dispute_tx in dispute_txs[:2]:
|
||||||
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(dispute_tx)
|
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(dispute_tx)
|
||||||
|
|
||||||
# After generating enough blocks, the number of appointments should have reduced by two
|
# After generating a block, the appointment count should have been reduced by 2 (two breaches)
|
||||||
generate_blocks(START_TIME_OFFSET + END_TIME_OFFSET)
|
generate_blocks_w_delay(1)
|
||||||
|
|
||||||
assert len(watcher.appointments) == APPOINTMENTS - 2
|
assert len(watcher.appointments) == APPOINTMENTS - 2
|
||||||
|
|
||||||
# The rest of appointments will timeout after the end (2) + EXPIRY_DELTA
|
# The rest of appointments will timeout after the subscription times-out (9 more blocks) + EXPIRY_DELTA
|
||||||
# Wait for an additional block to be safe
|
# Wait for an additional block to be safe
|
||||||
generate_blocks(config.get("EXPIRY_DELTA") + START_TIME_OFFSET + END_TIME_OFFSET)
|
generate_blocks_w_delay(10 + config.get("EXPIRY_DELTA"))
|
||||||
|
|
||||||
assert len(watcher.appointments) == 0
|
assert len(watcher.appointments) == 0
|
||||||
|
|
||||||
@@ -242,7 +243,7 @@ def test_filter_valid_breaches_random_data(watcher):
|
|||||||
for i in range(TEST_SET_SIZE):
|
for i in range(TEST_SET_SIZE):
|
||||||
dummy_appointment, _ = generate_dummy_appointment()
|
dummy_appointment, _ = generate_dummy_appointment()
|
||||||
uuid = uuid4().hex
|
uuid = uuid4().hex
|
||||||
appointments[uuid] = {"locator": dummy_appointment.locator, "end_time": dummy_appointment.end_time}
|
appointments[uuid] = {"locator": dummy_appointment.locator, "user_id": dummy_appointment.user_id}
|
||||||
watcher.db_manager.store_watcher_appointment(uuid, dummy_appointment.to_dict())
|
watcher.db_manager.store_watcher_appointment(uuid, dummy_appointment.to_dict())
|
||||||
watcher.db_manager.create_append_locator_map(dummy_appointment.locator, uuid)
|
watcher.db_manager.create_append_locator_map(dummy_appointment.locator, uuid)
|
||||||
|
|
||||||
@@ -282,7 +283,7 @@ def test_filter_valid_breaches(watcher):
|
|||||||
breaches = {dummy_appointment.locator: dispute_txid}
|
breaches = {dummy_appointment.locator: dispute_txid}
|
||||||
|
|
||||||
for uuid, appointment in appointments.items():
|
for uuid, appointment in appointments.items():
|
||||||
watcher.appointments[uuid] = {"locator": appointment.locator, "end_time": appointment.end_time}
|
watcher.appointments[uuid] = {"locator": appointment.locator, "user_id": appointment.user_id}
|
||||||
watcher.db_manager.store_watcher_appointment(uuid, dummy_appointment.to_dict())
|
watcher.db_manager.store_watcher_appointment(uuid, dummy_appointment.to_dict())
|
||||||
watcher.db_manager.create_append_locator_map(dummy_appointment.locator, uuid)
|
watcher.db_manager.create_append_locator_map(dummy_appointment.locator, uuid)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user