在 Corda 交易中,特定的状态转换是否与特定的命令相关联?

In a Corda transaction are particular state transitions associated with partcular commands?

commands webinar 指出(在 3:10 左右)"input and output states are always grouped by type and that a command is required for each group." 叙述者似乎暗示,如果交易由多个命令组成,那么每个命令将与一个不同的子集相关联交易中提出的状态转换。

然而LedgerTransaction的结构似乎并没有捕捉到这样的事物观。它由完全独立的 inputsoutputscommands 列表组成。没有任何内容表示特定命令与特定输入或输出状态之间的关联。

在我的合约代码中,我可以按类型对状态进行分组,例如:

override fun verify(tx: LedgerTransaction) {
    val fooStates = tx.inputsOfType<FooState>()
    val barStates = tx.inputsOfType<BarStates>()

但我只是根据选择进行分组 - 我不必这样做,也没有将这些组与特定命令联系起来。

那么当网络研讨会说 "a command is required for each group" 时指的是什么?

如果命令和状态转换之间的关系如网络研讨会中所述那样存在,那么签名与命令相关联的含义就会很清楚。然而实际上,人们并没有在每个命令的基础上签署特定的转换,因为 LedgerTransaction class 没有捕捉到这种关系。

在关键概念中 section on commands 有一个优惠券命令和一个支付命令,并且必须在债券状态转换上签字的一组人可能与需要签字的一组人不同,这是有道理的签署现金状态转换。但是在代码中,没有任何内容将优惠券命令与与命令关联的签名者签名时同意的特定状态联系起来。

这个规定的要求是每个组 必须 有一个相关的命令只是开发者 应该 在他们的合同验证逻辑中实现的东西而不是是人们试图在交易结构中捕捉到的东西吗?

好问题。

您谈到了合同内的分组,这是正确的,它取决于合同的实施,您只需要进一步扩展它以根据交易中的命令强制要求哪些方签署。

因此,您的验证函数可能类似于以下 Option CorDapp 示例中合约的简化版本:

override fun verify(tx: LedgerTransaction) {

    val command = tx.commands.requireSingleCommand<Commands>()

    when (command.value) {
        is Commands.Issue -> {
            requireThat {
                val cashInputs = tx.inputsOfType<Cash.State>()
                val cashOutputs = tx.outputsOfType<Cash.State>()
                "Cash.State inputs are consumed" using (cashInputs.isNotEmpty())
                "Cash.State outputs are created" using (cashOutputs.isNotEmpty())

                val option = tx.outputsOfType<OptionState>().single()
                "The issue command requires the issuer's signature" using (option.issuer.owningKey in command.signers)
            }
        }

        is Commands.Trade -> {
            requireThat {
                val cashInputs = tx.inputsOfType<Cash.State>()
                val cashOutputs = tx.outputsOfType<Cash.State>()
                "Cash.State inputs are consumed" using (cashInputs.isNotEmpty())
                "Cash.State outputs are created" using (cashOutputs.isNotEmpty())

                val inputOption = tx.inputsOfType<OptionState>().single()
                val outputOption = tx.outputsOfType<OptionState>().single()
                "The transfer command requires the old owner's signature" using (inputOption.owner.owningKey in command.signers)
                "The transfer command requires the new owner's signature" using (outputOption.owner.owningKey in command.signers)
            }
        }

        else -> throw IllegalArgumentException("Unknown command.")
    }
}

我们首先从事务中提取命令(或多个命令),这为我们提供了上下文。

基于此,我们可以从输入或输出中提取我们感兴趣的状态,例如cash/option 并开始检查我们的约束是否得到满足。

您可以在 https://github.com/CaisR3/cordapp-option 找到上述示例的完整版本,合约代码可以在 base\src\main\kotlin\net\corda\option\base\contract\OptionContract.kt

找到