コンテンツにスキップ

ルートネームスペースの登録⚓︎

中級

ネームスペース は、アカウントモザイク に対して人間が読み取り可能なエイリアス(別名)を提供します。これにより、長いアドレスや16進数のモザイクIDの代わりに使用することができます。

このチュートリアルでは、ルートネームスペース を登録し、そのレンタル 有効期間 を設定する方法を説明します。

一度登録した後は、次のステップ で説明するように、ネームスペースをモザイクやアカウントにリンクするための追加ステップが必要です。

前提条件⚓︎

開始する前に、以下を確認してください。

さらに、トランザクションがどのようにアナウンスされ承認されるかを理解するために、転送トランザクション のチュートリアルを復習しておいてください。

完全なコード⚓︎

このチュートリアルの完全なコード一覧を以下に示します。 詳細な手順ごとの説明は次のセクションで行います。

import json
import os
import time
import urllib.request

from symbolchain.CryptoTypes import PrivateKey
from symbolchain.facade.SymbolFacade import SymbolFacade
from symbolchain.symbol.IdGenerator import generate_namespace_id
from symbolchain.symbol.Network import Address

NODE_URL = os.getenv('NODE_URL', 'https://reference.symboltest.net:3001')
print(f'Using node {NODE_URL}')


# Helper function to announce a transaction
def announce_transaction(payload, label):
    print(f'Announcing {label} to /transactions')
    request = urllib.request.Request(
        f'{NODE_URL}/transactions',
        data=payload.encode(),
        headers={'Content-Type': 'application/json'},
        method='PUT'
    )
    with urllib.request.urlopen(request) as announce_response:
        print(f'  Response: {announce_response.read().decode()}')


# Helper function to wait for transaction confirmation
def wait_for_confirmation(tx_hash, label):
    print(f'Waiting for {label} confirmation...')
    for attempt in range(60):
        time.sleep(1)
        try:
            url = f'{NODE_URL}/transactionStatus/{tx_hash}'
            with urllib.request.urlopen(url) as confirm_response:
                status = json.loads(confirm_response.read().decode())
                print(f'  Transaction status: {status["group"]}')
                if status['group'] == 'confirmed':
                    print(f'{label} confirmed in {attempt} seconds')
                    return
                if status['group'] == 'failed':
                    raise RuntimeError(
                        f'{label} failed: {status["code"]}')
        except urllib.error.HTTPError:
            print('  Transaction status: unknown')
    raise TimeoutError(f'{label} not confirmed after 60 seconds')


SIGNER_PRIVATE_KEY = os.getenv(
    'SIGNER_PRIVATE_KEY',
    '0000000000000000000000000000000000000000000000000000000000000000')
signer_key_pair = SymbolFacade.KeyPair(PrivateKey(SIGNER_PRIVATE_KEY))

facade = SymbolFacade('testnet')
signer_address = facade.network.public_key_to_address(
    signer_key_pair.public_key)
print(f'Signer address: {signer_address}')

