Source code for rizemind.web3.config

from typing import Any

from flwr.common.context import Context
from pydantic import Field, HttpUrl, field_validator
from pydantic_core import Url
from web3 import HTTPProvider, Web3
from web3.middleware import ExtraDataToPOAMiddleware

from rizemind.configuration.base_config import BaseConfig
from rizemind.configuration.transform import unflatten
from rizemind.web3.chains import RIZENET_TESTNET_CHAINID

poaChains = [RIZENET_TESTNET_CHAINID]

WEB3_CONFIG_STATE_KEY = "rizemind.web3"


[docs] class Web3Config(BaseConfig): """Configuration for Web3 blockchain connections. Manages Web3 provider configuration including URL validation, middleware injection for Proof-of-Authority chains, and Web3 instance creation. Attributes: url: The HTTP provider URL for blockchain connectivity. If None, defaults to RizeNet testnet URL. """ url: HttpUrl | None = Field(..., description="The HTTP provider URL")
[docs] @field_validator("url", mode="before") @classmethod def coerce_url(cls, value: Any) -> Any: """Validates and coerces URL values to HttpUrl format. Handles various input types and converts them to the appropriate HttpUrl format for Pydantic validation. Args: value: The URL value to validate. Can be None, string, HttpUrl, or Url. Returns: The validated HttpUrl object or None. Raises: TypeError: If the value type is not supported. ValidationError: If the URL string is invalid (raised by HttpUrl). """ # Let Pydantic handle None or already-parsed HttpUrl if value is None or isinstance(value, HttpUrl | Url): return value if isinstance(value, str): return HttpUrl(value) # will raise if invalid raise TypeError("url must be a string, HttpUrl, or None")
[docs] def get_web3(self, *, web3_factory=Web3) -> Web3: """Creates a configured Web3 instance. Initializes a Web3 instance with the configured HTTP provider and automatically injects Proof-of-Authority middleware for supported chains. Args: web3_factory: Factory function for creating Web3 instances. Defaults to the standard Web3 constructor. Returns: A configured Web3 instance ready for blockchain interaction. """ w3 = web3_factory(self.web3_provider()) if w3.eth.chain_id in poaChains: w3.middleware_onion.inject(ExtraDataToPOAMiddleware, layer=0) return w3
[docs] def web3_provider(self) -> HTTPProvider: """Creates an HTTP provider for Web3 connections. Constructs an HTTPProvider using the configured URL or defaults to the RizeNet testnet if no URL is specified. Returns: An HTTPProvider instance configured with the appropriate endpoint URL. """ url = self.url if url is None: url = "https://testnet.rizenet.io" return Web3.HTTPProvider(str(url))
[docs] @staticmethod def from_context(context: Context) -> "Web3Config | None": """Creates a Web3Config instance from a Flower context. Extracts Web3 configuration from the provided Flower context state and constructs a Web3Config instance if the configuration exists. Args: context: The Flower context containing configuration state. Returns: A Web3Config instance if configuration is found in the context, otherwise None. """ if WEB3_CONFIG_STATE_KEY in context.state.config_records: records: Any = context.state.config_records[WEB3_CONFIG_STATE_KEY] return Web3Config(**unflatten(records)) return None