mirror of
https://github.com/aljazceru/python-teos.git
synced 2025-12-17 22:24:23 +01:00
Refactord Watcher and BlockProcessor. Closes #36.
Brings back check_potential_matches and check_matches to the Watcher. The methods have now been renamed to check_matches (old check_potential_matches) and filter_valid_matches (old check_matches) to provide a better description of their purpose. decode_raw_transaction has been added to BlockProcessor
This commit is contained in:
@@ -1,6 +1,3 @@
|
||||
import binascii
|
||||
from hashlib import sha256
|
||||
|
||||
from pisa.logger import Logger
|
||||
from pisa.tools import bitcoin_cli
|
||||
from pisa.utils.auth_proxy import JSONRPCException
|
||||
@@ -45,6 +42,18 @@ class BlockProcessor:
|
||||
|
||||
return block_count
|
||||
|
||||
@staticmethod
|
||||
def decode_raw_transaction(raw_tx):
|
||||
|
||||
try:
|
||||
tx = bitcoin_cli().decoderawtransaction(raw_tx)
|
||||
|
||||
except JSONRPCException as e:
|
||||
tx = None
|
||||
logger.error("Can't build transaction from decoded data.", error=e.error)
|
||||
|
||||
return tx
|
||||
|
||||
def get_missed_blocks(self, last_know_block_hash):
|
||||
current_block_hash = self.get_best_block_hash()
|
||||
missed_blocks = []
|
||||
@@ -72,49 +81,6 @@ class BlockProcessor:
|
||||
|
||||
return distance
|
||||
|
||||
# FIXME: The following two functions does not seem to belong here. They come from the Watcher, and need to be
|
||||
# separated since they will be reused by the TimeTraveller.
|
||||
# DISCUSS: 36-who-should-check-appointment-trigger
|
||||
@staticmethod
|
||||
def get_potential_matches(txids, locator_uuid_map):
|
||||
potential_locators = {sha256(binascii.unhexlify(txid)).hexdigest(): txid for txid in txids}
|
||||
|
||||
# Check is any of the tx_ids in the received block is an actual match
|
||||
intersection = set(locator_uuid_map.keys()).intersection(potential_locators.keys())
|
||||
potential_matches = {locator: potential_locators[locator] for locator in intersection}
|
||||
|
||||
if len(potential_matches) > 0:
|
||||
logger.info("List of potential matches", potential_matches=potential_matches)
|
||||
|
||||
else:
|
||||
logger.info("No potential matches found")
|
||||
|
||||
return potential_matches
|
||||
|
||||
@staticmethod
|
||||
# NOTCOVERED
|
||||
def get_matches(potential_matches, locator_uuid_map, appointments):
|
||||
matches = []
|
||||
|
||||
for locator, dispute_txid in potential_matches.items():
|
||||
for uuid in locator_uuid_map[locator]:
|
||||
try:
|
||||
# ToDo: #20-test-tx-decrypting-edge-cases
|
||||
justice_rawtx = appointments[uuid].encrypted_blob.decrypt(dispute_txid)
|
||||
justice_txid = bitcoin_cli().decoderawtransaction(justice_rawtx).get("txid")
|
||||
logger.info("Match found for locator.", locator=locator, uuid=uuid, justice_txid=justice_txid)
|
||||
|
||||
except JSONRPCException as e:
|
||||
# Tx decode failed returns error code -22, maybe we should be more strict here. Leaving it simple
|
||||
# for the POC
|
||||
justice_txid = None
|
||||
justice_rawtx = None
|
||||
logger.error("Can't build transaction from decoded data.", error=e.error)
|
||||
|
||||
matches.append((locator, uuid, dispute_txid, justice_txid, justice_rawtx))
|
||||
|
||||
return matches
|
||||
|
||||
# DISCUSS: This method comes from the Responder and seems like it could go back there.
|
||||
@staticmethod
|
||||
# NOTCOVERED
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
from uuid import uuid4
|
||||
from queue import Queue
|
||||
from hashlib import sha256
|
||||
from threading import Thread
|
||||
from binascii import unhexlify
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
||||
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 pisa.logger import Logger
|
||||
from pisa.cleaner import Cleaner
|
||||
from pisa.conf import EXPIRY_DELTA, MAX_APPOINTMENTS, PISA_SECRET_KEY
|
||||
from pisa.responder import Responder
|
||||
from pisa.appointment import Appointment
|
||||
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
|
||||
|
||||
logger = Logger("Watcher")
|
||||
|
||||
@@ -115,35 +119,35 @@ class Watcher:
|
||||
expired_appointments, self.appointments, self.locator_uuid_map, self.db_manager
|
||||
)
|
||||
|
||||
potential_matches = BlockProcessor.get_potential_matches(txids, self.locator_uuid_map)
|
||||
matches = BlockProcessor.get_matches(potential_matches, self.locator_uuid_map, self.appointments)
|
||||
matches = self.get_matches(txids, self.locator_uuid_map)
|
||||
filtered_matches = self.filter_valid_matches(matches, self.locator_uuid_map, self.appointments)
|
||||
|
||||
for locator, uuid, dispute_txid, justice_txid, justice_rawtx in matches:
|
||||
for uuid, filtered_match in filtered_matches.items():
|
||||
# Errors decrypting the Blob will result in a None justice_txid
|
||||
if justice_txid is not None:
|
||||
if filtered_match["valid_match"] is True:
|
||||
logger.info(
|
||||
"Notifying responder and deleting appointment.",
|
||||
justice_txid=justice_txid,
|
||||
locator=locator,
|
||||
justice_txid=filtered_match["justice_txid"],
|
||||
locator=filtered_match["locator"],
|
||||
uuid=uuid,
|
||||
)
|
||||
|
||||
self.responder.add_response(
|
||||
uuid,
|
||||
dispute_txid,
|
||||
justice_txid,
|
||||
justice_rawtx,
|
||||
filtered_match["dispute_txid"],
|
||||
filtered_match["justice_txid"],
|
||||
filtered_match["justice_rawtx"],
|
||||
self.appointments[uuid].end_time,
|
||||
block_hash,
|
||||
)
|
||||
|
||||
# Delete the appointment and update db
|
||||
Cleaner.delete_complete_appointment(
|
||||
self.appointments, self.locator_uuid_map, locator, uuid, self.db_manager
|
||||
self.appointments, self.locator_uuid_map, filtered_match["locator"], uuid, self.db_manager
|
||||
)
|
||||
|
||||
# Register the last processed block for the watcher
|
||||
self.db_manager.store_last_block_hash_watcher(block_hash)
|
||||
# Register the last processed block for the watcher
|
||||
self.db_manager.store_last_block_hash_watcher(block_hash)
|
||||
|
||||
# Go back to sleep if there are no more appointments
|
||||
self.asleep = True
|
||||
@@ -151,3 +155,55 @@ class Watcher:
|
||||
self.block_queue = Queue()
|
||||
|
||||
logger.info("No more pending appointments, going back to sleep")
|
||||
|
||||
@staticmethod
|
||||
def compute_locator(tx_id):
|
||||
return sha256(unhexlify(tx_id)).hexdigest()
|
||||
|
||||
# DISCUSS: 36-who-should-check-appointment-trigger
|
||||
@staticmethod
|
||||
def get_matches(txids, locator_uuid_map):
|
||||
potential_locators = {Watcher.compute_locator(txid): txid for txid in txids}
|
||||
|
||||
# Check is any of the tx_ids in the received block is an actual match
|
||||
intersection = set(locator_uuid_map.keys()).intersection(potential_locators.keys())
|
||||
matches = {locator: potential_locators[locator] for locator in intersection}
|
||||
|
||||
if len(matches) > 0:
|
||||
logger.info("List of matches", potential_matches=matches)
|
||||
|
||||
else:
|
||||
logger.info("No matches found")
|
||||
|
||||
return matches
|
||||
|
||||
@staticmethod
|
||||
# NOTCOVERED
|
||||
def filter_valid_matches(matches, locator_uuid_map, appointments):
|
||||
filtered_matches = {}
|
||||
|
||||
for locator, dispute_txid in matches.items():
|
||||
for uuid in locator_uuid_map[locator]:
|
||||
|
||||
justice_rawtx = Cryptographer.decrypt(appointments[uuid].encrypted_blob, dispute_txid)
|
||||
justice_tx = BlockProcessor.decode_raw_transaction(justice_rawtx)
|
||||
|
||||
if justice_rawtx is not None:
|
||||
justice_txid = justice_tx.get("txid")
|
||||
valid_match = True
|
||||
|
||||
logger.info("Match found for locator.", locator=locator, uuid=uuid, justice_txid=justice_txid)
|
||||
|
||||
else:
|
||||
justice_txid = None
|
||||
valid_match = False
|
||||
|
||||
filtered_matches[uuid] = {
|
||||
"locator": locator,
|
||||
"dispute_txid": dispute_txid,
|
||||
"justice_txid": justice_txid,
|
||||
"justice_rawtx": justice_rawtx,
|
||||
"valid_match": valid_match,
|
||||
}
|
||||
|
||||
return filtered_matches
|
||||
|
||||
Reference in New Issue
Block a user