6. ネームスペース

速習Symbolブロックチェーン6章、ネームスペース編です。

URLとしてはこちら

テストネットの紹介はやめます。
(全然終わりそうもないので、進めるのを優先します)

それではやっていきます。

実践編

ネームスペースをレンタルし、アドレスやモザイクに名前を付けることができるということみたいです。

Symbolブロックチェーンではネームスペースをレンタルしてアドレスやモザイクに視認性の高い単語をリンクさせることができます。 ネームスペースは最大64文字、利用可能な文字は a, b, c, …, z, 0, 1, 2, …, 9, _ , – です。

Symbolerなら見たことあるかもしれません。

小文字しかできないのかな?

6.1 手数料の計算

ネームスペースのレンタルには手数料が必要なようです。ブロックチェーンに刻む=手数料が必要、そんな感じですね。参照は無料です。

こんな感じのコードを記述しました。

  /// レンタルフィーを取得する。
  /// [rentalDays]にレンタルする日数を指定する。(30日以上とする必要がある)
  /// ※ここでは、rentalDaysは365を指定した。
  Future<void> getRentalFees(int rentalDays) async {

    // 有効なネットワークホストを取得する。
    var availableHost = await _getNetworkHost();

    // レンタルフィーはNetworkRoutesから取得する様子。
    var networkRoute = NetworkRoutesHttp(availableHost.networkHost);

    // レンタルフィーはRootNamespace、SubNamespace、Mosaicで違うようだ。
    var rentalFees = (await networkRoute.getRentalFeesInformation());

    // レンタル日数を秒に戻し、30(Symbolのブロック生成速度は30sec)で割り、ブロック数を割り出す。
    var rentalBlock = rentalDays * 24 * 60 * 60 / 30;

    var rootRentalFee = rentalFees.effectiveRootNamespaceRentalFeePerBlock.value * rentalBlock;
    var childRentalFee = rentalFees.effectiveChildNamespaceRentalFee;

    print("rentalBlock: ${rentalBlock}");
    print("rootRentalFee: ${rootRentalFee}");
    print("childRentalFee: ${childRentalFee.value}");

  }

実行結果は以下。

ネームスペースレンタルフィー手数料は210240000と算出されます。

Symbolノードを利用しているため、手数料に使用するXYMは可分性が6であることから、1/1000000します。つまり、210.24XYMが手数料になります。速習Symbol通り。

また、ネームスペースは日付を指定した親(Root)ネームスペースと、紐づいた子(Child)ネームスペースが用意できるようです。

期間が指定できるのは親のようなので、親が生きている限り子も生きているということでいいのかな、と。

で、親がいる限りは子の追加は子(childRentalFee)のみで実行できるということでしょうか。10XYMかな?

6.2 レンタル

ルートネームスペース/サブネームスペースをレンタルするようです。

ルートネームスペースの子どもとして、サブネームスペース、サブのサブネームスペースぐらいの階層までは取得できるようです。

なお、ルート/サブのネームスペース取得には手数料がかかることがわかります。

また、ネームスペースの有効期限はルートネームスペースに依存しているとのことで、サブよりルートのネームスペースのレンタル料は高くなっています。

有効期限の更新についても、ルートネームスペースの期限さえ気にしていればよさそうですね。

さて、

  • murakamiharuki(ルート)
  • sekai-no-owari(サブ)
  • wonder-land(サブサブ)

という形で取得してみたいと思います。
murakamiharuki.sekai-no-owari.wonder-landという完成形ですね。

また、レンタルする期間は1051200ブロックを考えています。

以下、ソースコード。

// aliceのアカウントを作成する。
var alice = await sym.Account.createFromPrivateKey(
  sym.PrivateKey(alicePrivateKey), sym.NetworkTypeEnum.testnet);

print("[送信元] alice address: ${alice.address}");

// 大体、一年間分の期間。
var rentalDuration = sym.BlockDuration(1051200);

// ルートネームスペース。
var rootNamespaceId = sym.NamespaceId("murakamiharuki");

// サブネームスペース。
var subNamespaceId = sym.NamespaceId("murakamiharuki.sekai-no-owari");

// サブサブネームスペース。
var subsubNamespaceId = sym.NamespaceId('murakamiharuki.sekai-no-owari.wonder-land');

