Repository: Chia-Network/chia-blockchain
File: chia/full_node/full_node_rpc_api.py (Python)

Code before:

    assert newer_block.timestamp is not None and older_block.timestamp is not None

    if newer_block.height == older_block.height:  # small chain not long enough to have a block in between
        return None

    average_block_time = uint32(
        (newer_block.timestamp - older_block.timestamp) / (newer_block.height - older_block.height)
    )
    return average_block_time


class FullNodeRpcApi:
    if TYPE_CHECKING:
        from chia.rpc.rpc_server import RpcApiProtocol

        _protocol_check: ClassVar[RpcApiProtocol] = cast("FullNodeRpcApi", None)

    def __init__(self, service: FullNode) -> None:
        self.service = service
        self.service_name = "chia_full_node"
        self.cached_blockchain_state: Optional[dict[str, Any]] = None

    def get_routes(self) -> dict[str, Endpoint]:
        return {
            # Blockchain
            "/get_blockchain_state": self.get_blockchain_state,
            "/get_block": self.get_block,
            "/get_blocks": self.get_blocks,
            "/get_block_count_metrics": self.get_block_count_metrics,
            "/get_block_record_by_height": self.get_block_record_by_height,
            "/get_block_record": self.get_block_record,
            "/get_block_records": self.get_block_records,
            "/get_block_spends": self.get_block_spends,
            "/get_block_spends_with_conditions": self.get_block_spends_with_conditions,
            "/get_unfinished_block_headers": self.get_unfinished_block_headers,
            "/get_network_space": self.get_network_space,
            "/get_additions_and_removals": self.get_additions_and_removals,
            "/get_aggsig_additional_data": self.get_aggsig_additional_data,
            "/get_recent_signage_point_or_eos": self.get_recent_signage_point_or_eos,
            # Coins
            "/get_coin_records_by_puzzle_hash": self.get_coin_records_by_puzzle_hash,
            "/get_coin_records_by_puzzle_hashes": self.get_coin_records_by_puzzle_hashes,
            "/get_coin_record_by_name": self.get_coin_record_by_name,
            "/get_coin_records_by_names": self.get_coin_records_by_names,
            "/get_coin_records_by_parent_ids": self.get_coin_records_by_parent_ids,
            "/get_coin_records_by_hint": self.get_coin_records_by_hint,
            "/push_tx": self.push_tx,
            "/get_puzzle_and_solution": self.get_puzzle_and_solution,
            # Mempool
            "/get_all_mempool_tx_ids": self.get_all_mempool_tx_ids,

Review comment (suggestion):
this doesn't seem to improve throughput of these RPCs. It's not clear to me why, perhaps there's only a single `asyncio.Task` per RPC connection. In either case, compute heavy work should not be performed on the main thread.

Code after:
    older_block = await get_nearest_transaction_block(blockchain, prev_block)

    assert newer_block.timestamp is not None and older_block.timestamp is not None

    if newer_block.height == older_block.height:  # small chain not long enough to have a block in between
        return None

    average_block_time = uint32(
        (newer_block.timestamp - older_block.timestamp) / (newer_block.height - older_block.height)
    )
    return average_block_time


class FullNodeRpcApi:
    executor: ThreadPoolExecutor

    if TYPE_CHECKING:
        from chia.rpc.rpc_server import RpcApiProtocol

        _protocol_check: ClassVar[RpcApiProtocol] = cast("FullNodeRpcApi", None)

    def __init__(self, service: FullNode) -> None:
        self.service = service
        self.service_name = "chia_full_node"
        self.cached_blockchain_state: Optional[dict[str, Any]] = None
        self.executor = ThreadPoolExecutor(max_workers=2, thread_name_prefix="node-rpc-")

    def get_routes(self) -> dict[str, Endpoint]:
        return {
            # Blockchain
            "/get_blockchain_state": self.get_blockchain_state,
            "/get_block": self.get_block,
            "/get_blocks": self.get_blocks,
            "/get_block_count_metrics": self.get_block_count_metrics,
            "/get_block_record_by_height": self.get_block_record_by_height,
            "/get_block_record": self.get_block_record,
            "/get_block_records": self.get_block_records,
            "/get_block_spends": self.get_block_spends,
            "/get_block_spends_with_conditions": self.get_block_spends_with_conditions,
            "/get_unfinished_block_headers": self.get_unfinished_block_headers,
            "/get_network_space": self.get_network_space,
            "/get_additions_and_removals": self.get_additions_and_removals,
            "/get_aggsig_additional_data": self.get_aggsig_additional_data,
            "/get_recent_signage_point_or_eos": self.get_recent_signage_point_or_eos,
            # Coins
            "/get_coin_records_by_puzzle_hash": self.get_coin_records_by_puzzle_hash,
            "/get_coin_records_by_puzzle_hashes": self.get_coin_records_by_puzzle_hashes,
            "/get_coin_record_by_name": self.get_coin_record_by_name,
            "/get_coin_records_by_names": self.get_coin_records_by_names,
            "/get_coin_records_by_parent_ids": self.get_coin_records_by_parent_ids,
            "/get_coin_records_by_hint": self.get_coin_records_by_hint,