BETA

BTCトランザクションのモヤモヤを解消しよう

投稿日:2019-12-08
最終更新:2019-12-09

はじめに

ブロックチェーンの書籍をいくつか読むに当たって、頭の悪い私はある程度理解するまでにそれなりに
往復をしました。

書籍等では、章ごとに解説されているため全体の流れが掴みにくかったのではないかと思います。
私が疑問を感じた部分について特にフォーカスして、全体的にまとめておきたいと思います。

※ブロックチェーンの本は軽く読んだことがある方を対象とし、細かい用語などは一部割愛します。

もやっとしたトランザクションライフサイクル

よくありそうなトランザクションライフサイクルの概要

  1. ウォレットによるトランザクションの作成
  2. 各P2Pノードへトランザクションの伝搬
  3. ノードによるトランザクションの検証
  4. マイニング(Proof of work)
  5. 各P2Pノードへのブロック伝搬
  6. ブロックの承認
  7. ウォレットによるトランザクションの作成...loop

簡易トランザクション図

山田太郎は5BTC所持しており、白鳥麗子に3BTC送金したい場合

ポイント

  • 1.9BTCを自分へのお釣りとして、トランザクションアウトプットを作成する
  • 手数料が必要。手数料は宛先を指定しない。

トランザクションinputのBTCはどこから来るのだろうか? という疑問

トランザクションインプットのBTCはトランザクションアウトプットである(UTXO)
いまいちパッとこないこともあるかと思います。

まずはトランザクションの簡易構造を見てみましょう。

トランザクションインプットの簡易データイメージ

名前 内容
tx_hash トランザクションハッシュ
output Index UTXOのindex
unLockingScript scirptSigとも言う。後述

トランザクションアウトプットの簡易データイメージ

名前 内容
amount 金額
LockingScript scirptPubkeyとも言う。後述

トランザクションハッシュとはなんだろう?

transaction hash(transaction id)、ブロックチェーン上でトランザクションを検索したい時などにも利用されていると思います。

何故ハッシュなのか?いつどこでハッシュ化されるのか?

マイニングして、ブロックを生成する際に、大量のトランザクションをまとめます。この際、トランザクションの検索性を上げるために利用されているのが、マークルツリーというデータ構造です。

作成されたマークルツリーのマークルルート(最上位)だけをブロックチェーンヘッダに格納しています。

この辺りは別途調べて頂くとして、マークルツリーを作成する際に、トランザクションはハッシュ化されます。
SHA256を2回行ったものです。

SHA256(SHA256(transaction))  

UTXOのインデックスとはなんだろう?

ウォレットは過去のブロックチェーンから自分が受取人となっているUTXOを含むトランザクションを検索します。

ここでトランザクションのデータ構造を確認しましょう

名前 内容
inputCount inputの数
inputs トランザクションインプットの配列
outputCount outputの数
outputs トランザクションアウトプットの配列

最初の画像では、白鳥麗子さんへのアウトプットと自分自身へのお釣りとしてのアウトプットがありました。1つのトランザクションに対して、インプットとアウトプットが複数になる場合があります。

インプットが複数になる時は1つのUTXOの金額が、受取人に送金する金額より少ない場合です。

銀行口座のようなものはないので、個人の残高はUTXOの総和となります。もし山田太郎さんのUTXOが1.5BTCと1.5BTCの2つを組み合わせて3BTC送金したい場合は、トランザクションインプットは2つになります。

最初の図の状態を表にすると、次のようになります。
(手数料は割愛)

名前
inputCount 1
inputs[1] 山田太朗 5BTC(UTXO)
outputCount 2
outputs[1] 白鳥麗子 3BTC
outputs[2] 山田太郎 1.9BTC

上記のトランザクションがマイニングされ、ブロックに承認され、UTXOとして確定したとします。

※UTXOの確定タイミングは、ブロックの承認が完了した段階で、UTXOプールに格納されると思っておりますが、確定タイミングについて詳しい方がいたら教えてください。

トランザクションハッシュの値が次のものだとして、この1.9BTCを利用して、山田太郎がワンパンマンに1BTC送金するイメージをみてみましょう。

transaction hash: tarouToreiko
output[2]: 山田太郎 1.9BTC

トランザクションインプット

名前 内容
tx_hash tarouToreiko
output Index 2
unLockingScript ...

トランザクションが連鎖していっているイメージは掴めたでしょうか?

lockingScript/unLockingScript

ビットコインでは、公開鍵暗号方式と電子署名を利用して、以下を確認しています。

  • 受取人が正しいか
  • トランザクションが改ざんされていないか
  • 送金人が送金権利を保有しているか

一般的なhttpsの説明にある公開鍵暗号の知識をイメージした状態で、ビットコインの検証について考えると、ある意味混乱するような気がします。