try:
    # Fetch recommended fees
    fee_path = '/network/fees/transaction'
    print(f'Fetching recommended fees from {fee_path}')
    with urllib.request.urlopen(f'{NODE_URL}{fee_path}') as response:
        response_json = json.loads(response.read().decode())
        median_multiplier = response_json['medianFeeMultiplier']
        minimum_multiplier = response_json['minFeeMultiplier']
        fee_multiplier = max(median_multiplier, minimum_multiplier)
        print(f'  Fee multiplier: {fee_multiplier}')

    # Build the namespace name
    namespace_name = os.getenv(
        'ROOT_NAMESPACE', f'ns_{int(time.time())}')
    print(f'Creating root namespace: {namespace_name}')

    # Build the transaction
    transaction = facade.create_transaction_from_descriptor(
        {
            'type': 'namespace_registration_transaction_v1',
            'registration_type': 'root',
            'duration': 86400,  # approximately 30 days
            'name': namespace_name
        },
        signer_key_pair.public_key,
        fee_multiplier,
        2 * 60 * 60)

    # Sign transaction and generate final payload
    signature = facade.sign_transaction(signer_key_pair, transaction)
    json_payload = facade.transaction_factory.attach_signature(
        transaction, signature)
    print('Built transaction:')
    print(json.dumps(transaction.to_json(), indent=2))

    transaction_hash = facade.hash_transaction(transaction)
    print(f'Transaction hash: {transaction_hash}')

    # Announce transaction
    announce_transaction(json_payload, 'namespace registration')

    # Wait for confirmation
    wait_for_confirmation(transaction_hash, 'namespace registration')

    # Retrieve the namespace
    namespace_id = generate_namespace_id(namespace_name)
    print(f'Namespace ID: {namespace_id} (0x{namespace_id:016X})')

    namespace_path = f'/namespaces/{namespace_id:016X}'
    print(f'Fetching namespace information from {namespace_path}')
    with urllib.request.urlopen(
        f'{NODE_URL}{namespace_path}'
    ) as response:
        response_json = json.loads(response.read().decode())
        namespace_info = response_json['namespace']
        print('Namespace information:')
        reg_type = namespace_info['registrationType']
        print(f'  Registration type: {reg_type}')
        owner_address = Address.from_decoded_address_hex_string(
            namespace_info['ownerAddress'])
        print(f'  Owner address: {owner_address}')
        print(f"  Start height: {namespace_info['startHeight']}")

        print(f"  End height: {namespace_info['endHeight']}")

except Exception as e:
    print(e)

Download source

import { PrivateKey } from 'symbol-sdk';
import {
    Address,
    SymbolFacade,
    descriptors,
    generateNamespaceId,
    models
} from 'symbol-sdk/symbol';

const NODE_URL = process.env.NODE_URL ||
    'https://reference.symboltest.net:3001';
console.log('Using node', NODE_URL);

// Helper function to announce a transaction
async function announceTransaction(payload, label) {
    console.log(`Announcing ${label} to /transactions`);
    const response = await fetch(`${NODE_URL}/transactions`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: payload
    });
    console.log('  Response:', await response.text());
}

// Helper function to wait for transaction confirmation
async function waitForConfirmation(transactionHash, label) {
    console.log(`Waiting for ${label} confirmation...`);
    for (let attempt = 0; 60 > attempt; attempt++) {
        await new Promise(resolve => { setTimeout(resolve, 1000); });
        const response = await fetch(
            `${NODE_URL}/transactionStatus/${transactionHash}`);
        if (!response.ok) {
            if (404 === response.status) {
                console.log('  Transaction status: unknown');
                continue;
            }
            throw new Error(`HTTP ${response.status}`);
        }
        const status = await response.json();
        console.log('  Transaction status:', status.group);
        if ('confirmed' === status.group) {
            console.log(`${label} confirmed in`, attempt, 'seconds');
            return;
        }
        if ('failed' === status.group)
            throw new Error(`${label} failed: ${status.code}`);
    }
    throw new Error(`${label} not confirmed after 60 seconds`);
}


const SIGNER_PRIVATE_KEY = process.env.SIGNER_PRIVATE_KEY ||
    '0000000000000000000000000000000000000000000000000000000000000000';
const signerKeyPair = new SymbolFacade.KeyPair(
    new PrivateKey(SIGNER_PRIVATE_KEY));

const facade = new SymbolFacade('testnet');
const signerAddress = facade.network.publicKeyToAddress(
    signerKeyPair.publicKey);
console.log('Signer address:', signerAddress.toString());

