暗号通貨に関する事など

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

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

【仮想通貨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であげようと思ってます。シェア大事。



【仮想通貨NEM】税金付き(levy)モザイクについて

税金付き(levy)モザイク (はじめに)

 NEMのモザイクには税金徴収(levy)機能というものがあり、モザイク作成時にそれを設定することが出来ます。そのことに関して書こうと思います。


 levyの意味はこちら。


 NEMの税金付きモザイクはそのモザイクを送金する時に、通常手数料と別に税金を課すことができます。説明は下記図のとおりです。


何に使えるのか?

 早速ですがNEMの税金機能がどうやって使われることが考えられるかを一例を持って説明したいと思います。(ほんの一例です)


 例えばここに「GJモザイク」というモザイクがあったとします。そして、それと同時に絵や作品を自分が良いねと思ったらGJモザイクを送る遊びがあったとします。


 このサービスにはサービス提供者と呼ばれる主催が存在していると考えられます。GJモザイクを作った人ですね。何もしなければGJモザイクの作成、GJモザイクを送る為の専用ソフトウェア(あれば)の開発費、維持費は全て主催の負担となります。


 ここで、税金が活躍する時が来ます。GJモザイク作者はGJモザイクに税金を課すことで負担を利用者にも支えてもらうことができます。


 これなら主催者の負担は軽くなるし、利用頻度が多い人が多くの支援を自動的におこなうことができますね。あくまで一例ですが、NEMの税金機能はこうして使われることを想定して作られたものでは無いかと考えます。
(個人的には"サービスには主体がいる"という考えがとてもNEMっぽいしその設計思想を表しているように感じます)


Levyの問題点

 全ての物事には良い面と悪い面が有ります。先に税金の良い面を紹介しました。では、悪い点はどこなのか。


 一言で言うと「相手のアドレスからお金を吸い取ることに使える」ことです。下記図で簡単に説明します。

 誰かからモザイクを貰ったけど、NanoWalletのダッシュボード占領して邪魔だから適当なアドレスに送って捨てようと送ると、知らない間に税金も一緒に送られます。


 NEMはパブリックブロックチェーンなので被害を訴えてもロールバックすることは実際不可能であると考えたほうが良く、攻撃者の一人勝ちとなります。


 税金機能自体は悪いものではありません。ちょうどメール機能が悪いのではなくスパムメールが悪いのと同じです。


 では不審なモザイクを誰かから送られた時はどうすれば良いのか。簡単です。無視してください。それだけです。モザイク作成にはお金(xem)がかかります。攻撃するにもコストがかかるので、無視することが攻撃者への反撃になるのです。


lebyの確認(NanoWallet)

 そのモザイクに税金が設定されているかどうかを確認するには下記図を参考にして確認してください。


悪意?実験?

 「このモザイク、税金付きだけど悪意あるの?ただのお遊びなの?」こういう話をすると必ずでてきますよね。個人的には貰ったものは個々が判断してくださいとしか言いようがありません。しかし、送る側については配慮が必要であると思っています。

 モザイクは表現であり、それを送るのはメッセージを送ることと同義です。

 「GJモザイク」を送れば相手は喜んでくれるかも知れないし、「FXckモザイク」を送られれば相手は気を悪くするかも知れません。当たり前ですけどね。


 「GJモザイク」を送れば相手は喜ぶと思っても、何の挨拶もなしにいきなり送りつけると相手を戸惑わせるかも知れません。たとえそのモザイクに税金が付いていなくても。


 これもちょうどメールと同じなんですよね。

 ・・・うざいですよね。うっかりカアチャンからのメールも一緒に消しそうになりますよね。


 相手に送るのは構わないでしょう。個人の自由なので。しかしそれによって相手にどう思われてもいけないと覚悟はすべきですね。税金をつけたモザイクをいきなり相手に送ればそれに対する相手の反応には覚悟を持つべきです。


 要は悪意があると受け取られても仕方ないと前もって思っておく必要があると思います。


問題は仕組みで解決しましょう

 悪意の有無は一旦置いておいて、自身の知らないところでお金がウォレットから出て行くのは悲劇です。これはなんとかしましょう。


 警告しても殆どの人の耳に入ることはないと思うし分かっていても"うっかり"があるのが人間なので、そういうものは仕組みで解決すればいいと思います。具体的には

  • 大金の保管用にはxemだけしか対応していないウォレットを利用する
  • xem以外のモザイク送金はホワイトリストで許可したものしか表示させない、送れないウォレットの開発
 をすればいいと思っています。作っていかないといけないですね。

 (話が飛びますが、今度発売されるTREZOR2はNEM対応らしいですが、上記の理由から個人的にはxem以外対応してないウォレットだと良いなと思っています。確認してませんが…)


最期に

 個人的に技術を使う事自体には良いも悪いもないのでどんどん使えば良いと思っています。そこに問題があるなら問題の認知を広げるのとソフトウェアで対策するのと両方から解決していくしか無いんでしょうね。