From a9950e3c4484cde678360f507ba082a6519302ac Mon Sep 17 00:00:00 2001 From: Alejandro Cabeza Romero Date: Thu, 30 Oct 2025 13:13:42 +0100 Subject: [PATCH] Update deps. Fix transaction select. Move transaction randomizing logic to TransactionSerializer. --- pyproject.toml | 6 +++--- src/db/transaction.py | 2 +- src/models/block.py | 33 +------------------------------ src/node/api/serializers/block.py | 33 +++++++++++++++++++++++++++++-- src/node/lifespan.py | 5 ++--- src/node/manager/docker.py | 12 ++++++----- 6 files changed, 45 insertions(+), 46 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 21974e1..f15e129 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,14 +3,14 @@ name = "nomos-block-explorer" version = "0.1.0" requires-python = ">=3.14,<3.15" dependencies = [ - "fastapi~=0.118.0", + "fastapi~=0.120.2", "httpx>=0.28.1", "pydantic-settings>=2.11.0", - "python-on-whales~=0.78.0", + "python-on-whales~=0.79.0", "requests~=2.32.5", "rusty-results~=1.1.1", "sqlmodel~=0.0.25", - "uvicorn~=0.37.0", + "uvicorn~=0.38.0", ] [tool.pyright] diff --git a/src/db/transaction.py b/src/db/transaction.py index 603d5b0..fa1d8d7 100644 --- a/src/db/transaction.py +++ b/src/db/transaction.py @@ -82,7 +82,7 @@ class TransactionRepository: while True: statement = ( - select(Transaction, Block.slot, Block.id) + select(Transaction) .options(selectinload(Transaction.block)) .join(Block, Transaction.block_id == Block.id) .where( diff --git a/src/models/block.py b/src/models/block.py index fd9cd74..5833918 100644 --- a/src/models/block.py +++ b/src/models/block.py @@ -1,9 +1,6 @@ import logging -import os -import random -from typing import TYPE_CHECKING, Any, List, Self +from typing import TYPE_CHECKING, List, Self -from pydantic.config import ExtraValues from sqlalchemy import Column from sqlmodel import Field, Relationship @@ -19,12 +16,6 @@ if TYPE_CHECKING: logger = logging.getLogger(__name__) -def _should_randomize_transactions(): - is_debug = os.getenv("DEBUG", "False").lower() == "true" - is_debug__randomize_transactions = os.getenv("DEBUG__RANDOMIZE_TRANSACTIONS", "False").lower() == "true" - return is_debug and is_debug__randomize_transactions - - class Block(TimestampedModel, table=True): __tablename__ = "block" @@ -54,25 +45,3 @@ class Block(TimestampedModel, table=True): def with_transactions(self, transactions: List["Transaction"]) -> Self: self.transactions = transactions return self - - @classmethod - def model_validate_json( - cls, - json_data: str | bytes | bytearray, - *, - strict: bool | None = None, - extra: ExtraValues | None = None, - context: Any | None = None, - by_alias: bool | None = None, - by_name: bool | None = None, - ) -> Self: - self = super().model_validate_json( - json_data, strict=strict, extra=extra, context=context, by_alias=by_alias, by_name=by_name - ) - if _should_randomize_transactions(): - from models.transactions.transaction import Transaction - - logger.debug("DEBUG and DEBUG__RANDOMIZE_TRANSACTIONS are enabled, randomizing Block's transactions.") - n_transactions = 0 if random.randint(0, 1) <= 0.3 else random.randint(1, 5) - self.transactions = [Transaction.from_random() for _ in range(n_transactions)] - return self diff --git a/src/node/api/serializers/block.py b/src/node/api/serializers/block.py index 7b708be..a0ef0ee 100644 --- a/src/node/api/serializers/block.py +++ b/src/node/api/serializers/block.py @@ -1,3 +1,5 @@ +import logging +from os import getenv from random import randint from typing import List, Self @@ -10,10 +12,32 @@ from node.api.serializers.signed_transaction import SignedTransactionSerializer from utils.protocols import FromRandom +def _should_randomize_transactions(): + is_debug = getenv("DEBUG", "False").lower() == "true" + is_debug__randomize_transactions = getenv("DEBUG__RANDOMIZE_TRANSACTIONS", "False").lower() == "true" + return is_debug and is_debug__randomize_transactions + + +def _get_random_transactions() -> List[SignedTransactionSerializer]: + n = 1 if randint(0, 1) <= 0.5 else randint(2, 5) + return [SignedTransactionSerializer.from_random() for _ in range(n)] + + +logger = logging.getLogger(__name__) + + class BlockSerializer(NbeSerializer, FromRandom): header: HeaderSerializer transactions: List[SignedTransactionSerializer] + @classmethod + def model_validate_json(cls, *args, **kwargs) -> Self: + self = super().model_validate_json(*args, **kwargs) + if _should_randomize_transactions(): + logger.debug("DEBUG and DEBUG__RANDOMIZE_TRANSACTIONS are enabled, randomizing Block's transactions.") + self.transactions = _get_random_transactions() + return self + def into_block(self) -> Block: transactions = [transaction.into_transaction() for transaction in self.transactions] return Block.model_validate( @@ -29,6 +53,11 @@ class BlockSerializer(NbeSerializer, FromRandom): @classmethod def from_random(cls, *, slot: Option[int] = None) -> Self: slot = slot or Empty() - n = 1 if randint(0, 1) <= 0.5 else randint(2, 5) - transactions = [SignedTransactionSerializer.from_random() for _ in range(n)] + transactions = _get_random_transactions() return cls.model_validate({"header": HeaderSerializer.from_random(slot=slot), "transactions": transactions}) + + def __str__(self) -> str: + return f"BlockSerializer(slot={self.header.slot})" + + def __repr__(self) -> str: + return f"" diff --git a/src/node/lifespan.py b/src/node/lifespan.py index 49c68b8..d1feb33 100644 --- a/src/node/lifespan.py +++ b/src/node/lifespan.py @@ -9,7 +9,6 @@ from db.blocks import BlockRepository from db.clients import SqliteClient from db.transaction import TransactionRepository from models.block import Block -from models.transactions.transaction import Transaction from node.api.fake import FakeNodeApi from node.api.http import HttpNodeApi from node.api.serializers.block import BlockSerializer @@ -28,8 +27,8 @@ async def node_lifespan(app: "NBE") -> AsyncGenerator[None]: app.state.node_manager = FakeNodeManager() # app.state.node_manager = DockerModeManager(app.settings.node_compose_filepath) - app.state.node_api = FakeNodeApi() - # app.state.node_api = HttpNodeApi(host="127.0.0.1", port=18080) + # app.state.node_api = FakeNodeApi() + app.state.node_api = HttpNodeApi(host="127.0.0.1", port=18080) app.state.db_client = db_client app.state.block_repository = BlockRepository(db_client) diff --git a/src/node/manager/docker.py b/src/node/manager/docker.py index a16c1e2..98b46ca 100644 --- a/src/node/manager/docker.py +++ b/src/node/manager/docker.py @@ -1,4 +1,4 @@ -from logging import error, warn +import logging from python_on_whales import DockerException from python_on_whales.docker_client import DockerClient @@ -6,6 +6,8 @@ from rusty_results import Err, Ok, Result from node.manager.base import NodeManager +logger = logging.getLogger(__name__) + class DockerModeManager(NodeManager): def __init__(self, compose_filepath: str): @@ -16,10 +18,10 @@ class DockerModeManager(NodeManager): match self.ps(): case Err(1): - error("Compose services are not running.") - exit(21) # FIXME: There's too much output here. + logger.error("Docker compose services are not running.") + exit(21) # FIXME: There's too much output here: Don't exit here, raise error and exit outside. case Err(_): - error("Failed to run docker compose.") + logger.error("Failed to run docker compose.") exit(20) def ps(self, only_running: bool = True) -> Result: @@ -32,7 +34,7 @@ class DockerModeManager(NodeManager): async def start(self): services = self.ps().map(lambda _services: len(_services)).expect("Failed to get compose services.") if services > 0: - warn("Compose services are already running.") + logger.warn("Compose services are already running.") return self.client.compose.up(