ScalarDL の適切なコントラクトを作成する方法に関するガイド
このページは英語版のページが機械翻訳されたものです。英語版との間に矛盾または不一致がある場合は、英語版を正としてください。
このドキュメントでは、ScalarDL のコントラクトを作成するためのガイドラインをいくつか示します。
ScalarDL のコントラクトとは何ですか?
ScalarDL のコントラクト (別名スマート コントラクト) は、事前定義された基本コントラクトを拡張する Java プログラムです (ContractBase クラス) は、単一のビジネス ロジックを実装するために記述されています。 コントラクトとその引数は、コントラクト所有者の秘密キーでデジタル署名され、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 のコントラクトを作成する前に、抽象化を使用してデータを設計することを常に推奨します。
コントラクト引数は、リクエスタによって指定されたコントラクトの実行時引数です。 コントラクト引数は通常、ランタイム変数を定義するために使用されます。 たとえば、銀行アプリケーションでは、支払いコントラクトが実行されるたびに、支払者と受取人が引数としてコントラクトに渡される場合があります。
コントラクトのプロパティは、コントラクトの静的変数です。 これは、コントラクトのインスタンスごとの静的変数を定義するために使用できます。 たとえば、契約アプリケーションでは、契約のビジネス ロジックは一般的な契約として定義できますが、契約条件は実際のアプリケーションによって異なる場合があります。 オプションのプロパティ フィールドを使用すると、契約内でハードコーディングせずに、各契約インスタンスのクォーラムなどの契約条件を定義できます。