狗哥区块链与AI精品内容集@NonceGeek

2025年03月28日更新 75 人订阅
原价: ¥ 20 限时优惠
专栏简介 「造」最关键的是什么?| Hackathon 漫游指南(贰) Why Hackathon?| Hackathon 漫游指南(壹) 设计「众人维护」的 BuidlerBoard | BeWater.xyz Movement 白皮书中文版 Rebuidl RSS 生产因素与反生产因素 | 独立黑客创业手册(陆) 组织 | 独立黑客创业手册(伍) 生产 | 独立黑客创业手册(肆) 销售 | 独立黑客创业手册(叄) 最优先的能力 | 独立黑客创业手册(贰) 为什么从独立黑客开始 | 独立黑客创业手册(壹) Aptos Token Object V2 | Move dApp 极速入门(贰拾肆) 可編程交易塊 | Move dApp 極速入門(貳拾叁) Aptos 密鑰輪換 | Move dApp 極速入門(貳拾貳) Aptos 对象模型 | Move dApp 极速入门(贰拾壹) Aptos Moveflow SDK使用指南 | Move dApp 极速入门(贰拾) Sui 上简单 Swap 的实现 | Move dApp 极速入门(拾玖) 用 Elixir 交互 Aptos | Move dApp 极速入门(拾捌) Sui 链上数据查询 | Move dApp 极速入门(拾柒) SUI 合约测试攻略 | Move dApp 极速入门(拾陆) Sui 数据类型详解 | Move dApp 极速入门(拾伍) Airdropper Contract in Aptos | Move dApp 极速入门(拾肆) Sandwich合约源码解析 | Move dApp 极速入门(拾叁) Sui 极速上手 | Move dApp 极速入门(拾贰) scaffold-aptos 脚手架 | Move dApp 极速入门(拾壹) 对 DID Document 的思考 | Move dApp 极速入门(九) DID中地址聚合器的实现 | Move dApp 极速入门(八) 值的存取应用3.0 | Web3.0 dApp 开发(五) 合约数据类型综述 | Move dApp 极速入门(四) 操作资源 | Move dApp 极速入门(三) 第一个 Move dApp | Move dApp 极速入门(二) Hello Move | Move dApp极速入门(一) Staker | Web3.0 dApp 开发(九) Token 自动售卖机 | Web3.0 dApp 开发(七) SVG NFT 全面实践 | Web3.0 dApp 开发(六) 值的存取应用2.0 | Web3.0 dApp 开发(四) 值的存取应用1.0 | Web3.0 dApp开发(三) Scaffold-eth 快速上手 | Web3.0 dApp 开发(二) eth.build 快速上手 | Web3.0 dApp 开发(一) 1 小时理解比特币系统 【NonceGeek Workshop 0x01总结】基于链上数据生成游戏地图 Remix 完全本地化部署 NFT:实体与虚拟载体的主与辅 | 狗哥的元宇宙思辨(一) Web3Camp 内容大全@NonceGeek 用 Python 创建一条 Pow 区块链(上) 区块链与共识机制演变史 基于 Etherscan 实现 Blockchain Syncer 【论文分享】去中心化社会:寻找 Web3 的灵魂(上) 【论文分享】去中心化社会:寻找 Web3 的灵魂(下) Ted Yin | 2021 年的区块链基础设施将是什么? 0. 公链、联盟链与分布式未来(全文) 基于 Infura 与 Web3py 部署调用 Hello 合约全过程 | 以太坊开发极速入门 太上中的基因设计与Binary | 函数式与区块链(一) 理解以太坊合约数据读取过程 | 函数式与区块链(二) Hello, Ink! | 用 Rust 写智能合约(一) Mapping 数据结构 | 用 Rust 写智能合约(二) 用 Rust 程序和 Webase 交互 | Rust 学习笔记(四) 用 Sqlite 存储 WeId | Rust 学习笔记(五) 链上注册WeId与错误处理 | Rust 学习笔记(六) WeId 链上创建与本地存储的完整闭环 | Rust 学习笔记(七) 以太坊上的核心开发者 Austin | 以太坊上的最佳开发实践 1. FISCO BCOS 开发环境节点搭建全攻略 伪代码简述 ECDSA 签名过程 | 联盟链开发 WeIdentity 源码分析 | 狗哥解码 WeIdentity 源码分析 | 狗哥解码 FISCO BCOS 介绍 | 联盟链开发 给Remix升个级 | 联盟链开发 2. 控制台的安装与使用 3. 【实验】补全一个区块链应用 4. 控制台的Web化 5. Web化控制台2.0:打造团队共用区块链学习平台 6. 使用脚手架快速搭建 Java DApp 【视频+文字】分布式思维 Rebuidl RSS (EN)

