The problem here is that contract ids of contracts created in the current transaction are not yet fixed during interpretation, there is some additional suffixing happening later (daml/contract-id.rst at b446fba6d886580d74fbedfb90d9820203c9eac2 · digital-asset/daml · GitHub has details on that if you’re interested but not really relevant from a user PoV). To allow for that suffixing contract ids have to be opaque and only support a limited number of operations that are preserved under suffixing (equality & ordering), otherwise adding the suffix could change the behavior of your daml program which would break all kinds of things.
Off-ledger you’re dealing with contract ids of contracts that have already been committed to the ledger and thereby have already been suffixed so there is no issue there.
Thanks @cocreature
The thing is the contractId which I’m trying to show and persist has been already created in a separate transaction ( providerHoldingCid in the figure is passed as parameter in a choice ).
To give you a little of context, I’d like to have a template where a contractId from a different template is part of the key. The issue I’m facing is that a contractId cannot be part of a template key. Because of that I’m trying to do show contractId before creating the template.
The thing is the contractId which I’m trying to show and persist has been already created in a separate transaction
Right, the problem is that we cannot treat contracts created in the current transaction differently because that breaks compositionality (you now cannot combine things into a single transaction anymore) and because it’s not even clear when a contract has been created in the current transaction because a party may see only a subview of the transaction but not the create. So the limitation applies to all contract ids.
For your contract key problem, you’ll have to find a different identifier that you can use in your key. One option is to generate UUIDs off-ledger and pass them into the command that creates the contracts.
Why does show return a fixed string when called on ledger rather than throw an error or otherwise abort the transaction? (Given that it can’t be used on ledger, it seems correct to think of it as an error.)
All template fields in Daml have to be serializable which is represented by a requirement they have Show t and Ord t instances. So because we need to allow ContractId t as a field on a template, it needs to have an implementation for show. For the reasons given by Moritz, this can’t be the actual Contract Id as that might not exist yet and there is no way for a party that only sees a sub-transaction to know if it was created before or during the current transaction. So the only sensible alternative that satisfies the type is a constant string.
Is this later addition deterministic?
Can you export this “suffix” function upstream?
I would expect the client-side function to be capable of both failure and success, allowing me to implement a retry mechanism around it to handle potential failures and eventually resolve them.
No. The suffix is a hash of the contract data that is randomized with a cryptographically strong seed.
Can you export this “suffix” function upstream?
The format of the suffix is intentionally undocumented because it evolves across SDK versions in incompatible ways, as new Daml features are developed. As such, it cannot be part of the public stable API.
I would expect the client-side function to be capable of both failure and success, allowing me to implement a retry mechanism around it to handle potential failures and eventually resolve them.
What kind of failures are you referring to? It is in general impossible to predict the seed that randomizes the hash.