使用合约密钥有两个功能fetchByKey
和lookupByKey
,后者允许我处理否定查询。我没有看到lookup : (Template t) => ContractId t -> Update (Optional t)
对合同 ID 执行相同操作的函数。我也没有看到允许我处理失败fetch
调用的 try-catch 机制。
如何在不重新实现整个 DAML 逻辑客户端的情况下避免失败的事务?
使用合约密钥有两个功能fetchByKey
和lookupByKey
,后者允许我处理否定查询。我没有看到lookup : (Template t) => ContractId t -> Update (Optional t)
对合同 ID 执行相同操作的函数。我也没有看到允许我处理失败fetch
调用的 try-catch 机制。
如何在不重新实现整个 DAML 逻辑客户端的情况下避免失败的事务?
这个问题有很多东西要解开:
lookup
?lookupByKey
提议的lookup
功能允许交易的提交者对合同做出不存在的断言。None
结果 fromlookupByKey
断言特定键不存在,fromNone
断言lookup
特定键不ContractId
存在。最大的区别在于合约的合约密钥包括密钥维护者,即验证查找的各方。因此,谁必须授权 alookupByKey
以及谁验证否定结果是很清楚的。使用lookup
,没有与 a 关联的各方,ContractId
因此没有合理的授权或验证规则。
较弱的版本是fetchIfNotArchived : (Template t) => ContractId t -> Update (Optional t)
,如果 id 未知,则失败,None
如果合同 id 已存档,则返回。DAML 交易对当前账本状态具有确定性,当前账本状态是所有活动合约的集合。诸如此类的功能fetchIfNotArchived
将在 DAML 账本模型中引入不存在的合约和存档合约之间的区别,因此账本状态将从一开始就从所有活动合约变为整个账本。DAML 分类账不能再被截断并随着时间线性增长,这是不可取的。
使用 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 必须是“未检查的”,这意味着提交者可以自由选择是走这条路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
从外界传入,这很烦人。可以想象“未经检查的查询”在这里提供帮助。例如,可以引入一个函数uncheckedContractActive : (Template t) => ContractId t -> Update Bool
,该函数检查合约在提交者端是否处于活动状态,然后仅将 包含Bool
在交易中。很明显,提交者可以自由选择是否像 cid 存在一样运行事务,或者相反。
到目前为止,未经检查的查询还没有进入 DAML,原因很简单,它们混淆了共享、保证和验证逻辑的图景,以及单个客户的关注点。在当前的设计中,这种拆分恰好在 DAML 合约和分类账客户之间。
失败的交易实际上并没有那么昂贵,只要它们在解释期间在提交者节点上失败。重要的是以这样一种方式设计合约模型和账本客户端,使得fetch
调用只会因为竞争条件而失败,并且合约上没有太多的争论,即交易失败很多。你可以试试
Lock
合同写入分类帐,向非批处理自动化指示它应该暂停,或者使用Operation
在批处理开始时被撤销的合同来保护选择。后者有更强的保证,但增加了开销,因为它fetch
为每个选择增加了一个。fetch
一旦您将争用减少到可接受的水平,就可以使用分类帐客户端中的重试逻辑来处理失败的调用。