暗号通貨に関する事など

暗号通貨に関する覚書など。メモや日記。

※技術的なことに関して、間違っていたらコメントから指摘していただけると泣いて喜びます

【仮想通貨NEM】TransferTransaction実験1

はじめに

 NEMのFee計算がなんだか分かりにくいということで、徹底的に調べて記事にしようかと思って最近NEM-coreのソースコードを眺めてたりしています。すると、関係ないところで疑問に思ったことがありまして、今回はその実験と結果です。


 ちなみに、当然ですがテストネットで試してます。


疑問

 ソースコードを見る限りだとMosaicが添付されたTransferTransactionはAmount(送信xem量)フィールドが無視されるっぽい。実際、NanoWalletを利用してもモザイクの送信をしたい時に一緒にxemを送信するとなると "nem:xem" をわざわざ添付してあげないといけない仕様になっている。


 では、mosaicが添付されている + Amountフィールドに数値が入力されているTransferTransactionをブロードキャストするとどうなるのか。主に気になるのは以下の点。

  1. 手数料は?
  2. xemの送信量は?
  3. そもそもverificationを通過するの?

結果

 結果だけお伝えします


 Amountフィールドはモザイク送信時には別の意味になる


説明

 モザイクが添付されている場合、モザイクの送信量は以下の通りとなります。

トータルの送信量 = ( amount / 1,000,000 ) × ( quantity / 10^dividibility )

 ややこしいのでamountを1,000,000に固定すれば( amount / 1,000,000)は "1" になるので、それで良いと思います。送信量はquantityで調整できるので。


 なお、この時amountは1,000,000で割り切れる数字でないといけません。そうでなければ検証で弾かれます。


example

 上記説明の例を書いておきます。

[mosaic]

1. 名前 : alice

2. 総発行数 : 100

3. divisibility(可分性) : 2

4. 可分性を含めた発行数(2,3より) : 100.00


[送信]

amount : 2,000,000

quantity : 100

実際の転送量 : 2,000,000 / 1,000,000 * 100 / 10^2 = 2

[mosaic]

1. 名前 : alice

2. 総発行数 : 1000

3. divisibility(可分性) : 1

4. 可分性を含めた発行数(2,3より) : 1000.0


[送信]

amount : 4,000,000

quantity : 20

実際の転送量 : 4,000,000 / 1,000,000 * 20 / 10^1 = 8


今回送信したデータ

[MosaicInfo]
namespace : 1alice.1alice
mosaicname : 1alice
initial suply : 10,000
divisibility : 2
(つまり総発行数は10,000.00)


[TxData1]
01010000
02000098
21447005
20000000
2CE02903E133430372A5082DC544928CDD5EC8AED20ADEBB614BA096ABB2B6CF
3057050000000000
31527005
28000000
5441564E335036535A32483452524232495A54514D454855544A4552364B36504C55544959554E54
80841E0000000000 amount(2,000,000 == 2)
00000000
01000000
27000000
1B000000
0D000000
31616C6963652E31616C696365
06000000
31616C696365
6400000000000000 quantity(100)
(フィールド名は省略しています)


[txID]
a49efe9b1ddd1ecb907616491c017447d2efd440bb71d45d242b35f7786d7743


[送信量]
2,000,000(amount) / 1,000,000 × 100(quantity) / 10^2(divisibility) = 2
=> 1aliceモザイクを2.00送信できた


[TxData2]
01010000
02000098
90497005
20000000
2CE02903E133430372A5082DC544928CDD5EC8AED20ADEBB614BA096ABB2B6CF
3057050000000000
A0577005
28000000
5441564E335036535A32483452524232495A54514D454855544A4552364B36504C55544959554E54
20A1070000000000 amount(500,000 == 0.5)
00000000
01000000
27000000
1B000000
0D000000
31616C6963652E31616C696365
06000000
31616C696365
6400000000000000 quantity(100)