try {
    // Fetch recommended fees
    const feePath = '/network/fees/transaction';
    console.log('Fetching recommended fees from', feePath);
    const feeResponse = await fetch(`${NODE_URL}${feePath}`);
    const feeJSON = await feeResponse.json();
    const medianMultiplier = feeJSON.medianFeeMultiplier;
    const minimumMultiplier = feeJSON.minFeeMultiplier;
    const feeMultiplier = Math.max(medianMultiplier, minimumMultiplier);
    console.log('  Fee multiplier:', feeMultiplier);

    // Build the namespace name
    const namespaceName =
        process.env.ROOT_NAMESPACE || `ns_${Date.now()}`;
    console.log('Creating root namespace:', namespaceName);

    // Build the transaction
    const transaction = facade.createTransactionFromTypedDescriptor(
        new descriptors.NamespaceRegistrationTransactionV1Descriptor(
            new models.NamespaceId(0n),
            models.NamespaceRegistrationType.ROOT,
            new models.BlockDuration(86400n), // approximately 30 days
            undefined,
            namespaceName),
        signerKeyPair.publicKey,
        feeMultiplier,
        2 * 60 * 60);

    // Sign transaction and generate final payload
    const signature = facade.signTransaction(
        signerKeyPair, transaction);
    const jsonPayload = facade.transactionFactory.static.attachSignature(
        transaction, signature);
    console.log('Built transaction:');
    console.dir(transaction.toJson(), { colors: true });

    const transactionHash =
        facade.hashTransaction(transaction).toString();
    console.log('Transaction hash:', transactionHash);

    // Announce transaction
    await announceTransaction(jsonPayload, 'namespace registration');

    // Wait for confirmation
    await waitForConfirmation(transactionHash, 'namespace registration');

    // Retrieve the namespace
    const namespaceId = generateNamespaceId(namespaceName);
    const namespaceIdHex = namespaceId.toString(16)
        .toUpperCase().padStart(16, '0');
    console.log(
        'Namespace ID:',
        `${namespaceId} (0x${namespaceIdHex})`);

    const namespacePath = `/namespaces/${namespaceIdHex}`;
    console.log('Fetching namespace information from', namespacePath);
    const namespaceResponse = await fetch(`${NODE_URL}${namespacePath}`);
    const namespaceJSON = await namespaceResponse.json();
    const namespaceInfo = namespaceJSON.namespace;
    console.log('Namespace information:');
    console.log('  Registration type:', namespaceInfo.registrationType);
    const ownerAddress = Address.fromDecodedAddressHexString(
        namespaceInfo.ownerAddress);
    console.log('  Owner address:', ownerAddress.toString());
    console.log('  Start height:', namespaceInfo.startHeight);
    console.log('  End height:', namespaceInfo.endHeight);
} catch (e) {
    console.error(e.message);
}

Download source

//JAVA 21+
//DEPS org.symbol:symbol-sdk:3.3.1

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.StandardCharsets;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.symbol.sdk.CryptoTypes;
import org.symbol.sdk.facade.SymbolFacade;
import org.symbol.sdk.symbol.Address;
import org.symbol.sdk.symbol.IdGenerator;
import org.symbol.sdk.symbol.KeyPair;
import org.symbol.sdk.symbol.SymbolTransactionFactory;
import org.symbol.sdk.symbol.descriptors.*;
import org.symbol.sdk.symbol.models.*;

public final class RegisterRootNamespace {
    private static final ObjectMapper JSON_MAPPER = new ObjectMapper();

    private static final HttpClient HTTP_CLIENT =
        HttpClient.newHttpClient();

    private final String nodeUrl = System.getenv().getOrDefault(
        "NODE_URL", "https://reference.symboltest.net:3001");

    private final SymbolFacade facade = new SymbolFacade("testnet");

    private void announceTransaction(
        final String payload,
        final String label
    ) throws IOException, InterruptedException {
        System.out.printf("Announcing %s to /transactions%n", label);
        final HttpRequest request = HttpRequest.newBuilder(
            URI.create(nodeUrl + "/transactions"))
            .header("Content-Type", "application/json")
            .PUT(HttpRequest.BodyPublishers.ofString(payload))
            .build();
        final HttpResponse<String> response = HTTP_CLIENT.send(
            request, BodyHandlers.ofString());
        System.out.printf("  Response: %s%n", response.body());
    }

    private void waitForConfirmation(
        final String transactionHash,
        final String label
    ) throws IOException, InterruptedException {
        System.out.printf("Waiting for %s confirmation...%n", label);
        for (int attempt = 0; 60 > attempt; ++attempt) {
            Thread.sleep(1000);
            final String statusPath =
                "/transactionStatus/" + transactionHash;
            final HttpRequest statusRequest = HttpRequest.newBuilder(
                URI.create(nodeUrl + statusPath)).GET().build();
            final HttpResponse<String> statusResponse = HTTP_CLIENT
                .send(statusRequest, BodyHandlers.ofString());
            if (404 == statusResponse.statusCode()) {
                System.out.println("  Transaction status: unknown");
                continue;
            }
            if (2 != statusResponse.statusCode() / 100)
                throw new IOException(
                    "HTTP " + statusResponse.statusCode());

            final JsonNode status =
                JSON_MAPPER.readTree(statusResponse.body());
            final String group = status.get("group").asText();
            System.out.printf("  Transaction status: %s%n", group);
            if ("confirmed".equals(group)) {
                System.out.printf("%s confirmed in %d seconds%n",
                    label, attempt);
                return;
            }
            if ("failed".equals(group))
                throw new IOException(String.format("%s failed: %s",
                    label, status.get("code").asText()));
        }
        throw new IOException(String.format(
            "%s not confirmed after 60 seconds", label));
    }

