【Proof of Work】JavaScriptでブロックチェーンにおけるnonceを理解する

前回の記事「【ソースコードあり】JavaScriptでブロックチェーンを作ってみた」で簡単なブロックチェーンをJavaScriptで実装し、それを紹介しましたが今回はその続編です。まだ記事を読んでいない方はそちらに一度目を通しておくと良いでしょう。

今回はブロックチェーンのブロックにおける「nonce(ノンス、ナンス)」について簡単に解説していこうと思います。コードは前回のものを転用して説明していきます。

スポンサードリンク

Proof of Work(プルーフ・オブ・ワーク)とは

nonceについて理解する前にまずはビットコイン・ブロックチェーンにも採用されている「PoW」すなわち「Proof of Work(プルーフ・オブ・ワーク)」について紹介しておきます。PoWとは、各取引を認証するために算出しなければならないデータ、またはそのようなシステムのことを総称して指します。要は自分が計算した証を記録するためのシステム、またはそのデータのことです。ビットコイン等はこのシステムによりデータの改ざんを防ぎます。このPoWを実現するために使われているのがnonceという訳です。では、nonceが一体どのような働きをしているのでしょうか?

ブロックチェーンにおけるnonceの働き

nonceは言ってしまえば、単純にランダムな値のことです。ブロックチェーンにおいてハッシュ値を計算するためにこのランダムな値であるnonceを使用します。なぜnonceが必要なのかは前回の記事では補えていないので、今回の記事で補填しておこうと思います。

前回実装したブロックチェーンではnonceを導入しておらず、そのブロックのハッシュ値を計算するために

・ブロック番号

・タイムスタンプ

・取引内容(任意のデータ)

・前回のハッシュ値

この4つのデータを引数に取ってSHA256で計算しました。ブロックチェーンではこれらに加えてコンピュータがランダムに計算した値であるnonceという値も引数にとってハッシュ値を生成します。

ところで、ブロックチェーンにおけるハッシュ値はその最初の数字が0から始まることが決まっています(ビットコインでは少なくともそう)。頭が0から始まるようにハッシュ値を計算しているので、もし頭が0でなければブロックはハッシュ値をループで回し再計算する必要があります。ハッシュ値を変更するにはハッシュ値を計算するための関数にとる引数の内容を変更する必要がありますが、上に記述した

・ブロック番号

・タイムスタンプ

・取引内容(任意のデータ)

・前回のハッシュ値

は変更することができません。よってもう1つ、変更できる変数を用意する必要があります。それが「nonce(ノンス、ナンス)」なのです。

ビットコイン・ブロックチェーン上では各ノードが各取引のハッシュ値を計算するためにnonceを繰り返し計算します。そして、最も早くnonceを見つけたノードに対して報酬が支払われるシステムになっています。これがいわゆる「マイニング」の仕組みであり、すなわちマイニングとは「ハッシュ値を求めるためにnonceを計算すること」に他ならないのです。

実際に簡単なnonceを実装してみる(ブロックにマイニング機能を付ける)

まずはブロックにnonceを定義します。前回のコードからnonceを追加しておきましょう。

初期値には0を代入しておきます。

次に同じBlockクラス配下にマイニングをするためのmineBlock()関数を定義します。

引数にdifficultyを取ったり、条件式を実装していたりしてわかりにくいと思いますが1行ずつ解説していきます。

まず、mineBlock(){}mineBlock()関数を定義し、引数にdifficultyを定義します。このdifficultyはマイニングにおける難易度を定義するための引数です。

マイニングの難易度とは、その名の通りマイニングにおける計算量を調整するために与えられた数値です。この数値が大きくなればなるほどマイニングの難易度は上がっていきます(つまり、ハッシュ値が計算しにくくなるということ。計算量が単純に増加するということ)。ここではマイニングの難易度があがるということを、ハッシュ値の頭から0が続く数が増加することと同値とします。ハッシュ値が「0」から始まるのと、ハッシュ値が「0000」から始まるのとでは後者の方が大きく難易度が上がることが理解できるかと思います。

これが理解できれば関数内の1行目の処理は理解可能です。whileの条件式には「ハッシュ値の頭から0が何個続くか」を定義しており、それはdifficultyに依存しています。

また、条件式がfalseな限り、nonceをインクリメントしながらハッシュ値を再計算していることが確認できるかと思います。ここではインクリメントをしていますが、実際にはランダムな値を計算してハッシュ値を求めている場合が多いです。

whileを抜けると、ハッシュ値の計算に成功しているということなので、console.log()でその結果を出力しています。

 

さて、これで上記の関数の実装は終了なのですが、これだけではマイニングできません。というのも前回のコードのままだったら、calculateHash()関数は同じハッシュ値を返してしまうからです。これを、nonceを導入することによってコードを変えていきましょう。

また、difficultyもBlockchainクラスに定義しておきます。この数値は任意に設定しても大丈夫です。(ただし、あまり大きすぎるとマイニングするのに時間がかかるので適度に調整してください。今回は5で設定しています。)

以上でnonceの実装は終了ですが、実行方法が前回と異なるので下の部分(addBlock()関数)もコードを変更しておいてください。

以上が変更できたら、マイニングを実際に行うためのコードを追加します。最終行にこれを書いておきましょう。

ブロック内容は任意に変更してもよい

マイニングを実行する

それではスクリプトを実行してみましょう。

$ node main.js
Minig Block1...
Block mined...00000d4bc2977ee2700fd4331c3947943cfa562210ef30a81ecbc9cc8ed526a3
Minig Block2...
Block mined...00000db5d0021a6d03e668057f9cd3ecfb7c471827bef53665986942a31a4b82
Minig Block3...
Block mined...00000e3174091f725f9cdb57beaa4be3223f93d8b76af353034776ba457f7d1c

上記のように表示されたらマイニングに成功しています。きちんとdifficultyで設定した5が動作していることを確認してください。(ハッシュ値の頭~5桁目までが0)

ソースコード全容

今回もGistでソースコードを公開しているのでこちらに埋め込んでおきましょう。うまく動作しない人はこちらのコードをコピペして実行してみてください。

おわりに

今回はPoWの概要と、PoWに使われているnonceの解説を行いました。ブロックチェーンではこのnonceによってハッシュ値が決定します。ビットコイン・ブロックチェーンではこのnonceの計算時間が均等になるように難易度が調整されており、nonceの発見者には報酬が与えられるといううまい仕組みで構成されています。このようにデータが改ざんされない、かつノードが積極的にブロックチェーン・ネットワークに参加できる仕組みを実装しているビットコインに導入されている技術にはやはり目をひかれる所がありますね…。

今回の実装も、JavaScriptでなくても書けるので是非自分の得意な言語で再実装してみてはいかがでしょうか?

スポンサードリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です