ScalarDL のファンクションの書き方に関するガイド
このページは英語版のページが機械翻訳されたものです。英語版との間に矛盾または不一致がある場合は、英語版を正としてください。
このドキュメントでは、ScalarDL のファンクションを作成するためのガイドラインをいくつか示します。
ScalarDL のファンクションとは何ですか?
ScalarDL のファンクション(スマートファンクション)は、単一のビジネスロジックを実装するために記述された JacksonBasedFunction クラスのような定義済みのベースファンクションを拡張する Java プログラムです。Function は主に ScalarDL アプリケーションのデータを管理し、Contract はデータの証拠を管理します。これを見る前に、ScalarDL 入門と ScalarDL のコントラクトの書き方を参照して、ScalarDL とは何か、ScalarDL とコントラクトで何ができるかを理解してください。
背景
ScalarDL のコントラクトによって管理されるアセットには改ざん検知機能があり、追加のみが可能なため、さまざまなアプリケーションをモデル化する際にそのデータ構造が制限されます。さらに、改ざん証拠を保証するためにアセットを削除することはできません。多くの分散 Ledger プラットフォームは、Ledger の前に RDBMS などの別のデータベースを配置して、データベース内のアプリケーションのデータを処理し、証拠として Ledger にログを書き込むことでこの問題に対処しています。ただし、データベースと Ledger の間のデータの一貫性が常に維持されるとは限らないため、このスキームは理想的ではありません。致命的な障害により、アプリケーションのログが Ledger に存在しない場合があり、証拠として Ledger にログを書き込む目的が無効になります。ScalarDL は、アプリケーションのデータを管理するファンクションを導入し、ScalarDB で基盤となる分散 ACID トランザクションを利用してコントラクトとファンクションをアトミックに実行することで、別のアプローチで問題を解決します。
ファンクションを書く
ファンクションの書き方をよりよく理解するために、Payment
ファンクションを詳しく見てみましょう。
public class Payment extends JacksonBasedFunction {
private final String FROM_KEY_NAME = "from";
private final String TO_KEY_NAME = "to";
private final String AMOUNT_KEY_NAME = "amount";
private final String NAMESPACE_KEY_NAME = "namespace";
private final String TABLE_KEY_NAME = "table";
@Nullable
@Override
public JsonNode invoke(
Database<Get, Scan, Put, Delete, Result> database,
@Nullable JsonNode functionArgument,
JsonNode contractArgument,
@Nullable JsonNode contractProperties) {
// error handling is omitted
String fromId = contractArgument.get(FROM_KEY_NAME).asText();
String toId = contractArgument.get(TO_KEY_NAME).asText();
int amount = contractArgument.get(AMOUNT_KEY_NAME).asInt();
String namespace = contractProperties.get(NAMESPACE_KEY_NAME).asText();
String table = contractProperties.get(TABLE_KEY_NAME).asText();
Key fromKey = Key.ofText("id", fromId);
Key toKey = Key.ofText("id", toId);
// get the account balances
Optional<Result> account1 =
database.get(
Get.newBuilder().namespace(namespace).table(table).partitionKey(fromKey).build());
Optional<Result> account2 =
database.get(
Get.newBuilder().namespace(namespace).table(table).partitionKey(toKey).build());
// assumes that both accounts exist, but it should be checked in production code
long balance1 = account1.get().getInt("balance");
long balance2 = account2.get().getInt("balance");
if (balance1 - amount < 0) {
throw new ContractContextException(
"The account " + fromId + " does not have enough account balance.");
}
// transfer amount
balance1 -= amount;
balance2 += amount;
// update the account balances
database.put(
Put.newBuilder()
.namespace(namespace)
.table(table)
.partitionKey(fromKey)
.bigIntValue("balance", balance1)
.build());
database.put(
Put.newBuilder()
.namespace(namespace)
.table(table)
.partitionKey(toKey)
.bigIntValue("balance", balance2)
.build());
return null;
}
}
これは、ScalarDB API で記述された送金アプリケーションであり、指定された口座残高を取得し、2つの口座残高間で指定された金額を送金し、残高を更新します。ScalarDB API の詳細については、ScalarDB ドキュメントもお読みください。