按显卡世代和创世编号结算回本,机房批量接入需审核网段并用硬件指纹防克隆。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -23,6 +23,8 @@ from sqlalchemy import (
|
||||
Enum,
|
||||
ForeignKey,
|
||||
Index,
|
||||
Boolean,
|
||||
Float,
|
||||
Integer,
|
||||
Numeric,
|
||||
String,
|
||||
@@ -35,6 +37,7 @@ from sqlalchemy.types import JSON, TypeDecorator
|
||||
from app.clock import utcnow
|
||||
from app.database import Base, UtcDateTime
|
||||
from app.money import money
|
||||
from app.services.hardware import display_node_id, is_genesis
|
||||
|
||||
|
||||
class PreciseDecimal(TypeDecorator):
|
||||
@@ -109,6 +112,12 @@ class OrderStatus(str, enum.Enum):
|
||||
REJECTED = "rejected"
|
||||
|
||||
|
||||
class DatacenterStatus(str, enum.Enum):
|
||||
PENDING = "pending"
|
||||
APPROVED = "approved"
|
||||
REJECTED = "rejected"
|
||||
|
||||
|
||||
class User(Base):
|
||||
"""用户。一个钱包地址对应一名用户,可绑定多台算力节点。"""
|
||||
|
||||
@@ -125,6 +134,7 @@ class User(Base):
|
||||
yields: Mapped[list[NodeYield]] = relationship(back_populates="user")
|
||||
withdrawals: Mapped[list[WithdrawalLog]] = relationship(back_populates="user")
|
||||
orders: Mapped[list[LicenseOrder]] = relationship(back_populates="user")
|
||||
datacenter_applications: Mapped[list[DatacenterApplication]] = relationship(back_populates="user")
|
||||
|
||||
|
||||
class ComputeNode(Base):
|
||||
@@ -140,6 +150,7 @@ class ComputeNode(Base):
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True)
|
||||
sn: Mapped[str] = mapped_column(String(64), unique=True, index=True, comment="节点唯一序列号")
|
||||
node_index: Mapped[int] = mapped_column(Integer, unique=True, comment="激活顺序,从 1 开始")
|
||||
purchase_amount: Mapped[Decimal] = mapped_column(MONEY, comment="授权购买金额")
|
||||
license_months: Mapped[int] = mapped_column(Integer, default=12)
|
||||
licensed_at: Mapped[datetime] = mapped_column(UtcDateTime, comment="授权开始时间")
|
||||
@@ -148,16 +159,69 @@ class ComputeNode(Base):
|
||||
last_heartbeat_at: Mapped[datetime | None] = mapped_column(UtcDateTime)
|
||||
callback_url: Mapped[str | None] = mapped_column(String(512), comment="可选的任务推送地址")
|
||||
node_token: Mapped[str | None] = mapped_column(String(128), unique=True, comment="挂机客户端凭证,审核通过后生成")
|
||||
gpu_model: Mapped[str | None] = mapped_column(String(128), comment="心跳上报的显卡型号")
|
||||
vram_gb: Mapped[float | None] = mapped_column(Float, comment="显存,GB")
|
||||
cpu_count: Mapped[int | None] = mapped_column(Integer, comment="CPU 逻辑核心数")
|
||||
memory_gb: Mapped[float | None] = mapped_column(Float, comment="内存,GB")
|
||||
hardware_weight: Mapped[float] = mapped_column(Float, default=0.05, comment="硬件算力权重")
|
||||
gpu_generation: Mapped[str] = mapped_column(String(8), default="10", comment="显卡世代:40、30 或 10")
|
||||
recovery_days: Mapped[int] = mapped_column(Integer, default=540, comment="质押回本目标天数")
|
||||
generation_locked: Mapped[bool] = mapped_column(default=False, comment="世代已按上报显卡锁定")
|
||||
recoverable_stake_amount: Mapped[Decimal | None] = mapped_column(MONEY, comment="尚未返还的质押金")
|
||||
is_whitelist: Mapped[bool] = mapped_column(Boolean, default=False, comment="白名单节点,跳过单 IP 限制")
|
||||
client_ip: Mapped[str | None] = mapped_column(String(64), index=True, comment="最近一次注册或心跳的客户端 IP")
|
||||
hardware_fingerprint: Mapped[str | None] = mapped_column(
|
||||
String(64), unique=True, comment="显卡 UUID、主板与网卡合成的硬件指纹"
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(UtcDateTime, default=utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(UtcDateTime, default=utcnow, onupdate=utcnow)
|
||||
|
||||
user: Mapped[User] = relationship(back_populates="nodes")
|
||||
order: Mapped[LicenseOrder | None] = relationship(back_populates="node")
|
||||
|
||||
@property
|
||||
def display_node_id(self) -> int:
|
||||
return display_node_id(self.node_index)
|
||||
|
||||
@property
|
||||
def genesis(self) -> bool:
|
||||
return is_genesis(self.node_index)
|
||||
yields: Mapped[list[NodeYield]] = relationship(back_populates="node")
|
||||
tasks: Mapped[list[ComputeTask]] = relationship(back_populates="node")
|
||||
uptime_intervals: Mapped[list[UptimeInterval]] = relationship(back_populates="node")
|
||||
|
||||
|
||||
class IPWhitelist(Base):
|
||||
"""管理员维护的豁免地址。可以是单 IP,也可以是机房网段,例如 203.0.113.0/24。"""
|
||||
|
||||
__tablename__ = "ip_whitelist"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
ip_address: Mapped[str] = mapped_column(String(64), unique=True, index=True)
|
||||
note: Mapped[str | None] = mapped_column(String(128))
|
||||
created_at: Mapped[datetime] = mapped_column(UtcDateTime, default=utcnow)
|
||||
|
||||
|
||||
class DatacenterApplication(Base):
|
||||
"""机房大客户申请。通过后把出口网段写入 IP 白名单。"""
|
||||
|
||||
__tablename__ = "datacenter_applications"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True)
|
||||
contact: Mapped[str] = mapped_column(String(128))
|
||||
node_count: Mapped[int] = mapped_column(Integer)
|
||||
subnet_ip: Mapped[str] = mapped_column(String(64))
|
||||
hardware_proof: Mapped[str] = mapped_column(Text)
|
||||
gpu_generation: Mapped[str] = mapped_column(String(8))
|
||||
status: Mapped[DatacenterStatus] = mapped_column(_enum(DatacenterStatus), default=DatacenterStatus.PENDING, index=True)
|
||||
note: Mapped[str | None] = mapped_column(String(500))
|
||||
created_at: Mapped[datetime] = mapped_column(UtcDateTime, default=utcnow)
|
||||
reviewed_at: Mapped[datetime | None] = mapped_column(UtcDateTime)
|
||||
|
||||
user: Mapped[User] = relationship(back_populates="datacenter_applications")
|
||||
|
||||
|
||||
class UptimeInterval(Base):
|
||||
"""一段连续在线时间。心跳首次上线时打开,超时或授权到期时关闭。"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user