返回实战项目
Day 12

【实战4.3】基于图分析的女巫检测:地址关联图谱与集群识别

利用地址间转账关系构建关联图谱,用图算法识别女巫集群,设计聚类检测方法论和可视化方案

2026-03-20
实战项目图分析女巫集群地址关联聚类算法可视化

实战项目 4.3:基于图分析的女巫检测

项目信息

项目编号:4.3
所属方向:反女巫检测
难度:⭐⭐⭐⭐⭐ 专家
预计时间:5-6小时
前置技能:女巫评分(实战4.1)、女巫猎人(实战4.2)

项目目标

利用地址间的转账关系构建关联图谱,用图算法识别女巫集群

产出清单:
├── ✅ 地址关联分析方法论
├── ✅ 集群检测算法设计
└── ✅ 可视化方案

Task 1:地址关联分析方法论

图模型定义

地址关联图(Address Interaction Graph):
═══════════════════════════════════════════════════════════

节点(Node)= 钱包地址
边(Edge)= 两个地址之间的交互关系

边的类型:
├── ETH 转账(权重高)— 直接资金关系
├── ERC20 转账(权重中)— Token 流转
├── 同合约交互(权重低)— 使用同一 DApp
└── 同区块交易(权重中)— 时间同步信号

边的属性:
├── 权重:交互金额 × 频率
├── 方向:A→B 还是 B→A
├── 时间:首次和最近交互
└── 类型:转账/交互/同步

女巫集群特征:
├── 星型结构:一个中心→多个外围(母钱包→子钱包)
├── 链式结构:A→B→C→D(洗钱路径)
├── 环形结构:A→B→C→A(循环交易)
└── 全连接:小组内两两互转(小型集群)
═══════════════════════════════════════════════════════════

核心 SQL — 构建地址关联边

-- 项目4.3 Task 1: 构建地址间的转账关联图
-- 目标:找到两两之间有直接 ETH 转账的地址对

WITH eth_transfers AS (
  SELECT
    "from" as sender,
    "to" as receiver,
    COUNT(*) as transfer_count,
    SUM(value / 1e18) as total_eth,
    MIN(block_time) as first_transfer,
    MAX(block_time) as last_transfer
  FROM ethereum.transactions
  WHERE block_time >= NOW() - INTERVAL '90' DAY
    AND value > 0
    AND gas_used < 25000  -- 简单转账(非合约调用)
  GROUP BY "from", "to"
  HAVING COUNT(*) >= 2  -- 至少转过 2 次
),

-- 找到"星型结构":一个地址给 5+ 地址转过账
star_centers AS (
  SELECT
    sender as center,
    COUNT(DISTINCT receiver) as spoke_count,
    SUM(total_eth) as total_distributed,
    AVG(total_eth / transfer_count) as avg_per_transfer
  FROM eth_transfers
  GROUP BY sender
  HAVING COUNT(DISTINCT receiver) >= 5
)

SELECT
  sc.center,
  sc.spoke_count,
  ROUND(sc.total_distributed, 4) as total_eth_distributed,
  ROUND(sc.avg_per_transfer, 4) as avg_eth_per_tx,
  CASE
    WHEN sc.spoke_count >= 50 THEN '大型集群中心'
    WHEN sc.spoke_count >= 20 THEN '中型集群中心'
    ELSE '小型集群中心'
  END as cluster_type
FROM star_centers sc
ORDER BY sc.spoke_count DESC
LIMIT 100

核心 SQL — 检测环形转账

-- 检测 A→B→C→A 的三角环形转账
WITH transfers AS (
  SELECT DISTINCT
    "from" as sender,
    "to" as receiver
  FROM ethereum.transactions
  WHERE block_time >= NOW() - INTERVAL '30' DAY
    AND value / 1e18 BETWEEN 0.01 AND 1  -- 小额转账
    AND gas_used < 25000
)

SELECT
  a.sender as node_a,
  a.receiver as node_b,
  b.receiver as node_c,
  'Triangle: A→B→C→A' as pattern
FROM transfers a
INNER JOIN transfers b ON a.receiver = b.sender
INNER JOIN transfers c ON b.receiver = c.sender AND c.receiver = a.sender
WHERE a.sender < a.receiver  -- 去重
LIMIT 100

Task 2:集群检测算法设计

算法一:Union-Find(并查集)

用途:将有直接关联的地址合并为同一集群

算法步骤:
═══════════════════════════════════════════════════════════

1. 初始化:每个地址是自己的"集群"
2. 遍历所有边:
   ├── 如果 A→B 有转账
   ├── 将 A 和 B 合并到同一集群
   └── 递归:A 的集群和 B 的集群所有成员合并
3. 结果:所有直接或间接关联的地址在同一集群

示例:
  A→B, B→C, D→E, E→F
  集群1:{A, B, C}
  集群2:{D, E, F}

SQL 实现(简化版,用递归 CTE):

WITH RECURSIVE edges AS (
  SELECT "from" as a, "to" as b
  FROM ethereum.transactions
  WHERE value > 0
    AND block_time >= NOW() - INTERVAL '30' DAY
),
clusters AS (
  SELECT a as node, a as cluster_root FROM edges
  UNION
  SELECT e.b, c.cluster_root
  FROM edges e
  JOIN clusters c ON e.a = c.node
)
SELECT cluster_root, COUNT(DISTINCT node) as cluster_size
FROM clusters
GROUP BY cluster_root
HAVING COUNT(DISTINCT node) >= 5
ORDER BY cluster_size DESC

