Давайте посмотрим на 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
может раскрыть контракт и делегировать 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
. Часто рекомендуется проектировать рабочие процессы таким образом, чтобы все ключевые запросы были положительными.
person
bame
schedule
09.09.2019