SubQuery开发者指南丨映射(Mapping)

fffmCQ.jpg

SubQuery开发者指南丨映射(Mapping)

SubstrateBlock 是 signedBlock 的扩展接口类型,但还包括 specVersion 和 timestamp。

事件处理程序(Event Handler)

当一些事件包含在一个新块中时,你可以使用事件处理程序来捕获信息。 该事件是默认 Substrate 运行时间组成部分,一个块可能包含多个事件。

处理过程中,事件处理程序将接收一个 Substrate 事件作为参数,带有事件已键入的输入和输出。 任何类型的事件都会触发映射,导致产生捕获数据源的活动。 你应该在清单中使用映射过滤器(Mapping Filtershttps://doc.subquery.network/create/manifest.html#mapping-filters)来过滤事件,减少索引数据所需的时间,并提高映射性能。

import {SubstrateEvent} from "@subql/types";


export async function handleEvent(event: SubstrateEvent): Promise<void> {
    const {event: {data: [account, balance]}} = event;
    // Retrieve the record by its ID
    const record = new starterEntity(event.extrinsic.block.block.header.hash.toString());
    record.field2 = account.toString();
    record.field3 = (balance as Balance).toBigInt();
    await record.save();

SubstrateEvent 是 EventRecord 的扩展接口类型,除了事件数据之外,它还包括一个 id(这个事件所属的块)和这个块的外来内部信息。

调用处理程序(Call Handler)

当你想要捕获一些 Substrate 外来上链信息时,会使用到调用处理程序。

export async function handleCall(extrinsic: SubstrateExtrinsic): Promise<void> {
    const record = new starterEntity(extrinsic.block.block.header.hash.toString());
    record.field4 = extrinsic.block.timestamp;
    await record.save();
}

SubstrateExtrinsic(substrate 外来上链信息), 扩展 GenericExtrinsic(泛型外来上链信息) 它被分配一个 id(该外来上链信息所属的块),提供外部属性扩展这个块之间的事件。 此外,它还记录了外来上链信息的成功状态。

查询状态(Query States)

我们的目标是覆盖用户用于映射处理程序的所有数据源(不仅仅是上述三种接口事件类型)。因

此,我们公开了一些@polkadot/api 接口以增加功能。

这些是我们目前支持的接口:

api.query.<module>.<method>() (打开新窗口/opens new window)

will query the current block./将查询当前块。

api.query.<module>.<method>() 将查询当前块。

api.query.<module>.<method>.multi() (opens new window/打开新窗口/)

will make multiple queries of the same type at the current block.

api.query.<module>.<method>.multi() 将在当前块进行多个相同类型的查询。

api.queryMulti() (opens new window/打开新窗口)

will make multiple queries of different types at the current block.

api.queryMulti() 将在当前块进行不同类型的多个查询。

这些是我们目前不支持的接口:

  • api.tx.*
  • api.derive.*
  • api.query.<module>.<method>.at
  • api.query.<module>.<method>.entriesAt
  • api.query.<module>.<method>.entriesPaged
  • api.query.<module>.<method>.hash
  • api.query.<module>.<method>.keysAt
  • api.query.<module>.<method>.keysPaged
  • api.query.<module>.<method>.range
  • api.query.<module>.<method>.sizeAt

在我们的验证器阈值示例中查看使用此 API 的示例(打开新窗口)https://github.com/subquery/tutorials-validator-threshold 示例适用案例

RPC 调用(RPC calls)

我们还支持一些 API RPC 方法,这些方法是远程调用,允许映射函数与实际节点、查询和提交进行交互。 SubQuery 的一个核心前提是它是确定性的,因此,为了保持结果一致,我们只允许历史 RPC 调用。

JSON-RPC 中的文档(打开新窗口)https://polkadot.js.org/docs/substrate/rpc/#rpc,提供一些将 BlockHash 作为输入参数的方法(例如 at?: BlockHash),这些方法现在是允许的。 我们还修改了这些方法以默认采用当前索引块哈希。

对于自定义Substrate链 RPC 调用,请参阅用法 https://doc.subquery.network/create/mapping/#usage

模块和库(Modules and Libraries)

为了提高 SubQuery 的数据处理能力,我们允许 NodeJS 的一些内置模块在沙箱中运行映射函数,并允许用户调用第三方库。

请注意,这是一项实验性功能,你可能会遇到可能对您的映射功能产生负面影响的错误或问题。 请通过在 GitHub(https://github.com/subquery/subql)中创建问题来报告发现的任何错误。

内置模块(Built-in modules)

目前,我们允许使用以下 NodeJS 模块:assert、buffer、crypto、util 和 path。

我们建议只导入您需要的必需方法,而不是导入整个模块。 这些模块中的某些方法可能具有不受支持的依赖项,并且会在导入时失败。

import {hashMessage} from "ethers/lib/utils"; //Good way
import {utils} from "ethers" //Bad way


export async function handleCall(extrinsic: SubstrateExtrinsic): Promise<void> {
    const record = new starterEntity(extrinsic.block.block.header.hash.toString());
    record.field1 = hashMessage();
    await record.save();
}

第三方库(Third-party libraries)

由于我们沙箱中虚拟机的限制,目前我们只支持由 CommonJS 编写的第三方库。

我们还支持像 @polkadot/* 这样的混合库,它默认使用 ESM。 但是,如果任何其他库依赖于 ESM 格式的任何模块,虚拟机将不会编译并显示错误。

自定义Substrate链(Custom Substrate Chains)

SubQuery 可用于任何基于 Substrate 的链,而不仅仅是 Polkadot 或 Kusama。

您可以使用自定义的基于 Substrate 的链,我们提供了使用 @polkadot/typegen 自动导入类型、接口和其他方法的工具

在以下部分中,我们使用我们的 kitty (https://github.com/subquery/tutorials-kitty-chain) 示例解释集成过程。

准备(Preparation)

在项目 src 文件夹下创建一个新目录 api-interfaces 以存储所有必需和生成的文件。 我们还创建了一个 api-interfaces/kitties 目录,因为我们想从 kitties 模块在 API 中添加修饰。

元数据(Metadata)

我们需要元数据来生成实际的 API 端点。 在 kitty 示例中,我们使用了来自本地测试网的端点,它提供了其他类型的端点。 按照 PolkadotJS 元数据设置中的步骤操作,来从其 HTTP 端点检索一个节点的元数据。

curl -H "Content-Type: application/json" -d  http://localhost:9933

或利用websocat形成websocket端

//Install the websocat
brew install websocat


//Get metadata
echo state_getMetadata | websocat  --jsonrpc

然后,复制黏贴输出到 JSON 文件,在我们 kitty 示例中,我们创建了 api-interface/kitty.json.

键入定义(Type definitions)

我们假定用户知道具体类型和来自区块链的RPC支持,并在清单中定义。

使用类型设置,我们创建:

  • src/api-interfaces/definitions.ts – this exports all the sub-folder definitions
export { default as kitties } from ;
  • src/api-interfaces/kitties/definitions.ts – type definitions for the kitties module
export default {
    // custom types
    types: {
        Address: "AccountId",
        LookupSource: "AccountId",
        KittyIndex: "u32",
        Kitty: "[u8; 16]"
    },
    // custom rpc : api.rpc.kitties.getKittyPrice
    rpc: {
        getKittyPrice:{
            description: ,
            params: [
                {
                    name: ,
                    type: ,
                    isHistoric: true,
                    isOptional: false
                },
                {
                    name: ,
                    type: ,
                    isOptional: false
                }
            ],
            type: 
        }
    }
}

包(Packages)

  • 在package.json文件中,确保加上 @polkadot/typegen 作为开发依赖项,加上 @polkadot/api 作为常规依赖项 (最好是相同版本)。我们还需要 ts-node 作为开发依赖项帮助我们运行脚本。
  • 我们加上 脚本运行2种类型:generate:defs 和metadata generate:meta 生成器 (此命令下,元数据可使用这些类型)。

下面是package.json的简化版本。确保脚本的包名是正确的,目录是有效的。

{
  "name": "kitty-birthinfo",
  "scripts": {
    "generate:defs": "ts-node --skip-project node_modules/.bin/polkadot-types-from-defs --package kitty-birthinfo/api-interfaces --input ./src/api-interfaces",
    "generate:meta": "ts-node --skip-project node_modules/.bin/polkadot-types-from-chain --package kitty-birthinfo/api-interfaces --endpoint ./src/api-interfaces/kitty.json --output ./src/api-interfaces --strict"
  },
  "dependencies": {
    "@polkadot/api": "^4.9.2"
  },
  "devDependencies": {
    "typescript": "^4.1.3",
    "@polkadot/typegen": "^4.9.2",
    "ts-node": "^8.6.2"
  }
}

键入生成(Type generation)

现在已完成准备,可以生成类型和元数据。运行以下命令:

# Yarn to install new dependencies
yarn


# Generate types
yarn generate:defs

每个模块文件夹(eg /kitties),应有已生成的types.ts 可以定义按照该模块定义的所有接口,且文件 index.ts可以全部将他们导出。

# Generate metadata
yarn generate:meta

该命令将生成元数据和新的针对 API 的 api- 函数。由于我们不想使用内置的 API, 我们需要在我们的 tsconfig.json.添加明确的覆盖来取代他们。更新后,配置种的路径如是(无备注):

{
  "compilerOptions": {
      // this is the package name we use (in the interface imports, --package for generators) */
      "kitty-birthinfo/*": ["src/*"],
      // here we replace the @polkadot/api augmentation with our own, generated from chain
      "@polkadot/api/augment": ["src/interfaces/augment-api.ts"],
      // replace the augmented types with our own, as generated from definitions
      "@polkadot/types/augment": ["src/interfaces/augment-types.ts"]
    }
}

用法(Usage)

现在,在映射函数中,我们可以展示元数据和类型是如何装饰API的。RPC端点将支持我们上述模块和方法。要使用自定义rpc调用,请参阅自定义链 rpc 调用一节

export async function kittyApiHandler(): Promise<void> {
    //return the KittyIndex type
    const nextKittyId = await api.query.kitties.nextKittyId();
    // return the Kitty type, input parameters types are AccountId and KittyIndex
    const allKitties  = await api.query.kitties.kitties(,123)
    logger.info(`Next kitty id ${nextKittyId}`)
    //Custom rpc, set undefined to blockhash
    const kittyPrice = await api.rpc.kitties.getKittyPrice(undefined,nextKittyId);
}

如果你想将这个项目发布到我们的资源管理器中,请在 src/api-interfaces 中该包含生成文件。

自定义链 rpc 调用(Custom chain rpc calls)

为了支持自定义链 RPC 调用,我们必须手动为 typesBundle 注入 RPC 定义,允许按规格进行配置。你可以在 project.yml 中定义 typesBundle。请记住,只支持历史类型的调用。

...
  types: {
    "KittyIndex": "u32",
    "Kitty": "[u8; 16]",
  }
  typesBundle: {
    spec: {
      chainname: {
        rpc: {
          kitties: {
            getKittyPrice:{
                description: string,
                params: [
                  {
                    name: ,
                    type: ,
                    isHistoric: true,
                    isOptional: false
                  },
                  {
                    name: ,
                    type: ,
                    isOptional: false
                  }
                ],
                type: "Balance",
            }
          }
        }
      }
    }
  }
声明:该文观点仅代表作者本人,与炒币网无关。炒币网系信息发布平台,仅提供信息存储空间服务。对所包含内容的准确性、可靠性或者完整性不提供任何明示或暗示的保证,并不对文章观点负责。 提示:投资有风险,入市须谨慎。本资讯仅供参阅,不作为投资理财建议。

发表评论

登录后才能评论