注意:递归 CTE 在大数据集上性能差
生产环境应使用 Python + NetworkX 或 Spark GraphX
═══════════════════════════════════════════════════════════

算法二:社区检测(Community Detection)

用途:在大型图中找到紧密连接的子图

推荐算法:

1. Louvain 算法(最常用)
   ├── 优化模块度(Modularity)
   ├── 复杂度:O(n·log(n))
   ├── 适合大规模图
   └── Python: community_louvain.best_partition(G)

2. Label Propagation
   ├── 每个节点传播标签给邻居
   ├── 收敛后同标签 = 同社区
   ├── 速度最快但结果不稳定
   └── Python: nx.community.label_propagation_communities(G)

3. 基于度的简单方法(Dune 可实现)
   ├── 计算每个节点的入度和出度
   ├── 高出度节点 = 可能是分发中心
   ├── 高入度节点 = 可能是归集中心
   └── 两者结合 = 女巫集群的"母钱包"

集群评分规则:
├── 集群大小 > 20 → 高度可疑(+40分)
├── 集群内交易时间标准差 < 10min → 脚本行为(+30分)
├── 集群内所有地址交互相同协议 → 空投农场(+20分)
├── 集群资金最终归集到 < 3 地址 → 确认女巫(+50分)
└── 集群内有 ENS/Gitcoin 验证用户 → 可能误判(-20分)

Task 3:可视化方案

可视化设计

女巫集群可视化方案:
═══════════════════════════════════════════════════════════

视图 1:集群总览(Force-Directed Graph)
├── 每个集群一个颜色
├── 节点大小 = 地址交易量
├── 边粗细 = 转账金额
├── 集群间距离 = 关联强度
└── 工具:D3.js / Gephi / Cytoscape

视图 2:集群详情
├── 选中一个集群 → 展开显示所有地址
├── 时间线:显示集群内交易时间分布
├── 资金流:Sankey 图显示资金流向
└── 标注:已知标签(CEX/合约/ENS)

视图 3:Dashboard 指标
├── 总发现集群数 / 涉及地址数
├── 集群大小分布(直方图)
├── 女巫地址占比趋势
└── 按风险等级分类统计

简化版(Dune 可实现):
├── 表格:Top 集群列表(大小/风险分/中心地址)
├── 柱状图:集群大小分布
├── 饼图:高/中/低风险占比
└── 时间线:集群活跃时间分布
═══════════════════════════════════════════════════════════

Python 可视化示例代码

# 伪代码 — 使用 NetworkX + Matplotlib

import networkx as nx
import community as community_louvain

# 1. 构建图
G = nx.DiGraph()
for row in dune_results:
    G.add_edge(row['sender'], row['receiver'],
               weight=row['total_eth'])

# 2. 社区检测
partition = community_louvain.best_partition(G.to_undirected())

# 3. 过滤大集群
cluster_sizes = {}
for node, cluster_id in partition.items():
    cluster_sizes[cluster_id] = cluster_sizes.get(cluster_id, 0) + 1

suspicious = {cid for cid, size in cluster_sizes.items() if size >= 10}

# 4. 输出可疑集群
for cid in suspicious:
    members = [n for n, c in partition.items() if c == cid]
    print(f"Cluster {cid}: {len(members)} addresses")

方向四完成总结

三个项目串联:
═══════════════════════════════════════════════════════════

实战 4.1 规则评分
  → 基于行为特征的自动评分系统
  → 产出:评分模型(高/中风险信号+正向信号)

实战 4.2 社区猎人
  → 人工审核和争议解决机制
  → 产出:举报流程+三层仲裁+审核系统PRD

实战 4.3 图分析
  → 基于地址关联的集群检测
  → 产出:图模型+聚类算法+可视化方案

三层防护体系:
  Layer 1:自动评分 → 过滤 60% 明显女巫
  Layer 2:社区举报 → 捕获 20% 隐蔽女巫
  Layer 3:图分析   → 发现 10% 关联集群
  总覆盖率目标:90%+

PM 核心能力验证:
  ✅ 能设计风控规则系统
  ✅ 能设计社区参与治理机制
  ✅ 能理解图分析在安全中的应用
═══════════════════════════════════════════════════════════

面试题准备

Q: 如何用链上数据识别女巫集群?

30 秒版本: 三步走 — (1) 构建图:以地址为节点,转账关系为边,构建地址关联图;(2) 聚类检测:用 Union-Find 或 Louvain 算法找到紧密关联的子图,大于 10 个地址的集群高度可疑;(3) 集群评分:检查集群内的行为同步性(时间标准差 < 10min)、协议交互一致性、资金归集模式。核心信号:如果 20 个地址从同一母钱包获得 Gas、在相同时间交互相同协议、最终资金归集到同一地址,99% 是女巫。


下一步

完成方向四后,推荐继续:

  • 方向五 项目 5.1:Rug Pull 预警系统设计
  • 方向六 项目 6.1:DEX 协议竞品对比

反欺诈和反女巫是安全的两面 — 女巫伤害公平,欺诈伤害资产。