diff --git a/pisa/responder.py b/pisa/responder.py index fd7e6fc..5392864 100644 --- a/pisa/responder.py +++ b/pisa/responder.py @@ -15,28 +15,26 @@ logger = Logger("Responder") class Job: - def __init__(self, dispute_txid, justice_txid, justice_rawtx, appointment_end): + def __init__(self, locator, dispute_txid, justice_txid, justice_rawtx, appointment_end): + self.locator = locator self.dispute_txid = dispute_txid self.justice_txid = justice_txid self.justice_rawtx = justice_rawtx self.appointment_end = appointment_end - # FIXME: locator is here so we can give info about jobs for now. It can be either passed from watcher or info - # can be directly got from DB - self.locator = dispute_txid[:32] - @classmethod def from_dict(cls, job_data): + locator = job_data.get("locator") dispute_txid = job_data.get("dispute_txid") justice_txid = job_data.get("justice_txid") justice_rawtx = job_data.get("justice_rawtx") appointment_end = job_data.get("appointment_end") - if any(v is None for v in [dispute_txid, justice_txid, justice_rawtx, appointment_end]): + if any(v is None for v in [locator, dispute_txid, justice_txid, justice_rawtx, appointment_end]): raise ValueError("Wrong job data, some fields are missing") else: - job = cls(dispute_txid, justice_txid, justice_rawtx, appointment_end) + job = cls(locator, dispute_txid, justice_txid, justice_rawtx, appointment_end) return job @@ -79,7 +77,9 @@ class Responder: return synchronized - def add_response(self, uuid, dispute_txid, justice_txid, justice_rawtx, appointment_end, block_hash, retry=False): + def add_response( + self, uuid, locator, dispute_txid, justice_txid, justice_rawtx, appointment_end, block_hash, retry=False + ): if self.asleep: logger.info("Waking up") @@ -90,7 +90,9 @@ class Responder: # retry holds that information. If retry is true the job already exists if receipt.delivered: if not retry: - self.create_job(uuid, dispute_txid, justice_txid, justice_rawtx, appointment_end, receipt.confirmations) + self.create_job( + uuid, locator, dispute_txid, justice_txid, justice_rawtx, appointment_end, receipt.confirmations + ) else: # TODO: Add the missing reasons (e.g. RPC_VERIFY_REJECTED) @@ -100,8 +102,8 @@ class Responder: return receipt - def create_job(self, uuid, dispute_txid, justice_txid, justice_rawtx, appointment_end, confirmations=0): - job = Job(dispute_txid, justice_txid, justice_rawtx, appointment_end) + def create_job(self, uuid, locator, dispute_txid, justice_txid, justice_rawtx, appointment_end, confirmations=0): + job = Job(locator, dispute_txid, justice_txid, justice_rawtx, appointment_end) self.jobs[uuid] = job if justice_txid in self.tx_job_map: @@ -240,6 +242,7 @@ class Responder: for uuid in self.tx_job_map[txid]: job = self.jobs[uuid] receipt = self.add_response( + job.locator, uuid, job.dispute_txid, job.justice_txid, @@ -288,7 +291,13 @@ class Responder: # FIXME: Whether we decide to increase the retried counter or not, the current counter should be # maintained. There is no way of doing so with the current approach. Update if required self.add_response( - uuid, job.dispute_txid, job.justice_txid, job.justice_rawtx, job.appointment_end, block_hash + job.locator, + uuid, + job.dispute_txid, + job.justice_txid, + job.justice_rawtx, + job.appointment_end, + block_hash, ) logger.warning("Justice transaction banished. Resetting the job", justice_tx=job.justice_txid) diff --git a/pisa/watcher.py b/pisa/watcher.py index a451abb..4b2a4b7 100644 --- a/pisa/watcher.py +++ b/pisa/watcher.py @@ -7,10 +7,12 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.serialization import load_pem_private_key +from common.cryptographer import Cryptographer +from common.constants import LOCATOR_LEN_HEX + from pisa.logger import Logger from pisa.cleaner import Cleaner from pisa.responder import Responder -from pisa.cryptographer import Cryptographer from pisa.block_processor import BlockProcessor from pisa.utils.zmq_subscriber import ZMQHandler from pisa.conf import EXPIRY_DELTA, MAX_APPOINTMENTS, PISA_SECRET_KEY @@ -40,7 +42,7 @@ class Watcher: @staticmethod def compute_locator(tx_id): - return tx_id[:32] + return tx_id[:LOCATOR_LEN_HEX] def sign_appointment(self, appointment): data = appointment.serialize() @@ -134,6 +136,7 @@ class Watcher: self.responder.add_response( uuid, + filtered_match["locator"], filtered_match["dispute_txid"], filtered_match["justice_txid"], filtered_match["justice_rawtx"], diff --git a/test/unit/conftest.py b/test/unit/conftest.py index 49f8d5f..4c32a6d 100644 --- a/test/unit/conftest.py +++ b/test/unit/conftest.py @@ -18,10 +18,13 @@ from pisa.watcher import Watcher from pisa.tools import bitcoin_cli from pisa.db_manager import DBManager from pisa.appointment import Appointment + from test.simulator.utils import sha256d from test.simulator.transaction import TX from test.simulator.bitcoind_sim import run_simulator, HOST, PORT +from common.constants import LOCATOR_LEN_HEX + @pytest.fixture(scope="session") def run_bitcoind(): @@ -139,9 +142,14 @@ def generate_dummy_job(): dispute_txid = get_random_value_hex(32) justice_txid = get_random_value_hex(32) justice_rawtx = get_random_value_hex(100) + locator = dispute_txid[:LOCATOR_LEN_HEX] job_data = dict( - dispute_txid=dispute_txid, justice_txid=justice_txid, justice_rawtx=justice_rawtx, appointment_end=100 + locator=locator, + dispute_txid=dispute_txid, + justice_txid=justice_txid, + justice_rawtx=justice_rawtx, + appointment_end=100, ) return Job.from_dict(job_data) diff --git a/test/unit/test_cleaner.py b/test/unit/test_cleaner.py index 58cbeb9..b8d2238 100644 --- a/test/unit/test_cleaner.py +++ b/test/unit/test_cleaner.py @@ -6,8 +6,11 @@ from pisa.responder import Job from pisa.cleaner import Cleaner from pisa.appointment import Appointment from pisa.db_manager import WATCHER_PREFIX + from test.unit.conftest import get_random_value_hex +from common.constants import LOCATOR_LEN_BYTES, LOCATOR_LEN_HEX + CONFIRMATIONS = 6 ITEMS = 10 MAX_ITEMS = 100 @@ -23,7 +26,7 @@ def set_up_appointments(db_manager, total_appointments): for i in range(total_appointments): uuid = uuid4().hex - locator = get_random_value_hex(32) + locator = get_random_value_hex(LOCATOR_LEN_BYTES) appointment = Appointment(locator, None, None, None, None, None) appointments[uuid] = appointment @@ -55,9 +58,10 @@ def set_up_jobs(db_manager, total_jobs): # We use the same txid for justice and dispute here, it shouldn't matter justice_txid = get_random_value_hex(32) dispute_txid = get_random_value_hex(32) + locator = dispute_txid[:LOCATOR_LEN_HEX] # Assign both justice_txid and dispute_txid the same id (it shouldn't matter) - job = Job(dispute_txid, justice_txid, None, None) + job = Job(locator, dispute_txid, justice_txid, None, None) jobs[uuid] = job tx_job_map[justice_txid] = [uuid] @@ -131,9 +135,10 @@ def test_delete_completed_jobs_no_db_match(db_manager): for uuid in selected_jobs[: ITEMS // 2]: justice_txid = jobs[uuid].justice_txid dispute_txid = get_random_value_hex(32) + locator = dispute_txid[:LOCATOR_LEN_HEX] new_uuid = uuid4().hex - jobs[new_uuid] = Job(dispute_txid, justice_txid, None, None) + jobs[new_uuid] = Job(locator, dispute_txid, justice_txid, None, None) tx_job_map[justice_txid].append(new_uuid) selected_jobs.append(new_uuid) @@ -142,8 +147,9 @@ def test_delete_completed_jobs_no_db_match(db_manager): uuid = uuid4().hex justice_txid = get_random_value_hex(32) dispute_txid = get_random_value_hex(32) + locator = dispute_txid[:LOCATOR_LEN_HEX] - jobs[uuid] = Job(dispute_txid, justice_txid, None, None) + jobs[uuid] = Job(locator, dispute_txid, justice_txid, None, None) tx_job_map[justice_txid] = [uuid] selected_jobs.append(uuid) diff --git a/test/unit/test_responder.py b/test/unit/test_responder.py index 69fd8f3..b41e972 100644 --- a/test/unit/test_responder.py +++ b/test/unit/test_responder.py @@ -9,11 +9,14 @@ from queue import Queue, Empty from pisa import c_logger from pisa.db_manager import DBManager -from test.simulator.utils import sha256d from pisa.responder import Responder, Job -from test.simulator.bitcoind_sim import TX from pisa.block_processor import BlockProcessor from pisa.tools import check_txid_format, bitcoin_cli + +from common.constants import LOCATOR_LEN_HEX + +from test.simulator.utils import sha256d +from test.simulator.bitcoind_sim import TX from test.unit.conftest import generate_block, generate_blocks, get_random_value_hex c_logger.disabled = True @@ -58,18 +61,21 @@ def create_dummy_job_data(random_txid=False, justice_rawtx=None): justice_txid = get_random_value_hex(32) appointment_end = bitcoin_cli().getblockcount() + 2 + locator = dispute_txid[:LOCATOR_LEN_HEX] - return dispute_txid, justice_txid, justice_rawtx, appointment_end + return locator, dispute_txid, justice_txid, justice_rawtx, appointment_end def create_dummy_job(random_txid=False, justice_rawtx=None): - dispute_txid, justice_txid, justice_rawtx, appointment_end = create_dummy_job_data(random_txid, justice_rawtx) - return Job(dispute_txid, justice_txid, justice_rawtx, appointment_end) + locator, dispute_txid, justice_txid, justice_rawtx, appointment_end = create_dummy_job_data( + random_txid, justice_rawtx + ) + return Job(locator, dispute_txid, justice_txid, justice_rawtx, appointment_end) def test_job_init(run_bitcoind): - dispute_txid, justice_txid, justice_rawtx, appointment_end = create_dummy_job_data() - job = Job(dispute_txid, justice_txid, justice_rawtx, appointment_end) + locator, dispute_txid, justice_txid, justice_rawtx, appointment_end = create_dummy_job_data() + job = Job(locator, dispute_txid, justice_txid, justice_rawtx, appointment_end) assert ( job.dispute_txid == dispute_txid @@ -157,6 +163,7 @@ def test_add_response(db_manager): # The block_hash passed to add_response does not matter much now. It will in the future to deal with errors receipt = responder.add_response( + job.locator, uuid, job.dispute_txid, job.justice_txid, @@ -187,6 +194,7 @@ def test_add_bad_response(responder): # The block_hash passed to add_response does not matter much now. It will in the future to deal with errors receipt = responder.add_response( + job.locator, uuid, job.dispute_txid, job.justice_txid, @@ -204,7 +212,7 @@ def test_create_job(responder): for _ in range(20): uuid = uuid4().hex confirmations = 0 - dispute_txid, justice_txid, justice_rawtx, appointment_end = create_dummy_job_data(random_txid=True) + locator, dispute_txid, justice_txid, justice_rawtx, appointment_end = create_dummy_job_data(random_txid=True) # Check the job is not within the responder jobs before adding it assert uuid not in responder.jobs @@ -212,7 +220,7 @@ def test_create_job(responder): assert justice_txid not in responder.unconfirmed_txs # And that it is afterwards - responder.create_job(uuid, dispute_txid, justice_txid, justice_rawtx, appointment_end, confirmations) + responder.create_job(uuid, locator, dispute_txid, justice_txid, justice_rawtx, appointment_end, confirmations) assert uuid in responder.jobs assert justice_txid in responder.tx_job_map assert justice_txid in responder.unconfirmed_txs @@ -231,12 +239,12 @@ def test_create_job(responder): def test_create_job_same_justice_txid(responder): # Create the same job using two different uuids confirmations = 0 - dispute_txid, justice_txid, justice_rawtx, appointment_end = create_dummy_job_data(random_txid=True) + locator, dispute_txid, justice_txid, justice_rawtx, appointment_end = create_dummy_job_data(random_txid=True) uuid_1 = uuid4().hex uuid_2 = uuid4().hex - responder.create_job(uuid_1, dispute_txid, justice_txid, justice_rawtx, appointment_end, confirmations) - responder.create_job(uuid_2, dispute_txid, justice_txid, justice_rawtx, appointment_end, confirmations) + responder.create_job(uuid_1, locator, dispute_txid, justice_txid, justice_rawtx, appointment_end, confirmations) + responder.create_job(uuid_2, locator, dispute_txid, justice_txid, justice_rawtx, appointment_end, confirmations) # Check that both jobs have been added assert uuid_1 in responder.jobs and uuid_2 in responder.jobs @@ -261,11 +269,11 @@ def test_create_job_already_confirmed(responder): for i in range(20): uuid = uuid4().hex confirmations = i + 1 - dispute_txid, justice_txid, justice_rawtx, appointment_end = create_dummy_job_data( + locator, dispute_txid, justice_txid, justice_rawtx, appointment_end = create_dummy_job_data( justice_rawtx=TX.create_dummy_transaction() ) - responder.create_job(uuid, dispute_txid, justice_txid, justice_rawtx, appointment_end, confirmations) + responder.create_job(uuid, locator, dispute_txid, justice_txid, justice_rawtx, appointment_end, confirmations) assert justice_txid not in responder.unconfirmed_txs @@ -360,7 +368,9 @@ def test_check_confirmations(temp_db_manager): responder.unconfirmed_txs.extend(txs_subset) # We also need to add them to the tx_job_map since they would be there in normal conditions - responder.tx_job_map = {txid: Job(txid, None, None, None) for txid in responder.unconfirmed_txs} + responder.tx_job_map = { + txid: Job(txid[:LOCATOR_LEN_HEX], txid, None, None, None) for txid in responder.unconfirmed_txs + } # Let's make sure that there are no txs with missed confirmations yet assert len(responder.missed_confirmations) == 0 @@ -457,11 +467,11 @@ def test_rebroadcast(db_manager): # Rebroadcast calls add_response with retry=True. The job data is already in jobs. for i in range(20): uuid = uuid4().hex - dispute_txid, justice_txid, justice_rawtx, appointment_end = create_dummy_job_data( + locator, dispute_txid, justice_txid, justice_rawtx, appointment_end = create_dummy_job_data( justice_rawtx=TX.create_dummy_transaction() ) - responder.jobs[uuid] = Job(dispute_txid, justice_txid, justice_rawtx, appointment_end) + responder.jobs[uuid] = Job(locator, dispute_txid, justice_txid, justice_rawtx, appointment_end) responder.tx_job_map[justice_txid] = [uuid] responder.unconfirmed_txs.append(justice_txid)