    public static void main(final String[] args) {
        try {
            new RegisterRootNamespace().run();
        } catch (final Exception ex) {
            System.out.println(null == ex.getMessage()
                ? ex.toString()
                : ex.getMessage());
        }
    }

    private void run() throws IOException, InterruptedException {
        System.out.printf("Using node %s%n", nodeUrl);

        final String signerPrivateKey = System.getenv().getOrDefault(
            "SIGNER_PRIVATE_KEY", "0".repeat(64));
        final KeyPair signerKeyPair = new KeyPair(
            new CryptoTypes.PrivateKey(signerPrivateKey));

        final Address signerAddress = facade.network.publicKeyToAddress(
            signerKeyPair.getPublicKey());
        System.out.printf("Signer address: %s%n", signerAddress);

        // Fetch recommended fees
        final String feePath = "/network/fees/transaction";
        System.out.printf("Fetching recommended fees from %s%n", feePath);
        final JsonNode feeJson = getJson(feePath);
        final long feeMultiplier = Math.max(
            feeJson.get("medianFeeMultiplier").asLong(),
            feeJson.get("minFeeMultiplier").asLong());
        System.out.printf("  Fee multiplier: %d%n", feeMultiplier);

        // Build the namespace name
        final String namespaceName = System.getenv().getOrDefault(
            "ROOT_NAMESPACE",
            "ns_" + System.currentTimeMillis() / 1000);
        System.out.printf("Creating root namespace: %s%n",
            namespaceName);

        // Build the transaction
        final Transaction transaction =
            facade.createTransactionFromTypedDescriptor(
                new NamespaceRegistrationTransactionV1Descriptor(
                    new NamespaceId(0),
                    NamespaceRegistrationType.ROOT,
                    new BlockDuration(86400), // approximately 30 days
                    null,
                    namespaceName.getBytes(StandardCharsets.UTF_8)),
                signerKeyPair.getPublicKey(),
                feeMultiplier,
                2 * 60 * 60);

        // Sign transaction and generate final payload
        final CryptoTypes.Signature signature = facade.signTransaction(
            signerKeyPair, transaction);
        final String jsonPayload = SymbolTransactionFactory
            .attachSignature(transaction, signature);
        System.out.println("Built transaction:");
        System.out.println(JSON_MAPPER.writerWithDefaultPrettyPrinter()
            .writeValueAsString(transaction.toJson()));

        final String transactionHash =
            facade.hashTransaction(transaction).toString();
        System.out.printf("Transaction hash: %s%n", transactionHash);

        // Announce transaction
        announceTransaction(jsonPayload, "namespace registration");

        // Wait for confirmation
        waitForConfirmation(transactionHash, "namespace registration");

        // Retrieve the namespace
        final long namespaceId = IdGenerator.generateNamespaceId(
            namespaceName);
        System.out.printf("Namespace ID: %s (0x%016X)%n",
            Long.toUnsignedString(namespaceId), namespaceId);

        final String namespacePath = "/namespaces/%016X".formatted(
            namespaceId);
        System.out.printf("Fetching namespace information from %s%n",
            namespacePath);
        final JsonNode namespaceInfo = getJson(namespacePath)
            .get("namespace");
        System.out.println("Namespace information:");
        System.out.printf("  Registration type: %s%n",
            namespaceInfo.get("registrationType").asText());
        final Address ownerAddress = Address
            .fromDecodedAddressHexString(
                namespaceInfo.get("ownerAddress").asText());
        System.out.printf("  Owner address: %s%n", ownerAddress);
        System.out.printf("  Start height: %s%n",
            namespaceInfo.get("startHeight").asText());
        System.out.printf("  End height: %s%n",
            namespaceInfo.get("endHeight").asText());
    }

