高级

预言机 (Oracle)

连接链上与链下数据的桥梁

概述

本指南展示如何使用 SDK 执行 Æternity 预言机生命周期中的所有操作。

预言机是链上与链下数据交互的桥梁,可以将外部世界的数据(如天气、价格、API 响应等)带入区块链。

1 注册预言机 (Register)

首先创建 Oracle 类实例。预言机地址与账户地址相同,只是前缀不同(ok_ 代替 ak_)。

import { AeSdk, Oracle, AccountMemory, ORACLE_TTL_TYPES } from '@aeternity/aepp-sdk';

const aeSdk = new AeSdk({ ... });
const oracleAccount = new AccountMemory(ORACLE_SECRET_KEY);

// 创建预言机实例
const oracle = new Oracle(oracleAccount, aeSdk.getContext());

// 注册预言机
// 第一个参数是查询格式,第二个是响应格式
await oracle.register(
  '{"city": "str"}',        // 查询格式
  '{"temperature": "int"}', // 响应格式
  {
    queryFee: 1337,                          // 查询费用(可选,默认 0)
    oracleTtlType: ORACLE_TTL_TYPES.delta,   // TTL 类型
    oracleTtlValue: 1000                     // 存活 1000 个区块
  }
);
TTL 说明:
  • delta: 从当前区块开始的相对区块数
  • block: 指定的绝对区块高度
  • 默认存活 500 个关键区块
2 查询预言机 (Query)

知道 oracleId 的任何人都可以查询预言机:

import { OracleClient, ORACLE_TTL_TYPES } from '@aeternity/aepp-sdk';

const oracleId = 'ok_...';

// 创建预言机客户端
const oracleClient = new OracleClient(oracleId, aeSdk.getContext());

// 查询并等待响应
const response = await oracleClient.query('{"city": "Berlin"}', {
  queryFee: 1337,                            // 查询费用
  queryTtlType: ORACLE_TTL_TYPES.delta,      // 查询 TTL 类型
  queryTtlValue: 20,                         // 查询有效期
  responseTtlType: ORACLE_TTL_TYPES.delta,   // 响应 TTL 类型
  responseTtlValue: 50,                      // 响应有效期
  interval: 6000                             // 轮询间隔(毫秒)
});

console.log('预言机响应:', response);
分步方式(发送查询 + 轮询响应)
// 只发送查询,不等待响应
const { queryId } = await oracleClient.postQuery('{"city": "Berlin"}');
console.log('查询 ID:', queryId); // oq_...

// 稍后轮询响应
const response = await oracleClient.pollForResponse(queryId);
console.log('响应:', response);
3 响应查询 (Respond)

预言机服务通常轮询自己的查询并尽快响应:

推荐方式:handleQueries
// 自动处理所有查询
const stopHandling = await oracle.handleQueries(
  (query) => {
    // 根据查询内容返回响应
    if (query.decodedQuery === '{"city": "Berlin"}') {
      return '{"temperature": 27}';
    }
    return '{"error": "Unknown city"}';
  },
  { interval: 1000 } // 轮询间隔(毫秒)
);

// 需要时停止处理
stopHandling();
分步方式
// 只轮询查询
const stopPolling = await oracle.pollQueries(
  (query) => {
    console.log('收到查询:', query);
  },
  { interval: 1000 }
);

// 手动响应特定查询
await oracle.respondToQuery(queryId, '{"temperature": 27}');
4 延长预言机 TTL (Extend)

在预言机过期前延长其生命周期:

// 从当前过期高度再延长 500 个区块
await oracle.extend({
  oracleTtlType: ORACLE_TTL_TYPES.delta,
  oracleTtlValue: 500
});
获取状态

OracleOracleClient 都提供获取状态的方法:

方法 说明
getState() 获取预言机状态(等同于 Node.getOracleByPubkey
getQuery(queryId) 获取特定查询详情,包含解码后的查询和响应
getQueries() 获取所有查询列表