プログラミング

C#でブロックチェーンの基礎を学んでみよう

はじめに

どうも!プログラマのどらです。

今回はC#でブロックチェーンの基礎となる部分を実装してみました。
やっぱり自分で作った方が文章でただ説明を読むより理解力が深まりますね!

この記事はC#でブロックチェーンを実装してみたい
ブロックチェーンプログラミングに興味があるので勉強してみたいという方にぜひ読んでいただきたいです!

今回実装したのは以下のようなものです。ビットコイン仕様です。

  • ブロック
  • ブロックの追加(採掘)
  • プルーフ・オブ・ワーク(PoW/Proof of Work)

なお実装につきましては↓の記事を参考にさせていただきました。
Learn Blockchains by Building One – Hacker Noon

ブロックについて

ブロックチェーンはいくつものブロックが連なっているList(リスト)です。

ブロックはインデックス、タイムスタンプ、トランザクション、ナンス、前のブロックのハッシュ値で構成されています。

トランザクション・・・取引データのList
ナンス・・・ブロックの採掘に用いる承認用の値

前のブロックのハッシュ値を持つことによって、ブロックが改ざんや破壊されても、そのブロック以降は不正なブロック扱いとなります。
ここがブロックチェーンが改ざん不可能といわれる理由です。

ブロックのクラスが以下です。このクラスをList型や配列で扱えばブロックチェーンみたいになりますね。

    public class Block
    {
        /// <summary>
        /// インデックス
        /// </summary>
        public int Index { get; set; }

        /// <summary>
        /// タイムスタンプ
        /// </summary>
        public DateTime Timestamp { get; set; }

        /// <summary>
        /// トランザクション(取引データ)
        /// </summary>
        public List<Transaction> Transactions { get; set; }

        /// <summary>
        /// ナンス
        /// </summary>
        public int Nonce { get; set; }

        /// <summary>
        /// 前のブロックのハッシュ
        /// </summary>
        public string PreviousHash { get; set; }

        public Block()
        {
            Transactions = new List<Transaction>();
        }
    }

トランザクションクラスは以下のような取引に関するデータを保持します。

    /// <summary>
    /// トランザクション
    /// </summary>
    public class Transaction
    {
        /// <summary>
        /// 量
        /// </summary>
        public int Amount { get; set; }

        /// <summary>
        /// 受信者
        /// </summary>
        public string Recipient { get; set; }

        /// <summary>
        /// 送信者
        /// </summary>
        public string Sender { get; set; }
    }

ブロックの作成・追加

ブロックチェーンの最初のブロックはジェネシスブロックと呼ばれています。
ジェネシスブロックの追加はコード内にべた書きしています。(ジェネシスブロックがないと次に追加するブロックに前のブロックのハッシュ値を保持できないので)

    public class BlockChain
    {
        /// <summary>
        /// ブロックチェーン
        /// </summary>
        private List<Block> blockChain = new List<Block>();

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public BlockChain()
        {
            //ジェネシスブロック生成
            blockChain.Add(new Block()
            {
                Index = blockChain.Count,
                Timestamp = DateTime.UtcNow,
                Nonce = 100,
                PreviousHash = "1"
            });
        }

ブロックの生成は以下のコードです。
ポイントは前のブロックのハッシュ値を前のブロックから生成しているところです。

        /// <summary>
        /// ブロック生成
        /// </summary>
        public void CreateBlock()
        {
            blockChain.Add(new Block
            {
                Index = blockChain.Count,
                Timestamp = DateTime.UtcNow,
                Nonce = CreateNonce(blockChain.Last().Nonce),
                PreviousHash = CreateHash(blockChain.Last())
            });
        }

PoW(Proof of Work)

ブロックチェーンに新しいブロックを追加するには、追加する権利を得るため計算問題を解かなければなりません。
計算問題を解き他のマイニング参加者から承認を得るとブロックが追加されます。

今回は計算問題は ”hash(pp’) の最初の4つが0となるような p’ を探す” というシンプルなものにしています。

どら
どら
この計算問題を解いてるからビットコインのマイニングは時間と電気代がかかるんだね…
        /// <summary>
        /// ナンス生成
        /// </summary>
        /// <param name="previousNonce">前のブロックのナンス</param>
        /// <returns>ナンス</returns>
        private int CreateNonce(int previousNonce)
        {
            int nonce = 0;
            while (!CheckNonce(previousNonce, nonce))
            {
                nonce++;
            }
            return nonce;
        }

        /// <summary>
        /// ナンスチェック
        /// </summary>
        /// <param name="previousNonce">前のブロックのナンス</param>
        /// <param name="nonce">チェックするナンス</param>
        /// <returns></returns>
        private bool CheckNonce(int previousNonce, int nonce)
        {
            return GetHash($"{previousNonce}{nonce}").StartsWith("0000");
        }

        /// <summary>
        /// ハッシュ値作成
        /// </summary>
        /// <param name="block"></param>
        /// <returns></returns>
        private string CreateHash(Block block)
        {
            return GetHash(JsonConvert.SerializeObject(block));
        }


        /// <summary>
        /// ハッシュ値取得
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private string GetHash(string data)
        {
            byte[] hash = null;
            var bytes = Encoding.Unicode.GetBytes(data);

            using (var sha256 = new SHA256CryptoServiceProvider())
            {
                hash = sha256.ComputeHash(bytes);
            }

            return string.Join("", hash.Select(x => x.ToString("X")));
        }

最後に

今回はブロックチェーンの基本的なところを実装してみました。
参考になれば幸いです…!

まだネットワークやノードを実装できていないので今後作っていきたいですね。

読んでいただきありがとうございました!

bitFlyer ビットコインを始めるなら安心・安全な取引所で