    private JsonNode getJson(final String path)
        throws IOException, InterruptedException {
        final HttpRequest request = HttpRequest.newBuilder(
            URI.create(nodeUrl + path)).GET().build();
        final HttpResponse<String> response = HTTP_CLIENT.send(
            request, BodyHandlers.ofString());
        return JSON_MAPPER.readTree(response.body());
    }

}

Download source

コード解説⚓︎

アカウントの設定⚓︎

SIGNER_PRIVATE_KEY = os.getenv(
    'SIGNER_PRIVATE_KEY',
    '0000000000000000000000000000000000000000000000000000000000000000')
signer_key_pair = SymbolFacade.KeyPair(PrivateKey(SIGNER_PRIVATE_KEY))

facade = SymbolFacade('testnet')
signer_address = facade.network.public_key_to_address(
    signer_key_pair.public_key)
print(f'Signer address: {signer_address}')
const SIGNER_PRIVATE_KEY = process.env.SIGNER_PRIVATE_KEY ||
    '0000000000000000000000000000000000000000000000000000000000000000';
const signerKeyPair = new SymbolFacade.KeyPair(
    new PrivateKey(SIGNER_PRIVATE_KEY));

const facade = new SymbolFacade('testnet');
const signerAddress = facade.network.publicKeyToAddress(
    signerKeyPair.publicKey);
console.log('Signer address:', signerAddress.toString());
        final String signerPrivateKey = System.getenv().getOrDefault(
            "SIGNER_PRIVATE_KEY", "0".repeat(64));
        final KeyPair signerKeyPair = new KeyPair(
            new CryptoTypes.PrivateKey(signerPrivateKey));

        final Address signerAddress = facade.network.publicKeyToAddress(
            signerKeyPair.getPublicKey());
        System.out.printf("Signer address: %s%n", signerAddress);

このスニペットは、署名者の 秘密鍵SIGNER_PRIVATE_KEY 環境変数から読み取ります。設定されていない場合は、デフォルトのテストキーが使用されます。 署名者の アドレス公開鍵 から派生します。 このアカウントが、登録されたネームスペースを所有することになります。

    # Fetch recommended fees
    fee_path = '/network/fees/transaction'
    print(f'Fetching recommended fees from {fee_path}')
    with urllib.request.urlopen(f'{NODE_URL}{fee_path}') as response:
        response_json = json.loads(response.read().decode())
        median_multiplier = response_json['medianFeeMultiplier']
        minimum_multiplier = response_json['minFeeMultiplier']
        fee_multiplier = max(median_multiplier, minimum_multiplier)
        print(f'  Fee multiplier: {fee_multiplier}')
    // Fetch recommended fees
    const feePath = '/network/fees/transaction';
    console.log('Fetching recommended fees from', feePath);
    const feeResponse = await fetch(`${NODE_URL}${feePath}`);
    const feeJSON = await feeResponse.json();
    const medianMultiplier = feeJSON.medianFeeMultiplier;
    const minimumMultiplier = feeJSON.minFeeMultiplier;
    const feeMultiplier = Math.max(medianMultiplier, minimumMultiplier);
    console.log('  Fee multiplier:', feeMultiplier);
        // Fetch recommended fees
        final String feePath = "/network/fees/transaction";
        System.out.printf("Fetching recommended fees from %s%n", feePath);
        final JsonNode feeJson = getJson(feePath);
        final long feeMultiplier = Math.max(
            feeJson.get("medianFeeMultiplier").asLong(),
            feeJson.get("minFeeMultiplier").asLong());
        System.out.printf("  Fee multiplier: %d%n", feeMultiplier);

転送トランザクション チュートリアルで説明されているプロセスに従い、推奨手数料を /network/fees/transaction GET から取得します。