// トランザクション。
var transactions = [
  // ルートネームスペース登録トランザクション。
  sym.NamespaceRegistrationInfoV1.createRoot(alice.publicAccount, rentalDuration, rootNamespaceId, rootNamespaceId.fullName!),
  // サブネームスペース登録トランザクション。
  sym.NamespaceRegistrationInfoV1.createSub(alice.publicAccount, rootNamespaceId, subNamespaceId, subNamespaceId.name!),
  // サブサブネームスペース登録トランザクション。
  sym.NamespaceRegistrationInfoV1.createSub(alice.publicAccount, subNamespaceId, subsubNamespaceId, subsubNamespaceId.name!)
];

// Transaction設定を行う。
var transSetting = sym.TransactionSetting(
  signer: alice, 
  generationHash: "49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4", 
  networkType: sym.NetworkTypeEnum.testnet, 
  deadline: sym.Deadline.create(1667250467),
  fee: sym.FeeMultiplier(100) );     // 手数料は100%。          


// トランザクションの通知。
var transactionSender = TransactionSender();

for (var element in transactions) {
  await transactionSender.sendTransaction(transSetting, element);
}

作りの問題で、alice.publicAccountが複数でてきていますね。
これは不要なので、そのうち直したいですが。。。

では実行してみます。

ルートネームスペース取得までの結果は以下。

サブネームスペースは以下。

サブサブネームスペースは以下。

一応ウォレットで確認すると、作成されていることが確認できます。

。。。たぶんこれでいいんだよね? というところ。

有効期限の計算

先ほどの通り、有効期限はルートネームスペースに依存している、ということのようです。

ブロックチェーンのタクトとしては「時間」ではなく「ブロック高」ということなので、

  1. ネームスペース情報を取得し、有効期限のブロック数を取得する。
  2. 現在の最後のブロック数を取得する。
  3. ブロックに関する情報を取得することで、ブロックが生成された時刻を取得する。
  4. (ブロックが生成された時刻 + 現在から有効期限終了までのブロック数スパンを時間化)とすることで、予定時刻が出せるようです。

なお、ネームスペースをレンタルするトランザクション発行から、この有効期限の計算を行うまでいくらか時間経過しています。うーむ。

var networkHostInfo = await TransactionSender.getNetworkHost();

var namespaceHttp = sym.NamespaceRoutesHttp(networkHostInfo.networkHost);
var chainHttp = sym.ChainRoutesHttp(networkHostInfo.networkHost);
var blockHttp = sym.BlockRoutesHttp(networkHostInfo.networkHost);

var namespaceId = sym.NamespaceId("murakamiharuki");

// ネームスペース情報を取得する。
var nsInfo = await namespaceHttp.getInformation(namespaceId);

var lastHeight = (await chainHttp.getCurrentInformation()).height;

var lastBlock = await blockHttp.getInformation(lastHeight);

var remainHeight = nsInfo.namespace.endHeight - lastHeight;

print("namespace endHeight: ${lastHeight.value}");
print("lastBlock: ${lastBlock.block.height.value}");

print("remainHeight: ${remainHeight.value}");

var timestamp = lastBlock.block.timestamp.value + (remainHeight.value * 30000 + epochAdjustment * 1000);

var endDate = DateTime.fromMillisecondsSinceEpoch(timestamp.toInt(), isUtc: false);

print("endDate: $endDate");

取得した結果がこちら。

まぁこんなもんでしょうか。

念のため本日(20230701)のウォレットからの確認結果です。

まぁ、大体あってると思います。

6.3 リンク

ネームスペースは取得しただけでは活用法がない? ため、特に意味はないかも?

ネームスペースはアドレスやモザイクと紐づくことで、それに命名できる感じなようです。便利ですね。

アカウントへのリンク

アカウントへというか、アカウントのアドレスみたいですね。

// aliceのアカウントを作成する。
var alice = await sym.Account.createFromPrivateKey(
  sym.PrivateKey(alicePrivateKey), sym.NetworkTypeEnum.testnet);

print("[送信元] alice address: ${alice.address}");

// ネームスペース。
var namespaceId = sym.NamespaceId("murakamiharuki");

// アドレスエイリアストランザクション。
var tx = sym.AddressAliasInfoV1.create(alice.publicAccount, namespaceId, alice.address, sym.AliasActionEnum.link);

// 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.sendTransaction(transSetting, tx);

ウォレットで確認したところ、下記のようでした。

エイリアスタイプがaddressでエイリアスにアドレスが登録されていることが確認できました。

モザイクへリンク

そのまま続けてモザイクへリンクを行います。

