Windows と TypeScript ではじめる Symbol 通信 14【モザイク情報】


## ノード情報の取得

### ノードへリクエスト

モザイク情報を取得するパケットタイプは、`0x44d`です。

```typescript: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,
  ACCOUNT_INFOS: 0x4_43,
  METADATA_INFOS: 0x4_44,
  MOSAIC_INFOS: 0x4_4d,
}

async getMosaicInfos(mosaicIds: Uint8Array[]) {
  const mosaicInfos: MosaicInfo[] = []
  try {
    const payload = Buffer.concat(mosaicIds)
    const socketData = await this.request(this.PacketType.MOSAIC_INFOS, payload)
    if (socketData) {
      let offset = 0
      do {
        const mosaicInfo = MosaicInfo.deserialize(socketData.slice(offset))
        mosaicInfos.push(mosaicInfo)
        offset += mosaicInfo.mosaicInfoSize
      } while (offset < socketData.length)
    }
  } catch (e) {
    if (e instanceof Error) console.error(e.message)
    else console.error(e)
  } finally {
    this.close()
  }
  return mosaicInfos
}
```

### レスポンスデータの解析

シリアライズされたデータが返ってくるので、デシリアライズします。

```typescript:src/models/MosaicInfo.ts
import { Address, models } from 'symbol-sdk/symbol'
import { PacketBuffer } from '../PacketBuffer.js'

export class MosaicInfo {
  constructor(
    public mosaicInfoSize: number,
    public mosaicDataSize: number,
    public mosaicInfoKey: String,
    public version: number,
    public mosaicId: models.MosaicId,
    public supply: models.Amount,
    public startHeight: models.Height,
    public ownerAddress: Address,
    public revision: number,
    public flags: number,
    public divisibility: number,
    public duration: models.BlockDuration
  ) {}

  static deserialize(payload: Uint8Array) {
    const packetBuf = new PacketBuffer(Buffer.from(payload))
    const mosaicInfoSize = packetBuf.readUInt32LE()
    const mosaicDataSize = packetBuf.readUInt32LE()
    const mosaicInfoKey = packetBuf.readBigUInt64LE().toString().toUpperCase()
    const version = packetBuf.readUInt16LE()
    const mosaicId = new models.MosaicId(packetBuf.readBigUInt64LE())
    const supply = new models.Amount(packetBuf.readBigUInt64LE())
    const startHeight = new models.Height(packetBuf.readBigUInt64LE())
    const ownerAddress = Address.fromDecodedAddressHexString(packetBuf.readHexString(24))
    const revision = packetBuf.readUInt32LE()
    const flags = packetBuf.readUInt8()
    const divisibility = packetBuf.readUInt8()
    const duration = new models.BlockDuration(packetBuf.readBigUInt64LE())

    return new MosaicInfo(
      mosaicInfoSize,
      mosaicDataSize,
      mosaicInfoKey,
      version,
      mosaicId,
      supply,
      startHeight,
      ownerAddress,
      revision,
      flags,
      divisibility,
      duration
    )
  }

  toJson() {
    return {
      version: this.version,
      id: this.mosaicId.value.toString(16).toUpperCase(),
      supply: this.supply.toJson(),
      startHeight: this.startHeight.toJson(),
      ownerAddress: Buffer.from(this.ownerAddress.bytes).toString('hex').toUpperCase(),
      revision: this.revision,
      flags: this.flags,
      divisibility: this.divisibility,
      duration: this.duration.toJson(),
    }
  }
}
```

## メインの作成

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

```typescript:src/mainMosaicInfo.ts
import { Catapult } from './Catapult.js'
import { utils } from 'symbol-sdk'

const mosaicIds = [
  utils.hexToUint8('72C0212E67A08BCE').reverse(),
  utils.hexToUint8('21E832B4F69E32F2').reverse(),
]

const catapult = new Catapult(
  'cert/ca.crt.pem',
  'cert/node.crt.pem',
  'cert/node.key.pem',
  '127.0.0.1'
)
const mosaicInfos = await catapult.getMosaicInfos(mosaicIds)
for (const mosaicInfo of mosaicInfos) {
  console.log(JSON.stringify(mosaicInfo.toJson(), null, 2))
}
```

### 実行

```posh
yarn tsx .\src\mainMosaicInfo.ts
```

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

```plaintext
socket connected.
{
  "version": 1,
  "id": "72C0212E67A08BCE",
  "supply": "8165875618344038",
  "startHeight": "1",
  "ownerAddress": "9889432DE263BB8FE88444A4DA28D3609BD8BB8FAE18AE95",
  "revision": 1,
  "flags": 2,
  "divisibility": 6,
  "duration": "0"
}
{
  "version": 1,
  "id": "21E832B4F69E32F2",
  "supply": "500000000",
  "startHeight": "1685127",
  "ownerAddress": "9872DE7A88A74255A51CF543C4CCE7113A46EA255C7EDBEC",
  "revision": 1,
  "flags": 2,
  "divisibility": 6,
  "duration": "0"
}
socket close: 1101
```