🦊

【Dev】Blockchainをjsで実装してみる(その4:Chainの仕組み編)

2021/10/05に公開

ここまでで、Blockの中には複数のTransactionが含まれている、というところまで解説してきました。今回はBlockを繋げるChainの仕組みについてです。

一つ一つのBlockが正しい情報である(改竄された情報ではない)ということを担保するのがBlockchainの "chain" の部分になります。Chainがどのように作られているかというと、ひとつ前のBlockのHash値(すなわち "previousBlockHash")とそのBlock自身のHash値との関係性を担保することによって、一つ一つのBlockがずーっとチェーンのように繋がり続けていることを表しているのです。

これらのHash値の一貫性が保たれていない部分があるとすれば、明確にそのデータは"改竄されている"と判断することができます。ハッシュ値はそのままにamount/sender/recipientなどのデータを改竄したとしても、hash値に不整合が生じるために不整合データであることがすぐに判明します。

またデータを改竄してhash値も再計算したとしても、前後のブロックとのhash値の整合性が崩れてしまい、Blockchainの一貫性が失われてしまいます。

また、チェーンとして繋がれるそれぞれのブロックは複数のノードにより保持、公開されているため、中央集権的に管理されているRDBをこっそり書き換えてしまえばOK、的なデータ修正はできないのです。

ではまず、hash値を生成するメソッドがこちら。

dev/blockchain.js
Blockchain.prototype.hashBlock = function(
	previousBlockHash, currentBlockData, nonce) {
    const dataAsString =
	    previousBlockHash
	    + nonce.toString()
	    + JSON.stringify(currentBlockData);
    const hash = sha256(dataAsString);
    return hash;
}

"currentBlockData" にはTransactionの詳細情報がセットされており、hash値のインプットになるcurrentBlockDataに含まれるデータが改竄されると、hash値が全く別物に変わってしまうため改竄をすぐに検知できるというわけです。また、hash値の生成は実はこれだけではなく、あるルールに基づいたhash値でなければいけないのです。ルールに基づいたhash値であるかどうかを判定しているのがこちらのメソッドです。

dev/blockchain.js
Blockchain.prototype.proofOfWork = function(previousBlockHash, currentBlockData) {
    let nonce = 0;
    let hash = this.hashBlock(previousBlockHash, currentBlockData, nonce);
    while (hash.substring(0, 4) !== '0000') {
        nonce++;
        hash = this.hashBlock(previousBlockHash, currentBlockData, nonce);
    }

    return nonce;
}

「あるルール」とはなんだったのか。ここでコーディングされている例だと、hash値の先頭4桁がゼロでなければいけない、というのが「あるルール」です。先頭4桁が0になるようなhash値を生成するnonceを見つけるためにひたすらループの中で計算を繰り返すのです。ルール自体はシンプルですが、これが地味に計算に時間がかかるのです。そして、先頭4桁がゼロになるhash値というのはなかなか真似ができない、、といえばいいのでしょうか。限りなくユニークなものなのです。ちなみに、Bitcoinのhash値は確か先頭16桁がゼロになるようになっていたと記憶しています。

実際にテストしてみましょう。

dev/test.js
const Blockchain = require('./blockchain');
const bitcoin = new Blockchain();

const previousBlockHash = '0000fhse@aip9ahf0pahXgr40';
const currentBlockData = [
    {
        amount: 10,
        sender: 'ichiro_347w8058rghgre0',
        recipient: 'shohei_fa934wf8h7g358'
    },
    {
        amount: 30,
        sender: 'yoshihide_jfsoep9ehgf579gha',
        recipient: 'yuriko_fsap89a3hga08sgsg'
    }
];

console.log(bitcoin.proofOfWork(previousBlockHash, currentBlockData));

こんなテストコードを書いて実行すると、nonceは 259941 になります。259941回ループの中で計算を繰り返してようやく導き出されたnonce値です。そしてこのnonceを使って導き出されるhash値は 0000ac5d2edfee12a3a92e6a9ad06f61f301a9bec09410b206321617a4d2b94e でした。

一つのブロックの中に previousBlockHashと(currentBlock)Hashの二つを格納することで、改竄が困難なBlockのChainをつくり出しているのです。いかがでしょう?ここで実装しているのはコンセプトを理解するためのコードではありますが、仕組みとしては意外とシンプルではないですか?

次回はマルチノードでのBlockchain構築の仕組みについて触れられればと思います!
いったん落ち着いたら再開します!

Discussion