[APIcallの結果(JSON)]
{"innerTransactionHash"{},"code":148,"type":1,"message":"
FAILURE_MOSAIC_DIVISIBILITY_VIOLATED","transactionHash":{"data":"be83c04540dcccc1a0accb22114a0c59d1e1a6dfcca33639478f031c70b861f6"}}


※amountが1,000,000で割りきれない数字だとエラーが出るので送金できませんでした

さいごに

 最初無視しているのかと思いましたが、違ったようです。


 ここまでさらっとしてますが、これやるのにライブラリ使えばいいのに簡単なHTTPクライアントをJavaで作ったり(折角なので今後使いまわせるやつ作った)、MosaicInfoのデータが無いのでNEM-coreのコードを書き換えて自力入力できるようにしたりなんか色々やったので大変でした。


 コードが散らばってしまって多分来月には何がなんやらわからない状態になっていると思います。


 気になったらTestNetでどんどん試しましょうね。場合によってはバグバウンティ貰えるかもよ。


 手数料の記事はリファレンスを信用するならあれで解ると思いますし、わざわざ書かなくてもいいかな...とか思ってます。


 あと、今回"実験1"としているのは単に将来用です。2があるかどうかはわかりません。

【仮想通貨NEM】TransferTransactionの構造

はじめに

 NEMはビットコイン等と違い、基本的にはネイティブ機能として様々な機能を実装しており、機能毎に送信するトランザクションの構造自体が変化する。今回、我々が普段の利用で最もよく利用するxemやモザイクを送信する時に使うTransferTransactionというトランザクションの構造を調べたので記録として残す。


 間違っていたら指摘してください。


TransferTransactionの構造

 早速ですが構造を図にしたので載せます。下記図参照。


 ちなみに、バイトオーダーはリトルエンディアンになっている。また、当然といえば当然だがこの中で登場するintやlong値はマイナスであってはならない。


 versionとtype以外はそれほど特殊なものは無いと思う。ちなみに、上記表の中には全トランザクション共通の部分がある。上から見ていってversion〜deadlineまでは全てのトランザクションで共通の部分となる。
 一応説明の補足としてクラスの継承の図を載せておく。各クラスで定義されたフィールドを見ればどこが共通した部分か分かると思います。

 
 次に、構造の最上部2つ、versionとtypeの部分について、補足が必要だと思ったのでそのことについて書く。
 

version

 versionは4byteでただのintかと思いきや、実際は3byteと1byteに分かれている。3byteの部分がversionを表現する数値、最後の1byteがネットワークを表現している。下記図参照。

※network info部分は名前が分からなかったので私が勝手にそう呼んでいるだけです


type

 typeは4byteのフィールドだが、単にVerifiableEntityの種類によって1から数えて数値を割り振っているわけではない。先頭2byteを利用して大分類と小分類の分類分けを利用して表現している。 " 0x [小分類] [大分類] 00 00 "といった具合にその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)
 となっている。説明に難があるが要するに、intは4byteのデータでシリアライズされ、longは8byteのデータになる。バイト配列のデータ(utf-8としてバイト配列化されたデータ等)は、まず最初に4byteでデータ長が頭につくと思えば良いし、そういう目で一番上のTransaction構造の図を見ればそうなっていることが分かる。

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++の勉強をするのが先になりますが...。

仮想通貨NEMのハーベスティングの状態を確認できるWatchFace

 NEMのハーベスティングの状態をPebbleから監視できるアプリを作りました。元々はQitiaの方で書いていました(後に大きく修正しました)が、今は特に技術的なお知らせもないのでこちらで…

Qiitaの記事はこちら


 また、Githubでソースコード公開しています。ライセンスは特に気にしていないので、物好きな方はお好きにフォーク、再利用、再配布してください。外部リソースとして使用しているフォントも、オープンソースフォントを利用しているのでライセンスは問題ないかと思います。アプリ中で使用している画像は自分で描いたのでこれも気にせず使ってください(気にしなくても使う人いないでしょう)。なお、フォーク、再利用などで生じた損害損失は一切私の方では受け付けませんのであらかじめご了承ください。


使い方

 使い方は簡単です。


 まず、PebbleAppStoreから”NEM”で検索していただけると出てくるのでそれを取り込んでください。その後、設定画面でNEMアドレスと委任先ノードIPアドレスを入力してもらえれば、準備完了です。(委任先ノードのIPアドレスを設定しないと正しい判断が出来ません。)




 もし、委任ハーベストしているはずのNEMアドレスをセットしても正しく表示されない場合、アドレス設定欄にリモートアカウントのアドレスを直接セットして再度試してみてください。
 基本的に委任元のノードを入力してもリモートアカウントのアドレスの取得を試みるよう動きますが、場合によっては取得できないことがある(仕様の関係で)のでその時はリモートアカウントのアドレスをアドレス設定欄に入力してください。


 ハーベスティングの状態確認は時刻版の下にある小さな丸いアイコンで確認できます。それぞれの画像と意味は下記図のとおりです。

 以上です。もし、何かあればGithubの方かツイッターでクレーム投げていただければと思います。私が持っているものはPebbleTimeで、他の形のものはエミュレータを使って確認しただけなので、もしかしたら表示のバランスが悪いかも知れません。


無駄話

 最初別のフォント使ってたんですね。海外のフリーフォントらしきものを。で、一応ちゃんとやるかということでライセンスとか調べていたのですがそのうちにめんどくさくなって、GoogleFontさんにお世話になることにしました。GoogleFontさんは偉大。

 真面目にやればすぐに作れるものだと思います。NEMではHttpを利用したAPIを提供してくれているので、基本的に学ぶことはアプリ側の実装や言語だけでした。実働時間のほとんどがPebbleのアプリとCとjsについて調べてました。しつこいぐらいに言われていますが、これがNEMの良さの一つですよね。レイヤー分けって大事。


 作っていて、設定画面どうやって作ればいいんだろうか。困ったな。と思った時にPebbleClayなるものを発見しました。公式サイトにも記事あるんですけどね。これがとても便利。「こんなものがあるといいのにな」と思ったものは大体どこかの誰かが作ってくれていたりするんですね。インターネットすごい。


 あと、今回行ったAPIアクセスのフローなんかはまたQiitaであげようと思ってます。シェア大事。