5
1

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

Symbolブロックチェーンのアカウント数推移を調べる

Last updated at Posted at 2024-12-21

はじめに

2021年3月17日のローンチから早や4年を迎えようとしているSymbolブロックチェーン。
ふとこれまでに発行されたアカウント総数や各月ごとにどれくらいのアカウントが発行されているのか気になったので、今回はその調査結果および調査方法を備忘録として書き記していきます。

調査結果

アカウント発行総数:286,091(~2024年12月17日、ブロック高3946672)

各月ごとの詳細
集計期間 生成されたアカウント数 アカウント総数
2021/03/17 ~ 2021/03/31 74,545 74,545
2021/04/01 ~ 2021/04/30 16,167 90,712
2021/05/01 ~ 2021/05/31 21,650 112,362
2021/06/01 ~ 2021/06/30 8,589 120,951
2021/07/01 ~ 2021/07/31 4,232 125,183
2021/08/01 ~ 2021/08/31 5,150 130,333
2021/09/01 ~ 2021/09/30 4,027 134,360
2021/10/01 ~ 2021/10/31 3,134 165,703
2021/11/01 ~ 2021/11/30 7,714 173,417
2021/12/01 ~ 2021/12/31 9,552 182,969
2022/01/01 ~ 2022/01/31 5,712 188,681
2022/02/01 ~ 2022/02/28 5,530 194,211
2022/03/01 ~ 2022/03/31 5,050 199,261
2022/04/01 ~ 2022/04/30 4,273 203,534
2022/05/01 ~ 2022/05/31 3,304 206,838
2022/06/01 ~ 2022/06/30 1,885 208,723
2022/07/01 ~ 2022/07/31 1,538 210,261
2022/08/01 ~ 2022/08/31 1,443 211,704
2022/09/01 ~ 2022/09/30 1,512 213,216
2022/10/01 ~ 2022/10/31 2,345 215,561
2022/11/01 ~ 2022/11/30 1,775 217,336
2022/12/01 ~ 2022/12/31 1,291 218,627
2023/01/01 ~ 2023/01/31 1,827 220,454
2023/02/01 ~ 2023/02/28 2,588 223,042
2023/03/01 ~ 2023/03/31 1,800 224,842
2023/04/01 ~ 2023/04/30 1,742 226,584
2023/05/01 ~ 2023/05/31 1,139 227,723
2023/06/01 ~ 2023/06/30 1,368 229,091
2023/07/01 ~ 2023/07/31 1,289 230,380
2023/08/01 ~ 2023/08/31 2,811 233,191
2023/09/01 ~ 2023/09/30 1,730 234,921
2023/10/01 ~ 2023/10/31 1,507 236,428
2023/11/01 ~ 2023/11/30 2,597 239,025
2023/12/01 ~ 2023/12/31 1,633 240,658
2024/01/01 ~ 2024/01/31 4,466 245,124
2024/02/01 ~ 2024/02/29 5,324 250,448
2024/03/01 ~ 2024/03/31 8,879 259,327
2024/04/01 ~ 2024/04/30 19,035 278,362
2024/05/01 ~ 2024/05/31 1,514 279,876
2024/06/01 ~ 2024/06/30 988 280,864
2024/07/01 ~ 2024/07/31 785 281,649
2024/08/01 ~ 2024/08/31 699 282,348
2024/09/01 ~ 2024/09/30 1,131 283,479
2024/10/01 ~ 2024/10/31 720 284,199
2024/11/01 ~ 2024/11/30 1,182 285,381
2024/12/01 ~ 2024/12/17 710 286,091

image.png

参考までにEthereumの推移も載せておきます。
image.png

調査方法

各月における先頭/末尾のブロック高を取得する

まずは各月における先頭/末尾のブロック高を取得します。

Symbolブロックチェーンでは約30秒に1ブロック生成されるため1日の理論ブロック高は2880ですが、実際は少なからず誤差があり安直に2880ブロックずつ加算していくとズレが生じるので注意しましょう。


2024/01/01: 29338732936748(2875ブロック)

2024/01/02: 29367492939625(2876ブロック)

import dayjs from 'dayjs';

const NODE_URL = 'https://sym-main-03.opening-line.jp:3001';
const NEMESIS_TIMESTAMP = 1615853185000; // mainnet

type ResponseSearchBlock = {
  data: {
    id: string;
    meta: {
      hash: string;
      totalFee: string;
      generationHash: string;
      stateHashSubCacheMerkleRoots: any[];
      totalTransactionsCount: number;
      transactionsCount: number;
      statementsCount: number;
    };
    block: {
      size: number;
      signature: string;
      signerPublicKey: string;
      version: number;
      network: number;
      type: number;
      height: number;
      timestamp: number;
      difficulty: number;
      proofGamma: string;
      proofVerificationHash: string;
      proofScalar: string;
      previousBlockHash: string;
      transactionsHash: string;
      receiptsHash: string;
      stateHash: string;
      beneficiaryAddress: string;
      feeMultiplier: number;
    };
  }[];
  pagination: {
    pageNumber: number;
    pageSize: number;
  };
};

