この記事は nem Advent Calendar 2019 の記事です。
前日は @hhatto さんの 「NEM2 SDK for Rustを作り始めました」でした。
はじめに
アドベントと言えば真っ先に龍騎1が思い浮かぶのは私だけ?最強の不死鳥2も出てくるしね。
2019年NEMアドベント、不死鳥ファイナルベント!
ひょんな事3からアドベントカレンダー参加することになりました。しかもトリなんて。。。
普段はリング設営なる裏方仕事が多いので、お手柔らかにお願いいたします。
テーマ:Catapultにクリスマスを詰め込みたい!
クリスマスにちなんだ何かを、Catapultを使ってやってみようと思案すること数日。
メッセージとアグリゲートトランザクションを使って、 クリスマスカード画像データそのもの をブロックチェーンへ保存してみることに。
ファイルハッシュ値じゃなく、ファイルのデータそのものを。
NEM特有の単語 簡単な説明
メッセージについて
NEM/mijinブロックチェーンの転送トランザクションにはメッセージを付与できます。
改竄不可能データを永続保存することができる機能です。応用アイデア次第で様々な用途に使えます。
アポスティーユ 4は、メッセージ領域に__ファイルハッシュ値__を保存し、ブロックチェーンへタイムスタンプすることで実現していますね。
このメッセージには 1023byteまで という制限があります。
**nemtechからの引用文 (クリックで表示)**
パブリックネットワーク では、転送トランザクションは 1023 文字までの長さのメッセージを持つことができ、ブロックチェーンにデータを永続的にタイムスタンプするのに適しています。
In the public network, transfer transactions can hold a message up to 1023 characters in length, making them suitable for timestamping data permanently on the blockchain.
引用: https://nemtech.github.io/ja/concepts/transfer-transaction.html#message
アグリゲートトランザクションについて
Catapult新機能 アグリゲートトランザクション
最大1000トランザクションを1つにまとめることができます。
**nemtechからの引用文 (クリックで表示)**
Catapult パブリックネットワーク は 1,000 までのインナートランザクションを内包し、 25 の連署者を参加させたアグリゲートトランザクションをサポートしています。
Catapult’s public network supports aggregate transaction containing up to 1,000 inner transactions involving up to 25 different cosignatories.
引用: https://nemtech.github.io/ja/concepts/aggregate-transaction.html
nem Advent Calendar 2019にもアグリゲートトランザクションについての記事があります。
NEMの十八番、アグリゲートトランザクションについて
最大メッセージデータ量が1000倍に?!
- 1転送トランザクションに格納できるメッセージは1023byte
- 最大1000トランザクションを1つにまとめることができる
と、いうことは?!
Catapultでは
1023 * 1000 = 1023000 byte
のメッセージデータを1度にまとめて送信できる
ということになりますね!
1023000 byte
約0.975MB
このサイズまでの画像、PDF、音声データ等を1つのアグリゲートトランザクション内にまとめて格納可能とな!
やってみよう!
2018年のnemアドベントカレンダーで投稿された
NEMでファイル共有システムを作ってみたらこうなった
のCatapult アグリゲートトランザクション利用版イメージです。
アプリ画面は作ってないです。コマンド叩きのみです。すいません
処理の流れ
1.データ送信
imageToAggregateTransaction.js
- ファイルをBase64エンコードする
- 1023byte毎に分割して、インナートランザクションメッセージに格納する(宛先アドレスは全て同一)
- アグリゲートコンプリートトランザクションとして送信する
2.データ受信
- トランザクションハッシュ値指定で、アグリゲートトランザクション内容を受け取る
- インナートランザクション内のメッセージを全て結合する
- Base64デコードしてファイルに保存
Base64はおっきくなる
Base64エンコードすると約3割強データが太ります
(データ量が4/3になる)
Base64エンコードした結果が 1023000 byteまで。
Base64エンコードする前の元データとしては
767250 byte
約0.731MB 5
1アグリゲートトランザクションで送信できる、実ファイルサイズ上限になります。
メッセージ暗号化について
メッセージを暗号化することもできますが、格納できるサイズが小さくなります。
今回のサンプルでは行いません。
開発環境
クライアント
macOS 10.15.2
Node js v12.14.0
npm 6.13.4
使用ライブラリ
nem2-sdk@0.15.1
image-to-base64@2.0.1
file-type@12.4.2
Catapult ノード環境
Catapultパブリックチェーンがローンチ前です。mijin Catapultプライベートブロックチェーンを構築します。
Catapult Fushicho2
NetworkType.MIJIN
http://lb-7qvhzx74i6vzy.japaneast.cloudapp.azure.com:3000
node | 台数 | spec | vcpu | メモリ | SSD |
---|---|---|---|---|---|
api | 1 | Standard F2s_v2 | 2 | 4 GiB | 32 GiB |
peer | 3 | Standard F2s_v2 | 2 | 4 GiB | 32 GiB |
NEMアドカレ用 mijin Catapult Fushicho2を立ててみました。2019年内は公開のままにする予定です。
簡単にCatapultプライベート・コンソーシアムブロックチェーンを構築できるプラットフォームのプレビュー版、ちょっとだけちらみせな感じで
Azure上に4台の仮想マシン、2つのロードバランサーが立ち上がっています。
マシンスペックは低めにしていますが、今回の要件はトランザクション速度を必要としないので問題なし。
このあたりの構築について、ワンチーム から別記事がでるかも?!(ム茶ぶり)
Tx手数料の設定 minFeeMultiplier=0
で送金手数料無料チェーンとしています。
- catapult-service-bootstrapの場合
ruby/catapult-templates/api_node/resources/config-node.properties.mt
ruby/catapult-templates/peer-node/resources/config-node.properties.mt
# 23 行目
- minFeeMultiplier = 100
+ minFeeMultiplier = 0
前準備
クリスマスカード作り
今回のアドカレで一番時間を食ったのが、このクリスマスカード作り。
私はデザイン能力ゼロと言うかマイナスのため、普段は懇意にしているデザイナーさんに頼むんですが。
今回は自分で頑張りました。(頼めばヨカッタよ。。失敗した)
は梅田のグランフロントで撮りました。
インナートランザクション数がきっちり1000
になるように画像byte数もちょいちょい調整しました。
もっとNEMっぽくしたかったんですがね。。。
CatapultChristmas2019.jpg
(766788 byte)
不死鳥イラストはイラストACを使っております。[Oyu](https://
www.ac-illust.com/main/profile.php?id=rcfTi1QV&area=1)さんによる[イラストAC](https://www.ac-illust.com/)からのイラストです。
git clone
githubにサンプルを置いておきます。cloneしてください。
$ git clone https://github.com/falcon-man-stone-river/qiita-nem-advent-calendar-samples.git
$ cd qiita-nem-advent-calendar-samples
$ tree -L 1
.
├── CatapultChristmas2019.jpg # ChristmasCardSample file
├── README.md
├── imageFromTxHash.js # Sample2
├── imageToAggregateTransaction.js # Sample1
├── package-lock.json
└── package.json
ライブラリのインストール
$ npm install
ジェネレーションハッシュ値確認
curl -s http://lb-7qvhzx74i6vzy.japaneast.cloudapp.azure.com:3000/block/1 | jq -r '.meta.generationHash'
$ curl -s http://lb-7qvhzx74i6vzy.japaneast.cloudapp.azure.com:3000/block/1 | jq -r '.meta.generationHash'
13C3F1DEFCE3ECFC9018E8A75261068C55F0315528B778D83320BFD7660497AA
環境変数設定
今回のサンプルは環境変数に必要データを入れて、process.envで処理します。
NODE_URL
GENERATION_HASH
IMAGE_FILENAME
3つの環境変数をセットしてください。
$ export NODE_URL=http://lb-7qvhzx74i6vzy.japaneast.cloudapp.azure.com:3000
$ export GENERATION_HASH=13C3F1DEFCE3ECFC9018E8A75261068C55F0315528B778D83320BFD7660497AA
$ export IMAGE_FILENAME=CatapultChristmas2019.jpg
環境変数 IMAGE_FILENAME
に サンプルクリスマスカード画像 CatapultChristmas2019.jpg
を入れています。
他のファイルをアップしてみたい場合は、IMAGE_FILENAME
を変更してみてください。
ご自身で建てられたCatapultノードに切り替える場合は
環境変数 NODE_URL
GENERATION_HASH
をそれぞれ変更してください。
Sample1
画像データをBase64配列化し アグリゲートトランザクション送信
imageToAggregateTransaction.js (クリックで表示)
const { NODE_URL, GENERATION_HASH, IMAGE_FILENAME } = process.env;
const { AggregateTransaction, Account, TransactionHttp, TransferTransaction, Deadline, PlainMessage, NetworkCurrencyMosaic, NetworkType } = require('nem2-sdk');
const image2base64 = require('image-to-base64');
// アカウント新規作成
const account = Account.generateNewAccount(NetworkType.MIJIN);
// Base64配列作成
const splitBase64List = async (data, splitSize) => {
const dataSpread = [...data];
return new Promise((resolve, reject) => {
resolve(dataSpread.reduce(
(acc, c, i) => i % splitSize ? acc : [...acc, dataSpread.slice(i, i + splitSize).join('')], []
));
});
};
// トランザクション作成
const createTransction = (address, message) => {
return TransferTransaction.create(
Deadline.create(),
address,
[NetworkCurrencyMosaic.createRelative(0)], // 0
PlainMessage.create(message), // メッセージ
NetworkType.MIJIN
);
};
(async() => {
try {
const base64Str = await image2base64(IMAGE_FILENAME);
console.log('image to base64:', IMAGE_FILENAME, base64Str.length);
// 最大byte数 1023000を超える場合、エラーで終了
if (base64Str.length > 1023000) {
throw new Error('file size over');
}
// Base64文字列を1023byte分割
const base64List = await splitBase64List(base64Str, 1023);
console.log('base64List size:', base64List.length);
// Base64配列数分、インナートランザクション作成
const innerTransactions = base64List.map((r) => {
return createTransction(account.address, r).toAggregate(account.publicAccount);
});
// アグリゲートコンプリート トランザクション作成
const aggregateTransaction = AggregateTransaction.createComplete(
Deadline.create(),
innerTransactions, // Base64分割メッセージ格納 インナートランザクション
NetworkType.MIJIN,
[]
);
// アグリゲートトランザクション署名
const signedTransaction = account.sign(aggregateTransaction, GENERATION_HASH);
console.log('- signedTransaction hash -');
console.log(signedTransaction.hash);
const transactionHttp = new TransactionHttp(NODE_URL);
console.log('- sendTransaction -');
// トランザクション送信
transactionHttp
.announce(signedTransaction)
.subscribe(
(x) => console.log(x.message),
(err) => console.error(err)
);
} catch (e) {
console.log('ERROR!', e);
if (NODE_URL === void 0 || GENERATION_HASH === void 0 || IMAGE_FILENAME === void 0) {
console.log('Please set the environment variable NODE_URL or GENERATION_HASH or IMAGE_FILENAME');
}
}
})();
参考:【JavaScript】文字列を任意の文字数で分割し、配列を作成する方法
Sample1の実行
3つの環境変数をセットしてから実行します。
実行 $ node imageToAggregateTransaction.js
$ node imageToAggregateTransaction.js
image to base64: CatapultChristmas2019.jpg 1022384
base64List size: 1000 # インナートランザクション数
- signedTransaction hash -
A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594
- sendTransaction -
packet 9 was pushed to the network via /transaction
-
元画像のバイト数
766788 byte
-
Base64エンコード後のバイト数
1022384 byte
-
インナートランザクション数(1023byte毎に分解)
1000
-
トランザクションハッシュ値
A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594
注)ここで得られるトランザクションハッシュ値は、次のSample2で使用します。
トランザクションのステータスは様々な方法で取得できます。
今回は簡単なREST API(/transaction/{トランザクションハッシュ値}/status)を叩いてみます。 6
http://lb-7qvhzx74i6vzy.japaneast.cloudapp.azure.com:3000/transaction/A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594/status
$ curl http://lb-7qvhzx74i6vzy.japaneast.cloudapp.azure.com:3000/transaction/A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594/status | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 155 100 155 0 0 729 0 --:--:-- --:--:-- --:--:-- 731
{
"group": "confirmed",
"code": "Success",
"hash": "A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594",
"deadline": "117701505382",
"height": "27542"
}
"group": "confirmed"
になっていればブロックチェーンに取り込まれております。
さて、ほんとにクリスマスカード画像データはブロックチェーンに取り込まれているのでしょうか?!
確認してみましょう。
REST API(/transaction/{トランザクションハッシュ値})を叩いてみます。 7
http://lb-7qvhzx74i6vzy.japaneast.cloudapp.azure.com:3000/transaction/A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594
$ curl http://lb-7qvhzx74i6vzy.japaneast.cloudapp.azure.com:3000/transaction/A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594 | jq
# ずらずらー
# 大量のJSONが流れます。
# (1023Byte毎に別れた1000個のBase64 hex dump messageを含んでます)
Sample2では、1000インナートランザクションメッセージを結合、Base64デコードして新規画像ファイル保存をします。
Sample2
トランザクションメッセージから画像データを取り出す
imageFromTxHash.js (クリックで表示)
const { NODE_URL, TX_HASH } = process.env;
const { TransactionHttp } = require('nem2-sdk');
const fs = require('fs').promises;
const fileType = require('file-type');
(async() => {
try {
console.log(NODE_URL);
console.log(TX_HASH);
// Transaction内容取得
console.log('- getTransaction -');
const resTx = await new TransactionHttp(NODE_URL).getTransaction(TX_HASH).toPromise();
console.log('txTimestamp: ', new Date(parseInt(resTx.transactionInfo.id.substring(0, 8), 16) * 1000));
console.log('isConfirmed: ', resTx.isConfirmed());
// Confirmedチェック
if (resTx.isConfirmed()) {
// トランザクションサイズ
console.log('Transaction size: ', resTx.size);
const resTxJSON = resTx.toJSON();
// インナートランザクション内のメッセージを取得
const txMessages = resTxJSON.transaction.transactions.map((res) => res.transaction.message.payload);
// decode
const decode = new Buffer.from(txMessages.join(), 'base64');
// file Type取得
const fileExtension = fileType(decode).ext;
// トランザクションハッシュ値+fileTypeで保存
const fileName = TX_HASH + '.' + fileExtension;
console.log('fileName:', fileName);
console.log('- writeFile -');
const res = await fs.writeFile(fileName, decode);
}
} catch (e) {
console.log('ERROR!', e);
if (NODE_URL === void 0 || TX_HASH === void 0) {
console.log('Please set the environment variable NODE_URL or TX_HASH');
}
}
})();
Sample2の実行
まず今回Sample1で送信した際に取得したトランザクションハッシュ値
A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594
を環境変数 TX_HASH
に指定して実行します。
$ export TX_HASH=A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594
$ node imageFromTxHash.js
または
$ TX_HASH=A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594 node imageFromTxHash.js
$ export TX_HASH=A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594
$ node imageFromTxHash.js
http://lb-7qvhzx74i6vzy.japaneast.cloudapp.azure.com:3000 #NODE_URL
A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594 #TX_HASH
- getTransaction -
txTimestamp: 2019-12-24T04:52:14.000Z #トランザクションのタイムスタンプ(UTC)
isConfirmed: true
Transaction size: 1119552 #トランザクションのサイズ
fileName: A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594.jpg #ファイル名
- writeFile -
- トランザクションのタイムスタンプ
-
2019-12-24T04:52:14.000Z
2019年クリスマスイブ!
-
保存する際のファイル名はTX_HASH+'.'+fileType(拡張子)
にしています。
- 今回のファイル名
A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594.jpg
保存されてるかな?
$ tree -s -L 1
.
├── [ 766788] A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594.jpg
├── [ 766788] CatapultChristmas2019.jpg
├── [ 2444] README.md
├── [ 1556] imageFromTxHash.js
├── [ 2742] imageToAggregateTransaction.js
├── [ 2592] node_modules
├── [ 21788] package-lock.json
└── [ 740] package.json
保存されています。byte数は766788
。全く一緒ですね。
トランザクションメッセージからデコード作成した画像を開いてみる
お好みの画像ビュワーで開いてみてください。
OK!いけました!
サンプル動作がうまくいかなかったらお気軽にコメントで質問してくださいね。
REST API -> 直接画像ファイル作る [追記]
Sample2の処理内容は、以下ワンライナーでも可能です。
REST API(/transaction/{トランザクションハッシュ値})
で得られるJSON文字列から、直接画像ファイルを生成する。
- curl
- jq
curl -s http://{ノードのURL}:3000/transaction/{トランザクションハッシュ値} | jq -r -c '.transaction.transactions[].transaction.message.payload' | awk '{printf "%s",$0}' | xxd -r -p | base64 -D > output.jpg
注)内容から拡張子判定はしていないため、出力ファイル名は "output.jpg" 固定にしてます。
macOS
$ curl -s http://lb-7qvhzx74i6vzy.japaneast.cloudapp.azure.com:3000/transaction/A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594 | jq -r -c '.transaction.transactions[].transaction.message.payload' | awk '{printf "%s",$0}' | xxd -r -p | base64 -D > output.jpg
Linux系(ubuntu)
base64 -d (オプションが小文字になる)
$ curl -s http://lb-7qvhzx74i6vzy.japaneast.cloudapp.azure.com:3000/transaction/A1E3C523C67FEA8F4D333C662CF8918FCC1BA91F147F9EF7FAE070CEE787E594 | jq -r -c '.transaction.transactions[].transaction.message.payload' | awk '{printf "%s",$0}' | xxd -r -p | base64 -d > output.jpg
ここまでのまとめ
- mijin Catapult Fushicho2 プライベートブロックチェーンを利用
- (Sample1) クリスマスカード画像データそのものをアグリゲートトランザクション送信
- (Sample2) トランザクションハッシュ値指定で画像データを取得し保存
備考:手数料について
今回はCatapultプライベートチェーン、かつ送金手数料を0にてサンプル実装しました。
Catapultは2020年春にパブリックローンチが予定されています。
気になるのはパブリックチェーン上で同じことした場合、手数料はどのくらいになるのか?
手数料計算
先ほどのクリスマスカード アグリゲートトランザクションサイズは
Transaction size: 1119552
minFeeMultiplier 100
基軸通貨 nem:xem
可分性6
とした場合
1119552 * 100=111955200
111.9552xem
2019・12・24時点のxemの価格 3.5円としますと
392円ぐらいになります。(あくまで暫定の計算です)
参考: NEM1 と NEM2 で変わる仕様まとめ / fushicho-2のTIPS
パブリックチェーンへデータ送信する際は、基軸通貨での送金手数料がかかります。
逆にデータ取得する場合は、送金手数料はかかりません。
今回の処理をパブリックチェーン上で行うかどうか?は、アプリやサービス要件次第になりますね。
注)プライベート・コンソーシアムチェーンはカスタマイズによって送金手数料を0にすることが可能です。8
- パブリックチェーンにはファイルハッシュ値だけを記録
- プライベート・コンソーシアムチェーンにはファイルデータそのものを記録
- アンカリングする
パブリックチェーン<->プライベート・コンソーシアムチェーン
ハイブリッド型で構築することも可能ですね。
nemgraphでRiNG公証
ということでハイブリッドっぽく
今回のクリスマスカード画像ハッシュをパブリックブロックチェーン NEM にあげてみよう!
https://nemgraph.net/
を使います。 9
NEM(NIS1)パブリックブロックチェーンに nemgraph RiNG公証をしてみます。10
パブリックブロックチェーンNEM上に
登録者アドレス、登録日時、画像ハッシュ、Txハッシュ
が書き込まれました!
懸念点
定番クリスマスソング「ジングルベル」「きよしこの夜」のmp3 を書き込むことも考えたのですが、
著作権フリー楽曲とはいえ、音源を使う場合はリンク先を明記する必要があるなどなど。断念
(自分で歌ったら?と言われましたが、、、いやいや。。。)
ブロックチェーンに書き込まれたトランザクションデータは改竄できない=消すこと自体ができません。
個人情報や著作権問題を考えると、パブリックチェーン上でファイルオブジェクトを閲覧可能にする事は、リスキーな一面があります。
NEMでファイル共有システムを作ってみたらこうなった
でもあげられていましたが、プライベート・コンソーシアム型ブロックチェーン mijin Catapult の利用でリスク対処することは可能です。
まとめ
世の中には不正改竄があふれています。悲しいですが性善説だけでは人間界はまわらない、まわせない
アポスティーユ 4を使えばファイルハッシュ値とタイムスタンプ、元データと突合、改竄されていないことを証明できます。
しかし。
"元データを破棄したので、もうどこにもありません???"
なんて、おかしな言葉も最近よく聞きますね
2019年12月25日は「消してはいけない元データを破棄(破壊)される憂き目」にあう世界。
我々は、ブロックチェーンが生まれて苦しみながらも成長する途上を見ながら生きています。
これから徐々に、"生まれたときから、ブロックチェーンが存在していた世代"が社会にやってきます。
「それ、そもそもブロックチェーンでやる必要あるのか??否」(今。国内回るとまだ多め)
↓
「それ、もしかしてブロックチェーンでやったらいいんじゃない?」(徐々にの感覚アリ)
↓
(ここからは想像と希望)
↓
「それ、なんでブロックチェーンで管理をしてないのヨ!?早よせえ!」(ブロックチェーンネイティブ世代台頭時)
元データをタイムスタンプとともにブロックチェーンへ記録する=改竄破棄不可能
こんな思いを込めた?サンプルの"発展系"が、未来選択の一つとして考えられるのではないでしょうか。
クリスマスカードがテーマ&クリスマスイブナイトなのにメチャ重いまとめをかいてしまった!
改竄不可能な「愛」でもいいんですよ?(無理やり)
"Love is the one thing we're capable of perceiving that transcends dimensions of time and space."
Dr. Amelia Brand (Interstellar)
2020年nemアドベントカレンダーでは
"愛"を、稼働しているCatapultパブリックチェーンへ、 Morse codeで送信してみたい。
(送金手数料めちゃくちゃ高くなってたらどうしよう、、、w)
愛の可視化か。方法を探そう
今回やりきれなかったこと
- アプリ画面作るまで至らず(デザインをいつもまかっせきりだからこうなる。。。)
- mijin Catapult Fushicho3での同処理を実施済み。記事修正間に合わず。
- Catapult新機能 メタデータ 11 を合わせて使う。
- 複数アグリゲートトランザクションに分割し、もっと大きいファイルを送れるようにする。
- インナートランザクション上限設定を変更してやってみる
- インナートランザクション最大数1000はパブリックチェーンの設定値です。
- 最大数上限をあげて、マシンスペック別プライベートチェーンテストをする。
- catapult-service-bootstrapの場合
ruby/catapult-templates/api_node/resources/config-network.properties.mt
ruby/catapult-templates/peer-node/resources/config-network.properties.mt
#44行目
[plugin:catapult.plugins.aggregate]
- maxTransactionsPerAggregate = 1'000
+ maxTransactionsPerAggregate = 数値を変更
ここまで読んでいただきありがとうございました!
nem Advent Calendar 2019 に参加できて光栄です。
メリークリスマス!素敵な2019年クリスマスをお過ごしください
May the Joy and Happiness spread like the lights of the Christmas tree and wings of the phoenix "Fushicho"!
-
仮面ライダー龍騎 (2002年) 契約モンスター召喚の際のデジタル音声「アドベント-召喚-」。同じく「コントラクト-契約-」があるとこがニヤリ。 ↩
-
不死鳥 "ゴルトフェニックス (GOLD PHOENIX)" 不死鳥型モンスター 劇中最強の設定。不死鳥に"GOLD"とついてるとこもニヤリ。 ↩
-
若手「hさん、(nemアドカレ)25日空いてますw」 私「Congrats on your engagement! 」 ↩
-
[3.5インチFDD 2DD形式] (https://ja.wikipedia.org/wiki/%E3%83%95%E3%83%AD%E3%83%83%E3%83%94%E3%83%BC%E3%83%87%E3%82%A3%E3%82%B9%E3%82%AF#3.5%E3%82%A4%E3%83%B3%E3%83%81%E3%83%95%E3%83%AD%E3%83%83%E3%83%94%E3%83%BC%E3%83%87%E3%82%A3%E3%82%B9%E3%82%AF%E5%90%84%E5%BD%A2%E5%BC%8F%E3%81%AE%E8%A9%B3%E7%B4%B0) 約1枚分。隔世の感を禁じ得ない? ↩
-
https://nemtech.github.io/nem2-openapi/#operation/getTransactionStatus ↩
-
https://nemtech.github.io/nem2-openapi/#operation/getTransaction ↩
-
プライベート・コンソーシアムチェーンノードの維持費用が必要です。 ↩
-
nemgraph 引用 "nemgraphは暗号通貨NEMコミュニティの声から誕生したサービスです。 本サービスは写真の投稿を通じてユーザー同士がつながる場所を提供する コミュニケーションツールです。" ↩
-
nemtech メタデータ 引用 "Catapult にはトランザクションとともに アカウント, モザイク, ネームスペース にメタデータを関連付ける手段が用意されています。" ↩