LoginSignup
5
1

More than 5 years have passed since last update.

nem catapult バイトレベルで理解する その2 TransferTransaction

Last updated at Posted at 2018-06-23

Refference

[1] https://github.com/nemtech/nem2-library-js/blob/master/src/schema/TransferTransactionSchema.js

[2] https://github.com/nemtech/nem2-library-js/blob/master/src/transactions/TransferTransaction.js

[3] https://github.com/nemtech/nem2-library-js/blob/master/src/buffers/TransferTransactionBuffer.js

[4] https://github.com/nemtech/nem2-library-js/blob/master/src/coders/uint64.js

[5] https://nemtech.github.io/nem2-sdk-typescript-javascript/classes/_model_uint64_.uint64.html

前置き

TransferTransaction(署名済み)のデータって見てみると以下のような感じになります。

C5000000AAE822D5AEF30F96B21B7816F880D71F6AA03915025DF2CEBC4E8B4F1B21312CE8D26A1EADA4FDE336A00DA3FF8147253F61027614283AFCAE5C2F2B915A7A0C5D9513282B65A12A1B68DCB67DB64245721F7AE7822BE441FE813173803C512C03905441809698000000000093666D5C1000000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E20100030043B884C898706C138096980000000000C319EE771243D835002D31010000000029CF5FD941AD25D58096980000000000

これってどうなってるのでしょうか。

環境

Alpaca版

長いので先に結論置いておく

項目 サイズ 意味
サイズ 4byte(LE) payloadのバイト数
署名 64byte トランザクションへの署名
公開鍵 32byte 署名者の公開鍵
version 2byte(LE) 0390
type 2byte(LE) 5441
fee(l) 4byte(LE) 手数料
fee(h) 4byte(LE) 手数料
deadline(l) 4byte(LE) 期限
deadline(h) 4byte(LE) 期限
受取人 25byte 受取人アドレス
msg size 2byte(LE) メッセージバイト数+1
num mosaics 1byte モザイクの種類数
msg type 1byte メッセージタイプ
msg payload 可変 メッセージ本文
mosaic id(l) 4byte(LE) モザイクID
mosaic id(h) 4byte(LE) モザイクID
amount(l) 4byte(LE)
amount(h) 4byte(LE)
mosaic id + amount 16の倍数 モザイク種類数に応じてデータが続く

調べながらやってみる

項目を調べてみる

まずは、トランザクションの項目について書いてありそうなところを探してみる。

[1]を見てみる。

TransferTransactionSchema.js
/**
 * Transfer transaction schema
 * @const {module:schema/Schema}
 */
const schema = new Schema([
    uint('size'),
    array('signature'),
    array('signer'),
    ushort('version'),
    ushort('type'),
    array('fee', TypeSize.INT),
    array('deadline', TypeSize.INT),
    array('recipient'),
    ushort('messageSize'),
    ubyte('numMosaics'),
    table('message', [
        ubyte('type'),
        array('payload')
    ]),
    tableArray('mosaics', [
        array('id', TypeSize.INT),
        array('amount', TypeSize.INT)
    ])
]);

これを見ると、このような順番で並んでいる。

  • サイズ
  • 署名
  • 署名者の公開鍵
  • バージョン
  • タイプ
  • 手数料
  • 期限
  • 受取人
  • メッセージサイズ
  • モザイク種類数
  • メッセージ
    • タイプ
    • 本文
  • モザイク(配列)
    • ID

これらは、[2][3]で使われているみたい。

これを追っていったら混乱したので、とりあえずバイトデータを分解してみることにします。

トランザクション作成してみる