ネームスペース名の選択⚓︎

    # Build the namespace name
    namespace_name = os.getenv(
        'ROOT_NAMESPACE', f'ns_{int(time.time())}')
    print(f'Creating root namespace: {namespace_name}')
    // Build the namespace name
    const namespaceName =
        process.env.ROOT_NAMESPACE || `ns_${Date.now()}`;
    console.log('Creating root namespace:', namespaceName);
        // Build the namespace name
        final String namespaceName = System.getenv().getOrDefault(
            "ROOT_NAMESPACE",
            "ns_" + System.currentTimeMillis() / 1000);
        System.out.printf("Creating root namespace: %s%n",
            namespaceName);

ネームスペースは名前によって識別され、トランザクションがその名前をネットワーク上に登録します。 命名規則については、テキストブックの 名前 を参照してください。

チュートリアルを複数回実行してもネームスペース名が重複しないように、名前にタイムスタンプが付加されています。 実用的なプログラムでは、ネームスペースに固定の名前を使用します。 ROOT_NAMESPACE 環境変数を使って、固定の名前を強制的に使用させることもできます。

トランザクションの構築⚓︎

    # Build the transaction
    transaction = facade.create_transaction_from_descriptor(
        {
            'type': 'namespace_registration_transaction_v1',
            'registration_type': 'root',
            'duration': 86400,  # approximately 30 days
            'name': namespace_name
        },
        signer_key_pair.public_key,
        fee_multiplier,
        2 * 60 * 60)
    // Build the transaction
    const transaction = facade.createTransactionFromTypedDescriptor(
        new descriptors.NamespaceRegistrationTransactionV1Descriptor(
            new models.NamespaceId(0n),
            models.NamespaceRegistrationType.ROOT,
            new models.BlockDuration(86400n), // approximately 30 days
            undefined,
            namespaceName),
        signerKeyPair.publicKey,
        feeMultiplier,
        2 * 60 * 60);
        // Build the transaction
        final Transaction transaction =
            facade.createTransactionFromTypedDescriptor(
                new NamespaceRegistrationTransactionV1Descriptor(
                    new NamespaceId(0),
                    NamespaceRegistrationType.ROOT,
                    new BlockDuration(86400), // approximately 30 days
                    null,
                    namespaceName.getBytes(StandardCharsets.UTF_8)),
                signerKeyPair.getPublicKey(),
                feeMultiplier,
                2 * 60 * 60);

ネームスペース登録トランザクションは、ネットワークにネームスペースを登録します。 に渡した署名者が、登録されたネームスペースの所有者になります。 トランザクションの記述子には以下を指定します。

  • : ネームスペース登録トランザクションにはタイプ NamespaceRegistrationTransactionV1 を使用します。

  • : root という値は、ルートネームスペースが作成されることを示します。 代わりに サブネームスペースを登録 するには child を使用してください。

  • : ネームスペースがレンタルされるブロック数。 最小期間は 86,400 ブロック(約30日)、最大期間は 5,256,000 ブロック(約5年)です。

  • : ルートネームスペースの名前。

ネームスペースレンタル手数料

標準の トランザクション手数料 に加えて、ネームスペースの登録には、要求された期間に比例した レンタル手数料 が必要です。

トランザクション手数料とは異なり、レンタル手数料はトランザクションリクエストには 含まれません。 登録トランザクションが承認されると、ネットワークによって トランザクション署名者のアカウント から自動的に計算され、差し引かれます。

レンタル手数料の額は、 /network/fees/rental GET エンドポイントを使用して事前に計算できます。

トランザクションの送信⚓︎

    # Sign transaction and generate final payload
    signature = facade.sign_transaction(signer_key_pair, transaction)
    json_payload = facade.transaction_factory.attach_signature(
        transaction, signature)
    print('Built transaction:')
    print(json.dumps(transaction.to_json(), indent=2))

    transaction_hash = facade.hash_transaction(transaction)
    print(f'Transaction hash: {transaction_hash}')

    # Announce transaction
    announce_transaction(json_payload, 'namespace registration')
    // Sign transaction and generate final payload
    const signature = facade.signTransaction(
        signerKeyPair, transaction);
    const jsonPayload = facade.transactionFactory.static.attachSignature(
        transaction, signature);
    console.log('Built transaction:');
    console.dir(transaction.toJson(), { colors: true });

    const transactionHash =
        facade.hashTransaction(transaction).toString();
    console.log('Transaction hash:', transactionHash);

    // Announce transaction
    await announceTransaction(jsonPayload, 'namespace registration');
        // Sign transaction and generate final payload
        final CryptoTypes.Signature signature = facade.signTransaction(
            signerKeyPair, transaction);
        final String jsonPayload = SymbolTransactionFactory
            .attachSignature(transaction, signature);
        System.out.println("Built transaction:");
        System.out.println(JSON_MAPPER.writerWithDefaultPrettyPrinter()
            .writeValueAsString(transaction.toJson()));

        final String transactionHash =
            facade.hashTransaction(transaction).toString();
        System.out.printf("Transaction hash: %s%n", transactionHash);

        // Announce transaction
        announceTransaction(jsonPayload, "namespace registration");