const fetchBlockHeight = async (fromTimestamp: string, toTimestamp: string) => {
  const query = new URLSearchParams({
    fromTimestamp: fromTimestamp,
    toTimestamp: toTimestamp,
  });

  const blockResponse: ResponseSearchBlock = await fetch(
    new URL(`/blocks?${query}`, NODE_URL),
    {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
      },
    },
  ).then((res) => res.json());

  if (blockResponse.data.length === 0) {
    throw new Error('Block not found');
  }

  return blockResponse.data[0]?.block.height || 0;
};

const getBlockHeights = async (fromTimestamp: string, toTimestamp: string) => {
  try {
    // 検索開始日の最初のブロック高を取得
    const fromStartTimestamp = dayjs(fromTimestamp, 'YYYY/MM/DD').unix() * 1000 - NEMESIS_TIMESTAMP;
    const fromEndTimestamp = dayjs(fromTimestamp, 'YYYY/MM/DD').add(1, 'minute').unix() * 1000 - NEMESIS_TIMESTAMP;
    // 検索終了日の最終ブロック高を取得
    const toStartTimestamp = dayjs(toTimestamp, 'YYYY/MM/DD').add(1, 'day').unix() * 1000 - NEMESIS_TIMESTAMP;
    const toEndTimestamp = dayjs(toTimestamp, 'YYYY/MM/DD').add(1, 'day').add(1, 'minute').unix() * 1000 - NEMESIS_TIMESTAMP;

    const [fromBlockHeight, rawToBlockHeight] = await Promise.all([
      fetchBlockHeight(fromStartTimestamp.toString(), fromEndTimestamp.toString()),
      fetchBlockHeight(toStartTimestamp.toString(), toEndTimestamp.toString()),
    ]);

    if (fromBlockHeight === 0 || rawToBlockHeight === 0) {
      throw new Error('Block not found');
    }

    // 欲しい検索終了ブロック高は1つ前のブロックなので調整
    const toBlockHeight = rawToBlockHeight - 1;
    return { fromBlockHeight, toBlockHeight };
  } catch (e) {
    console.error(e);
    return { fromBlockHeight: 0, toBlockHeight: 0 };
  }
};

各月に発行されたアカウント数を取得する

アカウントが発行されたブロック高はaddressHeightから確認できます。
今回は上記で取得した先頭/末尾ブロック高の間に含まれるaddressHeightを持つアカウントを抽出、カウントしました。

image.png

抽出の際にページ番号(pageNumber)を指定しないと毎度途方もない数のリクエストを送ることになり無限に時間が溶けます。もしお試し実行される際には以下の一覧表を参考にページ番号を指定いただくと幸せになれるかもしれません。

開始日/終了日とページ番号一覧
開始日 終了日 開始日の最初のブロック高 終了日の最後のブロック高 開始位置のページ番号
2021-03-17 2021-03-31 0 42176 0
2021-04-01 2021-04-30 42177 128505 745
2021-05-01 2021-05-31 128506 217699 907
2021-06-01 2021-06-30 217700 304026 1123
2021-07-01 2021-07-31 304027 393233 1209
2021-08-01 2021-08-31 393234 482429 1251
2021-09-01 2021-09-30 482430 568750 1303
2021-10-01 2021-10-31 568751 657942 1343
2021-11-01 2021-11-30 657943 744258 1657
2021-12-01 2021-12-31 744259 833462 1734
2022-01-01 2022-01-31 833463 922652 1829
2022-02-01 2022-02-28 922653 1003214 1886
2022-03-01 2022-03-31 1003215 1092417 1942
2022-04-01 2022-04-30 1092418 1178732 1992
2022-05-01 2022-05-31 1178733 1267932 2035
2022-06-01 2022-06-30 1267933 1354250 2068
2022-07-01 2022-07-31 1354251 1443445 2087
2022-08-01 2022-08-31 1443446 1532643 2102
2022-09-01 2022-09-30 1532644 1618958 2117
2022-10-01 2022-10-31 1618959 1708151 2132
2022-11-01 2022-11-30 1708152 1794472 2155
2022-12-01 2022-12-31 1794473 1883664 2173
2023-01-01 2023-01-31 1883665 1972860 2186
2023-02-01 2023-02-28 1972861 2053424 2204
2023-03-01 2023-03-31 2053425 2142621 2230
2023-04-01 2023-04-30 2142622 2228938 2248
2023-05-01 2023-05-31 2228939 2318134 2265
2023-06-01 2023-06-30 2318135 2404452 2277
2023-07-01 2023-07-31 2404453 2493646 2291
2023-08-01 2023-08-31 2493647 2582844 2303
2023-09-01 2023-09-30 2582845 2669160 2332
2023-10-01 2023-10-31 2669161 2758360 2349
2023-11-01 2023-11-30 2758361 2844675 2364
2023-12-01 2023-12-31 2844676 2933872 2390
2024-01-01 2024-01-31 2933873 3023063 2406
2024-02-01 2024-02-29 3023064 3106509 2451
2024-03-01 2024-03-31 3106510 3195694 2504
2024-04-01 2024-04-30 3195695 3282026 2593
2024-05-01 2024-05-31 3282027 3371218 2783
2024-06-01 2024-06-30 3371219 3457532 2798
2024-07-01 2024-07-31 3457533 3546730 2808
2024-08-01 2024-08-31 3546731 3635930 2816
2024-09-01 2024-09-30 3635931 3722250 2823
2024-10-01 2024-10-31 3722251 3811439 2834
2024-11-01 2024-11-30 3811440 3897755 2842
2024-12-01 2024-12-17 3897756 3946672 2853

