丸の内で働くブロックチェーンエンジニアのブログ

丸の内やその他でフリーのブロックチェーンエンジニアとして働いています。勉強している技術情報やニュースを紹介します。

ERC20トークンの取引イベントログを抽出してネットワーク図を作成する

ERC20トークンは送金(transfer / transferFrom関数が呼ばれる)とevent Transferによってログが発行されます。ログは、Bloomフィルタという構造で格納され、ブロックチェーン自体には刻まれませんが、トランザクションを受け取った相手から受領するTransaction Receiptに刻まれます。

また、Transaction Receiptのハッシュ値自体はブロック内に含まれますので、ログも検証されることになります。ノードに備わるeth_getLogsという機能を用いると、このログを抽出することができます。

ログを抽出して、取引をネットワーク図にしてみます。

eth_getLogs関数について

eth_getLogsは、Bloomフィルタオブジェクトを引数にして、イベントログを抽出します。Bloomフィルタというと難しそうですが、要は抽出条件を設定するということです。

Bloomフィルタオブジェクトの具体的なパラメータはこちらになります。検索範囲、やログを出したアドレス、対象イベントなどを設定します。

名前 説明
fromBlock 検索範囲ブロック(開始)
toBlock 検索範囲ブロック(終点)
address 検索条件アドレス
topics 対象となるイベントのハッシュ値(※)
limit 返却する検索結果上限

※イベント名、引数の型をsha3(keccak)-256にかけて計算して求めます。 Deep dive into Ethereum logs – codeburstから引用して、

To find out which event the topic refers to we need to compute a signature of each event and find the matching one. Signature is a sha3 hash of event name and input argument types,

で、今回のTransferイベントの例だと、

sha3('Transfer(address,address,uint256)') ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

となります。

JSON-RPCの定義(parity)はこちらをどうぞ

wiki.parity.io

parityノードからERC20トークンのイベントログを抽出

EthereumのノードからERC20トークンのイベントログを抽出します。

今回はベータ版が公開されたALISのALISトークンを対象にしてみます。引数は以下の通りです。

  • fromBlock 設定なし
  • toBlock latest
  • address 0xea610b1153477720748dc13ed378003941d84fab(ALISのコントラクトアドレス
  • topics 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef(Transfer eventのハッシュ値
  • limit 設定なし

今回はparityでノードを立てています。parityノードの立て方はこちら

www.blockchainengineer.tokyo

「eth_parity_node」という名前でDockerコンテナを立てています。

#dockerコンテナ内にbashで入る
docker exec -it eth_parity_node bash

pwd
/build

#イベントログをjsonrpcで抽出する
curl 'http://127.0.0.1:8545' -H 'Content-Type: application/json' -H 'Accept: application/json' --data-binary '{"id":1,"jsonrpc":"2.0","params":[{"toBlock":"latest","address":"0xea610b1153477720748dc13ed378003941d84fab","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]}],"method":"eth_getLogs"}' > event_logs.json


#コンテナから出る
exit

#コンテナ内のevent_logs.jsonをホストにコピー
docker cp eth_parity_node:/build/event_logs.json .

今回抽出したイベントログですが、直近のブロック分しか抽出できていません。おそらく、parityの起動時に古いtransaction receiptも保持するように設定すれば古いイベントログも網羅的に抽出できると思われます。 (原理的には、現在のブロックチェーンから再計算することもできるはずですが、大変なので今回は見送ります)

イベントログを加工

抽出したイベントログ「event_logs.json」を加工して必要なデータだけ抽出します。

# coding: utf-8

import json
import pandas as pd

def extract_vals(results):
    '''
    results:イベントログのresult項目
    '''
    ret = []
    for result in results:
        tmp = []
        tmp.append(result['transactionHash'])
        tmp.append(int(result['blockNumber'],16))
        tmp.append(hex(int(result['topics'][1],16))) # from_address 0x0...と0が続くのであえて一度hex変換でフォーマットしている
        tmp.append(hex(int(result['topics'][2],16))) # to_address 
        tmp.append(int(result['data'],16) / (10**18)) # value ALIS は18桁なので10の18乗で割る
        ret.append(tmp) 
    return ret

def main():
    # イベントログファイルの読込
    f = open('event_logs.json', 'r')
    json_data = json.load(f)
    f.close()
    # トランザクションに加工
    txs = extract_vals(json_data['result'])
    df = pd.DataFrame(txs,columns=['transactionHash','blockNumber','from','to','data'])
    df.to_csv('txs.csv',index=False)

if __name__ == '__main__':
    main()

加工後のデータ「txs.csv」の一部です。 左からトランザクションハッシュ値、ブロック番号、送信元アドレス、送信先アドレス、ALIS金額になっていることが確認できます。

f:id:naomasabit:20180527194126p:plain

ネットワーク図で可視化

Cytoscapeを使って可視化してみます。GUIで簡単にcsvファイルなどからネットワーク図を作成できます。(APIもあります)

www.cytoscape.org

まずは、csvファイルのインポート

f:id:naomasabit:20180527162237p:plain

インポート時に、ソースとする項目、ターゲットとする項目をそれぞれ設定します。

f:id:naomasabit:20180527162245p:plain

そうするとこのようなネットワーク図ができます。 アドレスがノード(丸)で、トランザクションがエッジ(線)です。

f:id:naomasabit:20180527162439p:plain

少し調整して、取引が多いアドレスを大きくします。

一番大きいアドレスが出てきたので、こちらをEtherscanで調べてみます。

f:id:naomasabit:20180527162432p:plain

どうやらCoinExchangeのアドレスのようです。ALISはこちらの取引所で上場しています。

CoinExchangeでは、このアドレスを通じて入出金や取引がされているようです。

f:id:naomasabit:20180527194846p:plain

ERC20トークンのログは簡単に抽出、取引の動きも簡単な分析ならできそうなことがわかりました。

今回抽出したALISトークンのログは、本当にごく一部の直近トランザクションです。全てのトランザクションを抽出するともっと広大なネットワーク図になるはずです。

関連

今回実験したソースコード

github.com

ERC20の定義を過去にまとめた記事

www.blockchainengineer.tokyo