我有一个用例,在一个原子事务中,我想将两个或多个相同类型的状态转换到不同的生命周期。 (即)
val x : SomeState
val y : SomeState
x
应通过Command.Approve
y
应转换为使用Command.Audit
在verifyApprove
上运行x
时,合约代码如何仅在verifyAudit
上运行y
。
可以有无限数量的SomeState
可以转换到同一原子事务中的不同生命周期。
我是否必须使Command.Approve
具有带List<UniqueIdentitifer>
的构造函数,以便它可以确定运行其相应验证函数的状态。
随后在流程中填充命令?
答案 0 :(得分:0)
每个verify
函数都会完整地验证事务,而不是其各个状态。但是,您可以在verify
内轻松编写逻辑来控制每种状态类型的检查方式。例如,如果XState
和YState
州共享相同的合同,您可以执行以下操作:
class XAndYContract: Contract {
override fun verify(tx: LedgerTransaction) {
val inputXStates = tx.inputsOfType<XState>()
val outputXStates = tx.outputsOfType<XState>()
val inputYStates = tx.inputsOfType<YState>()
val outputYStates = tx.outputsOfType<YState>()
requireThat {
"All XState inputs are unapproved." using (inputXStates.all { it.approved == false })
"All XState outputs are approved" using (outputXStates.all { it.approved == true })
"All YState inputs are unaudited." using (inputYStates.all { it.audited == false })
"All YState outputs are audited" using (outputYStates.all { it.audited == true })
}
}
}
这只是一个例子。您可以使用Java / Kotlin的全部功能来控制检查哪些状态以及如何检查。
另一种选择是将逻辑拆分为两个合同 - XContract
和YContract
。然后你会:
class XContract : Contract {
override fun verify(tx: LedgerTransaction) {
val inputXStates = tx.inputsOfType<XState>()
val outputXStates = tx.outputsOfType<XState>()
requireThat {
"All XState inputs are unapproved." using (inputXStates.all { it.approved == false })
"All XState outputs are approved" using (outputXStates.all { it.approved == true })
}
}
}
和
class YContract : Contract {
override fun verify(tx: LedgerTransaction) {
val inputYStates = tx.inputsOfType<YState>()
val outputYStates = tx.outputsOfType<YState>()
requireThat {
"All YState inputs are unaudited." using (inputYStates.all { it.audited == false })
"All YState outputs are audited" using (outputYStates.all { it.audited == true })
}
}
}
编辑:上面的示例假设有两种类型的状态。假设只有一种状态类型:
class MyState(val lifecycle: Lifecycle, override val linearId: UniqueIdentifier) : LinearState {
override val participants = listOf<AbstractParty>()
}
Lifecycle
定义为:
enum class Lifecycle {
ISSUED, AUDITED, APPROVED
}
我们希望强加规则,即在每个事务中,ISSUED
阶段中的任何输入都会转换为APPROVED
,并且APPROVED
阶段中的任何输入都会转换为{{ 1}}。
我们可以使用AUDITED
:
groupStates
class MyContract : Contract {
override fun verify(tx: LedgerTransaction) {
val groups = tx.groupStates { it: MyState -> it.linearId }
requireThat {
for (group in groups) {
val inputState = group.inputs.single()
val outputState = group.outputs.single()
when (inputState.lifecycle) {
Lifecycle.ISSUED -> {
"Issued states have been transitioned to approved" using (outputState.lifecycle == Lifecycle.APPROVED)
}
Lifecycle.APPROVED -> {
"Approved states have been transitioned to audited" using (outputState.lifecycle == Lifecycle.AUDITED)
}
}
}
}
}
}
的工作原理是根据某些规则将输入和输出分组在一起。在我们的例子中,我们将共享相同groupStates
的输入和输出分组。然后我们可以检查每个输入是否已正确演变为相应的输出。
答案 1 :(得分:0)
要实现该功能,您只需使用命令中的switch语句即可。例如,在验证(tx)中,您可以执行以下操作:
when (command.value) {
is Commands.Approve -> verifyApprove(tx, setOfSigners)
is Commands.Audit -> verifyAudit(tx, setOfSigners)
else -> throw IllegalArgumentException("Unrecognised command")
}
虽然命令可以定义如下:
interface Commands : CommandData {
class Issue : TypeOnlyCommandData(), Commands
class Transfer : TypeOnlyCommandData(), Commands
}
并在verifyApprove()和verifyAudit()中,您可以进行验证。
答案 2 :(得分:0)
我尝试将状态传递给命令本身,以便我们知道命令需要注意哪些状态。在验证方法中,然后不要检查单个命令。
interface Commands : CommandData {
class Create(val outputStates:List<MyState>): TypeOnlyCommandData(), Commands
class Update(val inOutStates:List<InOutState<MyState>>): TypeOnlyCommandData(), Commands
}
................
@CordaSerializable
data class InOutState<T: ContractState>(val inputState: T, val outputState:T)
............
tx.commands.forEach {
when (it.value) {
is Commands.Create -> {
val cmd = it.value as Commands.Create
requireThat{
"Output states must be present" using (cmd.outputStates.isNotEmpty())
}
}
}
答案 3 :(得分:0)
另一种模式是将Corda contract Command设置为State Object,并在合同验证期间由Command进行分组
@CordaSerializable
interface CommandAwareState<T:CommandData>: LinearState,QueryableState{
val command: T
}
============
interface LinearStateCommands<T : LinearState> : CommandData {
fun verify(inOutStates: List<InOutState<T>>, tx: LedgerTransaction)
}
===========
data class StateA(val attribX: String, val attribY: String
, override val command: StateAContract.Commands =
StateAContract.Commands.None()):
CommandAwareState<StateAContract.Commands>
============
open class StateAContract : Contract {
companion object {
@JvmStatic
val CONTRACT_ID = "com.myproj.contract.StateAContract"
}
interface Commands : LinearStateCommands<DocumentState> {
class None(): TypeOnlyCommandData(), Commands{
override fun verify(inOutState: List<InOutState<StateA>>, tx:
LedgerTransaction) {
requireThat {
"There should not be any Input and Outputs" using
(inOutState.isEmpty())
}
}
}
class Create(): TypeOnlyCommandData(), Commands{
override fun verify(inOutStates: List<InOutState<DocumentState>>, tx:
LedgerTransaction) {
//WRITE Contract verification
}
}
override fun verify(tx: LedgerTransaction) {
tx.matchLinearStatesByCommand(DocumentState::class.java).forEach{
it.key.verify(it.value,tx)
}
}
}
==========
inline fun <T,reified K : CommandAwareState<T>> LedgerTransaction.matchLinearStatesByCommand(ofType: Class<K>): Map<T,List<InOutState<K>>>{
groupStates<K,UniqueIdentifier> { it.linearId }.let {
var mapByCommand = mutableMapOf<T,MutableList<InOutState<K>>>()
it.forEach {
if(mapByCommand.containsKey(it.outputs.single().command)){
mapByCommand.get(it.outputs.single().command)?.add(InOutState(it.inputs.noneOrSingle(),it.outputs.noneOrSingle()))
}else{
mapByCommand.put(it.outputs.single().command, mutableListOf(InOutState(it.inputs.noneOrSingle(),it.outputs.noneOrSingle())))
}
}
return mapByCommand
}
}