Controlling contract read access with readAs and ledger contents

readAs field of the access token can be used to grant access to more contracts than by default. My questions:

  1. Is it possible to manipulate this field based on the contents of the ledger (i.e. in “runtime”)?

  2. If yes, is it a bad practice / not how it is usually done?

What I want is Alice to have read access to the price of something:

template CurrentPrice
  with
    itemName: Text
    price : Int
    operator : Party
    reader : Party
  where
    signatory operator
    observer reader
    key (operator, itemName) : (Party, Text)
    maintainer key._1

So I can add reader party to readAs of Alice:

{
   "https://daml.com/ledger-api": {
     "actAs": ["Alice"],
     "readAs": ["reader"]
   },
}

Is it possible to set readAs of Alice based on the presence of some contract (1. question above) with something along the lines:

template CanReadPrice
  with
    somebody : Party
    reader : Party
    operator : Party
  where
    signatory operator
    observer somebody

Edit: I have a feeling that readAs does not work this way from this post. Any suggestion on how to achieve runtime read control of the price is welcome.

The most obvious on-ledger mechanism for read access is to add observers. As the post you linked to mentioned, it’s not the only way.

Generally speaking, a full Daml system must include a “smart” authentication system that is at least a little bit aware of the semantics of your application, as it needs to be able to deliver appropriate tokens. How much you want it to be aware is really up to you. I would personally prefer my authentication system not to need to read information on the ledger, but it’s certainly possible to set up.

Thank you. My goal is to have a single point of reference for the price, which every authorized party can look up. I also strive to find an efficient solution for updating the price and authorizing new party.
I could collect three different approaches from the post. I try to summarize what I found out:

  1. List of observers (what you mentioned).
    Upside: Single point of reference for the price.
    Downside: As one of the answers in the post pointed out, this could be inefficient when new party joins.

  2. The Broadcast pattern.
    Upside: This is more efficient than list of observers when new party joins.
    Downside: No single point of reference, as the price is broadcasted (i.e. copied) to parties.

  3. readAs field.
    Upside: Single point of reference for the price. Efficient when new party joins.
    Downside: Not trivial to set up.

3 can be trivial to setup if the price is expected to be public: just always add the “priceWatcher” party to all tokens as readAs. Or if it’s based on some external, slow-changing factor, like the organization the user belongs to or some such.

It becomes tricky if you want that to be decided on the ledger itself, because then you need to:

  • Have a complex enough authentication flow that it actually looks on the ledger when emitting tokens.
  • Somehow find a way to nudge/force users to refresh their tokens when they get granted access.
  • Somehow find a way to invalidate tokens when a user loses access to some of their readAs parties.
1 Like

Thank you for your clear explanation.

Keep in mind that the multi-party token solution is also topology dependent. The party in your readAs token must be hosted on your participant. In Canton where a party can be on multi-participant you can have it be as a read-only party but it still won’t work if it’s not allocated to the participant at all.

That’s not necessarily an issue just something to keep in mind.