G-d willing
Hello,
I am a bit confused about the differences between the observer, witness, and divulge. What each type can see, and how is it effected when a new contract is created from the original contract they participated?
Thanks,
G-d willing
Hello,
I am a bit confused about the differences between the observer, witness, and divulge. What each type can see, and how is it effected when a new contract is created from the original contract they participated?
Thanks,
This is all described in detail in the Privacy section of the Daml documentation.
But let me offer a more concise explanation.
Observers are stakeholders on the contract, who get to see creation and archival of the contract and the exercise of any consuming choice. Observers are able to fetch the contract in Daml templates and to retrieve it via query from the client side.
In certain circumstances a contract may be disclosed to a non-stakeholder. E.g. a controller on a choice gets to see the creation of any contract that happens as a consequence of exercising the choice, even those contracts where the choice controller is not a stakeholder. This disclosure of contracts to non-stakeholders is referred to as “divulgence” and the non-stakeholder party that witnesses the creation of the contract is known as “witness”.
Here’s an example. In the testDivulgence script the Issuer creates an asset with Alice as the owner. Alice then transfers the asset to Bob. Alice is not a stakeholder on the asset owned by Bob. But she gets to see this contract as a witness. If you look at MyAsset contract in the Script Results view in Visual Studio Code and check “Show detailed disclosure” checkbox, you’ll see that the contract is visible to 3 parties: Issuer as a signatory (S), Bob as an observer (O) and Alice as a witness (W).
A witness cannot retrieve the contract from the client side using query
functions. But a witness can fetch the contract with the aid of a helper template and the authority of a stakeholder. Note how at the bottom of the script Alice can fetch MyAsset contract owned by Bob, and Charlie cannot.
In practical terms the effect of divulgence is that the action of creating divulged contract is recorded on the participant node that hosts the witness party. Which potentially allows the witness party to read this data by directly accessing the transactions database.
template MyAsset
with
issuer : Party
owner : Party
amount : Decimal
where
signatory issuer
observer owner
choice MyAsset_Transfer : ContractId MyAsset
with
recipient : Party
controller owner
do
create this with
owner = recipient
template DivulgenceTestHelper
with
issuer : Party
witness : Party
where
signatory issuer
observer witness
nonconsuming choice FetchContract : MyAsset
with
cid : ContractId MyAsset
controller witness
do
fetch cid
testDivulgence = script do
issuer <- allocateParty "Issuer"
alice <- allocateParty "Alice"
bob <- allocateParty "Bob"
charlie <- allocateParty "Charlie"
aCid <- submit issuer do
createCmd MyAsset with
owner = alice
amount = 5.0
..
bCid <- submit alice do
exerciseCmd aCid MyAsset_Transfer with recipient = bob
Some bAsset <- queryContractId bob bCid
testDivulgenceHelperCid <- submit issuer do
createCmd DivulgenceTestHelper with
issuer
witness = alice
-- Alice gets to see bCid contract because Alice is a witness
testDivulgenceAsset <- submit alice do
exerciseCmd testDivulgenceHelperCid FetchContract with cid = bCid
testDivulgenceAsset === bAsset
testDivulgenceHelperCid <- submit issuer do
createCmd DivulgenceTestHelper with
issuer
witness = charlie
-- Charlie does not have visibility of bCid contract because Alice is a witness
testDivulgenceAsset <- submitMustFail charlie do
exerciseCmd testDivulgenceHelperCid FetchContract with cid = bCid
return ()
Alex, thanks for a great answer!
In the example, Alice is a witness of MyAsset contract, but not a stakeholder. To fetch the data she needs ContractId of an asset. Is it right, that a single way she can obtain ContractId through a ledger is by a returning value of the Transfer choice? Since she cannot query it…
Or if I set a Java listener on CreatedEven of MyAsset on behalf of Alice she will get a notification after the Transfer action?
Thanks!
G-d willing
Thanks @a_putkov for a great example about the witness and the way it can access the contract.
What about the divulge, how is it created?
@VictorShneer
You should be able to see the ContractId of MyAsset in the transaction stream. Indeed, if you set a Java listener on behalf of Alice I’d expect it to capture the creation of MyAsset contract as a consequence of the exercise of Transfer choice.
@cohen.avraham
“Divulge” is not a notion that hasn’t been introduced before. “Divulge” is a verb that describes the act of divulgence. In the example I provided MyAsset contract with Bob as owner is divulged to Alice (the witness).
@a_putkov
I noticed that there is a warning that this feature is deprecated. Do you know when will it be removed?
And also, what is the plan for Witness
when this feature will not be available anymore?
What are the consequences will be for a witness?
@cohen.avraham
I suppose you’re referring to the following warning you can see in the IDE:
“Tried to fetch or exercise <Template>
on contract <Contract Id>
but none of the reading parties <Reading parties>
are contract stakeholders <Contract stakeholder parties>
. Use of divulged contracts is deprecated and incompatible with pruning. To remedy, add one of the readers <Reading parties>
as an observer to the contract”.
This warning doesn’t say that divulgence is deprecated. What’s deprecated is the deliberate use of divulgence as a disclosure mechanism in Daml applications, because such use of divulgence is incompatible with pruning.
Suppose you have an application that relies on a witness party to be able to fetch a divulged contract (as long as the contract is still active when the witness party tries to fetch it). Suppose this witness party is hosted on its own participant node, where no other parties are hosted. When a contract is divulged to the witness party, the event is logged in the witness party’s participant node. This event is then used by the witness party’s participant node to validate the fetch action, when the witness party submits a command fetching the divulged contract. Preserving the ability of the witness party to fetch the divulged contract requires unbounded storage on the participant node for divulgence events. It’s never safe to prune this event from the witness party’s participant node because this participant node cannot know whether the contract is active or not. The witness party’s participant node is not notified when the contract is archived because the witness party is not privy to the archive action.
The only way to avoid unbounded storage is to include divulgence events in pruning. This, however, results in the behavior when, after pruning the divulgence event, the witness party’s participant node will no longer have any knowledge of the divulged contract and will fail a transaction, where the witness party tries to fetch the contract.
To solve for bounded storage while preserving backwards compatibility for applications that rely on divulgence, pruning of divulgence events was introduced as optional. However, it’s obvious that not pruning divulgence events is not sustainable, hence a deprecation warning was introduced in the IDE when a divulged contract is fetched. It advises you that you cannot rely on fetching the divulged contract by the witness party to check whether the contract is active.