How to check if a contract instance exists on the ledger

Hi all,

suppose I have a template that takes a contract (not a contract ID) as a parameter, like in the snippet below, where reservation is a contract of type CodeReservationConfirmation:

template Security
  with
     otherParty: Party
     reservation: CodeReservationConfirmation
  where ...

Is there a way to write an “ensure” clause to check that “reservation” is a contract that exists on the ledger, not something one has instantiated in a “let” block?

in the latter case, the contract would not have an ID, but not sure how to test that in an ensure clause…

ensure clauses are pure expressions not Update clauses so they cannot query the ledger. For your example there is another challenge: Even in Update you cannot query the active contracts of a template type (you can in DAML Script) so there is no way to check if one or more contracts exist with the corresponding payload. What I would recommend doing is to store a ContractId CodeReservationConfirmation check instead. You still cannot enforce activeness in the ensure clause but you can use fetch in your choices to get the associated payload and that will fail if the contract is not active.

yeah, that’s not helping much. See in my scenario the existence of a CodeReservationConfirmation on the ledger is meant to ensure that whoever is creating the Security, went through the proper steps to provision the security’s ISIN code.

I don’t want the Security contract to be created if the CodeReservationConfirmation does not exist.

If I let it, it would mean that a malicious party on the ledger could flood the ledger with Security contracts without properly provision ISIN codes, and then when another party tries to legitimately create a security with one of those ISIN codes, it would fail…

I’ll think about it, and get back to you…

on the other hand, if I pass a contractId, I guess that guarantees that a CodeReservationConfirmation exists on the ledger, but then I need to pass the code as a template parameter (not a problem by itself) but I cannot “ensure” that the code passed as a parameter is the one that was reserved…

Hi @entzik,

Small clarification regarding a potential misunderstanding in your original question: an object of type CodeReservationConfirmation in DAML code is not a contract, but the payload of a contract, or rather a data structure that has the right shape to be the payload of a contract corresponding to the CodeReservationConfirmation template. The contract ID is what holds the “identity” of the contract on the ledger. There is no way in DAML code to get access to the contract itself, only either its payload (which is completely anonymous and can be easily fabricated) or its ID (from which you can request the payload from the ledger using the fetch action). Note that “having” a contract ID is no guarantee of anything either: it could be completely made up, or it could be expired. The only way you can trust the data you have is if you have just fetched the payload base on the contract ID within the current transaction. That would prove both that the contract ID exists (and is currently active) and that it corresponds to the payload.

DAML is designed for distributed applications, and therefore does not have any concept of global truth (except for contract keys and their uniqueness property) or global variables. The only mechanism for ensuring properties is signatures; you cannot ensure that a Security has been created with a correct ISIN in the absolute sense, but you can verify that its creation has been signed by a trusted authority.

It seems to me that the idiomatic approach to your problem here would be to have a small set of “trusted” parties that can validate ISIN numbers and have them sign securities. I’ve written “trusted” in quotes there because that is, again, not going to be a global property in your application; each participating party will need to define who they trust to issue (or verify) ISIN numbers, and consequently who they trust to sign securities.

Thanks guys. @Gary_Verhaegen thanks for explaining the payload stuff, very instructive.

yes I get it, that’s what we are doing. I don’t have any complaint against the happy path.

It’s just that at Liquidshare we are a bit paranoid about information security and that’s a primary concern for us from the begining.

From this paranoid point of view, if I have a malicious party on the ledger that party can issue a large number of securities using illegitimate ISINs. there are two problems with that:

  1. it’s effectively a denial of service attack on the ledger
  2. it litters my ledger with useless data

When I say a maliciuous party, I don’t mean a bank or a broker are inehrently malicious, but one of their employees can always go roque. Think Kerviel who alledgely used to go in and book fake trades to compensate for his hazardous positions before the risk analisys batches kicked in and cancelled them afterwards. Some could argue they trust Societe Generale but, because of a roque employee, SocGen can under some circumstance act as a maliciuous party, and that’s what I would like to be able to defend against.

