geth-智能合约调用
研究一下geth如何调用智能合约,如何拦截请求。
TEST_COIN: 0x258761046E2Bbf701cb1EEfdDA738EeF5F7e8bcB
StringTracker: 0x319b4b3b71398EABaDae47ccEA2e1e6be3e83056
RegulatoryContract:0x15bC1CE1Ef41D6B00D47693014BB3A8Bf83f4fc0
REG_COIN: 0xedbF11C56a3fAE725c6db115b903734dd0336E01
口头表述
现在我们监听以太坊上所有函数签名在敏感列表里的函数。但是这样仍有问题:
- 合约可以通过调用别的函数来触发交易,绕过敏感列表。
- 交易函数的参数各式各样,无法统一管理。(没有一个统一的办法返回交易函数的发送方、接收方、转账金额等)
所以决定按如下方法操作:
- 监管机构在区块链上发一个“监管合约”。监管合约的数据结构:
- white_list: map[address => bool],对应地址为true表示该合约通过了监管部门审查,允许放行。不为true则禁止任何人调用对应的合约。
- 敏感函数列表:一个合约地址对应一个数组,数组里存放该合约所有需要监管的敏感函数、和解析该函数的方式(如何根据参数推断出发送方、接收方、转账金额)。
- 例如:合约0x1234…是一个兼容ERC20的合约,其函数transfer(to address, amount uint256)是一个敏感函数,“解析方式”可以设计一种编码,表示{from: msg.sender, to: to, amount: amount}.
- riskScores: map[address => uint256],某个账户的风险指标。
- owner:监管合约所有者(监管机构)
- 以后,任何人在以太坊上部署新的合约时,都必须主动到监管合约里“注册”。
- 智能合约部署的时候,必须在构造函数里将自己的敏感函数列表和对应的解析方式发送给“监管合约”,存在监管合约的链上存储中。
- 之后等待监管机构审核,审核通过后,由监管合约所有者修改white_list,将该合约设置为 true
- 修改geth的源码,拦截所有外部调用。首先执行如下检查:
- 查看调用的合约是否在监管合约的白名单里。如否,则禁止后续操作。
- 查看调用的函数是否为敏感函数。如否,直接执行。
- 如果是敏感函数,获取该函数的解析方式,解析本次调用的发送方、接收方、转账金额。如果发送方的风险指标不为零,则根据某个函数
_calculateRiskScore,自动计算出一个新的风险指标给接收方记录上。(_calculateRiskScore的实现就写成接收方的score = max(0, 发送放的score - 1))
- 可以调用监管合约的 queryRisk() 函数查询某个账户的风险指标。(only Owner)
一句话概括
合约如果想在我们的私有链上有效,必须主动提交敏感函数注册表。监管机构审核通过后,合约才可以被调用。
敏感函数注册表的作用是:声明该合约中哪些函数涉及交易,以及如何根据参数解析出交易的发送者、接受者、金额。
所有合约都必须先到监管合约上进行注册。只有注册并通过审核的合约,才能在以太坊上执行。
注册时,合约将填写敏感函数表。以太坊evm在执行表中的敏感函数时,会自动解析交易的发送者、接受者、发送金额,用于后续风险传播计算。
重新整理的设计方案
监管架构概述
建立基于智能合约的去中心化监管体系,通过链上监管合约实现对所有合约交互的统一管控和风险评估。
- 监管合约数据结构
contract RegulatoryContract {
// 白名单:合约审核状态
mapping(address => bool) public whiteList;
// 敏感函数注册表:合约地址 => 敏感函数配置数组
mapping(address => SensitiveFunction[]) public sensitiveFunctions;
// 风险评分:账户地址 => 风险指标
mapping(address => uint256) public riskScores;
// 监管机构地址
address public owner;
struct SensitiveFunction {
bytes4 selector; // 函数选择器
string parseRule; // 解析规则编码
}
}
- 合约注册流程
- 新合约强制注册:新合约部署时必须在构造函数中调用监管合约的注册接口
- 信息提交:提交所有敏感函数的选择器和对应的参数解析规则
- 等待审核:监管机构验证合约代码和提交信息的一致性
- 白名单激活:审核通过后,监管机构将合约地址添加到白名单
- EVM层面拦截机制
在geth的EVM调用层面实现三级检查:
第一级:白名单验证
- 检查目标合约是否在监管合约白名单中
- 未通过审核的合约禁止被调用
第二级:敏感函数识别
- 查询目标合约的敏感函数注册表
- 普通函数直接放行,敏感函数进入风险评估
第三级:风险评估与传播
- 根据注册的解析规则提取交易参数(发送方、接收方、金额)
- 应用风险传播算法:接收方风险 = max(0, 发送方风险 - 1)
- 更新监管合约中的风险评分
-
风险传播算法
-
监管查询接口
完善后的监管架构设计
1. 监管合约数据结构
contract RegulatoryContract {
// 白名单:合约审核状态
mapping(address => bool) public whiteList;
// 敏感函数注册表:合约地址 => 敏感函数配置数组
mapping(address => SensitiveFunction[]) public sensitiveFunctions;
// 风险评分:账户地址 => 风险指标
mapping(address => uint256) public riskScores;
// 监管机构地址
address public owner;
struct SensitiveFunction {
bytes4 selector; // 函数选择器
string parseRule; // 解析规则编码
}
}
2. 双重注册机制
A. 新合约自主注册
function registerSensitiveFunctions(
SensitiveFunction[] calldata functions
) external {
// 合约只能注册自己的敏感函数
delete sensitiveFunctions[msg.sender];
for (uint i = 0; i < functions.length; i++) {
sensitiveFunctions[msg.sender].push(functions[i]);
}
emit SensitiveFunctionsRegistered(msg.sender, functions);
}
B. 监管机构手动注册(兼容历史合约)
function setSensitiveFunctions(
address contractAddr,
SensitiveFunction[] calldata functions
) external onlyOwner {
// 监管机构可以为任何地址设置敏感函数
delete sensitiveFunctions[contractAddr];
for (uint i = 0; i < functions.length; i++) {
sensitiveFunctions[contractAddr].push(functions[i]);
}
emit SensitiveFunctionsSet(contractAddr, functions);
}
3. 完整的注册流程
新合约注册流程
- 部署时注册:新合约在构造函数中调用
registerSensitiveFunctions() - 等待审核:监管机构验证注册信息与合约代码的一致性
- 白名单激活:审核通过后调用
setWhiteList(contractAddr, true)
历史合约兼容流程
- 监管机构分析:监管机构分析已部署合约的源码和ABI
- 手动注册:监管机构调用
setSensitiveFunctions()为历史合约注册敏感函数 - 直接审核:由于是监管机构直接操作,可以同时设置白名单状态
4. 权限控制矩阵
| 操作 | 合约自身 | 监管机构(Owner) | 其他地址 |
|---|---|---|---|
| 注册自己的敏感函数 | ✅ | ✅ | ❌ |
| 注册其他地址的敏感函数 | ❌ | ✅ | ❌ |
| 设置白名单 | ❌ | ✅ | ❌ |
| 查询风险评分 | ❌ | ✅ | ❌ |
5. 更新后的监管合约接口
-
合约自主注册接口
function registerSensitiveFunctions(SensitiveFunction[] calldata functions) external; -
监管机构管理接口
function setSensitiveFunctions(address contractAddr, SensitiveFunction[] calldata functions) external onlyOwner; function setWhiteList(address contractAddr, bool status) external onlyOwner; function setRiskScore(address account, uint256 score) external onlyOwner; -
查询接口
function isWhitelisted(address contractAddr) external view returns (bool); function getSensitiveFunctions(address contractAddr) external view returns (SensitiveFunction[] memory); function queryRisk(address account) external view onlyOwner returns (uint256);
6. 实施策略
渐进式部署
- Phase 1:部署监管合约,开始手动注册重要的历史合约(如主流DeFi协议)
- Phase 2:要求新部署的合约必须自主注册
- Phase 3:逐步扩大监管范围,覆盖更多历史合约
批量操作支持
function batchSetSensitiveFunctions(
address[] calldata contracts,
SensitiveFunction[][] calldata functions
) external onlyOwner {
require(contracts.length == functions.length, "Length mismatch");
for (uint i = 0; i < contracts.length; i++) {
setSensitiveFunctions(contracts[i], functions[i]);
}
}
7. 优势总结
- ✅ 向后兼容:历史合约可通过监管机构手动注册接入系统
- ✅ 自主性保持:新合约仍可自主注册,保持去中心化特性
- ✅ 渐进部署:可以分阶段实施,降低系统性风险
- ✅ 权限清晰:明确的权限控制,防止恶意操作
- ✅ 批量操作:支持批量处理,提高管理效率
老师我改了一下,加了一个合约层面的限制。
在我们私有链上的合约,必须主动提交敏感函数注册表。监管机构审核通过后,把合约加入白名单,合约才可以被调用。
敏感函数注册表的作用:声明该合约中哪些函数涉及交易,以及如何根据参数解析出交易的发送者、接受者、转账金额。
简单画了两个流程图。
现在代码已经跑通了,整体思路没问题的话就看之后怎么跑实验了。
现在要求私有链上的合约,必须主动提交敏感函数注册表,由监管机构审核通过后
合约如果想在我们的私有链上有效,必须主动提交敏感函数注册表。监管机构审核通过后,合约才可以被调用。
敏感函数注册表的作用是:声明该合约中哪些函数涉及交易,以及如何根据参数解析出交易的发送者、接受者、金额。