Для запуска DAML LookupByKey и FetchByKey требуются разные разрешения.

У меня есть контракт с несколькими подписантами. Есть ли пример того, как сделать контракт LookupBykey? У меня возникли проблемы с тем, как добиться авторизации всех сторон для работы LookupBykey.

Также кто-нибудь может объяснить мне, почему для запуска LookupByKey требуется больше разрешений, чем для FetchByKey?

Добавьте несколько кодов, чтобы получить тот же контракт, используя LookupByKey и FetchByKey. Для той же стороны FetchByKey работает, а LookupByKey — нет.

LookupByKey получил Сбой выполнения сценария при фиксации в Main:38:3: #1: поиск по ключу Sample:Sample в DA.Internal.Prelude:365:26 не удался из-за отсутствия авторизации от '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


person Frankie    schedule 07.08.2019    source источник


Ответы (1)


Давайте посмотрим на 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