この記事では、開発テスト環境としてビットコイン テストネットを使用し、Node.js を組み合わせて PPkPub オープンソース プロジェクト ODIN の ID 登録機能を実装し、具体的なアプリケーション ケースとして、マルチ署名トランザクションを使用してカスタム データを埋め込み、署名後にブロードキャストする方法を説明します。マイナーノードによって確認され、ブロックチェーンに保存された後、最終的に読み取られて解析され、登録結果を取得できるため、ブロックチェーンへの書き込みから読み取りまでの完全なプロセスが実現されます。 1. ODINオープン識別子の定義を理解する
ODIN は、PPkPub オープン グループによってリリースされた最初のオープン ソース プロジェクトです。 Open Data Index Nameの略称です。広義では、ODIN はネットワーク環境内でデータ コンテンツ インデックスを識別および交換するためのオープン システムを指します。 URI(Uniform Resource Identifier)仕様に準拠しており、デジタル暗号通貨ブロックチェーン(BlockChain)に基づく自律的、オープン、安全、信頼性の高いデータコンテンツ管理と知的財産管理のための拡張可能なフレームワークを提供します。識別子、解決システム、メタデータ、ルール (ポリシー) の 4 つのコンポーネントで構成されます。狭義では、ODIN は、任意のデータ コンテンツ オブジェクトを識別する永続的なオープン識別子を指します。 ODIN は比喩的に言えば「データ時代の自律ドメイン名」です。これは、ビットコイン ブロックチェーンに基づく完全にオープンで分散化された命名および識別システムであり、スケーラブルで、より多くのブロックチェーンと互換性があります。従来の DNS ドメイン名と比較して、より革新的な機能を備えており、ビッグデータ、スマートデバイス、モノのインターネットなどの新興分野にうまく適用できます。 ODINは、XCP(コントラクトコイン)やマスターコインなどのデジタル暗号通貨の技術原理を参考に、ビットコインプロトコル仕様に従って特定のメッセージデータをエンコードし、ビットコイントランザクションとしてビットコインネットワークにブロードキャストし、ブロックチェーンに保存することで実装されます。 各 ODIN メッセージには次の特性が含まれます。 (a)ビットコインの送信元アドレス(ODINメッセージジェネレータに対応) (b)ビットコインの宛先アドレス(ODINメッセージが指し示す対象個体に対応。メッセージ生成者とメッセージが指し示す対象個体が同じ場合、このアドレスは空になります) (c)複数の 1-of-N マルチ署名出力 Bitcoin アドレス公開鍵 (ODIN データ パケットにエンコードして生成されます。実際にトランザクションを生成する際には、ODIN 設定データから 32 バイトが順に抽出され、その 32 バイトの先頭に文字列の長さに対応する 1 バイトが追加されます。合計 33 バイトが Bitcoin 公開鍵に対応します。33 バイトに満たない場合は、圧縮された公開鍵に対応する 33 バイトになるまで、バイナリ 0 が自動的に末尾に追加されます) (d)ビットコインの送信元アドレスに一定額のビットコイン残高があること(送信元アドレスから宛先アドレスに送信され、ODIN データ パケットに埋め込まれる有効なトランザクション エントリを複数生成するには、0.001 BTC 以上が推奨されます。注: ビットコインの 1-of-N マルチ署名トランザクションの特性上、これらのビットコイン金額は実際には使用されず、次の ODIN メッセージで再利用されます) (e)ビットコインでのメッセージコストの固定手数料(デフォルトは0.0001 BTC)。この手数料は、このトランザクションデータブロックを組み込んだビットコインネットワークマイナーに支払われます。 (f)ビットコイン変更アドレス(上記最初の項目のビットコインソースアドレスと同じで、ビットコイン取引プロトコルに従ってODINデータパケットを送信者のアカウントに埋め込む要件を満たす複数の取引エントリを生成した後、ビットコイン入力取引の超過額を回収するために使用される) 上記(c)の機能が、この技術を実現するための鍵となります。 ODIN データ ブロックは、ビットコイン トランザクションのマルチ署名出力データ ブロックに埋め込まれます。これは 1/N 出力です。各データ ブロックの最初の公開鍵は送信者に固定されているため、出力通貨の価値を償還してリサイクルすることができます。 2 番目から N 番目の公開鍵を格納するアドレス空間は、エンコードされた ODIN メッセージ データを格納するために使用されます。 Bitcoin マルチ署名トランザクションの詳細については、Bitcoin プロトコル仕様を参照してください。 注: N の推奨値は 10 以下です。1 つの 1/10 マルチ署名出力に収まらない ODIN データ ブロックは、2 番目、3 番目、およびその他のマルチ署名出力レコードに拡張して保存できます。 各 ODIN 情報データ ブロックの形式は、次のようにバイト順に定義されます。 バイト 1 ~ 32: プレフィックス機能識別子、32 バイトの ASCII 文字列 "P2P is future! ppkpub.org->ppk:0" (両側の二重引用符を除く) バイト 33: メッセージ タイプ、1 バイト。 メッセージの 34 バイト目から最後までは、メッセージ タイプによって区別される異なるメッセージ データです。詳細については、特定の ODIN メッセージ タイプの定義を参照してください。 注: 簡単に識別できるように、各 ODIN メッセージには、32 バイトの ASCII 文字列「P2P is future! ppkpub.org->ppk:0」(両側の引用符なし) がプレフィックスとして付けられます。この文字列は非常に長いため、ODIN 固有のトランザクションを他の Bitcoin トランザクションと混同することは不可能です。 2. ODINロゴをブロックチェーンに登録する例の分析 以下は、ODIN プロトコルにおける「新しく登録された ODIN 識別子」の具体的なメッセージ定義です。 ———————————————————————————————————— 新規登録されたODINロゴ Bitcoinの送信元アドレス: ODIN識別子の登録者に対応 Bitcoinの送信先アドレス: ODIN識別子の所有者に対応 メッセージ データ ブロックの形式は、バイト順序で次のように定義されます。 バイト 1 ~ 32: プレフィックス機能識別子、32 バイトの ASCII 文字列 "P2P is future! ppkpub.org->ppk:0" (両側の二重引用符を除く) バイト33: メッセージタイプ、1バイト、値はASCII文字R バイト 34: メッセージ本体のデータ形式、1 バイト。 値の定義: ASCII文字、 Tは「UTF-8でエンコードされたテキスト文字列」を意味します。 G は「gzip アルゴリズムによって圧縮されたバイナリ データ。UTF-8 でエンコードされた元のテキスト文字列を取得するには解凍する必要があります」を意味します。 バイト 35 ~ 36: メッセージ本文データのバイト長。2 バイトの符号なし短整数バイナリ データで、値の範囲は 0 ~ 65535 です。 メッセージ本体の 37 バイト目から指定された長さの最後までのメッセージ本体データがバイト単位で保存されます。 34 バイト目のデータ形式に従って元のメッセージ テキストを取得する必要があります。これは、以下に説明するように、JSON オブジェクト データに対応する UTF-8 でエンコードされた JSON 形式の文字列です。 { "title":"説明: 個人名の文字列", "email":"説明: 個人の公開メール(オプション)", "auth":"説明: 権限を設定します。値の定義については以下のコメントを参照してください", ”ap_list”:["説明: 複数のデータ アクセス ポイント AP の URL 配列。少なくとも 1 つは入力する必要があります",...,"xxxx"], "catalog":"説明: データ ソース タイプ、オプションの予約フィールド、補足されるもの" } 注: 構成権限値の説明: ASCII 文字 0、1、または 2 0 は「登録者または所有者のいずれかが所有者の関連情報を変更できる」ことを意味します。 1は「登録者のみが所有者の関連情報を変更できる」ことを意味します。 2は「所有者の関連情報を変更する前に、登録者と所有者が一緒に確認する必要がある」ことを意味します。 ———————————————————————————————————— ODIN 識別登録情報の例が以下にあると仮定します。 {“title”:”PPk-ODIN-sample”,”email”:”[email protected]”,”auth”:”2″,”ap_list”:["http://ppkpub.org/AP/"]} その後、上記のメッセージ定義に従って、ビットコインのトランザクション記録に組み立てられ、ビットコイン ネットワークにブロードキャストされて有効になります。対応するトランザクションの元のデータは次のとおりです (元のバイナリ データは、分析を容易にするために、バイトごとに 16 進 ASCII コード形式で出力されます)。 01000000032237b858f1a697cc2d26a451bd3fd3ef1944eb53f579b4fac38e5ecb5c0fc42c010000006b483045022100da55 a2d9f97695db12aecc0113662437957a6d4f17064ff49602ddc39904c31302201e81eae0c84f25019485ae4a2ce9b67c0e84 85599df87ab876b469e3cbbd24100121022e9f31292873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b9ff ffffff2ef89686bebf72bd31b8f27780223f7b5f448d0110b6fdda19595a073f42a301000000006b483045022100d49360fa 6bd45b92a068127db31c9cfd93af87543799968a5b076c2fea151f9b0220647900f5fc763f5a3eed13d382e13a3bddd15646 867b56f1be9d2629b2ccb4360121022e9f31292873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b9ffffff ffd704b1c1977cd50be182134b18fafaa16db1e917dfe4f93bcab1584aabf323d4010000006b483045022100fb88f75cae8a ccfe969cd89afbca677ff78a4914f5f506d6e5d481baf484e9f2022039f560414ec5a778a19565f7fe9e51b6acf7b841b4ba 2188785a5bb6051d7d510121022e9f31292873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b9ffffffff03 7d1600000000000001976a91451a09d25106715f09a14cac6367c3f4f2408590d88ac7d1600000000000000cf5121022e9f3129 2873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b9212050325020697320667574757265212070706b7075 622e6f72672d3e70706b3a302120525400657b227469746c65223a2250506b2d4f44494e2d73616d706c65222c222120656d 61696c223a2270706b70756240676d61696c2e636f6d222c22617574682221203a2232222c2261705f6c697374223a5b2268 7474703a2f2f70706b7075622e6f210972672f41502f225d7d000000000000000000000000000000000000000000000000000000056ae e6cac223000000001976a914391ef5239da2a3904cda1fd995fb7c4377487ea988ac00000000 上記のメッセージは、プロトコル規則に従って次のようにフィールドに分解できます。 01000000 // バージョン番号、UINT32 03 // Tx入力量、可変長INT。 0×03=3入力。 /*** 次は Input Tx の最初のグループです ***/ 2237b858f1a697cc2d26a451bd3fd3ef1944eb53f579b4fac38e5ecb5c0fc42c // Txトランザクションのハッシュ値、32バイトに固定 01000000 // 消費されたTxは0番目のフォワードトランザクション出力に位置し、UINT32、固定4バイト 6b // 次は対応する署名データの長さ、0x6b = 107 バイトです。 // この 107 バイトの署名には、秘密鍵署名 + 公開鍵の 2 つの部分が含まれています。 // ここでの値が00の場合、元のトランザクションがまだ署名されていないことを意味します 48 // 秘密鍵署名に対応するデータ長、0×48 = 72 バイト 3045022100da55a2d9f97695db12aecc0113662437957a6d4f17064ff49602ddc39904c31302201e 81eae0c84f25019485ae4a2ce9b67c0e8485599df87ab876b469e3cbbd241001 //秘密鍵署名の内容 21 // 対応する公開鍵データの長さ、0×21 = 33 バイト 022e9f31292873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b9 //対応する公開鍵データ ffffffff // シリアル番号、UINT32、固定4バイト。このフィールドは現在使用されていないトランザクション置換関数であり、デフォルトでは 0xFFFFFFFF に設定されています。 /*** 入力 Tx の 2 番目のグループ。上記と同様、分解は省略***/ 2ef89686bebf72bd31b8f27780223f7b5f448d0110b6fdda19595a073f42a301000000006b483045 022100d49360fa6bd45b92a068127db31c9cfd93af87543799968a5b076c2fea151f9b0220647900 f5fc763f5a3eed13d382e13a3bddd15646867b56f1be9d2629b2ccb4360121022e9f31292873eee4 95ca9744fc410343ff373622cca60d3a4c926e58716114b9ffffffff /*** 入力 Tx の 3 番目のグループ。上記と同様、分解は省略***/ d704b1c1977cd50be182134b18fafaa16db1e917dfe4f93bcab1584aabf323d4010000006b483045 022100fb88f75cae8accfe969cd89afbca677ff78a4914f5f506d6e5d481baf484e9f2022039f560 414ec5a778a19565f7fe9e51b6acf7b841b4ba2188785a5bb6051d7d510121022e9f31292873eee4 95ca9744fc410343ff373622cca60d3a4c926e58716114b9ffffffff 03 // Tx はトランザクション量を可変長 INT 型で出力します。 0×03=3出力。 /*** 出力の最初のグループ ***/ 7d160000000000000 // 出力されるビットコインの数、UINT64、8 バイト。バイト順序を反転すると、0x000000000000167d = 5757 satoshi = 0.00005757 BTC になります。 19 // 出力記述スクリプトのバイト数、0×19 = 25バイト、いくつかの操作コードと値で構成される 76 //スクリプト開始操作 0×76 は OP_DUP (スタックの先頭要素をコピー) を表します a9 //アドレスタイプ 0xa9 は OP_HASH160 を表します (スタックの最上位項目は 2 回ハッシュされ、最初は SHA-256 で、次に RIPEMD-160 でハッシュされます) 14 //アドレス長 0×14 = 20 バイト 51a09d25106715f09a14cac6367c3f4f2408590d //ODIN識別子の所有者アドレスに対応するHASH160値、20バイト 88 //0×88 は OP_EQUALVERIFY を表します (スクリプトのバイナリ演算と条件を実行し、結果が 0 の場合は OP_VERIFY を実行します) ac //Oxac は OP_CHECKSIG の略です (トランザクションで使用される署名はハッシュ値と公開鍵の有効な署名である必要があり、true の場合は 1 を返します) /*** 出力の 2 番目のグループ ***/ 7d160000000000000 // 出力されるビットコインの数、UINT64、8 バイト。バイト順序を反転する必要があります。 cf // 出力記述スクリプトのバイト数、0xcf = 207 バイト、いくつかのオペコードと値で構成 51 //Ox51 は OP_1 を表します (スクリプト コード 1 をスタックにプッシュします) 21 //スタックにプッシュされた最初の公開鍵のデータ長、0×21 = 33 バイト。 ODIN識別子登録者アドレスに対応する公開鍵 022e9f31292873eee495ca9744fc410343ff373622cca60d3a4c926e58716114b9 21 //スタックにプッシュされた 2 番目の公開キーのデータ長。 2番目の公開鍵から始まるODIN識別メッセージコンテンツを埋め込む 2050325020697320667574757265212070706b7075622e6f72672d3e70706b3a30 21 //スタックにプッシュされた3番目の公開鍵のデータ長 20525400657b227469746c65223a2250506b2d4f44494e2d73616d706c65222c22 21 //スタックにプッシュされた4番目の公開鍵のデータ長 20656d61696c223a2270706b70756240676d61696c2e636f6d222c226175746822 21 //スタックにプッシュされた5番目の公開鍵のデータ長 203a2232222c2261705f6c697374223a5b22687474703a2f2f70706b7075622e6f 21 //スタックにプッシュされた6番目の公開鍵のデータ長 0972672f41502f225d7d0000000000000000000000000000000000000000000000 56 //Ox56 は OP_6 (スクリプト コード 6 をスタックにプッシュ) を表します。前の0×51と合わせて1of6マルチ署名を表す。 ae //Oxae は OP_CHECKMULTISIG (マルチ署名検証を実行する) を表します /*** 出力の3番目のグループ ***/ e6cac22300000000 // ビットコイン出力の量、UINT64、8 バイト。バイト順序を反転する必要があります。 19 // 出力記述スクリプトのバイト数、0×19 = 25バイト、いくつかの操作コードと値で構成される 76 //スクリプト開始操作 0×76 は OP_DUP (スタックの先頭要素をコピー) を表します a9 //アドレスタイプ 0xa9 は OP_HASH160 を表します (スタックの最上位項目は 2 回ハッシュされ、最初は SHA-256 で、次に RIPEMD-160 でハッシュされます) 14 //アドレス長 0×14 = 20 バイト 391ef5239da2a3904cda1fd995fb7c4377487ea9 // 対応する HASH160 値、20 バイト 88 //0×88 は OP_EQUALVERIFY を表します (スクリプトのバイナリ演算と条件を実行し、結果が 0 の場合は OP_VERIFY を実行します) ac //Oxac は OP_CHECKSIG の略です (トランザクションで使用される署名はハッシュ値と公開鍵の有効な署名である必要があり、true の場合は 1 を返します) 00000000 // ロック時間、UINT32、固定4バイト 上記の ODIN プロトコル定義コンテンツと組み合わせると、対応する ODIN 識別登録メッセージを復元し、上記のトランザクション データの青い領域を通じて解析できます。 3. サンプルプログラムを実行する サンプル プログラムは 2 つの部分で構成されています。 1. OdinMonitorTestnet.js: Bitcoin テスト ネットワーク Testnet に関連するブロックチェーン データの変更を監視し、新しく登録された ODIN ロゴを解析します。 ソースコードはここからダウンロードできます: http://ppkpub.org/sample/OdinMonitorTestnet.js 2. OdinRegisterTestnet.js: Bitcoin テストネットに新しい ODIN ID を登録します。 ソースコードはここからダウンロードできます: http://ppkpub.org/sample/OdinRegisterTestnet.js 上記のサンプル コードをダウンロードし、Node.js がインストールされているテスト環境に保存します (保存されたファイルの名前は OdinRegisterTestnet.js および OdinMonitorTestnet.js です)。 Node.js テスト環境のインストール方法については、必要に応じて「初心者から上級者まで学ぶビットコイン ブロックチェーン開発ガイド 1」のインストール手順を参照してください (http://www.8btc.com/blockchain_develope_lesson_1)。 上記のサンプルプログラムを実行する前に、Bitcoin テストネットワーク (bitcoin-testnet) の Docker ランタイム環境がインストールされていることを確認してください。まだインストールされていない場合は、「Bitcoin Blockchain Development Guide from Beginner to Advanced 2」の手順を参照してインストールしてください (http://www.8btc.com/ppkpub_blockchain_develope_lesson_2)。 Node.js 開発およびテスト環境で新しいテキスト ターミナル ウィンドウを開き、コマンド ラインに次のコマンドを入力して、監視サンプル プログラムを起動します。 ノード OdinMonitorTestnet.js 次に、新しいテキスト ターミナル ウィンドウを開き、コマンド ラインに次のコマンドを入力して、登録サンプル プログラムを実行します。 ノード OdinRegisterTestnet.js 登録サンプルプログラムを実行した後、ビットコインテストネットワーク(bitcoin-testnet)のDockerランタイム環境のコマンドラインに「make generate BLOCKS=6」と入力して、新しいブロックレコードの生成をシミュレートします。新しく生成された取引記録は効果的に確認され、ブロックチェーンに保存されます。このとき、監視プログラムの実行中のインターフェイスに、新しい ODIN 識別登録レコードが解析されたことが表示されます (下の図を参照)。
|