Contract と Function のライフサイクルを管理する
このページは英語版のページが機械翻訳されたものです。英語版との間に矛盾または不一致がある場合は、英語版を正としてください。
このドキュメントでは、ScalarDL における Contract と Function のライフサイクルについて、作成や登録からバグ修正や機能追加が必要な場合の更新まで説明します。
作成
ScalarDL では、ビジネスロジックを Contract と Function という2種類の Java プログラムとして実装します。Contract は Ledger 内の改ざん検知可能なアセットレコードを管理し、Function は Contract と連携して ScalarDB を通じた外部データベース内の可変レコードを管理します。
Contract または Function を作成するには、Contract の場合は JacksonBasedContract、Function の場合は JacksonBasedFunction などの定義済みベースクラスを拡張する Java クラスを作成します。
Contract と Function の書き方の詳細については、以下を参照してください:
登録
Contract または Function を作成した後、使用する前に ScalarDL に登録する必要があります。
Contract を登録するには:
scalardl register-contract --properties client.properties --contract-id StateUpdater --contract-binary-name com.org1.contract.StateUpdater --contract-class-file build/classes/java/main/com/org1/contract/StateUpdater.class
Function を登録するには:
scalardl register-function --properties client.properties --function-id test-function --function-binary-name com.example.function.TestFunction --function-class-file /path/to/TestFunction.class
登録コマンドとオプションの詳細については、ScalarDL クライアントコマンドリファレンスを参照してください。
Contract の登録制約
Contract を登録する際、以下の制約に注意してください:
- 一意な Contract ID: 各 Contract には一意な Contract ID が必要です。既に存在する ID で Contract を登録しようとすると、登録は失敗します。
- 一貫したバイナリ名とバイトコード: あるバイナリ名が特定のバイトコードで既に登録されている場合、同じバイナリ名で異なるバイトコードを登録できません。ただし、同じバイナリ名で同じバイトコードで あっても、異なるクライアントや異なる Contract ID であれば登録できます。
Function の登録制約
Contract とは異なり、Function は同じ Function ID で再登録できます。動作は ScalarDL へのアクセス方法によって異なります:
- 特権ポート (デフォルト: 50052): Function は常に制限なく登録および上書きできます。
- 非特権ポート (デフォルト: 50051): Function の登録と上書きは管理者の設定によって制御されます。詳細については、名前空間に制限付きでアクセスするを参照してください。
更新
Contract と Function は ScalarDL において異なるアーキテクチャ上の役割を担っているため、更新のメカニズムが異なります。Contract は Ledger 内の改ざん検知可能なアセットレコードを管理し、ScalarDL はアセット更新の完全な履歴を再生して検証できる必要があるため、Contract は不変 (追記のみ) です。一方、Function は ScalarDB を通じて外部データベース内の可変レコードを管理するため、過去のバージョンを保持する必要がなく、上書きが可能です。
Contract を更新する
Contract は不変であるため、既存の Contract を変更したり上書きしたりできません。代わりに、新しい Contract ID と新しいバイナリ名で新しいバージョンの Contract を登録する必要があります。
バージョニングのベストプラクティス
Contract のバージョニングには、一般的に2つのアプローチがあります:
パッケージベースのバージョニング (本番環境に推奨): Java パッケージ名にバージョン番号を含めます。ScalarDL の HashStore や TableStore などの抽象化が内部的に使用する定義済み Contractもこのアプローチを採用しています。
例えば、元の Contract が com.example.contract.v1.StateUpdater にある場合、更新されたバージョンは com.example.contract.v2.StateUpdater になります。同様に、Contract ID も v1.StateUpdater や v2.StateUpdater のようにバージョンを反映する必要があります。
scalardl register-contract --properties client.properties --contract-id v2.StateUpdater --contract-binary-name com.example.contract.v2.StateUpdater --contract-class-file build/classes/java/main/com/example/contract/v2/StateUpdater.class
クラス名ベースのバージョニング (小規模やテストに適している): StateUpdaterV2 のように、クラス名にバージョン番号を直接追加します。このアプローチはよりシンプルですが、大規模プロジェクトではやや整理しにくくなる場合があります。
scalardl register-contract --properties client.properties --contract-id StateUpdaterV2 --contract-binary-name com.example.contract.StateUpdaterV2 --contract-class-file build/classes/java/main/com/example/contract/StateUpdaterV2.class
アプリケーションコードを更新する
新しい Contract バージョンを登録した後、新しい Contract ID を使用するよう にアプリケーションコードを更新します。例えば、ClientService を使用している場合は、executeContract メソッドに渡す Contract ID を更新します。
古い Contract バージョンは ScalarDL に登録されたまま残ります。これは意図的な設計です。ScalarDL はアセットの検証と履歴の再生のためにそれらを必要とします。古い Contract バージョンを削除しようとしないでください。
Function を更新する
Function は可変であるため、同じ Function ID で再登録することで更新できます。新しいバイトコードが古いバイトコードを上書きします。
scalardl register-function --properties client.properties --function-id test-function --function-binary-name com.example.function.TestFunction --function-class-file /path/to/TestFunction.class
Function を上書きする際、必要に応じてバイナリ名を変更することもできます。同じでなければならない識別子は Function ID のみです。
マルチテナント (名前空間) 構成では、非特権ポートを通じた Function の登録と上書きは管理者の設定によって制御されます。詳細については、名前空間に制限付きでアクセスするを参照してください。
更新された Contract と Function を実行する
Contract を更新した後は、実行時に新しい Contract ID を使用します。古い Contract ID は引き続き古いバージョンを参照します。
scalardl execute-contract --properties client.properties --contract-id v2.StateUpdater --contract-argument '{"asset_id":"some_asset", "state":3}'
Function を更新した後は、以前と同じ Function ID を使用でき、更新された Function が自動的に実行されます。
scalardl execute-contract --properties client.properties --contract-id v2.StateUpdater --contract-argument '{"asset_id":"some_asset", "state":3}' --function-id test-function --function-argument '{...}'
Contract と Function の実行の詳細につい ては、以下を参照してください: