TapyrusのCOLOR識別子について

就活モチベが吹き飛んだので趣味に走ります。

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)」で構成される。タイプとペイロードの内容については以下の通り。

タイプ定義ペイロード
0xC1Reissuable Token発行TXのインプットのscriptPubkeyのSHA256値
0xC2Non-Reissuable Token発行TXのインプットのOutPointのSHA256値
0xC3Non-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進数文字列へ変換

以上

自己満のコーナーでした。理解するととても単純な構造。

参考