// aliceのアカウントを作成する。
var alice = await sym.Account.createFromPrivateKey(
  sym.PrivateKey(alicePrivateKey), sym.NetworkTypeEnum.testnet);

print("[送信元] alice address: ${alice.address}");

// モザイクid。以前の章で作成済み。
var mosaicId = sym.MosaicId("50E29F813AA1B901");

// ネームスペース。世界の終わり。
var namespaceId = sym.NamespaceId("murakamiharuki.sekai-no-owari");

// アドレスエイリアストランザクション。
var tx = sym.MosaicAliasInfoV1.create(alice.publicAccount, namespaceId, mosaicId, sym.AliasActionEnum.link);

// 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.sendTransaction(transSetting, tx);

実行結果は以下。

とりあえずトランザクションが承認されている様子。

ウォレットで確認したところ、以下となっていました。

エイリアスタイプがmosaicで、エイリアスにモザイクIDが設定されています。

ウォレットのモザイクページで確認したところ、モザイクにも名前が紐づいていることが確認できます。

6.4 未解決で使用

アカウント(アドレス)、モザイクIDにネームスペースをリンクすることで、わかりやすく名前を紐づけることができるようになりました。

この未解決で使用の項では、ネームスペース→アドレスやネームスペース→モザイクIDと変換しなくても、ネームスペース=アドレス、ネームスペース=モザイクIDとして直接送信できるようですね。

ここいらでunresolved addressって名前が出てきたりするのですが、unresolved addressは未解決って意味らしいです。へー。

以下はコード。

print("bobがaliceに送信する");

var bob = await sym.Account.createFromPrivateKey(
  sym.PrivateKey(bobPrivateKey), sym.NetworkTypeEnum.testnet
);

print("[送信元] bob address: ${bob.address}");

// 未解決アドレス(alice)
var unresolvedAddress = sym.NamespaceId("murakamiharuki").getUnresolvedAddress(sym.NetworkTypeEnum.testnet);

// 未解決モザイク(murakamiharuki.sekai-no-owari)
var unresolvedMosaicId = sym.NamespaceId("murakamiharuki.sekai-no-owari").getUnresolvedMosaicId();

// 転送モザイク。
var transMosaic = sym.Mosaic(amount: sym.Amount(100), id: unresolvedMosaicId);

// Transaction設定を行う。
var transSetting = sym.TransactionSetting(
  signer: bob, 
  generationHash: "49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4", 
  networkType: sym.NetworkTypeEnum.testnet, 
  deadline: sym.Deadline.create(epochAdjustment),
  fee: sym.FeeMultiplier(100) );     // 手数料は100%。    

// 送り先に未解決アドレス、未解決モザイクを設定する。
var tx = sym.TransferInfoV1.create(bob.publicAccount, unresolvedAddress, [transMosaic] );

// トランザクションの通知。
var transactionSender = TransactionSender();

// トランザクション送信。
await transactionSender.sendTransaction(transSetting, tx);

速習Symbolでは未解決アドレス、未解決モザイクでやっていましたが、横着して一度にやることにしました。

送信するモザイクはsekai-no-owariに紐づいたモザイクIDです。

今回はbob → alice(未解決アドレス)と送信するため、あらかじめaliceからbobへ、sekai-no-owariをウォレットにて送信しておきました。

いざ実行です。

とりあえず承認されました。

ウォレットで確認します。

murakamiharukiあてに送られているのは確認できました。

sekai-no-owariモザイクはなんか表示がバグってますね(ウォレットが古い?)

数はしっかり減っていたため、explorerで見ると転送されていることが確認できました。

6.5 参照

ネームスペースのリンク情報を参照する方法についてです。

以下の感じです。

var namespaceId = sym.NamespaceId("murakamiharuki");
var namespaceId2 = sym.NamespaceId("murakamiharuki.sekai-no-owari");

var networkHostInfo = await TransactionSender.getNetworkHost();
var namespaceHttp = sym.NamespaceRoutesHttp(networkHostInfo.networkHost);

// ネームスペース情報を取得する。
var nsInfo = await namespaceHttp.getInformation(namespaceId);
var nsInfo2 = await namespaceHttp.getInformation(namespaceId2);

print("murakamiharuki info");
print(nsInfo.baseMap);

print("murakamiharuki.sekai-no-owari info");
print(nsInfo2.baseMap);

結果は以下。

aliasのtypeが2でアドレスエイリアス、addressに紐づいている対象アドレスでしょうか。

aliasのtypeが1でmosaicIdって形のようですね。

