Hi everyone!
As per this thread I’m trying to get a better understanding of the error message received after validating contract keys.
I am currently sending the same command twice, waiting in between for command completion. Instead of seeing the expected DuplicateKeys
error, I am instead seeing InconsistentKeys
.
I am trying to ensure proper error handling in my application, but as I cannot understand why I am not getting DuplicateKeys
I cannot manage the response well.
Thanks in advance!
1 Like
To clarify, what does the command you are sending doing? Is it just creating a new contract twice, both times with the same key? Or is some contract being consumed in the process as well?
1 Like
There are multiple contracts being consumed, but all are created with new values (hence it is possible to race here, but I wait to ensure no race), and then a final contract is created as a final result. The choice itself is nonconsuming, it’s all secondary contracts being fetched, archived, and created again.
1 Like
Hi @lashenhurst,
currently InconsistentKeys
is produced when contract keys referenced in a transaction have changed between submission and commit. This shouldn’t happen in your case though, if I understand correctly, as you are waiting for the first transaction to complete before sending the second one that could cause keys contention.
Is there a minimal example you can share that reproduces the condition you describe?
1 Like
The closest example would be something like:
template Vendor
with
networkOwner: Party
vendor: Party
vendorId: Text
where
signatory networkOwner
observer vendor
key (networkOwner, vendorId): (Party, Text)
maintainer key._1
controller networkOwner can
nonconsuming RegisterProduct: (Optional (ContractId Client), ContractId Product)
with productInfo: ProductInformation; clientInfo: ClientInformation
do
clientCid <- lookupByKey @Client (clientKey)
productCid <- lookupByKey @Product (productKey)
assertMsg "Product already registered" (isNone productCid) !!! Should have stopped here but productKey had a bug !!!
newClient <- case clientCid of
None -> do
exerciseByKey @ClientList AddClients with newClients = [clientInfo]
case clientInfo.clientType of
FIRSTTYPE -> do
newClient <- create Client with ...
return (Some newClient)
SECONDTYPE -> do return None
Some clientCid -> do
client <- fetch clientCid
archive clientCid
newClient <- create client with products = dedup (productInfo :: client.products)
return (Some newClient)
product <- create Product with ...
return (newClient, product)
Thanks for sharing the example; in the model, multiple concurrent transactions that exercise RegisterProduct
could contend for a client key if they update (i.e., archive/re-create) the same client.
Is that right that your application prevents that from happening by submitting at most one such transaction per client, then waits for it to complete before submitting another one? If that’s not the case, then two transactions could interleave as follows:
- T1 looks up a client C by key.
- T2 looks up the same client C by key.
- T2 successfully adds a new product to C that becomes C’.
- T1 tries to add a new product to C too: when updating C, it expects the key to point to C but, due to T2, it now points to C’ instead and thus T1 is rejected with
InconsistentKeys
.
1 Like
Yeah, you’re exactly right. To debug this issue I’m submitting the commands manually, ensuring the first has completed and my app has the ledger response before sending the second. We shouldn’t be getting InconsistentKeys
but we are anyway.
1 Like
This feels like a potential bug to me.
Would you mind opening a GitHub issue at digital-asset/daml
? We’ll investigate and report back there (and here once clarified).
Thanks!
1 Like
Hi @lashenhurst, daml 1.13.0-snapshot.20210426.6770.0.ca66061b
should fix the issue. Could you give it a try?
2 Likes
Hi @fabio.tudone , unfortunately I’m not able to do this due to the security restrictions in the environment where this code sits, snapshots are viewed with extreme prejudice! I would probably have to wait until 1.13.0 release to give it a try.
But I’m glad I found an actual bug, and that it was resolved, thanks for following up!
3 Likes