Sui 链上数据查询 | Move dApp 极速入门(拾柒)

  • 李大狗
  • 发布于 2023-08-20 12:21
  • 阅读 4840

如何查询 Sui 的链上数据?

示例代码见: https://github.com/NonceGeek/Web3-dApp-Camp/tree/main/move-dapp/sui/sui-data-fetch

0x01 通过ID / address直接查询

Related Link:

https\://docs.sui.io/sui-jsonrpc#sui_getObject

在sui中查询数据最直接的方式就是通过Object Id获取object信息。

import { JsonPrcProvider } from '@mysten/sui.js'
const provider = new JsonRpcProvider();
// 查询单个对象数据
const objectId = '0xd7d27a9a68c11b9035be08428feceea9bf374510';
provider.getObject(objectId);

// 查询多个对象数据
const objectIds = [
  '0x9177ffd1ab19b7dfe6323f2674fb58c29c75bf7a',
  '0xa46d8caa8ac4d39791a0542ae99de1f8ffb9a18d'
];
provider.getObjectBatch(objectIds);

// 通过对象ID查询其包含的其他对象
provider.getObjectsOwnedByObject(objectId)

// 查询某个地址下拥有的对象
const address = '0x81b9154bf2135207168ee73ac47a45af20af6431';
provider.getObjectsOwnedByAddress(address)

0x02 利用 devInspectTransaction 查询数据

Related Links:

https\://docs.sui.io/sui-jsonrpc#sui_devInspectTransaction

https\://github.com/MystenLabs/sui/pull/6538

devInspectTransaction 原理是:利用实时的链上数据模拟方法调用,解析调用结果来获取需要的数据。

它的优势在于:

  • 模拟调用,无需gas
  • 可以直接调用非 entry的 public方法,并获取返回结果
  • 自定义查询逻辑,支持各类复杂的查询需求
module test_query::test_query {
  
  use std::vector;
  use std::type_name::{TypeName, get};
  use sui::object::{Self, UID};
  use sui::table::{Self, Table};
  use sui::tx_context::TxContext;
  use sui::transfer;
  
  struct A has drop {}
  struct B has drop {}
  
  struct BalanceSheet has copy, store, drop {
    cash: u64,
    debt: u64
  }
  
  struct BalanceSheets has key {
    id: UID,
    table: Table<TypeName, BalanceSheet>
  }
  
  struct QueryResult has copy, drop {
    typeName: TypeName,
    balanceSheet: BalanceSheet,
  }
  
  fun init(ctx: &mut TxContext) {
    let balanceSheets = BalanceSheets {
      id: object::new(ctx),
      table: table::new(ctx)
    };
    table::add(&mut balanceSheets.table, get<A>(), BalanceSheet { cash: 100, debt: 20 });
    table::add(&mut balanceSheets.table, get<B>(), BalanceSheet { cash: 80, debt: 10 });
    transfer::share_object(balanceSheets)
  }
  
  public fun query(balanceSheets: &BalanceSheets): vector<QueryResult> {
    let res = vector::empty<QueryResult>();
    let typeA = get<A>();
    let balanceSheetA = table::borrow(&balanceSheets.table, typeA);
    let queryResultA = QueryResult { typeName: typeA, balanceSheet: *balanceSheetA };
    
    let typeB = get<B>();
    let balanceSheetB = table::borrow(&balanceSheets.table, typeB);
    let queryResultB = QueryResult { typeName: typeB, balanceSheet: *balanceSheetB };
    
    vector::push_back(&mut res, queryResultA);
    vector::push_back(&mut res, queryResultB);
    res
  }
}

