4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

nem / symbolAdvent Calendar 2024

Day 22

Windows と TypeScript ではじめる Symbol 通信 12【メタデータ】

Last updated at Posted at 2024-12-21

すこし面倒ですが、メタデータも取得することが出来ます。

ノード情報の取得

ノードへリクエスト

ブロック高を取得するパケットタイプは、0x444です。

Catapult.ts
/** パケットタイプ */
private PacketType = {
  PULL_BLOCK: 0x0_04,
  CHAIN_STATISTICS: 0x0_05,
  PULL_BLOCKS: 0x0_08,
  PUSH_TRANSACTIONS: 0x0_09,
  PUSH_PARTIAL_TRANSACTIONS: 0x1_00,
  NODE_DISCOVERY_PULL_PING: 0x1_11,
  TIME_SYNC_NETWORK_TIME: 0x1_20,
  FINALIZATION_STATISTICS: 0x1_32,
  UNLOCKED_ACCOUNTS: 0x3_04,
  METADATA_INFOS: 0x4_44,
}

async getMetadataInfos(payloads: Uint8Array[]) {
  const metadataEntries: MetadataEntry[] = []
  try {
    const payload = Buffer.concat(payloads)
    const socketData = await this.request(
      this.PacketType.METADATA_INFOS,
      payload
    )
    if (socketData) {
      let offset = 0
      do {
        const metadata = MetadataEntry.deserialize(
          socketData.slice(offset)
        ) as MetadataEntry
        metadataEntries.push(metadata)
        offset += metadata.metadataSize
      } while (offset < socketData.length)
    }
  } catch (e) {
    if (e instanceof Error) console.error(e.message)
    else console.error(e)
  } finally {
    this.close()
  }
  return metadataEntries
}

レスポンスデータの解析

シリアライズされたデータが返ってくるので、デシリアライズします。
型は表示しやすいように全てstringにしています。

src/models/MetadataEntry.ts
import { PacketBuffer } from '../PacketBuffer.js'

export class MetadataEntry {
  constructor(
    public metadataSize: number,
    public size: number,
    public version: number,
    public compositeHash: string,
    public sourceAddress: string,
    public targetAddress: string,
    public scopedMetadataKey: string,
    public targetId: string,
    public metadataType: number,
    public valueSize: number,
    public value: string
  ) {}

  static deserialize(payload: Uint8Array) {
    const packetBuf = new PacketBuffer(Buffer.from(payload))
    const metadataSize = packetBuf.readUInt32LE()
    const size = packetBuf.readUInt32LE()
    const compositeHash = packetBuf.readHexString(32).toUpperCase()
    const version = packetBuf.readUInt16LE()
    const sourceAddress = packetBuf.readHexString(24).toUpperCase()
    const targetAddress = packetBuf.readHexString(24).toUpperCase()
    const scopedMetadataKey = packetBuf
      .readBigUInt64LE()
      .toString(16)
      .toUpperCase()
    const targetId = packetBuf
      .readBigUInt64LE()
      .toString(16)
      .toUpperCase()
      .padStart(16, '0')
    const metadataType = packetBuf.readUInt8()
    const valueSize = packetBuf.readUInt16LE()
    const value = packetBuf.readHexString(valueSize).toUpperCase()
    return new MetadataEntry(
      metadataSize,
      size,
      version,
      compositeHash,
      sourceAddress,
      targetAddress,
      scopedMetadataKey,
      targetId,
      metadataType,
      valueSize,
      value
    )
  }
}

メインの作成

実行するコードを作成します。

ノードに問い合わせる際のメタデータのキーはコンポジットハッシュです。
メタデータの作成者、記録者、メタデータキーから算出する必要があります。

src/mainMetadata.ts
import { sha3_256 } from '@noble/hashes/sha3'
import { utils } from 'symbol-sdk'
import { Address } from 'symbol-sdk/symbol'
import { Catapult } from './Catapult.js'

const calculateCompositeHash = (
  type: Uint8Array,
  sourceAddress: Address,
  targetAddress: Address,
  targetId: undefined | string,
  key: Uint8Array
) => {
  const hasher = sha3_256.create()
  hasher.update(sourceAddress.bytes)
  hasher.update(targetAddress.bytes)
  hasher.update(key.reverse())
  hasher.update(utils.hexToUint8(targetId || '0000000000000000').reverse())
  hasher.update(type)
  return hasher.digest()
}

// ターゲットと作成者アドレスの設定
const targetAddress = new Address('TBZN46UIU5BFLJI46VB4JTHHCE5EN2RFLR7NX3A') // メタデータ記録先アドレス
const sourceAddress = new Address('TBZN46UIU5BFLJI46VB4JTHHCE5EN2RFLR7NX3A') // メタデータ作成者アドレス
// メタデータキーの設定
const metadataKey = utils.hexToUint8('CF1ED85F57869D66')
// コンポジットハッシュ算出
const compositeHash = calculateCompositeHash(
  utils.hexToUint8('00'),
  sourceAddress,
  targetAddress,
  '0000000000000000',
  metadataKey
)

const catapult = new Catapult(
  'cert/ca.crt.pem',
  'cert/node.crt.pem',
  'cert/node.key.pem',
  'localhost'
)

const metadataEntries = await catapult.getMetadataInfos([compositeHash])
if (metadataEntries) {
  for (const metadataEntrie of metadataEntries) {
    console.log(JSON.stringify(metadataEntrie, null, 2))
  }
}

実行

yarn tsx .\src\mainMetadata.ts

実行すると以下の様に結果が出力されます。

socket connected.
{
  "metadataSize": 114,
  "size": 74,
  "version": 1,
  "compositeHash": "C8D8CEA0C98E7570D6136AEA41B89FE41EE41A4307309BEBA9F072A6F92BA657",
  "sourceAddress": "9872DE7A88A74255A51CF543C4CCE7113A46EA255C7EDBEC",
  "targetAddress": "9872DE7A88A74255A51CF543C4CCE7113A46EA255C7EDBEC",
  "scopedMetadataKey": "CF1ED85F57869D66",
  "targetId": "0000000000000000",
  "metadataType": 0,
  "valueSize": 5,
  "value": "7465737431"
}
socket close: 1092
4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?