I undertstand that ensure is executed locally and for some valid reason it’s not allowed to fetch data from the ledger and us it to validate the payload of the contract about to be created. But this opens the door to attacks like the one I’ve mentioned both here, as well as in the other discussion we had about roles.

I guess what I am trying to say is that DAML seems to tend towards a “trust by default” type of policy while the norm in information security today is zero trust and defense in depth.

That’s not quite the way I think about it. Ultimately you have to trust someone, or something, if only the CPU running your code. DAML is making some of that explicit.

In your case, based on your description and zero prior knowledge of what ISINs are on my end, you could imagine Société Générale would have a separate party that is only in charge of validating ISIN numbers, and is running as a separate bot on its own machine. You still need to trust whoever has access to that machine, of course, but presumably that’s a much smaller set of people than “all Société Générale employees”. Now imagine there are three other banks involved in that process, and they all run a similar bot. Now if you say a valid ISIN must have been signed by all four, you have a slightly more cumbersome process, but you also have a much harder one to break. No single employee in any of the four banks can compromise the system, and any one of them trying would be detected by the other three.

The key here is that if you want to be able to trust these securities, you need to have multiple trustworthy parties signing them.

In a way, you’re asking for “foreign key” constraints in DAML. I’d say the main conceptual reason we don’t allow such invariants is privacy. In your example, ISINs are normally issued by the country’s ISIN authority; so in the DAML model it’d be reasonable to represent them as contracts with just the authority. Now let’s say that I create a contract with you that refers to this ISIN. Then, any change to the ISIN contract could violate the foreign key constraint; however, the ISIN authority doesn’t even have to know about the existence of our contract. Depending on the ledger you’re using, the authority might not even know that the other parties exist. So it has no way of checking their foreign key constraints, or informing them of the change (to do something like ON DELETE CASCADE) the only safe way to preserve the constraints is to prohibit the authority from ever changing the contract (including deleting it).

In your example, you can still arrange your workflow such that the parties agree to create the Security contract only if a valid ISIN can be first shown. This mirrors pretty closely that what happens in the real world; in principle, the authority could at some point revoke the ISIN, but this would be an extraordinary event.

Hi @oggy - apologies for missing your reply. The question is probably not very clear, so let me clarify:

  • I am not asking for foreign keys. the question I had back then was for a way to check if a contract with a specific ID already exists on the ledger and the ability to use the payload of that contract in an ensure clause.

  • I would only need to know if the contract with the specified ID exists at the moment of the inquiry, I don’t expect any relationship to be enforced between the contract I am about to create and the one I check for.

Hi @entzik ,

I thought the question was clear and I still stand by my comment that it’s akin to foreign keys; let me try to explain again what I mean.

You wanted to prohibit the creation of the Security if the corresponding CodeReservationConfirmation doesn’t exist. In RDBMS terms, if you think about Security and CodeReservationConfirmation as tables and of contracts instances as rows in those tables, you want to prohibit the creation of a new row in Security if the reservation column doesn’t point to the ID of an existing row in CodeReservationConfirmation. A foreign key constraint would check that for you.

So far so good, DAML and DAML-based ledgers could be changed to check this for you reasonably easily at the creation time. The question is what happens later. If at some point after creating some Security contract, let’s call it s, the s.reservation gets archived, should s automatically be archived as well? That would correspond to ON DELETE CASCADE. The problem is that this doesn’t play so well with DAML’s visibility constraints; it is possible that the stakeholders of s.reservation don’t even know about the existence of s.

What you can currently do instead is to add a fetch s.reservation to every place where you use s in an Update. The caveat is that you would have to make your own provisions for archiving the s, once the s.reservation is gone.

IMO if there’s sufficient popular demand, this is something that we could also add some syntax sugar for (technically, it might be more than just syntax sugar, as we could make the Fetch a subaction of the Create, for example). The syntax sugar could also be extended to check an arbitrary relationship between s and s.reservation, as you’ll usually want to assert some kind of relation. We’d have to figure out how to do this best; if we’re already doing the fetch, then you probably want to be able to access the fields of s.reservation without doing another fetch. @bernhard has some plans for adding what he calls “fat contracts” to DAML, which would combine the contract ID and the data; this could potentially be combined with the “auto-fetch”.