Windows と TypeScript ではじめる Symbol 通信 03【ブロック高】


Rest の`/chain/info`と同等の値を取得してみましょう。
ただ、今回はブロック高とファイナライズとパケットタイプが分かれているので、2 つリクエストすることになります。

## ブロック高の取得

### ノードへリクエスト (ブロック高)

ブロック高を取得するパケットタイプは、`0x005`です。もちろん、ペイロードはありません。`Catapult.ts`ファイルに追記します。

また、続けてファイナライズもリクエストするので、ソケットを閉じないオプションも付けます。

```typescript:Catapult.ts
/** パケットタイプ */
private PacketType = {
  CHAIN_STATISTICS: 0x0_05,
  TIME_SYNC_NETWORK_TIME: 0x1_20,
}

/**
 * ChainStatistics取得
 * @param isCloase ソケットをクローズするか
 * @returns ChainStatistics
 */
async getChainStatistics(isCloase = true) {
  let chainStatistics: ChainStatistics | undefined
  try {
    const socketData = await this.request(this.PacketType.CHAIN_STATISTICS)
    if (socketData) chainStatistics = ChainStatistics.deserialize(socketData)
  } catch (e) {
    if (e instanceof Error) console.error(e.message)
    else console.error(e)
  } finally {
    if (isCloase) this.close()
  }
  return chainStatistics
}
```

### レスポンスデータの解析（ブロック高）

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

| 項目            | 長さ     |
| :-------------- | :------- |
| height          | 8 バイト |
| finalizedHeight | 8 バイト |
| scoreHigh       | 8 バイト |
| scoreLow        | 8 バイト |

```typescript:src/models/ChainStatistics.ts
import { PacketBuffer } from '../PacketBuffer.js'

export class ChainStatistics {
  constructor(
    public height: bigint,
    public finalizedHeight: bigint,
    public scoreHigh: bigint,
    public scoreLow: bigint
  ) {}

  static deserialize(payload: Uint8Array) {
    const bufferView = new PacketBuffer(Buffer.from(payload))
    const height = bufferView.readBigUInt64LE()
    const finalizedHeight = bufferView.readBigUInt64LE()
    const scoreHigh = bufferView.readBigUInt64LE()
    const scoreLow = bufferView.readBigUInt64LE()
    return new ChainStatistics(height, finalizedHeight, scoreHigh, scoreLow)
  }

  toJson() {
    return {
      height: this.height.toString(),
      finalizedHeight: this.finalizedHeight.toString(),
      scoreHigh: this.scoreHigh.toString(),
      scoreLow: this.scoreLow.toString(),
    }
  }
}
```

## ファイナライズの取得

### ノードへリクエスト（ファイナライズ）

ファイナライズを取得するパケットタイプは、`0x132`です。これもペイロードはありません。`Catapult.ts`ファイルに追記します。

これも同じようにソケットを閉じないオプションを付けます。

```typescript:Catapult.ts
  /** パケットタイプ */
  private PacketType = {
    CHAIN_STATISTICS: 0x0_05,
    TIME_SYNC_NETWORK_TIME: 0x1_20,
    FINALIZATION_STATISTICS: 0x1_32,
  }

  /**
   * FinalizationStatistics取得
   * @param isCloase ソケットをクローズするか
   * @returns  FinalizationStatistics
   */
  async getFinalizationStatistics(isCloase = true) {
    let finalizationStatistics: FinalizationStatistics | undefined
    try {
      const socketData = await this.request(
        this.PacketType.FINALIZATION_STATISTICS
      )
      if (socketData)
        finalizationStatistics = FinalizationStatistics.deserialize(socketData)
    } catch (e) {
      if (e instanceof Error) console.error(e.message)
      else console.error(e)
    } finally {
      if (isCloase) this.close()
    }
    return finalizationStatistics
  }
```

### レスポンスデータの解析（ファイナライズ）

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

| 項目   | 長さ      |
| :----- | :-------- |
| epoch  | 4 バイト  |
| point  | 4 バイト  |
| height | 8 バイト  |
| hash   | 32 バイト |

