簡単な銀行口座申請
このページは英語版のページが機械翻訳されたものです。英語版との間に矛盾または不一致がある場合は、英語版を正としてください。
概要
これは単純な銀行口座アプリケーションであり、scalardl
リポジトリにあります。ユーザーが実行できるアクションは、アカウントの作成、アカウント履歴の表示、アカウントへの資金の入金、アカウントからの資金の引き出し、アカウント間の資金の転送です。アカウントで実行されたすべてのアクションは ScalarDL に記録されます。これは、ブロックチ ェーンがブロックを記録する方法と似た方法で、アカウント履歴が改ざん検知可能な方法で記録されることを意味します。これは、アカウント履歴が (意図的かどうかに関わらず) 変更された場合、これを検出することが可能であることを意味します。
ここでは物事を簡単にするために、銀行がすべてのコントラクトを実行するための秘密鍵を保持していると仮定します (これがどのように機能するかについては、以下を参照してください)。おそらくこれは、この銀行アプリケーションを実際に使用する方法ではありません。この場合、悪意のあるアカウントマネージャーがユーザーのアカウント履歴を実際に変更する可能性があります。たとえば、単にアカウントを再作成し、偽のデータを入力するだけです。より意味のある設定は、銀行が口座に入金するための秘密鍵を所有し、各ユーザーが自分の秘密鍵を使用して引き出しと送金のコントラクトを登録することです。その場合、銀行のみが口座に資金を移動でき、ユーザーのみが口座から資金を移動できます。
このアプリケーションでは、次の5つのコントラクトを使用します。
これらのコントラクトは銀行によって登録され、銀行はそれぞれ、口座履歴の表示、口座の作成、口座への入金、口座間の資金移動、口座からの資金の引き出しを行うことができます。
このアプリケーションの全体的なアーキテクチャは次のようになります。(この使用例は簡素化のためのものであり、実際には少し異なる可能性があることに再度注意してください。)
このサンプルアプリケーションの前提条件
- Eclipse Temurin の OpenJDK LTS バージョン (8, 11, 17, or 21)
- 上記の LTS バージョンの使用をお勧めしますが、他の非 LTS バージョンでも動作する可能性があります。
- また、他の JDK でもこのサンプルアプリケーションは動作するはずですが、テストは行っていません。
アプリケーションを試してみる
ScalarDL Client SDKをダウンロードします。ScalarDL が実行されていることを確認し、必要なコントラクトをすべて実行して登録します。
./gradlew build
cd contract
SCALAR_SDK_HOME=/path/to/scalardl-client-sdk ./register
IntelliJ (または選択した IDE) を使用するか、プロジェクトのホームディレクトリで gradle bootRun
を実行して、アプリケーションを実行します。アプリと対話するために HTTP リクエストを送信できるサーバーを localhost:8080
上に作成する必要があります。詳細については、API ドキュメントを参照してください。HTTP リクエストを作成するには、Postman が便利です。
ScalarDL アプリケーションの作成に関する短いチュートリアル
Spring Boot を使用して、コントラクトと対話する Web サービスを作成することにしました。もちろん、これが唯一の選択肢ではありません。別の選択肢は、たとえば アセット管理アプリケーションで行われたように、コマンドラインインターフェースを作成することです。そこには、ScalarDL 用のアプリケーションを作成するための非常に優れたチュートリアルもあります。
このチュートリアルでは、Web サービスまたはコマンドラインインターフェースのレベルでの詳細については説明せず、代わりにアプリケーションと ScalarDL の間の対話に焦点を当てます。コントラクトの作成方法、コントラクトの登録方法、そして ScalarDL SDK を使用してアプリケーションからこれらのコントラクトを呼び出す方法について説明します。
コントラクト
コントラクトは、 JacksonBasedContract
クラスを拡張し、 invoke
メソッドをオーバーライドする Java クラスです。Deposit.java
コントラクトを詳しく見てみましょう。
package com.scalar.application.bankaccount.contract;
import com.fasterxml.jackson.databind.JsonNode;
import com.scalar.dl.ledger.statemachine.Asset;
import com.scalar.dl.ledger.contract.JacksonBasedContract;
import com.scalar.dl.ledger.exception.ContractContextException;
import com.scalar.dl.ledger.statemachine.Ledger;
import java.util.Optional;
import javax.annotation.Nullable;
public class Deposit extends JacksonBasedContract {
@Override
public JsonNode invoke(
Ledger<JsonNode> ledger, JsonNode argument, @Nullable JsonNode properties) {
if (!argument.has("id") || !argument.has("amount")) {
throw new ContractContextException("a required key is missing: id and/or amount");
}
String id = argument.get("id").asText();
long amount = argument.get("amount").asLong();
if (amount < 0) {
throw new ContractContextException("amount is negative");
}
Optional<Asset<JsonNode>> asset = ledger.get(id);
if (!asset.isPresent()) {
throw new ContractContextException("account does not exist");
}
long oldBalance = asset.get().data().get("balance").asLong();
long newBalance = oldBalance + amount;
ledger.put(id, getObjectMapper().createObjectNode().put("balance", newBalance));
return getObjectMapper()
.createObjectNode()
.put("status", "succeeded")
.put("old_balance", oldBalance)
.put("new_balance", newBalance);
}
}
このコントラクトが適切に機能するためには、ユーザーはアカウントの id
と amount
を指定する必要があります。したがって、最初に行うことは、引数にこれら2つのキーが含まれているかどうかを確認し、含まれていない場合は ContractContextException
をスローすることです。
注記: ContractContextException
はコントラクト内で唯一スロー可能な例外であり、回復不可能なエラーが発生した場合は常にスローされる必要があります。
したがって、id
と amount
があると仮定して、amount
に対して簡単な非負のチェックを行い、負の場合は再度 ContractContextException
をスローします。これで、ledger
を操作する準備が整いました。
ledger
で呼び出すことができるメソッドは3つあります: get(String s)
、 put(String s, JsonNode jsonNode)
、および scan(AssetFilterassetFilter)
です。get(String s)
は Ledger からアセット s
を取得します。put(String s, JsonNode jsonNode)
は、アセット s
をデータ jsonNode
に関連付け、アセットの age を増やします。scan(AssetFilterassetFilter)
は、AssetFilter
で指定されたアセットの履歴のバージョンを返します。
注記: Ledger ではブラインドライトは許可されていません。つまり、特定のアセットに対して put
を実行する前に、まずそのアセットを get
する必要があります。さらに、 scan
は読み取り専用コントラクトでのみ許可されます。つまり、1つのコントラクトで scan
と put
の両方を行うことはできません。
コントラクトの残りの部分は単純な方法で進められます。まず Ledger からアセットを get
し、現在の残高を取得し、それに預金額を追加し、最後に新しい残高でアセットを Ledger に put
します。
最後に JsonNode
を返す必要があります。JsonNode
に何が含まれるかは、コントラクトの設計者次第です。ここでは、status
メッセージ、old_balance
、および new_balance
を含めることにしました。
必要に応じて、このアプリケーションが使用する他のコントラクトを scalardl
リポジトリ内のこのサンプルの contract
フォルダーで参照できます。
コントラクトを作成したら、それをコンパイルする必要があります。これは次のようにして実行できます。
./gradlew build
認定資格とコントラクトの登録
これでコントラクトを作成し、コンパイルしたはずです。ただし、それらを実行する前に、ScalarDL ネットワークに登録する必要があります。ScalarDL Client SDK client/bin
ディレクトリで利用可能なツールを利用して、コントラクトを登録して実行します。このディレクトリにアクセスできることを確認してください。
ここで、証明書 (例: client.pem
) とそれに対応する秘密鍵 (例: client-key.pem
)、および ScalarDL を起動して実行する必要があります。構成に合わせて client.properties
(conf
ディレクトリにあります) を編集します。次のような行が含まれている必要があります。
scalar.dl.client.server.host=localhost
scalar.dl.client.server.port=50051
scalar.dl.client.cert_holder_id=alice
scalar.dl.client.cert_path=conf/client.pem
scalar.dl.client.private_key_path=conf/client-key.pem
すべてが正しく設定されていれば、次のように証明書を ScalarDL ネットワークに登録できるはずです。
cd contract
${SCALAR_SDK_HOME}/client/bin/register-cert --properties ../conf/client.properties