Why is that fetch results in a ledger update and query does not? I understand that fetch is part of a choice where as query is in the script, but both of them are doing the same thing - looking for something in the ledger. So why is one recorded and the other not? I feel I am missing something big here.
The key difference is whether it is performed on the ledger versus off the ledger. A Daml script runs the Daml interpreter but connected to the ledger via the gRPC ledger API. We record actions taken on the ledger (that’s the fundamental concepts behind a it) but not those taken off the ledger.
This is not precise, they are both looking for an active contract on the ledger. One could also look at the ledger for the previous transactions that took place.
Lastly, notice the different types (for now ignoring the type class constraints):
- fetch :: ContractId t → Update t
- query :: p → Script [(ContractId t, t)]
- queryContractId :: p → ContractId t → Script (Optional t)
- Notice how
fetchdoes not take a
Partyargument, the visibility is implied by the authorization inside of an
Update. We always know who is performing an action on the ledger. Not off-ledger.
queryContractIdis the more appropriate parallel for an off-ledger
fetch. Notice how there isn’t anything like
fetchAll : -> Update [(ContractId, t)]. That is intentional, an
Updateis “evaluated” twice as part of submission and then validation. AFAIU, it is not easy to make the result of a potential
fetchAllconsistent across the two.
Thanks @Leonid_Rozenberg. Your answer does help, but I think I am unable to understand the difference between on-ledger vs. off-ledger. Does on-ledger mean invoking choices written in the template and off-ledger means any code outside of templates?
For example, we can do things such as createCmd or exerciseCmd in script, both of which result in ledger updates. It is only query which doesn’t. And I notice the difference that createCmd and exerciseCmd are invoking template-code where as query statement stands on its own. So is ‘query’ provided as a tool to query the ledger without updating it possibly for debugging purposes?
And please pardon my imprecise language as I am trying to abstract out the details!
Yes, and no. On vs off ledger is just where is the code being executed. Daml uses specific types to denote where your code is being executed,
Update for on,
Script for off.
They result in a ledger update because they first construct a Command that is executed there.
I wouldn’t think of it as a tool but as the things that one could do off ledger (for now as provided via Daml Script). I can send commands or I can find contracts among my ACS. There’s other stuff but, within Script, it is a function of what portion of the Ledger API has been wrapped.
One other important thing to note is that
fetch is a ledger event, it is recorded on the ledger. For example, if you need to look up a price to determine what to charge me, you could fetch that contract and I would need to verify that it is one that we previously agreed upon. It is a long standing TODO to expose that over the LedgerAPI, but it is an event in the sense that we charge for it.
So what I understand is this: fetch is always part of a choice that is executed as a Command by exerciseCmd. Since choices can change the ledger, their actions - including fetch - are recorded in a transaction tree.
But query is not submitted as a Command, and hence cannot change the ledger, and hence not recorded.
I hope I got that right.
Yes, makes sense.