```typescript:src/models/FinalizationStatistics.ts
import { PacketBuffer } from "../PacketBuffer.js";

export class FinalizationStatistics {
  constructor(
    public epoch: number,
    public point: number,
    public height: bigint,
    public hash: string
  ) {}

  static deserialize(payload: Uint8Array) {
    const bufferView = new PacketBuffer(Buffer.from(payload));
    const epoch = bufferView.readUInt32LE();
    const point = bufferView.readUInt32LE();
    const height = bufferView.readBigUInt64LE();
    const hash = bufferView.readHexString(32).toUpperCase();
    return new FinalizationStatistics(epoch, point, height, hash);
  }

  toJson() {
    return {
      epoch: this.epoch,
      point: this.point,
      height: this.height.toString(),
      hash: this.hash,
    };
  }
}
```

## ブロック高とファイナライズをまとめる

2 つをまとめて`/chain/info`の形にします。
このメソッドの終わりにソケットを切断します。

```typescript:Catapult.ts
/**
 * /chain/info 同等の値を持つクラスを取得
 * @returns ChainInfo
 */
async getChainInfo() {
  console.info('ChainInfo')
  let chainInfo: ChainInfo | undefined
  try {
    const chainStat = await this.getChainStatistics(false)
    const finalStat = await this.getFinalizationStatistics(false)
    if (chainStat && finalStat)
      chainInfo = ChainInfo.create(chainStat, finalStat)
  } catch (e) {
    if (e instanceof Error) console.error(e.message)
    else console.error(e)
  } finally {
    this.close()
  }
  return chainInfo
}
```

`/chain/info`の形のクラスです。

```typescript:src/models/ChainInfo.ts
import { ChainStatistics } from "./ChainStatistics.js";
import { FinalizationStatistics } from "./FinalizationStatistics.js";

export class ChainInfo {
  constructor(
    public height: string,
    public scoreHigh: string,
    public scoreLow: string,
    public latestFinalizedBlock: LatestFinalizedBlock
  ) {}

  static create(chainStat: ChainStatistics, finalStat: FinalizationStatistics) {
    const latestFinalizedBlock = new LatestFinalizedBlock(
      finalStat.epoch,
      finalStat.point,
      finalStat.height.toString(),
      finalStat.hash
    );
    return new ChainInfo(
      chainStat.height.toString(),
      chainStat.scoreHigh.toString(),
      chainStat.scoreLow.toString(),
      latestFinalizedBlock
    );
  }

  toJson() {
    return {
      height: this.height.toString(),
      scoreHigh: this.scoreHigh.toString(),
      scoreLow: this.scoreLow.toString(),
      latestFinalizedBlock: this.latestFinalizedBlock.toJson(),
    };
  }
}

export class LatestFinalizedBlock {
  constructor(
    public finalizationEpoch: number,
    public finalizationPoint: number,
    public height: string,
    public hash: string
  ) {}

  toJson() {
    return {
      finalizationEpoch: this.finalizationEpoch,
      finalizationPoint: this.finalizationPoint,
      height: this.height,
      hash: this.hash,
    };
  }
}
```

### メインの作成

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

```typescript:src/mainChainInfo.ts
import { Catapult } from './Catapult.js'

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

const chainInfo = await catapult.getChainInfo()
if (chainInfo) console.log(chainInfo)
```

### 実行

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

実行すると以下の様にチェーン情報が出力されます。

```plaintext
ChainInfo
socket connected.
ChainInfo {
  height: '141667',
  scoreHigh: '0',
  scoreLow: '1418022653461819074',
  latestFinalizedBlock: LatestFinalizedBlock {
    finalizationEpoch: 67,
    finalizationPoint: 62,
    height: '47520',
    hash: 'C820B5484FBE24A2084A33C913E83352E883911B8BE294633786846BA3591317'
  }
}
socket close: 5
socket close: 306
```

## バックナンバー

https://qiita.com/ccHarvestasya/items/7b9c66f145b636fe70ee

https://qiita.com/ccHarvestasya/items/46af59638c5aadc1f0be