YM 中心记账系统开发文档

版本:2.0  |  修订日期:2026-07-01  |  状态:正式发布


1. 引言

1.1 项目背景

传统中心化账务系统常将用户私钥托管于服务器,存在被攻击或内部作恶的风险。YM 系统采用区块链式去信任设计,私钥完全由客户端生成并保管,服务器仅存储公钥与交易账本,所有转账必须通过数字签名验证,确保资产安全与交易不可篡改。

1.2 项目目标

1.3 术语定义

术语解释
私钥 (Private Key)256 位随机数,用于签名交易,永不传输
公钥 (Public Key)由私钥通过椭圆曲线算法推导,可公开,用于验证签名
地址 (Address)公钥经 SHA‑256 和 RIPEMD‑160 双重哈希后的 40 位十六进制串
Nonce从 0 开始递增的序号,防止交易重放攻击
交易哈希 (TxHash)SHA256(from + to + amount + nonce) 计算得出
账本 (Ledger)所有交易记录的不可变集合
余额缓存 (Balance Cache)由账本实时维护的地址余额快照

2. 系统架构

2.1 整体架构图(概念层)

┌─────────────────────────────────────────────────────────────────┐
│                       钱包客户端(用户端)                       │
│  ┌─────────────┐  ┌─────────────┐  ┌───────────────────────┐  │
│  │ 生成私钥/公钥 │  │ 生成地址   │  │ 签名交易(离线)     │  │
│  └─────────────┘  └─────────────┘  └───────────────────────┘  │
│          │               │                     │                │
│          └───────────────┼─────────────────────┘                │
│                          │ HTTPS / JSON                         │
└──────────────────────────┼──────────────────────────────────────┘
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│                         服务器端(PHP 8.0)                     │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │                    API 网关 (路由)                        │  │
│  │  - /api/register   - /api/transfer                       │  │
│  │  - /api/transaction - /api/ledger                        │  │
│  │  - /api/wallets    - /api/transactions                   │  │
│  │  - /api/ping       - /api/frozen/{addr}                  │  │
│  │  - /api/exists/{hash}                                    │  │
│  └───────────────────────────────────────────────────────────┘  │
│                              │                                   │
│  ┌──────────────────────────▼──────────────────────────────┐   │
│  │                   业务逻辑层                             │   │
│  │  - 地址/公钥验证  - 签名验证  - Nonce 检查             │   │
│  │  - 余额查询/更新  - 交易写入  - 冻结状态检测           │   │
│  └──────────────────────────────────────────────────────────┘   │
│                              │                                   │
│  ┌──────────────────────────▼──────────────────────────────┐   │
│  │                   数据访问层                             │   │
│  │  - PDO 数据库连接  - 事务控制  - SQL 执行              │   │
│  └──────────────────────────────────────────────────────────┘   │
│                              │                                   │
│  ┌──────────────────────────▼──────────────────────────────┐   │
│  │               MySQL 数据库(5.7+)                       │   │
│  │  wallets | transactions | wallet_balance | admin_config │   │
│  └──────────────────────────────────────────────────────────┘   │
│                                                                   │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │              管理员后台(/admin/{admin_key}/)           │  │
│  │  登录认证  |  钱包列表  |  交易列表  |  增发  |  冻结   │  │
│  │  余额重建  |  登出                                      │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘
            

2.2 模块职责

模块职责
API 网关解析请求 URL,分发至对应处理函数,统一 JSON 输出
验证器地址格式、公钥匹配地址、签名有效性、Nonce 连续性、冻结状态
账本引擎插入交易记录,更新余额缓存,确保原子性
查询服务交易哈希/地址交易检索,钱包列表,余额查询
管理模块后台认证、代币增发(SYSTEM 交易)、冻结/解冻、余额重建
工具库椭圆曲线适配、哈希计算、地址生成、签名接口

3. 技术选型

层次技术版本原因
后端语言PHP8.0+性能优异(JIT)、成熟生态、完美支持 OpenSSL 及 PDO
数据库MySQL5.7+稳定、支持事务与行锁,满足并发转账需求
加密算法ECDSA (secp256k1 / prime256v1)-公钥/私钥体系,secp256k1 为比特币标准
哈希算法SHA‑256, RIPEMD‑160-用于地址生成与交易哈希
通信协议HTTPS / RESTful JSON-简单、跨平台
会话管理PHP 内置 Session-轻量级
密码存储bcrypt (password_hash)-抗暴力破解

