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]を見てみる。
/**
* 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
- 量
これを追っていったら混乱したので、とりあえずバイトデータを分解してみることにします。
トランザクション作成してみる
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]を見てみます。
/**
* 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