BlockSciデータ解析編

環境構築後のデータ解析の部分についてのお話です。

環境構築については↓をご参照ください。

- [BlockSci環境構築（AWS編）](https://qiita.com/John110/items/67c0f5c3b82eda0f3b23)
- [BlockSci環境構築（ローカル編）](https://qiita.com/John110/items/87803eb54bdea8ba6a22)

## データの準備
### blocksci_parser
BlockSciのディレクトリでコマンドを実行していきます。
bitcoindは停止しておくことをお勧めします。
動作したままで最新のブロックまで同期している場合にパースがうまくいかないことが多いです。

```bash
# <data-directory>にはパースデータを出力したいディレクトリを指定してください。ディレクトリが存在しない場合は自動で作成されます。
# <coin-directory>にはbitcoindで同期したブロックチェーンデータがあるフォルダを指定してください。 mainnetであれば ~/.bitcoin など
blocksci_parser --output-directory <data-directory> update disk --coin-directory <coin-directory>
```

#### 注意事項
- testnetのデータはパースが出来ることは確認できていますが`jupyter notebook`でデータが使用できるかは確認していません。
- regtestはソースコード内では対応しているはずですが動作検証はしていません。

### clusterer
クラスターデータを使用する場合はこちらも実行します。
`BlockSci環境構築（AWS編）`にて初期から入っているmainnetデータでのみ動作確認しています。
また、testnetのデータではビットコインアドレスを指定してデータを取得するコードがうまく動きませんでした。

```bash
cd <data-directory>
mkdir clusters
cd clusters
clusterer ../
```

## データ解析
### 最新のブロック高取得
```python3
import blocksci

chain = blocksci.Blockchain("/home/ubuntu/bitcoin/") # パースデータのディレクトリパス
height = chain[-1].height
print("ブロック高： {0}".format(height))
```

### OpenAssetsトランザクション数の遷移グラフ
```python3
import blocksci
import matplotlib.pyplot as plt
import matplotlib.ticker
import collections
import pandas as pd
import numpy as np
%matplotlib notebook

chain = blocksci.Blockchain("/home/ubuntu/bitcoin/")
# OP_RETURNを含むトランザクションを全て取得
txes = chain.script_type_txes(0, len(chain), blocksci.address_type.nulldata)
# OP_RETURN payloadにOpenAssetsのバイトコードを含むものをリスト化
assets = [tx for tx in txes if tx.op_return.address.script.data[0:4] == b'OA\x01\x00']
labels = [(tx.block.time, blocksci.label_application(tx)) for tx in assets]

df = pd.DataFrame([x for x in labels], columns=["date", "label"])
df = df.reset_index().groupby(["date", "label"]).count().unstack(level=-1).fillna(0)
df.columns = df.columns.droplevel()
important_columns = list(df[df.index > pd.to_datetime("1-1-2016")].sum().sort_values()[-10:].index)
important_columns = [x for x in important_columns if "Address" not in x]
ax = df[df.index > pd.to_datetime("1-1-2016")].cumsum().resample("w").mean()[important_columns].plot()
ax.set_ylim(0)
plt.tight_layout()
```
↓出力結果
![OpenAssetsTransaction.png](https://qiita-image-store.s3.amazonaws.com/0/79633/86d0d980-a39e-8476-f13c-5d9a78a9ef2b.png "mainnet(2017/12/12 15:54:15)までのデータ")

### OpenAssetsIssueトランザクション数の日別グラフ
```python3
import blocksci
import matplotlib.pyplot as plt
import matplotlib.ticker
import collections
import pandas as pd
import numpy as np
%matplotlib notebook

chain = blocksci.Blockchain("/home/ubuntu/bitcoin/")
txes = chain.script_type_txes(0, len(chain), blocksci.address_type.nulldata)
assets = [tx for tx in txes if tx.op_return.address.script.data[0:4] == b'OA\x01\x00']

issues = []
for tx in assets:
    if tx.outs.all.index(tx.op_return) > 0:
        issues.append(tx)

labels = [(tx.block.time, blocksci.label_application(tx)) for tx in issues]
df = pd.DataFrame([x for x in labels], columns=["date", "label"])
df = df.reset_index().groupby(["date", "label"]).count().unstack(level=-1).fillna(0)
df.columns = df.columns.droplevel()
important_columns = list(df[df.index > pd.to_datetime("1-1-2016")].sum().sort_values()[-10:].index)
important_columns = [x for x in important_columns if "Address" not in x]
ax = df[df.index > pd.to_datetime("1-1-2016")][important_columns].plot()
ax.set_ylim(0)
plt.tight_layout()
```
↓出力結果
![OpenAssetIssueTransaction.png](https://qiita-image-store.s3.amazonaws.com/0/79633/b93b17e8-39bc-9c08-8bad-3aabfc800a2d.png "mainnet(2017/12/12 15:54:15)までのデータ")


### OpenAssetsTransferトランザクション数の日別グラフ
```python3
import blocksci
import matplotlib.pyplot as plt
import matplotlib.ticker
import collections
import pandas as pd
import numpy as np
%matplotlib notebook

chain = blocksci.Blockchain("/home/ubuntu/bitcoin/")
txes = chain.script_type_txes(0, len(chain), blocksci.address_type.nulldata)
assets = [tx for tx in txes if tx.op_return.address.script.data[0:4] == b'OA\x01\x00']

transfers = []
for tx in assets:
    if tx.outs.all.index(tx.op_return) == 0:
        transfers.append(tx)
    elif tx.outs.all.index(tx.op_return) > 0:
        if tx.outs.all.index(tx.op_return) < tx.op_return.address.script.data[4]:
            transfers.append(tx)

labels = [(tx.block.time, blocksci.label_application(tx)) for tx in transfers]
df = pd.DataFrame([x for x in labels], columns=["date", "label"])
df = df.reset_index().groupby(["date", "label"]).count().unstack(level=-1).fillna(0)
df.columns = df.columns.droplevel()
important_columns = list(df[df.index > pd.to_datetime("1-1-2016")].sum().sort_values()[-10:].index)
important_columns = [x for x in important_columns if "Address" not in x]
ax = df[df.index > pd.to_datetime("1-1-2016")][important_columns].plot()
ax.set_ylim(0)
plt.tight_layout()
```
↓出力結果
![OpenAssetsTransferTransaction.png](https://qiita-image-store.s3.amazonaws.com/0/79633/23007c7f-9295-e4ad-8217-32a92a3105d2.png "mainnet(2017/12/12 15:54:15)までのデータ")