はじめに (対象読者・この記事でわかること)
この記事は、R3 Cordaのプラットフォーム上で開発を行っている、またはこれから開発を始めようとしているエンジニアの方々を対象としています。特に、CordaのState(状態)のライフサイクル、とりわけ「UNCONSUMED」(未消費)から「CONSUMED」(消費済み)へと遷移するメカニズムについて理解を深めたいと考えている読者におすすめです。
この記事を読むことで、以下の点が明確になります。
- CordaにおけるStateの基本的な役割と、そのライフサイクル。
- Stateが「UNCONSUMED」状態から「CONSUMED」状態へと遷移する具体的な条件。
- Transaction(トランザクション)の生成と、Stateの消費・生成の関係性。
- Stateのステータス変更が、Cordaネットワークにおけるデータの永続性や整合性にどのように影響するか。
Cordaは、プライベートなブロックチェーンプラットフォームとして、金融業界を中心に様々なユースケースで活用されています。その根幹をなすStateの管理メカニズムを正確に理解することは、安全かつ効率的な分散型アプリケーション(DApp)を開発する上で不可欠です。本記事が、読者のCorda開発における理解の一助となれば幸いです。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。
- Javaプログラミングの基本的な知識
- ブロックチェーンの基本的な概念(トランザクション、台帳など)
- Cordaの基本的なアーキテクチャに関する概要理解(任意ですが、あるとより理解が深まります)
CordaにおけるStateとは?その役割とライフサイクル
Cordaは、トランザクションを通じて共有台帳上のデータを更新していくプラットフォームです。この「データ」の核となるのが「State」です。Stateは、特定の時点における共有台帳上の永続的な事実を表現します。例えば、ある契約における当事者、契約金額、締結日、あるいはある資産の所有権などがStateとして表現されます。
Stateの特性
CordaのStateは、以下の特徴を持っています。
- 不変性 (Immutability): 一度生成されたStateは、直接変更されることはありません。Stateの変更は、常に新しいStateの生成と古いStateの消費という形で実現されます。
- 公開範囲 (Visibility): Stateは、そのStateに関与するノード(当事者)のみが認識できます。これは、Cordaがプライバシーを重視しているためです。
- バージョン管理 (Versioning): Stateは、トランザクションによって生成・消費されるたびに、新しいバージョンが生成されます。これにより、共有台帳上のデータの履歴を追跡できます。
Stateのライフサイクル
CordaにおけるStateのライフサイクルは、基本的に「生成(Creation)」、「消費(Consumption)」、「再生成(Re-creation)」の連続です。
- 生成 (Creation): 新しいStateは、トランザクションによって生成されます。これは、新たな契約の締結や、資産の移転など、共有台帳上に新しい事実を記録する際に発生します。
- 消費 (Consumption): 既存のStateは、新しいトランザクションによって「消費」されることがあります。これは、Stateが表す事実がもはや有効でなくなった(例:契約が満了した、資産が別の当事者に移転した)ことを意味します。
- 再生成 (Re-creation): Stateが消費された後、そのStateの情報を基にして、新しいStateが生成されることがあります。例えば、資産の所有権が移転した場合、古いStateは消費され、新しい所有権を持つ新しいStateが生成されます。
Stateのステータス: UNCONSUMEDとCONSUMED
CordaのStateは、共有台帳上で「UNCONSUMED」または「CONSUMED」というステータスを持ちます。
- UNCONSUMED (未消費): これは、現在有効であり、かつ新しいトランザクションの入力として使用できるStateを指します。共有台帳上の「現在の有効な状態」を表します。
- CONSUMED (消費済み): これは、過去のトランザクションによって消費され、もはや新しいトランザクションの入力として使用できないStateを指します。これは、Stateが表す事実が更新または無効になったことを意味します。
Stateが"UNCONSUMED"から"CONSUMED"に変更される条件
Cordaにおいて、Stateが「UNCONSUMED」状態から「CONSUMED」状態へと変更されるのは、そのStateが、有効なトランザクションの入力(input)として参照され、かつそのトランザクションが共有台帳にコミットされたときです。
これをより具体的に、技術的な観点から解説します。
トランザクションの構造とStateの入力・出力
Cordaのトランザクションは、基本的に以下の要素で構成されます。
- Inputs: 消費されるStateのリスト。これらのStateは、トランザクションが実行される前に「UNCONSUMED」である必要があります。
- Outputs: 新たに生成されるStateのリスト。これらのStateは、トランザクションが成功した後に「UNCONSUMED」となります。
- Commands: トランザクションの意図を表現し、トランザクションの妥当性を検証するための命令。Stateの変更権限などを定義します。
- Signatures: トランザクションの参加者(当事者)による署名。
UNCONSUMEDからCONSUMEDへの遷移メカニズム
-
Stateの特定と参照: まず、あるトランザクションを生成する際、開発者は「どのようなStateを更新・変更したいか」を定義します。これは、トランザクションの
inputsフィールドに、既存の「UNCONSUMED」Stateを指定することによって行われます。例えば、ある資産の所有権をAさんからBさんに移転させる場合、まずAさんが所有しているState(UNCONSUMED)をトランザクションの入力として指定します。 -
トランザクションの構築と署名: トランザクションの入力(UNCONSUMED State)と、それに基づいて生成される出力(新しいUNCONSUMED State)が定義された後、トランザクションの当事者(この例ではAさんとBさん)は、トランザクションの有効性を検証し、それぞれ署名を行います。この検証プロセスでは、指定された入力Stateが確かにUNCONSUMEDであること、そしてCommandsがStateの変更を許可していることなどが確認されます。
-
トランザクションのコミット: 必要な署名がすべて集まった(あるいは、トランザクションの設計によっては一部の署名でコミット可能な場合もあります)トランザクションは、ネットワーク上の「オブザーバー」ノード(通常はネットワークマップサービスや、トランザクションを検証・永続化する役割を持つノード)にブロードキャストされます。
-
Stateのステータス変更: オブザーバーノードは、トランザクションの妥当性を最終的に検証し、共有台帳にコミットします。このコミットプロセスにおいて、トランザクションの
inputsフィールドにリストアップされていたStateは、そのライフサイクルを終え、「UNCONSUMED」から「CONSUMED」へとステータスが変更されます。同時に、outputsフィールドにリストアップされていた新しいStateは、共有台帳上に新規に記録され、「UNCONSUMED」というステータスで利用可能になります。
この一連のプロセスこそが、Stateの「UNCONSUMED」から「CONSUMED」への遷移を決定づける根幹です。
具体的なシナリオ例
シナリオ1:契約の満了
- 初期状態: 契約A(UNCONSUMED)が存在する。
- トランザクションの目的: 契約Aを終了させる。
- トランザクションの構成:
- Inputs: 契約A(UNCONSUMED)
- Outputs: 契約終了を示す新しいState(例: 終了ステータスを持つState、あるいは何も生成しない場合もある)
- Commands: 契約終了を許可するCommand
- 結果: トランザクションがコミットされると、契約A(UNCONSUMED)はCONSUMEDとなります。
シナリオ2:資産の移転
- 初期状態: 資産Xを所有するState B(UNCONSUMED)が存在する。
- トランザクションの目的: 資産Xを現在の所有者から新しい所有者に移転させる。
- トランザクションの構成:
- Inputs: 資産Xを所有するState B(UNCONSUMED)
- Outputs: 新しい所有者(例:Cさん)が資産Xを所有することを示すState C(UNCONSUMED)
- Commands: 資産移転を許可するCommand(所有者、または関係者の署名が必要)
- 結果: トランザクションがコミットされると、State B(UNCONSUMED)はCONSUMEDとなり、State C(UNCONSUMED)が新たに生成され、Cさんの所有物となります。
StateがCONSUMEDになった後の状態
CONSUMEDとなったStateは、共有台帳上には存在し続けますが、それ以上直接新しいトランザクションの入力として利用することはできません。これは、データの不変性を保証し、共有台帳の整合性を保つために重要です。過去のトランザクションやStateの履歴を追跡したい場合は、CONSUMEDとなったStateの情報や、そのStateを消費したトランザクションを参照することで可能です。
まとめ
本記事では、R3 CordaのStateが「UNCONSUMED」から「CONSUMED」へと遷移する条件について、そのメカニズムを詳細に解説しました。
- Stateの不変性とライフサイクル: CordaのStateは不変であり、更新は常に新しいStateの生成と古いStateの消費によって行われます。
- UNCONSUMEDとCONSUMED: 「UNCONSUMED」は現在有効で入力として利用可能なState、「CONSUMED」は過去のトランザクションで消費されたStateを指します。
- 遷移のトリガー: Stateが「UNCONSUMED」から「CONSUMED」へ遷移するのは、そのStateが有効なトランザクションの入力として参照され、そのトランザクションが共有台帳にコミットされたときです。
- トランザクションによる管理: トランザクションの入力(Inputs)として指定されたUNCONSUMED Stateは、トランザクションのコミット時に自動的にCONSUMEDとなり、出力(Outputs)で生成された新しいStateはUNCONSUMEDとなります。
この記事を通して、CordaにおけるState管理の基本と、データが共有台帳上でどのように更新されていくのかについての理解を深めていただけたことと思います。このStateの遷移メカニズムを正確に把握することは、安全で信頼性の高い分散型アプリケーションを構築する上で、開発者が必ず押さえておくべき重要なポイントです。
今後は、CordaにおけるStateの永続化、Stateの検索、およびより複雑なトランザクションフローにおけるStateの管理について、さらに掘り下げた記事も検討していきたいと考えております。
参考資料