REST(curl http://localhost:3000/transaction/[hash])で取得したらこのようなデータが取れるようなトランザクションを作成した。

試行 signature signer version type fee(l) fee(h) deadline(l) deadline(h) recipent msg type msg payload mosaic id(l) mosaic id(h) amount(l) amount(h) mosaic id(l) mosaic id(h) amount(l) amount(h)
1 "EC8E...840E", "A9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF32", 36867, 16724, 10000000, 0 1277060398, 16 "90758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E2", 0, "" 3646934825, 3576016193 10000000, 0
2 "E049...8701", "A9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF32", 36867, 16724, 12000000, 0 1292816197, 16 "90758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E2", 0, "73656E64696E67206D657373616765" 3646934825, 3576016193 3501587328, 232
3 "062B...1F0C", "A9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF32", 36867, 16724, 12000000, 0 , 16 "90758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E2", 0, "73656E64696E67206D657373616765206C6F6E67206D6573736167652073656E64696E67" 3646934825, 3576016193 3501587328, 232 800137557, 272525292 23, 0

それぞれのpayloadは、

試行 payload
1 A5000000EC8E88E9D1EAFAD916A72B0FC920D7732E83BF937C1A00B1506663580E8AEAC0AD1D46939FA12DF1DA7337914E82D6444B4C224AEA5FDC36B9D91BCA6C05840EA9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF320390544180969800000000002E651E4C1000000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E20100010029CF5FD941AD25D58096980000000000
2 B4000000E049585D1D347BA5566E222484729F8D209D3AFE07981F0EBFE69396834191CD20A47C8A34A3A91ED693F50CB134CB354604F7863CFDE21021D3B433310B8701A9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF3203905441001BB7000000000045CF0E4D1000000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E21000010073656E64696E67206D65737361676529CF5FD941AD25D580FBB5D0E8000000
3 D9000000062B14D43550C1476C1F82BB63325B19ECCD7B19C0AFC67CD5188630F46DEBBC81F07A2CD44C2E3E896CDAA6C12F15ED4AB4F16E70B156779AE8B35591CA1F0CA9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF3203905441001BB7000000000083BE354D1000000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E22500020073656E64696E67206D657373616765206C6F6E67206D6573736167652073656E64696E6729CF5FD941AD25D580FBB5D0E80000002FB12155103E67EC1700000000000000

となります。

では解析してみます。

試行1

payloadとREST

A5000000EC8E88E9D1EAFAD916A72B0FC920D7732E83BF937C1A00B1506663580E8AEAC0AD1D46939FA12DF1DA7337914E82D6444B4C224AEA5FDC36B9D91BCA6C05840EA9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF320390544180969800000000002E651E4C1000000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E20100010029CF5FD941AD25D58096980000000000

試行 signature signer version type fee(l) fee(h) deadline(l) deadline(h) recipent msg type msg payload mosaic id(l) mosaic id(h) amount(l) amount(h)
1 "EC8E...840E", "A9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF32", 36867, 16724, 10000000, 0 1277060398, 16 "90758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E2", 0, "" 3646934825, 3576016193 10000000, 0

わかりやすいところから取り出す

署名と公開鍵と受取人は値がわかりやすいので、すぐに切り出せる。

項目 データ
?1 A5000000
署名 EC8E88E9D1EAFAD916A72B0FC920D7732E83BF937C1A00B1506663580E8AEAC0AD1D46939FA12DF1DA7337914E82D6444B4C224AEA5FDC36B9D91BCA6C05840E
公開鍵 A9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF32
?2 0390544180969800000000002E651E4C10000000
受取人 90758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E2
?3 0100010029CF5FD941AD25D58096980000000000

それで、「?1」は順番からサイズだと思う。

「?2」は、バージョン、タイプ、手数料、期限

「?3」は、モザイク種類数、メッセージサイズ、メッセージ、モザイク

ここで、Uint64について調べてみる

手数料、期限、モザイクID、モザイク量って、なんかデータが2つあります。

モザイクを送るときにこのような記述をよく見ます。

new Mosaic(new MosaicId('nem:xem'), UInt64.fromUint(10000000))

UInt64という型かオブジェクトがあるんだろうなぁと。

[4]を見てみます。

uint64.js
/**
 * Converts a numeric unsigned integer into a uint64.
 * @param {number} number The unsigned integer.
 * @returns {module:coders/uint64~uint64} The uint64 representation of the input.
 */
fromUint: number => {
    const value = [(number & 0xFFFFFFFF) >>> 0, (number / 0x100000000) >>> 0];
    //if (0x00200000 <= value[1] || 0 > number || 0 !== (number % 1))
    //  throw Error(`number cannot be converted to uint '${number}'`);

    return value;
},

結論から言うと、64bitの数値を32bitずつに分割して、配列にしている、ということだと認識しています。

後ろ(下)32bitをlower part、前(上)32bitをhgher partと呼ぶみたいです。([5]にそういう説明がある)

nodejsで試す

(number & 0xFFFFFFFF) >>> 0が後ろ(下)32bitを取り出す

$ node
> number = 0x0001F8645223984F
1378064463
> number & 0xFFFFFFFF
1378064463
> (number & 0xFFFFFFFF) >>> 0
1378064463
> (1378064463).toString(16).toUpperCase()
'5223984F'

(number / 0x100000000) >>> 0が前(上)32bitを取り出す

$ node
> number = 0x0001F8645223984F
1378064463
> number / 0x100000000
129124.32085563592
> (number / 0x100000000) >>> 0
129124
> (129124).toString(16).toUpperCase()
'1F864'

>>>のビット符号なし右シフト演算子でUintにCastしてる感じがする。

というわけで、number = 0x0001F8645223984Fだと、value[1] = 0x0001F86となり、value[0] = 0x45223984Fとなる。

気になること

大きな数値、0x25E1F8645223984F = 2729735958921713743を入れてみます。

> nem2Sdk.UInt64.fromUint(2729735958921713743);
UInt64 { lower: 1378064384, higher: 635566180 }

hexにすると、このようになります。

{ lower: 0x52239800, higher: 0x25E1F864 }

合わせると0x25E1F86452239800となり、元の値0x25E1F8645223984Fと異なります。

javascriptの仕様で53bitが上限らしいのですが、気になります。

残りの情報

?2

0390544180969800000000002E651E4C10000000

version type fee(l) fee(h) deadline(l) deadline(h)
dec 36867, 16724, 10000000, 0 1277060398, 16
hex 9003, 4154, 989680 00 4C1E652E, 10

これを見比べてみると、

0390 -> version
5441 -> type
8096980000000000 -> fee(l) + fee(h)
2E651E4C10000000 -> deadline(l) + deadline(h)

feeとdeadlineはUint64だと思うので、4byte区切りでよさそうです。

?3

0100010029CF5FD941AD25D58096980000000000

msg type msg payload mosaic id(l) mosaic id(h) amount(l) amount(h)
dec 0, "" 3646934825, 3576016193 10000000, 0
hex 00, D95FCF29, D525AD41, 989680, 00

これを見比べてみると、

01000100 -> ?4
29CF5FD9 -> mosaic id(l)
41AD25D5 -> mosaic id(h)
8096980000000000 -> amount(l) + amount(h)

「?4」は以下のデータだと思います

  • メッセージサイズ
  • モザイク種類数
  • メッセージ
    • タイプ
    • 本文

が、これだけではわかりません。

ここまでの結果

項目 データ
サイズ A5000000
署名 EC8E88E9D1EAFAD916A72B0FC920D7732E83BF937C1A00B1506663580E8AEAC0AD1D46939FA12DF1DA7337914E82D6444B4C224AEA5FDC36B9D91BCA6C05840E
公開鍵 A9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF32
version 0390
type 5441
fee(l) 80969800
fee(h) 00000000
deadline(l) 2E651E4C
deadline(h) 10000000
受取人 90758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E2
?4 01000100
mosaic id(l) 29CF5FD9
mosaic id(h) 41AD25D5
amount(l) 80969800
amount(h) 00000000

次の試行で見てみます。

試行2

XEMの量を増やして、メッセージをつけました。

payloadとREST

B4000000E049585D1D347BA5566E222484729F8D209D3AFE07981F0EBFE69396834191CD20A47C8A34A3A91ED693F50CB134CB354604F7863CFDE21021D3B433310B8701A9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF3203905441001BB7000000000045CF0E4D1000000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E21000010073656E64696E67206D65737361676529CF5FD941AD25D580FBB5D0E8000000

試行 signature signer version type fee(l) fee(h) deadline(l) deadline(h) recipent msg type msg payload mosaic id(l) mosaic id(h) amount(l) amount(h)
2 "E049...8701", "A9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF32", 36867, 16724, 12000000, 0 1292816197, 16 "90758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E2", 0, "73656E64696E67206D657373616765" 3646934825, 3576016193 3501587328, 232

分けてみる

同じ要領で項目分けしていきます。

項目 データ
サイズ B4000000
署名 E049585D1D347BA5566E222484729F8D209D3AFE07981F0EBFE69396834191CD20A47C8A34A3A91ED693F50CB134CB354604F7863CFDE21021D3B433310B8701
公開鍵 A9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF32
version 0390
type 5441
fee(l) 001BB700
fee(h) 00000000
deadline(l) 45CF0E4D
deadline(h) 10000000
受取人 90758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E2
?4 1000010073656E64696E67206D657373616765
mosaic id(l) 29CF5FD9
mosaic id(h) 41AD25D5
amount(l) 80FBB5D0
amount(h) E8000000

残りの情報

?4について

  • メッセージサイズ
  • モザイク種類数
  • メッセージ
    • タイプ
    • 本文

RESTのデータを見てみます。

項目 試行2 試行1
msg type 0, 0,
msg payload "73656E64696E67206D657373616765" ""

msg payloadがわかっているので、「?4」はこうなります。

項目 試行2 試行1
?5 10000100 01000100
msg payload 73656E64696E67206D657373616765 -

「?5」の先頭1byteが、試行2で変化しました。

これが、メッセージのサイズだろう。

msg payloadのサイズは15(=0x0F)byteで、type + payloadの16(=0x10)byteとなり一致する。

そう考えると、試行1は、type(1byte) + payload(0byte)ってかんじ。

項目 データ
msg size 25
?6 00
num mosaics 01
msg type 00
msg payload 73656E64696E67206D657373616765206C6F6E67206D6573736167652073656E64696E67

「?6」は、msg sizeとして2500なのか、num mosaicsとして0001なのか。

なので、パターンとしてはどちらか。

パターン1 パターン2
25 -> msg size
0001 -> num mosaic
2500 -> msg size
01 -> num mosaic

数値はリトルエンディアン表記っぽいので、そのうえで解釈すると、

パターン1 パターン2
メッセージサイズは最大256byte?
モザイク種類は256?
メッセージサイズは最大65535byte
モザイク種類は1

になるので、パターン2が妥当そう

試行2.5

試しに、メッセージに半角1024文字のメッセージを入れてみた。

payloadが長すぎるのでここには書けないが、

項目 試行2.5 試行2 試行1
?5 01040100 10000100 01000100
msg payload 長すぎ省略 73656E64696E67206D657373616765 -

0104=0x0401=1025なので、msg sizeは2byteの長さ、つまりパターン2であってそう。

ここまでの結果

項目 データ
サイズ B4000000
署名 E049585D1D347BA5566E222484729F8D209D3AFE07981F0EBFE69396834191CD20A47C8A34A3A91ED693F50CB134CB354604F7863CFDE21021D3B433310B8701
公開鍵 A9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF32
version 0390
type 5441
fee(l) 001BB700
fee(h) 00000000
deadline(l) 45CF0E4D
deadline(h) 10000000
受取人 90758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E2
msg size 2500
num mosaics 01
msg type 00
msg payload 73656E64696E67206D657373616765206C6F6E67206D6573736167652073656E64696E67
mosaic id(l) 29CF5FD9
mosaic id(h) 41AD25D5
amount(l) 80FBB5D0
amount(h) E8000000

試行3

XEMとモザイクを送ってみる

payloadとREST

D9000000062B14D43550C1476C1F82BB63325B19ECCD7B19C0AFC67CD5188630F46DEBBC81F07A2CD44C2E3E896CDAA6C12F15ED4AB4F16E70B156779AE8B35591CA1F0CA9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF3203905441001BB7000000000083BE354D1000000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E22500020073656E64696E67206D657373616765206C6F6E67206D6573736167652073656E64696E6729CF5FD941AD25D580FBB5D0E80000002FB12155103E67EC1700000000000000

試行 signature signer version type fee(l) fee(h) deadline(l) deadline(h) recipent msg type msg payload mosaic id(l) mosaic id(h) amount(l) amount(h) mosaic id(l) mosaic id(h) amount(l) amount(h)
3 "062B...1F0C", "A9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF32", 36867, 16724, 12000000, 0 , 16 "90758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E2", 0, "73656E64696E67206D657373616765206C6F6E67206D6573736167652073656E64696E67" 3646934825, 3576016193 3501587328, 232 800137557, 272525292 23, 0

分けてみる

同じ要領で、分けてみます。

項目 データ
サイズ D9000000
署名 062B14D43550C1476C1F82BB63325B19ECCD7B19C0AFC67CD5188630F46DEBBC81F07A2CD44C2E3E896CDAA6C12F15ED4AB4F16E70B156779AE8B35591CA1F0C
公開鍵 A9DF85FAF72B1214146D0A8FD4CD4DD03C270EA6B395CDF0CDE2D4729AB6FF32
version 0390
type 5441
fee(l) 001BB700
fee(h) 00000000
deadline(l) 83BE354D
deadline(h) 10000000
受取人 90758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E2
msg size 2500
num mosaics 02
msg type 00
msg payload 73656E64696E67206D657373616765206C6F6E67206D6573736167652073656E64696E67
mosaic id(l) 29CF5FD9
mosaic id(h) 41AD25D5
amount(l) 80FBB5D0
amount(h) E8000000
mosaic id(l) 2FB12155
mosaic id(h) 103E67EC
amount(l) 17000000
amount(h) 00000000

モザイクが増えた分、num mosaicsが増えて、後ろにmosaic idとamountが追加された。

結論

TransferTransactionにおけるバイト列は、以下の意味合いを持つと推定されます。

項目 サイズ 意味
サイズ 4byte(LE) payloadのバイト数
署名 64byte トランザクションへの署名
公開鍵 32byte 署名者の公開鍵
version 2byte(LE) 0390
type 2byte(LE) 5441
fee(l) 4byte(LE) 手数料
fee(h) 4byte(LE) 手数料
deadline(l) 4byte(LE) 期限
deadline(h) 4byte(LE) 期限
受取人 25byte 受取人アドレス
msg size 2byte(LE) メッセージバイト数+1
num mosaics 1byte モザイクの種類数
msg type 1byte メッセージタイプ
msg payload 可変 メッセージ本文
mosaic id(l) 4byte(LE) モザイクID
mosaic id(h) 4byte(LE) モザイクID
amount(l) 4byte(LE)
amount(h) 4byte(LE)
mosaic id + amount 16の倍数 モザイク種類数に応じてデータが続く

LE -> Little Endian

ただ、バイト数の表現が、BitcoinのVarIntのようなものだった場合は、この推定は崩れます。

気になること一覧

  • Uint64のデータを入れるときに、53bit以上の数値を入れるときには気を付けなければならないこと
    • mosaicIDやDeadlineとかどうなるんだろう

関連

nem catapult バイトレベルで理解する その1 トランザクションハッシュ
https://qiita.com/planethouki/items/d7a7fc7adf8c8bc48668

nem catapult バイトレベルで理解する その2 TransferTransaction
https://qiita.com/planethouki/items/025d44f2ebe6cfcb4b1f

nem catapult バイトレベルで理解する その3 トランザクション署名
https://qiita.com/planethouki/items/932d96ee17bd4f305368

nem catapult バイトレベルで理解する その4 Cosignature Transaction
https://qiita.com/planethouki/items/fcac3c9d329b0278c4b7

nem catapult バイトレベルで理解する その5 SecretLock/Proof Transaction
https://qiita.com/planethouki/items/4c91c2e6c722283c50f1

nem catapult バイトレベルで理解する その6 空ブロック
https://qiita.com/planethouki/items/da717595a1ff58d0d84f

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1