ScalarDL の適切なコントラクトを作成する方法に関するガイド
このページは英語版のページが機械翻訳されたものです。英語版との間に矛盾または不一致がある場合は、英語版を正としてください。
このドキュメントでは、ScalarDL のコントラクトを作成するためのガイドラインをいくつか示します。
ScalarDL のコントラクトとは何ですか?
ScalarDL のコントラクト (別名スマートコントラクト) は、単一のビジネスロジックを実装するために記述された、事前定義済みの基本コントラクトを拡張する Java プログラムです。コントラクトとその引数は、コントラクト所有者の秘密鍵で電子署名され、ScalarDL に渡されます。この仕組みにより、コントラクトは所有者のみが実行できるようになり、データ改ざんなどの悪意のある行為をシステムが検出できるようになります。
このドキュメントを参照する前に、ScalarDL 入門を参照して、ScalarDL とは何か、およびその基本用語を理解してください。
簡単なコントラクトを書く
コントラクトの書き方をよりよく理解するために、StateUpdater
コントラクトの例を詳しく見てみましょう。
public class StateUpdater extends JacksonBasedContract {
@Nullable
@Override
public JsonNode invoke(Ledger<JsonNode> ledger, JsonNode argument, @Nullable JsonNode properties) {
if (!argument.has("asset_id") || !argument.has("state")) {
// ContractContextException is the only throwable exception in a contract and
// it should be thrown when a contract faces some non-recoverable error
throw new ContractContextException("please set asset_id and state in the argument");
}
String assetId = argument.get("asset_id").asText();
int state = argument.get("state").asInt();
Optional<Asset<JsonNode>> asset = ledger.get(assetId);
if (!asset.isPresent() || asset.get().data().get("state").asInt() != state) {
ledger.put(assetId, getObjectMapper().createObjectNode().put("state", state));
}
return null;
}
}
基本コントラクト
Ledger データと Contract 引数の内部表現は String です。ただし、String を使用した構造化データの処理はエラーが発生しやすく、必ずしも簡単であるとは限りません。基本コントラクトでは、Ledger データと Contract 引数の他の扱いやすいデータ型を定義します。また、データ型と文字列間のシリアル化と逆シリアル化も管理します。
たとえば、上記の StateUpdater
コントラクトは、JacksonBasedContract
と呼ばれる基本コントラクトの1つに基づいています。これにより、Jackson の JsonNode形式で Ledger データと Contract 引数を処理できるようになります。
これを書いている時点では、以下に示す4つの基本コントラクトを提供しています。ただし、開発の生産性とパフォーマンスのバランスを適切に保つには、 JacksonBasedContract
を使用することをお勧めします。
基本コントラクトクラス | コントラクト引数のタイプ、コントラクトプロパティ、コントラクト出力、およびLedger データ | ライブラリ |
---|---|---|
JacksonBasedContract (おすすめ) | JsonNode | Jackson |
JsonpBasedContract | JsonObject | JSONP |
StringBasedContract | String | Java標準ライブラリ |
Contract (廃止された) | JsonObject | JSONP |
古い Contract はまだ利用可能ですが、現在は非推奨となっており、今後のメジャーバージョンで削除される予定です。したがって、上記の新しい (非推奨ではない) コントラクトを基本コントラクトとして使用することを強くお勧めします。
invoke
引数について
上に示したように、オーバーライドされた invoke
メソッドは、基礎となるデータベースと対話するための Ledger、コントラクト引数の JsonNode、およびコントラクトプロパティ用のオプションである JsonNode を受け取ります。
Ledger
は一連のアセットを管理するデータベース抽象化であり、各アセットは asset_id
と呼ばれるキーと age
と呼ばれる履歴バージョン番号によって識別されるレコードの履歴で構成されます。get
、put
、および scan
API を使用して Ledger
と対話できます。get
API は、指定されたアセットの最新のアセットレコードを取得するために使用されます。put
API は、指定されたアセットに新しいアセットレコードを追加するために使用されます。scan
API は、指定されたアセットを走査するために使用されます。この抽象化では Ledger にアセットレコードを追加できるだけであることに注意してください。したがって、ScalarDL のコントラクトを作成する前に、抽象化を使用してデータを設計することを常に推奨します。
コントラクト引数は、リクエスタによって指定されたコントラクトの実行時引数です。コントラクト引数は通常、ランタイム変数を定義するために使用されます。たとえば、銀行アプリケーションでは、支払いコントラクトが実行されるたびに、支払者と受取人が引数としてコントラクトに渡される場合があります。
コントラクトのプロパティは、コントラクトの静的変数です。これは、コントラクトのインスタンスごとの静的変数を定義するために使用できます。たとえば、同意管理アプリケーションでは、同意のためのビジネスロジックは一般的なコントラクトとして定義できますが、同意条件は実際のアプリケーションによって異なる場合があります。オプションのプロパ ティフィールドを使用すると、コントラクト内でハードコーディングせずに、各コントラクトインスタンスのクォーラムなどのコントラクト条件を定義できます。
StateUpdater
ロジックについて
StateUpdater
コントラクトは、最初に引数に適切な変数があるかどうか、およびアプリケーションコンテキストと一致しているかどうかをチェックし、適切に定義されていない場合は ContractContextException
をスローします。ContractContextException
はコントラクトからスロー可能な唯一の例外であり、要件が完全に満たされていないためにコントラクトの実行を再試行しないようシステムに通知するために使用されます。
次に、コントラクトはリクエスタから指定された asset_id
と state
を取得し、指定された asset_id
を持つ Ledger から asset
を取得します。また、アセットが存在しない場合、またはアセットの状態が現在の状態と異なる場合は、アセットの状態を更新します。
Ledger と対話するときにコントラクトは RuntimeException
に直面する可能性がありますが、コントラクト内でそれを捕らえるべきではありません。すべての例外は、ScalarDL エグゼキューターによって適切に処理されます。
このコントラクトは、指定されたアセットの状態を作成または更新するだけなので、リクエスタに何も返す必要はあり ません。したがって、この場合は null
を返すことができます。リクエスタに何かを返したい、かつ JacksonBasedContract
を使用する場合は、任意の JsonNode
を返すことができます。
アセットのグループ化
asset_id
の値は任意に定義できますが、アセットをグループ化する場合は、いくつかのルールを設けることをお勧めします。
たとえば、特定の世代にグループ化したい場合は、{asset_id}-0
のようにアセットに世代番号を追加します。
または、{org-id}-{asset_id}
のようなプレフィックスとして組織 ID を付けることで、組織ごとにグループ化することもできます。
例外処理
上で述べたように ContractContextException
をスローする場合を除いて、コントラクト内で例外処理を行うべきではないことに注意してください。
したがって、 Ledger
は、何らかの理由で続行できない場合に実行時 (チェックされていない) 例外をスローする可能性がありますが、例外はキャッチされるべきではありません。例外はコントラクト外で適切に処理されます。