daml - DAML LookupByKey 和 FetchByKey 需要不同的权限才能运行
问题描述
我与多个签署人签订了合同。是否有关于如何执行 LookupBykey 合同的示例?我无法弄清楚如何获得各方授权 LookupBykey 工作。
还有没有人可以向我解释为什么 LookupByKey 需要比 FetchByKey 更多的运行权限?
使用 LookupByKey 和 FetchByKey 放置一些代码来获得相同的合约。对于同一方,FetchByKey 有效,但 LookupByKey 无效。
LookupByKey 在 Main:38:3 提交时遇到场景执行失败:#1: DA.Internal.Prelude:365:26 的 Sample:Sample 的键查找失败,因为缺少来自“partyA”的授权
run = scenario do
a <- getParty "partyA"
b <- getParty "partyB"
sample <- submit a do create Sample with sig = a, obs = b, content = "some text here"
caller <-submit b do create Caller with sig = b, obs = a
submit b do exercise caller FetchByKey with company="test", text = "fetch by key sample"
pure()
run2 = scenario do
a <- getParty "partyA"
b <- getParty "partyB"
sample <- submit a do create Sample with sig = a, obs = b, content = "some text here"
caller <-submit b do create Caller with sig = b, obs = a
submit b do exercise caller LookupByKey with company="test", text = "look up by key sample"
pure()
-- choices
controller sig can
FetchByKey : Bool
with
company : Text
text : Text
do
re <- fetchByKey @Sample (company, obs)
cid_tr <- exercise (fst re) Operate with text = text
return True
controller sig can
LookupByKey : Bool
with
company : Text
text : Text
do
re <- lookupByKey @Sample (company, obs)
cid <- fetch (fromSome re)
res <- exercise (fromSome re) Operate with text = text
return True
解决方案
让我们看一下通用模板fetchByKey
的上下文:lookupByKey
Sample
template Sample
with
maints : [Party]
extraSigs : [Party]
obs : [Party]
where
signatory maints ++ extraSigs
observer obs
key this : Sample
maintainer key.maints
关键是整个合同,由指定的签字人子集维护。可以使用一个简单的提案工作流来实例化这样的合约:
template SampleProposal
with
sample : Sample
sigs : [Party]
where
signatory sigs
observer (signatory sample)
choice Sign
: ContractId SampleProposal
with
sig : Party
controller sig
do
assert (sig `elem` signatory sample)
assert (sig `notElem` sigs)
create this with sigs = sig :: sigs
choice Accept
: ContractId Sample
with
sig : Party
controller sig
do
assert (sig `elem` signatory sample)
create sample
makeSample = scenario do
maints <- mapA getParty ["main1", "main2", "maint3"]
extraSigs <- mapA getParty ["sig1", "sig2", "sig3"]
obs <- mapA getParty ["obs1", "obs2", "obs3"]
let sample = Sample with ..
prop <- submit (head maints) do
create SampleProposal with
sample
sigs = [head maints]
signedProp <- foldlA
(\p sig -> submit sig do exercise p Sign with sig)
prop
(tail maints ++ tail extraSigs)
submit (head extraSigs) do
exercise signedProp Accept with sig = head extraSigs
现在,谁可以fetchByKey
,谁可以lookupByKey
这个样本?
两者的第一个条件是提交方必须知道合同。即他们必须是利益相关者(即签字人或观察员),或者合同必须已经泄露给他们。
其次,必须正确授权操作。fetchByKey
像 一样被授权fetch
,这意味着您必须拥有至少一个利益相关者的权限。因此, 的观察者Sample
可以泄露合同并委托 a fetchByKey
。
template FetchByKeyDelegation
with
sampleObserver : Party
agent : Party
where
signatory sampleObserver, agent
nonconsuming choice FetchSampleByKey
: (ContractId Sample, Sample)
with
ctl : Party
sample : Sample
controller ctl
do
fetchByKey @Sample sample
template FetchByKeyDelegationInvite
with
fbkd : FetchByKeyDelegation
where
signatory fbkd.sampleObserver
controller fbkd.agent can
AcceptFBKDI
: ContractId FetchByKeyDelegation
do
create fbkd
delegateFetch = scenario do
sample <- makeSample
let obs = head sample.obs
agent <- getParty "Agent"
prop <- submit obs do
create FetchByKeyDelegationInvite with
fbkd = FetchByKeyDelegation with
sampleObserver = obs
agent
fbkd <- submit agent do
exercise prop AcceptFBKDI
-- By calling FetchSampleByKey, `obs` divulges the contract to `agent`
submit obs do
exercise fbkd FetchSampleByKey with
ctl = obs
sample
-- Now `agent` can use the authority of `obs` to `fetchByKey`
submit agent do
exercise fbkd FetchSampleByKey with
ctl = agent
sample
lookupByKey
有更严格的授权规则。您需要所有维护者的权威,而不是一个利益相关者。除此之外,委托的工作方式相同:
template LookupByKeyDelegation
with
maints : [Party]
agent : Party
where
signatory maints, agent
nonconsuming choice LookupSampleByKey
: Optional (ContractId Sample)
with
ctl : Party
sample : Sample
controller ctl
do
lookupByKey @Sample sample
template LookupByKeyDelegationInvite
with
lbkd : LookupByKeyDelegation
sigs : [Party]
where
signatory sigs
observer (signatory lbkd)
choice SignLBKDI
: ContractId LookupByKeyDelegationInvite
with
sig : Party
controller sig
do
assert (sig `elem` signatory lbkd)
assert (sig `notElem` sigs)
create this with sigs = sig :: sigs
controller lbkd.agent can
AcceptLBKDI
: ContractId LookupByKeyDelegation
do
create lbkd
delegateLookup = scenario do
sample <- makeSample
let maints = sample.maints
agent <- getParty "agent"
lbkdi <- submit (head maints) do
create LookupByKeyDelegationInvite with
lbkd = LookupByKeyDelegation with
maints
agent
sigs = [head maints]
signedlbkdi <- foldlA
(\p sig -> submit sig do exercise p SignLBKDI with sig)
lbkdi
(tail maints)
lbkd <- submit agent do
exercise signedlbkdi AcceptLBKDI
-- By calling LookupSampleByKey, a maintainer divulges the contract to `agent`
submit (head maints) do
exercise lbkd LookupSampleByKey with
ctl = head maints
sample
-- Now `agent` can use the authority of `obs` to `lookupByKey`
submit agent do
exercise lbkd LookupSampleByKey with
ctl = agent
sample
在您的特定模型中,它似乎partyB
是观察者,而不是维护者。因此,他们知道合同(第一个条件),并且他们的行为得到了利益相关者的授权(第二个条件fetchByKey
)。但是,lookupByKey
维护者没有授权,所以它失败了。
授权差异的原因是负面查找情况下的行为。fetchByKey
在提交者节点上失败,因此负面查找永远不会到达网络。lookupByKey
允许否定查找,因此它们确实会影响网络。
DAML 是围绕这样一个原则设计的,即除非他们签署了某些东西,否则任何一方都不应工作。验证密钥查找是一项工作,因此除非您签署了合同,否则您永远不必这样做。这fetchByKey
是真的。除非您签署了一份由您担任维护者的合同,否则任何诚实的节点都不会提交fetchByKey
您担任维护者的合同。
然而,lookupByKey
事实并非如此。首先,如果你有一个否定的查找,你拥有的唯一信息就是维护者是谁,因为只有那些是关键的一部分。因此,要在提交者节点上运行授权检查,授权规则必须是关于维护者,而不是利益相关者。
现在假设一个维护者的权威,而不是所有维护者,就足够了。那么以下将是完全合法的事情:
badLookup = scenario do
frankie <- getParty "Frankie"
spammer <- getParty "spammer"
let
sample = Sample with
maints = [frankie, spammer]
extraSigs = []
obs = []
forA [1..1000] (\_ -> do
submit spammer do
lookupByKey @Sample sample
)
即恶意方可以通过昂贵的操作合法地向您发送垃圾邮件。这违背了 DAML 的核心原则,因此授权规则必须是需要所有维护者。
关键是人们应该非常仔细地考虑是否lookupByKey
真的需要。通常建议设计工作流程,以便所有关键查找都是积极的。
推荐阅读
- javascript - 附加 window.history.back() URL 以将变量传递到上一页
- scala - Scala Play、Apache Spark 和 KuduContext 不兼容
- django - 通过 Django orm 获取最高 x% 的对象集
- python - 如何检查句子特定部分之前的字符串是否与其他行中的任何文本匹配或不匹配(与特定部分之后相同)?
- c++ - WindowsPortableDevice IPortableDeviceContent::Delete 导致我的设备挂起。我该如何解决这个问题?
- python - 如何在python中使用文件名对文件夹中的文件进行排序
- pdf - UiPath 使用 GetText 从 PDF 读取复选框
- python - 如何在 Pandas 中将字符串列解析为日期时间格式?
- python - 编写程序来计算和打印文本文件中数字的平均值,其中包括使用两个高阶函数的文本和数字
- flutter - 如何在flutter bloc中使用数据模型