【仮想通貨NEM】TransferTransactionの構造
はじめに
間違っていたら指摘してください。
TransferTransactionの構造
早速ですが構造を図にしたので載せます。下記図参照。
ちなみに、バイトオーダーはリトルエンディアンになっている。また、当然といえば当然だがこの中で登場するintやlong値はマイナスであってはならない。
versionとtype以外はそれほど特殊なものは無いと思う。ちなみに、上記表の中には全トランザクション共通の部分がある。上から見ていってversion〜deadlineまでは全てのトランザクションで共通の部分となる。
一応説明の補足としてクラスの継承の図を載せておく。各クラスで定義されたフィールドを見ればどこが共通した部分か分かると思います。
次に、構造の最上部2つ、versionとtypeの部分について、補足が必要だと思ったのでそのことについて書く。
version
※network info部分は名前が分からなかったので私が勝手にそう呼んでいるだけです
type
write系メソッドとBinarySerializerClass
トランザクションに署名を行うとき、トランザクションをバイナリデータにする必要がある。バイナリデータを生成する時に利用される言葉が"serialize"という言葉で、実際VerifiableEntityClassやTransferTransactionClassのソースコード内にserializeというメソッドがある。
serializeメソッドが呼ばれるとその中でwriteIntメソッドやwirteBytesメソッドが呼ばれているのが分かるが、それらがBinarySerializerによってどういった変換がされているかというと...
- writeInt => 4byte int
- writeLong => 8byte long
- wirteDouble => 8byte double
- writeBytes => 4byte dataLength + var byte dataPayload
- writeObject => 4byte objectSerializedDataLength + var byte serializedObject
- writeObjectArray => 4byte objectArraySize + var byte serializedObject(add 4byte length prefix)
example
ここで実際にnem-coreのソースを利用して出力したデータをサンプルとして載せる。バイナリデータを各フィールド毎に切って説明を加えたものが下にある図になる。
なお、無理やり出力させたせいで手数料など一部おかしな部分が有ります。そこは参考にせず構造だけ参考にしてみてください。
【条件】
・ネットワーク
テストネット
・署名者(送金者)の公開鍵
C4E97281C84749E67E06027BBC695EF4034C9885AF369715B2F9A44E10D52BA8
・受取者アドレス
NBUO7V7YQ5A33IAKWUOEROEORCXNVPAMV5NCUIGR
・メッセージ
Hello NEM
・mosaic1
alice:alicecoinを10枚送信
・mosaic2
test.bob:bobcoinを20枚送信
【連結されたデータ】
0101000002000098E290180020000000157367594486F1C427C9A9D30FE88DBDD73599245702CC0EED50C57F5E11281580841E000000000000000000280000004E42554F37563759513541333349414B57554F45524F454F5243584E5650414D56354E435549475200E1F5050000000011000000010000000900000048656C6C6F204E454D02000000220000001600000005000000616C69636509000000616C696365636F696E0A00000000000000230000001700000008000000746573742E626F6207000000626F62636F696E1400000000000000
【フィールド毎に切ったもの】
01010000 type
02000098 version
D4171600 timestamp
20000000 SignerDataLength(32)
C4E97281C84749E67E06027BBC695EF4034C9885AF369715B2F9A44E10D52BA8 SignerPublicKey
80841E0000000000 amountFee(2,000,000)
00000000 deadLine
28000000 recipientAddressDataLength(40)
4E42554F37563759513541333349414B57554F45524F454F5243584E5650414D56354E4355494752 recipientAddress(UTF-8)
00E1F50500000000 amountSendXem(100,000,000)
11000000 messageObjectDataLength(17)
01000000 messageType(1 => PlainMesage)
09000000 messageLength(9)
48656C6C6F204E454D messagePayload("Hello NEM")
02000000 mosaicCount(2)
22000000 mosaic1 ObjectDataLength(34)
16000000 mosaic1 MosaicInfoDataLength(22)
05000000 mosaic1 NameSpaceDataLength(5)
616C696365 mosaic1 NameSoaceDataPayload("alice")
09000000 mosaic1 MosaicDataLength(9)
616C696365636F696E mosaic1 MosaicDataPayload("alicecoin")
0A00000000000000 mosaic1 sendQuantity(10)
23000000 mosaic2 ObjectDataLength(35)
17000000 mosaic2 MosaicInfoDataLength(22)
08000000 mosaic2 NameSpaceDataLength(8)
746573742E626F62 mosaic2 NameSoaceDataPayload("test.bob")
07000000 mosaic2 MosaicDataLength(7)
626F62636F696E mosaic2 MosaicDataPayload("bobcoin")
1400000000000000 mosaic2 sendQuantity(20)
トランザクションへの署名
署名は上記のバイナリデータに署名を行うことになります。暗号はEd25519です。
注意点(追記)
・mosaic添付時のAmountフィールドに関して
さいごに
カタパルトで構造が変わるかも知れないのでここまではあまり触れずに来ましたが、確かにこういう記事って無いので、書いてみました。
nem-coreのソースコードをコンパイルして出力したので構造自体は間違ってないと思いたいですが、間違っていたら教えてください。ちなみに、nem-coreのソースコードのままだと署名用データはprivateで隠蔽されるのでpublicに変更したりモザイク情報が無いので本来エラーが出るところを無理やり無視させて出力させたりしています。
他人のコード読むことってこういう機会でもないと無いので、色々良い勉強になったなと思います。実際いい勉強になったという感想が一番強いです。カタパルトOSS化したらまた見てみようかなと思ってます。その場合C/C++の勉強をするのが先になりますが...。