const PAGE_SIZE = '100';

type ResponseSearchAccounts = {
  data: {
    id: string;
    account: {
      version: number;
      address: string;
      addressHeight: string;
      publicKey: string;
      publicKeyHeight: string;
      accountType: number;
      SupplementalPublicKeys: {
        linked: {
          publicKey: string;
        };
        node: {
          publicKey: string;
        };
        vrf: {
          publicKey: string;
        };
        voting: {
          publicKey: string;
        };
      };
      activityBuckets: {
        startHeight: string;
        totalFeesPaid: string;
        beneficiaryCount: string;
        rawScore: string;
      }[];
      mosaics: {
        id: string;
        amount: string;
      }[];
      importance: string;
      importanceHeight: string;
    };
  }[];
  pagination: {
    pageNumber: number;
    pageSize: number;
  };
};

const getCreatedAccountForMonth = async () => {
  try {
    const fromTimestamp = '2024-01-01'; // 開始日を指定
    const toTimestamp = '2024-01-31'; // 終了日を指定
    const pageNumber = 2406; // ページ番号を指定

    // 日時からブロック高を取得
    const { fromBlockHeight, toBlockHeight } = await getBlockHeights(
      fromTimestamp,
      toTimestamp,
    );

    // アカウント情報を取得
    const fetchAccounts = async (pageNumber: number, count: number = 0): Promise<{ totalCount: number; lastPageNumber: number }> => {
      const query = new URLSearchParams({
        pageSize: PAGE_SIZE,
        pageNumber: pageNumber.toString(),
      });

      const accounts: ResponseSearchAccounts = await fetch(
        new URL(`/accounts?${query}`, NODE_URL),
        {
          method: 'GET',
          headers: {
            'Content-Type': 'application/json',
          },
        },
      ).then((res) => res.json());

      // fromBlockHeight以上かつtoBlockHeight以下のアカウントをカウント
      const validAccountsCount = accounts.data.filter((account) => {
        const addressHeight = Number(account.account.addressHeight);
        return (
          addressHeight >= fromBlockHeight && addressHeight <= toBlockHeight
        );
      }).length;
      const totalCount = count + validAccountsCount;

      if (
        accounts.data.length > 0 &&
        Number(accounts.data[accounts.data.length - 1].account.addressHeight) <=
          toBlockHeight
      ) {
        await new Promise((resolve) => setTimeout(resolve, 1000));
        return fetchAccounts(pageNumber + 1, totalCount);
      }

      return { totalCount, lastPageNumber: pageNumber };
    };

    const { totalCount, lastPageNumber } = await fetchAccounts(pageNumber);
    return {
      totalCount: totalCount,
      fromTimestamp: fromTimestamp,
      toTimestamp: toTimestamp,
      fromBlockHeight: fromBlockHeight,
      toBlockHeight: toBlockHeight,
      lastPageNumber: lastPageNumber,
    };
  } catch (error) {
    console.error('getCreatedAccountForMonth error', error);
  }
};

おわりに

全体通して見ると現状相場との相関がやや色濃く見られるな、という印象でした。
また2022年下期以降は低調に推移しつつもコンスタントに毎月1000アカウント近く発行されているのが少し意外でした(個人的にはもっと少ない予想だったので用途が気になっています)。

実際にどれだけ利用されているかという観点だと「各アカウントがどの程度アクティブなのか」「各月のトランザクション数推移との相関はどうなのか」なども併せて多角的に分析・考察する必要があると考えていますが、やるとなったらかなり膨大な作業になりそうだな...と天井を見上げつつ今回はここでキーを打つ手を止めたいと思います。

KEEP BUILDING.

5
1
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
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?