Reactive Contract
Reactive Contract(睿应层)
概述:
与传统的智能合约(Smart Contracts)不同,传统智能合约只能在用户发起交易时才会执行,而 RC 则能够主动监控 EVM 兼容链上的事件并对此作出反应。RC 会根据合约中实现的逻辑来处理这些事件,并在区块链上自动执行后续操作。这种创新引入了一种去中心化的机制,可以在无需人工干预的情况下自动对链上事件作出响应。
在 Ethereum 的世界中,智能合约彻底改变了我们对无信任协议执行方式的理解。
传统情况下,智能合约只有在用户主动发送交易时才会被触发执行。
这种模式存在一些天然的限制:
- 智能合约无法自主发起操作
- 无法在没有外部触发的情况下响应链上的事件
因此必须依赖外部系统,例如:
- 用户手动发送交易
- 自动化脚本(例如交易机器人)
但这种方式带来了新的问题:
- 需要持有私钥
- 引入中心化控制点
Reactive Contracts(RC)正是为了解决这一限制而设计的。
RC 可以:
- 自主监听 EVM 中发生的事件
- 自动触发后续区块链操作
这使得开发者可以实现:
- 从多个链获取信息
- 在不同区块链之间执行逻辑
- 无需中心化控制
RC 能够在整个区块链生态系统中自动执行复杂逻辑和交易。
Reactive Contracts 的核心特征:
- RC 不仅响应用户的直接交易,还能响应跨 EVM 链的事件。
- 在事件发生后,它们可以执行链上操作,可能是在同一条链或其他链上
与预言机结合时,RC 可以对 链外事件(由预言机写入链上) 做出实时响应,并执行预先定义好的链上操作。这种 RC 与预言机的协作实现了对数字世界与现实世界的动态互动,大幅拓展了区块链应用的范围和功能。
RC的优势
1. 去中心化(Decentralization)
RC 在区块链上独立运行,消除了中心化控制点。
这样可以通过减少操控或单点故障的风险来提升系统安全性。
2. 自动化(Automation)
RC 可以在链上事件发生时自动执行智能合约逻辑。
这带来的好处包括:
- 减少人工干预
- 提供实时自动响应
3. 跨链互操作性(Cross-Chain Interoperability)
RC 可以与多个区块链交互。
这意味着可以实现:
- 复杂的跨链逻辑
- 构建连接不同网络的应用
4. 更高的效率与功能性
通过对实时数据作出反应,RC 可以提升智能合约的效率,并支持更多高级功能,例如:
- 复杂金融工具
- 动态 NFT
- 创新的 DeFi 应用
例如在 Ethereum 上运行的 DeFi 协议 Uniswap 就可以通过 RC 实现更自动化的交易逻辑。
5. 推动 DeFi 及更多领域创新
RC 为 DeFi 以及其他区块链应用开启了新的可能性,例如:
- 自动化交易
- 动态治理系统
从而打造一个更加响应式和互联的区块链生态系统。
RC的劣势
Reactive Contract 无法阻止触发事件的交易,只能在事件发生后执行新的交易来响应或补救。
换句话说,Reactive Contract 不能阻止、取消、修改交易,RC只能监听事件、自动触发交易、自动执行策略。
==Reactive Network 可以理解为一种 去中心化的链上自动化执行网络,其功能类似自动化 bot,但由去中心化节点网络执行。==
RC 与传统智能合约的区别
RC 与传统智能合约的主要区别在于 “反应性(Reactivity)”。
传统智能合约是被动的(Passive):
- 只有在 EOA(Externally Owned Account) 发起交易时才会执行。
而 Reactive Contracts 是主动的(Reactive):
- 持续监控区块链
- 监听感兴趣的事件
- 在检测到事件时 自动执行预定义的区块链操作
控制反转(Inversion of Control)
理解 RC 的一个关键概念是 控制反转(IoC)。
传统智能合约采用的是 直接控制模型:
- 合约函数的执行由外部参与者触发,例如:
- 用户(EOA)
- 自动化机器人(bot)
而 RC 反转了这种控制关系:
- 合约根据预定义事件的发生来决定何时执行。
这种 IoC 模式改变了应用与区块链交互的方式,使系统更加:
- 动态
- 自动化
- 响应式
没有 RC 时的情况
如果没有 Reactive Contract,你通常需要创建一个额外的实体(例如一个机器人 bot):
该 bot 会:
- 监控区块链
- 使用某些数据服务(通常是中心化的)
- 持有私钥
- 从自己的 EOA 地址发起交易
这种系统确实有用,但存在一些问题:
- 需要托管私钥
- 引入中心化组件
- 某些场景下并不适合
IoC 的优势
通过 控制反转,我们可以避免运行那些“模拟人类签名交易”的额外实体。
如果你已经定义好了:
某个链上事件发生后需要执行的一系列交易逻辑
那么这些逻辑应该能够 完全去中心化地运行,因为:
- 输入数据在链上
- 输出结果也在链上
Reactive Network 为智能合约提供了一个过去一直缺失的重要能力:
自动执行能力
即:
- 不需要人
- 不需要 bot
- 不需要签名交易
只需要 其他链上事件触发即可执行。
开发者无需运行 bot 或持有私钥,Reactive Network 节点会自动代表 RC 提交交易。
Reactive Contract 内部发生了什么
创建 Reactive Contract 时,首先需要指定:
- 要监听的 区块链
- 要监听的 合约地址
- 要监听的 事件(topic0)
RC 会持续监控这些地址,当检测到指定事件时就会执行。
这些事件可能包括:
- ETH 转账
- Token 转账
- DEX 交易
- 借贷
- 闪电贷
- 投票
- 巨鲸转账
- 任何智能合约活动
事件触发后的流程
当 RC 检测到相关事件后:
Reactive Network 会自动执行 RC 中实现的逻辑。
执行内容可能包括:
- 根据事件数据进行计算
- 更新合约状态
RC 是 有状态的(stateful),意味着:
- 可以存储数据
- 可以更新数据
- 可以累积历史信息
因此可以实现:
- 长期数据统计
- 基于历史数据 + 新事件的决策逻辑
执行结果
在事件处理过程中:
- RC 更新自己的状态
- RC 可以在 EVM 链上发起交易
整个过程:
- 在 Reactive Network 中完成
- 无需信任
- 自动执行
- 快速可靠
事件(Events)与回调(Callbacks)的工作原理
在 Ethereum 中,事件(Events) 允许智能合约在满足特定条件时记录信息,从而与外部世界进行通信。这使得 去中心化应用(dApps) 能够在某些事件发生时触发响应,而无需持续轮询区块链。事件会被 EVM 进行索引,因此可以非常容易地搜索和过滤。这对于监控区块链活动非常有用,例如:
- Token 转账
- 合约状态更新
- 来自预言机的价格变化
ReactVM 执行环境
Reactive Contracts 在 ReactVM 中运行。
ReactVM 的特点:
- 私有执行环境
- 只能与同一部署者部署的合约交互
这样可以确保:
- 执行环境安全
- 合约隔离
向目标链发送 Callback
Reactive Contracts 可以通过 Callback 事件 发起跨链交易。
流程:
- RC 触发 Callback
- Reactive Network 监听该事件
- Network 在目标链发送交易
Callback 事件参数
1 | event Callback( |
Callback 需要提供:
- chain_id:目标链 ID(EIP-155)
- _contract:目标合约地址
- **gas_limit **:目标交易 gas
- payload:编码后的函数调用数据
Callback 处理过程
例如:
1 | bytes memory payload = |
流程:
当 Callback 事件被触发后:
Reactive Network 会:
- 读取 payload
- 解析交易数据
- 在目标链提交交易
1 | react() |
关于授权的重要说明
为了安全性(防止 RC 伪造地址调用):
Reactive Network 会自动:
用 RVM ID 替换 payload 中前 160 bit 的参数。
这样可以确保目标合约能够识别调用来源是 ReactVM,而不是用户伪造的地址。
RVM ID:
- 等价于 ReactVM 地址
- 与合约部署者地址相同
因此:回调函数的 第一个参数永远是 ReactVM 地址,无论你在 Solidity 中如何命名。
ReactVM 与 Reactive Network —— 双状态环境
Reactive Contracts 在两个独立环境中同时存在,并拥有两个不同的状态。
Reactive Network 与 ReactVM 的区别
每一个 Reactive Contract 都有 两个实例:
- 一个在 Reactive Network 执行 subscription
- 一个在 ReactVM 处理 react()
需要注意:
- 两个实例都会在每个网络节点上物理存储并运行
- 两个实例拥有 相同代码
- 但拥有 不同状态
并行化RC是一个架构决策,旨在确保即使事件数量庞大也能保持高性能。
Reactive Network
Reactive Network 的结构类似于普通的 Ethereum EVM 区块链,但增加了系统合约。
这些系统合约可以:
- 订阅事件
- 取消订阅事件
监听来源链,例如:
- Ethereum
- BNB Chain
- Polygon
- Optimism
执行环境:响应式合约可以使用所有标准的 EVM 功能。然而,它们运行在一个私有的 ReactVM 中,这限制了它们只能与同一部署者部署的合约进行交互。每个部署者地址都会拥有:
一个专属 ReactVM
Reactive Network 会持续监控事件日志,并将这些日志与响应式合约中定义的订阅条件进行匹配。当检测到符合条件的事件时,网络会触发 react() 方法,并将相关的事件信息作为参数传入。
ReactVM
ReactVM 是一个 受限制的虚拟机,专门用于在隔离环境中处理事件。从同一个地址部署的合约会在同一个 ReactVM 中执行。它们可以彼此交互,但不能与 Reactive Network 上的其他合约交互。
特点:
- 用于处理事件
- 运行环境隔离
规则:
- 同一地址部署的合约 → 在同一个 ReactVM 中运行
- 可以互相调用
- 不能调用 Reactive Network 上其他部署者的合约
ReactVM 与外界交互的两种方式
同一个ReactVM 中的合约可以通过 Reactive Network 与外部世界交互:
1 监听事件
ReactVM 会:
- 监听已订阅事件
- 当事件发生时执行代码
2 发起 Callback
根据事件输入执行代码后:
ReactVM 会请求 Reactive Network:
- 向目标链发送 Callback
- 执行链上交易
双状态架构
每个 Reactive Contract:
- 代码相同
- 状态不同
| 环境 | 状态 |
|---|---|
| Reactive Network | Network State |
| ReactVM | VM State |
因此每个函数必须明确:在哪个环境执行
如何识别执行环境
执行环境由变量 vm 决定。
项目中需要继承AbstractReactive
detectVm() 函数
系统通过检查一个系统合约地址来判断环境:
1 | function detectVm() internal { |
判断逻辑
检查地址:0x0000000000000000000000000000000000fffFfF,情况:
Reactive Network
1 | 该地址存在代码 |
ReactVM
1 | 该地址没有代码 |
限制执行环境
使用 modifier 控制函数执行环境。
Reactive Network 专用函数
1 | modifier rnOnly() { |
只允许该函数在Reactive Network执行。
ReactVM 专用函数
1 | modifier vmOnly() { |
只允许该函数在ReactVM执行。
双变量状态管理
在 Reactive 架构中,每个已部署的合约可以运行在两种不同的运行状态中:
1 Reactive Network State
负责:
- 与系统合约交互
- 订阅事件
使用用于注册和管理事件订阅所需的变量和方法,变量来自AbstractReactive,包括:
servicevmservice.subscribe()
2 ReactVM State
负责:
- 执行业务逻辑
- 处理事件
变量由合约自己定义。
为了适应这两种状态,需要维护两套概念上的变量集合:
- 一套位于 基础合约(面向网络的合约上下文) 中
- 另一套位于 ReactVM 上下文 中
在这个新的示例中:
- Reactive Network 的变量来自继承的
AbstractReactive合约 - ReactVM 的变量则是在响应式合约本身中声明的
交易执行模型
Reactive Contract 中存在两类交易:Reactive Network 交易、ReactVM 交易
Reactive Network 交易
Reactive Network 中交易有两种来源:
1 用户触发
用户可以调用反应式网络的 RC 实例的方法来执行管理功能或更新合同状态。
例如:暂停事件订阅可以通过调用pause()函数实现:
1 | function pause() external rnOnly onlyOwner |
执行流程:
- 获取订阅列表
- 调用
service.unsubscribe()取消事件监听。
pause()函数防止RC对事件作出反应,取消订阅,从而有效阻止后续事件驱动的交易,直到事件恢复。
resume()
恢复监听:service.subscribe()
resume() 函数会重新订阅这些相同的事件,以便在新事件出现时 RC 继续响应
2 事件触发
即使用户没有发送交易,Reactive Network 也会:
- 监听源链事件
- 分发给 ReactVM
- ReactVM 执行逻辑
ReactVM 交易
ReactVM 中的交易, 用户无法直接调用,只能通过事件触发:
1 | Origin Chain Event |
react() 作用
- 更新状态
- 执行业务逻辑
- 发送 Callback
Callback 触发跨链交易
Callback 可以:
- 在其他链执行交易
- 自动触发
无需用户操作。
订阅事件(Event Subscription)
Reactive Network 的核心能力就是 **订阅事件 (Event Subscription)**。Reactive Contract 不会直接调用目标链。而是emit Callback(...),由 Reactive Network 去执行。
Reactive Contract 可以:
1 | 订阅某个链上事件 |
结构:
1 | Origin Chain (如 Sepolia) |
所以核心流程:
- 订阅事件
- 事件发生
- react() 被触发
- 执行 callback
订阅是通过 Reactive Network System Contract 完成的:
接口:
1 | interface ISubscriptionService { |
常见订阅方式
Wildcard(通配符)
Reactive Network 支持通配:
| 值 | 含义 |
|---|---|
| address(0) | 任意合约 |
| uint256(0) | 任意 chain |
| REACTIVE_IGNORE | 任意 topic |
例如:topic_1 = REACTIVE_IGNORE
表示匹配任何 topic1
1 监听某个合约的所有事件
1 | service.subscribe( |
含义:监听这个合约的所有事件
2 监听某种 Event
例如:UniswapV2 Sync 的topic0:0x1c411e9a96e07124...
1 | service.subscribe( |
含义:监听所有合约的 Sync 事件
3 同时限制 合约 + 事件
1 | service.subscribe( |
含义:监听某个 pair 的 Sync
react() 函数
用于处理传入事件通知的关键函数。react()只能被 Reactive Network 调用
该函数接收一个 LogRecord 作为输入,使得响应式合约(reactive contracts)能够动态地处理事件日志。
Reactive Contract 必须实现:function react(LogRecord calldata log) external{}
当事件发生时,Reactive Network 会调用react(log)
1 | function react(LogRecord calldata log) external vmOnly { |
根据 topic0 判断是什么事件
动态订阅 (Dynamic Subscription)
Reactive Contract 可以根据事件动态修改 subscription
例如:
1 | 用户订阅 |
实现:subscribe()、unsubscribe()
构造函数订阅(Constructor Subscribtion)
1 | // State specific to reactive network instance of the contract |
Subscription 限制
Reactive Network 为了效率限制很多规则。
不支持:
至少有一个标准必须是具体的数值,以确保有意义的订阅。
- 范围 ,例如
amount > 100。 - OR ,例如
topic1 == A OR B - 集合 ,例如
topic in [A,B,C]
订阅不能使用 <、>、区间或按位运算来匹配事件参数,只能使用严格的等值匹配。
订阅不能在单次订阅中使用“或”条件或多值集合。虽然多次调用 subscribe() 可以实现类似功能,但可能导致组合爆炸(combinatorial explosion)。
只支持
严格等于topic1 == X
禁止的订阅
由于数据量太大,以下订阅 不允许:
不允许同时订阅所有链或所有合约的事件。只订阅单条链上的所有事件也不允许,因为被认为是不必要的。
- 所有链
chain_id = 0 - 所有合约
contract = address(0) - 所有
eventtopic0 = ignore
技术上允许重复订阅,但它们只作为一次订阅生效。用户每次发送交易给系统合约都要付费。由于 EVM 存储限制,在系统合约中防止重复订阅成本高昂,因此允许重复订阅以降低费用。
unsubscribe 为什么贵
取消订阅(Unsubscribing)是一项开销较大的操作,因为需要搜索并删除已有的订阅记录。允许存在重复或重叠的订阅,但客户端必须确保操作具有幂等性(idempotency)。
取消订阅需要:
- 查找 subscription
- 删除 storage
所以gas expensive
Examples
- 订阅特定合约的所有事件
你可以订阅来自0x7E0987E5b3a30e3f2828572Bb659A548460a3003的特定合约中所有事件。
1 | service.subscribe( |
- 订阅特定事件主题(Uniswap V2 Sync)
你可以订阅所有Uniswap V2 Sync 事件,其 topic_0 为:
0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1
1 | service.subscribe( |
- 组合参数
你可以将参数组合,订阅特定合约的特定事件:
1 | service.subscribe( |
- 处理来自不同来源的多个事件
要响应来自不同来源的多个事件,可以在构造函数中调用多次 subscribe:
1 | constructor( |
Gas 与费用模型
Reactive Contracts 在执行 callback 时需要支付 gas。费用来源是RC的合约余额。
流程:
1 | 事件触发 |
如果余额不足,callback 不会执行
核心代码:
ISubscriptionService(事件订阅服务接口)
1 | pragma solidity >=0.8.0; |
- chain_id:一个
uint256类型的值,表示事件来源链的 EIP-155 链 ID。 - _contract:在源链(origin chain)上触发该事件的合约地址。
- topic_0、topic_1、topic_2、topic_3:事件日志中的 topics,类型为
uint256。
IReactive Interface(反应接口)
1 | pragma solidity >=0.8.0; |
结构化数据类型 LogRecord:用于存储事件日志(event log)的详细信息
- chain_id:事件来源区块链的 ID。
- _contract:触发该事件的合约地址。
- topic_0 到 topic_3:日志中的索引主题(indexed topics)。
- data:事件日志中的非索引数据(non-indexed data)。
- block_number:事件发生所在区块的区块号。
- op_code:可能表示某种操作码(operation code)。
- block_hash、tx_hash 和 log_index:用于追踪事件来源及其上下文的附加标识信息。
Callback 事件(Callback Event): 这是一个用于通知订阅者某些特定事件发生的事件
- chain_id:事件所属区块链的 ID。
- _contract:触发该事件的合约地址。
- gas_limit:为回调(callback)分配的最大 gas 限制。
- payload:回调时附带的编码数据(encoded data)。
react() 函数逻辑
1 | // Methods specific to ReactVM contract instance |
pause()函数逻辑
1 | function pause() external rnOnly onlyOwner { |
- rnOnly:确保只有 Reactive Network 才能调用这个函数。
- onlyOwner:限制只有 合约所有者(owner) 才能调用该函数。
- **service.unsubscribe()**:用于取消订阅,使该合约不再监听特定事件(这些事件由
chain_id、topic_0等参数定义)。
resume()函数逻辑
1 | function resume() external rnOnly onlyOwner { |
- rnOnly:确保只有 Reactive Network 才能调用这个函数。
- onlyOwner:限制只有 合约所有者(owner) 才能调用该函数。
- **service.subscribe()**:用于重新订阅,使该合约继续监听特定事件(这些事件由
chain_id、topic_0等参数定义)。