トランザクションは、転送トランザクション チュートリアルと同じプロセスに従って署名され、アナウンスされます。

    # Wait for confirmation
    wait_for_confirmation(transaction_hash, 'namespace registration')
    // Wait for confirmation
    await waitForConfirmation(transactionHash, 'namespace registration');
        // Wait for confirmation
        waitForConfirmation(transactionHash, "namespace registration");

コードはその後、ステータスが confirmed に変わるまで /transactionStatus/{hash} GET エンドポイントをポーリングして、トランザクションが承認されるのを待ちます。

ネームスペースの取得⚓︎

    # Retrieve the namespace
    namespace_id = generate_namespace_id(namespace_name)
    print(f'Namespace ID: {namespace_id} (0x{namespace_id:016X})')

    namespace_path = f'/namespaces/{namespace_id:016X}'
    print(f'Fetching namespace information from {namespace_path}')
    with urllib.request.urlopen(
        f'{NODE_URL}{namespace_path}'
    ) as response:
        response_json = json.loads(response.read().decode())
        namespace_info = response_json['namespace']
        print('Namespace information:')
        reg_type = namespace_info['registrationType']
        print(f'  Registration type: {reg_type}')
        owner_address = Address.from_decoded_address_hex_string(
            namespace_info['ownerAddress'])
        print(f'  Owner address: {owner_address}')
        print(f"  Start height: {namespace_info['startHeight']}")
    // Retrieve the namespace
    const namespaceId = generateNamespaceId(namespaceName);
    const namespaceIdHex = namespaceId.toString(16)
        .toUpperCase().padStart(16, '0');
    console.log(
        'Namespace ID:',
        `${namespaceId} (0x${namespaceIdHex})`);

    const namespacePath = `/namespaces/${namespaceIdHex}`;
    console.log('Fetching namespace information from', namespacePath);
    const namespaceResponse = await fetch(`${NODE_URL}${namespacePath}`);
    const namespaceJSON = await namespaceResponse.json();
    const namespaceInfo = namespaceJSON.namespace;
    console.log('Namespace information:');
    console.log('  Registration type:', namespaceInfo.registrationType);
    const ownerAddress = Address.fromDecodedAddressHexString(
        namespaceInfo.ownerAddress);
    console.log('  Owner address:', ownerAddress.toString());
    console.log('  Start height:', namespaceInfo.startHeight);
    console.log('  End height:', namespaceInfo.endHeight);
        // Retrieve the namespace
        final long namespaceId = IdGenerator.generateNamespaceId(
            namespaceName);
        System.out.printf("Namespace ID: %s (0x%016X)%n",
            Long.toUnsignedString(namespaceId), namespaceId);

        final String namespacePath = "/namespaces/%016X".formatted(
            namespaceId);
        System.out.printf("Fetching namespace information from %s%n",
            namespacePath);
        final JsonNode namespaceInfo = getJson(namespacePath)
            .get("namespace");
        System.out.println("Namespace information:");
        System.out.printf("  Registration type: %s%n",
            namespaceInfo.get("registrationType").asText());
        final Address ownerAddress = Address
            .fromDecodedAddressHexString(
                namespaceInfo.get("ownerAddress").asText());
        System.out.printf("  Owner address: %s%n", ownerAddress);
        System.out.printf("  Start height: %s%n",
            namespaceInfo.get("startHeight").asText());
        System.out.printf("  End height: %s%n",
            namespaceInfo.get("endHeight").asText());

ネームスペースが登録されたことを確認するために、コードは /namespaces/{namespaceId} GET エンドポイントを使用してネットワークからネームスペースを取得し、そのプロパティを表示します。

ネームスペース ID は を使用して計算されます。 この関数はネームスペース名に決定論的なハッシュアルゴリズムを適用し、ネームスペース情報を照会するために必要な ID を生成します。

レスポンスが成功すれば、ネームスペースが登録され、ネットワーク上でアクティブであることが確認されます。

ネームスペースは登録されましたが、まだリンクされていません

ネームスペースが モザイクアカウント のエイリアスとして機能するとき、初めて有用なものとなります。 次のステップ のガイドを使用して、ネームスペースを識別子にリンクしてください。

出力⚓︎

以下に示す出力は、プログラムの典型的な実行結果に対応しています。

Using node https://reference.symboltest.net:3001
Signer address: TCHBDENCLKEBILBPWP3JPB2XNY64OE7PYHHE32I
Fetching recommended fees from /network/fees/transaction
  Fee multiplier: 100
Creating root namespace: ns_1766533079
Built transaction:
{
  "signature": "64F716B9F4CB265D7130FDBD6BABB93A3AE2CC31896D0D3C85DE7CAFDE3CC5053730FC56FCF64B3FCFD24213A9BF3432AC08D2C03766EAF847C86421D88EA603",
  "signer_public_key": "3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29",
  "version": 1,
  "network": 152,
  "type": 16718,
  "fee": "15900",
  "deadline": "99289814227",
  "duration": "86400",
  "id": "10704093651797406551",
  "registration_type": 0,
  "name": "6e735f31373636353333303739"
}
Transaction hash: 2E3ACFD140AEAA21E7839376C4290695E9E58761DC37B1E60D3207F76370CC22
Announcing namespace registration to /transactions
  Response: {"message":"packet 9 was pushed to the network via /transactions"}
Waiting for namespace registration confirmation...
  Transaction status: unconfirmed
  Transaction status: unconfirmed
  Transaction status: confirmed
namespace registration confirmed in 11 seconds
Namespace ID: 10704093651797406551 (0x948C9476ADE5F357)
Fetching namespace information from /namespaces/948C9476ADE5F357
Namespace information:
  Registration type: 0
  Owner address: TCHBDENCLKEBILBPWP3JPB2XNY64OE7PYHHE32I
  Start height: 2984442
  End height: 3073722

出力の主なポイント:

  • ネームスペース名 (5行目): 選択された名前 ns_1766533079 には、一意性を確保するためにタイムスタンプが含まれています。 ネームスペースの詳細を表示するには、Symbol Testnet Explorer でこの名前を検索してください。

  • 手数料 (13行目): 0.0159 XYM のトランザクション手数料は、トランザクションサイズに手数料倍率を乗じて計算されます。 レンタル手数料 は、トランザクションが承認された際にネットワークによって別途差し引かれます。

  • ID と名前 (16、18行目): id フィールドにはネームスペース ID が10進数で表示され、 name には16進数文字列としてエンコードされたネームスペース名が含まれます。例えば、 6e735f...ns_1... にデコードされます。

  • ネームスペース ID (28行目): 16行目の id フィールドと一致するように、10進数と16進数の両方の表現が表示されます。

  • 登録タイプ (31行目): 値 0 はルートネームスペースであることを示します(サブネームスペースの場合は 1 )。

  • 所有者アドレス (32行目): ネームスペースを登録し、所有しているアカウント。

  • 開始高と終了高 (33-34行目): ネームスペースはブロック 2984442 から 3073722 まで有効です。 終了高には、要求された期間を超えて 猶予期間 (テストネットでは1日、メインネットでは30日)が含まれており、所有者がネームスペースを他の人に利用可能になる前に更新する時間を与えます。

出力に印刷されたトランザクション ハッシュ を使用して、 Symbol Testnet Explorer でトランザクションを検索することもできます。

結論⚓︎

このチュートリアルでは、以下の方法を説明しました。

ステップ 関連ドキュメント
ネームスペース登録トランザクションを構築する , NamespaceRegistrationTransactionV1
ネームスペース ID を生成する
ネームスペースを取得する /namespaces/{namespaceId} GET

次のステップ⚓︎

ルートネームスペースを作成したので、以下のことができます。