【问题标题】:Corda IsRelevant() work around?Corda IsRelevant() 解决方法?
【发布时间】:2018-03-30 08:39:06
【问题描述】:

1.0 的 API 中有一些更改已删除 isRelevant()。最好的解决方法是什么?

给定一个用例:如果有 100 个参与方想要查看此可查询状态以及与之相关的所有更新(但只读且不需要签名),我是否需要将它们全部添加到参与者列表? “观察者”角色还不存在?对于仅查看静态参考数据的用例,是否有alsoInformed 或类似的东西?

这里的一般功能是一个共享的线性可查询状态,其中发行者拥有要更改/更新的主节点,该状态将传播到想要“订阅”这些更改的所有各方。我相信这可能适用于向“俱乐部”广播,但我认为俱乐部尚不存在,或者它们是否是网络地图的动态分组。

【问题讨论】:

    标签: corda


    【解决方案1】:

    在回答之前,我将介绍一些背景知识......平台中仍然存在相关性的概念。如您所知,在 Corda 中有两个数据持久性存储;存储服务和保管库。

    存储服务

    存储服务是一个键 -> 值存储,用于持久化数据,例如:

    • 序列化流状态机
    • 附件
    • 交易

    存储服务非常适合存储大量可以通过哈希索引和检索的序列化数据。但是,如果希望在其中一个存储对象中搜索数据,那就很尴尬了。例如。使用事务存储时,无法轻松搜索特定类型的事务输出状态。该方法将遍历所有事务,将它们一一反序列化,并按输出类型进行过滤。这很麻烦而且效率不高。这就是为什么存在 Vault 和相关性概念的原因!

    保险库

    保险库的存在是为了存储状态对象,而不是交易。有一个主 states 表,其中存储状态引用、事务 id(生成输出状态)和一些其他元数据,例如状态是否被消费(或不消费)。还有一个LinearStates 的表格和一个OwnableStates 的表格。此外,如果希望将 ORM 添加到他们的状态,则为反映 ORM 定义的每种状态对象创建一个数据库表。然后可以查询这些属性以从 Vault 中提取满足特定查询的状态,例如“任何债务都表明爱丽丝作为贷方尚未消费超过 1000 英镑”。这就是保险库的力量!

    相关性

    现在,并非节点收到的所有交易都会产生与该节点相关的状态。一个例子是支付与支付交易,其中 Alice 向 Bob 发送美元,而 Bob 向 Alice 发送英镑。由于 Bob 现在拥有 Alice 之前拥有的美元,这些美元现在与 Alice 无关。因此,Alice 不应该记录代表这些美元的输出状态,因为她不拥有这些美元的权利和义务。 Alice 所做的是将旧的美元状态标记为已消耗,因此它现在不会计入她的总美元余额,并且不能用作另一个交易的输入(因为它已经被花费了)。

    相关性在 Corda 中的工作原理

    因此,当一个节点接收到一个新交易时,它会将每个输出状态的participants 属性中定义的公钥与VaultService 知道的所有公钥相交。如果特定状态的结果集不为空,则该状态与节点相关。很简单。

    这意味着,如果一个节点收到一笔交易,其中他们的公钥未列在输出状态的参与者字段中,那么他们将不会将该输出状态存储在保险库中。但是,他们会将事务存储在事务存储中,并且仍然可以查询。

    OwnableStates 的相关性概念很简单,要么拥有它,要么不拥有它。代表多边协议的LinearStates 的概念更为复杂。在 M14 及以下版本中,可以在 LinearState 中覆盖 isRelevant 的功能,但在 V1 中,这已被删除,以支持一种更简单的方法,即仅将参与者密钥与保险库密钥进行比较(如上所述)。

    V1 方法对相关性的影响

    正如 OP 所指出的,在 V1 中,将有交易观察者的概念,其中不是状态参与者的节点仍然可以将状态存储在其保险库中并将其作为“第三方”状态进行查询。 IE。它不能被消耗或计入余额总计,但可以查询。与此同时,我们将不得不解决缺少该功能的问题,选项如下:

    1. 对于LinearStates,将所有预期的观察者添加到participants 列表中。然后,向状态对象添加一个名为consumers 的附加属性,它只包含可以在有效交易中使用此状态的参与者列表,即签署包含它的交易。然后,该状态的合约会将命令中的这些公钥与consumers 列表中的公钥进行比较。这样,所有观察者仍将状态存储在他们的保险库中。 FinalityFlow 会将此交易广播给所有participants。如果您不希望其他参与者知道观察者,可以使用随机生成的公钥。
    2. 对于OwnableStates,和Cash一样,participants中只能有一个身份,所有者。所以方法是使用FinalityFlow 将事务发送给一组观察者,然后这些观察者必须直接从事务中获取输出状态。繁琐但暂时的,因为我们目前正在研究事务观察器:https://r3-cev.atlassian.net/browse/CORDA-663

    【讨论】:

    • 我认为观察者彼此不了解是非常重要的,我从上面选项 1 的文本中假设您知道这是一种需要。最终解决方案是否也包括此属性?
    • 观察者可以被列为AnonymousParty实例。
    【解决方案2】:

    如果这是在代码中,这只是我所理解的一个稻草人。 即使用义务cordapp示例

    义务状态

    val consumers: List<AbstractParty> = listOf(lender, borrower)
    override val participants: List<AbstractParty> get() = listOf(lender, borrower, extraActor)
    

    合约代码验证

    override fun verify(tx: LedgerTransaction){
            val command = tx.commands.requireSingleCommand<Commands>()
            when (command.value) {
                is Obligation.Issue -> requireThat {
                    "The signers should only be the consumers for the obligation" using
                            (command.signers.toSet() == obligation.consumers.map { it.owningKey }.toSet())
                }
    

    添加命令指定签名者只需在 TX 创建期间成为消费者

    val utx = TransactionBuilder(notary = notary)
                        .addOutputState(state, OBLIGATION_CONTRACT_ID)
                        .addCommand(Obligation.Issue(), state.consumers.map { it.owningKey })
                        .setTimeWindow(serviceHub.clock.instant(), 30.seconds)
    

    这样,第一个 tx 允许 extraActor 将状态提交到账本中而无需签名。在未来的 tx 提案中,extraActor 可以在此处查询其状态表,并使用不同的命令提出状态生命周期的更改,这一次它可能需要所有参与者(如果需要)签署命令。即Obligation.DoSomethingExtra 命令,所有参与者签名(command.signers.toSet() == obligation.participants.map { it.owningKey }.toSet())

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-01
      • 1970-01-01
      • 2023-03-13
      • 2012-10-11
      • 1970-01-01
      • 2016-03-09
      • 2013-12-21
      • 2013-07-09
      相关资源
      最近更新 更多