ブロックチェーンを応用したデータの存在証明を Factom でやってみる

ビットコインのブロックチェーンを利用してドキュメントの存在証明を可能にする Factom というプロトコルを試してみましたので、紹介したいと思います。

# Factom とは
![screenshot-www.factom.com 2016-11-08 00-33-59.png](https://qiita-image-store.s3.amazonaws.com/0/44003/bd5fc249-deae-b6e1-9ff1-d452a29539a7.png)

Factom はビットコイン 2.0 (ビットコイン技術を応用して、通貨以外の役割・機能を持たすことを主目的とした技術・プロジェクト)のひとつです。

改ざん不能性を持つブロックチェーンに、貸付記録や証券、保険、権利書などのあらゆるドキュメントをハッシュ値として記録することにより、「あるドキュメントがある時点において確かに存在した」ことを証明 (Proof of Existence) することを目的としています。

# Factom の特徴

Factom は独自のチェーンと通貨 (Factoid) を持っており、独自のチェーン上の記録をビットコインのブロックチェーンに書き込むようになっています。ビットコインのブロックチェーンの上のレイヤに存在する、ともいえます。

なぜビットコインのブロックチェーンに直接記録しないのかというと、下記のような「スピード・コスト・ブロート」の課題があるからです。

- スピード
    - ビットコインでは、平均して10分に1つのブロックが生成されるように PoW の難易度が設定されている
- コスト
    - ビットコインのブロックチェーン上に記録する度にマイナーへの手数料が発生する
- ブロート
    - ビットコインでは、ブロックサイズは 1MB まで、トランザクションの処理能力は毎秒7トランザクションに制限されている

Factom は、ドキュメントを一定時間毎にハッシュツリーとしてまとめて、ビットコインのブロックチェーンの1トランザクションとして記録するという仕組みをとることで、これらの課題を解決しています。
また、ドキュメントはすべてハッシュ化されたものを記録するので、ドキュメントの存在は公開されつつも、ドキュメントの中身は漏洩しないという特徴があります。

![factom.jpg](https://qiita-image-store.s3.amazonaws.com/0/44003/10c7d371-f3bb-3ebe-2259-563b195ae747.jpeg)

ビットコインのブロックチェーンを使いながらも、大量のドキュメントを早く・安価に、そして機密を保護しつつ記録でき、その存在証明を可能とするのが Factom と言えます。

# ローカル環境で試す

以下のサンドボックス用のセットアップガイドに沿って進めていきます。

https://github.com/FactomProject/FactomDocs/blob/master/developerSandboxSetup.md

## ソフトウェアのインストール

まずは下記ドキュメントを見つつ、Factom のソフトウェアをインストールします。

https://www.factom.com/devs/docs/howto/binaries-install-guide

Mac では `/Applications/FactomApps` にインストールされますので、ターミナルで確認します。
以下のアプリケーションがインストールされていることを確認してください。

- Factomd: メインプログラム
    - blockchainを管理するパブリックネットワークに接続し、ネットワークルールを適用する
    - 起動すると localhost:8088 に立ち上がる
- Fctwallet: 秘密鍵を保持するためのアプリケーション
    - Factoid トランザクションを構築し、Factom にユーザーデータを追加するために、暗号関連の操作を処理する
    - 起動すると localhost:8089 に立ち上がる
- Factom-CLI: ユーザが factomd と fctwallet とのインタフェースするためのプログラム
    -  factomd と fctwallet 経由でチェーン、エントリ、および Factoid トランザクションを作成する

```
$ cd /Applications/FactomApps
$ ls
factom-cli  factomd     fctwallet   staticfiles walletapp
```

また、 `factom-cli help` で使用できるコマンド一覧が出ればOKです。

```
$ ./factom-cli help
factom-cli addecoutput [-r] TXNAME NAME|ECADDRESS|DNSADDRESS AMOUNT
        Add an ecoutput (purchase of entry credits to a transaction. Amount is denominated in factoids

factom-cli addfee TXNAME FCADDRESS
        Adds the needed fee to the given transaction. The Factoid Address specified must be an input to the transaction, and it must have a balance able to cover the additional fee. Also, the inputs must
exactly balance the outputs,  since the logic to understand what to do otherwise is quite complicated, and prone to odd behavior.

factom-cli addinput TXNAME NAME|FCADDRESS AMOUNT
        Add an input to a transaction.
...
```

## サンドボックス用の設定

Factom では、サンドボックス用の環境設定や鍵ペアが公式で用意されており、ローカル環境であればトランザクションの作成・データの追加などを無料で試すことができます。

デフォルト設定ではテストネットに接続してしまい、テストネットコインが必要になってしまうので、サンドボックス用の設定を行います。

まず、`$HOME/.factom` ディレクトリを作成して、`factomd.conf`を作ります。
`factomd.conf` には下記の内容をコピーしてください。

https://raw.githubusercontent.com/FactomProject/FactomCode/master/factomd/factomd.conf

そして、下記の変更を加えて保存します。

- Nodemode を `FULL` から `SERVER` に変更する
    - factomd でブロックチェーンを作成させるための設定
- ExchangeRate を `00000100` に変更する
    - factoid からより多くのエントリを作成させるための設定
- 必要に応じて DirectoryBlockInSeconds を調整する
    - 600で10分間に1ブロック生成、デフォルトでは60(1分間に1ブロック生成)

## Factomd の起動

```
$ ./factomd                                                                                                                                                                          [13:47:40]
2016/11/02 13:47:40 read factom config file:  /Users/[USERNAME]/.factom/factomd.conf
Go compiler version: go1.7.3
boltDBpath: /Users/[USERNAME]/.factom/

'factomd initializeonly' will do just that.  Initialize and stop.


>>>>>>>>>>>>>>>>>  SERVER MODE <<<<<<<<<<<<<<<<<<<<<<<


2016/11/02 13:47:40 web.go serving :8088
```

## Fctwallet の起動

```
$ ./fctwallet                                                                                                                                                                        [13:47:49]
2016/11/02 13:47:49 read factom config file:  /Users/[USERNAME]/.factom/factomd.conf
+================+
|  fctwallet v1  |
+================+
2016/11/02 13:47:49 web.go serving localhost:8089
```

## Entry Credit のチャージ

Factom では、エントリ(データ)を追加するために Factoid という独自通貨を使って、Entry Credit と交換する必要があります。
現在の自分の残高は、`factom-cli balance` で確認することができます。始めは何も持っていません。

```
$ ./factom-cli balance
```

今回は、以下のような 0 Entry Credits の鍵ペアを持っているとします。下記はサンドボックス用に用意されたもので、そのまま使用できます。

- 秘密鍵: `Es2Rf7iM6PdsqfYCo3D1tnAR65SkLENyWJG1deUzpRMQmbh9F3eG`
- 公開鍵: `EC2DKSYyRcNWf7RS963VFYgMExoHRYLHVeCfQ9PGPmNzwrcmgm2r`

```
$ ./factom-cli importaddress zeros Es2Rf7iM6PdsqfYCo3D1tnAR65SkLENyWJG1deUzpRMQmbh9F3eG
zeros EC2DKSYyRcNWf7RS963VFYgMExoHRYLHVeCfQ9PGPmNzwrcmgm2r
$ ./factom-cli balances

  Entry Credit Addresses

    zeros    EC2DKSYyRcNWf7RS963VFYgMExoHRYLHVeCfQ9PGPmNzwrcmgm2r              0


```

また、以下のジェネシスブロックにある 300 Factoids の鍵ペアを使用します。
それはメインネットでは枯渇してしまったものですが、サンドボックス環境では使用することができます。

- 秘密鍵: `Fs3E9gV6DXsYzf7Fqx1fVBQPQXV695eP3k5XbmHEZVRLkMdD9qCK`
- 公開鍵: `FA2jK2HcLnRdS94dEcU27rF3meoJfpUcZPSinpb7AwQvPRY6RL1Q`

```
$ ./factom-cli importaddress sand Fs3E9gV6DXsYzf7Fqx1fVBQPQXV695eP3k5XbmHEZVRLkMdD9qCK
sand FA2jK2HcLnRdS94dEcU27rF3meoJfpUcZPSinpb7AwQvPRY6RL1Q
$ ./factom-cli balances

  Factoid Addresses

     sand    FA2jK2HcLnRdS94dEcU27rF3meoJfpUcZPSinpb7AwQvPRY6RL1Q           300.0

  Entry Credit Addresses

    zeros    EC2DKSYyRcNWf7RS963VFYgMExoHRYLHVeCfQ9PGPmNzwrcmgm2r              0

```

これで 300 Factoids と 0 Entry Credits のウォレットができました。
Factom では、公開鍵をラベルとしても使用していて、`FA` で始まるものが Factoid の公開鍵、 `FC`で始まるものが Entry Credit の公開鍵になります。

## Factoid トランザクションを作成

次に Factoid トランザクションを作成します。
以下のコマンドで、10 Factoids を使って Entry Credits を購入します。

```
$ ./factom-cli newtransaction trans1
Success building a transaction
$ ./factom-cli addinput trans1 sand 10
Success adding Input
$ ./factom-cli addecoutput trans1 zeros 10
Success adding Entry Credit Output
$ ./factom-cli addfee trans1 sand
Added             0.000012 to sand
$ ./factom-cli sign trans1
Success signing transaction
$ ./factom-cli transactions
trans1:  Fee Due: 0.000012   Currently will pay: 0.000012

Transaction (size 181):
                 Version: 2
          Transaction ID: f10de5a770e795b9dfddfbeac3975155b0e6bddcd41370a85faa68eaa4211da6
          MilliTimestamp: 00000158236d2fa8 Wed, 02 Nov 2016 05:05:08 +0000
                # Inputs: 0001
               # Outputs: 0000
   # EntryCredit Outputs: 0001
      input:      10.000012   FA2jK2HcLnRdS94dEcU27rF3meoJfpUcZPSinpb7AwQvPRY6RL1Q
   ecoutput:      10.0        EC2DKSYyRcNWf7RS963VFYgMExoHRYLHVeCfQ9PGPmNzwrcmgm2r
 RCD 1: 01  718b5edd2914acc2e4677f336c1a32736e5e9bde13663e6413894f57ec272e28
 signature: 3864f4456a4b7f07e633cef0463aa3128ae1148f273bf942a9b4bb746b32c4ba
            44e242b6efa644d67b5ee444a366a27d93052b7a345b6f12a1cb1646b2582702
$ ./factom-cli submit trans1
Success Submitting transaction
```

これで残高を確認してみます。

```
$ ./factom-cli balances

  Factoid Addresses

     sand    FA2jK2HcLnRdS94dEcU27rF3meoJfpUcZPSinpb7AwQvPRY6RL1Q           289.999988

  Entry Credit Addresses

    zeros    EC2DKSYyRcNWf7RS963VFYgMExoHRYLHVeCfQ9PGPmNzwrcmgm2r       10000000

```

`sand` からは 10 Factoids と手数料分の 0.000012 Factoids が減り、`zeros` には 10000000 Entry Credits が増えたことが分かります。

## エントリを作成

Factom のすべてのエントリ(データ)は、チェーンに所属する必要があるので、まずはチェーンを作成します。
チェーンを作成する際には、初期のエントリが追加されますので、そのデータも同時に渡します。

```
$ echo "This is the payload of the first Entry in my chain" | ./factom-cli mkchain -e thisIsAChainName -e moreChainNameHere zeros
Creating Chain: 23985c922e9cdd5ec09c7f52a7c715bc9e26295778ead5d54e30a0a6215783c8
```

作成されたチェーンIDを指定して、エントリを作成します。`-e` オプションで外部アプリケーションのIDを紐付けることができます。
エントリに渡すデータは Factom のチェーン上で公開されてしまうので、機密性のあるデータはハッシュ値として渡しますが、今回はわかりやすさのためにデータをそのまま渡します。

```
$ echo "This is the payload of an Entry" | ./factom-cli put -e newextid -e anotherextid -c 23985c922e9cdd5ec09c7f52a7c715bc9e26295778ead5d54e30a0a6215783c8 zeros
Creating Entry: c0eeebbae3d50accff5b632ca5a6a54a8f63d7a61f747d28c5587c0f9186cc88
```

出力されるエントリハッシュを使用して、作成したエントリを確認します。

```
$ ./factom-cli get entry c0eeebbae3d50accff5b632ca5a6a54a8f63d7a61f747d28c5587c0f9186cc88
ChainID: 23985c922e9cdd5ec09c7f52a7c715bc9e26295778ead5d54e30a0a6215783c8
ExtID: newextid
ExtID: anotherextid
Content:
This is the payload of an Entry
```

チェーン作成に 10 factoid, エントリ作成に 1 factoid がかかるように設定しているはずなので、 `factom-cli balances` コマンドで残高を確認してください。

```
$ ./factom-cli balances                                                                                                                                                                                            [14:45:23]

  Factoid Addresses

     sand    FA2jK2HcLnRdS94dEcU27rF3meoJfpUcZPSinpb7AwQvPRY6RL1Q           289.999988

  Entry Credit Addresses

    zeros    EC2DKSYyRcNWf7RS963VFYgMExoHRYLHVeCfQ9PGPmNzwrcmgm2r        9999988

```

11 factoid 減っていることが分かります。

# 確認する

## ログで確認

Factomd で何が起きているかは、`$HOME/.factom/factom-d.log` にあるログで、概ね確認することができます。以下は一部を抜粋しました。

```
2016-11-02T14:12:53+09:00 [INFO] PROC: EntryCreditBlock: block28 created for chain: 000000000000000000000000000000000000000000000000000000000000000c
2016-11-02T14:12:53+09:00 [INFO] PROC: Admin Block: block 28 created for chain: 000000000000000000000000000000000000000000000000000000000000000a
2016-11-02T14:12:53+09:00 [INFO] PROC: Factoid chain: block 28 created for chain: 000000000000000000000000000000000000000000000000000000000000000f
2016-11-02T14:12:53+09:00 [INFO] PROC: EntryBlock: block0 created for chain: 23985c922e9cdd5ec09c7f52a7c715bc9e26295778ead5d54e30a0a6215783c8
2016-11-02T14:12:53+09:00 [INFO] PROC: Created directory /Users/[USERNAME]/.factom/data/export/23985c922e9cdd5ec09c7f52a7c715bc9e26295778ead5d54e30a0a6215783c8
2016-11-02T14:12:53+09:00 [DEBUG] PROC: in buildBlocks
2016-11-02T14:12:53+09:00 [DEBUG] PROC: **** new Dir Block
2016-11-02T14:12:53+09:00 [DEBUG] ANCH: UpdateDirBlockInfoMap: (*common.DirBlockInfo)(0x42103c100)({
 DBHash: (*common.Hash)(0x421a029a0)(68d2f122945ed8b49ffb4cf814d0b464bd6b694a136906dd56798fd4d42ee7c6),
 DBHeight: (uint32) 28,
 Timestamp: (int64) 1478063520,
 BTCTxHash: (*common.Hash)(0x421a02b20)(0000000000000000000000000000000000000000000000000000000000000000),
 BTCTxOffset: (int32) 0,
 BTCBlockHeight: (int32) 0,
 BTCBlockHash: (*common.Hash)(0x421a02b60)(0000000000000000000000000000000000000000000000000000000000000000),
 DBMerkleRoot: (*common.Hash)(0x421a02a60)(973c6a3c57048929fe4ad68edacd294ccc38b065fae60e45cca17974666966dc),
 BTCConfirmed: (bool) false
})

2016-11-02T14:12:53+09:00 [INFO] PROC: DirectoryBlock: block28 created for directory block chain: 000000000000000000000000000000000000000000000000000000000000000d
2016-11-02T14:12:53+09:00 [DEBUG] ANCH: SendRawTransactionToBTC: hash=973c6a3c57048929fe4ad68edacd294ccc38b065fae60e45cca17974666966dc, dir block height=28
2016-11-02T14:12:53+09:00 [WARNING] ANCH: 

$$$ WARNING: rpc clients and/or wallet are not initiated successfully. No anchoring for now.

```

一定時間でブロックが作成され、アンカー(ビットコインのブロックチェーンに書き込むこと)がされようとしているのがわかります。
現在はサンドボックス環境なので、アンカーされていません。

## get コマンドで確認

get コマンドで現在の状況を知ることができます。

### All Entries

すべてのエントリを取得します。

```
$ ./factom-cli get allentries 23985c922e9cdd5ec09c7f52a7c715bc9e26295778ead5d54e30a0a6215783c8
Entry [0] {
ChainID: 23985c922e9cdd5ec09c7f52a7c715bc9e26295778ead5d54e30a0a6215783c8
ExtID: thisIsAChainName
ExtID: moreChainNameHere
Content:
This is the payload of the first Entry in my chain

}
Entry [1] {
ChainID: 23985c922e9cdd5ec09c7f52a7c715bc9e26295778ead5d54e30a0a6215783c8
ExtID: newextid
ExtID: anotherextid
Content:
This is the payload of an Entry

}
```

### Chain Head

指定したチェーンの一番最新のエントリブロックを取得します。

- PrevKeyMR: 一つ前のエントリーのマークルツリー
- BlockSequenceNumber: そのチェーン内のエントリーの通番

```
$ ./factom-cli get chainhead 23985c922e9cdd5ec09c7f52a7c715bc9e26295778ead5d54e30a0a6215783c8
EBlock: 022c5182bdca03d26c791a3cce684f026bac801665181f6a28d8176369320ee0
BlockSequenceNumber: 1
ChainID: 23985c922e9cdd5ec09c7f52a7c715bc9e26295778ead5d54e30a0a6215783c8
PrevKeyMR: 8fa5ff97c680eebe39da72e78dbf7a50834f5a8e55d12ba5cf12f21fa2cc3a25
Timestamp: 1478063580
EBEntry {
        Timestamp 1478064060
        EntryHash c0eeebbae3d50accff5b632ca5a6a54a8f63d7a61f747d28c5587c0f9186cc88
}
```

### Entry Block

指定したエントリブロックを取得します。

```
$ ./factom-cli get eblock 022c5182bdca03d26c791a3cce684f026bac801665181f6a28d8176369320ee0
BlockSequenceNumber: 1
ChainID: 23985c922e9cdd5ec09c7f52a7c715bc9e26295778ead5d54e30a0a6215783c8
PrevKeyMR: 8fa5ff97c680eebe39da72e78dbf7a50834f5a8e55d12ba5cf12f21fa2cc3a25
Timestamp: 1478063580
EBEntry {
        Timestamp 1478064060
        EntryHash c0eeebbae3d50accff5b632ca5a6a54a8f63d7a61f747d28c5587c0f9186cc88
}
```

### Entry

指定したエントリを取得します。

```
$ ./factom-cli get entry c0eeebbae3d50accff5b632ca5a6a54a8f63d7a61f747d28c5587c0f9186cc88
ChainID: 23985c922e9cdd5ec09c7f52a7c715bc9e26295778ead5d54e30a0a6215783c8
ExtID: newextid
ExtID: anotherextid
Content:
This is the payload of an Entry
```

### Directory Block

指定したディレクトリブロックを取得します。

```
$ ./factom-cli get dblock 13eac8abb511e52b0216e6b47e8a7d70052d88409995f53fe39b4dfeab8bb925
PrevBlockKeyMR: a7b0378c6302cefd2be54facdaf6ec8ce93460d2e3d64ac8b601e7f11827d802
Timestamp: 1478063940
SequenceNumber: 36
EntryBlock {
        ChainID 000000000000000000000000000000000000000000000000000000000000000a
        KeyMR b4049b55589dbb990fc0e60e1b8d8da3049b8cadb6ce4c94d8cbcfe6990412bc
}
EntryBlock {
        ChainID 000000000000000000000000000000000000000000000000000000000000000c
        KeyMR 029cbac9225ef5efabe474ef985bdd7973e1bec6587596766726e21171ad41ea
}
EntryBlock {
        ChainID 000000000000000000000000000000000000000000000000000000000000000f
        KeyMR 85bfa8d03a26b24179df2538e6cc67dbdeb12834d014677669432b8903cdec90
}
```

### Head

一番最新のディレクトリブロックを取得します。

```
$ ./factom-cli get head
DBlock: 7a400bcbb511d5c2c15ca678c09b0cea1f09a4d10e373b8e41891872b8be50b0
PrevBlockKeyMR: e4a44ac7a14be5c21e2cc141b2526f616729acdf11ebd4dfe1c018afb0cd2709
Timestamp: 1478064060
SequenceNumber: 38
EntryBlock {
        ChainID 000000000000000000000000000000000000000000000000000000000000000a
        KeyMR b0fb6bfa32cab49c6140c8ae61fe5e8b422ce9a886fec63c3f58a2406fd2e971
}
EntryBlock {
        ChainID 000000000000000000000000000000000000000000000000000000000000000c
        KeyMR b44df5c09cd2a5e669afc70e85259479a975ea70e1d6caaf1fffb60cd758ccc5
}
EntryBlock {
        ChainID 000000000000000000000000000000000000000000000000000000000000000f
        KeyMR a6acf6b0d37a7ae1b1a1594e5f591cebdc50731f70df2d5b3125eabb5f0a4295
}

```

一旦ここまで。
Factoid や Entry Credit について、マークルツリーについて、実データはどこに置くのか、など書ききれなかったところはまた追記します。

# 参考
- https://github.com/FactomProject/FactomDocs/blob/master/Factom_Whitepaper_Japanese.pdf
- http://coinandpeace.hatenablog.com/entry/2015/01/12/125858
- http://doublehash.me/what-is-factom/
- https://coincheck.com/blog/2009