from __future__ import annotations from datetime import datetime from typing import Any, Dict, Optional, List from base64 import b64encode, b64decode from enum import Enum from pydantic import BaseModel, Field, ConfigDict from .types import JobState, Constraints # Payment schemas class JobPaymentCreate(BaseModel): """Request to create a payment for a job""" job_id: str amount: float currency: str = "AITBC" # Jobs paid with AITBC tokens payment_method: str = "aitbc_token" # Primary method for job payments escrow_timeout_seconds: int = 3600 # 1 hour default class JobPaymentView(BaseModel): """Payment information for a job""" job_id: str payment_id: str amount: float currency: str status: str payment_method: str escrow_address: Optional[str] = None refund_address: Optional[str] = None created_at: datetime updated_at: datetime released_at: Optional[datetime] = None refunded_at: Optional[datetime] = None transaction_hash: Optional[str] = None refund_transaction_hash: Optional[str] = None class PaymentRequest(BaseModel): """Request to pay for a job""" job_id: str amount: float currency: str = "BTC" refund_address: Optional[str] = None class PaymentReceipt(BaseModel): """Receipt for a payment""" payment_id: str job_id: str amount: float currency: str status: str transaction_hash: Optional[str] = None created_at: datetime verified_at: Optional[datetime] = None class EscrowRelease(BaseModel): """Request to release escrow payment""" job_id: str payment_id: str reason: Optional[str] = None class RefundRequest(BaseModel): """Request to refund a payment""" job_id: str payment_id: str reason: str # User management schemas class UserCreate(BaseModel): email: str username: str password: Optional[str] = None class UserLogin(BaseModel): wallet_address: str signature: Optional[str] = None class UserProfile(BaseModel): user_id: str email: str username: str created_at: str session_token: Optional[str] = None class UserBalance(BaseModel): user_id: str address: str balance: float updated_at: Optional[str] = None class Transaction(BaseModel): id: str type: str status: str amount: float fee: float description: Optional[str] created_at: str confirmed_at: Optional[str] = None class TransactionHistory(BaseModel): user_id: str transactions: List[Transaction] total: int class ExchangePaymentRequest(BaseModel): user_id: str aitbc_amount: float btc_amount: float class ExchangePaymentResponse(BaseModel): payment_id: str user_id: str aitbc_amount: float btc_amount: float payment_address: str status: str created_at: int expires_at: int class JobCreate(BaseModel): payload: Dict[str, Any] constraints: Constraints = Field(default_factory=Constraints) ttl_seconds: int = 900 payment_amount: Optional[float] = None # Amount to pay for the job payment_currency: str = "AITBC" # Jobs paid with AITBC tokens class JobView(BaseModel): job_id: str state: JobState assigned_miner_id: Optional[str] = None requested_at: datetime expires_at: datetime error: Optional[str] = None payment_id: Optional[str] = None payment_status: Optional[str] = None class JobResult(BaseModel): result: Optional[Dict[str, Any]] = None receipt: Optional[Dict[str, Any]] = None class MinerRegister(BaseModel): capabilities: Dict[str, Any] concurrency: int = 1 region: Optional[str] = None class MinerHeartbeat(BaseModel): inflight: int = 0 status: str = "ONLINE" metadata: Dict[str, Any] = Field(default_factory=dict) class PollRequest(BaseModel): max_wait_seconds: int = 15 class AssignedJob(BaseModel): job_id: str payload: Dict[str, Any] constraints: Constraints class JobResultSubmit(BaseModel): result: Dict[str, Any] metrics: Dict[str, Any] = Field(default_factory=dict) class JobFailSubmit(BaseModel): error_code: str error_message: str metrics: Dict[str, Any] = Field(default_factory=dict) class MarketplaceOfferView(BaseModel): id: str provider: str capacity: int price: float sla: str status: str created_at: datetime gpu_model: Optional[str] = None gpu_memory_gb: Optional[int] = None gpu_count: Optional[int] = 1 cuda_version: Optional[str] = None price_per_hour: Optional[float] = None region: Optional[str] = None class MarketplaceStatsView(BaseModel): totalOffers: int openCapacity: int averagePrice: float activeBids: int class MarketplaceBidRequest(BaseModel): provider: str = Field(..., min_length=1) capacity: int = Field(..., gt=0) price: float = Field(..., gt=0) notes: Optional[str] = Field(default=None, max_length=1024) class BlockSummary(BaseModel): model_config = ConfigDict(populate_by_name=True) height: int hash: str timestamp: datetime txCount: int proposer: str class BlockListResponse(BaseModel): model_config = ConfigDict(populate_by_name=True) items: list[BlockSummary] next_offset: Optional[str | int] = None class TransactionSummary(BaseModel): model_config = ConfigDict(populate_by_name=True, ser_json_tuples=True) hash: str block: str | int from_address: str = Field(alias="from") to_address: Optional[str] = Field(default=None, alias="to") value: str status: str class TransactionListResponse(BaseModel): model_config = ConfigDict(populate_by_name=True) items: list[TransactionSummary] next_offset: Optional[str | int] = None class AddressSummary(BaseModel): model_config = ConfigDict(populate_by_name=True) address: str balance: str txCount: int lastActive: datetime recentTransactions: Optional[list[str]] = Field(default=None) class AddressListResponse(BaseModel): model_config = ConfigDict(populate_by_name=True) items: list[AddressSummary] next_offset: Optional[str | int] = None class ReceiptSummary(BaseModel): model_config = ConfigDict(populate_by_name=True) receiptId: str jobId: Optional[str] = None miner: str coordinator: str issuedAt: datetime status: str payload: Optional[Dict[str, Any]] = None class ReceiptListResponse(BaseModel): model_config = ConfigDict(populate_by_name=True) jobId: str items: list[ReceiptSummary] class Receipt(BaseModel): """Receipt model for zk-proof generation""" receiptId: str miner: str coordinator: str issuedAt: datetime status: str payload: Optional[Dict[str, Any]] = None # Confidential Transaction Models class ConfidentialTransaction(BaseModel): """Transaction with optional confidential fields""" # Public fields (always visible) transaction_id: str job_id: str timestamp: datetime status: str # Confidential fields (encrypted when opt-in) amount: Optional[str] = None pricing: Optional[Dict[str, Any]] = None settlement_details: Optional[Dict[str, Any]] = None # Encryption metadata confidential: bool = False encrypted_data: Optional[str] = None # Base64 encoded encrypted_keys: Optional[Dict[str, str]] = None # Base64 encoded algorithm: Optional[str] = None # Access control participants: List[str] = [] access_policies: Dict[str, Any] = {} model_config = ConfigDict(populate_by_name=True) class ConfidentialTransactionCreate(BaseModel): """Request to create confidential transaction""" job_id: str amount: Optional[str] = None pricing: Optional[Dict[str, Any]] = None settlement_details: Optional[Dict[str, Any]] = None # Privacy options confidential: bool = False participants: List[str] = [] # Access policies access_policies: Dict[str, Any] = {} class ConfidentialTransactionView(BaseModel): """Response for confidential transaction view""" transaction_id: str job_id: str timestamp: datetime status: str # Decrypted fields (only if authorized) amount: Optional[str] = None pricing: Optional[Dict[str, Any]] = None settlement_details: Optional[Dict[str, Any]] = None # Metadata confidential: bool participants: List[str] has_encrypted_data: bool class ConfidentialAccessRequest(BaseModel): """Request to access confidential transaction data""" transaction_id: str requester: str purpose: str justification: Optional[str] = None class ConfidentialAccessResponse(BaseModel): """Response for confidential data access""" success: bool data: Optional[Dict[str, Any]] = None error: Optional[str] = None access_id: Optional[str] = None # Key Management Models class KeyPair(BaseModel): """Encryption key pair for participant""" participant_id: str private_key: bytes public_key: bytes algorithm: str = "X25519" created_at: datetime version: int = 1 model_config = ConfigDict(arbitrary_types_allowed=True) class KeyRotationLog(BaseModel): """Log of key rotation events""" participant_id: str old_version: int new_version: int rotated_at: datetime reason: str class AuditAuthorization(BaseModel): """Authorization for audit access""" issuer: str subject: str purpose: str created_at: datetime expires_at: datetime signature: str class KeyRegistrationRequest(BaseModel): """Request to register encryption keys""" participant_id: str public_key: str # Base64 encoded algorithm: str = "X25519" class KeyRegistrationResponse(BaseModel): """Response for key registration""" success: bool participant_id: str key_version: int registered_at: datetime error: Optional[str] = None # Access Log Models class ConfidentialAccessLog(BaseModel): """Audit log for confidential data access""" transaction_id: Optional[str] participant_id: str purpose: str timestamp: datetime authorized_by: str data_accessed: List[str] success: bool error: Optional[str] = None ip_address: Optional[str] = None user_agent: Optional[str] = None class AccessLogQuery(BaseModel): """Query for access logs""" transaction_id: Optional[str] = None participant_id: Optional[str] = None purpose: Optional[str] = None start_time: Optional[datetime] = None end_time: Optional[datetime] = None limit: int = 100 offset: int = 0 class AccessLogResponse(BaseModel): """Response for access log query""" logs: List[ConfidentialAccessLog] total_count: int has_more: bool