ブロックチェーン」タグアーカイブ

ビットコイントランザクションの中身を詳しく見てみる

(2017年10月3日にQiitaにて執筆した記事をこちらに転載しています。)

前回やったこと

Visual Studio Communityをインストールした後、コンソールアプリ( .NET Coreでも .NET Frameworkでもどちらでも構いません)のプロジェクトを作成し、NuGetパッケージの管理画面でNBitcoinとQBitNinjaをそれぞれ検索し、プロジェクトに追加して下さい。

今回例として参照するトランザクション

前回取得した堀江さんのビットコインアドレスの一番古いトランザクションであるこちらのトランザクションを例に使いましょう。トランザクションハッシュは以下の値になっています。

7008807adb713205d01d378f3d25f1bc5e06bda7d30b526c2b9d2c018cfa08b4

ちなみにこちらは堀江さんがビットコインを受け取ったときのトランザクションです。

ブロックチェーンAPIを使って該当のトランザクションを取得してみる

まずはブロックチェーンAPIにアクセスして該当のトランザクションを取得してみます。その為にQBitNinjaというクライアントライブラリを使用します。

using NBitcoin;
using QBitNinja.Client;
using QBitNinja.Client.Models;
using System;
namespace NBitcoinTest1
{
class Program
{
static void Main(string[] args)
{
QBitNinjaClient client = new QBitNinjaClient(Network.Main);
var transactionId = uint256.Parse("7008807adb713205d01d378f3d25f1bc5e06bda7d30b526c2b9d2c018cfa08b4");
GetTransactionResponse transactionResponse = client.GetTransaction(transactionId).Result;
Console.WriteLine(transactionResponse.TransactionId);
}
}
}

これでコンソールの出力にトランザクションハッシュが出力されるはずです。

ちなみに以下で使用しているNetwork.Mainというのは、ビットコインのテスト用ネットワークではなく、本番用のネットワークからデータを取得する為に指定しているものです。

QBitNinjaClient client = new QBitNinjaClient(Network.Main);

トランザクション内のビットコインの量を見てみる

このトランザクションのアウトプットに含まれるビットコインの量を見てみます。これはつまり堀江さんが受け取ったビットコインの量ということになります。

今回のトランザクションにはアウトプットが一つしかありませんが、アウトプットがひとつのトランザクションにひとつとは限りません。例えばビットコインを支払いに使いおつりが発生した場合などには、おつりがひとつのアウトプットとなり、支払者宛てに送られます。

transactionResponse.ReceivedCoins.ForEach((coin) =>
{
Money amount = (Money)coin.Amount;
Console.WriteLine(amount.ToDecimal(MoneyUnit.BTC));
});

出力は以下のようになります。

0.09020979

同じ要領でインプットの量も見てみます。こちらもひとつとは限りませんし、アウトプットと同量であるとも限りません。

decimal total = 0;
transactionResponse.SpentCoins.ForEach((coin) =>
{
Money amount = (Money)coin.Amount;
Console.WriteLine(amount.ToDecimal(MoneyUnit.BTC));
total += amount.ToDecimal(MoneyUnit.BTC);
});
Console.WriteLine(string.Format("Total input is {0} BTC", total));

出力は以下のようになりました。

0.001
0.01914202
0.00077777
0.0001
0.01
0.01
0.001
0.001
0.04649
0.001
Total input is 0.09050979 BTC

インプットが10個存在すること。それらのビットコインが集められて、インプットのビットコインの総量の方がアウトプットのビットコインの総量(0.09020979)よりも多いことが確認できます。

このインプットとアウトプットの差はビットコインのトランザクション手数料として、所謂マイナーさんがこのトランザクションをブロックチェーンのブロックとして正式に追加したときに彼らに払われるものです。

ScriptPubKeyを見てみる

ここで詳しくは触れませんが、ビットコインの所有権を示す為の根幹となるScriptPubKeyを見てみます。すごく簡単に言うと、このスクリプトは所有者にしか解けないパズルのようなものだと言えます。

transactionResponse.ReceivedCoins.ForEach((coin) =>
{
Console.WriteLine(coin.TxOut.ScriptPubKey);
});

出力は以下のようになります。

OP_DUP OP_HASH160 a4de1901ca3dd7167d655214c21baaa7fe554d3f OP_EQUALVERIFY OP_CHECKSIG

これは知識がないとチンプンカンプンだと思いますが、以下のようにNBitcoinを使用すると、実はここから堀江さんのビットコインアドレスである1G2jt5WeGhqWtDKEkcKY2GrZKjfYsuiVxXが抜き出せます。

using NBitcoin;
using QBitNinja.Client;
using QBitNinja.Client.Models;
using System;
namespace NBitcoinTest1
{
class Program
{
static void Main(string[] args)
{
QBitNinjaClient client = new QBitNinjaClient(Network.Main);
var transactionId = uint256.Parse("7008807adb713205d01d378f3d25f1bc5e06bda7d30b526c2b9d2c018cfa08b4");
GetTransactionResponse transactionResponse = client.GetTransaction(transactionId).Result;
var tx = transactionResponse.Transaction;
tx.Outputs.ForEach((txOut) =>
{
var script = txOut.ScriptPubKey;
Console.WriteLine(script);
Console.WriteLine(script.GetDestinationAddress(Network.Main));
});
}
}
}
OP_DUP OP_HASH160 a4de1901ca3dd7167d655214c21baaa7fe554d3f OP_EQUALVERIFY OP_CHECKSIG
1G2jt5WeGhqWtDKEkcKY2GrZKjfYsuiVxX

ビットコインアドレスというのは公開鍵から作られているものです(正確に言うと公開鍵のハッシュから作られています。)

これでこのスクリプトは受け取り手である堀江さんの公開鍵で鍵をかけられ、彼の秘密鍵でしか解けないものであることが何となくイメージできると思います。

次回にやること

ちょっと長くなってきてしまったので今回はここまでにします。

次回は、上で10個あったこのトランザクションへのインプットがどこからやってきたのかを見たいと思います。

参照

ブロックチェーンからあるビットコインアドレスのトランザクション情報を取得する

(2017年9月25日にQiitaにて執筆した記事をこちらに転載しています。)

ホリエモンこと堀江貴文さんはTwitterのプロフィール欄にて投げビットコインアドレスをひとつ公開しています。

f:id:rintaromasuda:20200405090936j:plain

今回はこのビットコインアドレスを例として使わせてもらい、ブロックチェーンからトランザクションの情報を取得してみます。これにより堀江さんがどれくらいのビットコインをこのアドレスで受け取ったのかが分かるはずです。

280万人ものフォロワーがいる堀江さんです。結構な数の人がこのアドレスを見て投げ銭をしたかもしれません(投げ銭目的で堀江さんがこのアドレスを載せているのかは知りませんが。)ちょっと結果が楽しみですね。

今回はBlockchain.infoのBlockchain Data APIを使いたいと思います。どうやらSingle AddressというAPIを使うと、あるひとつのビットコインアドレスに対するトランザクション情報が取得できるようです。

では実際に使ってみましょう。以下のコードはPowerShellです。

$address = "1G2jt5WeGhqWtDKEkcKY2GrZKjfYsuiVxX";
$uri = [System.String]::Format("https://blockchain.info/ja/rawaddr/{0}", $address);
$response = Invoke-RestMethod -Method Get -Uri $uri;
Write-Output $response.txs.Length;
# output
18

このコードの実行時点では18個のトランザクションが見つかりました。思ったより少ないですね。しかもこれには堀江さんのアドレスからビットコインが送信された場合のトランザクションも含まれていますので、受信のトランザクションはもっと少ないはずです。

堀江さんのアドレスが受信先だったトランザクションのみにデータを絞るため、取得したトランザクションの送り先アドレスを確認し、堀江さんのアドレスであった場合のみ対象とします。その際にトランザクションの総数と受け取ったビットコインの総量を計算します。

$receivedCount = 0;
$receivedAmount = 0;
foreach ($tx in $response.txs.out)
{
if ($tx.addr -eq $address)
{
$receivedCount += 1;
$receivedAmount += $tx.value;
}
}
Write-Output $receivedCount
Write-Output $receivedAmount
# output
13
47715300

受信のトランザクションは13件見つかりました。一方でビットコインの総量は47,715,300という数字が返ってきました。単位を良く知らないとここで「おおおっっ!さすがホリエモン!!!」と思ってしまうかもしれませんが、これは実はsatoshiという単位ベースの数字です。

1satsohiは1/100,000,000BTC(1億分の1ビットコイン)と定義されていますので、堀江さんが受け取った投げ銭の総額は0.477153BTCということになります。本日の相場で言うと20万円と少しというところです。

これでも「20万円はすごい!さすがホリエモン!」となるかもしれませんが、ほとんどのトランザクションは2014年、2015年とビットコインがまだ現在のような価格に暴騰する前のものでした。今年に入ってからのトランザクションはありませんでした。