この記事は、ブロックチェーン Advent Calendar 2017 の 20 日目の記事です。
概要
BlockSci というのは、Blockchain 解析用のソフトウェアです。
Blockchain を Jupyter Notebook 使って解析したいな〜というときにか〜なり便利です。
注意
インメモリデータベースなので、メモリをかなり食います。AMI をもとに、EC2 にインスタンスをサクッと立ち上げるのが良いでしょう。
公式が公開している AMI を使うと、立ち上げて ssh トンネリングするだけで Jupyter Notebook が使える状態になります。メチャクチャ楽です。
だいたい 3.5 時間後にすべてのデータが読み込まれ、クエリの処理速度が最高速に達します。
導入
Readme にある最新の AMI を元に EC2 インスタンスを立ち上げます。
2017/12/19 現在では ami-7cf38706
が最新となっています。
メモリ領域が 60GB 以上あることが期待されており, r4.2xlarge
が推奨されています。
r4.2xlarge
は $0.532 / hour なので, スポットインスタンス使わず一ヶ月回すと $383.04 程度かかります。
自分もこの記事のために昨日から回していて、$10 が失われました。
立ち上がると, Jupyter Notebook も起きているので,
ssh -i .ssh/your_private_key.pem -N -L 8888:localhost:8888 ubuntu@your_url.amazonaws.com
したら localhost:8888
へ見に行くだけです。
利用例
事前準備
import blocksci
import matplotlib.pyplot as plt
import matplotlib.ticker
import collections
import pandas as pd
import numpy as np
%matplotlib notebook
# parser_data_directory should be set to the data-directory which the blocksci_parser output
chain = blocksci.Blockchain("/home/ubuntu/bitcoin/")
Class: Block
ref: https://citp.github.io/BlockSci/chain/block.html
# 最新の block を取得
recent_block = chain[len(chain) - 1]
# coinbase
recent_block.coinbase_tx
# hash: ハッシュ
print("hash is", recent_block.hash)
# height: ブロック高さ
print("height is", recent_block.height)
# input_count: ブロックに含まれるトランザクションインプットの数
print("input count is", recent_block.input_count)
# input_value: ブロックに含まれるトランザクションインプットに含まれる satoshi の総数
print("input value is", recent_block.input_value)
# inputs: ブロックに含まれるトランザクションインプットを取得
recent_block.inputs
# net_address_type_value: Returns a set of the net change in the utxo pool after this block split up by address type
print("net_address_type_value is", recent_block.net_address_type_value)
# net_full_type_value(self: blocksci.blocksci_interface.Block)
print("net_full_type_value", recent_block.net_full_type_value)
# next_block: 次のブロック
recent_block.next_block
# nonce: nonce の数値
print("nonce is", recent_block.nonce)
# output_count: ブロックに含まれるトランザクションアウトプットの数
print("output count is", recent_block.output_count)
# output_value: ブロックに含まれるトランザクションアウトプットに含まれる satoshi の総数
print("output value is", recent_block.output_value)
# outsputs: ブロックに含まれるトランザクションアウトプットを取得
recent_block.outputs
# prev_block: 前のブロック
recent_block.prev_block
# size_bytes: ブロックサイズ
print("size bytes is", recent_block.size_bytes)
# time: タイム
print("time is", recent_block.time)
# timestamp: ブロックヘッダのタイムスタンプ
print("timestamp is", recent_block.timestamp)
# total_spent_of_ages: Returns a list of sum of all the outputs in the block that were spent within a certain of blocks, up to the max age given
print("total_spent_of_ages is", recent_block.total_spent_of_ages)
# txes: ブロックに含まれるトランザクションを取得
recent_block.txes
# version: ブロックヘッダのプロトコルバージョン
print("version is", recent_block.version)
hash is 0000000000000000006271a8c189b9591ad06a369e29d24dbe25e6a1819d6cee
height is 498919
input count is 4913
input value is 1290872675640
net_address_type_value is <bound method PyCapsule.net_address_type_value of Block(numTxes=3031, height=498919, header_hash=0000000000000000006271a8c189b9591ad06a369e29d24dbe25e6a1819d6cee, version=536870912, timestamp=1513094055, bits=402698477, nonce=231235938)>
net_full_type_value <bound method PyCapsule.net_full_type_value of Block(numTxes=3031, height=498919, header_hash=0000000000000000006271a8c189b9591ad06a369e29d24dbe25e6a1819d6cee, version=536870912, timestamp=1513094055, bits=402698477, nonce=231235938)>
nonce is 231235938
output count is 6720
output value is 1292122675640
size bytes is 1050481
time is 2017-12-12 15:54:15
timestamp is 1513094055
total_spent_of_ages is <bound method PyCapsule.total_spent_of_ages of Block(numTxes=3031, height=498919, header_hash=0000000000000000006271a8c189b9591ad06a369e29d24dbe25e6a1819d6cee, version=536870912, timestamp=1513094055, bits=402698477, nonce=231235938)>
version is 536870912
CurrencyConverter
converter = blocksci.CurrencyConverter()
converter.satoshi_to_currency(100, recent_block.time.date())
0.0171781025
サンプル
手数料のヒストグラム
USD_JPY_RATE = 112
fees = [converter.satoshi_to_currency(fee, recent_block.time) * USD_JPY_RATE for fee in recent_block.txes.fee]
plt.hist(fees, bins=20, range=(0, 6000))
(array([ 6., 8., 20., 217., 870., 897., 464., 126., 22.,
137., 39., 21., 54., 11., 12., 21., 18., 14.,
10., 4.]),
array([ 0., 300., 600., 900., 1200., 1500., 1800., 2100.,
2400., 2700., 3000., 3300., 3600., 3900., 4200., 4500.,
4800., 5100., 5400., 5700., 6000.]),
<a list of 20 Patch objects>)
トランザクションから手数料などを取り出してみる
all_tx = recent_block.txes.all
sample_tx = all_tx[1]
# https://blockchain.info/ja/tx/4fe8cca3318ac086eaf4dcb3958dbd1db324b446591fdb03dbec1342e664570c
print(sample_tx.hash)
fee = sample_tx.fee
input_value = sum(sample_tx.inputs.value)
output_value = sum(sample_tx.outputs.value)
print(fee, input_value, output_value)
print(input_value - output_value == fee)
converter.satoshi_to_currency(fee, recent_block.time.date())
4fe8cca3318ac086eaf4dcb3958dbd1db324b446591fdb03dbec1342e664570c
700000 832822188 832122188
True
120.2467175
最大の手数料を探す
tx = sorted(recent_block.txes.all, key=lambda tx: - tx.fee)[0]
tx.fee
10000000
# それぞれのブロックの最大の手数料を持つ TX のリスト
txes = [sorted(block.txes.all, key=lambda tx: - tx.fee)[0] for block in chain]
fees = [tx.fee for tx in txes]
df = pd.DataFrame({"Fees":fees})
ax = df.plot(legend=False)
ax.set_ylim(ymin=0)
plt.tight_layout()
# 最大の手数料を持つ TX
tx = sorted(txes, key=lambda tx: - tx.fee)[0]
print("Maximum fee is %s JPY" % (converter.satoshi_to_currency(tx.fee, recent_block.time) * USD_JPY_RATE))
print("hash is", tx.hash)
print("time is", tx.block.time)
Maximum fee is 560332195.6279321 JPY
hash is cc455ae816e6cdafdb58d54e35d4f46d860047458eacf1c7405dc634631c570d
time is 2016-04-26 14:15:22
I smell a "Where did my money go?" moment : Bitcoin
まあこんな感じで遊べるので, 楽しい。$0.532/hour
失いながら遊んでいきましょう。