トランザクションの構造をもう一度みてみましょう。

transactionイメージ

unLockingScript(scriptSig)に必要なもの

  • 電子署名(送金人)
  • 公開鍵(送金人)

lockingScript(scriptPubKey)に必要なもの

  • 公開鍵ハッシュ(受取人)

電子署名はどのように作成されるのか?

デジタル署名はトランザクションをダブルハッシュして、秘密鍵で暗号化したものである。

sign(SHA256(SHA256(transaction)) -> デジタル署名  

transactionにビットコインアドレスがないのは何故か?

一般的に、ビットコインを誰かに送金する場合は、ビットコインアドレスを指定します。

しかしながら、トランザクションアウトプットにはビットコインアドレスがありません。代わりに、公開鍵ハッシュがあります。

ビットコインアドレスの生成方法を確認します。

秘密鍵 -> 楕円曲線暗号(Secp256k1) -> 公開鍵 -> RIPEMD-160(SHA256(公開鍵)) -> 公開鍵ハッシュ ->  
エンコード(Base58Check) -> ビットコインアドレス  

公開鍵ハッシュは、Base58Checkエンコードされる前のデータになります。SHA256などの暗号学関数は、逆変換ができませんので公開鍵ハッシュから公開鍵を求めることはできません。もちろん秘密鍵も。

しかし、Base58Checkエンコードは受取人の指定時に、入力ミスがないように視覚的に読みやすく、バイト数を抑えるために行われていることもあり、ビットコインアドレスから公開鍵ハッシュはデコードすることで求めることが可能です。

次の暗号化をHASH160と呼びます

RIPEMD-160(SHA256(公開鍵)) -> 公開鍵ハッシュ  

ウォレットや取引所では、ビットコインアドレスをデコードし、公開鍵ハッシュをトランザクションアウトプットのLockingScriptに格納していると思います。

scriptの検証

この検証処理は各P2Pノードがブロックを生成する際に実施します。

受取人が正しいかのチェック

今までの経緯から、トランザクションを作成する場合は、トランザクションアウトプットのUTXOを利用する。UTXOにはLockingScriptとして、送金人の公開鍵ハッシュが格納されている。

トランザクションインプットには、自分の公開鍵をunLockingScriptとして格納されている状態です。

  1. unLockingScriptの公開鍵をHASH160し、公開鍵ハッシュを生成する
  2. LockingScriptの公開鍵ハッシュと1.で生成した公開鍵ハッシュを比較する
  3. 一致することで、送金人、受取人が正しいことが確認される

トランザクションの改ざん及び送金人が正しい権利を持っているかの確認

unLockignScriptには、電子署名が格納されています。トランザクション情報もノードに伝搬されています。

sign(SHA256(SHA256(transaction)) -> デジタル署名  
  1. トランザクションをダブルハッシュする
  2. デジタル署名を公開鍵で複合化する(signの部分が取れる)
  3. 上記のデータが一致することで、改ざんや送金人の正当性を検証する

httpsなどの公開鍵暗号との混乱

インターネットで利用されている公開鍵暗号のイメージとしては、公開鍵をクライアントに配布して、クライアントが公開鍵で暗号化し
サーバー側が秘密鍵で複合するという流れだと思います。

一旦忘れて、少し方式が異なるものとして理解した方がすっきりするかもしれません。

最後に

最後に、今私の把握している範囲のトランザクションライフサイクルをまとめて記載しておきたいと思います。
ソースコードまで確認しておりませんので、細かいところで齟齬があるかもしれません。

  1. ウォレットがトランザクションを作成
    1.1 UTXOの検索 && 回収
    1.2 トランザクションインプット設定(電子署名、公開鍵)
    1.3 トランザクションアウトプット設定(公開鍵ハッシュ)
  2. ウォレットがトランザクションをノードで送信
  3. ノードがトランザクションの検証
    3.1 UTXOの有効性の検証(存在、未使用状態であるか)
    3.2 公開鍵ハッシュの検証(HASH160形式か)
    3.3 電子署名の検証(unLockingScript/lockingScript)
    3.4 UTXO計 > アウトプットの金額計
  4. ノードがトランザクションを伝搬
  5. トランザクションをノード自身のトランザクションプールに格納
  6. ノードがトランザクションプールから取り出し、ブロックの生成
  7. マイニング(proof of work)
  8. 成功したブロックを各ノードへ伝搬
  9. 各ノードでブロックの承認
  10. トランザクションをUTXOプールへ
    ブロックの中にトランザクションは格納されているが、ノードの種類によってはUTXOプールにデータを保持する

今回の検証scriptの説明は、P2PKHという一般的なビットコインの送金に利用されるものを対象としました。

scriptにはいくつか種類がありますので、そちらについては別途ご確認ください。

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

学習記録・ログ用

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう