エンジニアの光田(@34ro)です。
近々有効化されるかもしれないsegwitについて技術的な観点でまとめました。
segwitはpayment channelのような上位レイヤーの技術の足がかりとなる重要なソフトフォーク(互換性のあるプロトコルの変更)です。
マイナーがブロック生成時に投票を行って採択を決める仕組み(BIP-9)を導入していることも興味深い点です。
segwitの概要
segwitとはsegregated witnessの略で分離された署名という意味です。新しい形式のトランザクションの形式が追加されます。
segwit-styleなトランザクションではscriptSig(unlocking scriptとも呼ばれています)に持っていた情報をwitnessという新たに追加した項目に移動します。
これにより以下のようなメリットがあります。
・意図しないトランザクション展性を不可能に
scriptSigを空にすることでtxidにunlocking scriptが含まれず、トランザクション展性の問題が解消します。
・ブロックあたりに詰め込めるトランザクションが増える
witnessデータはブロックサイズの計算対象ではないので結果的にブロックに詰め込めるトランザクションの数が増えます。
・未署名なトランザクションのアウトプットが利用可能に
未署名でもtxidが確定するので、未署名なトランザクションのアウトプットを使って承認されうるトランザクションを作成可能です。
トラストレスなpayment channelの確立に必要な要件です。
segwitが有効化されたあとでも従来通りの形式のトランザクションは利用可能です。
新しく増えるトランザクションの形式について説明します。
トランザクションの変更点
witnessの項目が追加される(BIP-141, BIP-144)
segwit-styleでない(従来通りの)トランザクションは以下のようなフィールドを持っています。
in-counter // inputsの長さ
inputs // inputの配列
out-counter // outputsの長さ
outputs // outputの配列
lock_time // lock時間
segwit-styleで作られたトランザクションでは以下のようになります。
marker // 0固定
flag // 拡張性を持たせるための値
in-counter // inputsの長さ
inputs // inputの配列
out-counter // outputsの長さ
outputs // outputの配列
script_witnesses // 署名情報の配列
lock_time // lock時間
古いバージョンのクライアントではパースできないようにmarkerという項目を設けます。
従来のトランザクションではin-counterの位置なのでinputsが空配列ということになり無効なトランザクションと判別されます。
通常inputにあるscriptSigに含まれる署名情報をscript_witnessesに持ってきます。
script_witnessesが空ならscriptSigを使ってスクリプトを検証します。
txid, wtxid
txidを算出する元になる項目は
txid: version inputs outputs lock_time
ということには変わりません。inputsに含まれているscriptSigを空にするので、txidの元データから証明情報が消えることになります。
未署名のままtxidを確定することができ、未署名の(ブロードキャストしても無意味な)トランザクションのアウトプットを使ったトランザクションが組み立てられるようになります。
これにより、トラストレスな手順でpayment channelの確立が可能になるわけですがこちらはまた別の機会に。
segwit-styleなトランザクションのためのwtxidというものも規定されています。
flagには1が固定で入ります。
wtxid: version marker flag txins txouts witnesses lock_time
P2WPKH, P2WSH, P2SHでネストしたP2WPKH
segwit-styleなトランザクションでは3つの形式で送金が可能になります。
まずはP2WPKH, P2WSHから。
P2WPKH
scriptSig: (empty)
scriptPubKey: 0 <20-byte-key-hash>
P2WSH(1-of-2 multi-sigを使った例)
scriptSig: (empty)
scriptPubKey: 0 <32-byte-hash>
それぞれP2PKH, P2WSHに対応しています
・scriptSigに入れていた値をwitnessに移す
・scriptPubKeyをsegwit用の形式で記述する
という変更です。
scriptPubkeyの最初の「0」はsegwit versionでありOP_0とは意味合いが違います。
P2SHでネストしたP2WSH(1-of-2 multi-sigを使った例)
scriptSig: <0 <32-byte-hash>>
scriptPubKey: HASH160 <20-byte-hash> EQUAL
scriptSigとwitnessを使うため、P2WSHよりデータ量が多くなってしまいます。
これは古いクライアントとの互換性を保つために用意されました。
どのようにして有効化されるか(BIP-9)
P2Pネットワークに対して一斉にデプロイするわけにはいきません。
BIP-9で規定された投票プロセスに従って採択が決定され、アクティベートされます。
difficultyの調節と同じ2048ブロックごとのタイミングで直近の2048ブロックの投票状況をみて95%以上が賛成のシグナルを出していたら無事採択となります。
まさに「プロトコルとしての通貨」ならではの試みです。
ちなみに直近で採択されうる候補日は12/16,12/30,1/13辺りです(多少前後します)。
現在の投票状況です。
まとめ
segwitに対応したトランザクションの変更点についてまとめました。
従来通りのトランザクション形式も使い続けられるので一気に広まるというよりはウォレットや取引所が対応すると徐々に普及していくという流れになるかと思います。