@mizumotokのブログ

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

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

ビットコインJavascriptで実装しながら理解しましょう。
前回までにブロックの実装を行ないました。今回はブロックをチェーンでつなげるブロックチェーンの実装を行ないます。

前回までの状態を再現

必要な場合は、前回の状態を再現しましょう。

$ git clone https://github.com/mizumotok/blockchain-js.git
$ cd blockchain-js
$ git checkout 01_block


ブロックチェーンの実装

ブロックチェーンはブロックを配列で持ちます。最初のブロックはgenesisブロックなので、constructorで持たせておけばいいです。

src/blockchain/blockchain.js

// @flow

import Block from './block';

class Blockchain {
  chain: Array<Block>;

  constructor() {
    this.chain = [Block.genesis()];
  }
}

export default Blockchain;

src/blockchain/index.js

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

export default Blockchain;
export { Block };

新しいブロックはマイナーがつくってそれをブロックチェーンについていくのですが、追加される際にそのブロックは追加するのに適当か検証しましょう。
src/blockchain/blockchain.js

  addBlock(block: Block): bool {
    if (!this.canAddBlock(block)) {
      return false;
    }
    this.chain.push(block);
    return true;
  }

  canAddBlock(block: Block): bool {
    const lastBlock = this.chain[this.chain.length - 1];
    return block.prevHash === lastBlock.hash() &&
      block.timestamp > lastBlock.timestamp &&
      block.isValid();
  }

ブロックチェーンの最後のブロックのハッシュ値は次のブロックを作るときに使われますので、簡単に取り出せるようにしておくとよいですね。
src/blockchain/blockchain.js

  lastHash(): string {
    return this.chain[this.chain.length - 1].hash();
  }

テスト

今回作成したメソッド(コンストラクタ、addBlock、canAddBlock、lastHash)のテストを用意しておけば完璧です。
src/__tests__/blockchain/blockchain.test.js

// @flow

import Blockchain, { Block } from '../../blockchain';

describe('Blockchain', () => {
  let blockchain;
  let newBlock;

  beforeEach(() => {
    blockchain = new Blockchain();
    newBlock = new Block(new Date(), blockchain.chain[0].hash(), 256, 0, []);
  });

  it('初期値はgenesis blockのみ', () => {
    expect(blockchain.chain).toHaveLength(1);
    const block = Block.genesis();
    expect(blockchain.chain[0].hash()).toBe(block.hash());
  });

  it('canAddBlock test', () => {
    const olderBlock = new Block(-1, blockchain.chain[0].hash(), 256, 0, []);
    expect(blockchain.canAddBlock(olderBlock)).toBe(false);

    const wrongHashBlock = new Block(new Date(), 'xxxx', 256, 0, []);
    expect(blockchain.canAddBlock(wrongHashBlock)).toBe(false);

    const inValidBlock = new Block(new Date(), blockchain.chain[0].hash(), 0, 0, []);
    expect(blockchain.canAddBlock(inValidBlock)).toBe(false);

    expect(blockchain.canAddBlock(newBlock)).toBe(true);
  });

  it('addBlock test', () => {
    const inValidBlock = new Block(new Date(), blockchain.chain[0].hash(), 0, 0, []);
    let result = blockchain.addBlock(inValidBlock);
    expect(result).toBe(false);
    expect(blockchain.chain).toHaveLength(1);

    result = blockchain.addBlock(newBlock);
    expect(result).toBe(true);
    expect(blockchain.chain).toHaveLength(2);
    expect(blockchain.chain[0].hash()).toBe(blockchain.chain[1].prevHash);
  });

  it('lastHash test', () => {
    const genesis = Block.genesis();
    expect(blockchain.lastHash()).toBe(genesis.hash());

    blockchain.addBlock(newBlock);
    expect(blockchain.lastHash()).toBe(newBlock.hash());
  });
});

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

まとめ

今回はブロックチェーンの実装をしました。ブロックを配列で持たせ、ブロック追加時にブロックの検証をするようにしました。また最後のブロックのハッシュ値を簡単に出せるメソッドを用意しました。
次回はブロックをマイニングして生成する、マイナーの実装をします。

GitHub

GitHub - mizumotok/blockchain-js

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

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