上面这个合约中query就是返回对BalanceSheets下table数据的一个查询结果。

query方法自定了一套查询逻辑,并将结果包装成QueryResult列表返回出来。下面看看如何调用这个方法获取查询数据。

import { JsonPrcProvider, bcs } from '@mysten/sui.js'
const provider = new JsonRpcProvider();

/******* 第一步: 需要构造解析返回结果的bcs解析器 *******/

// 解析类型根据 合约中定义的struct对于填写,例如下面的BalanceSheet
/****
  struct BalanceSheet has copy, store, drop {
    cash: u64,
    debt: u64
  }
*****/
bcs.registerStructType('BalanceSheet', {
  cash: 'u64',
  debt: 'u64',
})

bcs.registerStructType('TypeName', {
  name: 'string'
})

bcs.registerStructType('QueryResult', {
  typeName: 'TypeName',
  balanceSheet: 'BalanceSheet',
})

function des(data: Uint8Array) {
  return bcs.de('vector<QueryResult>', data)
}

/******* 第二步: 通过devInspectMoveCall模拟调用query方法 *******/

(async () => {
  const balanceSheetsId = '0x92a403ee9467f3753a28a8725a053eda6f64cca4';
  const testPkgId = '0xd7d27a9a68c11b9035be08428feceea9bf374510';
  const sender = '7738ccc64bd64bb7b3524296db285042f7876281'; // 地址可以任意使用
  const res = await provider.devInspectTransaction(sender, {
    kind: 'moveCall',
    data: {
      packageObjectId: testPkgId,
      module: 'test_query',
      function: 'query',
      typeArguments: [],
      arguments: [balanceSheetsId] 
    }
  })
  // 下面这段解析逻辑是精华,返回的数据结构很复杂,并且需要bcs反序列化
  if ('Ok' in res.results) {
    const returnValues = res.results.Ok[0][1].returnValues;
    if (returnValues) {
      const returnData = returnValues[0][0];
      const d = Uint8Array.from(returnData);
      let decoded = des(d) // 在这里用到了第一步的bcs解析器
      console.log(decoded)
    }
  }
})()

成功的话会打印出结果:

[
  {
    typeName: { name: 'd7d27a9a68c11b9035be08428feceea9bf374510::test_dev::A' },
    balanceSheet: { cash: 100n, debt: 20n }
  },
  {
    typeName: { name: 'd7d27a9a68c11b9035be08428feceea9bf374510::test_dev::B' },
    balanceSheet: { cash: 80n, debt: 10n }
  }
]

0x03 总结

  • 对于大多数简单查询,直接通过address,Id进行对象数据查询即可。

  • devInSpectMoveCall 可以做到查询任意数据,实现复杂的组合查询。代价就是需要自己写链上查询函数,以及链下的 bcs 解析逻辑。


前文链接:

SUI 合约测试攻略 | Move dApp 极速入门(拾陆)\

Sui 数据类型详解 | Move dApp 极速入门(十五)\

Airdropper Contract in Aptos | Move dApp 极速入门(拾肆)\

Sandwich合约案例实践 | Move dApp 极速入门(拾叁)\

Sui 极速上手 | Move dApp 极速入门(拾贰)

Move 高阶语法 | 共学课优秀笔记\

Move 基础语法 | 共学课优秀学习笔记

scaffold-aptos 脚手架 | Move dApp 极速入门(拾壹)

Aptos NFT 发行指南 | Move dApp 极速入门(十)

对 DID Document 的思考 | Move dApp 极速入门(九)\

DID中地址聚合器的实现 | Move dApp 极速入门(八)

Aptos 中的智能合约形式化验证 | Move dApp 极速入门(七)

Aptos CLI使用指南与REPL设计建议 | Move dApp 极速入门(六)\

实现一套 DID 之总体设计 | Move dApp 极速入门(五)\

合约数据类型综述 | Move dApp 极速入门(四)\

操作资源 | Move dApp极速入门(三)\

第一个 Move dApp | Move dApp极速入门(二)\

Hello Move | Move dApp极速入门(一)

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论