mirror of
https://github.com/aljazceru/python-teos.git
synced 2025-12-17 14:14:22 +01:00
Refactors the tests to match the new class definitions and config formats
This commit is contained in:
@@ -12,7 +12,7 @@ from common.tools import (
|
||||
check_locator_format,
|
||||
compute_locator,
|
||||
setup_data_folder,
|
||||
check_conf_fields,
|
||||
create_config_dict,
|
||||
extend_paths,
|
||||
setup_logging,
|
||||
)
|
||||
@@ -77,7 +77,7 @@ def test_setup_data_folder():
|
||||
|
||||
def test_check_conf_fields():
|
||||
# The test should work with a valid config_fields (obtained from a valid conf.py)
|
||||
assert type(check_conf_fields(conf_fields_copy)) == dict
|
||||
assert type(create_config_dict(conf_fields_copy)) == dict
|
||||
|
||||
|
||||
def test_bad_check_conf_fields():
|
||||
@@ -88,7 +88,7 @@ def test_bad_check_conf_fields():
|
||||
|
||||
# We should get a ValueError here.
|
||||
with pytest.raises(Exception):
|
||||
check_conf_fields(conf_fields_copy)
|
||||
create_config_dict(conf_fields_copy)
|
||||
|
||||
|
||||
def test_extend_paths():
|
||||
|
||||
@@ -1,32 +1,40 @@
|
||||
import os
|
||||
import pytest
|
||||
import random
|
||||
import requests
|
||||
from time import sleep
|
||||
from shutil import rmtree
|
||||
from threading import Thread
|
||||
|
||||
from coincurve import PrivateKey
|
||||
|
||||
from common.blob import Blob
|
||||
from teos.responder import TransactionTracker
|
||||
from teos.tools import bitcoin_cli
|
||||
from teos.db_manager import DBManager
|
||||
from common.appointment import Appointment
|
||||
from common.tools import compute_locator
|
||||
|
||||
from bitcoind_mock.transaction import create_dummy_transaction
|
||||
from bitcoind_mock.bitcoind import BitcoindMock
|
||||
from bitcoind_mock.conf import BTC_RPC_HOST, BTC_RPC_PORT
|
||||
from bitcoind_mock.transaction import create_dummy_transaction
|
||||
|
||||
from teos.carrier import Carrier
|
||||
from teos.tools import bitcoin_cli
|
||||
from teos.db_manager import DBManager
|
||||
from teos import LOG_PREFIX, DEFAULT_CONF
|
||||
from teos.responder import TransactionTracker
|
||||
from teos.block_processor import BlockProcessor
|
||||
|
||||
from teos import LOG_PREFIX
|
||||
import common.cryptographer
|
||||
from common.blob import Blob
|
||||
from common.logger import Logger
|
||||
from common.tools import compute_locator
|
||||
from common.appointment import Appointment
|
||||
from common.constants import LOCATOR_LEN_HEX
|
||||
from common.config_loader import ConfigLoader
|
||||
from common.cryptographer import Cryptographer
|
||||
|
||||
common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix=LOG_PREFIX)
|
||||
|
||||
# Set params to connect to regtest for testing
|
||||
DEFAULT_CONF["BTC_RPC_PORT"]["value"] = 18443
|
||||
DEFAULT_CONF["BTC_NETWORK"]["value"] = "regtest"
|
||||
|
||||
bitcoind_connect_params = {k: v["value"] for k, v in DEFAULT_CONF.items() if k.startswith("BTC")}
|
||||
bitcoind_feed_params = {k: v["value"] for k, v in DEFAULT_CONF.items() if k.startswith("FEED")}
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def run_bitcoind():
|
||||
@@ -54,6 +62,16 @@ def db_manager():
|
||||
rmtree("test_db")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def carrier():
|
||||
return Carrier(bitcoind_connect_params)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def block_processor():
|
||||
return BlockProcessor(bitcoind_connect_params)
|
||||
|
||||
|
||||
def generate_keypair():
|
||||
sk = PrivateKey()
|
||||
pk = sk.public_key
|
||||
@@ -84,7 +102,7 @@ def fork(block_hash):
|
||||
|
||||
def generate_dummy_appointment_data(real_height=True, start_time_offset=5, end_time_offset=30):
|
||||
if real_height:
|
||||
current_height = bitcoin_cli().getblockcount()
|
||||
current_height = bitcoin_cli(bitcoind_connect_params).getblockcount()
|
||||
|
||||
else:
|
||||
current_height = 10
|
||||
@@ -151,23 +169,7 @@ def generate_dummy_tracker():
|
||||
|
||||
|
||||
def get_config():
|
||||
data_folder = os.path.expanduser("~/.teos")
|
||||
config = {
|
||||
"BTC_RPC_USER": "username",
|
||||
"BTC_RPC_PASSWD": "password",
|
||||
"BTC_RPC_HOST": "localhost",
|
||||
"BTC_RPC_PORT": 8332,
|
||||
"BTC_NETWORK": "regtest",
|
||||
"FEED_PROTOCOL": "tcp",
|
||||
"FEED_ADDR": "127.0.0.1",
|
||||
"FEED_PORT": 28332,
|
||||
"DATA_FOLDER": data_folder,
|
||||
"MAX_APPOINTMENTS": 100,
|
||||
"EXPIRY_DELTA": 6,
|
||||
"MIN_TO_SELF_DELAY": 20,
|
||||
"SERVER_LOG_FILE": data_folder + "teos.log",
|
||||
"TEOS_SECRET_KEY": data_folder + "teos_sk.der",
|
||||
"DB_PATH": "appointments",
|
||||
}
|
||||
config_loader = ConfigLoader(".", DEFAULT_CONF, {})
|
||||
config = config_loader.build_config()
|
||||
|
||||
return config
|
||||
|
||||
@@ -5,10 +5,11 @@ from time import sleep
|
||||
from threading import Thread
|
||||
|
||||
from teos.api import API
|
||||
from teos.watcher import Watcher
|
||||
from teos.responder import Responder
|
||||
from teos.tools import bitcoin_cli
|
||||
from teos import HOST, PORT
|
||||
from teos.watcher import Watcher
|
||||
from teos.tools import bitcoin_cli
|
||||
from teos.inspector import Inspector
|
||||
from teos.responder import Responder
|
||||
from teos.chain_monitor import ChainMonitor
|
||||
|
||||
from test.teos.unit.conftest import (
|
||||
@@ -18,8 +19,11 @@ from test.teos.unit.conftest import (
|
||||
generate_dummy_appointment_data,
|
||||
generate_keypair,
|
||||
get_config,
|
||||
bitcoind_connect_params,
|
||||
bitcoind_feed_params,
|
||||
)
|
||||
|
||||
|
||||
from common.constants import LOCATOR_LEN_BYTES
|
||||
|
||||
|
||||
@@ -33,15 +37,21 @@ config = get_config()
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def run_api(db_manager):
|
||||
def run_api(db_manager, carrier, block_processor):
|
||||
sk, pk = generate_keypair()
|
||||
|
||||
watcher = Watcher(db_manager, Responder(db_manager), sk.to_der(), get_config())
|
||||
chain_monitor = ChainMonitor(watcher.block_queue, watcher.responder.block_queue)
|
||||
responder = Responder(db_manager, carrier, block_processor)
|
||||
watcher = Watcher(
|
||||
db_manager, block_processor, responder, sk.to_der(), config.get("MAX_APPOINTMENTS"), config.get("EXPIRY_DELTA")
|
||||
)
|
||||
|
||||
chain_monitor = ChainMonitor(
|
||||
watcher.block_queue, watcher.responder.block_queue, block_processor, bitcoind_feed_params
|
||||
)
|
||||
watcher.awake()
|
||||
chain_monitor.monitor_chain()
|
||||
|
||||
api_thread = Thread(target=API(watcher, config).start)
|
||||
api_thread = Thread(target=API(Inspector(block_processor, config.get("MIN_TO_SELF_DELAY")), watcher).start)
|
||||
api_thread.daemon = True
|
||||
api_thread.start()
|
||||
|
||||
@@ -131,7 +141,7 @@ def test_get_all_appointments_responder():
|
||||
locators = [appointment["locator"] for appointment in appointments]
|
||||
for locator, dispute_tx in locator_dispute_tx_map.items():
|
||||
if locator in locators:
|
||||
bitcoin_cli().sendrawtransaction(dispute_tx)
|
||||
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(dispute_tx)
|
||||
|
||||
# Confirm transactions
|
||||
generate_blocks(6)
|
||||
@@ -173,7 +183,7 @@ def test_request_appointment_watcher(new_appt_data):
|
||||
def test_request_appointment_responder(new_appt_data):
|
||||
# Let's do something similar to what we did with the watcher but now we'll send the dispute tx to the network
|
||||
dispute_tx = locator_dispute_tx_map[new_appt_data["appointment"]["locator"]]
|
||||
bitcoin_cli().sendrawtransaction(dispute_tx)
|
||||
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(dispute_tx)
|
||||
|
||||
r = add_appointment(new_appt_data)
|
||||
assert r.status_code == 200
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import pytest
|
||||
|
||||
from teos.block_processor import BlockProcessor
|
||||
from test.teos.unit.conftest import get_random_value_hex, generate_block, generate_blocks, fork
|
||||
from test.teos.unit.conftest import get_random_value_hex, generate_block, generate_blocks, fork, bitcoind_connect_params
|
||||
|
||||
|
||||
hex_tx = (
|
||||
@@ -14,19 +13,16 @@ hex_tx = (
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def best_block_hash():
|
||||
return BlockProcessor.get_best_block_hash()
|
||||
|
||||
|
||||
def test_get_best_block_hash(run_bitcoind, best_block_hash):
|
||||
def test_get_best_block_hash(run_bitcoind, block_processor):
|
||||
best_block_hash = block_processor.get_best_block_hash()
|
||||
# As long as bitcoind is running (or mocked in this case) we should always a block hash
|
||||
assert best_block_hash is not None and isinstance(best_block_hash, str)
|
||||
|
||||
|
||||
def test_get_block(best_block_hash):
|
||||
def test_get_block(block_processor):
|
||||
best_block_hash = block_processor.get_best_block_hash()
|
||||
# Getting a block from a block hash we are aware of should return data
|
||||
block = BlockProcessor.get_block(best_block_hash)
|
||||
block = block_processor.get_block(best_block_hash)
|
||||
|
||||
# Checking that the received block has at least the fields we need
|
||||
# FIXME: We could be more strict here, but we'll need to add those restrictions to bitcoind_sim too
|
||||
@@ -34,75 +30,75 @@ def test_get_block(best_block_hash):
|
||||
assert block.get("hash") == best_block_hash and "height" in block and "previousblockhash" in block and "tx" in block
|
||||
|
||||
|
||||
def test_get_random_block():
|
||||
block = BlockProcessor.get_block(get_random_value_hex(32))
|
||||
def test_get_random_block(block_processor):
|
||||
block = block_processor.get_block(get_random_value_hex(32))
|
||||
|
||||
assert block is None
|
||||
|
||||
|
||||
def test_get_block_count():
|
||||
block_count = BlockProcessor.get_block_count()
|
||||
def test_get_block_count(block_processor):
|
||||
block_count = block_processor.get_block_count()
|
||||
assert isinstance(block_count, int) and block_count >= 0
|
||||
|
||||
|
||||
def test_decode_raw_transaction():
|
||||
def test_decode_raw_transaction(block_processor):
|
||||
# We cannot exhaustively test this (we rely on bitcoind for this) but we can try to decode a correct transaction
|
||||
assert BlockProcessor.decode_raw_transaction(hex_tx) is not None
|
||||
assert block_processor.decode_raw_transaction(hex_tx) is not None
|
||||
|
||||
|
||||
def test_decode_raw_transaction_invalid():
|
||||
def test_decode_raw_transaction_invalid(block_processor):
|
||||
# Same but with an invalid one
|
||||
assert BlockProcessor.decode_raw_transaction(hex_tx[::-1]) is None
|
||||
assert block_processor.decode_raw_transaction(hex_tx[::-1]) is None
|
||||
|
||||
|
||||
def test_get_missed_blocks():
|
||||
target_block = BlockProcessor.get_best_block_hash()
|
||||
def test_get_missed_blocks(block_processor):
|
||||
target_block = block_processor.get_best_block_hash()
|
||||
|
||||
# Generate some blocks and store the hash in a list
|
||||
missed_blocks = []
|
||||
for _ in range(5):
|
||||
generate_block()
|
||||
missed_blocks.append(BlockProcessor.get_best_block_hash())
|
||||
missed_blocks.append(block_processor.get_best_block_hash())
|
||||
|
||||
# Check what we've missed
|
||||
assert BlockProcessor.get_missed_blocks(target_block) == missed_blocks
|
||||
assert block_processor.get_missed_blocks(target_block) == missed_blocks
|
||||
|
||||
# We can see how it does not work if we replace the target by the first element in the list
|
||||
block_tip = missed_blocks[0]
|
||||
assert BlockProcessor.get_missed_blocks(block_tip) != missed_blocks
|
||||
assert block_processor.get_missed_blocks(block_tip) != missed_blocks
|
||||
|
||||
# But it does again if we skip that block
|
||||
assert BlockProcessor.get_missed_blocks(block_tip) == missed_blocks[1:]
|
||||
assert block_processor.get_missed_blocks(block_tip) == missed_blocks[1:]
|
||||
|
||||
|
||||
def test_get_distance_to_tip():
|
||||
def test_get_distance_to_tip(block_processor):
|
||||
target_distance = 5
|
||||
|
||||
target_block = BlockProcessor.get_best_block_hash()
|
||||
target_block = block_processor.get_best_block_hash()
|
||||
|
||||
# Mine some blocks up to the target distance
|
||||
generate_blocks(target_distance)
|
||||
|
||||
# Check if the distance is properly computed
|
||||
assert BlockProcessor.get_distance_to_tip(target_block) == target_distance
|
||||
assert block_processor.get_distance_to_tip(target_block) == target_distance
|
||||
|
||||
|
||||
def test_is_block_in_best_chain():
|
||||
best_block_hash = BlockProcessor.get_best_block_hash()
|
||||
best_block = BlockProcessor.get_block(best_block_hash)
|
||||
def test_is_block_in_best_chain(block_processor):
|
||||
best_block_hash = block_processor.get_best_block_hash()
|
||||
best_block = block_processor.get_block(best_block_hash)
|
||||
|
||||
assert BlockProcessor.is_block_in_best_chain(best_block_hash)
|
||||
assert block_processor.is_block_in_best_chain(best_block_hash)
|
||||
|
||||
fork(best_block.get("previousblockhash"))
|
||||
generate_blocks(2)
|
||||
|
||||
assert not BlockProcessor.is_block_in_best_chain(best_block_hash)
|
||||
assert not block_processor.is_block_in_best_chain(best_block_hash)
|
||||
|
||||
|
||||
def test_find_last_common_ancestor():
|
||||
ancestor = BlockProcessor.get_best_block_hash()
|
||||
def test_find_last_common_ancestor(block_processor):
|
||||
ancestor = block_processor.get_best_block_hash()
|
||||
generate_blocks(3)
|
||||
best_block_hash = BlockProcessor.get_best_block_hash()
|
||||
best_block_hash = block_processor.get_best_block_hash()
|
||||
|
||||
# Create a fork (forking creates a block if the mock is set by events)
|
||||
fork(ancestor)
|
||||
@@ -111,6 +107,6 @@ def test_find_last_common_ancestor():
|
||||
generate_blocks(5)
|
||||
|
||||
# The last common ancestor between the old best and the new best should be the "ancestor"
|
||||
last_common_ancestor, dropped_txs = BlockProcessor.find_last_common_ancestor(best_block_hash)
|
||||
last_common_ancestor, dropped_txs = block_processor.find_last_common_ancestor(best_block_hash)
|
||||
assert last_common_ancestor == ancestor
|
||||
assert len(dropped_txs) == 3
|
||||
|
||||
@@ -5,6 +5,7 @@ from queue import Queue
|
||||
from teos.builder import Builder
|
||||
from teos.watcher import Watcher
|
||||
from teos.responder import Responder
|
||||
|
||||
from test.teos.unit.conftest import (
|
||||
get_random_value_hex,
|
||||
generate_dummy_appointment,
|
||||
@@ -12,8 +13,11 @@ from test.teos.unit.conftest import (
|
||||
generate_block,
|
||||
bitcoin_cli,
|
||||
get_config,
|
||||
bitcoind_connect_params,
|
||||
)
|
||||
|
||||
config = get_config()
|
||||
|
||||
|
||||
def test_build_appointments():
|
||||
appointments_data = {}
|
||||
@@ -89,8 +93,15 @@ def test_populate_block_queue():
|
||||
assert len(blocks) == 0
|
||||
|
||||
|
||||
def test_update_states_empty_list(db_manager):
|
||||
w = Watcher(db_manager=db_manager, responder=Responder(db_manager), sk_der=None, config=None)
|
||||
def test_update_states_empty_list(db_manager, carrier, block_processor):
|
||||
w = Watcher(
|
||||
db_manager=db_manager,
|
||||
block_processor=block_processor,
|
||||
responder=Responder(db_manager, carrier, block_processor),
|
||||
sk_der=None,
|
||||
max_appointments=config.get("MAX_APPOINTMENTS"),
|
||||
expiry_delta=config.get("EXPIRY_DELTA"),
|
||||
)
|
||||
|
||||
missed_blocks_watcher = []
|
||||
missed_blocks_responder = [get_random_value_hex(32)]
|
||||
@@ -103,13 +114,20 @@ def test_update_states_empty_list(db_manager):
|
||||
Builder.update_states(w, missed_blocks_responder, missed_blocks_watcher)
|
||||
|
||||
|
||||
def test_update_states_responder_misses_more(run_bitcoind, db_manager):
|
||||
w = Watcher(db_manager=db_manager, responder=Responder(db_manager), sk_der=None, config=get_config())
|
||||
def test_update_states_responder_misses_more(run_bitcoind, db_manager, carrier, block_processor):
|
||||
w = Watcher(
|
||||
db_manager=db_manager,
|
||||
block_processor=block_processor,
|
||||
responder=Responder(db_manager, carrier, block_processor),
|
||||
sk_der=None,
|
||||
max_appointments=config.get("MAX_APPOINTMENTS"),
|
||||
expiry_delta=config.get("EXPIRY_DELTA"),
|
||||
)
|
||||
|
||||
blocks = []
|
||||
for _ in range(5):
|
||||
generate_block()
|
||||
blocks.append(bitcoin_cli().getbestblockhash())
|
||||
blocks.append(bitcoin_cli(bitcoind_connect_params).getbestblockhash())
|
||||
|
||||
# Updating the states should bring both to the same last known block.
|
||||
w.awake()
|
||||
@@ -120,14 +138,21 @@ def test_update_states_responder_misses_more(run_bitcoind, db_manager):
|
||||
assert w.responder.last_known_block == blocks[-1]
|
||||
|
||||
|
||||
def test_update_states_watcher_misses_more(run_bitcoind, db_manager):
|
||||
def test_update_states_watcher_misses_more(db_manager, carrier, block_processor):
|
||||
# Same as before, but data is now in the Responder
|
||||
w = Watcher(db_manager=db_manager, responder=Responder(db_manager), sk_der=None, config=get_config())
|
||||
w = Watcher(
|
||||
db_manager=db_manager,
|
||||
block_processor=block_processor,
|
||||
responder=Responder(db_manager, carrier, block_processor),
|
||||
sk_der=None,
|
||||
max_appointments=config.get("MAX_APPOINTMENTS"),
|
||||
expiry_delta=config.get("EXPIRY_DELTA"),
|
||||
)
|
||||
|
||||
blocks = []
|
||||
for _ in range(5):
|
||||
generate_block()
|
||||
blocks.append(bitcoin_cli().getbestblockhash())
|
||||
blocks.append(bitcoin_cli(bitcoind_connect_params).getbestblockhash())
|
||||
|
||||
w.awake()
|
||||
w.responder.awake()
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import pytest
|
||||
|
||||
from teos.carrier import Carrier
|
||||
from bitcoind_mock.transaction import create_dummy_transaction
|
||||
from test.teos.unit.conftest import generate_blocks, get_random_value_hex
|
||||
from teos.rpc_errors import RPC_VERIFY_ALREADY_IN_CHAIN, RPC_DESERIALIZATION_ERROR
|
||||
@@ -14,11 +11,6 @@ from teos.rpc_errors import RPC_VERIFY_ALREADY_IN_CHAIN, RPC_DESERIALIZATION_ERR
|
||||
sent_txs = []
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def carrier():
|
||||
return Carrier()
|
||||
|
||||
|
||||
def test_send_transaction(run_bitcoind, carrier):
|
||||
tx = create_dummy_transaction()
|
||||
|
||||
@@ -56,15 +48,15 @@ def test_send_transaction_invalid_format(carrier):
|
||||
assert receipt.delivered is False and receipt.reason == RPC_DESERIALIZATION_ERROR
|
||||
|
||||
|
||||
def test_get_transaction():
|
||||
def test_get_transaction(carrier):
|
||||
# We should be able to get back every transaction we've sent
|
||||
for tx in sent_txs:
|
||||
tx_info = Carrier.get_transaction(tx)
|
||||
tx_info = carrier.get_transaction(tx)
|
||||
|
||||
assert tx_info is not None
|
||||
|
||||
|
||||
def test_get_non_existing_transaction():
|
||||
tx_info = Carrier.get_transaction(get_random_value_hex(32))
|
||||
def test_get_non_existing_transaction(carrier):
|
||||
tx_info = carrier.get_transaction(get_random_value_hex(32))
|
||||
|
||||
assert tx_info is None
|
||||
|
||||
@@ -3,17 +3,16 @@ import time
|
||||
from queue import Queue
|
||||
from threading import Thread, Event, Condition
|
||||
|
||||
from teos.block_processor import BlockProcessor
|
||||
from teos.chain_monitor import ChainMonitor
|
||||
|
||||
from test.teos.unit.conftest import get_random_value_hex, generate_block
|
||||
from test.teos.unit.conftest import get_random_value_hex, generate_block, bitcoind_connect_params, bitcoind_feed_params
|
||||
|
||||
|
||||
def test_init(run_bitcoind):
|
||||
def test_init(run_bitcoind, block_processor):
|
||||
# run_bitcoind is started here instead of later on to avoid race conditions while it initializes
|
||||
|
||||
# Not much to test here, just sanity checks to make sure nothing goes south in the future
|
||||
chain_monitor = ChainMonitor(Queue(), Queue())
|
||||
chain_monitor = ChainMonitor(Queue(), Queue(), block_processor, bitcoind_feed_params)
|
||||
|
||||
assert chain_monitor.best_tip is None
|
||||
assert isinstance(chain_monitor.last_tips, list) and len(chain_monitor.last_tips) == 0
|
||||
@@ -27,8 +26,8 @@ def test_init(run_bitcoind):
|
||||
assert isinstance(chain_monitor.responder_queue, Queue)
|
||||
|
||||
|
||||
def test_notify_subscribers():
|
||||
chain_monitor = ChainMonitor(Queue(), Queue())
|
||||
def test_notify_subscribers(block_processor):
|
||||
chain_monitor = ChainMonitor(Queue(), Queue(), block_processor, bitcoind_feed_params)
|
||||
# Subscribers are only notified as long as they are awake
|
||||
new_block = get_random_value_hex(32)
|
||||
|
||||
@@ -42,11 +41,11 @@ def test_notify_subscribers():
|
||||
assert chain_monitor.responder_queue.get() == new_block
|
||||
|
||||
|
||||
def test_update_state():
|
||||
def test_update_state(block_processor):
|
||||
# The state is updated after receiving a new block (and only if the block is not already known).
|
||||
# Let's start by setting a best_tip and a couple of old tips
|
||||
new_block_hash = get_random_value_hex(32)
|
||||
chain_monitor = ChainMonitor(Queue(), Queue())
|
||||
chain_monitor = ChainMonitor(Queue(), Queue(), block_processor, bitcoind_feed_params)
|
||||
chain_monitor.best_tip = new_block_hash
|
||||
chain_monitor.last_tips = [get_random_value_hex(32) for _ in range(5)]
|
||||
|
||||
@@ -63,14 +62,15 @@ def test_update_state():
|
||||
assert chain_monitor.best_tip == another_block_hash and new_block_hash == chain_monitor.last_tips[-1]
|
||||
|
||||
|
||||
def test_monitor_chain_polling(db_manager):
|
||||
def test_monitor_chain_polling(db_manager, block_processor):
|
||||
# Try polling with the Watcher
|
||||
wq = Queue()
|
||||
chain_monitor = ChainMonitor(wq, Queue())
|
||||
chain_monitor.best_tip = BlockProcessor.get_best_block_hash()
|
||||
chain_monitor = ChainMonitor(Queue(), Queue(), block_processor, bitcoind_feed_params)
|
||||
chain_monitor.best_tip = block_processor.get_best_block_hash()
|
||||
chain_monitor.polling_delta = 0.1
|
||||
|
||||
# monitor_chain_polling runs until terminate if set
|
||||
polling_thread = Thread(target=chain_monitor.monitor_chain_polling, kwargs={"polling_delta": 0.1}, daemon=True)
|
||||
polling_thread = Thread(target=chain_monitor.monitor_chain_polling, daemon=True)
|
||||
polling_thread.start()
|
||||
|
||||
# Check that nothing changes as long as a block is not generated
|
||||
@@ -88,10 +88,10 @@ def test_monitor_chain_polling(db_manager):
|
||||
polling_thread.join()
|
||||
|
||||
|
||||
def test_monitor_chain_zmq(db_manager):
|
||||
rq = Queue()
|
||||
chain_monitor = ChainMonitor(Queue(), rq)
|
||||
chain_monitor.best_tip = BlockProcessor.get_best_block_hash()
|
||||
def test_monitor_chain_zmq(db_manager, block_processor):
|
||||
responder_queue = Queue()
|
||||
chain_monitor = ChainMonitor(Queue(), responder_queue, block_processor, bitcoind_feed_params)
|
||||
chain_monitor.best_tip = block_processor.get_best_block_hash()
|
||||
|
||||
zmq_thread = Thread(target=chain_monitor.monitor_chain_zmq, daemon=True)
|
||||
zmq_thread.start()
|
||||
@@ -106,9 +106,9 @@ def test_monitor_chain_zmq(db_manager):
|
||||
assert chain_monitor.responder_queue.empty()
|
||||
|
||||
|
||||
def test_monitor_chain(db_manager):
|
||||
def test_monitor_chain(db_manager, block_processor):
|
||||
# Not much to test here, this should launch two threads (one per monitor approach) and finish on terminate
|
||||
chain_monitor = ChainMonitor(Queue(), Queue())
|
||||
chain_monitor = ChainMonitor(Queue(), Queue(), block_processor, bitcoind_feed_params)
|
||||
|
||||
chain_monitor.best_tip = None
|
||||
chain_monitor.monitor_chain()
|
||||
@@ -131,15 +131,16 @@ def test_monitor_chain(db_manager):
|
||||
generate_block()
|
||||
|
||||
|
||||
def test_monitor_chain_single_update(db_manager):
|
||||
def test_monitor_chain_single_update(db_manager, block_processor):
|
||||
# This test tests that if both threads try to add the same block to the queue, only the first one will make it
|
||||
chain_monitor = ChainMonitor(Queue(), Queue())
|
||||
chain_monitor = ChainMonitor(Queue(), Queue(), block_processor, bitcoind_feed_params)
|
||||
|
||||
chain_monitor.best_tip = None
|
||||
chain_monitor.polling_delta = 2
|
||||
|
||||
# We will create a block and wait for the polling thread. Then check the queues to see that the block hash has only
|
||||
# been added once.
|
||||
chain_monitor.monitor_chain(polling_delta=2)
|
||||
chain_monitor.monitor_chain()
|
||||
generate_block()
|
||||
|
||||
watcher_block = chain_monitor.watcher_queue.get()
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
from binascii import unhexlify
|
||||
|
||||
from teos.errors import *
|
||||
from teos.inspector import Inspector
|
||||
from common.appointment import Appointment
|
||||
from teos.block_processor import BlockProcessor
|
||||
from teos.conf import MIN_TO_SELF_DELAY
|
||||
|
||||
from test.teos.unit.conftest import get_random_value_hex, generate_dummy_appointment_data, generate_keypair, get_config
|
||||
|
||||
from common.constants import LOCATOR_LEN_BYTES, LOCATOR_LEN_HEX
|
||||
from common.cryptographer import Cryptographer
|
||||
from common.logger import Logger
|
||||
|
||||
from teos import LOG_PREFIX
|
||||
from teos.inspector import Inspector
|
||||
from teos.block_processor import BlockProcessor
|
||||
|
||||
import common.cryptographer
|
||||
from common.logger import Logger
|
||||
from common.appointment import Appointment
|
||||
from common.cryptographer import Cryptographer
|
||||
from common.constants import LOCATOR_LEN_BYTES, LOCATOR_LEN_HEX
|
||||
|
||||
from test.teos.unit.conftest import (
|
||||
get_random_value_hex,
|
||||
generate_dummy_appointment_data,
|
||||
generate_keypair,
|
||||
bitcoind_connect_params,
|
||||
get_config,
|
||||
)
|
||||
|
||||
common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix=LOG_PREFIX)
|
||||
|
||||
|
||||
inspector = Inspector(get_config())
|
||||
APPOINTMENT_OK = (0, None)
|
||||
|
||||
NO_HEX_STRINGS = [
|
||||
"R" * LOCATOR_LEN_HEX,
|
||||
get_random_value_hex(LOCATOR_LEN_BYTES - 1) + "PP",
|
||||
@@ -41,6 +42,11 @@ WRONG_TYPES = [
|
||||
]
|
||||
WRONG_TYPES_NO_STR = [[], unhexlify(get_random_value_hex(LOCATOR_LEN_BYTES)), 3.2, 2.0, (), object, {}, object()]
|
||||
|
||||
config = get_config()
|
||||
MIN_TO_SELF_DELAY = config.get("MIN_TO_SELF_DELAY")
|
||||
block_processor = BlockProcessor(bitcoind_connect_params)
|
||||
inspector = Inspector(block_processor, MIN_TO_SELF_DELAY)
|
||||
|
||||
|
||||
def test_check_locator():
|
||||
# Right appointment type, size and format
|
||||
@@ -200,7 +206,7 @@ def test_inspect(run_bitcoind):
|
||||
|
||||
# Valid appointment
|
||||
locator = get_random_value_hex(LOCATOR_LEN_BYTES)
|
||||
start_time = BlockProcessor.get_block_count() + 5
|
||||
start_time = block_processor.get_block_count() + 5
|
||||
end_time = start_time + 20
|
||||
to_self_delay = MIN_TO_SELF_DELAY
|
||||
encrypted_blob = get_random_value_hex(64)
|
||||
|
||||
@@ -1,27 +1,33 @@
|
||||
import json
|
||||
import pytest
|
||||
import random
|
||||
from queue import Queue
|
||||
from uuid import uuid4
|
||||
from queue import Queue
|
||||
from shutil import rmtree
|
||||
from copy import deepcopy
|
||||
from threading import Thread
|
||||
|
||||
from teos.db_manager import DBManager
|
||||
from teos.responder import Responder, TransactionTracker
|
||||
from teos.block_processor import BlockProcessor
|
||||
from teos.chain_monitor import ChainMonitor
|
||||
from teos.carrier import Carrier
|
||||
from teos.tools import bitcoin_cli
|
||||
from teos.db_manager import DBManager
|
||||
from teos.chain_monitor import ChainMonitor
|
||||
from teos.responder import Responder, TransactionTracker
|
||||
|
||||
from common.constants import LOCATOR_LEN_HEX
|
||||
from bitcoind_mock.transaction import create_dummy_transaction, create_tx_from_hex
|
||||
from test.teos.unit.conftest import generate_block, generate_blocks, get_random_value_hex
|
||||
from test.teos.unit.conftest import (
|
||||
generate_block,
|
||||
generate_blocks,
|
||||
get_random_value_hex,
|
||||
bitcoind_connect_params,
|
||||
bitcoind_feed_params,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def responder(db_manager):
|
||||
responder = Responder(db_manager)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue)
|
||||
def responder(db_manager, carrier, block_processor):
|
||||
responder = Responder(db_manager, carrier, block_processor)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||
chain_monitor.monitor_chain()
|
||||
|
||||
return responder
|
||||
@@ -61,7 +67,7 @@ def create_dummy_tracker_data(random_txid=False, penalty_rawtx=None):
|
||||
if random_txid is True:
|
||||
penalty_txid = get_random_value_hex(32)
|
||||
|
||||
appointment_end = bitcoin_cli().getblockcount() + 2
|
||||
appointment_end = bitcoin_cli(bitcoind_connect_params).getblockcount() + 2
|
||||
locator = dispute_txid[:LOCATOR_LEN_HEX]
|
||||
|
||||
return locator, dispute_txid, penalty_txid, penalty_rawtx, appointment_end
|
||||
@@ -86,21 +92,21 @@ def test_tracker_init(run_bitcoind):
|
||||
)
|
||||
|
||||
|
||||
def test_on_sync(run_bitcoind, responder):
|
||||
def test_on_sync(run_bitcoind, responder, block_processor):
|
||||
# We're on sync if we're 1 or less blocks behind the tip
|
||||
chain_tip = BlockProcessor.get_best_block_hash()
|
||||
assert Responder.on_sync(chain_tip) is True
|
||||
chain_tip = block_processor.get_best_block_hash()
|
||||
assert responder.on_sync(chain_tip) is True
|
||||
|
||||
generate_block()
|
||||
assert Responder.on_sync(chain_tip) is True
|
||||
assert responder.on_sync(chain_tip) is True
|
||||
|
||||
|
||||
def test_on_sync_fail(responder):
|
||||
def test_on_sync_fail(responder, block_processor):
|
||||
# This should fail if we're more than 1 block behind the tip
|
||||
chain_tip = BlockProcessor.get_best_block_hash()
|
||||
chain_tip = block_processor.get_best_block_hash()
|
||||
generate_blocks(2)
|
||||
|
||||
assert Responder.on_sync(chain_tip) is False
|
||||
assert responder.on_sync(chain_tip) is False
|
||||
|
||||
|
||||
def test_tracker_to_dict():
|
||||
@@ -147,8 +153,8 @@ def test_tracker_from_dict_invalid_data():
|
||||
assert True
|
||||
|
||||
|
||||
def test_init_responder(temp_db_manager):
|
||||
responder = Responder(temp_db_manager)
|
||||
def test_init_responder(temp_db_manager, carrier, block_processor):
|
||||
responder = Responder(temp_db_manager, carrier, block_processor)
|
||||
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.unconfirmed_txs, list) and len(responder.unconfirmed_txs) == 0
|
||||
@@ -156,8 +162,8 @@ def test_init_responder(temp_db_manager):
|
||||
assert responder.block_queue.empty()
|
||||
|
||||
|
||||
def test_handle_breach(db_manager):
|
||||
responder = Responder(db_manager)
|
||||
def test_handle_breach(db_manager, carrier, block_processor):
|
||||
responder = Responder(db_manager, carrier, block_processor)
|
||||
|
||||
uuid = uuid4().hex
|
||||
tracker = create_dummy_tracker()
|
||||
@@ -176,7 +182,11 @@ def test_handle_breach(db_manager):
|
||||
assert receipt.delivered is True
|
||||
|
||||
|
||||
def test_handle_breach_bad_response(responder):
|
||||
def test_handle_breach_bad_response(db_manager, block_processor):
|
||||
# We need a new carrier here, otherwise the transaction will be flagged as previously sent and receipt.delivered
|
||||
# will be True
|
||||
responder = Responder(db_manager, Carrier(bitcoind_connect_params), block_processor)
|
||||
|
||||
uuid = uuid4().hex
|
||||
tracker = create_dummy_tracker()
|
||||
|
||||
@@ -262,10 +272,10 @@ def test_add_tracker_already_confirmed(responder):
|
||||
assert penalty_txid not in responder.unconfirmed_txs
|
||||
|
||||
|
||||
def test_do_watch(temp_db_manager):
|
||||
def test_do_watch(temp_db_manager, carrier, block_processor):
|
||||
# Create a fresh responder to simplify the test
|
||||
responder = Responder(temp_db_manager)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue)
|
||||
responder = Responder(temp_db_manager, carrier, block_processor)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||
chain_monitor.monitor_chain()
|
||||
|
||||
trackers = [create_dummy_tracker(penalty_rawtx=create_dummy_transaction().hex()) for _ in range(20)]
|
||||
@@ -293,7 +303,7 @@ def test_do_watch(temp_db_manager):
|
||||
# And broadcast some of the transactions
|
||||
broadcast_txs = []
|
||||
for tracker in trackers[:5]:
|
||||
bitcoin_cli().sendrawtransaction(tracker.penalty_rawtx)
|
||||
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(tracker.penalty_rawtx)
|
||||
broadcast_txs.append(tracker.penalty_txid)
|
||||
|
||||
# Mine a block
|
||||
@@ -312,7 +322,7 @@ def test_do_watch(temp_db_manager):
|
||||
# Do the rest
|
||||
broadcast_txs = []
|
||||
for tracker in trackers[5:]:
|
||||
bitcoin_cli().sendrawtransaction(tracker.penalty_rawtx)
|
||||
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(tracker.penalty_rawtx)
|
||||
broadcast_txs.append(tracker.penalty_txid)
|
||||
|
||||
# Mine a block
|
||||
@@ -321,9 +331,9 @@ def test_do_watch(temp_db_manager):
|
||||
assert len(responder.tx_tracker_map) == 0
|
||||
|
||||
|
||||
def test_check_confirmations(db_manager):
|
||||
responder = Responder(db_manager)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue)
|
||||
def test_check_confirmations(db_manager, carrier, block_processor):
|
||||
responder = Responder(db_manager, carrier, block_processor)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||
chain_monitor.monitor_chain()
|
||||
|
||||
# check_confirmations checks, given a list of transaction for a block, what of the known penalty transaction have
|
||||
@@ -378,11 +388,11 @@ def test_get_txs_to_rebroadcast(responder):
|
||||
assert txs_to_rebroadcast == list(txs_missing_too_many_conf.keys())
|
||||
|
||||
|
||||
def test_get_completed_trackers(db_manager):
|
||||
initial_height = bitcoin_cli().getblockcount()
|
||||
def test_get_completed_trackers(db_manager, carrier, block_processor):
|
||||
initial_height = bitcoin_cli(bitcoind_connect_params).getblockcount()
|
||||
|
||||
responder = Responder(db_manager)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue)
|
||||
responder = Responder(db_manager, carrier, block_processor)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||
chain_monitor.monitor_chain()
|
||||
|
||||
# A complete tracker is a tracker that has reached the appointment end with enough confs (> MIN_CONFIRMATIONS)
|
||||
@@ -417,7 +427,7 @@ def test_get_completed_trackers(db_manager):
|
||||
}
|
||||
|
||||
for uuid, tracker in all_trackers.items():
|
||||
bitcoin_cli().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_blocks(6)
|
||||
@@ -438,9 +448,9 @@ def test_get_completed_trackers(db_manager):
|
||||
assert set(completed_trackers_ids) == set(ended_trackers_keys)
|
||||
|
||||
|
||||
def test_rebroadcast(db_manager):
|
||||
responder = Responder(db_manager)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue)
|
||||
def test_rebroadcast(db_manager, carrier, block_processor):
|
||||
responder = Responder(db_manager, carrier, block_processor)
|
||||
chain_monitor = ChainMonitor(Queue(), responder.block_queue, block_processor, bitcoind_feed_params)
|
||||
chain_monitor.monitor_chain()
|
||||
|
||||
txs_to_rebroadcast = []
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
from teos.tools import can_connect_to_bitcoind, in_correct_network, bitcoin_cli
|
||||
|
||||
from common.tools import check_sha256_hex_format
|
||||
from test.teos.unit.conftest import bitcoind_connect_params
|
||||
|
||||
|
||||
def test_in_correct_network(run_bitcoind):
|
||||
# The simulator runs as if it was regtest, so every other network should fail
|
||||
assert in_correct_network("mainnet") is False
|
||||
assert in_correct_network("testnet") is False
|
||||
assert in_correct_network("regtest") is True
|
||||
assert in_correct_network(bitcoind_connect_params, "mainnet") is False
|
||||
assert in_correct_network(bitcoind_connect_params, "testnet") is False
|
||||
assert in_correct_network(bitcoind_connect_params, "regtest") is True
|
||||
|
||||
|
||||
def test_can_connect_to_bitcoind():
|
||||
assert can_connect_to_bitcoind() is True
|
||||
assert can_connect_to_bitcoind(bitcoind_connect_params) is True
|
||||
|
||||
|
||||
# def test_can_connect_to_bitcoind_bitcoin_not_running():
|
||||
@@ -22,7 +22,7 @@ def test_can_connect_to_bitcoind():
|
||||
|
||||
def test_bitcoin_cli():
|
||||
try:
|
||||
bitcoin_cli().help()
|
||||
bitcoin_cli(bitcoind_connect_params).help()
|
||||
assert True
|
||||
|
||||
except Exception:
|
||||
|
||||
@@ -4,11 +4,19 @@ from shutil import rmtree
|
||||
from threading import Thread
|
||||
from coincurve import PrivateKey
|
||||
|
||||
from teos import LOG_PREFIX
|
||||
from teos.carrier import Carrier
|
||||
from teos.watcher import Watcher
|
||||
from teos.responder import Responder
|
||||
from teos.tools import bitcoin_cli
|
||||
from teos.chain_monitor import ChainMonitor
|
||||
from teos.responder import Responder
|
||||
from teos.db_manager import DBManager
|
||||
from teos.chain_monitor import ChainMonitor
|
||||
from teos.block_processor import BlockProcessor
|
||||
|
||||
import common.cryptographer
|
||||
from common.logger import Logger
|
||||
from common.tools import compute_locator
|
||||
from common.cryptographer import Cryptographer
|
||||
|
||||
from test.teos.unit.conftest import (
|
||||
generate_blocks,
|
||||
@@ -16,14 +24,9 @@ from test.teos.unit.conftest import (
|
||||
get_random_value_hex,
|
||||
generate_keypair,
|
||||
get_config,
|
||||
bitcoind_feed_params,
|
||||
bitcoind_connect_params,
|
||||
)
|
||||
from teos.conf import EXPIRY_DELTA, MAX_APPOINTMENTS
|
||||
|
||||
import common.cryptographer
|
||||
from teos import LOG_PREFIX
|
||||
from common.logger import Logger
|
||||
from common.tools import compute_locator
|
||||
from common.cryptographer import Cryptographer
|
||||
|
||||
common.cryptographer.logger = Logger(actor="Cryptographer", log_name_prefix=LOG_PREFIX)
|
||||
|
||||
@@ -33,6 +36,7 @@ START_TIME_OFFSET = 1
|
||||
END_TIME_OFFSET = 1
|
||||
TEST_SET_SIZE = 200
|
||||
|
||||
config = get_config()
|
||||
|
||||
signing_key, public_key = generate_keypair()
|
||||
|
||||
@@ -50,8 +54,22 @@ def temp_db_manager():
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def watcher(db_manager):
|
||||
watcher = Watcher(db_manager, Responder(db_manager), signing_key.to_der(), get_config())
|
||||
chain_monitor = ChainMonitor(watcher.block_queue, watcher.responder.block_queue)
|
||||
block_processor = BlockProcessor(bitcoind_connect_params)
|
||||
carrier = Carrier(bitcoind_connect_params)
|
||||
|
||||
responder = Responder(db_manager, carrier, block_processor)
|
||||
watcher = Watcher(
|
||||
db_manager,
|
||||
block_processor,
|
||||
responder,
|
||||
signing_key.to_der(),
|
||||
config.get("MAX_APPOINTMENTS"),
|
||||
config.get("EXPIRY_DELTA"),
|
||||
)
|
||||
|
||||
chain_monitor = ChainMonitor(
|
||||
watcher.block_queue, watcher.responder.block_queue, block_processor, bitcoind_feed_params
|
||||
)
|
||||
chain_monitor.monitor_chain()
|
||||
|
||||
return watcher
|
||||
@@ -89,9 +107,11 @@ def test_init(run_bitcoind, watcher):
|
||||
assert isinstance(watcher.appointments, dict) and len(watcher.appointments) == 0
|
||||
assert isinstance(watcher.locator_uuid_map, dict) and len(watcher.locator_uuid_map) == 0
|
||||
assert watcher.block_queue.empty()
|
||||
assert isinstance(watcher.config, dict)
|
||||
assert isinstance(watcher.signing_key, PrivateKey)
|
||||
assert isinstance(watcher.block_processor, BlockProcessor)
|
||||
assert isinstance(watcher.responder, Responder)
|
||||
assert isinstance(watcher.max_appointments, int)
|
||||
assert isinstance(watcher.expiry_delta, int)
|
||||
assert isinstance(watcher.signing_key, PrivateKey)
|
||||
|
||||
|
||||
def test_add_appointment(watcher):
|
||||
@@ -120,7 +140,7 @@ def test_add_too_many_appointments(watcher):
|
||||
# Any appointment on top of those should fail
|
||||
watcher.appointments = dict()
|
||||
|
||||
for _ in range(MAX_APPOINTMENTS):
|
||||
for _ in range(config.get("MAX_APPOINTMENTS")):
|
||||
appointment, dispute_tx = generate_dummy_appointment(
|
||||
start_time_offset=START_TIME_OFFSET, end_time_offset=END_TIME_OFFSET
|
||||
)
|
||||
@@ -160,7 +180,7 @@ def test_do_watch(watcher, temp_db_manager):
|
||||
|
||||
# Broadcast the first two
|
||||
for dispute_tx in dispute_txs[:2]:
|
||||
bitcoin_cli().sendrawtransaction(dispute_tx)
|
||||
bitcoin_cli(bitcoind_connect_params).sendrawtransaction(dispute_tx)
|
||||
|
||||
# After generating enough blocks, the number of appointments should have reduced by two
|
||||
generate_blocks(START_TIME_OFFSET + END_TIME_OFFSET)
|
||||
@@ -169,7 +189,7 @@ def test_do_watch(watcher, temp_db_manager):
|
||||
|
||||
# The rest of appointments will timeout after the end (2) + EXPIRY_DELTA
|
||||
# Wait for an additional block to be safe
|
||||
generate_blocks(EXPIRY_DELTA + START_TIME_OFFSET + END_TIME_OFFSET)
|
||||
generate_blocks(config.get("EXPIRY_DELTA") + START_TIME_OFFSET + END_TIME_OFFSET)
|
||||
|
||||
assert len(watcher.appointments) == 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user