有没有办法尝试通过 ID 获取合同并且在合同处于非活动状态时不会失败?
Is there a way to try to fetch a contract by ID and not fail if the contract is inactive?
对于合约密钥,有两个函数 fetchByKey
和 lookupByKey
,后者允许我处理否定查找。我没有看到对合同 ID 执行相同操作的 lookup : (Template t) => ContractId t -> Update (Optional t)
函数。
我也没有看到允许我处理失败的 fetch
调用的 try-catch 机制。
如何在不重新实现整个 DAML 逻辑客户端的情况下避免交易失败?
这个问题有很多要解开的问题:
- 为什么没有
lookup
?
- 为什么没有 try-catch 块?
- 交易失败是可以避免的吗?
- 如何在不复制合约逻辑的情况下编写账本客户端?
lookupByKey
和提议的 lookup
函数允许交易提交者对合约做出不存在的断言。来自 lookupByKey
的 None
断言特定键不存在,来自 lookup
的 None
断言特定 ContractId
不存在。最大的区别在于合约的合约密钥包括密钥维护者,即验证查找的各方。因此很清楚谁必须授权 lookupByKey
,以及谁验证否定结果。对于 lookup
,ContractId
没有关联方,因此没有合理的授权或验证规则。
较弱的版本是 fetchIfNotArchived : (Template t) => ContractId t -> Update (Optional t)
,如果 id 未知,则失败;如果合同 id 已存档,则 returns None
。 DAML 交易在当前分类帐状态上是确定性的,当前分类帐状态是当前所有活动合约的集合。 fetchIfNotArchived
之类的函数会在 DAML 账本模型中引入不存在合约和存档合约的区别,因此账本状态将从一开始就从所有活跃合约变为整个账本。 DAML 账本不再被 t运行 分类并随时间线性增长,这是不可取的。
使用 try-catch 块,我们 运行 遇到了非常相似的问题。假设我有某种试探。我可以写这个函数:
lookup : (Template t) => ContractId t -> Update (Optional t)
lookup cid = do
try do
c <- fetch cid
return (Some c)
catch
return None
如上所述,没有人可以合理地授权或验证提交者是否遵循了正确的路径。所以这样的 try-catch 必须是 "unchecked",这意味着提交者可以自由选择是走 try
还是 catch
路径。您已经可以通过传递存在来模拟它:
maybeLookup : (Template t) => ContractId t -> Bool -> Update (Optional t)
maybeLookup cid cidIsKnown = if cidIsKnown
then do
c <- fetch cid
return (Some c)
else return None
这需要你从外界传入cidIsKnown
,这很烦人。可以想象 "unchecked queries" 在这里提供帮助。例如。可以引入一个函数 uncheckedContractActive : (Template t) => ContractId t -> Update Bool
,它检查合约在提交者端是否处于活动状态,然后仅在交易中包含 Bool
。很明显,提交者可以自由选择是否 运行 交易就像 cid 存在一样,或者相反。
到目前为止,未经检查的查询还没有进入 DAML,原因很简单,因为它们混淆了共享、保证和验证逻辑的画面,以及个人客户关心的是什么。在当前的设计中,该拆分恰好在 DAML 合约和分类帐客户端之间。
失败的交易实际上并没有那么昂贵,只要它们在解释期间在提交者节点上失败即可。重要的是设计合约模型和分类帐客户端时,fetch
调用只会因竞争条件而失败,并且合约上没有太多交易失败的争用。你可以试试
- 设计每个自动化流程,使其跟踪 "pending set",它希望通过运行中的命令归档的合同 ID 集。这消除了每个自动化进程与自身的争用
- 如果您有两个自动化系统供同一方持续竞争同一份合同,请将合同一分为二,或将自动化合并为一个
- 如果您为竞争同一合同的两方设置了两套自动化系统,请重组选择以使工作流程更加同步。即在 DAML 中控制轮到谁
- 如果您的自动化部分偶尔会执行大批量操作,导致与其他自动化发生争用,请引入某种 "guard"。例如。将
Lock
合同写入分类帐,向非批处理自动化指示它应该暂停,或者使用 Operation
合同保护选择,该合同在批处理开始时被撤销。后者有更强的保证,但增加了开销,因为它为每个选择添加了 fetch
。
一旦您将争用减少到可接受的水平,失败的 fetch
调用可以使用分类帐客户端中的重试逻辑来处理。
对于合约密钥,有两个函数 fetchByKey
和 lookupByKey
,后者允许我处理否定查找。我没有看到对合同 ID 执行相同操作的 lookup : (Template t) => ContractId t -> Update (Optional t)
函数。
我也没有看到允许我处理失败的 fetch
调用的 try-catch 机制。
如何在不重新实现整个 DAML 逻辑客户端的情况下避免交易失败?
这个问题有很多要解开的问题:
- 为什么没有
lookup
? - 为什么没有 try-catch 块?
- 交易失败是可以避免的吗?
- 如何在不复制合约逻辑的情况下编写账本客户端?
lookupByKey
和提议的 lookup
函数允许交易提交者对合约做出不存在的断言。来自 lookupByKey
的 None
断言特定键不存在,来自 lookup
的 None
断言特定 ContractId
不存在。最大的区别在于合约的合约密钥包括密钥维护者,即验证查找的各方。因此很清楚谁必须授权 lookupByKey
,以及谁验证否定结果。对于 lookup
,ContractId
没有关联方,因此没有合理的授权或验证规则。
较弱的版本是 fetchIfNotArchived : (Template t) => ContractId t -> Update (Optional t)
,如果 id 未知,则失败;如果合同 id 已存档,则 returns None
。 DAML 交易在当前分类帐状态上是确定性的,当前分类帐状态是当前所有活动合约的集合。 fetchIfNotArchived
之类的函数会在 DAML 账本模型中引入不存在合约和存档合约的区别,因此账本状态将从一开始就从所有活跃合约变为整个账本。 DAML 账本不再被 t运行 分类并随时间线性增长,这是不可取的。
使用 try-catch 块,我们 运行 遇到了非常相似的问题。假设我有某种试探。我可以写这个函数:
lookup : (Template t) => ContractId t -> Update (Optional t)
lookup cid = do
try do
c <- fetch cid
return (Some c)
catch
return None
如上所述,没有人可以合理地授权或验证提交者是否遵循了正确的路径。所以这样的 try-catch 必须是 "unchecked",这意味着提交者可以自由选择是走 try
还是 catch
路径。您已经可以通过传递存在来模拟它:
maybeLookup : (Template t) => ContractId t -> Bool -> Update (Optional t)
maybeLookup cid cidIsKnown = if cidIsKnown
then do
c <- fetch cid
return (Some c)
else return None
这需要你从外界传入cidIsKnown
,这很烦人。可以想象 "unchecked queries" 在这里提供帮助。例如。可以引入一个函数 uncheckedContractActive : (Template t) => ContractId t -> Update Bool
,它检查合约在提交者端是否处于活动状态,然后仅在交易中包含 Bool
。很明显,提交者可以自由选择是否 运行 交易就像 cid 存在一样,或者相反。
到目前为止,未经检查的查询还没有进入 DAML,原因很简单,因为它们混淆了共享、保证和验证逻辑的画面,以及个人客户关心的是什么。在当前的设计中,该拆分恰好在 DAML 合约和分类帐客户端之间。
失败的交易实际上并没有那么昂贵,只要它们在解释期间在提交者节点上失败即可。重要的是设计合约模型和分类帐客户端时,fetch
调用只会因竞争条件而失败,并且合约上没有太多交易失败的争用。你可以试试
- 设计每个自动化流程,使其跟踪 "pending set",它希望通过运行中的命令归档的合同 ID 集。这消除了每个自动化进程与自身的争用
- 如果您有两个自动化系统供同一方持续竞争同一份合同,请将合同一分为二,或将自动化合并为一个
- 如果您为竞争同一合同的两方设置了两套自动化系统,请重组选择以使工作流程更加同步。即在 DAML 中控制轮到谁
- 如果您的自动化部分偶尔会执行大批量操作,导致与其他自动化发生争用,请引入某种 "guard"。例如。将
Lock
合同写入分类帐,向非批处理自动化指示它应该暂停,或者使用Operation
合同保护选择,该合同在批处理开始时被撤销。后者有更强的保证,但增加了开销,因为它为每个选择添加了fetch
。
一旦您将争用减少到可接受的水平,失败的 fetch
调用可以使用分类帐客户端中的重试逻辑来处理。