はじめてのアプリケーションを作成

このガイドでは Symbol Developer Documentation 開発サイクルについて説明します。

まず、 Symbol Developer Documentation で利用可能な組み込み機能である モザイクアカウント を組み合わせてソリューションを設計します。このガイドの最後に、ブロックチェーンでトランザクションを発行および監視する方法を理解するでしょう。

Use case

チケット二次市場は、再販市場としても知られており、最初の販売者からチケットを購入した後に個人間で行われるチケット交換です。最初の販売者は、イベントウェブサイト、オンラインチケット販売プラットフォーム、イベントの入口にあるショップまたは売店であったりします。

最初の販売者ではない人からチケットを購入しても、必ずしもそのチケットの追加料金を支払うという意味ではありません。これは最初の販売者が問題の解決に何もできず、偽造もしくは複製されたチケットを購入してしまう、被害者となる機会です。

私達は何を解決したいのでしょう?

../_images/getting-started.png

認証モデル

チケット販売者はシステムのセットアップを望んでいます:

  1. 各チケットと購入者を識別する。
  2. チケットの転売防止。
  3. 未認証のチケットとその複製の防止。

なぜ Symbol は正しい選択なのでしょう?

ブロックチェーンテクノロジーはこのようなケースに適用できます:

  • 様々な参加者が関係します。
  • 参加者はお互いに信頼する必要があります。
  • 不変のイベントの集合を追跡し続ける必要があります。

Symbol は フレキシブルなブロックチェーン テクノロジーです。すべてのアプリケーションロジックをブロックチェーンにアップロードする代わりに、 API 呼び出し によってテスト済みの機能を使用して、価値、認可、トレーサビリティ、そして認証の移転と格納を行うことができます。

残りのコードは オフチェーン のままです。これにより必要に応じてプロセスを変更できるため、固有の不変性リスクが軽減されます。

各参加者のアカウントを作成

まず、解決したいユースケースに関与するアクターを特定します:

  • チケット販売者
  • 購入者

チケット販売者と顧客を別々の アカウント として表現することにしました。アカウントとは対応する秘密鍵で変更できる、ブロックチェーン上の預金金庫と考えてください。各アカウントは一意であり、アドレスによって識別されます。

テスト symbol.xym をアカウントへ入金しましたか? 前のガイド では Symbol CLI を使用してアカウントの作り方を学習しました。このアカウントは チケット販売者 アカウントとして表現します。

  1. 次のコマンドを実行して、チケット販売者のアカウントに symbol.xym 単位があることを確認します。
symbol-cli account info --profile testnet

このような行がスクリーンに表示されているはずです:

Account Information
┌───────────────────┬────────────────────────────────────────────────┐
│ Property          │ Value                                          │
├───────────────────┼────────────────────────────────────────────────┤
│ Address           │ TCWYXK-VYBMO4-NBCUF3-AXKJMX-CGVSYQ-OS7ZG2-TLI  │
├───────────────────┼────────────────────────────────────────────────┤
│ Address Height    │ 1                                              │
├───────────────────┼────────────────────────────────────────────────┤
│ Public Key        │ 203...C0A                                      │
├───────────────────┼────────────────────────────────────────────────┤
│ Public Key Height │ 3442                                           │
├───────────────────┼────────────────────────────────────────────────┤
│ Importance        │ 0                                              │
├───────────────────┼────────────────────────────────────────────────┤
│ Importance Height │ 0                                              │
└───────────────────┴────────────────────────────────────────────────┘

Balance Information
┌──────────────────┬─────────────────┬─────────────────┬───────────────────┐
│ Mosaic Id        │ Relative Amount │ Absolute Amount │ Expiration Height │
├──────────────────┼─────────────────┼─────────────────┼───────────────────┤
│ 5E62990DCAC5BE8A │ 750.0           │ 750000000       │ Never             │
└──────────────────┴─────────────────┴─────────────────┴───────────────────┘

アカウントは 750 symbol.xym 相対単位を保有しています。もし 「Balance Information」 の次の行が空の場合は、テスト用通貨を手に入れるために 前のガイド に従ってください。

  1. 販売者 を識別するための2つ目のアカウントを CLI で作成します。
symbol-cli account generate --network TEST_NET --save --url http://api-01.us-east-1.0.10.0.x.symboldev.network:3000 --profile customer

New Account

