From a17ac9b15d0876e46f80e6f1b3175c4a4398f208 Mon Sep 17 00:00:00 2001 From: Evgeni Pandurski Date: Wed, 9 Oct 2024 16:06:44 +0300 Subject: [PATCH 1/7] Add missing queue.task_done() calls --- swpt_stomp/rmq.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/swpt_stomp/rmq.py b/swpt_stomp/rmq.py index 64dc2c0..81065b2 100644 --- a/swpt_stomp/rmq.py +++ b/swpt_stomp/rmq.py @@ -281,6 +281,7 @@ async def send_acks() -> None: await aiormq_channel.basic_ack(delivery_tag, multiple=True) recv_queue.task_done() + recv_queue.task_done() consume_queue_task.cancel() loop = asyncio.get_running_loop() @@ -366,6 +367,7 @@ async def publish_messages() -> None: pending_confirmations.add(confirmation) recv_queue.task_done() + recv_queue.task_done() send_receipts_task.cancel() report_task.cancel() From 1a139c01c9194ab0f4c995e53199bec04fbe4c9e Mon Sep 17 00:00:00 2001 From: Evgeni Pandurski Date: Sat, 12 Oct 2024 16:19:59 +0300 Subject: [PATCH 2/7] Implement swpt-drainer CLI command --- README.md | 9 + docker/entrypoint.sh | 3 + pyproject.toml | 1 + swpt_stomp/configure_queue.py | 3 + swpt_stomp/drainer.py | 317 +++++++++++++++++++++++++++++++++ swpt_stomp/peer_data.py | 13 +- swpt_stomp/process_messages.py | 6 +- swpt_stomp/server.py | 4 +- tests/test_process_messages.py | 24 +-- 9 files changed, 359 insertions(+), 21 deletions(-) create mode 100644 swpt_stomp/drainer.py diff --git a/README.md b/README.md index 7586e04..d75550d 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,15 @@ container allows you to execute the following *documented commands*: For more information, run `swpt-client --help`. +* `swpt-drainer` + + Consumes (drains) a RabbitMQ queue associated with an already + deactivated Swaptacular peer node, freeing up resources. A peer node + ID, and a queue name should be specified as arguments. You can start + simultaneously as many drainers as you like. + + For more information, run `swpt-drainer --help`. + * `configure-queue` Configures a RabbitMQ queue that will contain messages which have to be diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 2486726..2673989 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -47,6 +47,9 @@ case $1 in swpt-client) exec "$@" ;; + swpt-drainer) + exec "$@" + ;; configure-queue) exec "$@" ;; diff --git a/pyproject.toml b/pyproject.toml index 144da5b..68731c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ black = "^23.7.0" [tool.poetry.scripts] swpt-client = "swpt_stomp.client:client" swpt-server = "swpt_stomp.server:server" +swpt-drainer = "swpt_stomp.drainer:drainer" configure-queue = "swpt_stomp.configure_queue:configure_queue" [tool.pylsp-mypy] diff --git a/swpt_stomp/configure_queue.py b/swpt_stomp/configure_queue.py index 42ac3dc..30190e9 100644 --- a/swpt_stomp/configure_queue.py +++ b/swpt_stomp/configure_queue.py @@ -79,6 +79,9 @@ async def bind_queue() -> None: if peer_data is None: _logger.error("Peer %s is not in the database.", peer_node_id) sys.exit(1) + if peer_data.is_deactivated: # pragma: no cover + _logger.error("Peer %s has been deactivated.", peer_node_id) + sys.exit(1) connection = await aio_pika.connect(broker_url) channel = await connection.channel() diff --git a/swpt_stomp/drainer.py b/swpt_stomp/drainer.py new file mode 100644 index 0000000..6e92131 --- /dev/null +++ b/swpt_stomp/drainer.py @@ -0,0 +1,317 @@ +############################################################################## +# Implements a drainer that consumes messages from existing queues +# associated with already deactivated Swaptacular peers. +# +# Here is how the different parts fit together: +# +# messages_queue responses_queue +# /-------\ (messages) /----------\ (resp. messages) /-------\ +# | |------------------->| |-------------------->| | +# |Rabbit | |drainer | |Rabbit | +# |MQ | AMQP 0.9.1 |asyncio | AMQP 0.9.1 |MQ | +# |Server | |task | |Server | +# | |<-------------------| |<--------------------| | +# \-------/ acks_queue \----------/ confirms_queue \-------/ +# (msg. acks) | (publ. confirms) +# | +# | +# V +# /---------------------------------\ +# | Node Peers Database | +# \---------------------------------/ +# +# The "drainer asyncio task" reads messages from the RabbitMQ Server +# and acks them immediately. However, for some of the messages the +# drainer task will generate fake responses (and will publish them to +# the RabbitMQ Server), as if the responses were generated by the +# deactivated peer. The role of the fake responses is to free up +# resources. +# +# The "Node Peers Database" contains information about the peers of +# the given node. +############################################################################## + +import logging +import sys +import asyncio +import click +from datetime import datetime, timezone +from swpt_stomp.loggers import configure_logging +from typing import Union, Optional +from functools import partial +from swpt_stomp.common import ( + WatermarkQueue, + ServerError, + Message, + set_event_loop_policy, +) +from swpt_stomp import smp_schemas +from swpt_stomp.rmq import consume_from_queue, publish_to_exchange +from swpt_stomp.server import EXCHANGE_NAMES +from swpt_stomp.peer_data import get_database_instance +from swpt_stomp.process_messages import ( + transform_message, + preprocess_message, + parse_message_body, +) + +_logger = logging.getLogger(__name__) +_configure_account_message = smp_schemas.ConfigureAccountMessageSchema() +_finalize_transfer_message = smp_schemas.FinalizeTransferMessageSchema() +_rejected_config_message = smp_schemas.RejectedConfigMessageSchema() + + +def generate_optional_response(message: Message) -> Optional[Message]: + if message.type == "AccountUpdate": + msg_data = parse_message_body(message) + assert msg_data["type"] == message.type + response_type = "ConfigureAccount" + response_json = _configure_account_message.dumps({ + "type": response_type, + "creditor_id": msg_data["creditor_id"], + "debtor_id": msg_data["debtor_id"], + "negligible_amount": 1e30, + "config_data": "", + "config_flags": 1, # scheduled for deletion + "seqnum": 0, + "ts": datetime.now(tz=timezone.utc), + }) + elif message.type == "PreparedTransfer": + msg_data = parse_message_body(message) + assert msg_data["type"] == message.type + response_type = "FinalizeTransfer" + response_json = _finalize_transfer_message.dumps({ + "type": response_type, + "creditor_id": msg_data["creditor_id"], + "debtor_id": msg_data["debtor_id"], + "transfer_id": msg_data["transfer_id"], + "coordinator_type": msg_data["coordinator_type"], + "coordinator_id": msg_data["coordinator_id"], + "coordinator_request_id": msg_data["coordinator_request_id"], + "committed_amount": 0, + "transfer_note": "", + "transfer_note_format": "", + "ts": datetime.now(tz=timezone.utc), + }) + elif message.type == "ConfigureAccount": + msg_data = parse_message_body(message) + assert msg_data["type"] == message.type + response_type = "RejectedConfig" + response_json = _rejected_config_message.dumps({ + "type": response_type, + "creditor_id": msg_data["creditor_id"], + "debtor_id": msg_data["debtor_id"], + "config_ts": msg_data["ts"], + "config_seqnum": msg_data["seqnum"], + "config_flags": msg_data["config_flags"], + "negligible_amount": msg_data["negligible_amount"], + "config_data": msg_data["config_data"], + "rejection_code": "NO_CONNECTION_TO_DEBTOR", + "ts": datetime.now(tz=timezone.utc), + }) + else: + return None + + return Message( + id=message.id, + type=response_type, + body=bytearray(response_json.encode("utf8")), + content_type="application/json", + ) + + +async def drain( + *, + peer_node_id: str, + nodedata_url: str, + protocol_broker_url, + protocol_broker_queue, + client_queue_size: int, + server_queue_size: int, +): + db = get_database_instance(url=nodedata_url) + owner_node_data = await db.get_node_data() + peer_data = await db.get_peer_data(peer_node_id, active_peers_only=False) + if peer_data is None: + raise RuntimeError(f"Peer {peer_node_id} is not in the database.") + if not peer_data.is_deactivated: + raise RuntimeError(f"Peer {peer_node_id} has not been deactivated.") + + acks_queue: WatermarkQueue[Union[str, None]] = WatermarkQueue( + client_queue_size + ) + messages_queue: asyncio.Queue[ + Union[Message, None, ServerError] + ] = asyncio.Queue(client_queue_size) + + responses_queue: WatermarkQueue[Union[Message, None]] = WatermarkQueue( + server_queue_size + ) + confirms_queue: asyncio.Queue[ + Union[str, None, ServerError] + ] = asyncio.Queue(server_queue_size) + + async def respond_to_messages_if_necessary(): + while message := await messages_queue.get(): + if isinstance(message, ServerError): + messages_queue.task_done() + raise message + if r := generate_optional_response(message): + await responses_queue.put(r) + await acks_queue.put(message.id) + messages_queue.task_done() + messages_queue.task_done() + + async def ignore_confirmations(): + while confirm := await confirms_queue.get(): + if isinstance(confirm, ServerError): + confirms_queue.task_done() + raise confirm + confirms_queue.task_done() + confirms_queue.task_done() + + loop = asyncio.get_running_loop() + read_messages_task = loop.create_task( + consume_from_queue( + messages_queue, + acks_queue, + url=protocol_broker_url, + queue_name=protocol_broker_queue, + transform_message=partial( + transform_message, owner_node_data, peer_data + ), + ) + ) + respond_to_messages_task = loop.create_task( + respond_to_messages_if_necessary() + ) + publish_responses_task = loop.create_task( + publish_to_exchange( + confirms_queue, + responses_queue, + url=protocol_broker_url, + exchange_name=EXCHANGE_NAMES[owner_node_data.node_type], + preprocess_message=partial( + preprocess_message, owner_node_data, peer_data + ), + ) + ) + ignore_confirmations_task = loop.create_task( + ignore_confirmations() + ) + + tasks = [ + read_messages_task, + respond_to_messages_task, + publish_responses_task, + ignore_confirmations_task, + ] + try: + await asyncio.gather(*tasks) + except asyncio.CancelledError: + pass + finally: + for t in tasks: + t.cancel() + await asyncio.wait(tasks) + + +@click.command() +@click.argument("peer_node_id") +@click.argument("queue_name") +@click.option( + "-n", + "--nodedata-url", + envvar="SWPT_NODEDATA_URL", + default="file:///var/lib/swpt-nodedata", + show_envvar=True, + show_default=True, + help=( + "URL of the database that contains current node's data, including " + "information about peer nodes." + ), +) +@click.option( + "-u", + "--broker-url", + envvar="PROTOCOL_BROKER_URL", + default="amqp://guest:guest@localhost:5672", + show_envvar=True, + show_default=True, + help="URL of the RabbitMQ broker to connect to.", +) +@click.option( + "-b", + "--client-buffer", + type=int, + envvar="SWPT_CLIENT_BUFFER", + default=100, + show_envvar=True, + show_default=True, + help="Maximum number of consumed messages to store in memory.", +) +@click.option( + "-b", + "--server-buffer", + type=int, + envvar="SWPT_SERVER_BUFFER", + default=100, + show_envvar=True, + show_default=True, + help="Maximum number of response messages to store in memory.", +) +@click.option( + "-l", + "--log-level", + type=click.Choice(["error", "warning", "info", "debug"]), + envvar="APP_LOG_LEVEL", + default="info", + show_envvar=True, + show_default=True, + help="Application log level.", +) +@click.option( + "-f", + "--log-format", + type=click.Choice(["text", "json"]), + envvar="APP_LOG_FORMAT", + default="text", + show_envvar=True, + show_default=True, + help="Application log format.", +) +def drainer( + peer_node_id: str, + queue_name: str, + nodedata_url: str, + broker_url: str, + client_buffer: int, + server_buffer: int, + log_level: str, + log_format: str, +): + """Consumes (drains) an existing queue associated with an already + deactivated Swaptacular node. + + PEER_NODE_ID: The node ID of the deactivated peer Swaptacular node. + + QUEUE_NAME: The name of the RabbitMQ queue to consume messages from. + """ + set_event_loop_policy() + configure_logging(level=log_level, format=log_format) + + asyncio.run( + drain( + peer_node_id=peer_node_id, + nodedata_url=nodedata_url, + client_queue_size=client_buffer, + server_queue_size=server_buffer, + protocol_broker_url=broker_url, + protocol_broker_queue=queue_name, + ) + ) + sys.exit(1) # pragma: nocover + + +if __name__ == "__main__": # pragma: nocover + drainer() diff --git a/swpt_stomp/peer_data.py b/swpt_stomp/peer_data.py index 1dec704..14474fa 100644 --- a/swpt_stomp/peer_data.py +++ b/swpt_stomp/peer_data.py @@ -152,6 +152,7 @@ class PeerData: "creditors_subnet", "debtors_subnet", "is_active", + "is_deactivated", ) node_type: NodeType node_id: str @@ -161,6 +162,7 @@ class PeerData: creditors_subnet: Subnet debtors_subnet: Subnet is_active: bool + is_deactivated: bool class DatabaseError(Exception): @@ -416,9 +418,10 @@ async def _get_peer_data( try: await self._read_file(f"{dir}/DEACTIVATED") except FileNotFoundError: + is_deactivated = False pass else: # pragma: nocover - return None + is_deactivated = True try: # Peers that do not have a file with the name "ACTIVE" in their @@ -428,11 +431,12 @@ async def _get_peer_data( # exchanges, bindings etc.) have been created. await self._read_file(f"{dir}/ACTIVE") except FileNotFoundError: # pragma: nocover - if active_peers_only: - return None is_active = False else: - is_active = True + is_active = not is_deactivated + + if active_peers_only and not is_active: + return None # pragma: nocover root_cert = await self._read_cert_file(f"{dir}/root-ca.crt") @@ -488,6 +492,7 @@ async def _get_peer_data( creditors_subnet=creditors_subnet, debtors_subnet=debtors_subnet, is_active=is_active, + is_deactivated=is_deactivated, ) diff --git a/swpt_stomp/process_messages.py b/swpt_stomp/process_messages.py index 178e96c..65ce5a9 100644 --- a/swpt_stomp/process_messages.py +++ b/swpt_stomp/process_messages.py @@ -28,7 +28,7 @@ def transform_message( message: RmqMessage, ) -> Message: owner_node_type = owner_node_data.node_type - msg_data = _parse_message_body( + msg_data = parse_message_body( message, allow_in_messages=(owner_node_type != NodeType.AA), allow_out_messages=(owner_node_type == NodeType.AA), @@ -88,7 +88,7 @@ async def preprocess_message( ) -> RmqMessage: try: owner_node_type = owner_node_data.node_type - msg_data = _parse_message_body( + msg_data = parse_message_body( message, allow_in_messages=(owner_node_type == NodeType.AA), allow_out_messages=(owner_node_type != NodeType.AA), @@ -240,7 +240,7 @@ async def preprocess_message( ) -def _parse_message_body( +def parse_message_body( m: Union[Message, RmqMessage], *, allow_in_messages: bool = True, diff --git a/swpt_stomp/server.py b/swpt_stomp/server.py index 35ecd2e..c0e4008 100644 --- a/swpt_stomp/server.py +++ b/swpt_stomp/server.py @@ -75,7 +75,7 @@ os.environ.get("APP_PEERS_CHECK_SECONDS", "3600") ) -_EXCHANGE_NAMES = { +EXCHANGE_NAMES = { NodeType.AA: "accounts_in", NodeType.CA: "creditors_in", NodeType.DA: "debtors_in", @@ -103,7 +103,7 @@ async def serve( loop = asyncio.get_running_loop() db = get_database_instance(url=nodedata_url) owner_node_data = await db.get_node_data() - exchange_name = _EXCHANGE_NAMES[owner_node_data.node_type] + exchange_name = EXCHANGE_NAMES[owner_node_data.node_type] connection, channel = await open_robust_channel(protocol_broker_url) def create_protocol() -> StompServer: diff --git a/tests/test_process_messages.py b/tests/test_process_messages.py index b0fb33c..bfbbdfe 100644 --- a/tests/test_process_messages.py +++ b/tests/test_process_messages.py @@ -125,7 +125,7 @@ def test_change_subnet(): def test_parse_message_body(): - from swpt_stomp.process_messages import _parse_message_body + from swpt_stomp.process_messages import parse_message_body acc_purge_body = bytearray( create_account_purge_msg(123, 456).encode("utf8") @@ -135,7 +135,7 @@ def test_parse_message_body(): ) with pytest.raises(ProcessingError): - _parse_message_body( + parse_message_body( Message( id="1", type="AccountPurge", @@ -144,7 +144,7 @@ def test_parse_message_body(): ) ) with pytest.raises(ProcessingError): - _parse_message_body( + parse_message_body( Message( id="1", type="WrongType", @@ -153,7 +153,7 @@ def test_parse_message_body(): ) ) with pytest.raises(ProcessingError): - _parse_message_body( + parse_message_body( Message( id="1", type="AccountPurge", @@ -162,7 +162,7 @@ def test_parse_message_body(): ) ) with pytest.raises(ProcessingError): - _parse_message_body( + parse_message_body( Message( id="1", type="AccountPurge", @@ -171,7 +171,7 @@ def test_parse_message_body(): ) ) with pytest.raises(ProcessingError): - _parse_message_body( + parse_message_body( Message( id="1", type="AccountPurge", @@ -180,7 +180,7 @@ def test_parse_message_body(): ) ) with pytest.raises(ProcessingError): - _parse_message_body( + parse_message_body( Message( id="1", type="AccountPurge", @@ -189,7 +189,7 @@ def test_parse_message_body(): ) ) - obj = _parse_message_body( + obj = parse_message_body( Message( id="1", type="AccountPurge", @@ -202,7 +202,7 @@ def test_parse_message_body(): assert obj["creditor_id"] == 456 with pytest.raises(ProcessingError): - _parse_message_body( + parse_message_body( Message( id="1", type="AccountPurge", @@ -213,7 +213,7 @@ def test_parse_message_body(): ) with pytest.raises(ProcessingError): - _parse_message_body( + parse_message_body( Message( id="1", type="AccountPurge", @@ -223,7 +223,7 @@ def test_parse_message_body(): allow_out_messages=False, ) with pytest.raises(ProcessingError): - _parse_message_body( + parse_message_body( Message( id="1", type="PrepareTransfer", @@ -233,7 +233,7 @@ def test_parse_message_body(): allow_in_messages=False, ) - obj = _parse_message_body( + obj = parse_message_body( Message( id="1", type="PrepareTransfer", From 8ac6b84e582b8f0feade8722c2466cf99aaa66f7 Mon Sep 17 00:00:00 2001 From: Evgeni Pandurski Date: Sat, 12 Oct 2024 20:26:29 +0300 Subject: [PATCH 3/7] Minor refactoring --- swpt_stomp/drainer.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/swpt_stomp/drainer.py b/swpt_stomp/drainer.py index 6e92131..fffc26f 100644 --- a/swpt_stomp/drainer.py +++ b/swpt_stomp/drainer.py @@ -56,17 +56,18 @@ ) _logger = logging.getLogger(__name__) -_configure_account_message = smp_schemas.ConfigureAccountMessageSchema() -_finalize_transfer_message = smp_schemas.FinalizeTransferMessageSchema() -_rejected_config_message = smp_schemas.RejectedConfigMessageSchema() +_configure_account = smp_schemas.ConfigureAccountMessageSchema() +_finalize_transfer = smp_schemas.FinalizeTransferMessageSchema() +_rejected_config = smp_schemas.RejectedConfigMessageSchema() def generate_optional_response(message: Message) -> Optional[Message]: - if message.type == "AccountUpdate": + msg_type = message.type + if msg_type == "AccountUpdate": msg_data = parse_message_body(message) - assert msg_data["type"] == message.type + assert msg_data["type"] == msg_type response_type = "ConfigureAccount" - response_json = _configure_account_message.dumps({ + response_json = _configure_account.dumps({ "type": response_type, "creditor_id": msg_data["creditor_id"], "debtor_id": msg_data["debtor_id"], @@ -76,11 +77,11 @@ def generate_optional_response(message: Message) -> Optional[Message]: "seqnum": 0, "ts": datetime.now(tz=timezone.utc), }) - elif message.type == "PreparedTransfer": + elif msg_type == "PreparedTransfer": msg_data = parse_message_body(message) - assert msg_data["type"] == message.type + assert msg_data["type"] == msg_type response_type = "FinalizeTransfer" - response_json = _finalize_transfer_message.dumps({ + response_json = _finalize_transfer.dumps({ "type": response_type, "creditor_id": msg_data["creditor_id"], "debtor_id": msg_data["debtor_id"], @@ -93,11 +94,11 @@ def generate_optional_response(message: Message) -> Optional[Message]: "transfer_note_format": "", "ts": datetime.now(tz=timezone.utc), }) - elif message.type == "ConfigureAccount": + elif msg_type == "ConfigureAccount": msg_data = parse_message_body(message) - assert msg_data["type"] == message.type + assert msg_data["type"] == msg_type response_type = "RejectedConfig" - response_json = _rejected_config_message.dumps({ + response_json = _rejected_config.dumps({ "type": response_type, "creditor_id": msg_data["creditor_id"], "debtor_id": msg_data["debtor_id"], From 4aafe8030e024b8c5cc0d467e58455777f77b346 Mon Sep 17 00:00:00 2001 From: Evgeni Pandurski Date: Sat, 12 Oct 2024 20:31:59 +0300 Subject: [PATCH 4/7] Minor refactoring --- swpt_stomp/drainer.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/swpt_stomp/drainer.py b/swpt_stomp/drainer.py index fffc26f..3c2d1ff 100644 --- a/swpt_stomp/drainer.py +++ b/swpt_stomp/drainer.py @@ -259,7 +259,7 @@ async def ignore_confirmations(): default=100, show_envvar=True, show_default=True, - help="Maximum number of response messages to store in memory.", + help="Maximum number of generated response messages to store in memory.", ) @click.option( "-l", @@ -291,10 +291,10 @@ def drainer( log_level: str, log_format: str, ): - """Consumes (drains) an existing queue associated with an already - deactivated Swaptacular node. + """Consumes (drains) a RabbitMQ queue associated with an already + deactivated Swaptacular peer node, freeing up resources. - PEER_NODE_ID: The node ID of the deactivated peer Swaptacular node. + PEER_NODE_ID: The node ID of the deactivated Swaptacular peer node. QUEUE_NAME: The name of the RabbitMQ queue to consume messages from. """ From aa6cff4e149e102fa19c8735823e8a9c3a3aa2ef Mon Sep 17 00:00:00 2001 From: Evgeni Pandurski Date: Sun, 13 Oct 2024 19:23:21 +0300 Subject: [PATCH 5/7] Add tests --- swpt_stomp/drainer.py | 26 +- test_data/AA/db/index | 1 + test_data/AA/db/index.old | 1 + test_data/AA/db/serial | 2 +- test_data/AA/db/serial.old | 2 +- test_data/AA/db/subnets/creditors/000002 | 1 + test_data/AA/db/subnets/creditors/SEQNUM | 2 +- .../DEACTIVATED | 1 + .../nodeinfo/stomp.toml | 3 + .../nodeinfo/updated-at.txt | 1 + .../nodetype.txt | 1 + .../peercert.crt | 114 +++++ .../queues.txt | 1 + .../root-ca.crt | 100 +++++ .../sub-ca.crt | 110 +++++ .../subnet.txt | 1 + test_data/CA/db/index | 1 + test_data/CA/db/index.old | 1 + test_data/CA/db/serial | 2 +- test_data/CA/db/serial.old | 2 +- test_data/CA/peers/deac00ed/DEACTIVATED | 1 + test_data/CA/peers/deac00ed/masq-subnet.txt | 1 + .../CA/peers/deac00ed/nodeinfo/stomp.toml | 3 + .../CA/peers/deac00ed/nodeinfo/updated-at.txt | 1 + test_data/CA/peers/deac00ed/nodetype.txt | 1 + test_data/CA/peers/deac00ed/peercert.crt | 113 +++++ test_data/CA/peers/deac00ed/queues.txt | 1 + test_data/CA/peers/deac00ed/root-ca.crt | 100 +++++ test_data/CA/peers/deac00ed/sub-ca.crt | 111 +++++ tests/test_cli.py | 17 + tests/test_drainer.py | 420 ++++++++++++++++++ 31 files changed, 1124 insertions(+), 18 deletions(-) create mode 100644 test_data/AA/db/subnets/creditors/000002 create mode 100644 test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/DEACTIVATED create mode 100644 test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/nodeinfo/stomp.toml create mode 100644 test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/nodeinfo/updated-at.txt create mode 100644 test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/nodetype.txt create mode 100644 test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/peercert.crt create mode 100644 test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/queues.txt create mode 100644 test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/root-ca.crt create mode 100644 test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/sub-ca.crt create mode 100644 test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/subnet.txt create mode 100644 test_data/CA/peers/deac00ed/DEACTIVATED create mode 100644 test_data/CA/peers/deac00ed/masq-subnet.txt create mode 100644 test_data/CA/peers/deac00ed/nodeinfo/stomp.toml create mode 100644 test_data/CA/peers/deac00ed/nodeinfo/updated-at.txt create mode 100644 test_data/CA/peers/deac00ed/nodetype.txt create mode 100644 test_data/CA/peers/deac00ed/peercert.crt create mode 100644 test_data/CA/peers/deac00ed/queues.txt create mode 100644 test_data/CA/peers/deac00ed/root-ca.crt create mode 100644 test_data/CA/peers/deac00ed/sub-ca.crt create mode 100644 tests/test_drainer.py diff --git a/swpt_stomp/drainer.py b/swpt_stomp/drainer.py index 3c2d1ff..0c688ef 100644 --- a/swpt_stomp/drainer.py +++ b/swpt_stomp/drainer.py @@ -133,9 +133,9 @@ async def drain( db = get_database_instance(url=nodedata_url) owner_node_data = await db.get_node_data() peer_data = await db.get_peer_data(peer_node_id, active_peers_only=False) - if peer_data is None: + if peer_data is None: # pragma: no cover raise RuntimeError(f"Peer {peer_node_id} is not in the database.") - if not peer_data.is_deactivated: + if not peer_data.is_deactivated: # pragma: no cover raise RuntimeError(f"Peer {peer_node_id} has not been deactivated.") acks_queue: WatermarkQueue[Union[str, None]] = WatermarkQueue( @@ -153,23 +153,23 @@ async def drain( ] = asyncio.Queue(server_queue_size) async def respond_to_messages_if_necessary(): - while message := await messages_queue.get(): - if isinstance(message, ServerError): + while m := await messages_queue.get(): + if isinstance(m, ServerError): messages_queue.task_done() - raise message - if r := generate_optional_response(message): + raise m + + if r := generate_optional_response(m): await responses_queue.put(r) - await acks_queue.put(message.id) + + await acks_queue.put(m.id) messages_queue.task_done() - messages_queue.task_done() + + messages_queue.task_done() # pragma: no cover async def ignore_confirmations(): - while confirm := await confirms_queue.get(): - if isinstance(confirm, ServerError): - confirms_queue.task_done() - raise confirm + while True: + await confirms_queue.get() confirms_queue.task_done() - confirms_queue.task_done() loop = asyncio.get_running_loop() read_messages_task = loop.create_task( diff --git a/test_data/AA/db/index b/test_data/AA/db/index index 3dbcfda..8dd6292 100644 --- a/test_data/AA/db/index +++ b/test_data/AA/db/index @@ -3,3 +3,4 @@ V 30221013155002Z 0AB0004918EB71A4182CC1E9D544AF94 unknown /O=Swaptacular Nodes V 30221013163014Z 0AB0004918EB71A4182CC1E9D544AF95 unknown /O=Swaptacular Nodes Registry/OU=Debtors Agents/serialNumber=060791aeca7637fa3357dfc0299fb4c5 V 240613172443Z 0AB0004918EB71A4182CC1E9D544AF96 unknown /O=Swaptacular Nodes Registry/OU=Accounting Authorities/serialNumber=1234abcd V 21230702140615Z 0AB0004918EB71A4182CC1E9D544AF97 unknown /O=Swaptacular Nodes Registry/OU=Accounting Authorities/serialNumber=1234abcd +V 30240214153420Z 0AB0004918EB71A4182CC1E9D544AF98 unknown /O=Swaptacular Nodes Registry/OU=Creditors Agents/serialNumber=09cab36b6079e09c32a9dfd60446c469 diff --git a/test_data/AA/db/index.old b/test_data/AA/db/index.old index 30b1011..3dbcfda 100644 --- a/test_data/AA/db/index.old +++ b/test_data/AA/db/index.old @@ -2,3 +2,4 @@ V 30221013153736Z 0AB0004918EB71A4182CC1E9D544AF93 unknown /O=Swaptacular Nodes V 30221013155002Z 0AB0004918EB71A4182CC1E9D544AF94 unknown /O=Swaptacular Nodes Registry/OU=Creditors Agents/serialNumber=5921983fe0e6eb987aeedca54ad3c708 V 30221013163014Z 0AB0004918EB71A4182CC1E9D544AF95 unknown /O=Swaptacular Nodes Registry/OU=Debtors Agents/serialNumber=060791aeca7637fa3357dfc0299fb4c5 V 240613172443Z 0AB0004918EB71A4182CC1E9D544AF96 unknown /O=Swaptacular Nodes Registry/OU=Accounting Authorities/serialNumber=1234abcd +V 21230702140615Z 0AB0004918EB71A4182CC1E9D544AF97 unknown /O=Swaptacular Nodes Registry/OU=Accounting Authorities/serialNumber=1234abcd diff --git a/test_data/AA/db/serial b/test_data/AA/db/serial index efb88eb..5f51c79 100644 --- a/test_data/AA/db/serial +++ b/test_data/AA/db/serial @@ -1 +1 @@ -0AB0004918EB71A4182CC1E9D544AF98 +0AB0004918EB71A4182CC1E9D544AF99 diff --git a/test_data/AA/db/serial.old b/test_data/AA/db/serial.old index 8246c0e..efb88eb 100644 --- a/test_data/AA/db/serial.old +++ b/test_data/AA/db/serial.old @@ -1 +1 @@ -0AB0004918EB71A4182CC1E9D544AF97 +0AB0004918EB71A4182CC1E9D544AF98 diff --git a/test_data/AA/db/subnets/creditors/000002 b/test_data/AA/db/subnets/creditors/000002 new file mode 100644 index 0000000..38db41a --- /dev/null +++ b/test_data/AA/db/subnets/creditors/000002 @@ -0,0 +1 @@ +09cab36b6079e09c32a9dfd60446c469 diff --git a/test_data/AA/db/subnets/creditors/SEQNUM b/test_data/AA/db/subnets/creditors/SEQNUM index d00491f..0cfbf08 100644 --- a/test_data/AA/db/subnets/creditors/SEQNUM +++ b/test_data/AA/db/subnets/creditors/SEQNUM @@ -1 +1 @@ -1 +2 diff --git a/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/DEACTIVATED b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/DEACTIVATED new file mode 100644 index 0000000..3e772d2 --- /dev/null +++ b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/DEACTIVATED @@ -0,0 +1 @@ +2024-10-13 diff --git a/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/nodeinfo/stomp.toml b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/nodeinfo/stomp.toml new file mode 100644 index 0000000..013f254 --- /dev/null +++ b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/nodeinfo/stomp.toml @@ -0,0 +1,3 @@ +servers = ["ca.example.com:1234"] +host = "/" +destination = "/exchange/creditors_in" diff --git a/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/nodeinfo/updated-at.txt b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/nodeinfo/updated-at.txt new file mode 100644 index 0000000..5efcaa1 --- /dev/null +++ b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/nodeinfo/updated-at.txt @@ -0,0 +1 @@ +2024-10-03 diff --git a/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/nodetype.txt b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/nodetype.txt new file mode 100644 index 0000000..bce1d10 --- /dev/null +++ b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/nodetype.txt @@ -0,0 +1 @@ +Creditors Agents diff --git a/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/peercert.crt b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/peercert.crt new file mode 100644 index 0000000..66206bb --- /dev/null +++ b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/peercert.crt @@ -0,0 +1,114 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0a:b0:00:49:18:eb:71:a4:18:2c:c1:e9:d5:44:af:98 + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=Swaptacular Nodes Registry, OU=Accounting Authorities/serialNumber=1234abcd + Validity + Not Before: Oct 13 15:34:20 2024 GMT + Not After : Feb 14 15:34:20 3024 GMT + Subject: O=Swaptacular Nodes Registry, OU=Creditors Agents/serialNumber=09cab36b6079e09c32a9dfd60446c469 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (3072 bit) + Modulus: + 00:d8:6a:8a:99:72:a1:78:91:cd:e1:7f:06:6b:40: + e2:99:fa:17:15:2b:a0:67:65:52:fa:2c:82:f5:1a: + 8b:2b:34:23:0f:a7:a8:87:cb:55:91:17:0a:d1:be: + 5e:b3:c7:de:43:56:17:61:00:bd:02:51:83:d2:98: + 10:44:5f:13:0d:b1:0f:e6:fb:a7:a5:e6:a8:16:b5: + 19:93:77:c0:36:70:ae:a5:d5:dc:51:88:de:51:39: + 25:11:5a:c8:d3:e7:bf:6b:95:36:b3:fd:da:3c:d7: + 73:6c:5e:09:32:55:d4:18:4c:e2:8d:d8:75:2f:05: + f1:25:42:ce:e6:fd:37:f6:4e:86:e7:79:fa:3d:e6: + cb:86:bc:dc:30:6e:5d:70:36:96:11:31:2d:88:0a: + 96:f7:12:b4:7b:98:0f:3e:74:e9:60:76:4e:d9:04: + 45:91:0c:bb:3e:74:cd:55:be:66:62:f3:e8:69:a9: + e9:06:af:5b:d1:4a:c0:86:b4:51:08:c7:72:68:cf: + 20:7e:b2:c2:44:23:fd:25:82:73:1e:9a:13:1e:f1: + dd:0d:5b:5c:2a:95:88:68:34:b9:e8:2b:dc:ed:d4: + 61:f5:a6:a3:61:89:fd:4f:31:61:58:80:c1:ab:c5: + c0:c6:af:1e:f0:57:c8:cb:82:d5:4c:e9:43:d6:97: + 9b:f2:00:72:fc:c1:53:29:47:aa:f6:af:26:0c:4a: + 28:29:9d:7a:e5:2d:31:b1:c3:33:b8:ee:5a:bc:1d: + 2a:8b:65:2a:04:5e:a8:ef:df:31:fe:86:8f:48:f3: + 69:43:33:ab:19:70:7c:f7:23:9e:e3:ed:8f:a9:d7: + fa:29:02:53:9f:6a:a4:9a:43:39:bc:12:e1:01:1c: + ed:ad:12:50:5e:c0:bb:38:a0:bb:8f:94:54:74:63: + a9:4c:7a:5c:4c:fa:ff:4a:b9:d5:6b:83:a6:f5:eb: + 6b:a7:5e:21:56:d3:3b:38:13:e1:c2:98:03:2b:94: + 3c:bf:8a:09:f2:85:f6:58:e1:05 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + 2C:CF:E8:58:52:78:FA:3E:BA:51:72:57:25:3A:19:B4:AE:52:C9:34 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Name Constraints: critical + Permitted: + DirName:O = Swaptacular Nodes Registry, OU = Creditors Agents, serialNumber = 09cab36b6079e09c32a9dfd60446c469 + X509v3 Subject Key Identifier: + BB:AC:74:EB:7F:8D:3B:D4:0B:33:2E:54:D0:E9:8D:25:DD:3B:08:0F + Netscape Comment: + Subnet: 000002 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 2d:ca:4c:12:4c:2c:d5:2d:10:d9:18:77:8d:74:69:c6:80:77: + 84:2f:f2:c5:b0:88:f5:70:05:45:38:e1:d7:6e:78:72:ca:b0: + a1:4c:41:0c:e5:60:15:fa:18:be:eb:0b:36:e4:d3:46:bf:45: + c0:d6:bf:37:db:ac:ec:e7:0f:08:45:0e:b3:0a:10:53:d1:63: + 4e:52:58:98:4d:84:65:bd:f3:ef:93:5e:6a:16:c3:07:21:45: + 73:43:7b:83:86:3f:a2:e6:ef:2f:11:cc:30:18:ca:95:f7:06: + 8b:82:1f:a1:3d:74:be:2f:bf:05:3b:52:25:66:0e:c0:5b:01: + fe:f7:8e:c0:26:23:68:b0:94:76:c7:09:f8:23:19:32:3c:80: + 77:93:6d:75:81:d1:2e:e1:12:63:76:c8:0a:62:e0:8d:4e:18: + 55:87:7b:67:fc:4a:e7:04:6f:b0:54:cb:1b:ca:c0:19:f8:a3: + 77:dd:74:d4:f9:b2:4d:35:2d:db:af:05:46:0a:68:b7:e1:3c: + 3d:f6:55:04:98:aa:a2:48:f5:b1:48:fd:a0:52:54:4a:86:0a: + 71:10:c9:18:f2:8c:f5:eb:a4:78:9f:52:82:7d:33:b0:21:5d: + 40:16:d6:da:2f:e4:b8:72:6b:dd:4e:2c:75:59:87:09:cb:fc: + 0d:af:3a:ae:75:64:e7:e1:7d:32:51:b5:f2:71:6c:e6:e7:09: + 34:e8:b5:d7:f8:98:b5:f2:bb:14:eb:9e:91:0f:35:eb:11:51: + 7a:2e:50:05:2a:05:ec:31:dd:52:66:5f:28:67:97:4d:12:a7: + 65:2c:c1:f9:69:e2:ce:a3:da:02:44:9f:e1:f4:bc:ad:68:11: + 64:53:cf:a3:16:47:12:f2:13:74:62:49:a9:d5:8b:c6:5c:1a: + c6:b1:75:99:2f:a8:1f:dd:e5:f7:4c:63:cd:69:ec:ba:c6:b1: + 0e:74:88:7d:9b:d6:86:d6:f5:dc:4f:57:6d:8b:00:4b:bf:35: + 43:aa:2d:d3:ad:76 +-----BEGIN CERTIFICATE----- +MIIFeTCCA+GgAwIBAgIQCrAASRjrcaQYLMHp1USvmDANBgkqhkiG9w0BAQsFADBZ +MSMwIQYDVQQKDBpTd2FwdGFjdWxhciBOb2RlcyBSZWdpc3RyeTEfMB0GA1UECwwW +QWNjb3VudGluZyBBdXRob3JpdGllczERMA8GA1UEBRMIMTIzNGFiY2QwIBcNMjQx +MDEzMTUzNDIwWhgPMzAyNDAyMTQxNTM0MjBaMGsxIzAhBgNVBAoMGlN3YXB0YWN1 +bGFyIE5vZGVzIFJlZ2lzdHJ5MRkwFwYDVQQLDBBDcmVkaXRvcnMgQWdlbnRzMSkw +JwYDVQQFEyAwOWNhYjM2YjYwNzllMDljMzJhOWRmZDYwNDQ2YzQ2OTCCAaIwDQYJ +KoZIhvcNAQEBBQADggGPADCCAYoCggGBANhqiplyoXiRzeF/BmtA4pn6FxUroGdl +UvosgvUaiys0Iw+nqIfLVZEXCtG+XrPH3kNWF2EAvQJRg9KYEERfEw2xD+b7p6Xm +qBa1GZN3wDZwrqXV3FGI3lE5JRFayNPnv2uVNrP92jzXc2xeCTJV1BhM4o3YdS8F +8SVCzub9N/ZOhud5+j3my4a83DBuXXA2lhExLYgKlvcStHuYDz506WB2TtkERZEM +uz50zVW+ZmLz6Gmp6QavW9FKwIa0UQjHcmjPIH6ywkQj/SWCcx6aEx7x3Q1bXCqV +iGg0uegr3O3UYfWmo2GJ/U8xYViAwavFwMavHvBXyMuC1UzpQ9aXm/IAcvzBUylH +qvavJgxKKCmdeuUtMbHDM7juWrwdKotlKgReqO/fMf6Gj0jzaUMzqxlwfPcjnuPt +j6nX+ikCU59qpJpDObwS4QEc7a0SUF7Auzigu4+UVHRjqUx6XEz6/0q51WuDpvXr +a6deIVbTOzgT4cKYAyuUPL+KCfKF9ljhBQIDAQABo4IBJzCCASMwHwYDVR0jBBgw +FoAULM/oWFJ4+j66UXJXJToZtK5SyTQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV +HSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDgYDVR0PAQH/BAQDAgEGMH8GA1Ud +HgEB/wR1MHOgcTBvpG0wazEjMCEGA1UECgwaU3dhcHRhY3VsYXIgTm9kZXMgUmVn +aXN0cnkxGTAXBgNVBAsMEENyZWRpdG9ycyBBZ2VudHMxKTAnBgNVBAUTIDA5Y2Fi +MzZiNjA3OWUwOWMzMmE5ZGZkNjA0NDZjNDY5MB0GA1UdDgQWBBS7rHTrf4071Asz +LlTQ6Y0l3TsIDzAdBglghkgBhvhCAQ0EEBYOU3VibmV0OiAwMDAwMDIwDQYJKoZI +hvcNAQELBQADggGBAC3KTBJMLNUtENkYd410acaAd4Qv8sWwiPVwBUU44ddueHLK +sKFMQQzlYBX6GL7rCzbk00a/RcDWvzfbrOznDwhFDrMKEFPRY05SWJhNhGW98++T +XmoWwwchRXNDe4OGP6Lm7y8RzDAYypX3BouCH6E9dL4vvwU7UiVmDsBbAf73jsAm +I2iwlHbHCfgjGTI8gHeTbXWB0S7hEmN2yApi4I1OGFWHe2f8SucEb7BUyxvKwBn4 +o3fddNT5sk01LduvBUYKaLfhPD32VQSYqqJI9bFI/aBSVEqGCnEQyRjyjPXrpHif +UoJ9M7AhXUAW1tov5Lhya91OLHVZhwnL/A2vOq51ZOfhfTJRtfJxbObnCTTotdf4 +mLXyuxTrnpEPNesRUXouUAUqBewx3VJmXyhnl00Sp2Uswflp4s6j2gJEn+H0vK1o +EWRTz6MWRxLyE3RiSanVi8ZcGsaxdZkvqB/d5fdMY81p7LrGsQ50iH2b1obW9dxP +V22LAEu/NUOqLdOtdg== +-----END CERTIFICATE----- diff --git a/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/queues.txt b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/queues.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/queues.txt @@ -0,0 +1 @@ +1 diff --git a/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/root-ca.crt b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/root-ca.crt new file mode 100644 index 0000000..9664288 --- /dev/null +++ b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/root-ca.crt @@ -0,0 +1,100 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2c:77:80:89:3e:e1:d2:1d:01:18:0f:9e:1e:9f:3f:15 + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=Swaptacular Nodes Registry, OU=Creditors Agents/serialNumber=09cab36b6079e09c32a9dfd60446c469 + Validity + Not Before: Oct 3 13:17:12 2024 GMT + Not After : Feb 4 13:17:12 3024 GMT + Subject: O=Swaptacular Nodes Registry, OU=Creditors Agents/serialNumber=09cab36b6079e09c32a9dfd60446c469 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (3072 bit) + Modulus: + 00:d8:6a:8a:99:72:a1:78:91:cd:e1:7f:06:6b:40: + e2:99:fa:17:15:2b:a0:67:65:52:fa:2c:82:f5:1a: + 8b:2b:34:23:0f:a7:a8:87:cb:55:91:17:0a:d1:be: + 5e:b3:c7:de:43:56:17:61:00:bd:02:51:83:d2:98: + 10:44:5f:13:0d:b1:0f:e6:fb:a7:a5:e6:a8:16:b5: + 19:93:77:c0:36:70:ae:a5:d5:dc:51:88:de:51:39: + 25:11:5a:c8:d3:e7:bf:6b:95:36:b3:fd:da:3c:d7: + 73:6c:5e:09:32:55:d4:18:4c:e2:8d:d8:75:2f:05: + f1:25:42:ce:e6:fd:37:f6:4e:86:e7:79:fa:3d:e6: + cb:86:bc:dc:30:6e:5d:70:36:96:11:31:2d:88:0a: + 96:f7:12:b4:7b:98:0f:3e:74:e9:60:76:4e:d9:04: + 45:91:0c:bb:3e:74:cd:55:be:66:62:f3:e8:69:a9: + e9:06:af:5b:d1:4a:c0:86:b4:51:08:c7:72:68:cf: + 20:7e:b2:c2:44:23:fd:25:82:73:1e:9a:13:1e:f1: + dd:0d:5b:5c:2a:95:88:68:34:b9:e8:2b:dc:ed:d4: + 61:f5:a6:a3:61:89:fd:4f:31:61:58:80:c1:ab:c5: + c0:c6:af:1e:f0:57:c8:cb:82:d5:4c:e9:43:d6:97: + 9b:f2:00:72:fc:c1:53:29:47:aa:f6:af:26:0c:4a: + 28:29:9d:7a:e5:2d:31:b1:c3:33:b8:ee:5a:bc:1d: + 2a:8b:65:2a:04:5e:a8:ef:df:31:fe:86:8f:48:f3: + 69:43:33:ab:19:70:7c:f7:23:9e:e3:ed:8f:a9:d7: + fa:29:02:53:9f:6a:a4:9a:43:39:bc:12:e1:01:1c: + ed:ad:12:50:5e:c0:bb:38:a0:bb:8f:94:54:74:63: + a9:4c:7a:5c:4c:fa:ff:4a:b9:d5:6b:83:a6:f5:eb: + 6b:a7:5e:21:56:d3:3b:38:13:e1:c2:98:03:2b:94: + 3c:bf:8a:09:f2:85:f6:58:e1:05 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:1 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + BB:AC:74:EB:7F:8D:3B:D4:0B:33:2E:54:D0:E9:8D:25:DD:3B:08:0F + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 61:b5:85:05:b0:da:c7:0c:cb:92:17:0f:1b:f4:6c:fe:bb:ec: + d4:db:e5:5e:1e:0d:ff:a8:1c:60:10:40:e1:40:39:a5:53:cd: + d7:dd:c1:2b:02:34:8f:77:f9:ac:6c:59:f0:04:e8:46:3c:c4: + b5:0b:a6:20:36:e7:ee:41:1a:9c:3a:81:c2:47:48:d0:7a:1e: + 4d:b2:8a:54:80:53:fa:1c:de:e1:d5:8f:1f:26:5a:f8:af:4a: + ad:be:aa:77:8f:38:c0:da:db:e6:92:d6:b4:d9:da:a2:6b:90: + 4d:09:88:4a:ab:36:c5:0e:36:0a:b0:77:1f:90:dd:94:78:00: + d2:30:53:2e:17:c0:0c:c9:f5:5d:78:e1:0a:46:72:23:63:0c: + 2a:32:b8:a6:b1:7f:94:b3:90:d4:b6:fe:ba:b6:47:85:fa:32: + 01:9a:ba:05:5d:9e:35:ea:f9:ea:7c:75:e8:00:f0:f7:f7:47: + a5:d1:5a:7a:9d:c8:47:1b:42:95:66:f6:37:58:20:e5:ac:13: + c5:b7:86:0a:fe:78:61:c4:d9:8d:86:42:a8:8b:68:41:e9:07: + 03:28:6b:0e:67:a6:fa:0e:08:a8:a6:45:cd:82:5c:fd:05:54: + f6:1a:03:40:86:29:71:2d:f6:fa:28:56:c8:4b:99:83:c4:56: + 4d:7a:cc:2c:e2:70:50:46:9b:63:01:a9:1f:66:8a:4b:35:fd: + 74:ea:95:21:88:ef:a6:a6:ef:42:9c:c5:85:d9:e5:95:72:00: + 59:f2:f8:95:5a:75:4b:bb:4e:87:e0:e8:03:6e:6f:e5:d0:33: + fc:3c:b5:bb:e6:fb:c6:7f:43:d9:29:49:f3:43:0c:39:af:d6: + 59:ab:16:da:46:a1:a9:c0:14:e1:e0:bb:10:b9:4a:35:1b:40: + de:9f:e0:c2:1a:b7:22:2e:38:e5:37:c7:02:3d:83:54:30:c6: + ee:bc:35:e4:ec:78:24:1f:6e:64:fc:cc:dd:46:a4:f9:43:8a: + e7:40:82:3e:89:7a +-----BEGIN CERTIFICATE----- +MIIEpzCCAw+gAwIBAgIQLHeAiT7h0h0BGA+eHp8/FTANBgkqhkiG9w0BAQsFADBr +MSMwIQYDVQQKDBpTd2FwdGFjdWxhciBOb2RlcyBSZWdpc3RyeTEZMBcGA1UECwwQ +Q3JlZGl0b3JzIEFnZW50czEpMCcGA1UEBRMgMDljYWIzNmI2MDc5ZTA5YzMyYTlk +ZmQ2MDQ0NmM0NjkwIBcNMjQxMDAzMTMxNzEyWhgPMzAyNDAyMDQxMzE3MTJaMGsx +IzAhBgNVBAoMGlN3YXB0YWN1bGFyIE5vZGVzIFJlZ2lzdHJ5MRkwFwYDVQQLDBBD +cmVkaXRvcnMgQWdlbnRzMSkwJwYDVQQFEyAwOWNhYjM2YjYwNzllMDljMzJhOWRm +ZDYwNDQ2YzQ2OTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBANhqiply +oXiRzeF/BmtA4pn6FxUroGdlUvosgvUaiys0Iw+nqIfLVZEXCtG+XrPH3kNWF2EA +vQJRg9KYEERfEw2xD+b7p6XmqBa1GZN3wDZwrqXV3FGI3lE5JRFayNPnv2uVNrP9 +2jzXc2xeCTJV1BhM4o3YdS8F8SVCzub9N/ZOhud5+j3my4a83DBuXXA2lhExLYgK +lvcStHuYDz506WB2TtkERZEMuz50zVW+ZmLz6Gmp6QavW9FKwIa0UQjHcmjPIH6y +wkQj/SWCcx6aEx7x3Q1bXCqViGg0uegr3O3UYfWmo2GJ/U8xYViAwavFwMavHvBX +yMuC1UzpQ9aXm/IAcvzBUylHqvavJgxKKCmdeuUtMbHDM7juWrwdKotlKgReqO/f +Mf6Gj0jzaUMzqxlwfPcjnuPtj6nX+ikCU59qpJpDObwS4QEc7a0SUF7Auzigu4+U +VHRjqUx6XEz6/0q51WuDpvXra6deIVbTOzgT4cKYAyuUPL+KCfKF9ljhBQIDAQAB +o0UwQzASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E +FgQUu6x063+NO9QLMy5U0OmNJd07CA8wDQYJKoZIhvcNAQELBQADggGBAGG1hQWw +2scMy5IXDxv0bP677NTb5V4eDf+oHGAQQOFAOaVTzdfdwSsCNI93+axsWfAE6EY8 +xLULpiA25+5BGpw6gcJHSNB6Hk2yilSAU/oc3uHVjx8mWvivSq2+qnePOMDa2+aS +1rTZ2qJrkE0JiEqrNsUONgqwdx+Q3ZR4ANIwUy4XwAzJ9V144QpGciNjDCoyuKax +f5SzkNS2/rq2R4X6MgGaugVdnjXq+ep8degA8Pf3R6XRWnqdyEcbQpVm9jdYIOWs +E8W3hgr+eGHE2Y2GQqiLaEHpBwMoaw5npvoOCKimRc2CXP0FVPYaA0CGKXEt9voo +VshLmYPEVk16zCzicFBGm2MBqR9miks1/XTqlSGI76am70KcxYXZ5ZVyAFny+JVa +dUu7Tofg6ANub+XQM/w8tbvm+8Z/Q9kpSfNDDDmv1lmrFtpGoanAFOHguxC5SjUb +QN6f4MIatyIuOOU3xwI9g1Qwxu68NeTseCQfbmT8zN1GpPlDiudAgj6Jeg== +-----END CERTIFICATE----- diff --git a/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/sub-ca.crt b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/sub-ca.crt new file mode 100644 index 0000000..53549f4 --- /dev/null +++ b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/sub-ca.crt @@ -0,0 +1,110 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2c:77:80:89:3e:e1:d2:1d:01:18:0f:9e:1e:9f:3f:17 + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=Swaptacular Nodes Registry, OU=Creditors Agents/serialNumber=09cab36b6079e09c32a9dfd60446c469 + Validity + Not Before: Oct 13 15:35:58 2024 GMT + Not After : Feb 14 15:35:58 3024 GMT + Subject: O=Swaptacular Nodes Registry, OU=Accounting Authorities/serialNumber=1234abcd + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (3072 bit) + Modulus: + 00:a1:76:1e:08:0a:c9:23:69:be:f2:db:96:fa:9e: + 06:d1:f6:b5:d9:27:fe:23:20:d0:d7:5a:0d:07:dd: + c7:78:e0:10:a9:5d:c6:a2:dc:38:d4:84:07:d0:18: + 2f:2a:98:d6:d9:1a:65:f3:d5:2c:96:16:c3:b4:dc: + 41:34:ce:55:e4:cc:98:b9:8b:ad:e6:71:07:4f:5b: + 03:80:34:07:28:4c:91:2f:eb:dd:99:71:07:8e:df: + 8f:2a:69:4a:01:5a:6a:53:d7:4d:f3:09:e2:9b:c3: + 86:24:6a:b7:18:25:bb:46:26:d4:93:b5:bd:2e:f6: + 24:41:82:36:13:a9:36:37:4e:8f:20:e4:bd:3b:ef: + 28:39:fa:af:7a:8d:8a:06:58:6a:cf:ac:fc:82:8d: + 8b:04:e9:e6:e2:00:18:bc:5b:af:cc:24:90:66:6a: + 46:31:64:60:c1:fd:99:a4:d3:d9:95:9d:8b:f6:8b: + d7:03:e0:f3:ea:b1:35:d3:43:d9:76:1c:c9:d2:d0: + f8:f0:93:d3:e4:2c:b0:02:28:5c:79:d1:e1:d2:90: + 84:9d:c3:bf:d7:4e:b3:f4:cb:d3:72:8d:06:01:c2: + 3a:a1:38:fa:73:ae:0e:23:19:78:7f:a8:d6:b8:96: + c5:c3:99:ea:4d:bb:39:22:85:33:b5:00:bc:35:16: + 14:94:93:11:5f:6d:f0:9c:c3:f1:b2:c4:34:87:8b: + 26:3e:d8:da:e5:1b:02:16:c1:1a:30:ec:c0:df:2d: + ed:ed:71:37:66:ac:39:8c:c7:19:08:c8:b4:89:8e: + f6:89:e4:2c:4c:9f:17:0c:f0:fd:82:7f:d8:a8:94: + 64:1c:93:63:cd:13:2d:78:c6:9b:2f:34:dc:a5:10: + a5:36:85:8a:12:7c:21:03:e0:95:88:90:7a:9e:26: + ee:f0:02:8b:90:0f:b2:71:e5:b0:45:3a:eb:50:0c: + 09:a7:d0:61:4a:35:24:93:74:f4:c4:0a:b4:a2:5d: + 43:43:08:10:2f:4f:96:4e:59:0f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + BB:AC:74:EB:7F:8D:3B:D4:0B:33:2E:54:D0:E9:8D:25:DD:3B:08:0F + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Name Constraints: critical + Permitted: + DirName:O = Swaptacular Nodes Registry, OU = Accounting Authorities, serialNumber = 1234abcd + X509v3 Subject Key Identifier: + 2C:CF:E8:58:52:78:FA:3E:BA:51:72:57:25:3A:19:B4:AE:52:C9:34 + Netscape Comment: + .. + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + d1:a0:2c:26:53:a4:b1:04:85:90:52:45:1a:f3:9d:d7:32:fb: + ff:aa:8a:0f:88:ae:38:43:91:9c:ae:fe:dc:f8:0e:52:06:b5: + 2b:f7:43:98:92:12:6b:6c:c1:fd:de:cf:3a:32:d8:28:00:10: + 80:e8:69:fe:8f:92:e0:91:19:f9:f9:a4:44:9f:3e:40:26:f5: + df:92:2f:de:cc:64:40:76:cc:bb:73:64:ca:46:e9:b4:bb:fa: + 71:54:09:ef:67:6e:4a:21:cb:10:21:6c:69:2c:3a:7b:2f:c9: + fe:a2:9b:8c:c8:c3:1b:f6:0a:13:31:75:0c:b9:3c:c5:12:4a: + a0:55:f3:f8:ea:9c:97:a3:88:4a:c1:21:79:ed:3c:fa:f9:58: + 3d:b1:20:d3:91:89:1a:28:d4:ea:17:0d:80:16:01:d5:05:b5: + 8f:22:7c:ac:50:d3:a1:e9:79:33:8c:dd:b7:25:35:72:08:96: + 12:5d:90:76:59:c5:88:7a:99:fa:e7:b3:4c:5f:19:a3:4a:d0: + 32:ac:13:d1:74:c5:5d:ab:96:90:ca:f7:64:6d:60:88:e3:ed: + 0d:08:24:01:64:ef:3b:2f:0f:ed:32:c6:c2:51:ee:8a:d5:36: + cf:b3:2f:b9:e4:47:94:25:86:d0:68:93:75:25:63:69:b8:09: + d8:74:e7:b0:99:7f:bd:78:e1:9d:a2:78:24:46:b5:4d:2a:f2: + 83:2b:35:5c:78:7c:50:d7:b5:70:70:33:fe:15:1d:29:0c:c3: + 9b:de:cf:3b:01:bf:1d:89:f7:0c:87:f4:a7:de:32:d6:95:f8: + 56:0e:5d:8b:3a:d1:6b:2c:cd:2b:fb:f7:1a:a2:d8:3e:c9:b7: + 1a:02:49:36:9e:99:4c:48:ee:2e:c2:e3:cd:02:9f:f0:15:64: + ec:a2:85:db:60:a9:6d:55:f1:a2:9b:c9:d7:7b:b0:47:0c:24: + 03:d2:54:f0:2c:a2:75:ff:b7:61:a9:e7:a3:5c:03:a2:7f:b9: + 20:ae:fb:79:7c:8d +-----BEGIN CERTIFICATE----- +MIIFODCCA6CgAwIBAgIQLHeAiT7h0h0BGA+eHp8/FzANBgkqhkiG9w0BAQsFADBr +MSMwIQYDVQQKDBpTd2FwdGFjdWxhciBOb2RlcyBSZWdpc3RyeTEZMBcGA1UECwwQ +Q3JlZGl0b3JzIEFnZW50czEpMCcGA1UEBRMgMDljYWIzNmI2MDc5ZTA5YzMyYTlk +ZmQ2MDQ0NmM0NjkwIBcNMjQxMDEzMTUzNTU4WhgPMzAyNDAyMTQxNTM1NThaMFkx +IzAhBgNVBAoMGlN3YXB0YWN1bGFyIE5vZGVzIFJlZ2lzdHJ5MR8wHQYDVQQLDBZB +Y2NvdW50aW5nIEF1dGhvcml0aWVzMREwDwYDVQQFEwgxMjM0YWJjZDCCAaIwDQYJ +KoZIhvcNAQEBBQADggGPADCCAYoCggGBAKF2HggKySNpvvLblvqeBtH2tdkn/iMg +0NdaDQfdx3jgEKldxqLcONSEB9AYLyqY1tkaZfPVLJYWw7TcQTTOVeTMmLmLreZx +B09bA4A0ByhMkS/r3ZlxB47fjyppSgFaalPXTfMJ4pvDhiRqtxglu0Ym1JO1vS72 +JEGCNhOpNjdOjyDkvTvvKDn6r3qNigZYas+s/IKNiwTp5uIAGLxbr8wkkGZqRjFk +YMH9maTT2ZWdi/aL1wPg8+qxNdND2XYcydLQ+PCT0+QssAIoXHnR4dKQhJ3Dv9dO +s/TL03KNBgHCOqE4+nOuDiMZeH+o1riWxcOZ6k27OSKFM7UAvDUWFJSTEV9t8JzD +8bLENIeLJj7Y2uUbAhbBGjDswN8t7e1xN2asOYzHGQjItImO9onkLEyfFwzw/YJ/ +2KiUZByTY80TLXjGmy803KUQpTaFihJ8IQPglYiQep4m7vACi5APsnHlsEU661AM +CafQYUo1JJN09MQKtKJdQ0MIEC9Plk5ZDwIDAQABo4HnMIHkMB8GA1UdIwQYMBaA +FLusdOt/jTvUCzMuVNDpjSXdOwgPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0P +AQH/BAQDAgEGMG0GA1UdHgEB/wRjMGGgXzBdpFswWTEjMCEGA1UECgwaU3dhcHRh +Y3VsYXIgTm9kZXMgUmVnaXN0cnkxHzAdBgNVBAsMFkFjY291bnRpbmcgQXV0aG9y +aXRpZXMxETAPBgNVBAUTCDEyMzRhYmNkMB0GA1UdDgQWBBQsz+hYUnj6PrpRclcl +Ohm0rlLJNDAPBglghkgBhvhCAQ0EAhYAMA0GCSqGSIb3DQEBCwUAA4IBgQDRoCwm +U6SxBIWQUkUa853XMvv/qooPiK44Q5Gcrv7c+A5SBrUr90OYkhJrbMH93s86Mtgo +ABCA6Gn+j5LgkRn5+aREnz5AJvXfki/ezGRAdsy7c2TKRum0u/pxVAnvZ25KIcsQ +IWxpLDp7L8n+opuMyMMb9goTMXUMuTzFEkqgVfP46pyXo4hKwSF57Tz6+Vg9sSDT +kYkaKNTqFw2AFgHVBbWPInysUNOh6XkzjN23JTVyCJYSXZB2WcWIepn657NMXxmj +StAyrBPRdMVdq5aQyvdkbWCI4+0NCCQBZO87Lw/tMsbCUe6K1TbPsy+55EeUJYbQ +aJN1JWNpuAnYdOewmX+9eOGdongkRrVNKvKDKzVceHxQ17VwcDP+FR0pDMOb3s87 +Ab8difcMh/Sn3jLWlfhWDl2LOtFrLM0r+/caotg+ybcaAkk2nplMSO4uwuPNAp/w +FWTsooXbYKltVfGim8nXe7BHDCQD0lTwLKJ1/7dhqeejXAOif7kgrvt5fI0= +-----END CERTIFICATE----- diff --git a/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/subnet.txt b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/subnet.txt new file mode 100644 index 0000000..726c2db --- /dev/null +++ b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/subnet.txt @@ -0,0 +1 @@ +000002 diff --git a/test_data/CA/db/index b/test_data/CA/db/index index 66efbaf..3ce945d 100644 --- a/test_data/CA/db/index +++ b/test_data/CA/db/index @@ -2,3 +2,4 @@ V 30221012174054Z 829735ACEFACF31A37096F10CA25DBA8 unknown /O=Swaptacular Nodes V 30221013154159Z 829735ACEFACF31A37096F10CA25DBA9 unknown /O=Swaptacular Nodes Registry/OU=Accounting Authorities/serialNumber=1234abcd V 240613174044Z 829735ACEFACF31A37096F10CA25DBAA unknown /O=Swaptacular Nodes Registry/OU=Creditors Agents/serialNumber=5921983fe0e6eb987aeedca54ad3c708 V 21230702140744Z 829735ACEFACF31A37096F10CA25DBAB unknown /O=Swaptacular Nodes Registry/OU=Creditors Agents/serialNumber=5921983fe0e6eb987aeedca54ad3c708 +V 30240214131330Z 829735ACEFACF31A37096F10CA25DBAC unknown /O=Swaptacular Nodes Registry/OU=Accounting Authorities/serialNumber=deac00ed diff --git a/test_data/CA/db/index.old b/test_data/CA/db/index.old index ed8afc9..66efbaf 100644 --- a/test_data/CA/db/index.old +++ b/test_data/CA/db/index.old @@ -1,3 +1,4 @@ V 30221012174054Z 829735ACEFACF31A37096F10CA25DBA8 unknown /O=Swaptacular Nodes Registry/OU=Creditors Agents/serialNumber=5921983fe0e6eb987aeedca54ad3c708 V 30221013154159Z 829735ACEFACF31A37096F10CA25DBA9 unknown /O=Swaptacular Nodes Registry/OU=Accounting Authorities/serialNumber=1234abcd V 240613174044Z 829735ACEFACF31A37096F10CA25DBAA unknown /O=Swaptacular Nodes Registry/OU=Creditors Agents/serialNumber=5921983fe0e6eb987aeedca54ad3c708 +V 21230702140744Z 829735ACEFACF31A37096F10CA25DBAB unknown /O=Swaptacular Nodes Registry/OU=Creditors Agents/serialNumber=5921983fe0e6eb987aeedca54ad3c708 diff --git a/test_data/CA/db/serial b/test_data/CA/db/serial index 9e6e465..dec9ede 100644 --- a/test_data/CA/db/serial +++ b/test_data/CA/db/serial @@ -1 +1 @@ -829735ACEFACF31A37096F10CA25DBAC +829735ACEFACF31A37096F10CA25DBAD diff --git a/test_data/CA/db/serial.old b/test_data/CA/db/serial.old index ce39dbf..9e6e465 100644 --- a/test_data/CA/db/serial.old +++ b/test_data/CA/db/serial.old @@ -1 +1 @@ -829735ACEFACF31A37096F10CA25DBAB +829735ACEFACF31A37096F10CA25DBAC diff --git a/test_data/CA/peers/deac00ed/DEACTIVATED b/test_data/CA/peers/deac00ed/DEACTIVATED new file mode 100644 index 0000000..3e772d2 --- /dev/null +++ b/test_data/CA/peers/deac00ed/DEACTIVATED @@ -0,0 +1 @@ +2024-10-13 diff --git a/test_data/CA/peers/deac00ed/masq-subnet.txt b/test_data/CA/peers/deac00ed/masq-subnet.txt new file mode 100644 index 0000000..a12b836 --- /dev/null +++ b/test_data/CA/peers/deac00ed/masq-subnet.txt @@ -0,0 +1 @@ +000001 diff --git a/test_data/CA/peers/deac00ed/nodeinfo/stomp.toml b/test_data/CA/peers/deac00ed/nodeinfo/stomp.toml new file mode 100644 index 0000000..9f9edac --- /dev/null +++ b/test_data/CA/peers/deac00ed/nodeinfo/stomp.toml @@ -0,0 +1,3 @@ +servers = ["deactivated.example.com:1234"] +host = "/" +destination = "/exchange/accounts_in" diff --git a/test_data/CA/peers/deac00ed/nodeinfo/updated-at.txt b/test_data/CA/peers/deac00ed/nodeinfo/updated-at.txt new file mode 100644 index 0000000..3e772d2 --- /dev/null +++ b/test_data/CA/peers/deac00ed/nodeinfo/updated-at.txt @@ -0,0 +1 @@ +2024-10-13 diff --git a/test_data/CA/peers/deac00ed/nodetype.txt b/test_data/CA/peers/deac00ed/nodetype.txt new file mode 100644 index 0000000..b161b0d --- /dev/null +++ b/test_data/CA/peers/deac00ed/nodetype.txt @@ -0,0 +1 @@ +Accounting Authorities diff --git a/test_data/CA/peers/deac00ed/peercert.crt b/test_data/CA/peers/deac00ed/peercert.crt new file mode 100644 index 0000000..5d2dbd4 --- /dev/null +++ b/test_data/CA/peers/deac00ed/peercert.crt @@ -0,0 +1,113 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 82:97:35:ac:ef:ac:f3:1a:37:09:6f:10:ca:25:db:ac + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=Swaptacular Nodes Registry, OU=Creditors Agents/serialNumber=5921983fe0e6eb987aeedca54ad3c708 + Validity + Not Before: Oct 13 13:13:30 2024 GMT + Not After : Feb 14 13:13:30 3024 GMT + Subject: O=Swaptacular Nodes Registry, OU=Accounting Authorities/serialNumber=deac00ed + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (3072 bit) + Modulus: + 00:89:7c:35:af:c3:e2:f1:39:6d:44:09:ca:68:1d: + d1:70:fb:28:06:e1:74:9e:56:b0:7d:24:55:5d:21: + ca:eb:54:7a:88:5c:33:e3:bc:92:97:ad:0d:93:69: + d7:9a:4c:0d:a2:d5:75:2f:f9:7c:09:af:66:4d:dc: + e6:7a:74:62:f1:75:d3:d0:0f:86:46:e9:c8:93:e2: + 22:b8:4c:e8:c0:89:ab:84:f2:04:0f:1d:1d:6e:cd: + 28:68:2b:64:c6:7e:e6:17:99:ad:a5:3a:70:78:b3: + fc:39:4e:27:fe:6a:7e:4d:cc:74:6e:0f:30:30:5c: + 73:d5:7d:57:9b:f6:48:08:3b:80:3b:eb:50:b3:b7: + 07:53:3f:21:0c:d2:3a:1c:a6:8c:f4:dc:28:78:0e: + 06:2f:c1:fd:ab:f8:ff:b5:c7:61:e6:e6:1b:62:a4: + d8:a0:92:17:70:b5:dc:39:ca:35:2e:4d:1d:f2:94: + 52:1e:a2:4c:1c:21:9a:26:61:c1:86:3b:ae:a2:ec: + 45:86:63:38:6b:f3:5d:6e:02:98:0b:24:7e:58:b6: + a7:85:9c:3d:39:e2:26:be:01:b3:9d:09:71:2b:d5: + 95:ef:a6:89:75:56:aa:3a:a7:f4:74:d7:9c:c1:8c: + c4:3c:c1:c7:73:77:e3:cc:4b:31:ef:5c:c2:cc:8c: + 6e:8f:3a:14:6f:43:6c:b2:dd:c9:83:a4:f3:c8:cc: + c1:ce:70:dc:57:85:d6:ab:54:b2:83:b7:cf:d2:26: + 5a:38:3b:e6:ee:01:b1:dd:89:bd:29:45:7a:6a:6c: + f4:ba:ae:31:70:02:b0:7d:dc:7e:d3:39:c6:3e:c6: + 5d:c4:18:0b:23:cf:ed:70:44:f9:5b:8b:54:cd:f5: + 73:51:c9:02:b1:2c:ad:b5:42:96:2a:97:88:98:a0: + 3f:16:69:ce:a2:59:00:c3:28:d6:93:af:cf:18:15: + 4b:be:30:c5:1f:66:e4:3e:d0:c9:97:43:5c:80:ff: + 07:ea:c8:2f:69:8e:6e:2d:91:cd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + D4:61:BE:5D:A3:AF:A1:38:80:89:2E:81:A0:91:4E:C2:CD:82:13:E5 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Name Constraints: critical + Permitted: + DirName:O = Swaptacular Nodes Registry, OU = Accounting Authorities, serialNumber = deac00ed + X509v3 Subject Key Identifier: + 33:CA:B1:03:F6:7C:21:63:DA:13:66:22:6A:1B:4A:94:EC:A9:7E:B8 + Netscape Comment: + .. + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 1a:e5:4b:33:8b:76:f7:3e:62:b9:5a:68:a4:e7:c3:cd:2b:63: + dd:cf:53:12:19:9c:a3:37:e9:83:39:51:85:da:0b:49:90:21: + 71:c4:b6:c0:de:40:f1:9c:db:e6:8a:a1:f3:65:3e:26:1c:3a: + 1e:e9:e2:42:bb:80:0a:b1:33:4e:ce:50:6d:cd:bf:70:c1:62: + 69:be:51:0e:ff:fc:67:c8:e8:76:d9:9c:67:76:59:17:00:7c: + c9:75:a0:71:14:a0:59:3f:5b:58:45:99:a0:4d:b4:ae:70:25: + 6c:03:fc:72:cd:a7:17:a3:3b:b2:2d:85:16:f3:90:02:ad:45: + f4:ef:84:83:8f:db:9c:1a:98:d5:6d:e9:a6:1d:2a:c7:53:a1: + e7:0f:75:00:d1:db:82:e9:91:87:25:e4:b9:a9:30:32:b9:31: + 83:e7:51:5c:df:86:61:bc:a5:99:16:8d:0c:d0:e2:3b:36:bd: + 1b:f5:5e:8a:5e:f4:18:87:a5:43:72:58:01:fc:49:c3:1f:af: + d4:05:e7:dc:25:29:bf:9c:d2:b4:37:2b:15:c8:71:63:5a:97: + c4:31:0e:ae:91:89:bf:19:a9:88:3d:ce:b6:dc:c3:9c:06:ca: + 05:25:66:be:fe:a0:23:8d:5c:6f:f0:c2:28:24:1a:2c:b9:40: + 84:8d:6a:dc:02:e5:3f:a2:58:94:19:2a:51:82:67:93:06:c0: + 9e:e7:5f:a1:9c:4d:e5:2d:28:8b:dd:2e:6c:a7:98:cf:0f:3f: + 64:cb:59:8d:10:aa:1b:af:46:c6:02:6f:99:16:b3:bd:29:1c: + 0e:44:9a:0e:32:99:56:67:dc:20:42:0c:4d:c5:77:2d:5c:34: + 80:1e:e7:35:0c:b7:08:55:66:8f:4b:6d:c7:57:e5:1d:35:f1: + e0:8f:82:2a:69:6c:4a:7b:f6:22:b9:35:fb:9d:72:20:e8:4f: + 4d:fc:68:72:53:45:d9:80:97:8f:bc:e0:82:c7:13:6a:23:77: + 21:a4:ff:9f:c4:93 +-----BEGIN CERTIFICATE----- +MIIFWjCCA8KgAwIBAgIRAIKXNazvrPMaNwlvEMol26wwDQYJKoZIhvcNAQELBQAw +azEjMCEGA1UECgwaU3dhcHRhY3VsYXIgTm9kZXMgUmVnaXN0cnkxGTAXBgNVBAsM +EENyZWRpdG9ycyBBZ2VudHMxKTAnBgNVBAUTIDU5MjE5ODNmZTBlNmViOTg3YWVl +ZGNhNTRhZDNjNzA4MCAXDTI0MTAxMzEzMTMzMFoYDzMwMjQwMjE0MTMxMzMwWjBZ +MSMwIQYDVQQKDBpTd2FwdGFjdWxhciBOb2RlcyBSZWdpc3RyeTEfMB0GA1UECwwW +QWNjb3VudGluZyBBdXRob3JpdGllczERMA8GA1UEBRMIZGVhYzAwZWQwggGiMA0G +CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCJfDWvw+LxOW1ECcpoHdFw+ygG4XSe +VrB9JFVdIcrrVHqIXDPjvJKXrQ2TadeaTA2i1XUv+XwJr2ZN3OZ6dGLxddPQD4ZG +6ciT4iK4TOjAiauE8gQPHR1uzShoK2TGfuYXma2lOnB4s/w5Tif+an5NzHRuDzAw +XHPVfVeb9kgIO4A761CztwdTPyEM0jocpoz03Ch4DgYvwf2r+P+1x2Hm5htipNig +khdwtdw5yjUuTR3ylFIeokwcIZomYcGGO66i7EWGYzhr811uApgLJH5YtqeFnD05 +4ia+AbOdCXEr1ZXvpol1Vqo6p/R015zBjMQ8wcdzd+PMSzHvXMLMjG6POhRvQ2yy +3cmDpPPIzMHOcNxXhdarVLKDt8/SJlo4O+buAbHdib0pRXpqbPS6rjFwArB93H7T +OcY+xl3EGAsjz+1wRPlbi1TN9XNRyQKxLK21QpYql4iYoD8Wac6iWQDDKNaTr88Y +FUu+MMUfZuQ+0MmXQ1yA/wfqyC9pjm4tkc0CAwEAAaOCAQcwggEDMB8GA1UdIwQY +MBaAFNRhvl2jr6E4gIkugaCRTsLNghPlMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD +VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA4GA1UdDwEB/wQEAwIBBjBtBgNV +HR4BAf8EYzBhoF8wXaRbMFkxIzAhBgNVBAoMGlN3YXB0YWN1bGFyIE5vZGVzIFJl +Z2lzdHJ5MR8wHQYDVQQLDBZBY2NvdW50aW5nIEF1dGhvcml0aWVzMREwDwYDVQQF +EwhkZWFjMDBlZDAdBgNVHQ4EFgQUM8qxA/Z8IWPaE2YiahtKlOypfrgwDwYJYIZI +AYb4QgENBAIWADANBgkqhkiG9w0BAQsFAAOCAYEAGuVLM4t29z5iuVpopOfDzStj +3c9TEhmcozfpgzlRhdoLSZAhccS2wN5A8Zzb5oqh82U+Jhw6HuniQruACrEzTs5Q +bc2/cMFiab5RDv/8Z8jodtmcZ3ZZFwB8yXWgcRSgWT9bWEWZoE20rnAlbAP8cs2n +F6M7si2FFvOQAq1F9O+Eg4/bnBqY1W3pph0qx1Oh5w91ANHbgumRhyXkuakwMrkx +g+dRXN+GYbylmRaNDNDiOza9G/Veil70GIelQ3JYAfxJwx+v1AXn3CUpv5zStDcr +FchxY1qXxDEOrpGJvxmpiD3OttzDnAbKBSVmvv6gI41cb/DCKCQaLLlAhI1q3ALl +P6JYlBkqUYJnkwbAnudfoZxN5S0oi90ubKeYzw8/ZMtZjRCqG69GxgJvmRazvSkc +DkSaDjKZVmfcIEIMTcV3LVw0gB7nNQy3CFVmj0ttx1flHTXx4I+CKmlsSnv2Irk1 ++51yIOhPTfxoclNF2YCXj7zggscTaiN3IaT/n8ST +-----END CERTIFICATE----- diff --git a/test_data/CA/peers/deac00ed/queues.txt b/test_data/CA/peers/deac00ed/queues.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/test_data/CA/peers/deac00ed/queues.txt @@ -0,0 +1 @@ +1 diff --git a/test_data/CA/peers/deac00ed/root-ca.crt b/test_data/CA/peers/deac00ed/root-ca.crt new file mode 100644 index 0000000..e16258d --- /dev/null +++ b/test_data/CA/peers/deac00ed/root-ca.crt @@ -0,0 +1,100 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2e:b1:51:02:fc:6d:1c:33:c6:0e:e9:b0:50:8b:bd:24 + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=Swaptacular Nodes Registry, OU=Accounting Authorities/serialNumber=deac00ed + Validity + Not Before: Oct 13 13:08:29 2024 GMT + Not After : Feb 14 13:08:29 3024 GMT + Subject: O=Swaptacular Nodes Registry, OU=Accounting Authorities/serialNumber=deac00ed + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (3072 bit) + Modulus: + 00:89:7c:35:af:c3:e2:f1:39:6d:44:09:ca:68:1d: + d1:70:fb:28:06:e1:74:9e:56:b0:7d:24:55:5d:21: + ca:eb:54:7a:88:5c:33:e3:bc:92:97:ad:0d:93:69: + d7:9a:4c:0d:a2:d5:75:2f:f9:7c:09:af:66:4d:dc: + e6:7a:74:62:f1:75:d3:d0:0f:86:46:e9:c8:93:e2: + 22:b8:4c:e8:c0:89:ab:84:f2:04:0f:1d:1d:6e:cd: + 28:68:2b:64:c6:7e:e6:17:99:ad:a5:3a:70:78:b3: + fc:39:4e:27:fe:6a:7e:4d:cc:74:6e:0f:30:30:5c: + 73:d5:7d:57:9b:f6:48:08:3b:80:3b:eb:50:b3:b7: + 07:53:3f:21:0c:d2:3a:1c:a6:8c:f4:dc:28:78:0e: + 06:2f:c1:fd:ab:f8:ff:b5:c7:61:e6:e6:1b:62:a4: + d8:a0:92:17:70:b5:dc:39:ca:35:2e:4d:1d:f2:94: + 52:1e:a2:4c:1c:21:9a:26:61:c1:86:3b:ae:a2:ec: + 45:86:63:38:6b:f3:5d:6e:02:98:0b:24:7e:58:b6: + a7:85:9c:3d:39:e2:26:be:01:b3:9d:09:71:2b:d5: + 95:ef:a6:89:75:56:aa:3a:a7:f4:74:d7:9c:c1:8c: + c4:3c:c1:c7:73:77:e3:cc:4b:31:ef:5c:c2:cc:8c: + 6e:8f:3a:14:6f:43:6c:b2:dd:c9:83:a4:f3:c8:cc: + c1:ce:70:dc:57:85:d6:ab:54:b2:83:b7:cf:d2:26: + 5a:38:3b:e6:ee:01:b1:dd:89:bd:29:45:7a:6a:6c: + f4:ba:ae:31:70:02:b0:7d:dc:7e:d3:39:c6:3e:c6: + 5d:c4:18:0b:23:cf:ed:70:44:f9:5b:8b:54:cd:f5: + 73:51:c9:02:b1:2c:ad:b5:42:96:2a:97:88:98:a0: + 3f:16:69:ce:a2:59:00:c3:28:d6:93:af:cf:18:15: + 4b:be:30:c5:1f:66:e4:3e:d0:c9:97:43:5c:80:ff: + 07:ea:c8:2f:69:8e:6e:2d:91:cd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:1 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 33:CA:B1:03:F6:7C:21:63:DA:13:66:22:6A:1B:4A:94:EC:A9:7E:B8 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 32:e9:bd:04:e6:e9:97:8a:59:46:89:30:cd:4e:01:b8:25:39: + 27:4a:80:b9:d0:97:14:ae:f7:bd:b0:38:10:79:e5:c6:a8:5b: + 82:36:dd:2f:94:11:85:50:44:5e:19:56:10:eb:01:98:ba:3d: + 10:ef:e9:4c:3e:f1:44:d3:58:97:33:bc:f0:e8:70:7c:34:f9: + 7b:d6:92:23:bc:e2:b8:4b:41:bb:33:87:00:12:41:03:15:91: + 4c:ae:1e:52:7c:4a:7d:65:68:1a:c7:a4:b7:a1:45:05:a7:44: + 71:ff:ee:6f:f9:dc:37:95:4f:de:6e:44:6a:cf:2a:52:0f:0e: + 05:f3:70:f1:c8:f0:39:c8:57:48:91:09:00:b5:11:03:a8:14: + a0:15:11:cc:3d:6a:c9:c4:78:d8:9a:c4:11:ad:8e:88:01:56: + 18:91:a7:51:15:5a:c3:34:bb:d3:b6:74:2c:1d:05:57:26:ce: + da:f2:be:24:97:cf:ef:6d:f1:42:af:bf:20:44:16:bc:ad:e6: + 7e:61:3b:70:a2:53:87:c6:21:b0:c9:ce:d6:e1:80:67:01:ad: + b8:c5:91:c1:31:71:1f:d2:25:70:ec:32:72:04:fb:f2:86:95: + 55:8b:73:61:19:56:99:34:fe:4b:16:5b:3a:e9:ef:90:7b:18: + 51:84:11:d1:73:a5:b8:c0:b8:f4:4e:2c:55:a7:eb:82:4f:e8: + f0:5c:70:d3:fe:a9:bb:41:3a:6f:44:a5:0b:7e:75:47:29:77: + df:ac:f3:18:02:8b:96:28:ce:1d:49:e3:93:d1:2c:87:f7:0c: + f2:f1:1e:1e:c4:78:74:68:29:27:61:14:85:18:fd:cc:a6:8e: + 58:81:f2:7b:7e:dc:b9:d3:52:da:fe:b6:d6:a0:7c:76:85:c4: + f3:9c:c9:e6:8e:27:95:8c:db:ca:f6:a5:05:77:72:45:39:ca: + b7:9a:ee:b0:53:90:e5:ad:29:81:9e:72:e3:f3:d6:9a:f9:db: + 62:ef:92:6e:b3:67 +-----BEGIN CERTIFICATE----- +MIIEgzCCAuugAwIBAgIQLrFRAvxtHDPGDumwUIu9JDANBgkqhkiG9w0BAQsFADBZ +MSMwIQYDVQQKDBpTd2FwdGFjdWxhciBOb2RlcyBSZWdpc3RyeTEfMB0GA1UECwwW +QWNjb3VudGluZyBBdXRob3JpdGllczERMA8GA1UEBRMIZGVhYzAwZWQwIBcNMjQx +MDEzMTMwODI5WhgPMzAyNDAyMTQxMzA4MjlaMFkxIzAhBgNVBAoMGlN3YXB0YWN1 +bGFyIE5vZGVzIFJlZ2lzdHJ5MR8wHQYDVQQLDBZBY2NvdW50aW5nIEF1dGhvcml0 +aWVzMREwDwYDVQQFEwhkZWFjMDBlZDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCC +AYoCggGBAIl8Na/D4vE5bUQJymgd0XD7KAbhdJ5WsH0kVV0hyutUeohcM+O8kpet +DZNp15pMDaLVdS/5fAmvZk3c5np0YvF109APhkbpyJPiIrhM6MCJq4TyBA8dHW7N +KGgrZMZ+5heZraU6cHiz/DlOJ/5qfk3MdG4PMDBcc9V9V5v2SAg7gDvrULO3B1M/ +IQzSOhymjPTcKHgOBi/B/av4/7XHYebmG2Kk2KCSF3C13DnKNS5NHfKUUh6iTBwh +miZhwYY7rqLsRYZjOGvzXW4CmAskfli2p4WcPTniJr4Bs50JcSvVle+miXVWqjqn +9HTXnMGMxDzBx3N348xLMe9cwsyMbo86FG9DbLLdyYOk88jMwc5w3FeF1qtUsoO3 +z9ImWjg75u4Bsd2JvSlFemps9LquMXACsH3cftM5xj7GXcQYCyPP7XBE+VuLVM31 +c1HJArEsrbVCliqXiJigPxZpzqJZAMMo1pOvzxgVS74wxR9m5D7QyZdDXID/B+rI +L2mObi2RzQIDAQABo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQE +AwIBBjAdBgNVHQ4EFgQUM8qxA/Z8IWPaE2YiahtKlOypfrgwDQYJKoZIhvcNAQEL +BQADggGBADLpvQTm6ZeKWUaJMM1OAbglOSdKgLnQlxSu972wOBB55caoW4I23S+U +EYVQRF4ZVhDrAZi6PRDv6Uw+8UTTWJczvPDocHw0+XvWkiO84rhLQbszhwASQQMV +kUyuHlJ8Sn1laBrHpLehRQWnRHH/7m/53DeVT95uRGrPKlIPDgXzcPHI8DnIV0iR +CQC1EQOoFKAVEcw9asnEeNiaxBGtjogBVhiRp1EVWsM0u9O2dCwdBVcmztryviSX +z+9t8UKvvyBEFryt5n5hO3CiU4fGIbDJztbhgGcBrbjFkcExcR/SJXDsMnIE+/KG +lVWLc2EZVpk0/ksWWzrp75B7GFGEEdFzpbjAuPROLFWn64JP6PBccNP+qbtBOm9E +pQt+dUcpd9+s8xgCi5Yozh1J45PRLIf3DPLxHh7EeHRoKSdhFIUY/cymjliB8nt+ +3LnTUtr+ttagfHaFxPOcyeaOJ5WM28r2pQV3ckU5yrea7rBTkOWtKYGecuPz1pr5 +22Lvkm6zZw== +-----END CERTIFICATE----- diff --git a/test_data/CA/peers/deac00ed/sub-ca.crt b/test_data/CA/peers/deac00ed/sub-ca.crt new file mode 100644 index 0000000..cacd28c --- /dev/null +++ b/test_data/CA/peers/deac00ed/sub-ca.crt @@ -0,0 +1,111 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2e:b1:51:02:fc:6d:1c:33:c6:0e:e9:b0:50:8b:bd:25 + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=Swaptacular Nodes Registry, OU=Accounting Authorities/serialNumber=deac00ed + Validity + Not Before: Oct 13 13:15:53 2024 GMT + Not After : Feb 14 13:15:53 3024 GMT + Subject: O=Swaptacular Nodes Registry, OU=Creditors Agents/serialNumber=5921983fe0e6eb987aeedca54ad3c708 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (3072 bit) + Modulus: + 00:aa:57:a1:74:d4:54:9b:21:b6:96:16:ad:58:86: + 6c:c7:b2:90:40:3d:4c:b8:11:56:06:1c:e5:f9:44: + 66:38:2d:33:b1:c8:21:1d:62:56:d6:9a:6c:4b:7f: + 3a:3f:eb:29:0b:e4:d8:ca:66:a9:0e:71:c0:26:61: + 57:d8:5d:ef:29:10:6a:71:73:db:60:14:09:b6:31: + 82:44:d6:06:1f:c9:3c:c6:92:66:e5:9d:f6:01:30: + 7c:71:3f:29:38:d6:90:de:34:e4:e3:c8:20:f6:40: + c1:d4:8a:2f:52:4f:c2:5f:cd:5d:6d:4b:0c:27:83: + e3:5b:59:a2:45:08:a7:a5:60:2e:e9:bc:cf:0b:0c: + 72:41:4f:24:1c:d5:23:ea:3d:cc:64:24:15:c2:ac: + c7:c6:4f:6f:fe:41:7b:89:bd:32:5f:8c:29:7c:f2: + 61:29:76:ee:63:bb:ab:47:22:3a:52:08:d7:f3:83: + 60:4a:a9:10:70:48:3b:71:d0:bb:80:42:c8:06:b7: + 03:3b:76:35:72:45:53:12:04:f6:a3:50:8e:d0:fd: + 83:07:e0:1a:2e:dc:04:e4:85:b8:0f:a7:f1:52:4c: + 7e:8a:a8:af:da:57:c3:2b:3e:2b:74:db:78:d9:a9: + 62:f8:57:d9:c8:bd:df:93:00:8e:de:ea:3e:db:82: + 59:56:af:44:d9:d2:1b:c9:46:5a:d2:8b:a7:fb:66: + 84:e9:9f:9d:0e:eb:22:25:22:87:5a:03:c5:35:be: + aa:89:69:b8:f6:25:14:c8:c6:88:ac:28:ab:f4:60: + f8:28:8d:bc:99:5a:dc:d7:16:2e:96:1c:44:e9:d6: + 9b:ff:30:6c:a7:2e:84:77:23:ba:f9:cf:14:19:d5: + d6:80:e3:53:fc:d2:38:2b:ef:ad:d6:3e:bb:f8:be: + 66:9a:4c:a7:f2:01:ca:e6:31:e8:ab:7f:b7:75:8b: + 7d:4e:97:79:f8:1f:55:c0:cf:d1:77:9e:9c:2b:6a: + 50:5f:75:ee:22:89:3b:98:26:21 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + 33:CA:B1:03:F6:7C:21:63:DA:13:66:22:6A:1B:4A:94:EC:A9:7E:B8 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Name Constraints: critical + Permitted: + DirName:O = Swaptacular Nodes Registry, OU = Creditors Agents, serialNumber = 5921983fe0e6eb987aeedca54ad3c708 + X509v3 Subject Key Identifier: + D4:61:BE:5D:A3:AF:A1:38:80:89:2E:81:A0:91:4E:C2:CD:82:13:E5 + Netscape Comment: + Subnet: 000001 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 2d:60:f2:d0:93:d7:bd:6a:40:72:19:34:32:ea:9d:76:76:dc: + e0:f7:37:82:77:04:9a:3b:06:4b:26:14:7c:73:0e:f9:6d:c4: + 24:c0:c1:87:db:97:c2:92:b1:e6:fe:b9:0b:6e:6b:eb:98:2c: + e7:86:77:27:d1:f7:1e:ae:c7:c2:77:6a:fd:6c:dd:cf:8e:1b: + 0b:20:7f:d3:98:5b:f5:9d:7f:83:05:6e:bb:88:26:3e:80:fc: + a4:5e:ad:15:e8:6e:b3:fe:df:6f:e4:11:5f:37:6b:4f:68:a6: + 4a:64:0a:f1:5c:0f:5d:e6:1a:74:d0:4d:ab:dc:e9:07:b8:55: + 30:34:b2:6d:21:4c:8e:d4:12:4b:9d:1b:37:ec:9f:3d:72:54: + b3:02:6d:bc:e1:ce:ab:00:b2:34:ff:30:42:1f:c5:69:2c:3a: + c1:6b:e7:59:07:1c:95:5c:14:f4:3a:4b:29:c8:1a:f0:89:d9: + 56:a7:0a:21:ce:09:62:53:af:dd:e8:77:04:5e:01:e0:7a:1b: + b3:ea:7e:a9:f7:37:8f:25:7c:6f:00:86:8b:19:60:59:7a:b0: + 6a:f4:ff:f4:cc:ca:ed:c0:28:9d:c9:ff:06:7e:31:6c:36:63: + 19:c5:fb:ab:32:be:ae:34:ea:79:41:bd:a2:08:77:d8:41:6d: + c8:5e:89:3b:d9:60:60:9d:d4:41:6e:b9:cc:b7:c6:20:20:a4: + cd:02:dd:0c:0b:27:be:6b:54:17:1a:a0:05:56:9f:98:6f:ac: + 04:94:5d:e9:44:2e:bf:c4:53:c9:85:5b:0a:1e:bc:49:c8:a8: + ab:a3:60:37:ab:d1:65:a4:3e:5c:18:b6:f4:69:ef:db:9b:03: + d3:16:96:18:0b:00:28:bb:9d:f8:66:05:d7:35:6c:c1:9f:c6: + 04:4d:3d:81:24:be:a2:2c:01:87:bd:cf:d3:af:7b:f6:da:4b: + 88:53:b3:e8:86:9f:bb:be:5c:91:50:f7:b3:71:33:f2:30:7d: + d2:03:9c:aa:01:03 +-----BEGIN CERTIFICATE----- +MIIFWjCCA8KgAwIBAgIQLrFRAvxtHDPGDumwUIu9JTANBgkqhkiG9w0BAQsFADBZ +MSMwIQYDVQQKDBpTd2FwdGFjdWxhciBOb2RlcyBSZWdpc3RyeTEfMB0GA1UECwwW +QWNjb3VudGluZyBBdXRob3JpdGllczERMA8GA1UEBRMIZGVhYzAwZWQwIBcNMjQx +MDEzMTMxNTUzWhgPMzAyNDAyMTQxMzE1NTNaMGsxIzAhBgNVBAoMGlN3YXB0YWN1 +bGFyIE5vZGVzIFJlZ2lzdHJ5MRkwFwYDVQQLDBBDcmVkaXRvcnMgQWdlbnRzMSkw +JwYDVQQFEyA1OTIxOTgzZmUwZTZlYjk4N2FlZWRjYTU0YWQzYzcwODCCAaIwDQYJ +KoZIhvcNAQEBBQADggGPADCCAYoCggGBAKpXoXTUVJshtpYWrViGbMeykEA9TLgR +VgYc5flEZjgtM7HIIR1iVtaabEt/Oj/rKQvk2MpmqQ5xwCZhV9hd7ykQanFz22AU +CbYxgkTWBh/JPMaSZuWd9gEwfHE/KTjWkN405OPIIPZAwdSKL1JPwl/NXW1LDCeD +41tZokUIp6VgLum8zwsMckFPJBzVI+o9zGQkFcKsx8ZPb/5Be4m9Ml+MKXzyYSl2 +7mO7q0ciOlII1/ODYEqpEHBIO3HQu4BCyAa3Azt2NXJFUxIE9qNQjtD9gwfgGi7c +BOSFuA+n8VJMfoqor9pXwys+K3TbeNmpYvhX2ci935MAjt7qPtuCWVavRNnSG8lG +WtKLp/tmhOmfnQ7rIiUih1oDxTW+qolpuPYlFMjGiKwoq/Rg+CiNvJla3NcWLpYc +ROnWm/8wbKcuhHcjuvnPFBnV1oDjU/zSOCvvrdY+u/i+ZppMp/IByuYx6Kt/t3WL +fU6XefgfVcDP0XeenCtqUF917iKJO5gmIQIDAQABo4IBCDCCAQQwHwYDVR0jBBgw +FoAUM8qxA/Z8IWPaE2YiahtKlOypfrgwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNV +HQ8BAf8EBAMCAQYwfwYDVR0eAQH/BHUwc6BxMG+kbTBrMSMwIQYDVQQKDBpTd2Fw +dGFjdWxhciBOb2RlcyBSZWdpc3RyeTEZMBcGA1UECwwQQ3JlZGl0b3JzIEFnZW50 +czEpMCcGA1UEBRMgNTkyMTk4M2ZlMGU2ZWI5ODdhZWVkY2E1NGFkM2M3MDgwHQYD +VR0OBBYEFNRhvl2jr6E4gIkugaCRTsLNghPlMB0GCWCGSAGG+EIBDQQQFg5TdWJu +ZXQ6IDAwMDAwMTANBgkqhkiG9w0BAQsFAAOCAYEALWDy0JPXvWpAchk0Muqddnbc +4Pc3gncEmjsGSyYUfHMO+W3EJMDBh9uXwpKx5v65C25r65gs54Z3J9H3Hq7Hwndq +/Wzdz44bCyB/05hb9Z1/gwVuu4gmPoD8pF6tFehus/7fb+QRXzdrT2imSmQK8VwP +XeYadNBNq9zpB7hVMDSybSFMjtQSS50bN+yfPXJUswJtvOHOqwCyNP8wQh/FaSw6 +wWvnWQcclVwU9DpLKcga8InZVqcKIc4JYlOv3eh3BF4B4Hobs+p+qfc3jyV8bwCG +ixlgWXqwavT/9MzK7cAoncn/Bn4xbDZjGcX7qzK+rjTqeUG9ogh32EFtyF6JO9lg +YJ3UQW65zLfGICCkzQLdDAsnvmtUFxqgBVafmG+sBJRd6UQuv8RTyYVbCh68Scio +q6NgN6vRZaQ+XBi29Gnv25sD0xaWGAsAKLud+GYF1zVswZ/GBE09gSS+oiwBh73P +06979tpLiFOz6Iafu75ckVD3s3Ez8jB90gOcqgED +-----END CERTIFICATE----- diff --git a/tests/test_cli.py b/tests/test_cli.py index f1386ac..5509179 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2,6 +2,8 @@ from swpt_stomp.client import client from swpt_stomp.server import server from swpt_stomp.configure_queue import configure_queue +from swpt_stomp.drainer import drainer +from swpt_stomp.common import ServerError def test_client_cli(datadir): @@ -35,6 +37,21 @@ def test_server_cli(datadir): assert isinstance(result.exception, FileNotFoundError) +def test_drainer_cli(datadir): + runner = CliRunner() + result = runner.invoke( + drainer, + [ + f'--nodedata-url=file://{datadir["CA"]}', + "--log-format=json", + "deac00ed", + "test_nonexistent_queue", + ], + ) + assert result.exit_code == 1 + assert isinstance(result.exception, ServerError) + + def test_configure_queue(datadir): runner = CliRunner() diff --git a/tests/test_drainer.py b/tests/test_drainer.py new file mode 100644 index 0000000..259574f --- /dev/null +++ b/tests/test_drainer.py @@ -0,0 +1,420 @@ +import pytest +import asyncio +import aio_pika +import json +from typing import Optional +from contextlib import suppress +from swpt_stomp import drainer +from swpt_stomp.common import ServerError + +_MAX_INT64 = (1 << 63) - 1 +_MAX_UINT64 = (1 << 64) - 1 +_I64_SPAN = _MAX_UINT64 + 1 + + +def u64_to_i64(value: int) -> int: + if value > _MAX_UINT64 or value < 0: + raise ValueError() + if value <= _MAX_INT64: + return value + return value - _I64_SPAN + + +def create_account_update_msg(debtor_id: int, creditor_id: int) -> str: + props = f""" + "type": "AccountUpdate", + "debtor_id": {debtor_id}, + "creditor_id": {creditor_id}, + "creation_date": "2020-01-01", + "last_change_ts": "2022-01-01T12:00:00+00:00", + "last_change_seqnum": 123, + "principal": 1000, + "interest": 5.4, + "interest_rate": 3.14, + "last_interest_rate_change_ts": "2022-01-01T12:00:00+00:00", + "last_config_ts": "2022-01-01T12:00:00+00:00", + "last_config_seqnum": 456, + "negligible_amount": 100.0, + "config_flags": 0, + "config_data": "TEST_CONFIG", + "account_id": "TEST_ACCOUNT", + "debtor_info_iri": "", + "debtor_info_content_type": "", + "debtor_info_sha256": "", + "last_transfer_number": 789, + "last_transfer_committed_at": "2022-01-01T12:00:00+00:00", + "demurrage_rate": -10.0, + "commit_period": 5000000, + "transfer_note_max_bytes": 300, + "ttl": 10000, + "ts": "2023-01-01T12:00:00+00:00" + """ + return "{" + props + "}" + + +def create_prepare_transfer_msg( + debtor_id: int, + creditor_id: int, + coordinator_type: str = "direct", + coordinator_id: Optional[int] = None, +) -> str: + if coordinator_id is None: + coordinator_id = creditor_id + + props = f""" + "type": "PrepareTransfer", + "debtor_id": {debtor_id}, + "creditor_id": {creditor_id}, + "min_locked_amount": 1000, + "max_locked_amount": 2000, + "recipient": "RECIPIENT", + "final_interest_rate_ts": "9999-12-31T23:59:59+00:00", + "max_commit_delay": 100000, + "coordinator_type": "{coordinator_type}", + "coordinator_id": {coordinator_id}, + "coordinator_request_id": 1111, + "ts": "2023-01-01T12:00:00+00:00" + """ + return "{" + props + "}" + + +def create_prepared_transfer_msg( + debtor_id: int, + creditor_id: int, + transfer_id: int, + coordinator_type: str = "direct", + coordinator_id: Optional[int] = None, + coordinator_request_id: int = 1234, +) -> str: + if coordinator_id is None: + coordinator_id = creditor_id + + props = f""" + "type": "PreparedTransfer", + "debtor_id": {debtor_id}, + "creditor_id": {creditor_id}, + "transfer_id": {transfer_id}, + "coordinator_type": "{coordinator_type}", + "coordinator_id": {coordinator_id}, + "coordinator_request_id": {coordinator_request_id}, + "locked_amount": 1000, + "recipient": "RECIPIENT", + "demurrage_rate": -10.0, + "deadline": "2024-01-01T12:00:00+00:00", + "final_interest_rate_ts": "9999-12-31T23:59:59+00:00", + "prepared_at": "2023-01-01T11:00:00+00:00", + "ts": "2023-01-01T12:00:00+00:00" + """ + return "{" + props + "}" + + +def create_configure_account_msg(debtor_id: int, creditor_id: int) -> str: + props = f""" + "type": "ConfigureAccount", + "debtor_id": {debtor_id}, + "creditor_id": {creditor_id}, + "negligible_amount": 1000.0, + "config_flags": 666, + "config_data": "TEST_CONFIG", + "seqnum": 1234, + "ts": "2023-01-01T12:00:00+00:00" + """ + return "{" + props + "}" + + +@pytest.mark.asyncio +async def test_ca_drainer(datadir, rmq_url): + loop = asyncio.get_running_loop() + + # Ensure client and server queues are configured. + connection = await aio_pika.connect(rmq_url) + channel = await connection.channel() + client_queue = await channel.declare_queue("test_client") + server_exchange = await channel.declare_exchange( + "creditors_in", "headers", durable=True + ) + drainer_test_queue = await channel.declare_queue("test_drainer") + await drainer_test_queue.bind(server_exchange, "#") + + # Empty client and server queues. + while await client_queue.get(no_ack=True, fail=False): + pass + while await drainer_test_queue.get(no_ack=True, fail=False): + pass + + debtor_id = u64_to_i64(0xDEAC00ED00000001) + creditor_id = 0x0000081000000001 + + # Add test "PrepareTransfer "message. + s = create_prepare_transfer_msg(debtor_id, creditor_id) + message = aio_pika.Message( + s.encode("utf8"), + type="PrepareTransfer", + content_type="application/json", + ) + await channel.default_exchange.publish(message, "test_client") + + # Add two identical test "ConfigureAccount "messages. + s = create_configure_account_msg(debtor_id, creditor_id) + message = aio_pika.Message( + s.encode("utf8"), + type="ConfigureAccount", + content_type="application/json", + ) + await channel.default_exchange.publish(message, "test_client") + await channel.default_exchange.publish(message, "test_client") + + drainer_task = loop.create_task( + drainer.drain( + protocol_broker_url=rmq_url, + peer_node_id="deac00ed", + nodedata_url=f'file://{datadir["CA"]}', + protocol_broker_queue="test_client", + client_queue_size=1, + server_queue_size=1, + ) + ) + + async def read_messages(): + nonlocal messages_ok + i = 0 + async with drainer_test_queue.iterator() as q: + async for message in q: + i += 1 + assert message.type == "RejectedConfig" + assert message.content_type == "application/json" + msg_data = json.loads(message.body.decode("utf8")) + assert msg_data == { + "type": "RejectedConfig", + "creditor_id": creditor_id, + "debtor_id": debtor_id, + "negligible_amount": 1000.0, + "config_data": "TEST_CONFIG", + "config_flags": 666, + "config_seqnum": 1234, + "config_ts": "2023-01-01T12:00:00+00:00", + "rejection_code": "NO_CONNECTION_TO_DEBTOR", + "ts": msg_data["ts"], + } + assert message.headers == { + "message-type": "RejectedConfig", + "debtor-id": debtor_id, + "creditor-id": creditor_id, + "ca-creditors": True, + "ca-trade": False, + } + await message.ack() + if i == 2: + break + messages_ok = True + drainer_task.cancel() + + messages_ok = False + read_task = loop.create_task(read_messages()) + with suppress(asyncio.CancelledError): + await asyncio.wait_for( + asyncio.gather(drainer_task, read_task), + 15.0, + ) + + assert messages_ok + await channel.close() + await connection.close() + await asyncio.wait([drainer_task, read_task]) + + +@pytest.mark.asyncio +async def test_ca_drainer_consume_error(datadir, rmq_url): + loop = asyncio.get_running_loop() + drainer_task = loop.create_task( + drainer.drain( + protocol_broker_url=rmq_url, + peer_node_id="deac00ed", + nodedata_url=f'file://{datadir["CA"]}', + protocol_broker_queue="non_existent_queue", + client_queue_size=100, + server_queue_size=100, + ) + ) + with pytest.raises(ServerError): + await asyncio.wait_for(asyncio.gather(drainer_task), 15.0) + + +@pytest.mark.asyncio +async def test_aa_drainer_prepared_transfer(datadir, rmq_url): + loop = asyncio.get_running_loop() + + # Ensure client and server queues are configured. + connection = await aio_pika.connect(rmq_url) + channel = await connection.channel() + client_queue = await channel.declare_queue("test_client") + server_exchange = await channel.declare_exchange("accounts_in", "topic") + drainer_test_queue = await channel.declare_queue("test_drainer") + await drainer_test_queue.bind(server_exchange, "#") + + # Empty client and server queues. + while await client_queue.get(no_ack=True, fail=False): + pass + while await drainer_test_queue.get(no_ack=True, fail=False): + pass + + debtor_id = u64_to_i64(0x1234abcd00000001) + creditor_id = 0x0000020000000001 + transfer_id = 12345 + coordinator_id = 0x0000020000000002 + + # Add test "PreparedTransfer "message. + s = create_prepared_transfer_msg( + debtor_id, creditor_id, transfer_id, 'agent', coordinator_id + ) + message = aio_pika.Message( + s.encode("utf8"), + type="PreparedTransfer", + content_type="application/json", + ) + await channel.default_exchange.publish(message, "test_client") + + drainer_task = loop.create_task( + drainer.drain( + protocol_broker_url=rmq_url, + peer_node_id="09cab36b6079e09c32a9dfd60446c469", + nodedata_url=f'file://{datadir["AA"]}', + protocol_broker_queue="test_client", + client_queue_size=100, + server_queue_size=100, + ) + ) + + async def read_messages(): + nonlocal messages_ok + i = 0 + async with drainer_test_queue.iterator() as q: + async for message in q: + i += 1 + assert message.type == "FinalizeTransfer" + assert message.content_type == "application/json" + msg_data = json.loads(message.body.decode("utf8")) + assert msg_data == { + "type": "FinalizeTransfer", + "creditor_id": creditor_id, + "debtor_id": debtor_id, + "committed_amount": 0, + "coordinator_id": coordinator_id, + "coordinator_request_id": 1234, + "coordinator_type": "agent", + "transfer_id": transfer_id, + "transfer_note": "", + "transfer_note_format": "", + "ts": msg_data["ts"], + } + assert message.headers == { + "message-type": "FinalizeTransfer", + "debtor-id": debtor_id, + "creditor-id": creditor_id, + "coordinator-id": coordinator_id, + "coordinator-type": "agent", + } + await message.ack() + if i == 1: + break + messages_ok = True + drainer_task.cancel() + + messages_ok = False + read_task = loop.create_task(read_messages()) + with suppress(asyncio.CancelledError): + await asyncio.wait_for( + asyncio.gather(drainer_task, read_task), + 15.0, + ) + + assert messages_ok + await channel.close() + await connection.close() + await asyncio.wait([drainer_task, read_task]) + + +@pytest.mark.asyncio +async def test_aa_drainer_account_update(datadir, rmq_url): + loop = asyncio.get_running_loop() + + # Ensure client and server queues are configured. + connection = await aio_pika.connect(rmq_url) + channel = await connection.channel() + client_queue = await channel.declare_queue("test_client") + server_exchange = await channel.declare_exchange("accounts_in", "topic") + drainer_test_queue = await channel.declare_queue("test_drainer") + await drainer_test_queue.bind(server_exchange, "#") + + # Empty client and server queues. + while await client_queue.get(no_ack=True, fail=False): + pass + while await drainer_test_queue.get(no_ack=True, fail=False): + pass + + debtor_id = u64_to_i64(0x1234abcd00000001) + creditor_id = 0x0000020000000001 + + # Add two identicaltest "AccountUpdate "messages. + s = create_account_update_msg(debtor_id, creditor_id) + message = aio_pika.Message( + s.encode("utf8"), + type="AccountUpdate", + content_type="application/json", + ) + await channel.default_exchange.publish(message, "test_client") + await channel.default_exchange.publish(message, "test_client") + + drainer_task = loop.create_task( + drainer.drain( + protocol_broker_url=rmq_url, + peer_node_id="09cab36b6079e09c32a9dfd60446c469", + nodedata_url=f'file://{datadir["AA"]}', + protocol_broker_queue="test_client", + client_queue_size=1, + server_queue_size=1, + ) + ) + + async def read_messages(): + nonlocal messages_ok + i = 0 + async with drainer_test_queue.iterator() as q: + async for message in q: + i += 1 + assert message.type == "ConfigureAccount" + assert message.content_type == "application/json" + msg_data = json.loads(message.body.decode("utf8")) + assert msg_data == { + "type": "ConfigureAccount", + "config_data": "", + "config_flags": 1, + "creditor_id": creditor_id, + "debtor_id": debtor_id, + "negligible_amount": 1e+30, + "seqnum": 0, + "ts": msg_data["ts"], + } + assert message.headers == { + "message-type": "ConfigureAccount", + "debtor-id": debtor_id, + "creditor-id": creditor_id, + } + await message.ack() + if i == 2: + break + messages_ok = True + drainer_task.cancel() + + messages_ok = False + read_task = loop.create_task(read_messages()) + with suppress(asyncio.CancelledError): + await asyncio.wait_for( + asyncio.gather(drainer_task, read_task), + 15.0, + ) + + assert messages_ok + await channel.close() + await connection.close() + await asyncio.wait([drainer_task, read_task]) From 4727f84e832573375c7ece798053256394dad3c0 Mon Sep 17 00:00:00 2001 From: Evgeni Pandurski Date: Sun, 13 Oct 2024 19:31:48 +0300 Subject: [PATCH 6/7] Delete queue.txt files from test_data/ --- test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/queues.txt | 1 - test_data/CA/peers/deac00ed/queues.txt | 1 - 2 files changed, 2 deletions(-) delete mode 100644 test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/queues.txt delete mode 100644 test_data/CA/peers/deac00ed/queues.txt diff --git a/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/queues.txt b/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/queues.txt deleted file mode 100644 index d00491f..0000000 --- a/test_data/AA/peers/09cab36b6079e09c32a9dfd60446c469/queues.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/test_data/CA/peers/deac00ed/queues.txt b/test_data/CA/peers/deac00ed/queues.txt deleted file mode 100644 index d00491f..0000000 --- a/test_data/CA/peers/deac00ed/queues.txt +++ /dev/null @@ -1 +0,0 @@ -1 From f297de6a2671d2c7c398ea5ddde1d84d956f5d41 Mon Sep 17 00:00:00 2001 From: Evgeni Pandurski Date: Sun, 13 Oct 2024 19:51:18 +0300 Subject: [PATCH 7/7] Minor refactoring --- swpt_stomp/drainer.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/swpt_stomp/drainer.py b/swpt_stomp/drainer.py index 0c688ef..75fffe7 100644 --- a/swpt_stomp/drainer.py +++ b/swpt_stomp/drainer.py @@ -55,7 +55,6 @@ parse_message_body, ) -_logger = logging.getLogger(__name__) _configure_account = smp_schemas.ConfigureAccountMessageSchema() _finalize_transfer = smp_schemas.FinalizeTransferMessageSchema() _rejected_config = smp_schemas.RejectedConfigMessageSchema() @@ -152,7 +151,7 @@ async def drain( Union[str, None, ServerError] ] = asyncio.Queue(server_queue_size) - async def respond_to_messages_if_necessary(): + async def ack_and_respond_if_necessary(): while m := await messages_queue.get(): if isinstance(m, ServerError): messages_queue.task_done() @@ -183,8 +182,8 @@ async def ignore_confirmations(): ), ) ) - respond_to_messages_task = loop.create_task( - respond_to_messages_if_necessary() + process_messages_task = loop.create_task( + ack_and_respond_if_necessary() ) publish_responses_task = loop.create_task( publish_to_exchange( @@ -197,15 +196,15 @@ async def ignore_confirmations(): ), ) ) - ignore_confirmations_task = loop.create_task( + process_publish_confirmations_task = loop.create_task( ignore_confirmations() ) tasks = [ read_messages_task, - respond_to_messages_task, + process_messages_task, publish_responses_task, - ignore_confirmations_task, + process_publish_confirmations_task, ] try: await asyncio.gather(*tasks)