Help us understand the problem. What is going on with this article?

ブロックチェーンからアドレス毎のビットコイン増減を確認する

More than 3 years have passed since last update.

この記事では、Mac OS Sierra 10.12.4を使っています。
bitcoin関連記事の第3回目です。

第1回:bitcoindをdockerで環境構築する
第2回:bitcoindにpythonからアクセスする

トランザクションからビットコインの増減を確認する

前回は、pythonからビットコインのブロックを取得して中を見るところまで実施しました。
ビットコインデータは、ブロックが積み重なっており、さらにその中にトランザクションが記録されています。
どのアドレスからどのアドレスにビットコインが移動したかがトランザクションには記録されているので、理論的にはそれの積み重ねからアドレスの残高を計算できる事になります。

ブロックの中身を見てみる

まずはブロックの中身を見てみます

コネクション作成
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
rpc_user="bitcoinrpc"
rpc_password="passwordxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
rpc_connection = AuthServiceProxy("http://%s:%s@127.0.0.1:8332"%(rpc_user, rpc_password))
ブロック高110000のblockを取得する
blhash = rpc_connection.getblockhash(110000) #blhashはブロックのhash文字列
rpc_connection.getblock(blhash) #ブロック情報を取得する
結果
{'bits': '1b01cc26',
 'chainwork': '000000000000000000000000000000000000000000000000135fae65c9d5f919',
 'confirmations': 219401,
 'difficulty': Decimal('36459.88692507513'),
 'hash': '000000000001bbda3f22ef8e476b470a2d3ae16821c23a6d22db77318d0799a9',
 'height': 110000,
 'mediantime': 1298490035,
 'merkleroot': 'bb988af992654871e8cefe8bbe05e9f9679611eadcfa53980ee515978eebcd52',
 'nextblockhash': '0000000000018d067c617c2e262e544bae4807e413122b1f4814077a15ac57c6',
 'nonce': 3052574605,
 'previousblockhash': '0000000000017947e1ea1c4f011b5bf712a9edd5e35d2c4db331f2d1764c593a',
 'size': 3202,
 'strippedsize': 3202,
 'time': 1298491791,
 'tx': ['4e10436ca8206a2dd760dd351210a5120a3824d4eb53011be0a7b9a33b368208',
  '76dc5788be4a8cf6925aff15fd8c8fbf6417b4ad6c30a1ac12cd117e95c5820b',
  '7452bfa629b104985f7c937e0f7836206935d83872882c88ae183234fe9bcf97',
  'e325a8a968368aeb6d89bcdb362d311833f5a9fe5a80f3f0730b684922439a68',
  '8510c531b585e77a66a986cb0dfdd0ca280ff0747d2dca0d6fa87b0f8af4810a',
  'f9a5d31e7894c3983d38215060c55665db0024ad7fb373fa58db7316dd223ea9',
  '83e74406b0876fed2db187444dd0a4f3eedad42e9adb32ce82b3ff729fe77b58',
  '0f3e5f5b833dfad8ff19115ecd29fa40566aace67f2880da0ab4fa1acac00bcc',
  'a1743f0803926ef4343e217c78324ec3e3ebc4cfc7c96739f3696b3c510cc7d1',
  '5015ed6455e7d3fb50ce5ef1f63888fe7d4c37042f17f5f89bea176dce4ca0bd',
  '7b14b05552f053a862df22824f92e94f155722f9e5d91341b934a6de010b6560',
  '2564b40ef226c73eb63409f9dbdcc64aeacca6e3a7136e86156a64573ba3f6d1'],
 'version': 1,
 'versionHex': '00000001',
 'weight': 12808}

色々と書いてありますが、txがブロックの中に書き込まれているトランザクションです。
このブロックの中には12個保存されていますね。

トランザクションの中身を見てみる

先ほどのブロックの中にあるトランザクションを見てみます。
トランザクションの中身確認にはgetrawtransactionを利用します。

