Release of Daml 2.3.0

 Daml 2.3.0 has been released. You can install it using:

daml install 2.3.0



Beyond the usual smaller improvements and bug fixes, Daml 2.3.0 introduces a range of improvements to Canton:

  • Canton protocol version (3.0.0) fixes a class of potentially severe bugs with Contract Keys.
  • Canton Enterprise now has GA support for permissioned domains.
  • Canton Enterprise now supports dynamically changing sequencer connections during operation.

Impact and Migration

Daml and Canton 2.3.0 are fully backwards compatible with Daml 2.2.0. However, to fully mitigate all known limitations to Contract Keys in Canton 2.2.0 and below, Canton domains are required to run Canton protocol version 3.0.0. New domains deployed with Canton 2.3.0 will do so by default. Existing domains deployed with Canton 2.2.0 or below will need to be upgraded using a process detailed out below.

Some early access configuration options around domain permissioning were replaced as part of making permissioned domains a GA feature. Please refer to the detailed notes below for correspondence between old and new configuration options.

What’s new

Canton Protocol Version 3.0.0


Investigation of a mild bug leading to incorrect DUPLICATE_KEY errors in Sandbox and Canton ledgers led to the discovery of an issue with Canton protocol version 2.X which could cause participants to generate invalid transaction structures, leading to failures that would require manual intervention using the repair endpoints to resolve. These bugs are corner cases, triggered in a deterministic way, and are also present in the Sandbox, so it is highly unlikely that anyone would encounter them in production and not catch them during testing. However, given their potential severity, we advise all users to take steps to mitigate these bugs. Fixing this bug requires a new Canton protocol version so with Daml 2.3.0 we are introducing Canton protocol 3.0.0. Please refer to the documentation for more details about Canton protocol versions.

Specific Changes

  • Canton nodes now support Canton protocol 3.0.0 in addition to 2.X and 1.X protocol versions.
  • Canton protocol version 3.0.0 is the new default version for new domains.
  • Contract keys and Exceptions now behave correctly and consistently between IDE, daml test, Sandbox, and Canton on domains with protocol version 3.0.0.

Impact and Migration

While the releases 2.3.0 and beyond will still be capable of using protocol version 2.X, we advise production systems to start with protocol 3 directly, and migrate their older systems to fully mitigate all known limitations to contract keys in Canton. In addition, there is a limitation to the usual cross-version compatibility between participant versions when running on a domain with protocol version 2.X.

Canton 2.3.0 and <=2.2.0 participant nodes are both capable of connecting to a domain running protocol version 2.0.0. However, we strongly advise against mixing participant nodes of versions above and below 2.3.0 on the same domain running protocol version 2.0 since it can lead to fatal errors in some of the cases that previously triggered the Canton contract key bugs.

If you do not yet have a domain in operation, the mitigation is to simply move to Daml and Canton 2.3.0.

If you already have a domain in operation, you have two options:

  • Upgrade to a canton domain with protocol version 3.0.0. The detailed migration guide including the section on changing the Canton protocol version explains how to upgrade a network by first deploying a domain with a new protocol version, updating the participant binaries and finally migrating the contracts in a synchronized upgrade process using the repair.migrate_domain command on all participants.
  • If the above is not an option, you can upgrade the binaries of all your participants to 2.3.0 in lockstep. You’ll profit from some of the bug fixes, but will retain some of the corner cases that could cause fatal errors. We recommend testing using the Sandbox from SDK 2.2.0 in this case so you can detect any such issues in testing.

[Enterprise Only] Access Controls for Permissioned Domains


Daml 2.3.0 Enterprise introduces the ability to restrict access to a Canton domain by maintaining an allow-list of participant identities that are allowed to connect. This allows the creation of a permissioned domain without having to control access at the networking (TCP/IP) level.

Specific Changes

Canton can now run in two modes: open or permissioned. This can be configured using a new boolean flag = true | false

An open domain will let anyone with access to the sequencer join a domain as a participant.

A permissioned domain will reject the on-boarding of a participant unless that particular participant has been actively enabled by the domain manager operator using the domain.participants.set_state command.

Please also check the more detailed guide on how to manage permissioned domains.

The open source domain only supports open domains.

Impact and Migration

The previous early access option "auto-approve" is now represented by "open" domains. The "reject" mode is the normal behavior for any participant not on the allow-list of a permissioned domain. The preview feature "queue" mode has been entirely removed due to the better user experience of using allow-lists.

[Enterprise Only] Dynamic Sequencer Connections for all Canton Nodes


All Canton nodes - Participants, Mediators and the Domain Topology Manager - communicate through sequencers and their underlying sequencer backend. Sequencers are configured during node initialization and bootstrapping, but there are cases where one wants to change such connections during operation. For example to connect to multiple domains, or add additional sequencers for redundancy. 

The participant nodes already supported adjusting sequencer connections after initialisation. This is now also supported by mediator and domain topology manager nodes.

Specific Changes

Mediator and Domain Topology Manager nodes can now 

  • dynamically change sequencer connections after bootstrapping by using the new node.sequencer_connection.set command.
  • see the current connections use the command node.sequencer_connection.get
  • modify the the sequencer connection using the commands like node.sequencer_connection.modify(_.addConnection(conn))

Please check the reference manual for more details

Impact and Migration

This is a purely additive change.

Minor Improvements

  • The Trigger Service now has a /readyz endpoint to support readiness probes.
  • The Java Codegen APIs have been improved. The createAndExercise* and exerciseByKey* methods are now deprecated; instead, use the new createAnd().exercise* and byKey(key).exercise* methods. This significantly reduces the amount of generated code, especially when using interfaces, and improves the ergonomics of using generated code.
  • Templates generated by the Java Codegen now have a generic toValue method.  See #13859
  • The Canton demo now supports Apple silicon (M1).
  • Improvements to Early Access Features
    • Direct invocation of interface exercise methods on templates is no longer supported, and the exercise* methods are removed. Use toInterface to access interface exercise methods.
    • When the ledger API supports it, interface choices will be reachable via createAnd().toInterface(Ifc.INTERFACE).exercise* and byKey(key).toInterface(Ifc.INTERFACE).exercise*, exactly the syntax supported by contract-ID exercise; see #14056.
    • For interface types Ifc, the template contract ID conversion method toIfc() has been removed and replaced with toInterface(Ifc.INTERFACE), and the interface contract ID conversion method unsafeFromIfc has been replaced with unsafeFromInterface, always the same name.
    • Files are now generated for Daml modules with interfaces even if no serializable types are present, and the module contents are generally propagated as if they had serializable types in them.
    • Some imports were missing in TypeScript declarations and JavaScript module definitions when those imports were only used to implement interfaces; these imports are now properly generated. See #13844.
    • The compiler now provides better locations of certain types of error messages, e.g., missing interface methods.
    • The Java Codegen has been improved for use with interfaces:
    • The JavaScript Codegen has been improved for use with interfaces:

Bug and Security fixes

  • SDK fixes to the handling of transitive dependencies through a data-dependency (#13981), and data-dependency handling of constraint synonyms in superclasses (#13916).
  • Fixed the exception thrown by the Canton console command, if the given domain is not yet initialized. Improved documentation.
  • Fixed a bug in the Daml Engine which would cause a false positive key lookup after a true negative lookup inside a rolled-back sub-transaction. (#14107).