rwadurian/backend/mpc-system/docs/03-development-guide.md

510 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# MPC 分布式签名系统 - 开发指南
## 1. 开发环境设置
### 1.1 系统要求
| 软件 | 版本要求 | 说明 |
|------|---------|------|
| Go | 1.21+ | 主要开发语言 |
| Docker | 20.10+ | 容器化运行 |
| Docker Compose | 2.0+ | 多容器编排 |
| Make | 3.8+ | 构建工具 |
| protoc | 3.0+ | Protocol Buffers 编译器 |
### 1.2 克隆项目
```bash
git clone https://github.com/rwadurian/mpc-system.git
cd mpc-system
```
### 1.3 安装依赖
```bash
# 安装 Go 工具
make init
# 下载 Go 模块
go mod download
# 验证安装
go version
make version
```
### 1.4 IDE 配置
推荐使用 VSCode 或 GoLand:
**VSCode 扩展**:
- Go (golang.go)
- vscode-proto3
- Docker
**.vscode/settings.json**:
```json
{
"go.useLanguageServer": true,
"go.lintTool": "golangci-lint",
"go.formatTool": "goimports",
"[go]": {
"editor.formatOnSave": true
}
}
```
## 2. 项目结构详解
```
mpc-system/
├── api/ # API 定义
│ ├── grpc/ # gRPC 生成代码
│ │ └── coordinator/v1/ # Session Coordinator 接口
│ └── proto/ # Protobuf 源文件
│ └── session_coordinator.proto
├── pkg/ # 公共包 (可被其他项目引用)
│ ├── crypto/ # 加密工具
│ │ └── encryption.go # AES-GCM 加密
│ └── tss/ # TSS 核心封装
│ ├── keygen.go # 密钥生成
│ └── signing.go # 签名协议
├── services/ # 微服务目录
│ ├── account/ # 账户服务
│ │ ├── adapters/ # 适配器层
│ │ │ ├── input/http/ # HTTP 处理器
│ │ │ └── output/postgres/ # 数据库实现
│ │ ├── application/ # 应用层
│ │ │ ├── ports/ # 端口定义
│ │ │ └── use_cases/ # 用例实现
│ │ ├── domain/ # 领域层
│ │ │ ├── entities/ # 实体
│ │ │ ├── repositories/ # 仓储接口
│ │ │ └── value_objects/ # 值对象
│ │ └── cmd/server/ # 服务入口
│ │
│ ├── session-coordinator/ # 会话协调器
│ ├── message-router/ # 消息路由器
│ └── server-party/ # 服务端参与方
├── tests/ # 测试目录
│ ├── e2e/ # 端到端测试
│ ├── integration/ # 集成测试
│ ├── unit/ # 单元测试
│ └── mocks/ # Mock 实现
├── migrations/ # 数据库迁移
├── docs/ # 文档
├── docker-compose.yml # Docker 编排
├── Makefile # 构建脚本
├── go.mod # Go 模块定义
└── go.sum # 依赖校验
```
## 3. 六边形架构 (Hexagonal Architecture)
每个服务采用六边形架构 (也称端口-适配器架构):
```
┌─────────────────────────────────────┐
│ Adapters (Input) │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ HTTP Handler│ │gRPC Handler │ │
│ └──────┬──────┘ └──────┬──────┘ │
└─────────┼────────────────┼─────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ Application Layer │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Ports │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Input Ports │ │ Output Ports │ │ Use Cases │ │ │
│ │ │ (Interfaces) │ │ (Interfaces) │ │ (Business) │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Domain Layer │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Entities │ │ Value Objects│ │ Services │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────┐
│ Adapters (Output) │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ PostgreSQL │ │ Redis │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────┘
```
### 3.1 层级职责
| 层级 | 职责 | 示例 |
|------|------|------|
| Domain | 业务规则和实体 | Account, Session, KeyShare |
| Application | 用例编排 | CreateAccount, Keygen |
| Adapters | 外部接口实现 | HTTP Handler, PostgreSQL Repo |
### 3.2 依赖规则
- 内层不依赖外层
- 依赖通过接口注入
- 领域层零外部依赖
## 4. 核心模块开发
### 4.1 TSS 模块 (pkg/tss)
TSS 模块封装了 bnb-chain/tss-lib提供简化的 API:
```go
// keygen.go - 密钥生成
type KeygenConfig struct {
Threshold int // t in t-of-n
TotalParties int // n
Timeout time.Duration
}
func NewKeygenSession(
config KeygenConfig,
selfParty KeygenParty,
allParties []KeygenParty,
msgHandler MessageHandler,
) (*KeygenSession, error)
func (s *KeygenSession) Start(ctx context.Context) (*KeygenResult, error)
```
```go
// signing.go - 签名
type SigningConfig struct {
Threshold int
TotalSigners int
Timeout time.Duration
}
func NewSigningSession(
config SigningConfig,
selfParty SigningParty,
allParties []SigningParty,
messageHash []byte,
saveDataBytes []byte,
msgHandler MessageHandler,
) (*SigningSession, error)
func (s *SigningSession) Start(ctx context.Context) (*SigningResult, error)
```
### 4.2 加密模块 (pkg/crypto)
```go
// encryption.go
type CryptoService interface {
Encrypt(plaintext []byte) ([]byte, error)
Decrypt(ciphertext []byte) ([]byte, error)
}
// AES-256-GCM 实现
type AESCryptoService struct {
masterKey []byte
}
func NewAESCryptoService(masterKeyHex string) (*AESCryptoService, error)
```
### 4.3 添加新用例
1. **定义端口接口**:
```go
// application/ports/inputs.go
type CreateSessionInput struct {
SessionType string
ThresholdN int
ThresholdT int
Participants []ParticipantInfo
}
type CreateSessionOutput struct {
SessionID uuid.UUID
JoinTokens map[string]string
}
```
2. **实现用例**:
```go
// application/use_cases/create_session.go
type CreateSessionUseCase struct {
sessionRepo repositories.SessionRepository
}
func (uc *CreateSessionUseCase) Execute(
ctx context.Context,
input ports.CreateSessionInput,
) (*ports.CreateSessionOutput, error) {
// 业务逻辑
session := entities.NewSession(input.ThresholdN, input.ThresholdT)
if err := uc.sessionRepo.Save(ctx, session); err != nil {
return nil, err
}
return &ports.CreateSessionOutput{
SessionID: session.ID,
}, nil
}
```
3. **添加 HTTP 处理器**:
```go
// adapters/input/http/handler.go
func (h *Handler) CreateSession(c *gin.Context) {
var req CreateSessionRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
output, err := h.createSessionUC.Execute(c.Request.Context(), ports.CreateSessionInput{
SessionType: req.SessionType,
ThresholdN: req.ThresholdN,
ThresholdT: req.ThresholdT,
})
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(201, output)
}
```
## 5. 构建和运行
### 5.1 Makefile 命令
```bash
# 查看所有命令
make help
# 开发
make fmt # 格式化代码
make lint # 运行 linter
make build # 构建所有服务
# 单独构建
make build-session-coordinator
make build-message-router
make build-server-party
make build-account
# 测试
make test # 运行所有测试
make test-unit # 单元测试
make test-integration # 集成测试
# Docker
make docker-build # 构建镜像
make docker-up # 启动服务
make docker-down # 停止服务
make docker-logs # 查看日志
# 本地运行单个服务
make run-coordinator
make run-router
make run-party
make run-account
```
### 5.2 环境变量
```bash
# 数据库
MPC_DATABASE_HOST=localhost
MPC_DATABASE_PORT=5432
MPC_DATABASE_USER=mpc_user
MPC_DATABASE_PASSWORD=mpc_password
MPC_DATABASE_DBNAME=mpc_system
MPC_DATABASE_SSLMODE=disable
# 服务端口
MPC_SERVER_GRPC_PORT=50051
MPC_SERVER_HTTP_PORT=8080
# 加密
MPC_CRYPTO_MASTER_KEY=0123456789abcdef...
# 服务发现
SESSION_COORDINATOR_ADDR=localhost:50051
MESSAGE_ROUTER_ADDR=localhost:50052
# Party 配置
PARTY_ID=server-party-1
```
### 5.3 本地开发
```bash
# 1. 启动基础设施
docker-compose up -d postgres redis rabbitmq consul
# 2. 运行数据库迁移
make db-migrate
# 3. 启动服务 (多个终端)
make run-coordinator # 终端 1
make run-router # 终端 2
make run-party # 终端 3
make run-account # 终端 4
```
## 6. 代码规范
### 6.1 命名规范
```go
// 包名: 小写单词
package sessioncoordinator
// 接口: 名词或动词+er
type SessionRepository interface { ... }
type MessageHandler interface { ... }
// 结构体: 驼峰命名
type CreateSessionUseCase struct { ... }
// 方法: 动词开头
func (uc *UseCase) Execute(ctx context.Context, input Input) (*Output, error)
// 常量: 大写+下划线
const MaxParticipants = 10
```
### 6.2 错误处理
```go
// 定义错误变量
var (
ErrSessionNotFound = errors.New("session not found")
ErrInvalidThreshold = errors.New("invalid threshold")
)
// 错误包装
if err != nil {
return fmt.Errorf("failed to create session: %w", err)
}
// 错误检查
if errors.Is(err, ErrSessionNotFound) {
// 处理特定错误
}
```
### 6.3 日志规范
```go
import "log/slog"
// 结构化日志
slog.Info("session created",
"session_id", session.ID,
"threshold", session.ThresholdT,
)
slog.Error("failed to save session",
"error", err,
"session_id", session.ID,
)
```
### 6.4 Context 使用
```go
// 始终传递 context
func (uc *UseCase) Execute(ctx context.Context, input Input) error {
// 检查取消
select {
case <-ctx.Done():
return ctx.Err()
default:
}
// 传递给下游
return uc.repo.Save(ctx, entity)
}
```
## 7. 调试技巧
### 7.1 日志级别
```bash
# 设置日志级别
export LOG_LEVEL=debug
# 或在代码中
slog.SetLogLoggerLevel(slog.LevelDebug)
```
### 7.2 gRPC 调试
```bash
# 安装 grpcurl
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
# 列出服务
grpcurl -plaintext localhost:50051 list
# 调用方法
grpcurl -plaintext -d '{"session_id":"xxx"}' \
localhost:50051 mpc.coordinator.v1.SessionCoordinator/GetSessionStatus
```
### 7.3 数据库调试
```bash
# 连接数据库
docker exec -it mpc-postgres psql -U mpc_user -d mpc_system
# 查看会话
SELECT * FROM sessions;
# 查看密钥分片
SELECT id, account_id, party_id, created_at FROM key_shares;
```
## 8. 常见问题
### Q1: go mod tidy 报错
```bash
# 清理缓存
go clean -modcache
go mod download
```
### Q2: Docker 网络问题
```bash
# 重建网络
docker-compose down -v
docker network prune
docker-compose up -d
```
### Q3: TSS 超时
- 检查所有参与方是否连接
- 增加 Timeout 配置
- 检查网络延迟
### Q4: 密钥加密失败
```bash
# 确保主密钥是 64 个十六进制字符
export MPC_CRYPTO_MASTER_KEY=$(openssl rand -hex 32)
```