速習Symbolブロックチェーン7章、メタデータ編です。
今回は短そうですね。張り切ってやっていきます。
アカウント・モザイク・ネームスペースに対してKey-Value形式のデータを登録できる機能らしいです。
なるほど。わかるようなわからないような。なんかユースケースあるんだろうな。
実践編
7.1 アカウントに登録
aliceのアカウントに登録
アカウントに対してkey-value値を設定できるらしいです。
// aliceがaliceのメタデータを登録する。
// aliceのアカウントを作成する。
var alice = await sym.Account.createFromPrivateKey(
sym.PrivateKey(alicePrivateKey), sym.NetworkTypeEnum.testnet);
print("[送信元] alice address: ${alice.address}");
// メタデータキーを作成する。
var metadataKey = sym.MetadataKey("key-chan");
// 値を指定する。
var value = "value-chan";
var valueBytes = Uint8List.fromList(utf8.encode(value));
var tx = sym.AccountMetadataInfoV1.create(alice.publicAccount,
alice.address,
metadataKey,
sym.Int16(valueBytes.length),
valueBytes);
// Transaction設定を行う。
var transSetting = sym.TransactionSetting(
signer: alice,
generationHash: "49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4",
networkType: sym.NetworkTypeEnum.testnet,
deadline: sym.Deadline.create(epochAdjustment),
fee:sym.FeeMultiplier(100) ); // 手数料は100%。
// トランザクションの通知。アグリゲートである必要があるらしい。
var transactionSender = TransactionSender();
await transactionSender.sendAggregateCompolete(transSetting, [tx]);
こんな感じで。
登録先、登録者が同一でもアグリゲートである必要があるらしいです。
いまいち、理由はわからないのですが。。
で、実行結果は以下。ウォレットでの確認で。。。

実行したときは何日も前で、ログを取り忘れていて、既に登録されたあとでした。
aliceがbobのアカウントに登録
自分自身のアカウントではなく、aliceがbobのアカウントにメタデータを登録するようなことも可能なようです。
モザイクを利用せずとも、メタデータを利用することで「会員の有効期限をメタデータに刻む」みたいなことができるのかな。
ただし、aliceがbobのアカウントにメタデータを刻む場合、bobの署名も必要(つまり、bobの承認が必要)であるため、好き勝手に追加するわけにはいかない、ということの様子。
ここではaliceがbobのアドレスに向けて、”kyuuri”というキーで”cucumber”という値を刻んでいこうと思います。
// aliceのアカウントを作成する。
var alice = await sym.Account.createFromPrivateKey(
sym.PrivateKey(alicePrivateKey), sym.NetworkTypeEnum.testnet);
// bobのアカウントを作成する。
var bob = await sym.Account.createFromPrivateKey(
sym.PrivateKey(bobPrivateKey), sym.NetworkTypeEnum.testnet);
print("[送信元] alice address: ${alice.address}");
print("[設定先] bob address: ${bob.address}");
// メタデータキーを作成する。
var metadataKey = sym.MetadataKey("kyuuri");
// 値を指定する。
var value = "cucumber";
var valueBytes = Uint8List.fromList(utf8.encode(value));
var tx = sym.AccountMetadataInfoV1.create(alice.publicAccount,
bob.address,
metadataKey,
sym.Int16(valueBytes.length),
valueBytes);
// Transaction設定を行う。
var transSetting = sym.TransactionSetting(
signer: alice,
generationHash: "49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4",
networkType: sym.NetworkTypeEnum.testnet,
deadline: sym.Deadline.create(epochAdjustment),
fee:sym.FeeMultiplier(100),
cosignatoriesQ: 1); // 手数料は100%。連署者数1。
// トランザクションの通知。アグリゲートである必要があるらしい。
var transactionSender = TransactionSender();
await transactionSender.sendAggregateComplete(transSetting, [tx], [bob]);
トランザクション設定として連署者数を1とか設定しています。
(フィーリングで適当に、必要になったら追加しよう的なスタンスでやっているため、このときまで作ってませんでした)
実行結果は以下。とりあえず承認されたようです。

7.2 モザイクに登録
同様にモザイク相手にも、メタデータを設定できるようです。
以前の章でaliceが作ったモザイクに対し、キーを”daigouji”、値を”gai”で登録していこうと思います。
// aliceのアカウントを作成する。
var alice = await sym.Account.createFromPrivateKey(
sym.PrivateKey(alicePrivateKey), sym.NetworkTypeEnum.testnet);
// 以前作ったモザイクID。
var mosaicId = sym.MosaicId("50E29F813AA1B901");
print("[送信元] alice address: ${alice.address}");
// メタデータキーを作成する。
var metadataKey = sym.MetadataKey("daigouji");
// 値を指定する。
var value = "gai";
var valueBytes = Uint8List.fromList(utf8.encode(value));
var tx = sym.MosaicMetadataInfoV1.create(alice.publicAccount,
alice.address,
mosaicId,
sym.Int16(valueBytes.length),
metadataKey,
valueBytes);
// Transaction設定を行う。
var transSetting = sym.TransactionSetting(
signer: alice,
generationHash: "49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4",
networkType: sym.NetworkTypeEnum.testnet,
deadline: sym.Deadline.create(epochAdjustment),
fee:sym.FeeMultiplier(100)
); // 手数料は100%。
// トランザクションの通知。アグリゲートである必要があるらしい。
var transactionSender = TransactionSender();
await transactionSender.sendAggregateComplete(transSetting, [tx], []);
実行結果。結果確認は後ほど。

