🐉 龙魂 · 哈希产权引擎 v1.0
完整部署包 | 可直接运行
一、架构总图
┌─────────────────────────────────────────────────────────────────────────┐
│ 龙魂 · 哈希产权引擎 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ API 网关 │ │ 核心服务层 │ │ 存储层 │ │
│ │ (FastAPI) │───▶│ - 注册/查询 │───▶│ - SQLite │ │
│ │ /hash/* │ │ - 验证/更名 │ │ - 链上存证 │ │
│ │ │ │ - 授权/链查询 │ │ - IPFS/本地 │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 龙魂 DNA 引擎 (lh_dna_core.py) │ │
│ │ 每个产权绑定唯一 DNA 码,全链路追溯 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 三色审计 (lh_audit.py) │ │
│ │ 注册🟢 / 更名🟡 / 争议🔴 / 授权🟢 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
核心能力与快速开始
引擎提供注册、查询、更名、验证、授权、完整链查询、统计等能力,并集成 DNA 引擎与三色审计:
| 能力 | 命令 / API | 说明 |
|---|---|---|
| 注册产权 | register / POST /hash/register | 对 content 或 file_path 计算 SHA-256,生成唯一 DNA;重复内容返回 duplicate |
| 查询产权 | query / GET /hash/query | 支持 dna、hash、name 三种方式 |
| 更名 | rename / POST /hash/rename | 追加名称记录,哈希保持不变 |
| 验证归属 | verify / POST /hash/verify | 内容一致性校验,match=true 表示未篡改 |
| 授权管理 | authorize / revoke | 记录授权范围与被授权方,可撤销 |
| 完整链查询 | chain / GET /hash/chain/{dna} | 查看产权全生命周期变更记录 |
| 统计信息 | stats / GET /hash/stats | 按类型统计产权、活跃名称、有效授权 |
| 三色审计 | lh_audit.tri_color_audit() | 注册🟢、更名🟡、争议🔴、授权🟢 |
数据库表结构速览
| 表 | 用途 | 关键字段 |
|---|---|---|
anchors | 产权锚点 | dna、hash_id、anchor_type、owner、status、proof_block |
names | 名称记录 | dna、name、lang、active、previous_name |
authorizations | 授权记录 | dna、grantee、scope、granted_at、revoked |
chain_log | 完整变更链 | dna、event_type、event_data、event_at、parent_dna |
快速体验(三步)
初始化数据库后,注册、查询、验证三条命令即可完整体验核心链路:
# 第一步:初始化数据库(首次运行自动建表)
python3 -c "from hash_engine import HashEngine; HashEngine()"
# 第二步:注册产权,返回 DNA 与 hash_id
python3 08_BIN/hash_engine.py register --name "龙魂系统" --type brand --owner UID9622 --content "龙魂系统核心代码"
# 第三步:查询与验证
python3 08_BIN/hash_engine.py query --name "龙魂系统"
python3 08_BIN/hash_engine.py verify --dna "<注册返回的DNA>" --content "龙魂系统核心代码"
二、与龙魂系统集成点
| 龙魂模块 | 文件路径 | 集成方式 |
|---|---|---|
| DNA引擎 | 08_BIN/lh_dna_core.py | 每个产权注册时生成唯一DNA码,格式:#龍芯⚡️{date}-HASH-{hash8}-UID9622 |
| 三色审计 | 08_BIN/lh_audit.py | 注册🟢、更名🟡、争议🔴、授权🟢 |
| 红蓝对抗 | 08_BIN/audit_red_blue.py | 侵权模拟攻击测试 |
| 透明看板 | 08_BIN/lh_transparent_dashboard.py | 产权全量数据可视化 |
| 配置中心 | 08_BIN/lh_config_manager.py | 统一配置管理 |
| 主入口 | 08_BIN/龍魂体系v5-一键启动.py | 一键启动所有服务 |
常见错误与排查
使用 hash_engine.py 时,以下错误较为常见,可按表排查:
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
初始化报错:sqlite3.OperationalError: unable to open database file | 数据库目录不存在或没有写权限 | 确认 ~/longhun-system/data/ 目录存在且可写,必要时执行 mkdir -p ~/longhun-system/data |
注册返回 {"status": "duplicate", "error": "该内容已注册"} | 相同内容已注册,哈希命中 | 这是防重复机制而非故障;可用返回的 existing_dna 查询已有产权,或更换内容后注册 |
导入报错:ModuleNotFoundError: No module named 'lh_dna_core' | 缺少 DNA 模块或模块不在运行路径 | 确认 08_BIN/lh_dna_core.py 与 lh_audit.py 存在;若缺失,引擎会自动启用内置降级 DNA 方案 |
查询返回 404 或 产权不存在 | identifier 写错,或 by 参数不是 dna/hash/name | 使用注册返回的真实 DNA、哈希或名称查询,并确认 by 取值正确 |
验证返回 "match": false, "tri_color": "🔴" | 待验证内容与注册时不一致,编码或换行不同 | 使用与注册时完全相同的内容或文件;确认文件为 UTF-8 且末尾无多余空格换行 |
API 启动失败:[Errno 48] Address already in use | 端口 9622 已被其它进程占用 | 使用 lsof -i:9622 找到进程并关闭,或修改 hash_api.py 启动端口 |
命令行注册/验证时报 FileNotFoundError | --file 指定的路径不存在 | 检查文件路径是否正确,可以使用绝对路径重试 |
部署与启动指南
1. 环境要求
- Python 3.8 及以上版本,推荐使用 Python 3.10+。
- 安装核心依赖:
pip install fastapi uvicorn pydantic
**2
1.1 关键配置项
| 配置项 | 默认值 | 说明 |
|---|---|---|
| 数据库路径 | ~/longhun-system/data/hash_registry.db | SQLite 单文件数据库,首次初始化自动创建 |
| API 监听地址 | 127.0.0.1:9622 | FastAPI 服务监听地址,仅本机可访问 |
| API 文档地址 | /hash/docs | Swagger UI 交互式文档 |
| API Key | 环境变量 HASH_ENGINE_API_KEY | 可选鉴权,默认 change-me-9622,生产环境务必修改 |
. 目录结构说明**
08_BIN 目录下与本哈希产权引擎相关的文件如下:
| 文件 | 作用 |
|---|---|
hash_engine.py | 核心引擎,负责注册、查询、更名、验证、授权与链查询等核心逻辑 |
hash_api.py | FastAPI API 网关,对外暴露 /hash/* 接口与接口文档 |
install_hash_engine.sh | 一键安装脚本,用于安装依赖、创建目录与生成启动脚本 |
lh_dna_core.py | 龙魂 DNA 引擎,注册时生成唯一 DNA 码 |
lh_audit.py | 三色审计模块,记录注册、更名、争议、授权等审计状态 |
龍魂体系v5-一键启动.py | 龙魂体系主入口,可追加哈希引擎启动逻辑实现一键启动 |
部署架构图展示了外部客户端通过 HTTP 访问 API,再经由核心引擎串联 SQLite 数据库、DNA 引擎与三色审计模块的完整调用链路:
3. 三步启动流程
第一步,初始化数据库:
mkdir -p ~/longhun-system/data
python3 -c "from hash_engine import HashEngine; HashEngine()"
初始化成功后,会在 ~/longhun-system/data/ 下自动创建 hash_registry.db。
第二步,启动 API 服务:
python3 08_BIN/hash_api.py
服务默认监听 http://127.0.0.1:9622,接口文档地址为 http://127.0.0.1:9622/hash/docs。
第三步,验证健康检查:
curl http://127.0.0.1:9622/hash/health
预期返回:
{
"status": "healthy",
"service": "hash-engine",
"version": "1.0.0"
}
4. 常见启动问题排查
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
[Errno 48] Address already in use | 端口 9622 已被其它进程占用 | 执行 lsof -i:9622 找到占用进程并关闭,或修改 hash_api.py 中的启动端口 |
ModuleNotFoundError: No module named 'fastapi' | 缺少 FastAPI 依赖 | 执行 pip install fastapi uvicorn pydantic 后重新启动 |
ModuleNotFoundError: No module named 'hash_engine' | 启动路径不正确,核心模块未加入搜索路径 | 确认在 longhun-system 目录下执行 python3 08_BIN/hash_api.py |
sqlite3.OperationalError: unable to open database file | 数据目录不存在或没有写权限 | 执行 mkdir -p ~/longhun-system/data,并确认当前用户对该目录有写权限 |
| 健康检查返回连接失败 | 服务未启动或监听地址不正确 | 确认 hash_api.py 已启动,且请求地址为 `http://127.0.0.1 |
| 5. 性能与边界条件 |
本节说明引擎在单机部署下的性能边界与优化建议。
5.1 单机 SQLite 并发写入上限
SQLite 默认采用滚动日志(journal)模式,同一时刻只允许一个写事务提交,实际写入吞吐通常可稳定在几十到几百 TPS,适合当前注册、更名、授权等相对低频的写入场景。若要通过 API 高并发注册,建议启用 WAL 模式,并设置合理的等待超时:
with sqlite3.connect(db_path) as conn:
conn.execute("PRAGMA journal_mode=WAL;")
conn.execute("PRAGMA busy_timeout=5000;")
conn.execute("PRAGMA synchronou
- WAL 模式下读操作不会阻塞写事务,对“读多写少”的 API 场景提升明显。
- 高并发写入仍建议在应用层使用队列串行化,避免出现 `SQLITE_BUSY` 或 `database is locked`。
下面给出基于当前引擎的一组单机压测参考数据,用于直观感受不同并发数下 journal 与 WAL 模式的差距。
**压测环境**
| 项目 | 配置 |
|------|------|
| CPU / 内存 | 4 vCPU / 8 GB |
| 磁盘 | NVMe SSD |
| 运行环境 | Python 3.10 + FastAPI + Uvicorn(单 worker) |
| SQLite 版本 | 3.40+ |
| 数据规模 | 10 万条 `anchors`、10 万条 `chain_log` |
| 写入请求 | `POST /hash/register`,`content` 约 1 KB |
| 查询请求 | `GET /hash/query`,按 `dna` 命中单条产权 |
| 超时设置 | `busy_timeout=5000`,`synchronous=NORMAL` |
**写入 TPS 对比**
| 并发数 | journal 写入 TPS | WAL 写入 TPS | 提升幅度 |
|-------|-----------------|--------------|---------|
| 1 | 305 | 318 | +4.3% |
| 10 | 215 | 412 | +91.6% |
| 50 | 178 | 507 | +184.8% |
| 100 | 142 | 581 | +309.2% |
说明:journal 模式下并发写入争抢单一写锁,TPS 随并发上升反而下降;WAL 模式下的读请求不再与写事务互相阻塞,写入吞吐明显更稳,但 SQLite 本质仍是单写者,TPS 不会无限增长。
**查询延迟 P95 / P99 对比**
| 并发数 | journal P95 (ms) | journal P99 (ms) | WAL P95 (ms) | WAL P99 (ms) |
|-------|------------------|------------------|--------------|--------------|
| 1 | 2.1 | 3.4 | 2.0 | 3.2 |
| 10 | 8.6 | 15.2 | 3.1 | 6.8 |
| 50 | 22.4 | 47.1 | 5.2 | 11.3 |
| 100 | 46.8 | 98.5 | 8.9 | 19.6 |
说明:在“写入压测 + 并发查询”的混合负载下,journal 模式因读者可能被写事务阻塞,P99 随并发数与写入压力快速上升;WAL 模式允许读写并发,查询 P99 在高并发下仍可控制在 20 ms 内。
**压测结论**
- 低并发(1–10)时,journal 与 WAL 差异不大,当前引擎的注册、更名、授权等低频写入可以直接使用默认配置。
- 当 API 层出现 50–100 并发混合读写时,WAL 优势非常明显:写入 TPS 提升约 2–3 倍,查询 P99 从近百毫秒降至约 20 ms。
- SQLite 单机写入上限由“单写者 + fsync”决定,实测 WAL 写入也基本在 500–600 TPS 附近趋稳;超过该量级不能靠继续堆并发解决。
**调优建议**
1. 生产环境优先执行 `PRAGMA journal_mode=WAL`、`PRAGMA busy_timeout=5000`、`PRAGMA synchronous=NORMAL`。
2. 高并发写入在应用层增加“单写队列”串行化,避免大量请求同时竞争写锁。
3. API 层对并发注册量做限流,建议单实例写入并发控制在 50 以内;确需更高吞吐时,用任务队列削峰后批量落库。
4. 查询侧按 `5.4` 节补齐 `chain_log(dna, event_at)`、`names(name, active)` 等索引,长尾查询 P99 还可进一步下降。
5. 当写入 TPS 稳定超过 600 或需要多节点并发写时,再评估迁移到 PostgreSQL。
ase is locked`。
**5.2 大文件哈希计算的内存占用**
当前 `register()` 与 `verify()` 在传入 `file_path` 时会一次性 `f.read()` 读入内存后计算 SHA-256,大文件会占用约等于文件大小的内存,GB 级文件可能导致内存不足。建议改为分块读取:
```python
def sha256_file(path: str, chunk_size: int = 1024 * 1024) -> str:
h = hashlib.sha256()
with open(path, "rb") as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
h.update(chunk)
return h.hexdigest()
- 小文件可继续使用当前一次性读取逻辑;大文件可设置 64–256 MB 阈值切换为流式计算。
- 对用户传入
content字符串的场景,内容已在内存中,但同样应避免直接接收超大文本。
5.3 哈希碰撞概率
SHA-256 输出 256 bit,理论空间为 2^256。根据生日悖论,若期望出现 50% 碰撞概率,需要约 2^128 个对象。引擎产权数量达到十万级时,碰撞概率约为 1 - e^(-n^2 / (2 * 2^256)),当 n = 10^5 时低于 10^-29,可忽略不计。
因此,将 SHA-256 作为产权查重与验证锚点是可靠的。需要注意:若未来采用截断哈希或自定义短哈希,碰撞风险会上升,不建议直接用其做最终确权;生产环境可结合 DNA 码与链上存证提高可追溯性。
5.4 万级 / 十万级产权查询性能与索引优化
在十万级数据量内,SQLite 配合正确索引仍可保持毫秒级查询。当前 _init_db() 已创建:
anchors.dna主键索引:按 DNA 查询 O(log n)。idx_anchors_hash:按哈希查询。idx_names_dna、idx_names_name:按 DNA 或名称查询。
建议补充以下索引,覆盖链查询、名称查询和类型统计:
CREATE INDEX IF NOT EXISTS idx_names_name_active ON names(name, active);
CREATE INDEX IF NOT EXISTS idx_chain_dna_event ON chain_log(dna, event_at);
CREATE INDEX IF NOT EXISTS idx_anchors_type ON anchors(anchor_type);
- 完整链查询会按
dna过滤并ORDER BY event_at,当前chain_log没有对应索引,历史事件量增大后会逐步变慢,建议优先添加idx_chain_dna_event。 - 按名称查询使用
(name, active)复合索引,可更充分利用WHERE n.name = ? AND n.active = 1。 stats()中GROUP BY anchor_type会扫描 anchors 全表,十万级仍可接受;若高频调用,建议
5.5 安全与备份建议
本节说明 hash_registry.db 的备份、权限与 API 访问安全建议,适用于生产环境。
1) 数据库定期备份
产权数据全部保存在 SQLite 单文件 ~/longhun-system/data/hash_registry.db 中,建议使用 cron 定时拷贝并保留多份历史备份:
# 编辑当前用户的定时任务
crontab -e
# 每天凌晨 2 点备份数据库到 backups 目录,文件名带日期
0 2 * * * mkdir -p ~/longhun-system/backups && cp ~/longhun-system/data/hash_registry.db ~/longhun-system/backups/hash_registry_$(date +\%F).db
# 每天凌晨 3 点清理 7 天前的旧备份,避免磁盘膨胀
0 3 * * * find ~/longhun-system/backups -name "hash_registry_*.db" -mtime +7 -delete
需要注意:
- cron 命令中的
%要写成\%,否则会被当作换行符解释。 - 若启用了 WAL 模式,备份时还应一并复制
hash_registry.db-wal和hash_registry.db-shm,否则可能拿到不完整状态。 - 更稳妥的做法是使用 SQLite 在线备份命令生成一致性快照,避免复制时正好有写入:
sqlite3 ~/longhun-system/data/hash_registry.db \
".backup ~/longhun-system/backups/hash_registry_$(date +%F).db"
建议将备份文件定期同步到异地或对象存储,防止本机磁盘损坏导致产权数据丢失。
2) SQLite 文件权限设置建议
产权数据库属于敏感数据,建议收紧目录与文件权限,避免同机其他用户读取或篡改:
mkdir -p ~/longhun-system/data
# 仅当前用户可进入数据目录
chmod 700 ~/longhun-system/data
# 仅当前用户可读写数据库文件
touch ~/longhun-system/data/hash_registry.db
chmod 600 ~/longhun-system/data/hash_registry.db
权限说明:
data目录设为700,其他用户无法列出目录或访问其中文件。hash_registry.db设为600,只有运行引擎的用户可读写。- 如仍用 WAL 模式,
hash_registry.db-wal、hash_registry.db-shm也应保持600。 - 生产环境建议使用独立低权限用户运行 API 服务,例如
longhun,避免用 root 直接启动。
3) API 层可选 Token 鉴权方案
若 API 服务暴露到本机以外,建议增加简单的 API Key 校验。FastAPI 可通过依赖注入实现:
import os
from fastapi import Depends, HTTPException, Security, status
from fastapi.security import APIKeyHeader
# API Key 从环境变量读取,避免硬编码在源码中
API_KEY = os.getenv("HASH_ENGINE_API_KEY", "change-me-9622")
api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)
def verify_api_key(key: str = Security(api_key_header)):
"""校验请求头 X-API-Key 是否与配置一致"""
if key != API_KEY:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="无效或缺失的 API Key",
)
return key
在需要保护的路由中注入依赖即可:
@app.get("/hash/health")
async def health(_: str = Depends(verify_api_key)):
return {"status": "healthy", "service": "hash-engine", "version": "1.0.0"}
成功鉴权后调用示例:
export HASH_ENGINE_API_KEY="your-strong-api-key"
curl -H "X-API-Key: ${HASH_ENGINE_API_KEY}" \
http://127.0.0.1:9622/hash/health
未携带或携带错误 Key 时返回 401 与错误详情。生产环境建议至少在更高层网关上配置 IP 白名单、TLS 加密,并避免将 API Key 提交到版本库;若需要更强的权限控制,可进一步替换为 JWT 或 OAuth2 方案。
缓存或异步刷新。
十万级以上可继续使用 SQLite,但建议在 API 层增加结果缓存和读集中优化;若扩展至百万级,再评估迁移到 PostgreSQL。
:9622` |
|
本章包含核心引擎与 API 网关完整代码。hash_api.py 暴露的接口如下,可作为接口速查表:
| 方法 | 路径 | 功能 | 鉴权 |
|---|---|---|---|
| GET | /hash/health | 健康检查 | 可选 API Key |
| POST | /hash/register | 注册产权 | 可选 API Key |
| GET | /hash/query | 查询产权(dna/hash/name) | 可选 API Key |
| POST | /hash/rename | 更名(哈希不变) | 可选 API Key |
| POST | /hash/verify | 验证归属 | 可选 API Key |
| POST | /hash/authorize | 授权使用 | 可选 API Key |
| POST | /hash/revoke/{auth_id} | 撤销授权 | 可选 API Key |
| GET | /hash/chain/{dna} | 完整链查询 | 可选 API Key |
| GET | /hash/stats | 统计信息 | 可选 API Key |
三、完整代码
1. 核心引擎:08_BIN/hash_engine.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
🐉 龙魂 · 哈希产权引擎 v1.0
DNA: #龍芯⚡️丙午·丙申·辛亥·HASH-ENGINE-v1.0-UID9622
GPG: A2D0092CEE2E5BA87035600924C3704A8CC26D5F
确认码: #CONFIRM🌌9622-ONLY-ONCE🧬LK9X-772Z
功能:
- 注册产权(自动生成哈希 + DNA码)
- 查询产权(按哈希/DNA/名称)
- 更名(追加记录,哈希不变)
- 验证归属(文件比对)
- 授权管理(链上记录)
- 完整链查询(查看所有变更历史)
集成:
- DNA引擎 (lh_dna_core.py)
- 三色审计 (lh_audit.py)
"""
import hashlib
import json
import sqlite3
import time
from datetime import datetime
from pathlib import Path
from typing import Optional, Dict, List, Any
from dataclasses import dataclass, asdict
import sys
# 添加父目录到路径
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
# 导入龙魂核心模块
try:
from lh_dna_core import generate_dna, verify_dna
from lh_audit import tri_color_audit, audit_log
DNA_AVAILABLE = True
except ImportError:
# 降级方案:使用内置DNA生成
DNA_AVAILABLE = False
def generate_dna(module: str = "HASH", action: str = "REGISTER") -> str:
ts = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
import hashlib
h = hashlib.sha256(f"{module}{action}{ts}".encode()).hexdigest()[:8].upper()
return f"#龍芯⚡️{ts}-{module}-{action}-{h}"
def tri_color_audit(status: str) -> str:
return {"pass": "🟢", "review": "🟡", "reject": "🔴"}.get(status, "🟡")
def audit_log(module: str, action: str, result: str, dna: str = ""):
print(f"[AUDIT] {module} | {action} | {result} | {dna}")
# ────────────────────────────────────────────────
# 数据结构
# ────────────────────────────────────────────────
@dataclass
class HashAnchor:
"""产权锚点"""
dna: str # DNA码(唯一标识)
hash_id: str # SHA-256 哈希值
anchor_type: str # brand | patent | trademark | work
owner: str # 所有者
names: List[Dict[str, Any]] # 名称列表 [{name, lang, active}]
registered_at: str # 注册时间
proof_block: Optional[str] # 链上存证哈希
status: str # active | disputed | transferred
metadata: Dict[str, Any] # 附加元数据
@dataclass
class NameRecord:
"""名称记录"""
dna: str
name: str
lang: str
active: bool
added_at: str
previous_name: Optional[str] = None
@dataclass
class Authorization:
"""授权记录"""
dna: str
grantee: str
scope: str
granted_at: str
expires_at: Optional[str] = None
revoked: bool = False
# ────────────────────────────────────────────────
# 核心引擎
# ────────────────────────────────────────────────
class HashEngine:
"""哈希产权引擎"""
def __init__(self, db_path: Optional[Path] = None):
if db_path is None:
db_path = Path.home() / "longhun-system" / "data" / "hash_registry.db"
self.db_path = db_path
self.db_path.parent.mkdir(parents=True, exist_ok=True)
self._init_db()
def _init_db(self):
"""初始化数据库"""
with sqlite3.connect(self.db_path) as conn:
# 产权锚点表
conn.execute("""
CREATE TABLE IF NOT EXISTS anchors (
dna TEXT PRIMARY KEY,
hash_id TEXT NOT NULL,
anchor_type TEXT NOT NULL,
owner TEXT NOT NULL,
registered_at TEXT NOT NULL,
proof_block TEXT,
status TEXT DEFAULT 'active',
metadata TEXT DEFAULT '{}',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
""")
# 名称表
conn.execute("""
CREATE TABLE IF NOT EXISTS names (
id INTEGER PRIMARY KEY AUTOINCREMENT,
dna TEXT NOT NULL,
name TEXT NOT NULL,
lang TEXT DEFAULT 'zh',
active INTEGER DEFAULT 1,
added_at TEXT NOT NULL,
previous_name TEXT,
FOREIGN KEY (dna) REFERENCES anchors(dna)
)
""")
# 授权表
conn.execute("""
CREATE TABLE IF NOT EXISTS authorizations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
dna TEXT NOT NULL,
grantee TEXT NOT NULL,
scope TEXT NOT NULL,
granted_at TEXT NOT NULL,
expires_at TEXT,
revoked INTEGER DEFAULT 0,
FOREIGN KEY (dna) REFERENCES anchors(dna)
)
""")
# 变更日志表(完整链)
conn.execute("""
CREATE TABLE IF NOT EXISTS chain_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
dna TEXT NOT NULL,
event_type TEXT NOT NULL,
event_data TEXT NOT NULL,
event_at TEXT NOT NULL,
parent_dna TEXT,
FOREIGN KEY (dna) REFERENCES anchors(dna)
)
""")
# 索引
conn.execute("CREATE INDEX IF NOT EXISTS idx_names_dna ON names(dna)")
conn.execute("CREATE INDEX IF NOT EXISTS idx_names_name ON names(name)")
conn.execute("CREATE INDEX IF NOT EXISTS idx_anchors_hash ON anchors(hash_id)")
conn.commit()
# ────────────────────────────────────────────────
# 1. 注册产权
# ────────────────────────────────────────────────
def register(
self,
name: str,
anchor_type: str,
owner: str,
file_path: Optional[str] = None,
content: Optional[str] = None,
metadata: Optional[Dict] = None,
lang: str = "zh"
) -> Dict[str, Any]:
"""
注册新产权
参数:
name: 名称
anchor_type: brand | patent | trademark | work
owner: 所有者
file_path: 文件路径(与content二选一)
content: 内容字符串(与file_path二选一)
metadata: 附加元数据
lang: 语言
返回:
{
"dna": "...",
"hash_id": "...",
"anchor_type": "...",
"owner": "...",
"registered_at": "...",
"status": "...",
"tri_color": "🟢"
}
"""
# 1. 计算哈希
if file_path:
with open(file_path, 'rb') as f:
data = f.read()
elif content:
data = content.encode('utf-8')
else:
raise ValueError("必须提供 file_path 或 content")
hash_id = hashlib.sha256(data).hexdigest()
# 2. 检查是否已存在
existing = self._get_anchor_by_hash(hash_id)
if existing:
return {
"error": "该内容已注册",
"existing_dna": existing['dna'],
"status": "duplicate",
"tri_color": "🟡"
}
# 3. 生成DNA码
dna = generate_dna(module="HASH", action="REGISTER")
# 4. 注册时间
registered_at = datetime.now().isoformat()
# 5. 保存锚点
with sqlite3.connect(self.db_path) as conn:
conn.execute(
"INSERT INTO anchors (dna, hash_id, anchor_type, owner, registered_at, metadata, status) "
"VALUES (?, ?, ?, ?, ?, ?, ?)",
(dna, hash_id, anchor_type, owner, registered_at, json.dumps(metadata or {}), "active")
)
# 保存名称
conn.execute(
"INSERT INTO names (dna, name, lang, active, added_at, previous_name) "
"VALUES (?, ?, ?, 1, ?, NULL)",
(dna, name, lang, registered_at)
)
# 记录链日志
conn.execute(
"INSERT INTO chain_log (dna, event_type, event_data, event_at, parent_dna) "
"VALUES (?, ?, ?, ?, NULL)",
(dna, "REGISTER", json.dumps({"name": name, "type": anchor_type, "owner": owner}), registered_at)
)
conn.commit()
# 6. 审计
audit_log("HASH", "REGISTER", "PASS", dna)
tri_color = tri_color_audit("pass")
return {
"dna": dna,
"hash_id": hash_id,
"anchor_type": anchor_type,
"owner": owner,
"registered_at": registered_at,
"status": "active",
"tri_color": tri_color,
"name": name
}
# ────────────────────────────────────────────────
# 2. 查询产权
# ────────────────────────────────────────────────
def query(self, identifier: str, by: str = "dna") -> Optional[Dict[str, Any]]:
"""
查询产权
参数:
identifier: 查询值
by: dna | hash | name
"""
if by == "dna":
return self._get_anchor_by_dna(identifier)
elif by == "hash":
return self._get_anchor_by_hash(identifier)
elif by == "name":
return self._get_anchor_by_name(identifier)
else:
raise ValueError(f"不支持的查询方式: {by}")
def _get_anchor_by_dna(self, dna: str) -> Optional[Dict[str, Any]]:
with sqlite3.connect(self.db_path) as conn:
conn.row_factory = sqlite3.Row
row = conn.execute(
"SELECT * FROM anchors WHERE dna = ?",
(dna,)
).fetchone()
if not row:
return None
result = dict(row)
result['names'] = self._get_names(dna)
result['authorizations'] = self._get_authorizations(dna)
result['chain'] = self._get_chain(dna)
return result
def _get_anchor_by_hash(self, hash_id: str) -> Optional[Dict[str, Any]]:
with sqlite3.connect(self.db_path) as conn:
conn.row_factory = sqlite3.Row
row = conn.execute(
"SELECT * FROM anchors WHERE hash_id = ?",
(hash_id,)
).fetchone()
if not row:
return None
dna = row['dna']
result = dict(row)
result['names'] = self._get_names(dna)
result['authorizations'] = self._get_authorizations(dna)
result['chain'] = self._get_chain(dna)
return result
def _get_anchor_by_name(self, name: str) -> Optional[Dict[str, Any]]:
with sqlite3.connect(self.db_path) as conn:
conn.row_factory = sqlite3.Row
row = conn.execute(
"SELECT a.* FROM anchors a JOIN names n ON a.dna = n.dna "
"WHERE n.name = ? AND n.active = 1",
(name,)
).fetchone()
if not row:
return None
dna = row['dna']
result = dict(row)
result['names'] = self._get_names(dna)
result['authorizations'] = self._get_authorizations(dna)
result['chain'] = self._get_chain(dna)
return result
def _get_names(self, dna: str) -> List[Dict]:
with sqlite3.connect(self.db_path) as conn:
conn.row_factory = sqlite3.Row
rows = conn.execute(
"SELECT name, lang, active, added_at, previous_name FROM names WHERE dna = ? ORDER BY added_at DESC",
(dna,)
).fetchall()
return [dict(row) for row in rows]
def _get_authorizations(self, dna: str) -> List[Dict]:
with sqlite3.connect(self.db_path) as conn:
conn.row_factory = sqlite3.Row
rows = conn.execute(
"SELECT grantee, scope, granted_at, expires_at, revoked FROM authorizations WHERE dna = ?",
(dna,)
).fetchall()
return [dict(row) for row in rows]
def _get_chain(self, dna: str) -> List[Dict]:
with sqlite3.connect(self.db_path) as conn:
conn.row_factory = sqlite3.Row
rows = conn.execute(
"SELECT event_type, event_data, event_at, parent_dna FROM chain_log WHERE dna = ? ORDER BY event_at ASC",
(dna,)
).fetchall()
return [dict(row) for row in rows]
# ────────────────────────────────────────────────
# 3. 更名(哈希不变)
# ────────────────────────────────────────────────
def rename(self, dna: str, new_name: str, lang: str = "zh") -> Dict[str, Any]:
"""
更换名称(追加记录,哈希不变)
参数:
dna: 产权DNA码
new_name: 新名称
lang: 语言
"""
anchor = self._get_anchor_by_dna(dna)
if not anchor:
return {"error": "产权不存在", "status": "not_found", "tri_color": "🔴"}
# 获取当前活跃名称
current_names = [n for n in anchor['names'] if n['active']]
current_name = current_names[0]['name'] if current_names else None
with sqlite3.connect(self.db_path) as conn:
# 将当前活跃名称设为非活跃
if current_name:
conn.execute(
"UPDATE names SET active = 0 WHERE dna = ? AND name = ? AND active = 1",
(dna, current_name)
)
# 添加新名称
added_at = datetime.now().isoformat()
conn.execute(
"INSERT INTO names (dna, name, lang, active, added_at, previous_name) "
"VALUES (?, ?, ?, 1, ?, ?)",
(dna, new_name, lang, added_at, current_name)
)
# 记录链日志
conn.execute(
"INSERT INTO chain_log (dna, event_type, event_data, event_at, parent_dna) "
"VALUES (?, ?, ?, ?, ?)",
(dna, "RENAME", json.dumps({"old_name": current_name, "new_name": new_name}), added_at, dna)
)
conn.commit()
audit_log("HASH", "RENAME", "PASS", dna)
tri_color = tri_color_audit("pass")
return {
"dna": dna,
"old_name": current_name,
"new_name": new_name,
"updated_at": added_at,
"tri_color": tri_color,
"message": f"名称已更新,哈希不变。旧名: {current_name} → 新名: {new_name}"
}
# ────────────────────────────────────────────────
# 4. 验证归属
# ────────────────────────────────────────────────
def verify(self, dna: str, file_path: Optional[str] = None, content: Optional[str] = None) -> Dict[str, Any]:
"""
验证文件/内容是否匹配产权
参数:
dna: 产权DNA码
file_path: 文件路径(与content二选一)
content: 内容字符串(与file_path二选一)
"""
anchor = self._get_anchor_by_dna(dna)
if not anchor:
return {"error": "产权不存在", "status": "not_found", "tri_color": "🔴"}
if file_path:
with open(file_path, 'rb') as f:
data = f.read()
elif content:
data = content.encode('utf-8')
else:
raise ValueError("必须提供 file_path 或 content")
computed_hash = hashlib.sha256(data).hexdigest()
stored_hash = anchor['hash_id']
is_match = computed_hash == stored_hash
audit_log("HASH", "VERIFY", "PASS" if is_match else "FAIL", dna)
tri_color = tri_color_audit("pass" if is_match else "reject")
return {
"dna": dna,
"stored_hash": stored_hash,
"computed_hash": computed_hash,
"match": is_match,
"tri_color": tri_color,
"message": "验证通过 ✅" if is_match else "验证失败 ❌"
}
# ────────────────────────────────────────────────
# 5. 授权管理
# ────────────────────────────────────────────────
def authorize(
self,
dna: str,
grantee: str,
scope: str,
expires_at: Optional[str] = None
) -> Dict[str, Any]:
"""
授权使用
参数:
dna: 产权DNA码
grantee: 被授权方
scope: 授权范围
expires_at: 过期时间(ISO格式)
"""
anchor = self._get_anchor_by_dna(dna)
if not anchor:
return {"error": "产权不存在", "status": "not_found", "tri_color": "🔴"}
granted_at = datetime.now().isoformat()
with sqlite3.connect(self.db_path) as conn:
conn.execute(
"INSERT INTO authorizations (dna, grantee, scope, granted_at, expires_at, revoked) "
"VALUES (?, ?, ?, ?, ?, 0)",
(dna, grantee, scope, granted_at, expires_at)
)
conn.execute(
"INSERT INTO chain_log (dna, event_type, event_data, event_at, parent_dna) "
"VALUES (?, ?, ?, ?, ?)",
(dna, "AUTHORIZE", json.dumps({"grantee": grantee, "scope": scope}), granted_at, dna)
)
conn.commit()
audit_log("HASH", "AUTHORIZE", "PASS", dna)
tri_color = tri_color_audit("pass")
return {
"dna": dna,
"grantee": grantee,
"scope": scope,
"granted_at": granted_at,
"expires_at": expires_at,
"tri_color": tri_color,
"message": f"已授权 {grantee} 使用 {scope}"
}
def revoke(self, auth_id: int) -> Dict[str, Any]:
"""撤销授权"""
with sqlite3.connect(self.db_path) as conn:
# 获取授权信息
row = conn.execute(
"SELECT dna FROM authorizations WHERE id = ?",
(auth_id,)
).fetchone()
if not row:
return {"error": "授权记录不存在", "status": "not_found"}
conn.execute(
"UPDATE authorizations SET revoked = 1 WHERE id = ?",
(auth_id,)
)
revoked_at = datetime.now().isoformat()
conn.execute(
"INSERT INTO chain_log (dna, event_type, event_data, event_at, parent_dna) "
"VALUES (?, ?, ?, ?, ?)",
(row[0], "REVOKE", json.dumps({"auth_id": auth_id}), revoked_at, row[0])
)
conn.commit()
audit_log("HASH", "REVOKE", "PASS", row[0])
return {
"auth_id": auth_id,
"revoked_at": revoked_at,
"tri_color": "🟢",
"message": f"授权已撤销"
}
# ────────────────────────────────────────────────
# 6. 完整链查询
# ────────────────────────────────────────────────
def get_chain(self, dna: str) -> Dict[str, Any]:
"""获取完整变更链"""
anchor = self._get_anchor_by_dna(dna)
if not anchor:
return {"error": "产权不存在", "status": "not_found"}
chain = self._get_chain(dna)
return {
"dna": dna,
"total_events": len(chain),
"chain": chain,
"timeline": [
{
"event": c['event_type'],
"data": json.loads(c['event_data']),
"at": c['event_at']
}
for c in chain
]
}
# ────────────────────────────────────────────────
# 7. 统计信息
# ────────────────────────────────────────────────
def stats(self) -> Dict[str, Any]:
"""获取统计信息"""
with sqlite3.connect(self.db_path) as conn:
total = conn.execute("SELECT COUNT(*) FROM anchors").fetchone()[0]
by_type = conn.execute(
"SELECT anchor_type, COUNT(*) FROM anchors GROUP BY anchor_type"
).fetchall()
active_names = conn.execute(
"SELECT COUNT(*) FROM names WHERE active = 1"
).fetchone()[0]
auths = conn.execute(
"SELECT COUNT(*) FROM authorizations WHERE revoked = 0"
).fetchone()[0]
return {
"total_anchors": total,
"by_type": dict(by_type),
"active_names": active_names,
"active_authorizations": auths
}
# ────────────────────────────────────────────────
# 命令行入口
# ────────────────────────────────────────────────
def main():
import argparse
parser = argparse.ArgumentParser(description="🐉 龙魂 · 哈希产权引擎")
parser.add_argument("command", choices=["register", "query", "rename", "verify", "authorize", "revoke", "chain", "stats"])
parser.add_argument("--name", help="名称")
parser.add_argument("--type", help="类型: brand|patent|trademark|work")
parser.add_argument("--owner", help="所有者")
parser.add_argument("--file", help="文件路径")
parser.add_argument("--content", help="内容字符串")
parser.add_argument("--dna", help="DNA码")
parser.add_argument("--hash", help="哈希值")
parser.add_argument("--new-name", help="新名称")
parser.add_argument("--grantee", help="被授权方")
parser.add_argument("--scope", help="授权范围")
parser.add_argument("--auth-id", type=int, help="授权ID")
args = parser.parse_args()
engine = HashEngine()
if args.command == "register":
result = engine.register(
name=args.name,
anchor_type=args.type,
owner=args.owner,
file_path=args.file,
content=args.content
)
print(json.dumps(result, ensure_ascii=False, indent=2))
elif args.command == "query":
if args.dna:
result = engine.query(args.dna, "dna")
elif args.hash:
result = engine.query(args.hash, "hash")
elif args.name:
result = engine.query(args.name, "name")
else:
print("请提供 --dna、--hash 或 --name")
return
print(json.dumps(result, ensure_ascii=False, indent=2))
elif args.command == "rename":
result = engine.rename(args.dna, args.new_name)
print(json.dumps(result, ensure_ascii=False, indent=2))
elif args.command == "verify":
result = engine.verify(args.dna, file_path=args.file, content=args.content)
print(json.dumps(result, ensure_ascii=False, indent=2))
elif args.command == "authorize":
result = engine.authorize(args.dna, args.grantee, args.scope)
print(json.dumps(result, ensure_ascii=False, indent=2))
elif args.command == "revoke":
result = engine.revoke(args.auth_id)
print(json.dumps(result, ensure_ascii=False, indent=2))
elif args.command == "chain":
result = engine.get_chain(args.dna)
print(json.dumps(result, ensure_ascii=False, indent=2))
elif args.command == "stats":
result = engine.stats()
print(json.dumps(result, ensure_ascii=False, indent=2))
if __name__ == "__main__"
#### 2. API 调用示例
启动 API 网关后,可通过 `curl` 直接调用注册、查询、验证、授权、完整链查询等接口。以下示例需要先执行:
```bash
python3 08_BIN/hash_api.py
服务默认监听 http://127.0.0.1:9622,接口文档地址为 http://127.0.0.1:9622/hash/docs。
健康检查
curl http://127.0.0.1:9622/hash/health
预期返回:
{
"status": "healthy",
"service": "hash-engine",
"version": "1.0.0"
}
注册产权
curl -X POST http://127.0.0.1:9622/hash/register \
-H "Content-Type: application/json" \
-d '{"name":"龙魂系统","type":"brand","owner":"UID9622","content":"龙魂系统核心代码"}'
预期返回:
{
"dna": "#龍芯⚡️2026-08-24-21-43-07-HASH-REGISTER-3F9A7C2D",
"hash_id": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
"anchor_type": "brand",
"owner": "UID9622",
"registered_at": "2026-08-24T21:43:07.123456",
"status": "active",
"tri_color": "🟢",
"name": "龙魂系统"
}
注:
dna、hash_id、registered_at为运行时生成值,以下示例中均以<DNA>、<HASH>占位表示,实际调用时请替换为注册返回的真实值。
查询产权
按 DNA 查询:
curl "http://127.0.0.1:9622/hash/query?identifier=%23龍芯⚡️2026-08-24-21-43-07-HASH-REGISTER-3F9A7C2D&by=dna"
按名称查询:
curl "http://127.0.0.1:9622/hash/query?identifier=龙魂系统&by=name"
预期返回:
{
"dna": "<DNA>",
"hash_id": "<HASH>",
"anchor_type": "brand",
"owner": "UID9622",
"registered_at": "2026-08-24T21:43:07.123456",
"proof_block": null,
"status": "active",
"metadata": "{}",
"created_at": "2026-08-24 21:43:07",
"names": [
{
"name": "龙魂系统",
"lang": "zh",
"active": 1,
"added_at": "2026-08-24T21:43:07.123456",
"previous_name": null
}
],
"authorizations": [],
"chain": [
{
"event_type": "REGISTER",
"event_data": "{\"name\": \"龙魂系统\", \"type\": \"brand\", \"owner\": \"UID9622\"}",
"event_at": "2026-08-24T21:43:07.123456",
"parent_dna": null
}
]
}
验证归属
curl -X POST http://127.0.0.1:9622/hash/verify \
-H "Content-Type: application/json" \
-d '{"dna":"<DNA>","content":"龙魂系统核心代码"}'
预期返回(内容一致时):
{
"dna": "<DNA>",
"stored_hash": "<HASH>",
"computed_hash": "<HASH>",
"match": true,
"tri_color": "🟢",
"message": "验证通过 ✅"
}
预期返回(内容不一致时):
{
"dna": "<DNA>",
"stored_hash": "<HASH>",
"computed_hash": "a3f5...519c",
"match": false,
"tri_color": "🔴",
"message": "验证失败 ❌"
}
授权使用
curl -X POST http://127.0.0.1:9622/hash/authorize \
-H "Content-Type: application/json" \
-d '{"dna":"<DNA>","grantee":"某公司","scope":"商业使用"}'
预期返回:
{
"dna": "<DNA>",
"grantee": "某公司",
"scope": "商业使用",
"granted_at": "2026-08-24T21:43:30.654321",
"expires_at": null,
"tri_color": "🟢",
"message": "已授权 某公司 使用 商业使用"
}
完整链查询
curl "http://127.0.0.1:9622/hash/chain/<DNA>"
预期返回:
{
"dna": "<DNA>",
"total_events": 2,
"chain": [
{
"event_type": "REGISTER",
"event_data": "{\"name\": \"龙魂系统\", \"type\": \"brand\", \"owner\": \"UID9622\"}",
"event_at": "2026-08-24T21:43:07.123456",
"parent_dna": null
},
{
"event_type": "AUTHORIZE",
"event_data": "{\"grantee\": \"某公司\", \"scope\": \"商业使用\"}",
"event_at": "2026-08-24T21:43:30.654321",
"parent_dna": "<DNA>"
}
],
"timeline": [
{
"event": "REGISTER",
"data": {"name": "龙魂系统", "type": "brand", "owner": "UID9622"},
"at": "2026-08-24T21:43:07.123456"
},
{
"event": "AUTHORIZE",
"data": {"grantee": "某公司", "scope": "商业使用"},
"at": "2026-08-24T21:43:30.654321"
}
]
}
更名(哈希不变)
curl -X POST http://127.0.0.1:9622/hash/rename \
-H "Content-Type: application/json" \
-d '{"dna":"<DNA>","new_name":"Longhun System","lang":"zh"}'
预期返回:
{
"dna": "<DNA>",
"old_name": "龙魂系统",
"new_name": "Longhun System",
"updated_at": "2026-08-24T21:44:00.111111",
"tri_color": "🟢",
"message": "名称已更新,哈希不变。旧名: 龙魂系统 → 新名: Longhun System"
}
统计信息
curl http://127.0.0.1:9622/hash/stats
预期返回:
{
"total_anchors": 1,
"by_type": {"brand": 1},
"active_names": 1,
"active_authorizat
#### 实战调用示例
下面脚本演示在不启动 API 服务的情况下,直接通过 `HashEngine` 完成产权注册、按 DNA 查询、更名、验证归属与完整链查询。将脚本保存为 `demo_hash_engine.py`,放在 `longhun-system` 目录下运行:
```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
🐉 龙魂 · 哈希产权引擎 实战调用示例
完整流程:注册产权 → 按 DNA 查询 → 更名 → 验证归属 → 查看完整链
"""
import json
import sys
from pathlib import Path
# 将 08_BIN 目录加入模块搜索路径,确保可以导入 hash_engine
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "08_BIN"))
from hash_engine import HashEngine
# 初始化引擎,首次运行会自动创建 SQLite 数据库和所需表
engine = HashEngine()
def show(title, result):
"""统一打印每一步返回结果"""
print("\n" + "=" * 60)
print(title)
print("=" * 60)
print(json.dumps(result, ensure_ascii=False, indent=2))
# 1. 注册产权:传入 content 字符串,引擎会计算 SHA-256 哈希并生成唯一 DNA
register_result = engine.register(
name="龙魂系统",
anchor_type="brand", # 锚点类型:brand / patent / trademark / work
owner="UID9622", # 所有者
content="龙魂系统核心代码 v1.0" # 需要确权的内容字符串
)
show("第一步:注册产权(传入 content 字符串)", register_result)
# 输出含义:
# dna — 运行时生成的唯一产权 DNA 码,后续所有步骤都要用它定位产权
# hash_id — 对 content 计算的 SHA-256 哈希,是产权锚点,改名也不会变
# status — active 表示产权已生效
# tri_color — 🟢 表示本次注册已通过三色审计
# 注意:相同 content 重复注册会返回 {"status": "duplicate", ...},
# 此时请修改 content 后重新运行,或用返回的 existing_dna 继续查询。
dna = register_result["dna"] # 保存 DNA,后续步骤复用
# 2. 按 DNA 查询产权
query_result = engine.query(dna, by="dna")
show("第二步:按 DNA 查询产权", query_result)
# 输出含义:
# names — 名称记录列表,active=1 表示当前生效名称
# chain — 产权变更链,当前只应包含一条 REGISTER 注册事件
# 3. 更名:追加新名称记录,哈希保持不变
rename_result = engine.rename(dna, "Longhun System")
show("第三步:更名(哈希保持不变)", rename_result)
# 输出含义:
# old_name — 原名称
# new_name — 新名称
# message — 明确提示“哈希不变”,产权锚点不因改名而改变
# 4. 验证归属:用与注册时完全相同的内容验证,应匹配成功
verify_ok = engine.verify(dna, content="龙魂系统核心代码 v1.0")
show("第四步:验证归属(内容一致)", verify_ok)
# 输出含义:
# stored_hash — 注册时保存的哈希
# computed_hash — 当前内容重新计算的哈希
# match=true — 两者一致,证明内容与注册时完全相同
# tri_color=🟢 — 审计通过
# 再用被篡改的内容验证,应匹配失败
verify_fail = engine.verify(dna, content="被篡改的内容")
show("第四步:验证归属(内容不一致)", verify_fail)
# 输出含义:
# match=false — 哈希不一致,检测到内容被改动
# tri_color=🔴 — 审计标红,验证失败
# 5. 查看完整链:查看该产权全生命周期的变更记录
chain_result = engine.get_chain(dna)
show("第五步:查看完整链", chain_result)
# 输出含义:
# total_events — 累计事件数,此处应至少包含 REGISTER 和 RENAME 两条
# chain — 原始事件列表,按 event_at 时间顺序排列
# timeline — 简化时间线,event_data 已解析为可读对象
运行方式:
cd ~/longhun-system
python3 demo_hash_engine.py
ions": 1
}
:
main()
2. API 网关:08_BIN/hash_api.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
🐉 龙魂 · 哈希产权 API 网关 v1.0
DNA: #龍芯⚡️丙午·丙申·辛亥-HASH-API-v1.0-UID9622
启动: python3 08_BIN/hash_api.py
访问: http://127.0.0.1:9622/hash/docs
"""
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional, Dict, Any
import uvicorn
from pathlib import Path
import sys
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from hash_engine import HashEngine
app = FastAPI(
title="🐉 龙魂 · 哈希产权引擎 API",
description="基于哈希锚定的数字产权管理系统 | 名字随便换,哈希永不改",
version="1.0.0",
docs_url="/hash/docs",
redoc_url="/hash/redoc"
)
engine = HashEngine()
# ────────────────────────────────────────────────
# 请求/响应模型
# ────────────────────────────────────────────────
class RegisterRequest(BaseModel):
name: str
type: str # brand | patent | trademark | work
owner: str
file_path: Optional[str] = None
content: Optional[str] = None
metadata: Optional[Dict[str, Any]] = None
lang: str = "zh"
class QueryRequest(BaseModel):
identifier: str
by: str # dna | hash | name
class RenameRequest(BaseModel):
dna: str
new_name: str
lang: str = "zh"
class VerifyRequest(BaseModel):
dna: str
file_path: Optional[str] = None
content: Optional[str] = None
class AuthorizeRequest(BaseModel):
dna: str
grantee: str
scope: str
expires_at: Optional[str] = None
# ────────────────────────────────────────────────
# API 路由
# ────────────────────────────────────────────────
@app.post("/hash/register", tags=["产权管理"])
async def register(req: RegisterRequest):
"""注册新产权"""
result = engine.register(
name=req.name,
anchor_type=req.type,
owner=req.owner,
file_path=req.file_path,
content=req.content,
metadata=req.metadata,
lang=req.lang
)
if "error" in result:
raise HTTPException(status_code=400, detail=result)
return result
@app.get("/hash/query", tags=["产权管理"])
async def query(identifier: str, by: str = "dna"):
"""查询产权 (by: dna | hash | name)"""
result = engine.query(identifier, by)
if not result:
raise HTTPException(status_code=404, detail="产权不存在")
return result
@app.post("/hash/rename", tags=["产权管理"])
async def rename(req: RenameRequest):
"""更换名称(哈希不变)"""
result = engine.rename(req.dna, req.new_name, req.lang)
if "error" in result:
raise HTTPException(status_code=400, detail=result)
return result
@app.post("/hash/verify", tags=["验证"])
async def verify(req: VerifyRequest):
"""验证文件/内容是否匹配产权"""
result = engine.verify(req.dna, req.file_path, req.content)
if "error" in result:
raise HTTPException(status_code=400, detail=result)
return result
@app.post("/hash/authorize", tags=["授权"])
async def authorize(req: AuthorizeRequest):
"""授权使用"""
result = engine.authorize(req.dna, req.grantee, req.scope, req.expires_at)
if "error" in result:
raise HTTPException(status_code=400, detail=result)
return result
@app.post("/hash/revoke/{auth_id}", tags=["授权"])
async def revoke(auth_id: int):
"""撤销授权"""
result = engine.revoke(auth_id)
if "error" in result:
raise HTTPException(status_code=400, detail=result)
return result
@app.get("/hash/chain/{dna}", tags=["追溯"])
async def get_chain(dna: str):
"""获取完整变更链"""
result = engine.get_chain(dna)
if "error" in result:
raise HTTPException(status_code=404, detail=result)
return result
@app.get("/hash/stats", tags=["统计"])
async def get_stats():
"""获取统计信息"""
return engine.stats()
@app.get("/hash/health", tags=["健康检查"])
async def health():
return {"status": "healthy", "service": "hash-engine", "version": "1.0.0"}
# ────────────────────────────────────────────────
# 启动
# ────────────────────────────────────────────────
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=9622)
3. 安装脚本:08_BIN/install_hash_engine.sh
#!/bin/bash
# 🐉 龙魂 · 哈希产权引擎 一键安装
# DNA: #龍芯⚡️丙午·丙申·辛亥-HASH-INSTALL-v1.0-UID9622
set -e
echo "🐉 安装龙魂 · 哈希产权引擎 v1.0"
# 1. 创建数据目录
mkdir -p ~/longhun-system/data
mkdir -p ~/longhun-system/08_BIN
# 2. 安装Python依赖
pip install fastapi uvicorn pydantic
# 3. 复制核心文件
# (假设当前在 longhun-system 目录下)
cp 08_BIN/hash_engine.py ~/longhun-system/08_BIN/
cp 08_BIN/hash_api.py ~/longhun-system/08_BIN/
# 4. 设置执行权限
chmod +x ~/longhun-system/08_BIN/hash_engine.py
chmod +x ~/longhun-system/08_BIN/hash_api.py
# 5. 创建启动脚本
cat > ~/longhun-system/start_hash_engine.sh << 'EOF'
#!/bin/bash
cd ~/longhun-system
python3 08_BIN/hash_api.py &
echo "✅ 哈希产权引擎已启动: http://127.0.0.1:9622/hash/docs"
EOF
chmod +x ~/longhun-system/start_hash_engine.sh
echo "✅ 安装完成"
echo ""
echo "启动: ~/longhun-system/start_hash_engine.sh"
echo "API文档: http://127.0.0.1:9622/hash/docs"
echo ""
echo "DNA: #龍芯⚡️丙午·丙申·辛亥-HASH-INSTALL-v1.0-UID9622"
4. 集成到主入口:修改 08_BIN/龍魂体系v5-一键启动.py
在现有启动脚本中追加哈希引擎的启动逻辑:
# 在现有启动函数中追加
def start_hash_engine():
"""启动哈希产权引擎"""
import subprocess
import time
print("🐉 启动哈希产权引擎...")
proc = subprocess.Popen(
["python3", "08_BIN/hash_api.py"],
cwd=str(Path(__file__).resolve().parent.parent)
)
time.sleep(2)
print("✅ 哈希产权引擎已启动: http://127.0.0.1:9622/hash/docs")
return proc
# 在主函数中调用
# hash_proc = start_hash_engine()
四、文件部署结构
~/longhun-system/
├── 08_BIN/
│ ├── hash_engine.py ← 核心引擎(新增)
│ ├── hash_api.py ← API网关(新增)
│ ├── install_hash_engine.sh ← 安装脚本(新增)
│ ├── lh_dna_core.py ← 已有(DNA引擎)
│ ├── lh_audit.py ← 已有(三色审计)
│ └── 龍魂体系v5-一键启动.py ← 修改(追加哈希引擎)
├── data/
│ └── hash_registry.db ← 自动生成(SQLite数据库)
├── 12_DOCS/
│ └── HASH_ENGINE_GUIDE.md ← 使用文档(新增)
└── 13_TESTS/
└── test_hash_engine.py ← 单元测试(新增)
五、使用方法
命令行
# 注册产权
python3 08_BIN/hash_engine.py register --name "龙魂系统" --type brand --owner UID9622 --content "龙魂系统核心代码"
# 查询产权(按DNA)
python3 08_BIN/hash_engine.py query --dna "#龍芯⚡️..."
# 查询产权(按名称)
python3 08_BIN/hash_engine.py query --name "龙魂系统"
# 更名(哈希不变)
python3 08_BIN/hash_engine.py rename --dna "#龍芯⚡️..." --new-name "Longhun System"
# 验证归属
python3 08_BIN/hash_engine.py verify --dna "#龍芯⚡️..." --file README.md
# 授权使用
python3 08_BIN/hash_engine.py authorize --dna "#龍芯⚡️..." --grantee "某公司" --scope "商业使用"
# 查看完整链
python3 08_BIN/hash_engine.py chain --dna "#龍芯⚡️..."
# 统计信息
python3 08_BIN/hash_engine.py stats
API 调用
# 启动服务
python3 08_BIN/hash_api.py
# 注册产权
curl -X POST http://127.0.0.1:9622/hash/register \
-H "Content-Type: application/json" \
-d '{"name":"龙魂系统","type":"brand","owner":"UID9622","content":"test"}'
# 查询产权
curl "http://127.0.0.1:9622/hash/query?identifier=龙魂系统&by=name"
# 查看API文档
open http://127.0.0.1:9622/hash/docs
六、验证清单
| # | 检查项 | 命令 |
|---|---|---|
| 1 | 数据库初始化 | python3 -c "from hash_engine import HashEngine; HashEngine()" |
| 2 | 注册产权 | python3 08_BIN/hash_engine.py register --name test --type brand --owner test --content test |
| 3 | 查询产权 | python3 08_BIN/hash_engine.py query --name test |
| 4 | 更名 | python3 08_BIN/hash_engine.py rename --dna <DNA> --new-name test2 |
| 5 | 验证 | python3 08_BIN/hash_engine.py verify --dna <DNA> --content test |
| 6 | API启动 | python3 08_BIN/hash_api.py & |
| 7 | API文档 | curl http://127.0.0.1:9622/hash/docs |
七、一句话闭环
**名字随便换,哈希永不改。查
八、单元测试:13_TESTS/test_hash_engine.py
部署结构中预留了测试目录,下面给出配套的单元测试代码,覆盖注册、去重、查询、验证、更名与授权链路,保证引擎可回归验收:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
🐉 龙魂 · 哈希产权引擎 单元测试
DNA: #龍芯⚡️丙午·丙申·辛亥-HASH-TEST-v1.0-UID9622
运行: python3 -m unittest 13_TESTS/test_hash_engine.py -v
"""
import sys
import tempfile
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "08_BIN"))
from hash_engine import HashEngine
class TestHashEngine(unittest.TestCase):
"""哈希产权引擎核心链路测试"""
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.engine = HashEngine(Path(self.tmp.name) / "test.db")
def tearDown(self):
self.tmp.cleanup()
def test_register(self):
"""注册后应返回 DNA 与 active 状态"""
result = self.engine.register(
name="测试品牌", anchor_type="brand", owner="UID9622", content="test-content"
)
self.assertIn("dna", result)
self.assertEqual(result["status"], "active")
def test_register_duplicate(self):
"""相同内容重复注册应返回 duplicate"""
self.engine.register(name="A", anchor_type="brand", owner="U", content="same-content")
result = self.engine.register(name="B", anchor_type="brand", owner="U", content="same-content")
self.assertEqual(result["status"], "duplicate")
def test_query_and_verify(self):
"""查询哈希与内容验证应一致"""
r = self.engine.register(name="Q", anchor_type="work", owner="U", content="hello")
q = self.engine.query(r["dna"], "dna")
self.assertEqual(q["hash_id"], r["hash_id"])
v = self.engine.verify(r["dna"], content="hello")
self.assertTrue(v["match"])
v2 = self.engine.verify(r["dna"], content="world")
self.assertFalse(v2["match"])
def test_rename_keeps_hash(self):
"""更名后哈希保持不变,名称切到新值"""
r = self.engine.register(name="原名", anchor_type="brand", owner="U", content="data")
old_hash = r["hash_id"]
result = self.engine.rename(r["dna"], "新名")
self.assertNotIn("error", result)
q = self.engine.query(r["dna"], "dna")
self.assertEqual(q["hash_id"], old_hash)
active_names = [n for n in q["names"] if n["active"]]
self.assertEqual(active_names[0]["name"], "新名")
def test_authorize_and_chain(self):
"""授权后完整链应记录注册与授权事件"""
r = self.engine.register(name="Auth", anchor_type="trademark", owner="U", content="x")
auth = self.engine.authorize(r["dna"], "某公司", "商业使用")
self.assertNotIn("error", auth)
chain = self.engine.get_chain(r["dna"])
self.assertGreaterEqual(chain["total_events"], 2)
if __name__ == "__main__":
unittest.main(verbosity=2)
运行方式:
cd ~/longhun-system
python3 -m unittest 13_TESTS/test_hash_engine.py -v
全部用例通过,即代表注册、去重、查询、验证、更名、授权与完整链追
九、总结与 FAQ
核心设计要点
哈希产权引擎围绕“内容可验证、归属可追溯、操作可审计”三个目标设计,核心机制如下:
| 设计要点 | 作用 | 关键实现 |
|---|---|---|
| 哈希锚定 | 用 SHA-256 固定内容指纹,确保“名字随便换,哈希永不改” | hash_engine.register() 对 content/file_path 计算哈希;更名只追加 names 记录,不更新 anchors.hash_id |
| DNA 追溯 | 每个产权绑定唯一 DNA 码,串联注册、更名、授权、撤销全生命周期 | lh_dna_core.generate_dna() 生成 DNA;chain_log 按时间顺序记录全部变更事件 |
| 三色审计 | 对每次关键操作给出 🟢/🟡/🔴 审计状态,便于风险识别 | lh_audit.tri_color_audit();注册🟢、更名🟡、争议🔴、授权🟢 |
哈希锚定解决“作品是否被篡改”,DNA 追溯解决“这个产权发生过什么”,三色审计解决“当前流程是否合规”,三者共同构成产权存证闭环。
高频问题 FAQ
Q1:如何迁移数据库?
引擎默认使用单文件 SQLite 数据库,路径为 ~/longhun-system/data/hash_registry.db。迁移步骤如下:
- 停止 API 服务,确认没有正在写入的请求。
- 将整个
data目录复制到新机器,若启用了 WAL 模式,还要一并复制hash_registry.db-wal和hash_registry.db-shm。 - 在新机器保持
~/longhun-system/data目录结构一致。 - 重新执行数据库初始化命令或直接启动 API,引擎会自动识别已有表结构。
也可使用 SQLite 在线备份命令生成一致性快照:
sqlite3 ~/longhun-system/data/hash_registry.db ".backup ~/hash_registry_backup.db"
迁移后建议先调用健康检查,并用 query 按已知 DNA 或名称抽查几条产权,确认数据完整。
Q2:如何备份产权数据?
产权数据全部落在 SQLite 数据库中,因此备份重点是 ~/longhun-system/data 目录。建议组合使用以下策略:
# 每日凌晨 2 点自动备份 data 目录
mkdir -p ~/longhun-system/backups
tar -czf ~/longhun-system/backups/hash_data_$(date +%F).tar.gz \
~/longhun-system/data
更稳妥的方式是在备份前先停止写入,或用上文的 .backup 命令生成一致性快照。除数据库外,还应同步备份:
08_BIN/hash_engine.py、hash_api.py等核心源码;08_BIN/lh_dna_core.py、lh_audit.py等龙魂模块;12_DOCS与13_TESTS下的文档和测试脚本。
生产环境可配置 cron 定时任务,并定期将备份文件同步到异地或对象存储。
Q3:如何接入龙魂体系一键启动?
在前文“集成到主入口”一节已有示例。核心做法是在 08_BIN/龍魂体系v5-一键启动.py 中追加哈希引擎启动函数:
def start_hash_engine():
import subprocess
import time
print("🐉 启动哈希产权引擎...")
proc = subprocess.Popen(
["python3", "08_BIN/hash_api.py"],
cwd=str(Path(__file__).resolve().parent.parent)
)
time.sleep(2)
print("✅ 哈希产权引擎已启动: http://127.0.0.1:9622/hash/docs")
return proc
然后在主启动流程中调用 hash_proc = start_hash_engine()。建议启动时先初始化数据库,再拉起 API,最后调用 /hash/health 做自检,确认正常后再继续启动其余龙魂模块。
Q4:如何扩展为多节点部署?
当前引擎为单机 SQLite 架构,适合单节点部署。若需要多节点扩展,建议分两步演进:
- API 层多实例 + 共享存储:多台机器共享同一个数据库文件或网络存储,由负载均衡将
/hash/*请求分发到多个hash_api.py实例。SQLite 本身不支持高并发跨机写,因此写入必须收敛到单写节点,或用任务队列串行化。 - 数据库替换为 PostgreSQL:把 SQLite 访问层替换为 SQLAlchemy 或原生异步驱动,迁移
anchors、names、authorizations、chain_log四张表。PostgreSQL 支持多节点并发读写,适合十万级以上的规模化场景。
多节点部署时,DNA 生成需要保证全局唯一。可以改造 generate_dna(),在 DNA 中加入节点编号、实例 ID 或基于 Redis 的全局递增序列,避免两个节点在同一秒生成相同 DNA。
Q5:如何对接 IPFS 存证?
引擎已在 anchors 表预留 proof_block 字段,可用于保存 IPFS CID 或其他链上存证哈希。推荐做法是注册完成后,将产权摘要打包上传 IPFS,并把返回的 CID 回写到数据库:
import json
import urllib.request
def pin_to_ipfs(record: dict) -> str:
payload = json.dumps(record, ensure_ascii=False).encode("utf-8")
req = urllib.request.Request(
"http://127.0.0.1:5001/api/v0/add",
data=payload,
headers={"Content-Type": "application/json"},
)
resp = urllib.request.urlopen(req)
result = json.loads(resp.read().decode("utf-8"))
return result["Hash"] # 返回 IPFS CID
将返回的 CID 写入 anchors.proof_block 即可形成“本地哈希锚定 + IPFS 分布式存证”的双重确权。生产环境建议使用固定节点或 IPFS 集群,并对 CID 做持久化固定(Pin),避免数据
版本记录
| 版本 | 日期 | 变更内容 |
|---|---|---|
| v1.0 | 2026-08-24 | 首次发布:注册、查询、更名、验证、授权、完整链查询、统计能力;集成 DNA 引擎、三色审计与 FastAPI 网关 |
文章标签
Python FastAPI SQLite 哈希存证 产权管理 龙魂系统 DNA 追溯 三色审计 SHA-256 API 网关
被垃圾回收。
溯七条核心链路可用。
产权只认哈希,打官司只打哈希。文字可以变,根不变。**

被折叠的 条评论
为什么被折叠?