ネームスペース → 紐づき状態を確認できるって感じですね。

また、速習SymbolによるとregistrationTypeで親か子かもわかるようです。

逆引き

ネームスペース → アドレスと取得できるのであれば、逆にアドレス → ネームスペースと取得することができる、とのこと。

ネームスペースをアドレスに紐づける場合、「紐づき先のアドレスはネームスペース所有者以外でもよい」とのことなので、ネームスペース:アドレスは1:Nの関係であるらしいですね。

ここまで使用しているaliceのアドレスと、今回ネームスペースとリンクしたモザイクに付与されているネームスペースを取得します。

// 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 networkHostInfo = await TransactionSender.getNetworkHost();
var namespaceHttp = sym.NamespaceRoutesHttp(networkHostInfo.networkHost);

// アカウント名を取得。
var accountNames = await namespaceHttp.getReadableNamesFromAddresses([alice.address]);

// モザイク名を取得。
var mosaicNames = await namespaceHttp.getReadableNamesFromMosaics([mosaicId]);

print("account names");
print(accountNames.baseMap);

print("mosaic names");
print(mosaicNames.baseMap);

結果としては以下。

accountNamesも、mosaicNamesも、内容が配列になっているため、複数の情報を一度に取ることができることが確認できます。

レシートの参照

トランザクションに使用されたネームスペースを、ブロックチェーンがどうやって解決したかを確認するらしいです。

ネームスペースAは今、浜田くんと紐づいている。

しかし期限が切れた後、ネームスペースAを松本くんがレンタルして自分に紐づけた場合、同じネームスペースAであっても紐づけ先が変わっている。

そのため、現在の状態で過去の情報を引っ張ってきても、送り先が変わっている可能性がある、ということかな。

電話番号みたいですね。

以下のコードは、ブロック高が597274に対して、アドレス解決とモザイクIDの解決内容を取得するようにしました。

// 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 networkHostInfo = await TransactionSender.getNetworkHost();
var receiptHttp = sym.ReceiptRoutesHttp(networkHostInfo.networkHost);

var criteria = sym.GetReceiptsAddressResolutionStatementsCriteria();

// ブロック高を597274を指定(bobがaliceにsekai-no-owariを送付したブロック)。
criteria.height = sym.Height(597274);

var receipt1 = await receiptHttp.getAddressResolutionStatements(criteria);
var receipt2 = await receiptHttp.getMosaicResolutionStatements(criteria);

print("receipt address");
print(receipt1.baseMap);
// わかりづらいのでエンコード済みアドレス化。
print(receipt1.data[0].statement.resolutionEntries[0].resolved.toAddress().value);

print("receipt mosaicId");
print(receipt2.baseMap);

結果は以下。アドレスも、モザイクIDも取得されていることがわかるため、これで当時の紐づき状態を知ることができるようです。

6.6 現場で使えるヒント

読みました。ドメインのような「個人を識別しやすくする」ということでしょうか。あとは譲渡について、というところ。

感想編

ざっくりといえば、

  • Symbolにはネームスペースという概念がある。
  • ネームスペースは3階層まで指定可能。(ネットワーク設定による?)
  • ネームスペースはレンタル制で、レンタル期間はルートネームスペースの期限で定めている。
  • ネームスペースにはアドレス、モザイクIDを紐づけることができる。
  • 紐づけることで、アドレスやモザイクIDに任意の名前を付けることができる。
  • ネームスペースについてはチェーン上で一意である。

という機能のようですね。

基本的にアドレス、モザイクID自体には「名前」といったものがないので、それを任意に付与する、というもののようです。

ネームスペースIDは文字列から生成され、かつ、一意であるため、使用する名前=IDのようです。

現場で使えるヒントからすると、ネームスペースのレンタルを途中でやめる、という選択肢はなさそう?
同様にネームスペースの譲渡ということもできない模様。

よって、譲渡する可能性のあるネームスペースであった場合、
マルチシグの子アカウントを作成し、子アカウントごとマルチシグで譲渡する。そういう風にするようです。

未解決状態でアドレス、モザイクIDとして扱えるのは面白いですが、レンタル期間の終了、または意図しないものとの紐づきに注意する必要もありそうですね。

ただ実際に使用する際にはレンタル期間が切れている可能性もありますし、タイポの可能性もある? とかって考えると、ひと手間かかりますが、リンク状態を確認してから使用するほうが安心な気もしますね。

以上です。また次回。