7.3 ネームスペースに登録
同様にネームスペースに登録します。
以前作成したネームスペース”murakamiharuki”に、キーを”murasaki”、値を”shikibu”として追加します。
// aliceのアカウントを作成する。
var alice = await sym.Account.createFromPrivateKey(
sym.PrivateKey(alicePrivateKey), sym.NetworkTypeEnum.testnet);
// 以前作ったネームスペースID。
var namespaceId = sym.NamespaceId("murakamiharuki");
print("[送信元] alice address: ${alice.address}");
// メタデータキーを作成する。
var metadataKey = sym.MetadataKey("murasaki");
// 値を指定する。
var value = "shikibu";
var valueBytes = Uint8List.fromList(utf8.encode(value));
var tx = sym.NamespaceMetadataInfoV1.create(alice.publicAccount,
alice.address,
namespaceId,
sym.Int16(valueBytes.length),
metadataKey,
valueBytes);
// Transaction設定を行う。
var transSetting = sym.TransactionSetting(
signer: alice,
generationHash: "49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4",
networkType: sym.NetworkTypeEnum.testnet,
deadline: sym.Deadline.create(epochAdjustment),
fee:sym.FeeMultiplier(100)
); // 手数料は100%。
// トランザクションの通知。アグリゲートである必要があるらしい。
var transactionSender = TransactionSender();
await transactionSender.sendAggregateComplete(transSetting, [tx], []);
実行結果は以下。

とりあえずすべて、承認されたようでした。
7.4 確認
登録したメタデータを確認するようです。
restapiに条件を投げ入れて、内容を確認します。
aliceにづいたメタデータをすべて取得し、メタデータのキー、バリュー、取得した1レコードの全体を出力しています。
// aliceのアカウントを作成する。
var alice = await sym.Account.createFromPrivateKey(
sym.PrivateKey(alicePrivateKey), sym.NetworkTypeEnum.testnet);
print("[送信元] alice address: ${alice.address}");
var networkHostInfo = await TransactionSender.getNetworkHost();
var metadataHttp = sym.MetadataRoutesHttp(networkHostInfo.networkHost);
var criteria = sym.SearchMetadataCriteria();
criteria.targetAddress = alice.address;
criteria.sourceAddress = alice.address;
var result = await metadataHttp.search(criteria);
for (var element in result.data){
var metadata = element.metadataEntry;
print("メタデータキー: ${metadata.scopedMetadataKey.value}");
print("メタデータバリュー: ${utf8.decode(hex.decode(metadata.value.value))}");
print("データ全体");
print(metadata.baseMap);
}

上からメタデータバリューが
- value-chan
- gai
- shikibu
となっていることが確認できます。
速習Symbolによると、metadataTypeの値により、なんのメタデータかを判別することができるようです。
sym.MetadataType
{0: 'Account', 1: 'Mosaic', 2: 'Namespace'}
“value-chan”はmetadataTypeが0となっているため、アカウントに紐づいていることが確認できます。
同様に”gai”はモザイク、”shikibu”はNamespaceということが確認できます。以上です。おつかれさまでした。
感想編
メタデータはキーバリュー型で値を登録することができるため、汎用性が高そうですね。いくつまで登録できるのだろう?
現場で使えるヒントで有資格証明の話がありました。
“実社会で信頼性の高いドメインからリンクされたアカウントが発行したメタデータの付与を受けることで、そのドメイン内での有資格情報の所有を証明できる”
例えばアドレスNAAAAからNBBBBにキー”友人証明”というメタデータを与えて、NBBBBが承認した場合、
NAAAAがNBBBBに対して友人証明というメタデータを与えただけという事象になる。
それを仮に、NAAAAにはkishidaというネームスペースが付与してあり、実際にkishidaというネームスペースでいろいろな活動(評価)を受けていたとして。
同様に、NBBBBにはtakashiというネームスペースが付与してあり、実際にいろいろな活動(評価)を受けていたとした場合。
kishidaがtakashiに友人証明というメタデータを登録することで、kishidaはtakashiと友人である、ということになる。
わかりづらいな。。。
これが仮にkishidaを英検の認定試験者、友人証明を英検合格証明、値として級とした場合、
英検の認定試験者(ネームスペース・アドレス)が、英検の合格者(ネームスペースorアドレス)に、英検合格証明(メタデータキー)として1級(メタデータの値として1)を登録した。
とすることで、価値がでるよね、って話でしょうかね。
DIDはちょっと、すぐにはわかりませんでした。なんか他でもそんな話があったので、後日理解に勤めます。。。
メタデータはアグリゲートトランザクションで実行する必要がある、というのは原則として、他アドレスに付与するのがメインの用途、という感じなんでしょうか?
処理上の問題であったらわからないですが。
また、メタデータキーとしてはハッシュで取得するようなので、元々の文字列は不可逆ということでしょうか。
別に戻せる必要はない、と言われたらそうかもしれないですが。。。
あまり考えずに行き当たりばったりでやっているため、まだ作っていないところがボロボロ出てきて時間がかかりました。
本当は速習Symbolを夏までに終わらせたいと思っていたのですが、なかなかうまくはいかないものですね。年内に終わればいいですけれど。
お疲れさまでした。