Divulgence only on consuming choices

Why does only the default “consuming” choice below cause divulgence?

module Main where

import Daml.Script

template Secret
  with
    p : Party
  where
    signatory p

template SecretFetcher
  with
    p : Party
    obs : [Party]
  where
    signatory p
    observer obs

    choice PublicFetch : Secret
      with s : ContractId Secret
      controller p
      do fetch s

    nonconsuming choice NonPublicFetch : Secret
      with s : ContractId Secret
      controller p
      do fetch s

    preconsuming choice PreconsumingFetch : Secret
      with s : ContractId Secret
      controller p
      do fetch s

    postconsuming choice PostconsumingFetch : Secret
      with s : ContractId Secret
      controller p
      do fetch s

    nonconsuming choice CustomPreconsumingFetch : Secret
      with s : ContractId Secret
      controller p
      do
        archive self
        fetch s

    nonconsuming choice CustomPostconsumingFetch : Secret
      with s : ContractId Secret
      controller p
      do
        x <- fetch s
        archive self
        return x

template Fetcher
  with
    stakeholder : Party
    fetcher : Party
  where
    signatory stakeholder
    observer fetcher

    nonconsuming choice FetchSecret : Secret
      with
        cid : ContractId Secret
      controller fetcher
      do fetch cid

test : Choice SecretFetcher c Secret => Party -> Text -> Bool -> (ContractId Secret -> c) -> Script ()
test p observerName divulged f = do
  o <- allocateParty observerName
  s <- submit p do createCmd Secret with p
  sf <- submit p do createCmd SecretFetcher with p; obs = [o]
  submit p do exerciseCmd sf (f s)
  f <- submit p do createCmd Fetcher with stakeholder = p; fetcher = o

  if divulged then do
    submit o do exerciseCmd f $ FetchSecret s
    pure ()
  else
    submitMustFail o do exerciseCmd f $ FetchSecret s

privacyTest : Script ()
privacyTest = do
  p <- allocateParty "p"

  test p "publicFetcher"        True  PublicFetch
  test p "nonconsumingPublic"   False NonPublicFetch
  test p "preconsumingFetcher"  False PreconsumingFetch
  test p "postconsumingFetcher" False PostconsumingFetch
  test p "customPreFetcher"     False CustomPreconsumingFetch
  test p "customPostFetcher"    False CustomPostconsumingFetch

1 Like

It’s described in the privacy section of the ledger model.

a party p is an informee of an action A if one of the following holds:

  • A is a consuming Exercise on a contract c, and p is a stakeholder of c or an actor on A.
  • A is a non-consuming Exercise on a contract c, and p is a signatory of c or an actor on A.
  • A is an Exercise action and p is a choice observer on A.

The idea here is that stakeholders are entitled to see contract state changes, i.e., create and archive. The slightly unfortunate thing here is that there is no separate archive primitive in Daml so “see contract archive” really means “see consuming exercise”.

The preconsuming keyword allows you to sidestep that by desugaring the choice to a non-consuming choice that calls archive at the beginning so observers really only see the exercise of the archive choice.

The ledger model docs also have the workaround for the case where you actually want to share the full choice: Add the party as a choice observer.

Maybe the question should have been - why does only the default choice cause divulgence and the others do not? Specifically, why does post-consuming not cause divulgence? Is this because all the others are effective non-consuming (preconsuming and postconsuming just being the same as the CustomXXX variants)?

1 Like

Yes, post-consuming and pre-consuming are just syntactic sugar for non-consuming + a call to the autogenerated archive choice at the beginning/end.

@cocreature I think the part that you quoted only defines the informee’s if they are acting on the ledger not passively observing, but that did lead me to the part that clarifies it which is right above

As a design choice, Daml Ledgers show to contract observers only the state changing actions on the contract. More precisely, Fetch and non-consuming Exercise actions are not shown to contract observers - except when they are also actors or choice observers of these actions

The contract state is defined

The contract state is changed by creating the contract and by exercising it consumingly.

1 Like

But I thought a fetch causes divulgence to contract observers? Isn’t it only non-consuming exercises that are not shown to contract observers?

@Mr_Mannoroth In this context is is the fetch of the contract in a different Update that is not disclosed to an observer.