ブロックチェーンを使ったアプリケーションの難しさを理解する

## はじめに

この記事は [DENSO アドベントカレンダー 2023](https://qiita.com/advent-calendar/2023/denso) の9日目の記事です。

今年度、社内で Web3 のプロダクト開発をやってみようと思い立ち、起案に向け調査をしてきました。その中で分かってきたブロックチェーンを使ったアプリケーション開発の難しさを紹介します。

## そもそもブロックチェーンとは

ブロックチェーンの起源は BitCoin です。

過去、サブプライムローン問題の様な基軸通貨の価値が激変する事件が起き、中央集権的な政府・中央銀行・金融機関への不信感から、分散型金融や通貨へのニーズが出てきていました。そのニーズに応えるべく考案されたのが BitCoin であり、BitCoin を実現する分散型台帳技術として開発されたのがブロックチェーンです。

ブロックチェーンはあくまでデータベースということです。

その代表的な特徴として、

- 耐改ざん性: データは直前に書き込まれたデータから計算される値を持ち、ブロックチェーンネットワークに参加する複数のノードにデータが分散されているため、過去のデータを改ざんするのが困難。
- 透明性: 書き込まれたすべてのデータが公開されるため、誰でも閲覧・追跡が可能。

というものがあります。

## ブロックチェーンを適用する課題発見の難しさ

2023年現在、ブロックチェーンの明確なユースケースとしては、BitCoin の様な仮想通貨のみの理解です。ブロックチェーンというハンマーで打てる他の釘を血眼になってみな探している理解ですが、ブロックチェーンを適用すべき課題発見は本当に難しいなと感じます。

先に上げたブロックチェーンの特徴が生きるユースケースかの観点として、

- 耐改ざん性
    - 更新や削除が不要なデータか
- 透明性
    - 1つの事業者を超えてデータの共有が必要か
    - 機密性・プライバシー性の高いデータでないか

ぐらいは最低限確認する必要があります。

[それ、本当にブロックチェーンが必要ですか？再確認すべき６つの項目](https://blogs.itmedia.co.jp/narisako/2023/01/post_67.html))にも書かれている様な通称”それブロ”の観点にきちんと答えられない場合、ブロックチェーンを適用する課題としては合理性が弱いです。

## ブロックチェーンを使ったアプリケーション開発の難しさ

いくつかのチュートリアルをやってみたり、DApp を作ってみたり、GitHub で公開されている DApps のコードを読んでみたりしたインプットからわかったことをつらつら書いていきます。

### とりあえず動くまでの前提知識が多い

新しく登場してくる概念が多い・・・
チュートリアルをなぞっているだけだと、全体としてどの様に動かす設計になっているのかが分かりづらく、理解に苦しんだ。現時点理解している範囲で初心者が DApps を開発する際に理解しておくと良さそうな概念と具体的なサービス・技術の名称と、その関係性をグラフにまとめてみた。

NFT の DApps を作る場合、NFT のデジタルデータの情報も全てブロックチェーンに保存するフルオンチェーンで作るのならこのコンポーネント図に近い形になるが、フルオンチェーンで作らないのなら IPFS サービスを利用する必要が出てくるので、もう少し複雑になる。

```mermaid
graph TD
    subgraph 取引所
        trade[取引所]
    end

    subgraph クライアント
        user[ユーザー] -->|所有| wallet[ウォレット\nMetamask]
        wallet -->|所有| secret[秘密鍵]
        wallet -->|所有| EOA[ウォレットアドレス 1,2,3...]
    end

    user --->|購入| trade
    trade --->|送金| wallet

    subgraph フロントエンド
        frontend[Front-end\nHTML,CSS,Javascript] -->|呼び出し| web3Library[Ethereum-api-js-library\nweb3.js]
    end

    user -->|利用| frontend
    wallet -->|接続\nトランザクション| web3Library

    subgraph フォーセット
        faucet[フォーセット]
    end

    subgraph 開発チーム
        developer[開発者] -->|所有| devWallet[ウォレット\nMetamask]
        developer[開発者] -->|開発| contractDevTools[スマートコントラクト開発ツール\nSolidity,Foundry,Hardhat]
        devWallet --->|接続| contractDevTools
        devWallet -->|所有| devSecret[秘密鍵]
        devWallet -->|所有| devEOA[ウォレットアドレス 1,2,3...]
    end

    developer --->|送金リクエスト| faucet
    faucet --->|テスト用通貨の送金| devWallet

    subgraph ノードプロバイダ
        rpc[RPC\nINFURA]
        devRpc[開発用RPC\nINFURA]
    end

    contractDevTools --->|デプロイ| devRpc
    web3Library --->|リクエスト| rpc

    subgraph メインネット_Ethereum
        mainSmartContract[スマートコントラクト\nEthereumバイトコード] -->|所有| mainContractAddress[コントラクトアドレス]
    end

    subgraph テストネット_EthereumSepolia
        testSmartContract[スマートコントラクト\nEthereumバイトコード] -->|所有| testContractAddress[コントラクトアドレス]
    end

    rpc ---->|トランザクション| mainSmartContract
    rpc ---->|トランザクション| testSmartContract
    devRpc ---->|デプロイ| mainSmartContract
    devRpc ---->|デプロイ\nテスト| testSmartContract

    subgraph ブロックチェーンエクスプローラ
        explorer[エクスプローラー\nEtherScan]
    end

    user -->|閲覧| explorer
    developer -->|閲覧| explorer
    explorer --->|詳細取得| mainSmartContract
    explorer --->|詳細取得| testSmartContract
```

### スマートコントラクトの動作確認が面倒くさい

まずは CryptoZombie をやってみましょう。そうすれば必要最低限の Solidity の文法は分かるようになります。

そこからローカルでの開発環境を整えるのには苦労しました。他のプログラミング言語で当たり前の様に行っている、`console.log` や `print` なる術を簡単に見つけられませんでした。変数の中身を気軽に確認することすらできない Solidity の不便さを痛感しました。

私自身が見つけた順にやり方をいくつか挙げていくと、

**パブリックな状態変数に確認したい値を格納。ローカルデプロイ、ローカルRPCから読み取る。**

こんなコントラクトにしておいて、ローカルにデプロイ。ローカルRPCから関数実行し、`variable` の値が変わっているはずなので、その後読み取り。めちゃくちゃ面倒くさいです。

```:solidity
contract Sample {
    uint variable public;

    function sampleFunc(uint _a, uint _b) public {
        uint result = _a * _b;
        public = result;
        return result;
    }
}
```

**パブリックな状態変数に確認したい値を格納。テストコードからそれを読み取る。**

`hardhat` をコントラクト開発ツールに使用した場合、テストコードを書く JavaScript 内でなら、public な状態変数を `console.log()` にわたすことが出来るので読み取れる。自動テストを書きながらやれるのは、動作への自信を積み上げていきやすいのでまだマシかなと感じています。

```:typescript
import { expect } from "chai";
import { Contract } from "ethers";
import { ethers } from "hardhat";

describe("Sample", function() {
  let sample: Contract;

  beforeEach(async () => {
    const Sample = await ethers.getContractFactory("Sample");
    sample = await Sample.deploy();
  });

  describe("sampleFunc", function() {
    it(`状態変数に所望の値が入っている`, async () => {
      await sample.sampleFunc();
      console.log(sample.variable());
      expect(1).to.equal(1);
    });
  });
});
```

**Foundry には console.log() がある。**

`Foundry` というスマートコントラクト開発ツールに付随してくる `forge-std/console.log` にてようやく出会えました。・・・もっと早く知りたかったです。

ただ、コードの実行はテストコードから呼び出すのが一番楽そう。

```solidity
import "forge-std/console.sol";

contract Sample {
  uint256 public value;

  function setValue(uint256 _value) public {
    value = _value;

    console.logString("-------------------");
    console.logUint(value);
    console.logString("-------------------");
  }
}
```

### 他 Tips

- `Openzeppelin` というライブラリに ERC の基本規格通りのスマートコントラクトは大体ある。自作せず活用する。その方がセキュリティリスクも少なく安心。
- 「特に変哲のないもので良いからトークン・NFTを作ってみたい」という場合には、`ThirdWeb` を使う。Web3 ハッカソンでも ThirdWeb を使って開発している方がちらほらいたので、とにかくスピード重視で作るならかなり良さそう。特に、ノーコードである程度のスマートコントラクトが出来てしまう点と、フロントエンド側からウォレット接続・スマートコントラクトを呼び出すのに必要な記述量が web3.js を使っていたときと比べて激減した印象。

## ブロックチェーンを使ったアプリケーション運用の難しさ

より詳しく調査する必要があるが会計ルールの遵守のために、仮想通貨の入手とガス代での使用を管理する必要がある。これを解決できる開発支援ツールがあればぜひ使いたいところ・・・

## まとめ

この1年間で分かったことをまとめてみました。社内外でこの投稿に興味をもってくださる方いれば、気軽にコンタクトを取ってくださると嬉しいです。