就活モチベが吹き飛んだので趣味に走ります。
TapyrusのCOLOR識別子について、軽くまとめる記事。
COLOR識別子とは
Tapyrusで発行されるTokenなどに対し、識別子として付与される。OP_COLOR以後に記載され、このopcodeが出現することでスタック最上位の要素がCOLOR識別子として解釈される。また、そのUTXOは任意のトークンを示すこととなる。
tapyrus-cliにて、トークンを発行すると
{ "color": "c3fe867030bbc10029a2d11a7ef4719a4b6ef11e5bdbe0d023bd5a57732c48cf99", "txid": "28618a610078b4460b8302e3cc4a1e822b600024b399ede7815de9b830a4a83a" }
のような形で出力が返るが、このcolor
要素がCOLOR識別子である。
端的にTokenのIDと解釈できる。
COLOR識別子の構造
COLOR識別子は1バイトの「タイプ(TYPE)」と32バイトの「ペイロード(PAYLOAD)」で構成される。タイプとペイロードの内容については以下の通り。
タイプ | 定義 | ペイロード |
---|---|---|
0xC1 | Reissuable Token | 発行TXのインプットのscriptPubkeyのSHA256値 |
0xC2 | Non-Reissuable Token | 発行TXのインプットのOutPointのSHA256値 |
0xC3 | Non-Fungible Token | 発行TXのインプットのOutPointのSHA256値 |
発行TXのインプットのOutPoint、つまり発行に用いるUTXOはチェーン上で一意であることからCOLOR識別子も一意なものであることがわかる。またこれによりUTXO単体でCOLOR識別子を導出することが可能である。
COLOR識別子を導出してみる
NFTの発行を例として導出してみる。
発行に用いるUTXOは以下とする。
UTXO-01
{ "txid": "08504c03b29073a8ad8705363c7fcb2708afac2e1f11453bd7f64d9d365f269d", "vout": 0, "address": "1EjNxzpqw411MfY8i2HFLHjDvUERfR9VLj", "token": "TPC", "amount": 0.00050000, "label": "", "scriptPubKey": "76a914969d7101a2c2aa9b25310785ecfa837e1220df7988ac", "confirmations": 7660, "spendable": true, "solvable": true, "safe": true },
タイプ
タイプについて、NFTを発行するので「0xC3
(16進数表示で c3
)」となる。
ペイロード
ペイロードの内容は「発行TXのインプットのOutPointのSHA256値」である。
「発行TX」は今から作る(tapyrus-cli issuetoken
で生成される)トランザクションのこと。
「発行TXのインプット」は発行に用いるUTXO。つまり上記で示したUTXO-01。
UTXO-01のアウトポイントを導出する。導出にはtapyrusrbを用いる。
$ irb # tapyrusrbを導入 irb(main):001:0> require 'tapyrus' => true # TXID irb(main):002:0> txid = '08504c03b29073a8ad8705363c7fcb2708afac2e1f11453bd7f64d9d365f269d' => "08504c03b29073a8ad8705363c7fcb2708afac2e1f11453bd7f64d9d365f269d" # index irb(main):003:0> index = 0 => 0 # TXIDからアウトポイントオブジェクトを生成 irb(main):004:0> out_point = Tapyrus::OutPoint.from_txid(txid, index) => #<Tapyrus::OutPoint:0x00000001045a6388 @index=0, @tx_hash="9d265f369d4df6d73b45111f2eacaf0827cb7f3c360587ada87390b2034c5008"> # アウトポイントオブジェクトのペイロードを取得 irb(main):005:0> out_point_payload = out_point.to_payload => "\x9D&_6\x9DM\xF6\xD7;E\x11\x1F.\xAC\xAF\b'\xCB\x7F<6\x05\x87\xAD\xA8s\x90\xB2\x03LP\b\x00\x00\x00\x00" # アウトポイントのペイロードのSHA256値を求め、バイナリをHexに変換 irb(main):006:0> Tapyrus::sha256(out_point_payload).bth => "47b0042d422289833b5c74b169efcd54f16aa0de97085fb12c787222f7ded1c7"
これでCOLOR識別子の「ペイロード」が
47b0042d422289833b5c74b169efcd54f16aa0de97085fb12c787222f7ded1c7
であることが得られた。
COLOR識別子
上記より、「タイプ」と「ペイロード」を組み合わせることでCOLOR識別子は
c347b0042d422289833b5c74b169efcd54f16aa0de97085fb12c787222f7ded1c7
であることがわかる。これで導出は完了。
確認
実際に発行し確認してみる。
$ tapyrus-cli issuetoken 3 1 08504c03b29073a8ad8705363c7fcb2708afac2e1f11453bd7f64d9d365f269d 0 { "color": "c347b0042d422289833b5c74b169efcd54f16aa0de97085fb12c787222f7ded1c7", "txid": "d8129bc7e3287bf38895cc203d8472d2e5888b94df189900b27f826d2f88eb4f" }
導出したCOLOR識別子と同じものが出力された。導出は成功。
補足
ペイロードの導出をtapyrusrbに丸投げしたので使わずやってみる。SHA256は流石にライブラリに頼る。
$ irb # digestを導入 irb(main):001:0> require "digest" => true # TXID irb(main):002:0> txid = '08504c03b29073a8ad8705363c7fcb2708afac2e1f11453bd7f64d9d365f269d' => "08504c03b29073a8ad8705363c7fcb2708afac2e1f11453bd7f64d9d365f269d" # index irb(main):003:0> index = 0 => 0 # OutPointの導出 irb(main):004:0> outpoint = [[txid].pack('H*').reverse, index].pack('a32V') => "\x9D&_6\x9DM\xF6\xD7;E\x11\x1F.\xAC\xAF\b'\xCB\x7F<6\x05\x87\xAD\xA8s\x90\xB2\x03LP\b\x00\x00\x00\x00" # COLOR識別子の導出 irb(main):005:0> Digest::SHA256.digest(outpoint).unpack('H*').first => "47b0042d422289833b5c74b169efcd54f16aa0de97085fb12c787222f7ded1c7"
OutPointの導出は
TXIDをバイナリに変換しエンディアンを反転したものとインデックスをpackする。packテンプレート文字列の内容は「a: ASCII文字, 32: 32バイト, V: リトルエンディアンの32bit 符号なし整数」
COLOR識別子の導出は
OutPointのSHA256値を求め、16進数文字列へ変換
以上
自己満のコーナーでした。理解するととても単純な構造。