仮想通貨・ブロックチェーン Advent Calendar 2016 10日目の記事です。
昨日の記事
明日は、 him0net さんの、「一行ずつ理解しながら bitcore-lib でトランザクションを作る」 という記事です。 普段ライブラリなどを通して何気なくトランザクションを作っていますが、Scriptとかを使おうとすると、トランザクションの中身を一つずつ理解してみたくなりますよね!楽しみです。
やべーやべーよー
Bitcore でビットコインのトランザクションをステップ・バイ・ステップで作る記事を書こうと思っていたのですが,調査してたらすごいわかりやすい記事を発見してしまいました(つい2日前).
Bitcoreでビットコインのトランザクションを生成しブロードキャストする
やっちまった,完全にテーマ設定ミスった...
でも,いい記事あったから!いっかではチャオ
とはいかないので,NEM のトランザクションを発行してみたいと思います.
お前誰や
ひも(him0)と申します.暗号通貨好きでわいわいしている人です.
世界初 $NEM で支払われたピザです。 pic.twitter.com/F4sfeAtgJV
— ひもさん@がんばリーリエ (@him0net) 2016年6月28日
XEM という通貨で初めてピザを買った人だったりします.(開発者たちにはクレイジーとか言われた)
NEM/XEM も好きですがビットコイン,Counterparty も大好きです,
OUSHI COIN 時すでにお🍣。 https://t.co/e2kxeSDlTS #OSUSHI
— ひもさん@がんばリーリエ (@him0net) 2016年12月11日
OSUSHI COIN という(現時点では)使いみちがないトークンを配ってたりします.
NEM とは,なんぞや
NEM は,New Economy Movement の略称(今はその限りではないらしい)であり,Proof-of-Importance(PoI) というコンセンサスアルゴリズムに基づくブロックチェーンを用いたプラットフォームです.
NEM では,XEM という暗号(仮想)通貨を扱うことができる他,モザイクと呼ばれるトークンを発行したり,アポスティーユと呼ばれる公証サービスを利用することができます.
ブロックは1分毎に生成されるので支払い用途でも現実的な時間でトランザクション承認を得ることができます.
また,Proof-of-Importance は,経済活動の貢献度が高い人ほど,報酬を得られる可能性が高いという,ノードのスペックに依存しないコンセンサスアルゴリズムであり,XEM 所有者であれば誰もがハーベスティング(マイニング)を行うことが可能となっています.
詳しくは,いつもお世話になっている @TrendStream さんの記事が非常にわかりやすく説明しているので,こちらをご覧ください
もっと技術的な仕様が知りたいという方は,NEM Technical Reference を参照すると良いと思います.
本題 NEM のトランザクションを作る
今回は,npm のパッケージ nem-api を使って nem のトランスファートランザクション(送金トランザクッション)を発行したいと思います.
課題設定
送信者のアドレス "NBBNC2-K72UDI-N5HMRA-EUWJ4F-22RZPQ-L2LYON-UDET"
送信者の秘密鍵 "ひみつ"
受信者のアドレス "NAPLE5-5ZXP4V-5DPHR5-4BRJVR-YP26TE-MCJCZ3-37W7"
nem には live-net(本環境)と test-net(テスト環境)が存在しますが,今回は live-net での送金を試みます.
送信者から 10 xem 受信者に送金します.
メッセージとして,"hello!" と送ります.
手数料は最安価に設定します.
レッツトライ
1. クライアントの初期化
nem はローカルにノードを立ててトランザクションをブロードキャストすることもできますが,スーパーノードと呼ばれるリモートのノードを使ってトランザクションをブロードキャストすることも可能です.
ビットコインで言うところの bitpay API がスーパーノードと言うかたちで提供されているイメージです.
ライブネットのスーパーノードの一覧はこちらこれらから1つを選んで利用すれば nem でできるすべての操作が可能です.
ローカルのノードを使う場合は,nem nis と呼ばれるノードサーバをインストールしブロックの同期を行う必要がありますがスーパーノードを利用する場合は,何もインストールする必要はありません.
var nemApi = require("nem-api");
var nis = new nemApi('http://62.75.171.41:7890/'); // Livenet は 7890
ライブネットの場合ポート番号は,7890 です.
2. パブリックキーの取得
XEM の残高をもつアカウントはパブリックキーを持ちます.
nem-api のライブラリは,オフラインで公開鍵を取得する API がなかった(nem-api には,issueにあげておきます)ので,アドレスをもとに NIS から取得します.
本来は秘密鍵からオフラインで生成できます.
var getPublicKey = function(nis, address) {
address = address.replace(/-/g , ""); // ハイフンを取り除く
nis.get('/account/get', { 'address': address }, function(res) {
var addressInfo = res.body;
return addressInfo["account"]["publicKey"];
});
};
var senderAddress = "NBBNC2-K72UDI-N5HMRA-EUWJ4F-22RZPQ-L2LYON-UDET";
var senderPublicKey = getPublicKey(nis, senderAddress)
3. 手数料(fee)を計算する
nem v0.6.82. で手数料は見直しが行われ,パッケージ nem-api の 手数料(fee) のこのアップデートが反映されていません.
NEM Update 0.6.82. Lower Fees and New API
なので今回は,自前で手数料計算を実装します.(こちらも,issue を上げておきます.)
var byteLength = function(str) {
return(encodeURIComponent(str).replace(/%../g,"x").length);
};
var getFee = function(amount, messageType, message) {
var fee = 0;
// xem transfer fee
if(amount < 20000) {
fee += 1;
}else if(amount > 250000) {
fee += 25;
}else {
fee += Math.floor(amount / 10000);
}
// message fee
fee += Math.floor(byteLength(message) / 32) + 1
return fee;
};
var amount = 10;
var messageType = 1;
var message = "hello!";
var fee = getFee(amount, messageType, message);
4. メッセージの Hex 文字列化
メッセージは HEX 文字列で扱われるので変換を行います.
var utf8ToHex = function(str) {
var hex;
hex = unescape(encodeURIComponent(str)).split('').map(function(v){
return ( '0' + v.charCodeAt(0).toString(16) ).slice( -2 )
}).join('');
return hex;
};
var hexMessage = utf8ToHex(message);
5. タイムスタンプの取得
nem のブロックチェーンで扱われるタイムスタンプは,nem のブロックチェーンの開始時間をベース時間にしたタイムスタンプです.
var getTimeStamp = function() {
const NEM_EPOCH = Date.UTC(2015, 2, 29, 0, 6, 25, 0);
return Math.floor((Date.now() / 1000) - (NEM_EPOCH / 1000));
};
var timeStamp = getTimeStamp();
var deadline = timeStamp + (1 * 60 * 60); // 1時間承認されなければ破棄
6. 送金量を microXEM 表現に変換
nem のブロックチェーンで扱われる XEM の単位は micro XEM で扱われるので,送金量と,手数料を変換します.
var microAmount = amount * 1000000;
var microFee = fee * 1000000
7. ネットワークのバージョン設定
ネットワークのバージョンを設定(テストネットか,否かです)
var isMainnet = true;
var version = isMainnet ? 1744830465 : -1744830463;
8. トランザクション オブジェクトの作成
var reciverAddress = "NAPLE5-5ZXP4V-5DPHR5-4BRJVR-YP26TE-MCJCZ3-37W7".replace(/-/g , "");
var txObj = {
timeStamp: timeStamp,
amount: microAmount,
fee: microFee,
recipient: reciverAddress,
type: 257, // transter transaction
deadline: deadline,
message: {
type: 1, // 暗号化なし 1 暗号化あり 2
payload: hexMessage
},
version: version,
signer: senderPublicKey
};
9. リクエストアナウンス情報の作成
秘密鍵で署名を行います.
var privateKey = "ひみつ"
var requestAnnounce = nis.signTX(txObj, privateKey);
10. リクエストアナウンスのブロードキャスト
署名されたデータをネットワークにブロードキャストすることでトランザクションを実行します.
nis.post('/transaction/announce', requestAnnounce, function(res) {
console.log(res.body);
});
実行
$ node app.js
{ innerTransactionHash: {},
code: 1,
type: 1,
message: 'SUCCESS',
transactionHash: { data: 'a744a12dc594f0c469b84512912a93cb8f0926eb52a2455b8a90bb3447ecfd61' } }
1分前後で認証が得られブロックチェーンに反映されます.
ブロックチェーンを確認
NEM Blockchain Explorer v3
トランスファー(送金)トランザクションが生成できました!
まとめ
ソースコードは him0/nem-transaction: nem transaction test with nodejs こちら
nem はまだまだ発展途上で,ライブラリや,ドキュメントの整備がいまいちだったり,というのが現状です.
私も翻訳手伝いをしたり,ウォレットのバグ修正をしたりと微力ですが開発に参加させていただいております.
興味ある方は,nem のに本フォーラムや,テレグラムチャンネルなどに参加してみるといいと思います.
今後 nem-api のパッケージの問題点が解決したらまたその点について追記したいと思います.
投稿遅れてごめんさい!
2017-01-04 手数料の計算式を修正,Typoを修正 @kmn さんありがとうございます.