4. 数据库设计

4.1 实体关系(逻辑描述)

4.2 表结构明细

wallets(钱包主表)

CREATE TABLE `wallets` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `address` varchar(40) NOT NULL UNIQUE COMMENT '40位十六进制地址',
  `public_key` text NOT NULL COMMENT 'PEM格式公钥',
  `last_nonce` int(11) NOT NULL DEFAULT -1 COMMENT '已使用最大nonce',
  `frozen` tinyint(1) NOT NULL DEFAULT 0 COMMENT '0正常 1冻结',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `address` (`address`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

transactions(交易账本)

CREATE TABLE `transactions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `tx_hash` varchar(64) NOT NULL UNIQUE COMMENT 'SHA256哈希',
  `from_address` varchar(40) NOT NULL COMMENT '付款方,SYSTEM表示增发',
  `to_address` varchar(40) NOT NULL,
  `amount` decimal(20,8) NOT NULL,
  `nonce` int(11) NOT NULL COMMENT '付款方的nonce',
  `signature` text NOT NULL COMMENT 'Base64签名(增发为空)',
  `public_key` text NOT NULL COMMENT 'PEM公钥(增发为空)',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `tx_hash` (`tx_hash`),
  KEY `from_address` (`from_address`),
  KEY `to_address` (`to_address`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

wallet_balance(余额缓存)

CREATE TABLE `wallet_balance` (
  `address` varchar(40) NOT NULL PRIMARY KEY,
  `balance` decimal(20,8) NOT NULL DEFAULT 0,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

admin_config(管理员配置)

CREATE TABLE `admin_config` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `admin_key` varchar(50) NOT NULL COMMENT '后台URL后缀',
  `password_hash` varchar(255) NOT NULL,
  `ip_whitelist` text COMMENT '逗号分隔IP,空则允许所有',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

4.3 索引优化建议

5. API 接口规范

5.1 通用约定

5.2 接口列表

5.2.1 钱包备案 POST /register

请求体

{
  "address": "a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4",
  "public_key": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC...\n-----END PUBLIC KEY-----"
}

响应(成功)

{ "success": true, "address": "a1b2c3d4..." }

可能的错误

5.2.2 发起转账 POST /transfer

请求体

{
  "from": "付款方地址",
  "to": "收款方地址",
  "amount": 10.5,
  "nonce": 0,
  "signature": "MEUCIQD...",
  "public_key": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
}

响应(成功)

{ "success": true, "tx_hash": "abc123..." }

错误(部分)

5.2.3 查询交易详情 GET /transaction/{tx_hash}

返回完整交易记录(若无则返回 404)。

5.2.4 查询账本 GET /ledger?address={addr}?tx_hash={hash}

5.2.5 获取所有钱包 GET /wallets

[
  {"address":"...", "balance":"100.00000000", "frozen":0},
  ...
]

5.2.6 获取所有交易(分页)GET /transactions?page=1&limit=100

默认 page=1, limit=100。

5.2.7 服务器心跳 GET /ping

响应{"status":"ok"}

5.2.8 检查冻结状态 GET /frozen/{address}

响应{"frozen": true|false}

5.2.9 检查交易是否存在 GET /exists/{tx_hash}

响应{"exists": true|false}

6. 管理员后台

6.1 首次配置

访问 /admin/,系统自动检测 admin_config 表是否为空。若为空,显示配置表单,要求填写:

提交后,密码经 bcrypt 哈希保存,Admin Key 明文保存(建议保密)。

6.2 登录与认证

后续访问 /admin/{admin_key}/ 会要求输入密码,验证通过后建立 Session。同时检查请求 IP 是否在白名单内(若设置),否则返回 403。

6.3 后台功能菜单

功能说明
钱包列表展示所有地址、余额、冻结状态
交易列表显示最近 200 笔交易,可按时间排序
增发 YM 币表单输入目标地址和金额,生成 from='SYSTEM' 的交易
冻结/解冻输入地址,选择操作,更新 wallets.frozen
重建余额清空 wallet_balance,根据 transactions 全量重算并插入
登出销毁 Session,返回登录页

7. 核心业务流程

7.1 地址生成与备案(客户端主导)

  1. 客户端:生成 256 位随机数作为私钥。
  2. 客户端:使用 secp256k1 曲线通过私钥推导公钥(PEM 格式)。
  3. 客户端:对公钥 DER 编码进行 SHA‑256,再 RIPEMD‑160,得到 20 字节 → 转 40 位十六进制地址。
  4. 客户端:调用 /api/register{address, public_key} 发送至服务器。
  5. 服务器:验证地址格式、公钥与地址匹配性,若通过则存入 wallets 表,并初始化余额缓存(余额为 0)。
  6. 服务器:返回成功。

7.2 转账交易(客户端与服务器交互)

客户端 → 客户端:查询本地 last_nonce
客户端 → 客户端:构造数据 from+to+amount+nonce
客户端 → 客户端:用私钥签名得到 signature
客户端 → 服务器:POST /api/transfer (from,to,amount,nonce,signature,public_key)
服务器 → 服务器:验证公钥推导地址 == from
服务器 → 服务器:检查 from 已注册、未冻结
服务器 → 服务器:检查 nonce == last_nonce+1
服务器 → 服务器:查询余额缓存,判断 >= amount
服务器 → 服务器:用公钥验证签名
服务器 → 服务器:检查 to 是否已注册
服务器 → 服务器:计算 tx_hash 并检查唯一性
服务器 → 服务器:事务开始:插入 transactions,更新 from/to 余额缓存,更新 wallets.last_nonce
服务器 → 客户端:返回 tx_hash
            

7.3 余额缓存重建

  1. 管理员触发(后台操作)或脚本调用。
  2. 服务器:执行 TRUNCATE wallet_balance
  3. 服务器:按 id ASC 顺序读取所有交易记录。
  4. 对每条交易:
    • from_address != 'SYSTEM',则对应地址余额 减去 amount;
    • to_address != 'SYSTEM',则对应地址余额 加上 amount。
  5. 使用 INSERT ... ON DUPLICATE KEY UPDATE 将最终余额写入 wallet_balance
  6. 建议低峰期操作。

8. 安全机制

9. 部署指南

9.1 环境准备

9.2 安装步骤

  1. 下载代码:将项目文件(config.php, functions.php, index.php)放置于网站根目录。
  2. 修改配置:编辑 config.php,填写正确的数据库连接信息。
  3. 创建数据库:执行 SQL 脚本创建库及表。
  4. 设置 URL 重写:
    • Apache:在根目录创建 .htaccess,内容见文档。
    • Nginx:在站点配置中添加 try_files $uri $uri/ /index.php?$args;
  5. 权限设置:确保 session.save_path 目录可写。
  6. 访问配置:浏览器访问 https://yourdomain/admin/ 进行首次配置。
  7. 测试接口:使用 curl 测试 /api/ping

9.3 性能调优

10. 测试指南

10.1 单元测试

测试类覆盖功能
AddressTest地址生成、格式验证、公钥匹配
SignatureTest签名与验证流程
BalanceTest余额计算与缓存更新
TransactionTest转账完整流程、错误场景

10.2 集成测试

场景预期结果
注册新钱包成功,数据库中新增记录
重复注册返回错误
转账到未注册地址返回错误(若强制要求)
转账金额超过余额返回余额不足
转账 nonce 错误返回 nonce 错误
转账签名错误返回签名无效
增发代币目标地址余额增加,交易记录生成
冻结地址该地址无法发起转账
查询账本返回正确的交易列表
重建余额所有地址余额与账本计算一致

10.3 压力测试

使用 Apache Bench 或 JMeter 模拟并发转账,验证事务锁和数据库性能。

11. 扩展性考虑

12. 附录

12.1 错误码速查

错误码含义
1001地址格式无效
1002公钥不匹配地址
1003地址已存在
2001非法的 nonce
2002余额不足
2003无效签名
2004交易哈希重复
2005地址被冻结
3001目标地址未注册
4001管理员密码错误
4002IP 不在白名单

12.2 椭圆曲线参数说明

12.3 常见问题(FAQ)

Q:如何获取当前地址的 nonce?
A:目前设计由客户端本地维护,服务器在 wallets 表中记录 last_nonce,可添加接口 /api/nonce/{address} 返回。
Q:增发交易是否需要签名?
A:不需要,增发由管理员后台操作,信任管理员身份。
Q:如果余额缓存损坏,如何处理?
A:使用后台“重建余额”功能,系统会根据交易表全量重新计算。
Q:是否支持跨链资产?
A:当前为单一 YM 代币,扩展多币种需修改数据库与逻辑。

— 文档结束 —

↑ 返回顶部