┌─────────────┬────────────────────────────────────────────────┐
│ Property    │ Value                                          │
├─────────────┼────────────────────────────────────────────────┤
│ Address     │ TCHBDE-NCLKEB-ILBPWP-3JPB2X-NY64OE-7PYHHE-32I  │
├─────────────┼────────────────────────────────────────────────┤
│ Public Key  │ E59...82F                                      │
├─────────────┼────────────────────────────────────────────────┤
│ Private Key │ 111...111                                      │
└─────────────┴────────────────────────────────────────────────┘

ブロックチェーンの監視

アカウントはトランザクションを通じてブロックチェーンの状態を変更します。アカウントがトランザクションをアナウンスすると、正しく構成されている場合、サーバーは OK のレスポンスを返します。

ただし OK レスポンスを受信して​​も、トランザクションが有効であったり、ブロックに含まれるわけではありません。たとえば、発行者に十分な symbol.xym がない、メッセージセットが大きすぎる、手数料の指定が少なすぎるなど、トランザクションが拒否される可能性があります。

ネットワークによって承認または拒否されるタイミングを検知するために、アナウンスする前に トランザクションを監視する ことを推奨します。

新しいターミナルで、チケット販売者のアカウントに関するトランザクションを監視して、ネットワークによって承認または拒否されたかを確認します。

symbol-cli monitor all --address TCWYXK-VYBMO4-NBCUF3-AXKJMX-CGVSYQ-OS7ZG2-TLI

チケットの作成

Symbol モザイク でチケットを表現します。この機能は物体、チケット、クーポン、株式に相当するもの、あなたの暗号通貨さえも、いかなるアセットをブロックチェーン上に表現することができます。

モザイクは作成時に定義される変更可能なプロパティを持ちます。例えば 転送可能プロパティを false に設定します。これは、チケットの転売を防止するために、購入者がモザイク作成者だけに送り返すことしかできないことを意味します。

  1. CLI を使用し、チケット販売者アカウントでチケットを表現する新しいモザイクを作成します。この新しいモザイクは次のように構成します:
プロパティ 説明
Divisibility 0 “0.5 tickets” が送信できないように、モザイクは可分できないようにします。
Duration 1000 モザイクは 1000 ブロック登録されます。
Amount 99 作成するチケットの量
Supply mutable True モザイク供給量は後に変更可能です。
Transferable False モザイクはモザイク作成者だけに送り返すことしかできません。
symbol-cli transaction mosaic --amount 99 --supply-mutable --divisibility 0 --duration 1000 --max-fee 2000000 --sync --profile testnet
  1. トランザクションをアナウンスしたら、ターミナルに表示された MosaicID コピーしてください。
The new mosaic id is: 7cdf3b117a3c40cc

The transaction should appear as confirmed after ±15 seconds. If the terminal raises an error, you can check the error code description here.

チケットの送信

モザイクを定義したので、1 つのチケット単位を TransferTransaction をアナウンスして顧客に送信します。

  1. 新しいファイルを開き、次の値で TransferTransaction を定義してください。
プロパティ 説明
Deadline デフォルト (2 時間) トランザクションをブロックチェーンに含める最大時間。トランザクションは規定の時間を過ぎても未確認のままであると破棄されます。パラメーターは時間単位で定義され1から23時間の範囲である必要があります。
Recipient TCHBDE…32I 受信のアカウントアドレス。このケースでは顧客のアドレスです。
Mosaics [1 7cdf3b117a3c40cc] 送信するモザイクの配列
Message enjoy your ticket 添付されたメッセージ
Network TEST_NET ネットワークタイプ
// replace with mosaic id
const mosaicIdHex = '7cdf3b117a3c40cc';
const mosaicId = new MosaicId(mosaicIdHex);
// replace with customer address
const rawAddress = 'TCHBDE-NCLKEB-ILBPWP-3JPB2X-NY64OE-7PYHHE-32I';
const recipientAddress = Address.createFromRawAddress(rawAddress);
// replace with network type
const networkType = NetworkType.TEST_NET;

const transferTransaction = TransferTransaction.create(
    Deadline.create(),
    recipientAddress,
    [new Mosaic(mosaicId, UInt64.fromUint(1))],
    PlainMessage.create('enjoy your ticket'),
    networkType,
    UInt64.fromUint(2000000));
