@mizumotokのブログ

テクノロジー、投資、書評、映画、筋トレなどについて

javascriptでブロックチェーンをつくってみよう - 1 ブロックの実装

ビットコインを支える技術として注目をされているブロックチェーンですが、仕組みはそれほど複雑ではありません。

これらをjavasriptで実装しながら理解していきます。

イントロダクション

「ビットコインとブロックチェーン:暗号通貨を支える技術」によるとビットコインは4つの機能からできています。
f:id:mizumotok:20180421145005j:plain

ブロックチェーン
トランザクションのデータベース
マイナー
トランザクションを集めて、ブロックを作成する機能
ウォレット
秘密鍵を管理し、トランザクションを作成するための機能
ネットワークルーティング
ネットワークに参加するための機能

ネットワークルーティングは全ノードにありますが、その他の機能は持っていなかったり、ブロックチェーンの一部だけを持っていたりします。
今回はフルノード(全機能)を実装します。

環境構築

nodejsベースで開発します。パッケージマネージャはYarnを前提にします。
Macの場合はこんな感じで。

$ brew install nodebrew
$ nodebrew install-binary v8.11.1
$ nodebrew use v8.11.1
$ brew install yarn --without-node

プロジェクトを作成します。

$ mkdir blockchain-js
$ cd blockchain-js
$ yan init

eslint、flow、jestを使いたいので追加しておきます。

$ yarn add -D babel-cli babel-preset-env
$ yarn add -D eslint eslint-config-airbnb-base eslint-plugin-import babel-eslint
$ yarn add -D flow-bin flow-typed babel-preset-flow eslint-plugin-flowtype
$ yarn add -D jest eslint-plugin-jest

package.jsonにscriptsを追加。

  "scripts": {
    "test": "jest",
    "flow": "flow",
    "lint": "eslint src"
  },

.bashrc

{
  "presets": ["env", "flow"]
}

.eslintrc.js

module.exports = {
  "parser": "babel-eslint",
  "extends": ["airbnb-base", "plugin:jest/recommended"],
  "plugins": ["flowtype", "jest", "import"],
  "rules": {
      "no-console": 0,
  },
  "env": {
      "jest": true
  }
};

flowの初期化

$ yarn flow init

ここまでのソースはGitHubの00_setupブランチに公開しています。

ブロックの実装

ブロックにはブロック作成日時(timestamp)、前回のブロックのハッシュ値、ディフィカルティターゲット(マイニング困難度)、ナンス、トランザクションを持ちます。
最初のブロックはgenesisブロックといってハードコードされています。そのためのgenesis()メソッドをつくっておきます。プロパティは適当に。

src/blockchain/block.js

// @flow

const DIFFICULTY_TARGET = 255;

class Block {
  timestamp: number;
  prevHash: string;
  difficultyTarget: number;
  nonce: number;
  transactions: Array<any>;

  constructor(
    timestamp: number,
    prevHash: string,
    difficultyTarget: number,
    nonce: number,
    transactions: Array<any>,
  ) {
    this.timestamp = timestamp;
    this.prevHash = prevHash;
    this.difficultyTarget = difficultyTarget;
    this.nonce = nonce;
    this.transactions = transactions;

  static genesis(): Block {
    return new this(0, '0'.repeat(64), DIFFICULTY_TARGET, 0, []);
  }
}

export default Block;

次のブロックに渡すためのハッシュ値を返すメソッドを用意しましょう。そのハッシュ値がディフィカルティターゲットを満たしているか検証できるようにisValidメソッドもつくります。
crypto-jsのsha256関数を使います。

$ yarn add crypto-js

src/blockchain/block.js

import SHA256 from 'crypto-js/sha256';
hash(): string {
    return SHA256(JSON.stringify([
      this.timestamp,
      this.prevHash,
      this.difficultyTarget,
      this.nonce,
      this.transactions,
    ])).toString();
  }

  isValid(): bool {
    const hash = this.hash();
    return Number(`0x${hash}`) < 2 ** this.difficultyTarget;
  }

今回は以下の計算結果をマイニング成功基準としました。

ハッシュ値 < 2^{ディフィカルティターゲット}

テスト

jestをつかってテストをします。flowが通るように、jestのflow-typedを追加しておきます。

$ yarn flow-typed install jest@v22.x.x

.flowconfig

[libs]
flow-typed

genesis、hash、isValidあたりのテストをつくってみましょう。
src/__tests__/blockchain/block.test.js

// @flow

import Block from '../../blockchain/block';

describe('Block', () => {
  let genesis;
  beforeEach(() => {
    genesis = Block.genesis();
  });

  it('genesis block', () => {
    expect(genesis.timestamp).toBe(0);
    expect(genesis.prevHash).toBe('0'.repeat(64));
  });

  it('hashは64桁の16進数', () => {
    const block = new Block(new Date(), genesis.hash(), 0, 0, []);
    const hash = block.hash();
    expect(/[0-9a-f]{64}/.test(hash)).toBe(true);
  });

  it('isValid()', () => {
    // 最小difficultyTarget
    const minDifficultyBlock = new Block(new Date(), genesis.hash(), 0, 0, []);
    expect(minDifficultyBlock.isValid()).toBe(false);

    // 最大difficultyTarget
    const maxDifficultyBlock = new Block(new Date(), genesis.hash(), 256, 0, []);
    expect(maxDifficultyBlock.isValid()).toBe(true);
  });
});

テストは問題なく通ると思います。

$ yarn test

ここまでのソースはGitHubの01_blockブランチに公開しています。

まとめ

今回は環境構築をして、ブロックの実装をしました。ブロックではハッシュ値の計算、ディフィカルティターゲットに基づいた有効性の検証ができるようになっています。
次回はブロックをハッシュ値で連結させて、ブロックチェーンの実装をします。

GitHub

GitHub - mizumotok/blockchain-js

ビットコインとブロックチェーン:暗号通貨を支える技術

ビットコインとブロックチェーン:暗号通貨を支える技術