diff --git a/backend/mpc-system/docs/01-architecture.md b/backend/mpc-system/docs/01-architecture.md index 46e7ba65..260bfb9f 100644 --- a/backend/mpc-system/docs/01-architecture.md +++ b/backend/mpc-system/docs/01-architecture.md @@ -2,7 +2,7 @@ ## 1. 系统概述 -本系统是一个基于多方安全计算 (MPC) 的分布式门限签名系统,支持 t-of-n 阈值签名方案。系统采用微服务架构,使用 Go 语言开发,基于 bnb-chain/tss-lib 实现 TSS (Threshold Signature Scheme) 协议。 +本系统是一个基于多方安全计算 (MPC) 的分布式门限签名系统,支持 t-of-n 阈值签名方案。系统采用 **DDD (领域驱动设计) + 六边形架构 (Hexagonal Architecture) + 微服务** 的架构模式,使用 Go 语言开发,基于 bnb-chain/tss-lib 实现 TSS (Threshold Signature Scheme) 协议。 ### 1.1 核心特性 @@ -11,6 +11,7 @@ - **ECDSA secp256k1**: 与以太坊/比特币兼容的签名算法 - **高安全性**: 密钥分片加密存储,单点泄露不影响安全性 - **微服务架构**: 可独立扩展和部署 +- **Clean Architecture**: DDD + 六边形架构,领域逻辑与基础设施解耦 ### 1.2 技术栈 @@ -24,10 +25,474 @@ | 消息队列 | RabbitMQ | | 服务发现 | Consul | | 容器化 | Docker + Docker Compose | +| 架构模式 | DDD + Hexagonal + Microservices | -## 2. 系统架构 +### 1.3 架构设计原则 -### 2.1 整体架构图 +| 原则 | 说明 | +|------|------| +| **依赖倒置** | 内层定义接口,外层实现;依赖指向内层 | +| **领域隔离** | Domain 层零外部依赖,纯业务逻辑 | +| **端口适配** | 通过 Port/Adapter 模式解耦 I/O | +| **服务自治** | 每个微服务独立部署、独立数据库 | +| **单一职责** | 每个服务只负责一个业务领域 | + +## 2. 软件架构模式 + +### 2.1 DDD + 六边形架构 + 微服务 + +本系统采用三层架构模式的组合: + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ 微服务架构 (Microservices) │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Account Service │ │Session Coordinator│ │ Message Router │ ... │ +│ │ (独立部署) │ │ (独立部署) │ │ (独立部署) │ │ +│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────────────────────────────────────────────────────────────────┐ │ +│ │ 六边形架构 (Hexagonal / Ports & Adapters) │ │ +│ │ │ │ +│ │ ┌─────────────────────────────────────────────────────────────┐ │ │ +│ │ │ Adapters (Input) │ │ │ +│ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ +│ │ │ │HTTP Handler │ │gRPC Handler │ │ 消息消费者 │ │ │ │ +│ │ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ +│ │ └─────────┼────────────────┼────────────────┼──────────────────┘ │ │ +│ │ │ │ │ │ │ +│ │ ▼ ▼ ▼ │ │ +│ │ ┌─────────────────────────────────────────────────────────────┐ │ │ +│ │ │ Application Layer │ │ │ +│ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ +│ │ │ │ Input Ports │ │ Use Cases │ │ Output Ports │ │ │ │ +│ │ │ │ (接口定义) │ │ (业务编排) │ │ (接口定义) │ │ │ │ +│ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ +│ │ └─────────────────────────────────────────────────────────────┘ │ │ +│ │ │ │ │ │ │ +│ │ ▼ ▼ ▼ │ │ +│ │ ┌─────────────────────────────────────────────────────────────┐ │ │ +│ │ │ Domain Layer (DDD) │ │ │ +│ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ +│ │ │ │ Entities │ │Value Objects │ │Domain Services│ │ │ │ +│ │ │ │ (实体) │ │ (值对象) │ │ (领域服务) │ │ │ │ +│ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ +│ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ +│ │ │ │ Repositories │ │ Aggregates │ │ │ │ +│ │ │ │ (仓储接口) │ │ (聚合根) │ │ │ │ +│ │ │ └──────────────┘ └──────────────┘ │ │ │ +│ │ └─────────────────────────────────────────────────────────────┘ │ │ +│ │ │ │ │ │ │ +│ │ ▼ ▼ ▼ │ │ +│ │ ┌─────────────────────────────────────────────────────────────┐ │ │ +│ │ │ Adapters (Output) │ │ │ +│ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ +│ │ │ │ PostgreSQL │ │ Redis │ │ RabbitMQ │ │ │ │ +│ │ │ │ Repo │ │ Cache │ │ Publisher │ │ │ │ +│ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ +│ │ └─────────────────────────────────────────────────────────────┘ │ │ +│ └─────────────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +### 2.2 单个微服务内部结构 + +每个微服务采用六边形架构,内部分为三层: + +``` +service/ +├── domain/ # 领域层 (最内层,零外部依赖) +│ ├── entities/ # 实体 - 有唯一标识的领域对象 +│ ├── value_objects/ # 值对象 - 无标识的不可变对象 +│ ├── repositories/ # 仓储接口 - 领域定义,适配器实现 +│ └── services/ # 领域服务 - 跨实体的业务逻辑 +│ +├── application/ # 应用层 (中间层,编排业务用例) +│ ├── ports/ # 端口定义 +│ │ ├── input/ # 入站端口 - 定义用例接口 +│ │ └── output/ # 出站端口 - 定义基础设施接口 +│ └── use_cases/ # 用例实现 - 业务流程编排 +│ +├── adapters/ # 适配器层 (最外层,处理 I/O) +│ ├── input/ # 入站适配器 +│ │ ├── http/ # HTTP/REST 处理器 +│ │ └── grpc/ # gRPC 处理器 +│ └── output/ # 出站适配器 +│ ├── postgres/ # PostgreSQL 仓储实现 +│ ├── redis/ # Redis 缓存实现 +│ └── rabbitmq/ # RabbitMQ 消息发布 +│ +└── cmd/server/ # 服务入口 - 依赖注入和启动 + └── main.go +``` + +### 2.3 DDD 战术模式实现 + +#### 2.3.1 实体 (Entity) + +有唯一标识的领域对象,封装业务规则: + +```go +// services/account/domain/entities/account.go +type Account struct { + ID value_objects.AccountID // 唯一标识 + Username string + Email string + PublicKey []byte + Status value_objects.AccountStatus + ThresholdN int + ThresholdT int + CreatedAt time.Time + UpdatedAt time.Time +} + +// 业务方法封装在实体内 +func (a *Account) Suspend() error { + if a.Status == value_objects.AccountStatusRecovering { + return ErrAccountInRecovery + } + a.Status = value_objects.AccountStatusSuspended + a.UpdatedAt = time.Now().UTC() + return nil +} + +func (a *Account) CanLogin() bool { + return a.Status.CanLogin() +} +``` + +#### 2.3.2 值对象 (Value Object) + +无标识的不可变对象,通过值相等性比较: + +```go +// services/account/domain/value_objects/account_id.go +type AccountID struct { + value uuid.UUID +} + +func NewAccountID() AccountID { + return AccountID{value: uuid.New()} +} + +func (id AccountID) String() string { + return id.value.String() +} + +func (id AccountID) Equals(other AccountID) bool { + return id.value == other.value +} + +// services/session-coordinator/domain/value_objects/session_status.go +type SessionStatus string + +const ( + SessionStatusCreated SessionStatus = "created" + SessionStatusWaiting SessionStatus = "waiting" + SessionStatusInProgress SessionStatus = "in_progress" + SessionStatusCompleted SessionStatus = "completed" + SessionStatusFailed SessionStatus = "failed" +) + +func (s SessionStatus) CanTransitionTo(target SessionStatus) bool { + // 状态转换规则 + transitions := map[SessionStatus][]SessionStatus{ + SessionStatusCreated: {SessionStatusWaiting, SessionStatusFailed}, + SessionStatusWaiting: {SessionStatusInProgress, SessionStatusFailed}, + SessionStatusInProgress: {SessionStatusCompleted, SessionStatusFailed}, + } + for _, allowed := range transitions[s] { + if allowed == target { + return true + } + } + return false +} +``` + +#### 2.3.3 聚合 (Aggregate) + +聚合根管理一组相关实体的一致性边界: + +```go +// services/session-coordinator/domain/entities/mpc_session.go +// MPCSession 是聚合根,管理 Participants +type MPCSession struct { + ID uuid.UUID + Type SessionType + Status SessionStatus + ThresholdT int + ThresholdN int + Participants []Participant // 子实体 + CreatedAt time.Time +} + +// 聚合根负责维护内部一致性 +func (s *MPCSession) AddParticipant(p Participant) error { + if len(s.Participants) >= s.ThresholdN { + return ErrSessionFull + } + if s.Status != SessionStatusWaiting { + return ErrInvalidSessionStatus + } + s.Participants = append(s.Participants, p) + return nil +} + +func (s *MPCSession) AllParticipantsReady() bool { + if len(s.Participants) < s.ThresholdN { + return false + } + for _, p := range s.Participants { + if p.Status != ParticipantStatusReady { + return false + } + } + return true +} +``` + +#### 2.3.4 仓储接口 (Repository) + +领域层定义接口,适配器层实现: + +```go +// services/account/domain/repositories/account_repository.go +type AccountRepository interface { + Save(ctx context.Context, account *entities.Account) error + FindByID(ctx context.Context, id value_objects.AccountID) (*entities.Account, error) + FindByUsername(ctx context.Context, username string) (*entities.Account, error) + FindByEmail(ctx context.Context, email string) (*entities.Account, error) + Update(ctx context.Context, account *entities.Account) error + Delete(ctx context.Context, id value_objects.AccountID) error +} +``` + +#### 2.3.5 领域服务 (Domain Service) + +跨实体的业务逻辑: + +```go +// services/session-coordinator/domain/services/session_coordinator.go +type SessionCoordinatorService struct { + sessionRepo repositories.SessionRepository +} + +func (s *SessionCoordinatorService) ValidateThreshold(t, n int) error { + if t < 1 || t > n { + return ErrInvalidThreshold + } + if n < 2 { + return ErrInvalidPartyCount + } + return nil +} +``` + +### 2.4 六边形架构端口与适配器 + +#### 2.4.1 入站端口 (Input Port) + +定义用例接口: + +```go +// services/account/application/ports/input_ports.go +type CreateAccountInput struct { + Username string + Email string + PublicKey []byte + ThresholdN int + ThresholdT int +} + +type CreateAccountOutput struct { + Account *entities.Account +} + +// 用例接口 +type CreateAccountPort interface { + Execute(ctx context.Context, input CreateAccountInput) (*CreateAccountOutput, error) +} +``` + +#### 2.4.2 出站端口 (Output Port) + +定义基础设施接口: + +```go +// services/session-coordinator/application/ports/output/session_storage_port.go +type SessionStoragePort interface { + Save(ctx context.Context, session *entities.MPCSession) error + FindByID(ctx context.Context, id uuid.UUID) (*entities.MPCSession, error) + Update(ctx context.Context, session *entities.MPCSession) error +} + +// services/session-coordinator/application/ports/output/message_broker_port.go +type MessageBrokerPort interface { + PublishSessionEvent(ctx context.Context, event SessionEvent) error + PublishPartyNotification(ctx context.Context, partyID string, msg []byte) error +} +``` + +#### 2.4.3 用例实现 (Use Case) + +编排业务流程: + +```go +// services/account/application/use_cases/create_account.go +type CreateAccountUseCase struct { + accountRepo repositories.AccountRepository + eventPub ports.EventPublisherPort +} + +func (uc *CreateAccountUseCase) Execute( + ctx context.Context, + input ports.CreateAccountInput, +) (*ports.CreateAccountOutput, error) { + // 1. 创建领域实体 + account := entities.NewAccount( + input.Username, + input.Email, + input.PublicKey, + input.ThresholdN, + input.ThresholdT, + ) + + // 2. 验证业务规则 + if err := account.Validate(); err != nil { + return nil, err + } + + // 3. 持久化 + if err := uc.accountRepo.Save(ctx, account); err != nil { + return nil, err + } + + // 4. 发布领域事件 + uc.eventPub.Publish(ctx, events.AccountCreated{AccountID: account.ID}) + + return &ports.CreateAccountOutput{Account: account}, nil +} +``` + +#### 2.4.4 入站适配器 (Input Adapter) + +HTTP/gRPC 处理器: + +```go +// services/account/adapters/input/http/account_handler.go +type AccountHandler struct { + createAccountUC ports.CreateAccountPort + loginUC ports.LoginPort +} + +func (h *AccountHandler) CreateAccount(c *gin.Context) { + var req CreateAccountRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(400, gin.H{"error": err.Error()}) + return + } + + output, err := h.createAccountUC.Execute(c.Request.Context(), ports.CreateAccountInput{ + Username: req.Username, + Email: req.Email, + PublicKey: req.PublicKey, + ThresholdN: req.ThresholdN, + ThresholdT: req.ThresholdT, + }) + if err != nil { + c.JSON(500, gin.H{"error": err.Error()}) + return + } + + c.JSON(201, output) +} +``` + +#### 2.4.5 出站适配器 (Output Adapter) + +数据库/缓存实现: + +```go +// services/account/adapters/output/postgres/account_repo.go +type PostgresAccountRepository struct { + db *sql.DB +} + +func (r *PostgresAccountRepository) Save(ctx context.Context, account *entities.Account) error { + query := `INSERT INTO accounts (id, username, email, public_key, status, threshold_n, threshold_t, created_at) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8)` + _, err := r.db.ExecContext(ctx, query, + account.ID.String(), + account.Username, + account.Email, + account.PublicKey, + account.Status, + account.ThresholdN, + account.ThresholdT, + account.CreatedAt, + ) + return err +} + +func (r *PostgresAccountRepository) FindByID(ctx context.Context, id value_objects.AccountID) (*entities.Account, error) { + query := `SELECT id, username, email, public_key, status, threshold_n, threshold_t, created_at, updated_at + FROM accounts WHERE id = $1` + row := r.db.QueryRowContext(ctx, query, id.String()) + // ... scan and return +} +``` + +### 2.5 依赖注入 (Dependency Injection) + +在 main.go 中组装依赖: + +```go +// services/account/cmd/server/main.go +func main() { + // 基础设施 + db := connectDatabase() + redisClient := connectRedis() + rabbitConn := connectRabbitMQ() + + // 出站适配器 (实现端口) + accountRepo := postgres.NewAccountRepository(db) + cacheAdapter := redis.NewCacheAdapter(redisClient) + eventPublisher := rabbitmq.NewEventPublisher(rabbitConn) + + // 用例 (注入依赖) + createAccountUC := use_cases.NewCreateAccountUseCase(accountRepo, eventPublisher) + loginUC := use_cases.NewLoginUseCase(accountRepo, cacheAdapter) + + // 入站适配器 (使用用例) + handler := http.NewAccountHandler(createAccountUC, loginUC) + + // 启动服务器 + router := gin.Default() + handler.RegisterRoutes(router) + router.Run(":8080") +} +``` + +### 2.6 DDD 战术模式总览 + +| DDD 概念 | 本系统实现 | 位置 | +|---------|-----------|------| +| **Entity** | Account, MPCSession, Participant | `domain/entities/` | +| **Value Object** | AccountID, SessionStatus, Threshold | `domain/value_objects/` | +| **Aggregate** | Account (含 AccountShare), MPCSession (含 Participant) | `domain/entities/` | +| **Repository** | AccountRepository, SessionRepository (接口) | `domain/repositories/` | +| **Domain Service** | SessionCoordinatorService, AccountService | `domain/services/` | +| **Application Service** | CreateAccountUseCase, JoinSessionUseCase | `application/use_cases/` | +| **Input Port** | CreateAccountPort, LoginPort | `application/ports/input/` | +| **Output Port** | SessionStoragePort, MessageBrokerPort | `application/ports/output/` | +| **Input Adapter** | AccountHandler (HTTP), SessionGrpcHandler | `adapters/input/` | +| **Output Adapter** | PostgresRepo, RedisCache, RabbitMQPublisher | `adapters/output/` | + +## 3. 系统部署架构 + +### 3.1 整体架构图 ``` ┌─────────────────────────────────────────────────────────────────────┐ @@ -75,35 +540,35 @@ └─────────────────────────────────────────────────────────────────────┘ ``` -### 2.2 服务职责 +### 3.2 服务职责 -#### 2.2.1 Session Coordinator (会话协调器) +#### 3.2.1 Session Coordinator (会话协调器) - 创建和管理 MPC 会话 - 协调参与方加入会话 - 跟踪会话状态和进度 - 管理参与方就绪状态 -#### 2.2.2 Message Router (消息路由器) +#### 3.2.2 Message Router (消息路由器) - 路由 TSS 协议消息 - 支持点对点和广播消息 - 消息缓存和重传 - WebSocket 实时通信 -#### 2.2.3 Server Party (服务端参与方) +#### 3.2.3 Server Party (服务端参与方) - 作为 MPC 协议的服务端参与方 - 执行 DKG 和签名协议 - 安全存储加密的密钥分片 - 支持多实例部署 -#### 2.2.4 Account Service (账户服务) +#### 3.2.4 Account Service (账户服务) - 用户注册和认证 - 账户管理 - MPC 会话入口 API - 账户恢复流程 -## 3. 核心流程 +## 4. 核心流程 -### 3.1 密钥生成流程 (Keygen) +### 4.1 密钥生成流程 (Keygen) ``` ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ @@ -139,7 +604,7 @@ │ │ │ │ ``` -### 3.2 签名流程 (Signing) +### 4.2 签名流程 (Signing) ``` ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ @@ -170,9 +635,9 @@ │ │ │ │ ``` -## 4. 数据模型 +## 5. 数据模型 -### 4.1 Session (会话) +### 5.1 Session (会话) ```go type Session struct { @@ -188,7 +653,7 @@ type Session struct { } ``` -### 4.2 Participant (参与方) +### 5.2 Participant (参与方) ```go type Participant struct { @@ -200,7 +665,7 @@ type Participant struct { } ``` -### 4.3 KeyShare (密钥分片) +### 5.3 KeyShare (密钥分片) ```go type KeyShare struct { @@ -213,21 +678,21 @@ type KeyShare struct { } ``` -## 5. 安全设计 +## 6. 安全设计 -### 5.1 密钥安全 +### 6.1 密钥安全 - **密钥分片存储**: 使用 AES-256-GCM 加密存储 - **主密钥管理**: 从环境变量或 KMS 加载 - **无单点故障**: 任意 t 个节点被攻破不影响安全性 -### 5.2 通信安全 +### 6.2 通信安全 - **TLS 加密**: 所有 gRPC/HTTP 通信使用 TLS - **消息认证**: TSS 消息包含参与方签名 - **会话令牌**: 使用 UUID v4 生成一次性令牌 -### 5.3 安全属性 +### 6.3 安全属性 | 属性 | 描述 | |------|------| @@ -236,9 +701,9 @@ type KeyShare struct { | 前向安全 | 会话密钥独立,历史泄露不影响未来 | | 抗合谋 | t 个恶意方无法伪造签名 | -## 6. 部署架构 +## 7. 部署架构 -### 6.1 最小部署 (2-of-3) +### 7.1 最小部署 (2-of-3) ``` ┌─────────────────────────────────────────────────────────┐ @@ -259,14 +724,14 @@ type KeyShare struct { └──────────────────┘ └──────────────────┘ └──────────────────┘ ``` -### 6.2 生产环境部署 +### 7.2 生产环境部署 - **高可用**: 每个服务至少 2 副本 - **负载均衡**: Nginx/Traefik 反向代理 - **服务发现**: Consul 集群 - **监控**: Prometheus + Grafana -## 7. 目录结构 +## 8. 目录结构 ``` mpc-system/