記事の概要
Cordaの公式ドキュメントに沿って、CorDappを自作してみた。
この記事では、前回の続きとしてcontractを作成する所までを記載する。
公式ドキュメント
https://docs.corda.net/_static/corda-developer-site.pdf
(主に第5章 「Getting started developing CorDapps」と第6章「KEY CONCEPTS」に沿って実施。)
contractの概要
1.「contract」とは?
contractは、「statesをどのように作成し、展開するか」を定義したオブジェクト。
各トランザクションの正否はcontractの内容に従って判断される。また、入力側のstatesと出力側のstatesのcontractが
すべて有効とみなされる必要がある。
2.contractの記述について
contractコードは、任意のJVM言語で記述できる。(Java/Kotlinなど)
contractの実装
CorDappを公式ドキュメントの「5.2.3 Step Three: Creating contracts」に倣ってコーディングしてみる。
ちなみに、プログラミング言語はKotlin。
package com.template.contracts
import com.template.states.CarState
import net.corda.core.contracts.CommandData
import net.corda.core.contracts.Contract
import net.corda.core.contracts.requireSingleCommand
import net.corda.core.contracts.requireThat
import net.corda.core.transactions.LedgerTransaction
class CarContract : Contract {
companion object {
const val ID = "com.template.contracts.CarContract" ※1
}
override fun verify(tx: LedgerTransaction) { ※2
val command = tx.commands.requireSingleCommand<Commands>().value ※3
when(command) { ※4
is Commands.Issue ※4 -> requireThat { ※5
"There should be no input state" using (tx.inputs.isEmpty())
"There should be one input state" using (tx.outputs.size == 1)
"The output state must be of type CarState" using (tx.outputs.get(0).data is CarState)
val outputState = tx.outputs.get(0).data as CarState
"The licensePlateNumber must be seven characters long" using (outputState.licensePlateNumber.length == 7)
}
}
}
interface Commands : CommandData {
class Issue : Commands
}
}
※1:contractを一意的に識別するためのIDを動的に生成する。(「companion object」は1つのクラスに1つだけ宣言可能なオブジェクト)
※2:LedgerTransactionをオーバーライドする。
※3:「command」にLedgerTransactionのrequireSingleCommandの値を設定する。
※4:whenで「command」を判定。「Commands.Issue(新しく資産状態を発行するクラス)」である場合、後続の処理に遷移する。
※5:requireThatに、トランザクションの定義を記述する。ここで定義されているのは以下の内容
5-1:入力stateは未入力であること。
5-2:出力stateは1つであること
5-3:出力stateのデータ型は、CarStateであること。
5-4:出力state中の「licensePlateNumber」の長さは7であること。
終わりに
次回はflowの作成から再開する予定。