// replace with mosaic id
const mosaicIdHex = '7cdf3b117a3c40cc';
const mosaicId = new symbol_sdk_1.MosaicId(mosaicIdHex);
// replace with customer address
const rawAddress = 'TCHBDE-NCLKEB-ILBPWP-3JPB2X-NY64OE-7PYHHE-32I';
const recipientAddress = symbol_sdk_1.Address.createFromRawAddress(rawAddress);
// replace with network type
const networkType = symbol_sdk_1.NetworkType.TEST_NET;
const transferTransaction = symbol_sdk_1.TransferTransaction.create(symbol_sdk_1.Deadline.create(), recipientAddress, [new symbol_sdk_1.Mosaic(mosaicId, symbol_sdk_1.UInt64.fromUint(1))], symbol_sdk_1.PlainMessage.create('enjoy your ticket'), networkType, symbol_sdk_1.UInt64.fromUint(2000000));
        // replace with node endpoint
        try (final RepositoryFactory repositoryFactory = new RepositoryFactoryVertxImpl(
                "http://api-01.us-east-1.0.10.0.x.symboldev.network:3000")) {
            // replace with mosaic id
            final String mosaicIdHex = "7cdf3b117a3c40cc";
            final MosaicId mosaicId = new MosaicId(mosaicIdHex);

            // replace with customer address
            final String rawAddress = "TCHBDE-NCLKEB-ILBPWP-3JPB2X-NY64OE-7PYHHE-32I";
            final UnresolvedAddress recipientAddress = Address.createFromRawAddress(rawAddress);
            final NetworkType networkType = repositoryFactory.getNetworkType().toFuture().get();

            final Mosaic mosaic = new Mosaic(mosaicId, BigInteger.valueOf(1));
            final TransferTransaction transferTransaction = TransferTransactionFactory
                    .create(
                            networkType,
                            recipientAddress,
                            Collections.singletonList(mosaic),
                            PlainMessage.create("Enjoy your ticket"))
                    .maxFee(BigInteger.valueOf(2000000)).build();

トランザクションは定義されましたが、まだネットワークへはアナウンスされていません。

  1. ネットワークがトランザクションの信頼性を検証できるように チケット販売者のアカウント でトランザクションに署名をします。

注釈

あなたのネットワークでだけ妥当なトランザクションを作るには、ネットワークジェネレーションハッシュを含めてください。新しいブラウザタブで nodeUrl + '/node/info' を開いて meta.networkGenerationHash の値をコピーします。

// replace with ticket vendor private key
const privateKey = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
const account = Account.createFromPrivateKey(privateKey, networkType);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash = '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = account.sign(transferTransaction, networkGenerationHash);
// replace with ticket vendor private key
const privateKey = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
const account = symbol_sdk_1.Account.createFromPrivateKey(privateKey, networkType);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash = '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = account.sign(transferTransaction, networkGenerationHash);
            // replace with ticket vendor private key
            final String privateKey = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
            // replace with network generation hash
            final String generationHash = repositoryFactory.getGenerationHash().toFuture().get();

            final Account account = Account
                    .createFromPrivateKey(privateKey, networkType);
            final SignedTransaction signedTransaction = account
                    .sign(transferTransaction, generationHash);
  1. 署名が終わったら、トランザクションをネットワークへアナウンスします。
// replace with node endpoint
const nodeUrl = 'http://api-01.us-east-1.0.10.0.x.symboldev.network:3000';
const repositoryFactory = new RepositoryFactoryHttp(nodeUrl);

const transactionHttp = repositoryFactory.createTransactionRepository();

transactionHttp
    .announce(signedTransaction)
    .subscribe((x) => console.log(x), (err) => console.error(err));
// replace with node endpoint
const nodeUrl = 'http://api-01.us-east-1.0.10.0.x.symboldev.network:3000';
const repositoryFactory = new symbol_sdk_1.RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();
transactionHttp
    .announce(signedTransaction)
    .subscribe((x) => console.log(x), (err) => console.error(err));
            final TransactionRepository transactionRepository = repositoryFactory
                    .createTransactionRepository();
            transactionRepository.announce(signedTransaction).toFuture().get();
        }
symbol-cli transaction transfer --recipient-address TCHBDE-NCLKEB-ILBPWP-3JPB2X-NY64OE-7PYHHE-32I --mosaics 7cdf3b117a3c40cc::1 --message enjoy_your_ticket --max-fee 2000000 --sync
  1. トランザクションを監視しているターミナルウィンドウを確認します。トランザクションが承認されたら、次のコマンドで顧客がチケットを受け取ったかどうかを確認できます。
symbol-cli account info --profile customer

このユースケースを解決できたのでしょうか?

  • ✅ 各購入者の識別: 各購入者の Symbol アカウントの作成
  • ✅ チケットの転売防止: 転送不可能なモザイクの作成
  • ✅ 未認証なチケットとその複製: 一意なモザイクの作成

Symbol ビルドイン機能 の学習を続ける。