トランザクションの中身を取得
rpc_connection.getrawtransaction("76dc5788be4a8cf6925aff15fd8c8fbf6417b4ad6c30a1ac12cd117e95c5820b")
結果
'0100000001601f2f0143aa441690c7a2e1c90ae3696ceabf977afad8e08905a1efa20adced010000008b483045022100c3a2945b4cf7b6346a7e5e479bd3a7a2ca828ae6db2be5207f2377c737f64887022059116e34fded0bf5df39e2862cff59489b7701d60fe52367b62ea650b6360faf0141042d4b24c0c1a54e86399cc32e2f4b8524bae9442e6890960b4b11fd511794ccc16bd085102efdea3bb0f1809d10103f54db9597908eaf4f47bee694f73c742992ffffffff02404b4c00000000001976a914ec0994cb53016845edb1e207323faca42884629288ac40162094040000001976a914cb186543ad2d7c1195351678f1e94488c2813a0588ac00000000'

これだと何が何だかわかりませんね、
decoderawtransactionを呼んでデコードしてあげます。

トランザクションのデコード
rpc_connection.decoderawtransaction(rpc_connection.getrawtransaction(txid))
トランザクションのデコード結果
{'hash': '76dc5788be4a8cf6925aff15fd8c8fbf6417b4ad6c30a1ac12cd117e95c5820b',
 'locktime': 0,
 'size': 258,
 'txid': '76dc5788be4a8cf6925aff15fd8c8fbf6417b4ad6c30a1ac12cd117e95c5820b',
 'version': 1,
 'vin': [{'scriptSig': {'asm': '3045022100c3a2945b4cf7b6346a7e5e479bd3a7a2ca828ae6db2be5207f2377c737f64887022059116e34fded0bf5df39e2862cff59489b7701d60fe52367b62ea650b6360faf[ALL] 042d4b24c0c1a54e86399cc32e2f4b8524bae9442e6890960b4b11fd511794ccc16bd085102efdea3bb0f1809d10103f54db9597908eaf4f47bee694f73c742992',
    'hex': '483045022100c3a2945b4cf7b6346a7e5e479bd3a7a2ca828ae6db2be5207f2377c737f64887022059116e34fded0bf5df39e2862cff59489b7701d60fe52367b62ea650b6360faf0141042d4b24c0c1a54e86399cc32e2f4b8524bae9442e6890960b4b11fd511794ccc16bd085102efdea3bb0f1809d10103f54db9597908eaf4f47bee694f73c742992'},
   'sequence': 4294967295,
   'txid': 'eddc0aa2efa10589e0d8fa7a97bfea6c69e30ac9e1a2c7901644aa43012f1f60', #宛先、送金金額はこのトランザクション参照
   'vout': 1 #参照するトランザクションの番号 }],
 'vout': [{'n': 0,
   'scriptPubKey': {'addresses': ['1NX3wzGPxFaMJotm2KcDjrqAYGwu3N7rXb'] #宛先アドレス,
    'asm': 'OP_DUP OP_HASH160 ec0994cb53016845edb1e207323faca428846292 OP_EQUALVERIFY OP_CHECKSIG',
    'hex': '76a914ec0994cb53016845edb1e207323faca42884629288ac',
    'reqSigs': 1,
    'type': 'pubkeyhash'},
   'value': Decimal('0.05000000') #送金金額 },
  {'n': 1,
   'scriptPubKey': {'addresses': ['1KWsPyZ9BYFq9izzRcQXeGffLunCAKx32d'] #宛先アドレス,
    'asm': 'OP_DUP OP_HASH160 cb186543ad2d7c1195351678f1e94488c2813a05 OP_EQUALVERIFY OP_CHECKSIG',
    'hex': '76a914cb186543ad2d7c1195351678f1e94488c2813a0588ac',
    'reqSigs': 1,
    'type': 'pubkeyhash'},
   'value': Decimal('196.65000000') #送金金額 }],
 'vsize': 258}

なんとなくわかる形になりましたね。
項目が色々ありますが、vinとvoutのみに着目します。voutは宛先のアドレスと金額が書いてあります。
valueに注目すると、0.05と196.65と書いてあります。
アドレス「1NX3wzGPxFaMJotm2KcDjrqAYGwu3N7rXb」に0.05ビットコイン、
アドレス「1KWsPyZ9BYFq9izzRcQXeGffLunCAKx32d」に196.65ビットコインへ合計、196.70ビットコインを送ったということですね。

vinは別のtxid(トランザクションID)と、「vout」の番号が書いてありますね。
これは、このトランザクションIDのvoutの何番目に宛先アドレスと金額が書かれているかを表しています。
少しわかりにくいですが、つまりはvinに書かれている別のtxidを見に行って宛先と送金金額を取得する必要があります。
コードにするとこういう感じです。

vinのトランザクション取得
txid = "76dc5788be4a8cf6925aff15fd8c8fbf6417b4ad6c30a1ac12cd117e95c5820b"
in_txid = rpc_connection.decoderawtransaction(rpc_connection.getrawtransaction(txid)).get("vin")[0].get("txid")
in_no = rpc_connection.decoderawtransaction(rpc_connection.getrawtransaction(txid)).get("vin")[0].get("vout")
rpc_connection.decoderawtransaction(rpc_connection.getrawtransaction(in_txid)).get("vout")[in_no]
結果
{'n': 1,
 'scriptPubKey': {'addresses': ['1LfAi3G7xYmZKjr823RHWTANnCYdZvmDhK'],
  'asm': 'OP_DUP OP_HASH160 d7a24cc6e59ca8a1e553bc5c42c5f6e4c1277bbf OP_EQUALVERIFY OP_CHECKSIG',
  'hex': '76a914d7a24cc6e59ca8a1e553bc5c42c5f6e4c1277bbf88ac',
  'reqSigs': 1,
  'type': 'pubkeyhash'},
 'value': Decimal('196.70000000')}

vinは196.70ビットコインを送金していることがわかりましたね。これはvoutの合計と同額です。
つまり、これはアドレス「1LfAi3G7xYmZKjr823RHWTANnCYdZvmDhK」から
「1NX3wzGPxFaMJotm2KcDjrqAYGwu3N7rXb」に0.05ビットコイン、
「1KWsPyZ9BYFq9izzRcQXeGffLunCAKx32d」に196.65ビットコインを送金した取引ということになります。

図にするとこんな感じです。
スクリーンショット 2017-07-16 11.51.46.png

アドレス毎のビットコイン増減を取得する

ここまでで、トランザクションの取引を取得することができました。
これをどんどんと過去の履歴から辿っていけば、アドレスのビットコイン増減を確認することも可能です。

取得結果一部

    アドレス                             減算 加算   ブロック高    トランザクション
0   12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX  0   50.0    1   0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68be...
1   coinbase                            0    0.0    1   0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68be...
2   1HLoD9E4SDFFPDiYfNYnkBLQ85Y51J3Zb1  0   50.0    2   9b0fc92260312ce44e74ef369f5c66bbb85848f2eddd5a...
3   coinbase                            0    0.0    2   9b0fc92260312ce44e74ef369f5c66bbb85848f2eddd5a...
4   1FvzCLoTPGANNjWoUo6jUGuAG3wg1w4YjR  0   50.0    3   999e1c837c76a1b7fbb7e57baf87b309960f5ffefbf2a9...

出ていますね。今回対象にしたのは初期のブロックなので、サトシナカモトがマイニングしていた頃の記録です。coinbaseはマイニングした記録で、形式上、作成しているだけです。
減算は送金記録、加算は受領記録です。今回のブロックはマイニングだけなので、coinbaseから50ビットコインを受領しているだけですね。

このように、ブロックチェーンでは取引記録を第三者台帳として誰でも確認できる状態になっていることが確認できました。

Naomasa
渋谷で働いているブロックチェーンエンジニアです。 ブロックチェーンとデータ分析を仕事にしています。 ブログも書いています。
https://www.blockchainengineer.tokyo/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away