Canton 3 Contract Keys

I’ve been reading about contract keys in Canton 3, and I know that when they return they will no longer unique. I read through this post here and there’s this quote “function is fundamentally incompatible with multi-domain architecture of the Canton Network”. I have been aware that the keys will no longer be unique for some time, and I have always wondered why. My thought process is that since the maintainer will still exist (I assume) and parties are guaranteed to be unique, by default wouldn’t you still be able to make sure that keys are unique? Are we not able to get the entire ACS for a party and check if a key already exists, even if the party is distributed? Or in Canton 3 are contracts not “replicated” across different participant nodes when parties are distributed?

Also, if the second item above is the case, does that mean that the new fetchByKey, that can return multiple contracts, is not guaranteed to return a contract with that key if it does exist because it exists on a different node than the one that we are trying to fetch from?

Thanks,

Austin

It’s about consistent ordering. Let’s imagine we have a template T with a key and two maintainers set, m1 and m1. m1 and m2 are active on synchronizers (formerly domains) D1 and D2.

Now alice submits a transaction with key k via D1 and bob submits a transaction with key k via D2.

Since there is no ordering between D1 and D2, and due to network latencies etc, m1 may decide that alice’s transaction is “first”, and m2 may decide that bob’s transaction is “first”. m1 and m2 now fail to reach consensus and this goes against a fundamental assumption in the Canton protocol: that transaction validation is fully deterministic based on the ledger state and ordering.

@bernhard can you describe the problem using some sort of chart/image showing the process?

Isn’t every transaction is going to the global synchronizer - so it should know.

Also, when you said “Now alice submits a transaction with key k via D1 and bob submits a transaction with key k via D2.”, did you mean that the key values are the same?

I don’t think I have a diagram to hand. You are right that as long everything is via the global synchronizer, there’s no problem - the global synchronizer provides the ordering. But Canton has a network of networks design where transactions can happen on different synchronizers.

I slipped back into old language patterns above using “domain” for "synchronizer”. It’s synchronizers D1 and D2 in the example.

And yes, the example is that it’s the same key k on both sides, with same maintainers m1 and m2.

Hi Bernhard,

So is it fair to say that if we have a key with just one party as the maintainer, then effectively we can keep uniqueness for that key? The issue would only arrive if we had a key with 2 maintainers, which makes sense for the situation which you described. Also (and maybe this is a dumb question), isn’t there only one maintainer in DAML? Or for DAML 3 are we now introducing the ability to have multiple maintainers?

Thanks,

Austin

@austin
Contract keys in Daml 2 can have multiple maintainers. Here’s the link to Daml 2 reference documentation on contract keys:

The problem that Bernhard described could occur even with a single maintainer, albeit the example that I have in mind is arguably an edge case. If in Bernhard’s example we replace maintainers m1 and m2 with a single maintainer m, which is a multi-hosted party, that is hosted on Participant Nodes P1 and P2 with the confirmation threshold set to 1 (i.e. either Participant Node can single-handedly confirm the transaction on behalf of the maintainer party m), we have the same problem Bernhard described. Alice submits a transaction that creates a contract with the key value k on synchronizer S1, Bob submits a transaction that creates another contract with the same key value k on synchronizer S2. Then P1 could decide that Alice’s transaction is “first” and confirm it on behalf of m. And P2 could decide that Bob’s transaction is “first” and confirm it on behalf of m.

So, why not defining in the Canton network a master global synchronizer which will be the synchronizer of all the synchronizers? That should resolve this, of course. But I assume that the challenges that arise from it, are not that simple to implement/resolve.

So, maybe when a new contract is added (using a maintainer) then this will be kept in that “master synchronizer”, so, if another contract is being added with the same maintainer but on a different participant node (validator), that will be communicated to the master synchronizer, so eventually you will know which transaction was “first”

Oh, ok. So multiple maintainers could be something like:

key (party1,party2,textField) : (Party, Party, Text)
maintainer key._1
maintainer key._2

Then for your example, the issue is with distributed (or multi-hosted) parties. This may not ever happen, but essentially it would be a problem if the a contract was created with the same key on both nodes, at the same time. If they went through the same synchronizer S1, it would be able to catch that through deduplication? But since the transaction could be submitted through different synchronizers now, we could run into the duplicate contract keys? Am I following correctly?

Yes, I think that describes the problem well.

You already identified two solutions with clear downsides:

  1. Single “master synchroniser” for everything
  2. Single-node maintainers only

There are better alternatives in my opinion, but they get increasingly technically complex both for the protocol as well as for apps trying to use keys. But effectively for any given key at any given point in time, there must be a single synchroniser (or validator) solely responsible for determining ordering of key operations. How to track that and provide a decent app development experience especially with transactions across domains is a puzzle still.