L4

Oracle 预言机系统

Layer 1 原生预言机 - 将链外数据引入智能合约

概述
核心优势:Aeternity 的预言机是 Layer 1 原生协议,不同于以太坊上基于智能合约的 Chainlink 等 Layer 2 方案。

这意味着预言机对象(Oracles)和查询对象(Queries)是区块链状态树的一等公民,拥有:

  • 专用交易类型 - OracleRegisterTx, OracleQueryTx, OracleRespondTx, OracleExtendTx
  • 独立 Gas 定价 - 基于 TTL 的存储租赁模型
  • 自动状态修剪 - 过期数据自动清理,保持轻量级
核心架构
状态树设计 (State Tree)

Oracle 数据存储在全局状态树的专用子树中,由模块 aeo_state_tree 管理。

预言机对象 (Oracle Object)

存储预言机的元数据:

  • ID - 预言机唯一标识
  • TTL - 生存时间
  • query_fee - 查询费用
  • query_format - 问题格式
  • response_format - 响应格式
查询对象 (Query Object)

独立存储,Key 为 <<OracleId, QueryId>>

  • 高效查找特定预言机的所有查询
  • 避免大对象序列化开销
  • 支持 O(1) 复杂度过期清理
清理机制 (Pruning)

系统维护辅助的 Cache Tree,按"过期高度"索引所有对象:

%% 在每个区块生成前自动清理
aeo_state_tree:prune(Height, StateTree) ->
    %% 查询 Cache,O(1) 复杂度找到过期对象
    %% 批量删除过期的预言机和查询
    %% 防止状态膨胀
经济模型

Oracle 系统通过 TTL 和 Gas 费用进行自我调节:

存储租赁

注册和延长预言机需要支付与 TTL 成正比的 Gas 费用。TTL 越长,费用越高。

查询费用

查询者必须支付不低于预言机设定的 query_fee。费用在响应后转移给预言机所有者。

生命周期与交易

Oracle 的生命周期由四个核心交易驱动:

1. 注册 (Register) - OracleRegisterTx

功能:创建一个新的预言机身份

关键参数
  • query_format - 问题格式 (Sophia 类型签名)
  • response_format - 响应格式
  • query_fee - 服务定价
  • oracle_ttl - 初始生存时间
执行逻辑
  1. 检查账户是否已是预言机
  2. 验证 TTL 合法性
  3. 扣除 Gas 并写入状态树
// JavaScript SDK
const oracle = await aeSdk.registerOracle(
  "string",        // queryFormat
  "string",        // responseFormat  
  { queryFee: 30000, oracleTtl: { type: 'delta', value: 500 } }
);
2. 扩展 (Extend) - OracleExtendTx

功能:延长预言机的 TTL

  • 只能增加 TTL,不能减少
  • 没有协议级硬性上限(受限于 Gas Limit)
  • 必须由预言机所有者发起
// 续期预言机
await oracle.extendOracle({ oracleTtl: { type: 'delta', value: 1000 } });
3. 查询 (Query) - OracleQueryTx

功能:向预言机提问

执行流程
  1. 验证 query_fee 是否足够
  2. 生成唯一 QueryId(基于发送者 Nonce)
  3. 扣除费用并锁定在状态中
  4. 创建查询对象,状态为 open
TTL 参数
  • query_ttl - 等待回答的时间
  • response_ttl - 回答保留的时间
// 发起查询
const query = await oracleClient.query("What is the current BTC price?", {
  queryFee: 30000,
  queryTtl: { type: 'delta', value: 10 },
  responseTtl: { type: 'delta', value: 50 }
});
4. 响应 (Respond) - OracleRespondTx

功能:预言机提交答案

  1. 验证查询是否属于该预言机且处于 open 状态
  2. 写入 response 数据
  3. 将查询费用转移给预言机账户
  4. 更新查询对象的过期时间为 CurrentHeight + response_ttl
// 响应查询
await oracle.respondToQuery(queryId, "42000 USD");
智能合约交互
最大优势:Aeternity 的 Oracle 可以被智能合约(Sophia)直接调用
ABI 版本与类型检查
  • ABI Version:预言机在注册时声明 abi_version(如 ?ABI_FATE_SOPHIA_1
  • 查询验证:FATE 虚拟机验证查询数据是否符合 query_format
  • 响应验证:响应数据必须符合 response_format
Sophia 高层 API
// Sophia 合约中使用 Oracle
contract OracleConsumer =
  // 注册预言机
  stateful entrypoint register() : oracle(string, string) =
    Oracle.register(
      1000000000000000,  // query_fee (1 AE)
      RelativeTTL(1000)  // oracle_ttl
    )

  // 发起查询
  stateful entrypoint query(o : oracle(string, string), q : string) : oracle_query(string, string) =
    Oracle.query(
      o,
      q,
      1000000000000000,  // query_fee
      RelativeTTL(50),   // query_ttl
      RelativeTTL(50)    // response_ttl
    )

  // 响应查询
  stateful entrypoint respond(o : oracle(string, string), q : oracle_query(string, string), r : string) =
    Oracle.respond(o, q, r)

  // 获取响应(阻塞式)
  entrypoint get_answer(o : oracle(string, string), q : oracle_query(string, string)) : option(string) =
    Oracle.get_answer(o, q)
开发者最佳实践
TTL 策略

避免设置过长的 TTL。建议根据业务需求(如按月/按年)定期发送 ExtendTx 续期,以平摊 Gas 成本并保持灵活性。

查询费设置

query_fee 是防止垃圾查询(Spam)的第一道防线,应根据计算成本合理设置。

格式规范

强烈建议使用标准的 Sophia 类型描述字符串作为 Format,以便合约能无缝集成。

技术优势总结
原生集成

无需部署合约即可实现预言机功能,更省 Gas,更安全

自动清理

TTL 机制确保过时数据自动下链,保持轻量级

类型安全

结合 Sophia ABI,提供端到端的类型验证

学习路径