The fact that Fetch
and NoSuchKey
are not available over the LedgerAPI is an oversight in my opinion. The Ledger API should give you everything you need to validate a DAML Ledger.
And that idea is also the reason why Fetch
, nonconsuming Exercise
and NoSuchKey
are actions. The transaction graph (Ie the graph of Actions) should contain the information you need to decompose a DAML Ledger into individual party views (aka projections) and validate those. You need the Fetch
and NoSuchKey
nodes to be able to decompose into projections, and you need the information on those nodes to validate those projections.
Let’s just imagine a simple example where you sent me an instance of the DisclosureRequest
below:
template DisclosedAsset
with
assetCid : ContractId Asset
asset : Asset
disclosee : Party
where
signatory [asset.owner, disclosee]
template DisclosureRequest
with
requester : Party
requestee : Party
where
signatory requester
controller requestee can
Disclose : ContractId DisclosedAsset
with
assetCid : ContractId Asset
do
asset <- fetch assetCid
create DisclosedAsset with disclosee = requestee; ..
When I exercise Disclose
, the current Ledger Model says that there are three nodes:
Exercise (assetCid)
| - Fetch (assetCid -> asset)
| - Create (DisclosedAsset assetCid asset requester)
You and I validate the whole thing. The Fetch node contains the contract arguments of the Asset
contract which allow you to execute the create
statement.
The asset issuer only gets to see and validate the Fetch
node.
This model is safe:
- I can’t fake the contents of
assetCid
because the Fetch
node is validated by the issuer.
- I can’t create
DisclosedAsset
contents by any other means because they need your signature.
So you have the guarantee that unless the issuer collaborates with me, the asset
in DisclosedAsset
will always match assetCid
, and the contract is active at the time of the transaction.
Now let’s imagine we only had Create
and Exercise
nodes in the Ledger Model. Now the resulting transaction looks like this:
Exercise (assetCid)
| - Create (DisclosedAsset assetCid asset requester)
What does the issuer
get to see here? If nothing, you are at my mercy when it comes to saying what asset
contains. You lose the guarantee that assetCid
and asset
match.
But let’s say we have a magic wand which given an Asset
and a ContractId Asset
allows us to check that they match and that the contract is active. You as a human reading this DAML code can infer that if you see the transaction above, the asset
and assetCid
must match, and you can verify that using the magic wand. Thus, you can verify the whole transaction. But you can’t always do that. Imagine I added a second choice to DisclosureRequest
:
controller requestee can
DiscloseHigher : ContractId DisclosedAsset
with
assetCid1 : ContractId Asset
assetCid2 : ContractId Asset
do
asset1 <- fetch assetCid1
asset2 <- fetch assetCid2
let
(assetCid, asset) = if asset1.quantity >= asset2.quantity
then (assetCid1, asset1)
else (assetCid2, asset2)
create DisclosedAsset with disclosee = requestee; ..
If I exercised that, you’d see this:
Exercise (assetCid1, assetCid2)
| - Create (DisclosedAsset assetCid asset requester)
What can you infer now? With your magic wand you can still check that assetCid
and asset
match, and that the contract was active, but you have no chance to check that I evaluated the if..else
statement correctly. The only way you could validate that is to know what the fetches result in. Ie you need to know the Fetch
nodes.
With NoSuchKey
it’s more about the validation than sharing the needed information. You need a node that you can send to the maintainers of the key to confirm the non-existence.