暗号通貨のトランザクションを手作りする (3)

今回のおはなし

みなさんこんにちは。

VIPPOOL でエンジニアをやっています、星月です。

前回までで、トランザクションの概念と Script について解説しました。

今回は raw トランザクションの構造について説明します。
これで簡単なトランザクションが手作りできるようになります。

raw トランザクションとは、トランザクションの実データのことで、
可変長のバイナリ列で表現されます。
今回はこれを手作りすることを目指します。

var_int 型

トランザクションのデータで、数値を格納するために多用されている形式です。

格納したい値 x を、以下のルールで可変長のバイナリ列にします。

値域 形式
0≦x<0xFD x をそのまま 1 Byte で記述
0xFD≦x≦0xFFFF 0xFD に続けて x を 2 Byte リトルエンディアンで記述
0x10000≦x≦0xFFFFFFFF 0xFE に続けて x を 4 Byte リトルエンディアンで記述
0x100000000≦x 0xFF に続けて x を 8 Byte リトルエンディアンで記述

var_int に限らず、raw トランザクションではすべてリトルエンディアンを使用します。

トランザクションの構造

トランザクションの構造自体は単純で、ヘッダ+入力データ+出力データの構成となっています。

内容
バージョン (1か2を入れておく) int32_t
入力の個数 var_int
入力データの配列 後述
出力の個数 var_int
出力のデータ配列 後述
ロックタイム uint32_t

ロックタイムというのが初出ですが、ここは通常 0 を入れておけば問題ありません。

ざっくりこんなイメージです。

02 00 00 00      ... バージョン 2
03               ... 入力は 3 つ
入力データ1
入力データ2
入力データ3
02               ... 出力は 2 つ
出力データ1
出力データ2
00 00 00 00      ... ロックタイムはとりあえず 0

トランザクションの入力データ

トランザクションの入力データは以下の形式です。

内容
TXID uint256_t
出力インデックス uint32_t
scriptSig の長さ var_int
scriptSig 本体 可変長バイナリ
シーケンス番号 uint32_t

TXID はトランザクション ID のことで、256bit の整数をリトルエンディアンで書きます。

出力インデックスは、入力として接続する相手のトランザクションの出力の、
何番目か、というインデックスです。

シーケンス番号は普段使うことはないので 0 で問題ありません。

例えばこんな接続の場合。

f:id:y-hoshizuki:20181022130135p:plain

scriptSig には以下のプログラムを含めるとします。

02 CD AB         ... OP_PUSH 0xABCD

こうなります。

EC F2 65 AF 3E 30 B4 44 BC 14 1E EB 95 60 DD E8
34 DD 1B E2 CD 5D 2D BE 2F 84 75 01 00 A8 02 3F
                 ... 前 TXID: 3f02a8000175842fbe2d5dcde21bdd34e8dd6095eb1e14bc44b4303eaf65f2ec
02 00 00 00      ... 前 TX の第2出力を接続する
03               ... scriptSig の長さ
02 CD AB         ... scriptSig 本体
00 00 00 00      ... シーケンス番号はとりあえず 0

入力が複数ある場合は、この形式を連続して並べます。

トランザクションの出力データ

トランザクションの出力データは以下の形式です。

内容
出力金額 int64_t
scriptPubKey の長さ var_int
scriptPubKey 本体 可変長バイナリ

出力金額はコインではなく satoshi 単位の整数で書きます。
100,000,000 satoshi = 1.0 BTC です。
MONA の場合は特に呼び名は決まっていないそうですが、
同じ単位で書きます。

scriptPubKey には以下のプログラムを含めるとします。

02 CD AB         ... OP_PUSH 0xABCD
87               ... OP_EQUAL

こうなります。

00 E1 F5 05 00 00 00 00 ... 1BTC (100000000 satoshi)
04               ... scriptPubKey の長さ
02 CD AB 87      ... scriptPubKey

出力が複数ある場合は、この形式を連続して並べます。

まとめ

いかがでしたでしょうか。
raw トランザクション、意外に簡単な構造ではないでしょうか。

既にお気づきの方もいるとは思いますが、
TXID をプライマリキーとして見ると、
トランザクションのリンクは過去に向かう単方向リストの構造になっています。

よくよく考えれば当然の仕様で、
ブロックチェーンは追記はできても変更はできない分散型データベースですので、
トランザクションのリンクも必然的に過去に向かう単方向リストにせざるを得ないんですね。

今回はここまで。
ご質問、ご意見等ありましたらお気軽にリプライください。