Module jmcore.config
Base configuration classes for JoinMarket components.
This module provides Pydantic BaseModel classes that can be inherited by specific components (maker, taker, etc.) to reduce duplication and ensure consistency.
Functions
def create_tor_control_config_from_env() ‑> TorControlConfig-
Expand source code
def create_tor_control_config_from_env() -> TorControlConfig: """ Create TorControlConfig from environment variables with smart defaults. Environment variables: TOR_CONTROL_HOST - Tor control host (default: 127.0.0.1 or tor if exists) TOR_CONTROL_PORT - Tor control port (default: 9051) TOR_COOKIE_PATH - Cookie auth file path TOR_PASSWORD - Tor control password Auto-detection: - If TOR_COOKIE_PATH is set, use it - Otherwise try common paths: /var/lib/tor/control_auth_cookie, /run/tor/control.authcookie """ import os # Try to detect if we're in a docker environment with a tor container host = os.environ.get("TOR_CONTROL_HOST", "127.0.0.1") # If TOR_SOCKS_HOST is set to "tor", likely docker - try that for control too if not os.environ.get("TOR_CONTROL_HOST") and os.environ.get("TOR_SOCKS_HOST") == "tor": host = "tor" port = int(os.environ.get("TOR_CONTROL_PORT", "9051")) password = os.environ.get("TOR_PASSWORD") # Try to find cookie path cookie_path_str = os.environ.get("TOR_COOKIE_PATH") cookie_path: Path | None = None if cookie_path_str: cookie_path = Path(cookie_path_str) else: # Try common paths common_paths = [ Path("/var/lib/tor/control_auth_cookie"), Path("/run/tor/control.authcookie"), Path("/var/run/tor/control.authcookie"), ] for path in common_paths: if path.exists(): cookie_path = path break return TorControlConfig( enabled=True, host=host, port=port, cookie_path=cookie_path, password=password, )Create TorControlConfig from environment variables with smart defaults.
Environment variables: TOR_CONTROL_HOST - Tor control host (default: 127.0.0.1 or tor if exists) TOR_CONTROL_PORT - Tor control port (default: 9051) TOR_COOKIE_PATH - Cookie auth file path TOR_PASSWORD - Tor control password
Auto-detection: - If TOR_COOKIE_PATH is set, use it - Otherwise try common paths: /var/lib/tor/control_auth_cookie, /run/tor/control.authcookie
Classes
class BackendConfig (**data: Any)-
Expand source code
class BackendConfig(BaseModel): """ Configuration for Bitcoin backend connection. Supports different backend types: - full_node: Bitcoin Core RPC - neutrino: Light client using BIP 157/158 """ backend_type: str = Field( default="full_node", description="Backend type: 'full_node' or 'neutrino'", ) backend_config: dict[str, Any] = Field( default_factory=dict, description="Backend-specific configuration (RPC credentials, neutrino peers, etc.)", ) model_config = {"frozen": False}Configuration for Bitcoin backend connection.
Supports different backend types: - full_node: Bitcoin Core RPC - neutrino: Light client using BIP 157/158
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Class variables
var backend_config : dict[str, typing.Any]-
The type of the None singleton.
var backend_type : str-
The type of the None singleton.
var model_config-
The type of the None singleton.
class DirectoryServerConfig (**data: Any)-
Expand source code
class DirectoryServerConfig(BaseModel): """ Configuration for directory server instances. Used by standalone directory servers, not by clients. """ network: NetworkType = Field( default=NetworkType.MAINNET, description="Network type for the directory server" ) host: str = Field(default="127.0.0.1", description="Host address to bind to") port: int = Field(default=5222, ge=1, le=65535, description="Port to listen on") # Limits max_peers: int = Field(default=10000, ge=1, description="Maximum number of connected peers") max_message_size: int = Field( default=2097152, ge=1024, description="Maximum message size in bytes (default: 2MB)" ) max_line_length: int = Field( default=65536, ge=1024, description="Maximum JSON-line message length (default: 64KB)" ) max_json_nesting_depth: int = Field( default=10, ge=1, le=100, description="Maximum nesting depth for JSON parsing" ) # Rate limiting # Higher limits to accommodate makers responding to orderbook requests # A single maker might send multiple offer messages + bond proofs rapidly message_rate_limit: int = Field( default=500, ge=1, description="Messages per second (sustained)" ) message_burst_limit: int = Field(default=1000, ge=1, description="Maximum burst size") rate_limit_disconnect_threshold: int = Field( default=200, ge=1, description="Disconnect after N violations" ) # Broadcasting broadcast_batch_size: int = Field( default=50, ge=1, description="Batch size for concurrent broadcasts (lower = less memory)", ) # Logging log_level: str = Field(default="INFO", description="Logging level") # Server info motd: str = Field( default="JoinMarket Directory Server https://github.com/m0wer/joinmarket-ng", description="Message of the day sent to clients", ) # Health check health_check_host: str = Field( default="127.0.0.1", description="Host for health check endpoint" ) health_check_port: int = Field( default=8080, ge=1, le=65535, description="Port for health check endpoint" ) model_config = {"frozen": False}Configuration for directory server instances.
Used by standalone directory servers, not by clients.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Class variables
var broadcast_batch_size : int-
The type of the None singleton.
var health_check_host : str-
The type of the None singleton.
var health_check_port : int-
The type of the None singleton.
var host : str-
The type of the None singleton.
var log_level : str-
The type of the None singleton.
var max_json_nesting_depth : int-
The type of the None singleton.
var max_line_length : int-
The type of the None singleton.
var max_message_size : int-
The type of the None singleton.
var max_peers : int-
The type of the None singleton.
var message_burst_limit : int-
The type of the None singleton.
var message_rate_limit : int-
The type of the None singleton.
var model_config-
The type of the None singleton.
var motd : str-
The type of the None singleton.
var network : NetworkType-
The type of the None singleton.
var port : int-
The type of the None singleton.
var rate_limit_disconnect_threshold : int-
The type of the None singleton.
class TorConfig (**data: Any)-
Expand source code
class TorConfig(BaseModel): """ Configuration for Tor SOCKS proxy connection. Used for outgoing connections to directory servers and peers. """ socks_host: str = Field(default="127.0.0.1", description="Tor SOCKS5 proxy host address") socks_port: int = Field(default=9050, ge=1, le=65535, description="Tor SOCKS5 proxy port") model_config = {"frozen": False}Configuration for Tor SOCKS proxy connection.
Used for outgoing connections to directory servers and peers.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Class variables
var model_config-
The type of the None singleton.
var socks_host : str-
The type of the None singleton.
var socks_port : int-
The type of the None singleton.
class TorControlConfig (**data: Any)-
Expand source code
class TorControlConfig(BaseModel): """ Configuration for Tor control port connection. When enabled, allows dynamic creation of ephemeral hidden services at startup using Tor's control port. This allows generating a new .onion address each time without needing to pre-configure the hidden service in torrc. Requires Tor to be configured with: ControlPort 127.0.0.1:9051 CookieAuthentication 1 CookieAuthFile /var/lib/tor/control_auth_cookie Auto-detects configuration from environment variables: TOR_CONTROL_HOST - Tor control host (default: 127.0.0.1) TOR_CONTROL_PORT - Tor control port (default: 9051) TOR_COOKIE_PATH - Cookie auth file path TOR_PASSWORD - Tor control password (not recommended) """ enabled: bool = Field(default=True, description="Enable Tor control port integration") host: str = Field(default="127.0.0.1", description="Tor control port host") port: int = Field(default=9051, ge=1, le=65535, description="Tor control port") cookie_path: Path | None = Field( default=None, description="Path to Tor cookie auth file (e.g., /var/lib/tor/control_auth_cookie)", ) password: str | None = Field( default=None, description="Password for HASHEDPASSWORD auth (not recommended, use cookie auth)", ) model_config = {"frozen": False}Configuration for Tor control port connection.
When enabled, allows dynamic creation of ephemeral hidden services at startup using Tor's control port. This allows generating a new .onion address each time without needing to pre-configure the hidden service in torrc.
Requires Tor to be configured with: ControlPort 127.0.0.1:9051 CookieAuthentication 1 CookieAuthFile /var/lib/tor/control_auth_cookie
Auto-detects configuration from environment variables: TOR_CONTROL_HOST - Tor control host (default: 127.0.0.1) TOR_CONTROL_PORT - Tor control port (default: 9051) TOR_COOKIE_PATH - Cookie auth file path TOR_PASSWORD - Tor control password (not recommended)
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Class variables
-
The type of the None singleton.
var enabled : bool-
The type of the None singleton.
var host : str-
The type of the None singleton.
var model_config-
The type of the None singleton.
var password : str | None-
The type of the None singleton.
var port : int-
The type of the None singleton.
class WalletConfig (**data: Any)-
Expand source code
class WalletConfig(BaseModel): """ Base wallet configuration shared by all JoinMarket wallet users. Includes wallet seed, network settings, HD wallet structure, and backend connection details. """ # Wallet seed mnemonic: str = Field(..., description="BIP39 mnemonic phrase for wallet seed") # Network settings network: NetworkType = Field( default=NetworkType.MAINNET, description="Protocol network for directory server handshakes", ) bitcoin_network: NetworkType | None = Field( default=None, description="Bitcoin network for address generation (defaults to same as network)", ) # Data directory data_dir: Path | None = Field( default=None, description=( "Data directory for JoinMarket files (commitment blacklist, history, etc.). " "Defaults to ~/.joinmarket-ng or $JOINMARKET_DATA_DIR if set" ), ) # Backend configuration backend_type: str = Field( default="full_node", description="Backend type: 'full_node' or 'neutrino'", ) backend_config: dict[str, Any] = Field( default_factory=dict, description="Backend-specific configuration", ) # Directory servers directory_servers: list[str] = Field( default_factory=list, description="List of directory server URLs (e.g., ['onion_host:port', ...])", ) # Tor/SOCKS configuration socks_host: str = Field(default="127.0.0.1", description="Tor SOCKS5 proxy host") socks_port: int = Field(default=9050, ge=1, le=65535, description="Tor SOCKS5 proxy port") # HD wallet structure mixdepth_count: int = Field( default=5, ge=1, le=10, description="Number of mixdepths in the wallet (privacy compartments)", ) gap_limit: int = Field(default=20, ge=6, description="BIP44 gap limit for address scanning") # Dust threshold dust_threshold: int = Field( default=DUST_THRESHOLD, ge=0, description="Dust threshold in satoshis for change outputs (default: 27300)", ) model_config = {"frozen": False} @model_validator(mode="after") def set_bitcoin_network_default(self) -> WalletConfig: """If bitcoin_network is not set, default to the protocol network.""" if self.bitcoin_network is None: object.__setattr__(self, "bitcoin_network", self.network) return selfBase wallet configuration shared by all JoinMarket wallet users.
Includes wallet seed, network settings, HD wallet structure, and backend connection details.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- pydantic.main.BaseModel
Subclasses
Class variables
var backend_config : dict[str, typing.Any]-
The type of the None singleton.
var backend_type : str-
The type of the None singleton.
var bitcoin_network : NetworkType | None-
The type of the None singleton.
var data_dir : pathlib.Path | None-
The type of the None singleton.
var directory_servers : list[str]-
The type of the None singleton.
var dust_threshold : int-
The type of the None singleton.
var gap_limit : int-
The type of the None singleton.
var mixdepth_count : int-
The type of the None singleton.
var mnemonic : str-
The type of the None singleton.
var model_config-
The type of the None singleton.
var network : NetworkType-
The type of the None singleton.
var socks_host : str-
The type of the None singleton.
var socks_port : int-
The type of the None singleton.
Methods
def set_bitcoin_network_default(self) ‑> WalletConfig-
Expand source code
@model_validator(mode="after") def set_bitcoin_network_default(self) -> WalletConfig: """If bitcoin_network is not set, default to the protocol network.""" if self.bitcoin_network is None: object.__setattr__(self, "bitcoin_network", self.network) return selfIf bitcoin_network is not set, default to the protocol network.